Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wirel...
authorDavid S. Miller <davem@davemloft.net>
Tue, 8 Dec 2009 21:44:44 +0000 (13:44 -0800)
committerDavid S. Miller <davem@davemloft.net>
Tue, 8 Dec 2009 21:44:44 +0000 (13:44 -0800)
1776 files changed:
Documentation/DocBook/tracepoint.tmpl
Documentation/arm/Samsung-S3C24XX/EB2410ITX.txt
Documentation/arm/Samsung-S3C24XX/GPIO.txt
Documentation/arm/Samsung-S3C24XX/Overview.txt
Documentation/arm/Samsung-S3C24XX/S3C2412.txt
Documentation/arm/Samsung-S3C24XX/S3C2413.txt
Documentation/arm/Samsung-S3C24XX/Suspend.txt
Documentation/arm/Samsung-S3C24XX/USB-Host.txt
Documentation/blockdev/drbd/DRBD-8.3-data-packets.svg [new file with mode: 0644]
Documentation/blockdev/drbd/DRBD-data-packets.svg [new file with mode: 0644]
Documentation/blockdev/drbd/README.txt [new file with mode: 0644]
Documentation/blockdev/drbd/conn-states-8.dot [new file with mode: 0644]
Documentation/blockdev/drbd/disk-states-8.dot [new file with mode: 0644]
Documentation/blockdev/drbd/drbd-connection-state-overview.dot [new file with mode: 0644]
Documentation/blockdev/drbd/node-states-8.dot [new file with mode: 0644]
Documentation/cgroups/blkio-controller.txt [new file with mode: 0644]
Documentation/feature-removal-schedule.txt
Documentation/filesystems/proc.txt
Documentation/i2c/busses/i2c-voodoo3 [deleted file]
Documentation/i2c/i2c-stub
Documentation/i2c/old-module-parameters [new file with mode: 0644]
Documentation/kernel-parameters.txt
Documentation/kvm/api.txt
Documentation/power/runtime_pm.txt
Documentation/sound/alsa/ALSA-Configuration.txt
Documentation/sound/alsa/ControlNames.txt
Documentation/sound/alsa/HD-Audio-Models.txt
Documentation/sysctl/ctl_unnumbered.txt [deleted file]
Documentation/trace/kprobetrace.txt [new file with mode: 0644]
MAINTAINERS
arch/Kconfig
arch/alpha/include/asm/cacheflush.h
arch/arm/Kconfig
arch/arm/Kconfig.debug
arch/arm/Makefile
arch/arm/boot/compressed/head.S
arch/arm/common/dmabounce.c
arch/arm/configs/am3517_evm_defconfig [new file with mode: 0644]
arch/arm/configs/at91rm9200dk_defconfig
arch/arm/configs/cm_t35_defconfig [new file with mode: 0644]
arch/arm/configs/cm_x300_defconfig
arch/arm/configs/dove_defconfig [new file with mode: 0644]
arch/arm/configs/ezx_defconfig
arch/arm/configs/h3600_defconfig
arch/arm/configs/htcherald_defconfig [new file with mode: 0644]
arch/arm/configs/igep0020_defconfig [new file with mode: 0644]
arch/arm/configs/mx3_defconfig
arch/arm/configs/nuc910_defconfig [moved from arch/arm/configs/w90p910_defconfig with 100% similarity]
arch/arm/configs/nuc950_defconfig [new file with mode: 0644]
arch/arm/configs/nuc960_defconfig [new file with mode: 0644]
arch/arm/configs/omap3_beagle_defconfig
arch/arm/configs/omap3_defconfig [new file with mode: 0644]
arch/arm/configs/omap3_evm_defconfig
arch/arm/configs/omap3_pandora_defconfig
arch/arm/configs/omap_3430sdp_defconfig
arch/arm/configs/omap_3630sdp_defconfig [new file with mode: 0644]
arch/arm/configs/omap_4430sdp_defconfig
arch/arm/configs/omap_ldp_defconfig
arch/arm/configs/omap_zoom2_defconfig
arch/arm/configs/omap_zoom3_defconfig [new file with mode: 0644]
arch/arm/configs/overo_defconfig
arch/arm/configs/rx51_defconfig
arch/arm/configs/u8500_defconfig [new file with mode: 0644]
arch/arm/include/asm/cacheflush.h
arch/arm/include/asm/dma-mapping.h
arch/arm/include/asm/hardware/cache-tauros2.h [new file with mode: 0644]
arch/arm/include/asm/hardware/coresight.h [new file with mode: 0644]
arch/arm/include/asm/hardware/iop3xx.h
arch/arm/include/asm/memory.h
arch/arm/include/asm/pgtable.h
arch/arm/include/asm/swab.h
arch/arm/include/asm/system.h
arch/arm/kernel/Makefile
arch/arm/kernel/etm.c [new file with mode: 0644]
arch/arm/kernel/head-nommu.S
arch/arm/kernel/head.S
arch/arm/kernel/isa.c
arch/arm/kernel/vmlinux.lds.S
arch/arm/mach-at91/Kconfig
arch/arm/mach-at91/Makefile
arch/arm/mach-at91/at91sam9g45_devices.c
arch/arm/mach-at91/board-eco920.c [new file with mode: 0644]
arch/arm/mach-at91/board-sam9m10g45ek.c
arch/arm/mach-at91/cpuidle.c [new file with mode: 0644]
arch/arm/mach-at91/include/mach/board.h
arch/arm/mach-at91/pm.c
arch/arm/mach-at91/pm.h [new file with mode: 0644]
arch/arm/mach-bcmring/arch.c
arch/arm/mach-bcmring/include/mach/io.h
arch/arm/mach-davinci/include/mach/asp.h
arch/arm/mach-dove/Kconfig [new file with mode: 0644]
arch/arm/mach-dove/Makefile [new file with mode: 0644]
arch/arm/mach-dove/Makefile.boot [new file with mode: 0644]
arch/arm/mach-dove/addr-map.c [new file with mode: 0644]
arch/arm/mach-dove/common.c [new file with mode: 0644]
arch/arm/mach-dove/common.h [new file with mode: 0644]
arch/arm/mach-dove/dove-db-setup.c [new file with mode: 0644]
arch/arm/mach-dove/include/mach/bridge-regs.h [new file with mode: 0644]
arch/arm/mach-dove/include/mach/debug-macro.S [new file with mode: 0644]
arch/arm/mach-dove/include/mach/dove.h [new file with mode: 0644]
arch/arm/mach-dove/include/mach/entry-macro.S [new file with mode: 0644]
arch/arm/mach-dove/include/mach/gpio.h [new file with mode: 0644]
arch/arm/mach-dove/include/mach/hardware.h [new file with mode: 0644]
arch/arm/mach-dove/include/mach/io.h [new file with mode: 0644]
arch/arm/mach-dove/include/mach/irqs.h [new file with mode: 0644]
arch/arm/mach-dove/include/mach/memory.h [new file with mode: 0644]
arch/arm/mach-dove/include/mach/pm.h [new file with mode: 0644]
arch/arm/mach-dove/include/mach/system.h [new file with mode: 0644]
arch/arm/mach-dove/include/mach/timex.h [new file with mode: 0644]
arch/arm/mach-dove/include/mach/uncompress.h [new file with mode: 0644]
arch/arm/mach-dove/include/mach/vmalloc.h [new file with mode: 0644]
arch/arm/mach-dove/irq.c [new file with mode: 0644]
arch/arm/mach-dove/pcie.c [new file with mode: 0644]
arch/arm/mach-ep93xx/core.c
arch/arm/mach-ep93xx/include/mach/clkdev.h
arch/arm/mach-ep93xx/include/mach/dma.h
arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h
arch/arm/mach-ep93xx/include/mach/hardware.h
arch/arm/mach-ep93xx/include/mach/io.h
arch/arm/mach-ep93xx/include/mach/platform.h
arch/arm/mach-iop13xx/include/mach/memory.h
arch/arm/mach-iop13xx/include/mach/time.h
arch/arm/mach-iop13xx/iq81340mc.c
arch/arm/mach-iop13xx/iq81340sc.c
arch/arm/mach-iop32x/em7210.c
arch/arm/mach-iop32x/glantank.c
arch/arm/mach-iop32x/iq31244.c
arch/arm/mach-iop32x/iq80321.c
arch/arm/mach-iop32x/n2100.c
arch/arm/mach-iop33x/iq80331.c
arch/arm/mach-iop33x/iq80332.c
arch/arm/mach-kirkwood/Kconfig
arch/arm/mach-kirkwood/Makefile
arch/arm/mach-kirkwood/ts219-setup.c
arch/arm/mach-kirkwood/ts41x-setup.c [new file with mode: 0644]
arch/arm/mach-kirkwood/tsx1x-common.c [new file with mode: 0644]
arch/arm/mach-kirkwood/tsx1x-common.h [new file with mode: 0644]
arch/arm/mach-ks8695/include/mach/memory.h
arch/arm/mach-mmp/aspenite.c
arch/arm/mach-mmp/clock.c
arch/arm/mach-mmp/clock.h
arch/arm/mach-mmp/include/mach/irqs.h
arch/arm/mach-mmp/include/mach/pxa168.h
arch/arm/mach-mmp/include/mach/pxa910.h
arch/arm/mach-mmp/pxa168.c
arch/arm/mach-mmp/pxa910.c
arch/arm/mach-mmp/ttc_dkb.c
arch/arm/mach-mx2/Kconfig
arch/arm/mach-mx2/Makefile
arch/arm/mach-mx2/clock_imx21.c
arch/arm/mach-mx2/clock_imx27.c
arch/arm/mach-mx2/devices.c
arch/arm/mach-mx2/devices.h
arch/arm/mach-mx2/mxt_td60.c [new file with mode: 0644]
arch/arm/mach-mx2/pca100.c
arch/arm/mach-mx3/Kconfig
arch/arm/mach-mx3/Makefile
arch/arm/mach-mx3/armadillo5x0.c
arch/arm/mach-mx3/clock-imx35.c
arch/arm/mach-mx3/clock.c
arch/arm/mach-mx3/cpu.c [new file with mode: 0644]
arch/arm/mach-mx3/devices.c
arch/arm/mach-mx3/devices.h
arch/arm/mach-mx3/kzmarm11.c [new file with mode: 0644]
arch/arm/mach-mx3/mx31lilly-db.c
arch/arm/mach-mx3/mx31lilly.c
arch/arm/mach-mx3/mx31lite-db.c [new file with mode: 0644]
arch/arm/mach-mx3/mx31lite.c
arch/arm/mach-mx3/mx31moboard-devboard.c
arch/arm/mach-mx3/mx31moboard-marxbot.c
arch/arm/mach-mx3/mx31moboard.c
arch/arm/mach-mx3/mx35pdk.c
arch/arm/mach-mx3/pcm043.c
arch/arm/mach-nomadik/Kconfig
arch/arm/mach-nomadik/Makefile
arch/arm/mach-nomadik/board-nhk8815.c
arch/arm/mach-nomadik/include/mach/setup.h
arch/arm/mach-omap1/Kconfig
arch/arm/mach-omap1/Makefile
arch/arm/mach-omap1/board-ams-delta.c
arch/arm/mach-omap1/board-fsample.c
arch/arm/mach-omap1/board-generic.c
arch/arm/mach-omap1/board-h2-mmc.c
arch/arm/mach-omap1/board-h2.c
arch/arm/mach-omap1/board-h3-mmc.c
arch/arm/mach-omap1/board-h3.c
arch/arm/mach-omap1/board-htcherald.c [new file with mode: 0644]
arch/arm/mach-omap1/board-innovator.c
arch/arm/mach-omap1/board-nokia770.c
arch/arm/mach-omap1/board-osk.c
arch/arm/mach-omap1/board-palmte.c
arch/arm/mach-omap1/board-palmtt.c
arch/arm/mach-omap1/board-palmz71.c
arch/arm/mach-omap1/board-perseus2.c
arch/arm/mach-omap1/board-sx1-mmc.c
arch/arm/mach-omap1/board-sx1.c
arch/arm/mach-omap1/board-voiceblue.c
arch/arm/mach-omap1/clock.c
arch/arm/mach-omap1/clock.h
arch/arm/mach-omap1/devices.c
arch/arm/mach-omap1/fpga.c
arch/arm/mach-omap1/id.c
arch/arm/mach-omap1/include/mach/clkdev.h [new file with mode: 0644]
arch/arm/mach-omap1/include/mach/debug-macro.S [new file with mode: 0644]
arch/arm/mach-omap1/include/mach/entry-macro.S [new file with mode: 0644]
arch/arm/mach-omap1/include/mach/gpio.h [new file with mode: 0644]
arch/arm/mach-omap1/include/mach/hardware.h [new file with mode: 0644]
arch/arm/mach-omap1/include/mach/io.h [new file with mode: 0644]
arch/arm/mach-omap1/include/mach/irqs.h [new file with mode: 0644]
arch/arm/mach-omap1/include/mach/memory.h [new file with mode: 0644]
arch/arm/mach-omap1/include/mach/mtd-xip.h [moved from arch/arm/plat-omap/include/mach/mtd-xip.h with 100% similarity]
arch/arm/mach-omap1/include/mach/smp.h [new file with mode: 0644]
arch/arm/mach-omap1/include/mach/system.h [new file with mode: 0644]
arch/arm/mach-omap1/include/mach/timex.h [new file with mode: 0644]
arch/arm/mach-omap1/include/mach/uncompress.h [new file with mode: 0644]
arch/arm/mach-omap1/include/mach/vmalloc.h [new file with mode: 0644]
arch/arm/mach-omap1/io.c
arch/arm/mach-omap1/irq.c
arch/arm/mach-omap1/leds-h2p2-debug.c
arch/arm/mach-omap1/leds.c
arch/arm/mach-omap1/mailbox.c
arch/arm/mach-omap1/mcbsp.c
arch/arm/mach-omap1/mux.c
arch/arm/mach-omap1/pm.c
arch/arm/mach-omap1/pm.h
arch/arm/mach-omap1/serial.c
arch/arm/mach-omap1/sleep.S
arch/arm/mach-omap1/timer32k.c
arch/arm/mach-omap2/Kconfig
arch/arm/mach-omap2/Makefile
arch/arm/mach-omap2/board-2430sdp.c
arch/arm/mach-omap2/board-3430sdp.c
arch/arm/mach-omap2/board-3630sdp.c [new file with mode: 0755]
arch/arm/mach-omap2/board-4430sdp.c
arch/arm/mach-omap2/board-am3517evm.c [new file with mode: 0644]
arch/arm/mach-omap2/board-apollon.c
arch/arm/mach-omap2/board-cm-t35.c [new file with mode: 0644]
arch/arm/mach-omap2/board-generic.c
arch/arm/mach-omap2/board-h4.c
arch/arm/mach-omap2/board-igep0020.c [new file with mode: 0644]
arch/arm/mach-omap2/board-ldp.c
arch/arm/mach-omap2/board-n8x0.c
arch/arm/mach-omap2/board-omap3beagle.c
arch/arm/mach-omap2/board-omap3evm.c
arch/arm/mach-omap2/board-omap3pandora.c
arch/arm/mach-omap2/board-overo.c
arch/arm/mach-omap2/board-rx51-peripherals.c
arch/arm/mach-omap2/board-rx51-sdram.c [new file with mode: 0644]
arch/arm/mach-omap2/board-rx51.c
arch/arm/mach-omap2/board-zoom-debugboard.c
arch/arm/mach-omap2/board-zoom-peripherals.c [new file with mode: 0755]
arch/arm/mach-omap2/board-zoom2.c
arch/arm/mach-omap2/board-zoom3.c [new file with mode: 0644]
arch/arm/mach-omap2/clock.c
arch/arm/mach-omap2/clock.h
arch/arm/mach-omap2/clock24xx.c
arch/arm/mach-omap2/clock34xx.c
arch/arm/mach-omap2/clock34xx.h
arch/arm/mach-omap2/clockdomain.c
arch/arm/mach-omap2/clockdomains.h
arch/arm/mach-omap2/cm.h
arch/arm/mach-omap2/control.c
arch/arm/mach-omap2/cpuidle34xx.c [new file with mode: 0644]
arch/arm/mach-omap2/devices.c
arch/arm/mach-omap2/emu.c [new file with mode: 0644]
arch/arm/mach-omap2/gpmc-onenand.c
arch/arm/mach-omap2/gpmc-smc91x.c
arch/arm/mach-omap2/gpmc.c
arch/arm/mach-omap2/id.c
arch/arm/mach-omap2/include/mach/board-zoom.h [new file with mode: 0644]
arch/arm/mach-omap2/include/mach/clkdev.h [new file with mode: 0644]
arch/arm/mach-omap2/include/mach/debug-macro.S [moved from arch/arm/plat-omap/include/mach/debug-macro.S with 72% similarity]
arch/arm/mach-omap2/include/mach/entry-macro.S [moved from arch/arm/plat-omap/include/mach/entry-macro.S with 68% similarity]
arch/arm/mach-omap2/include/mach/gpio.h [new file with mode: 0644]
arch/arm/mach-omap2/include/mach/hardware.h [new file with mode: 0644]
arch/arm/mach-omap2/include/mach/io.h [new file with mode: 0644]
arch/arm/mach-omap2/include/mach/irqs.h [new file with mode: 0644]
arch/arm/mach-omap2/include/mach/memory.h [new file with mode: 0644]
arch/arm/mach-omap2/include/mach/smp.h [new file with mode: 0644]
arch/arm/mach-omap2/include/mach/system.h [new file with mode: 0644]
arch/arm/mach-omap2/include/mach/timex.h [new file with mode: 0644]
arch/arm/mach-omap2/include/mach/uncompress.h [new file with mode: 0644]
arch/arm/mach-omap2/include/mach/vmalloc.h [moved from arch/arm/plat-omap/include/mach/vmalloc.h with 94% similarity]
arch/arm/mach-omap2/io.c
arch/arm/mach-omap2/iommu2.c
arch/arm/mach-omap2/irq.c
arch/arm/mach-omap2/mailbox.c
arch/arm/mach-omap2/mcbsp.c
arch/arm/mach-omap2/mmc-twl4030.c
arch/arm/mach-omap2/mux.c
arch/arm/mach-omap2/omap-smp.c
arch/arm/mach-omap2/omap3-iommu.c
arch/arm/mach-omap2/omap_hwmod.c
arch/arm/mach-omap2/omap_hwmod_2420.h
arch/arm/mach-omap2/omap_hwmod_2430.h
arch/arm/mach-omap2/omap_hwmod_34xx.h
arch/arm/mach-omap2/pm-debug.c
arch/arm/mach-omap2/pm.h
arch/arm/mach-omap2/pm24xx.c
arch/arm/mach-omap2/pm34xx.c
arch/arm/mach-omap2/powerdomain.c
arch/arm/mach-omap2/powerdomains.h
arch/arm/mach-omap2/powerdomains24xx.h
arch/arm/mach-omap2/powerdomains34xx.h
arch/arm/mach-omap2/prcm.c
arch/arm/mach-omap2/prm-regbits-34xx.h
arch/arm/mach-omap2/prm.h
arch/arm/mach-omap2/sdram-hynix-h8mbx00u0mer-0em.h [new file with mode: 0644]
arch/arm/mach-omap2/sdram-micron-mt46h32m32lf-6.h
arch/arm/mach-omap2/sdram-qimonda-hyb18m512160af-6.h
arch/arm/mach-omap2/sdrc.c
arch/arm/mach-omap2/sdrc.h
arch/arm/mach-omap2/sdrc2xxx.c
arch/arm/mach-omap2/serial.c
arch/arm/mach-omap2/sleep24xx.S
arch/arm/mach-omap2/sleep34xx.S
arch/arm/mach-omap2/sram242x.S
arch/arm/mach-omap2/sram243x.S
arch/arm/mach-omap2/timer-gp.c
arch/arm/mach-omap2/usb-ehci.c [new file with mode: 0644]
arch/arm/mach-omap2/usb-musb.c
arch/arm/mach-omap2/usb-tusb6010.c
arch/arm/mach-pxa/Kconfig
arch/arm/mach-pxa/Makefile
arch/arm/mach-pxa/balloon3.c
arch/arm/mach-pxa/cm-x2xx.c
arch/arm/mach-pxa/cm-x300.c
arch/arm/mach-pxa/colibri-pxa270.c
arch/arm/mach-pxa/colibri-pxa300.c
arch/arm/mach-pxa/colibri-pxa320.c
arch/arm/mach-pxa/colibri-pxa3xx.c
arch/arm/mach-pxa/corgi.c
arch/arm/mach-pxa/corgi_pm.c
arch/arm/mach-pxa/csb726.c
arch/arm/mach-pxa/devices.c
arch/arm/mach-pxa/e330.c
arch/arm/mach-pxa/e350.c
arch/arm/mach-pxa/e400.c
arch/arm/mach-pxa/e740.c
arch/arm/mach-pxa/e750.c
arch/arm/mach-pxa/e800.c
arch/arm/mach-pxa/em-x270.c
arch/arm/mach-pxa/ezx.c
arch/arm/mach-pxa/generic.h
arch/arm/mach-pxa/gumstix.c
arch/arm/mach-pxa/h5000.c
arch/arm/mach-pxa/himalaya.c
arch/arm/mach-pxa/hx4700.c
arch/arm/mach-pxa/idp.c
arch/arm/mach-pxa/imote2.c
arch/arm/mach-pxa/include/mach/hardware.h
arch/arm/mach-pxa/include/mach/palmtreo.h [new file with mode: 0644]
arch/arm/mach-pxa/include/mach/pxafb.h
arch/arm/mach-pxa/include/mach/regs-u2d.h [new file with mode: 0644]
arch/arm/mach-pxa/include/mach/treo680.h [deleted file]
arch/arm/mach-pxa/littleton.c
arch/arm/mach-pxa/lpd270.c
arch/arm/mach-pxa/lubbock.c
arch/arm/mach-pxa/magician.c
arch/arm/mach-pxa/mainstone.c
arch/arm/mach-pxa/mioa701.c
arch/arm/mach-pxa/mp900.c
arch/arm/mach-pxa/palmld.c
arch/arm/mach-pxa/palmt5.c
arch/arm/mach-pxa/palmtc.c
arch/arm/mach-pxa/palmte2.c
arch/arm/mach-pxa/palmtreo.c [moved from arch/arm/mach-pxa/treo680.c with 53% similarity]
arch/arm/mach-pxa/palmtx.c
arch/arm/mach-pxa/palmz72.c
arch/arm/mach-pxa/pcm027.c
arch/arm/mach-pxa/pcm990-baseboard.c
arch/arm/mach-pxa/poodle.c
arch/arm/mach-pxa/pxa25x.c
arch/arm/mach-pxa/pxa27x.c
arch/arm/mach-pxa/pxa3xx.c
arch/arm/mach-pxa/saar.c
arch/arm/mach-pxa/sharpsl.h
arch/arm/mach-pxa/sharpsl_pm.c
arch/arm/mach-pxa/spitz.c
arch/arm/mach-pxa/spitz_pm.c
arch/arm/mach-pxa/ssp.c
arch/arm/mach-pxa/stargate2.c
arch/arm/mach-pxa/tavorevb.c
arch/arm/mach-pxa/tosa.c
arch/arm/mach-pxa/trizeps4.c
arch/arm/mach-pxa/viper.c
arch/arm/mach-pxa/xcep.c
arch/arm/mach-pxa/zylonite.c
arch/arm/mach-s3c2400/include/mach/map.h
arch/arm/mach-s3c2410/Kconfig
arch/arm/mach-s3c2410/Makefile
arch/arm/mach-s3c2410/bast-irq.c
arch/arm/mach-s3c2410/cpu-freq.c
arch/arm/mach-s3c2410/h1940-bluetooth.c
arch/arm/mach-s3c2410/include/mach/bast-cpld.h
arch/arm/mach-s3c2410/include/mach/bast-irq.h
arch/arm/mach-s3c2410/include/mach/bast-map.h
arch/arm/mach-s3c2410/include/mach/bast-pmu.h
arch/arm/mach-s3c2410/include/mach/dma.h
arch/arm/mach-s3c2410/include/mach/gpio-fns.h
arch/arm/mach-s3c2410/include/mach/osiris-map.h
arch/arm/mach-s3c2410/include/mach/regs-clock.h
arch/arm/mach-s3c2410/include/mach/regs-gpio.h
arch/arm/mach-s3c2410/include/mach/regs-power.h
arch/arm/mach-s3c2410/include/mach/uncompress.h
arch/arm/mach-s3c2410/include/mach/vr1000-irq.h
arch/arm/mach-s3c2410/mach-bast.c
arch/arm/mach-s3c2410/mach-h1940.c
arch/arm/mach-s3c2410/mach-n30.c
arch/arm/mach-s3c2410/mach-qt2410.c
arch/arm/mach-s3c2410/mach-vr1000.c
arch/arm/mach-s3c2410/pll.c
arch/arm/mach-s3c2410/usb-simtec.c
arch/arm/mach-s3c2412/mach-jive.c
arch/arm/mach-s3c2412/mach-vstms.c
arch/arm/mach-s3c2440/Kconfig
arch/arm/mach-s3c2440/Makefile
arch/arm/mach-s3c2440/irq.c
arch/arm/mach-s3c2440/mach-anubis.c
arch/arm/mach-s3c2440/mach-at2440evb.c
arch/arm/mach-s3c2440/mach-mini2440.c
arch/arm/mach-s3c2440/mach-osiris-dvs.c [new file with mode: 0644]
arch/arm/mach-s3c2440/mach-osiris.c
arch/arm/mach-s3c2440/mach-rx3715.c
arch/arm/mach-s3c2440/mach-smdk2440.c
arch/arm/mach-s3c2442/mach-gta02.c
arch/arm/mach-s3c24a0/include/mach/map.h
arch/arm/mach-s3c24a0/include/mach/regs-clock.h
arch/arm/mach-s3c6400/include/mach/map.h
arch/arm/mach-s3c6400/include/mach/regs-fb.h
arch/arm/mach-s3c6400/s3c6400.c
arch/arm/mach-s3c6410/cpu.c
arch/arm/mach-s3c6410/mach-hmt.c
arch/arm/mach-s3c6410/mach-smdk6410.c
arch/arm/mach-s5pc100/Kconfig
arch/arm/mach-s5pc100/Makefile
arch/arm/mach-s5pc100/cpu.c
arch/arm/mach-s5pc100/include/mach/gpio.h
arch/arm/mach-s5pc100/include/mach/irqs.h
arch/arm/mach-s5pc100/include/mach/map.h
arch/arm/mach-s5pc100/include/mach/regs-fb.h [new file with mode: 0644]
arch/arm/mach-s5pc100/include/mach/system.h
arch/arm/mach-s5pc100/mach-smdkc100.c
arch/arm/mach-s5pc100/setup-sdhci.c [new file with mode: 0644]
arch/arm/mach-sa1100/Kconfig
arch/arm/mach-sa1100/Makefile
arch/arm/mach-sa1100/assabet.c
arch/arm/mach-sa1100/badge4.c
arch/arm/mach-sa1100/cerf.c
arch/arm/mach-sa1100/collie.c
arch/arm/mach-sa1100/generic.c
arch/arm/mach-sa1100/generic.h
arch/arm/mach-sa1100/h3100.c [new file with mode: 0644]
arch/arm/mach-sa1100/h3600.c
arch/arm/mach-sa1100/h3xxx.c [new file with mode: 0644]
arch/arm/mach-sa1100/hackkit.c
arch/arm/mach-sa1100/include/mach/collie.h
arch/arm/mach-sa1100/include/mach/gpio.h
arch/arm/mach-sa1100/include/mach/h3600.h [deleted file]
arch/arm/mach-sa1100/include/mach/h3600_gpio.h [deleted file]
arch/arm/mach-sa1100/include/mach/h3xxx.h [new file with mode: 0644]
arch/arm/mach-sa1100/include/mach/mcp.h
arch/arm/mach-sa1100/jornada720.c
arch/arm/mach-sa1100/lart.c
arch/arm/mach-sa1100/pleb.c
arch/arm/mach-sa1100/shannon.c
arch/arm/mach-sa1100/simpad.c
arch/arm/mach-u300/Makefile
arch/arm/mach-u300/i2c.c
arch/arm/mach-u300/mmc.c
arch/arm/mach-u300/regulator.c [new file with mode: 0644]
arch/arm/mach-ux500/Kconfig [new file with mode: 0644]
arch/arm/mach-ux500/Makefile [new file with mode: 0644]
arch/arm/mach-ux500/Makefile.boot [new file with mode: 0644]
arch/arm/mach-ux500/board-mop500.c [new file with mode: 0644]
arch/arm/mach-ux500/clock.c [new file with mode: 0644]
arch/arm/mach-ux500/cpu-u8500.c [new file with mode: 0644]
arch/arm/mach-ux500/headsmp.S [new file with mode: 0644]
arch/arm/mach-ux500/include/mach/clkdev.h [new file with mode: 0644]
arch/arm/mach-ux500/include/mach/debug-macro.S [new file with mode: 0644]
arch/arm/mach-ux500/include/mach/entry-macro.S [new file with mode: 0644]
arch/arm/mach-ux500/include/mach/hardware.h [new file with mode: 0644]
arch/arm/mach-ux500/include/mach/io.h [new file with mode: 0644]
arch/arm/mach-ux500/include/mach/irqs.h [new file with mode: 0644]
arch/arm/mach-ux500/include/mach/memory.h [new file with mode: 0644]
arch/arm/mach-ux500/include/mach/setup.h [new file with mode: 0644]
arch/arm/mach-ux500/include/mach/smp.h [new file with mode: 0644]
arch/arm/mach-ux500/include/mach/system.h [new file with mode: 0644]
arch/arm/mach-ux500/include/mach/timex.h [new file with mode: 0644]
arch/arm/mach-ux500/include/mach/uncompress.h [new file with mode: 0644]
arch/arm/mach-ux500/include/mach/vmalloc.h [new file with mode: 0644]
arch/arm/mach-ux500/localtimer.c [new file with mode: 0644]
arch/arm/mach-ux500/platsmp.c [new file with mode: 0644]
arch/arm/mach-w90x900/dev.c
arch/arm/mm/Kconfig
arch/arm/mm/Makefile
arch/arm/mm/cache-l2x0.c
arch/arm/mm/cache-tauros2.c [new file with mode: 0644]
arch/arm/mm/copypage-v6.c
arch/arm/mm/dma-mapping.c
arch/arm/mm/fault-armv.c
arch/arm/mm/flush.c
arch/arm/mm/mm.h
arch/arm/mm/mmu.c
arch/arm/mm/proc-v6.S
arch/arm/mm/proc-xsc3.S
arch/arm/mm/vmregion.c [new file with mode: 0644]
arch/arm/mm/vmregion.h [new file with mode: 0644]
arch/arm/plat-iop/time.c
arch/arm/plat-mxc/Kconfig
arch/arm/plat-mxc/Makefile
arch/arm/plat-mxc/audmux-v1.c [new file with mode: 0644]
arch/arm/plat-mxc/audmux-v2.c [new file with mode: 0644]
arch/arm/plat-mxc/dma-mx1-mx2.c
arch/arm/plat-mxc/gpio.c
arch/arm/plat-mxc/include/mach/audmux.h [new file with mode: 0644]
arch/arm/plat-mxc/include/mach/board-kzmarm11.h [new file with mode: 0644]
arch/arm/plat-mxc/include/mach/board-mx31lite.h
arch/arm/plat-mxc/include/mach/dma-mx1-mx2.h
arch/arm/plat-mxc/include/mach/iomux-mx3.h
arch/arm/plat-mxc/include/mach/iomux-v3.h
arch/arm/plat-mxc/include/mach/iomux.h
arch/arm/plat-mxc/include/mach/mx21.h
arch/arm/plat-mxc/include/mach/mx25.h
arch/arm/plat-mxc/include/mach/mx27.h
arch/arm/plat-mxc/include/mach/mx2x.h
arch/arm/plat-mxc/include/mach/mx31.h
arch/arm/plat-mxc/include/mach/mx35.h
arch/arm/plat-mxc/include/mach/mx3x.h
arch/arm/plat-mxc/include/mach/ulpi.h [new file with mode: 0644]
arch/arm/plat-mxc/include/mach/uncompress.h
arch/arm/plat-mxc/iomux-v3.c
arch/arm/plat-mxc/ulpi.c [new file with mode: 0644]
arch/arm/plat-nomadik/Kconfig [new file with mode: 0644]
arch/arm/plat-nomadik/Makefile [new file with mode: 0644]
arch/arm/plat-nomadik/include/plat/mtu.h [moved from arch/arm/mach-nomadik/include/mach/mtu.h with 90% similarity]
arch/arm/plat-nomadik/timer.c [moved from arch/arm/mach-nomadik/timer.c with 81% similarity]
arch/arm/plat-omap/Kconfig
arch/arm/plat-omap/clock.c
arch/arm/plat-omap/common.c
arch/arm/plat-omap/cpu-omap.c
arch/arm/plat-omap/debug-devices.c
arch/arm/plat-omap/debug-leds.c
arch/arm/plat-omap/devices.c
arch/arm/plat-omap/dma.c
arch/arm/plat-omap/dmtimer.c
arch/arm/plat-omap/fb.c
arch/arm/plat-omap/gpio.c
arch/arm/plat-omap/i2c.c
arch/arm/plat-omap/include/plat/blizzard.h [moved from arch/arm/plat-omap/include/mach/blizzard.h with 100% similarity]
arch/arm/plat-omap/include/plat/board-ams-delta.h [moved from arch/arm/plat-omap/include/mach/board-ams-delta.h with 100% similarity]
arch/arm/plat-omap/include/plat/board-sx1.h [moved from arch/arm/plat-omap/include/mach/board-sx1.h with 100% similarity]
arch/arm/plat-omap/include/plat/board-voiceblue.h [moved from arch/arm/plat-omap/include/mach/board-voiceblue.h with 100% similarity]
arch/arm/plat-omap/include/plat/board.h [moved from arch/arm/plat-omap/include/mach/board.h with 89% similarity]
arch/arm/plat-omap/include/plat/clkdev.h [moved from arch/arm/plat-omap/include/mach/clkdev.h with 100% similarity]
arch/arm/plat-omap/include/plat/clock.h [moved from arch/arm/plat-omap/include/mach/clock.h with 100% similarity]
arch/arm/plat-omap/include/plat/clockdomain.h [moved from arch/arm/plat-omap/include/mach/clockdomain.h with 97% similarity]
arch/arm/plat-omap/include/plat/common.h [moved from arch/arm/plat-omap/include/mach/common.h with 96% similarity]
arch/arm/plat-omap/include/plat/control.h [moved from arch/arm/plat-omap/include/mach/control.h with 70% similarity]
arch/arm/plat-omap/include/plat/cpu.h [moved from arch/arm/plat-omap/include/mach/cpu.h with 80% similarity]
arch/arm/plat-omap/include/plat/dma.h [moved from arch/arm/plat-omap/include/mach/dma.h with 99% similarity]
arch/arm/plat-omap/include/plat/dmtimer.h [moved from arch/arm/plat-omap/include/mach/dmtimer.h with 100% similarity]
arch/arm/plat-omap/include/plat/dsp_common.h [moved from arch/arm/plat-omap/include/mach/dsp_common.h with 100% similarity]
arch/arm/plat-omap/include/plat/fpga.h [moved from arch/arm/plat-omap/include/mach/fpga.h with 100% similarity]
arch/arm/plat-omap/include/plat/gpio-switch.h [moved from arch/arm/plat-omap/include/mach/gpio-switch.h with 100% similarity]
arch/arm/plat-omap/include/plat/gpio.h [moved from arch/arm/plat-omap/include/mach/gpio.h with 97% similarity]
arch/arm/plat-omap/include/plat/gpmc-smc91x.h [moved from arch/arm/plat-omap/include/mach/gpmc-smc91x.h with 100% similarity]
arch/arm/plat-omap/include/plat/gpmc.h [moved from arch/arm/plat-omap/include/mach/gpmc.h with 97% similarity]
arch/arm/plat-omap/include/plat/hardware.h [moved from arch/arm/plat-omap/include/mach/hardware.h with 98% similarity]
arch/arm/plat-omap/include/plat/hwa742.h [moved from arch/arm/plat-omap/include/mach/hwa742.h with 100% similarity]
arch/arm/plat-omap/include/plat/io.h [moved from arch/arm/plat-omap/include/mach/io.h with 60% similarity]
arch/arm/plat-omap/include/plat/iommu.h [moved from arch/arm/plat-omap/include/mach/iommu.h with 99% similarity]
arch/arm/plat-omap/include/plat/iommu2.h [moved from arch/arm/plat-omap/include/mach/iommu2.h with 100% similarity]
arch/arm/plat-omap/include/plat/iovmm.h [moved from arch/arm/plat-omap/include/mach/iovmm.h with 100% similarity]
arch/arm/plat-omap/include/plat/irda.h [moved from arch/arm/plat-omap/include/mach/irda.h with 100% similarity]
arch/arm/plat-omap/include/plat/irqs.h [moved from arch/arm/plat-omap/include/mach/irqs.h with 70% similarity]
arch/arm/plat-omap/include/plat/keypad.h [moved from arch/arm/plat-omap/include/mach/keypad.h with 100% similarity]
arch/arm/plat-omap/include/plat/lcd_mipid.h [moved from arch/arm/plat-omap/include/mach/lcd_mipid.h with 100% similarity]
arch/arm/plat-omap/include/plat/led.h [moved from arch/arm/plat-omap/include/mach/led.h with 100% similarity]
arch/arm/plat-omap/include/plat/mailbox.h [moved from arch/arm/plat-omap/include/mach/mailbox.h with 79% similarity]
arch/arm/plat-omap/include/plat/mcbsp.h [moved from arch/arm/plat-omap/include/mach/mcbsp.h with 98% similarity]
arch/arm/plat-omap/include/plat/mcspi.h [moved from arch/arm/plat-omap/include/mach/mcspi.h with 100% similarity]
arch/arm/plat-omap/include/plat/memory.h [moved from arch/arm/plat-omap/include/mach/memory.h with 94% similarity]
arch/arm/plat-omap/include/plat/menelaus.h [moved from arch/arm/plat-omap/include/mach/menelaus.h with 100% similarity]
arch/arm/plat-omap/include/plat/mmc.h [moved from arch/arm/plat-omap/include/mach/mmc.h with 99% similarity]
arch/arm/plat-omap/include/plat/mux.h [moved from arch/arm/plat-omap/include/mach/mux.h with 90% similarity]
arch/arm/plat-omap/include/plat/nand.h [moved from arch/arm/plat-omap/include/mach/nand.h with 100% similarity]
arch/arm/plat-omap/include/plat/omap-alsa.h [moved from arch/arm/plat-omap/include/mach/omap-alsa.h with 98% similarity]
arch/arm/plat-omap/include/plat/omap-pm.h [moved from arch/arm/plat-omap/include/mach/omap-pm.h with 100% similarity]
arch/arm/plat-omap/include/plat/omap1510.h [moved from arch/arm/plat-omap/include/mach/omap1510.h with 100% similarity]
arch/arm/plat-omap/include/plat/omap16xx.h [moved from arch/arm/plat-omap/include/mach/omap16xx.h with 100% similarity]
arch/arm/plat-omap/include/plat/omap24xx.h [moved from arch/arm/plat-omap/include/mach/omap24xx.h with 100% similarity]
arch/arm/plat-omap/include/plat/omap34xx.h [moved from arch/arm/plat-omap/include/mach/omap34xx.h with 91% similarity]
arch/arm/plat-omap/include/plat/omap44xx.h [moved from arch/arm/plat-omap/include/mach/omap44xx.h with 79% similarity]
arch/arm/plat-omap/include/plat/omap730.h [moved from arch/arm/plat-omap/include/mach/omap730.h with 100% similarity]
arch/arm/plat-omap/include/plat/omap7xx.h [new file with mode: 0644]
arch/arm/plat-omap/include/plat/omap850.h [moved from arch/arm/plat-omap/include/mach/omap850.h with 100% similarity]
arch/arm/plat-omap/include/plat/omap_device.h [moved from arch/arm/plat-omap/include/mach/omap_device.h with 99% similarity]
arch/arm/plat-omap/include/plat/omap_hwmod.h [moved from arch/arm/plat-omap/include/mach/omap_hwmod.h with 99% similarity]
arch/arm/plat-omap/include/plat/omapfb.h [moved from arch/arm/plat-omap/include/mach/omapfb.h with 99% similarity]
arch/arm/plat-omap/include/plat/onenand.h [moved from arch/arm/plat-omap/include/mach/onenand.h with 100% similarity]
arch/arm/plat-omap/include/plat/param.h [moved from arch/arm/plat-omap/include/mach/param.h with 100% similarity]
arch/arm/plat-omap/include/plat/powerdomain.h [moved from arch/arm/plat-omap/include/mach/powerdomain.h with 99% similarity]
arch/arm/plat-omap/include/plat/prcm.h [moved from arch/arm/plat-omap/include/mach/prcm.h with 89% similarity]
arch/arm/plat-omap/include/plat/sdrc.h [moved from arch/arm/plat-omap/include/mach/sdrc.h with 89% similarity]
arch/arm/plat-omap/include/plat/serial.h [moved from arch/arm/plat-omap/include/mach/serial.h with 94% similarity]
arch/arm/plat-omap/include/plat/smp.h [moved from arch/arm/plat-omap/include/mach/smp.h with 100% similarity]
arch/arm/plat-omap/include/plat/sram.h [moved from arch/arm/plat-omap/include/mach/sram.h with 93% similarity]
arch/arm/plat-omap/include/plat/system.h [moved from arch/arm/plat-omap/include/mach/system.h with 97% similarity]
arch/arm/plat-omap/include/plat/tc.h [moved from arch/arm/plat-omap/include/mach/tc.h with 100% similarity]
arch/arm/plat-omap/include/plat/timer-gp.h [moved from arch/arm/plat-omap/include/mach/timer-gp.h with 100% similarity]
arch/arm/plat-omap/include/plat/timex.h [moved from arch/arm/plat-omap/include/mach/timex.h with 100% similarity]
arch/arm/plat-omap/include/plat/uncompress.h [moved from arch/arm/plat-omap/include/mach/uncompress.h with 90% similarity]
arch/arm/plat-omap/include/plat/usb.h [moved from arch/arm/plat-omap/include/mach/usb.h with 90% similarity]
arch/arm/plat-omap/io.c
arch/arm/plat-omap/iommu-debug.c
arch/arm/plat-omap/iommu.c
arch/arm/plat-omap/iovmm.c
arch/arm/plat-omap/mailbox.c
arch/arm/plat-omap/mcbsp.c
arch/arm/plat-omap/mux.c
arch/arm/plat-omap/omap-pm-noop.c
arch/arm/plat-omap/omap_device.c
arch/arm/plat-omap/sram.c
arch/arm/plat-omap/usb.c
arch/arm/plat-pxa/include/plat/pxa3xx_nand.h [moved from arch/arm/mach-pxa/include/mach/pxa3xx_nand.h with 100% similarity]
arch/arm/plat-s3c/Kconfig
arch/arm/plat-s3c/Makefile
arch/arm/plat-s3c/clock.c
arch/arm/plat-s3c/dev-hsmmc2.c [new file with mode: 0644]
arch/arm/plat-s3c/dev-i2c0.c
arch/arm/plat-s3c/dev-i2c1.c
arch/arm/plat-s3c/dev-nand.c
arch/arm/plat-s3c/dma.c
arch/arm/plat-s3c/include/plat/audio-simtec.h
arch/arm/plat-s3c/include/plat/audio.h
arch/arm/plat-s3c/include/plat/cpu-freq.h
arch/arm/plat-s3c/include/plat/cpu.h
arch/arm/plat-s3c/include/plat/devs.h
arch/arm/plat-s3c/include/plat/dma.h
arch/arm/plat-s3c/include/plat/fb.h
arch/arm/plat-s3c/include/plat/iic.h
arch/arm/plat-s3c/include/plat/nand.h
arch/arm/plat-s3c/include/plat/regs-fb-v4.h [new file with mode: 0644]
arch/arm/plat-s3c/include/plat/regs-nand.h
arch/arm/plat-s3c/include/plat/regs-s3c2412-iis.h
arch/arm/plat-s3c/include/plat/regs-serial.h
arch/arm/plat-s3c/include/plat/sdhci.h
arch/arm/plat-s3c/pm-check.c
arch/arm/plat-s3c/pm.c
arch/arm/plat-s3c24xx/Kconfig
arch/arm/plat-s3c24xx/Makefile
arch/arm/plat-s3c24xx/clock-dclk.c
arch/arm/plat-s3c24xx/common-smdk.c
arch/arm/plat-s3c24xx/cpu-freq.c
arch/arm/plat-s3c24xx/dma.c
arch/arm/plat-s3c24xx/include/plat/cpu-freq-core.h
arch/arm/plat-s3c24xx/include/plat/mci.h
arch/arm/plat-s3c24xx/include/plat/regs-dma.h
arch/arm/plat-s3c24xx/irq-pm.c
arch/arm/plat-s3c24xx/irq.c
arch/arm/plat-s3c24xx/pm-simtec.c
arch/arm/plat-s3c24xx/pm.c
arch/arm/plat-s3c24xx/s3c2410-iotiming.c
arch/arm/plat-s3c24xx/s3c2412-iotiming.c
arch/arm/plat-s3c24xx/s3c2440-cpufreq.c
arch/arm/plat-s3c24xx/s3c2440-pll-12000000.c
arch/arm/plat-s3c24xx/s3c244x-clock.c
arch/arm/plat-s3c24xx/s3c244x-irq.c
arch/arm/plat-s3c24xx/simtec-audio.c [new file with mode: 0644]
arch/arm/plat-s3c64xx/cpu.c
arch/arm/plat-s3c64xx/cpufreq.c
arch/arm/plat-s3c64xx/dev-audio.c
arch/arm/plat-s3c64xx/gpiolib.c
arch/arm/plat-s3c64xx/include/plat/gpio-bank-c.h
arch/arm/plat-s3c64xx/irq-eint.c
arch/arm/plat-s3c64xx/setup-sdhci-gpio.c
arch/arm/plat-s5pc1xx/Kconfig
arch/arm/plat-s5pc1xx/Makefile
arch/arm/plat-s5pc1xx/clock.c [new file with mode: 0644]
arch/arm/plat-s5pc1xx/cpu.c
arch/arm/plat-s5pc1xx/gpio-config.c [new file with mode: 0644]
arch/arm/plat-s5pc1xx/gpiolib.c [new file with mode: 0644]
arch/arm/plat-s5pc1xx/include/plat/gpio-cfg-s5pc1xx.h [new file with mode: 0644]
arch/arm/plat-s5pc1xx/include/plat/gpio-ext.h [new file with mode: 0644]
arch/arm/plat-s5pc1xx/include/plat/irqs.h
arch/arm/plat-s5pc1xx/include/plat/regs-clock.h
arch/arm/plat-s5pc1xx/include/plat/regs-gpio.h [new file with mode: 0644]
arch/arm/plat-s5pc1xx/include/plat/regs-power.h [new file with mode: 0644]
arch/arm/plat-s5pc1xx/include/plat/s5pc100.h
arch/arm/plat-s5pc1xx/irq-eint.c [new file with mode: 0644]
arch/arm/plat-s5pc1xx/irq-gpio.c [new file with mode: 0644]
arch/arm/plat-s5pc1xx/irq.c
arch/arm/plat-s5pc1xx/s5pc100-clock.c
arch/arm/plat-s5pc1xx/setup-fb-24bpp.c [new file with mode: 0644]
arch/arm/plat-s5pc1xx/setup-i2c0.c
arch/arm/plat-s5pc1xx/setup-i2c1.c
arch/arm/plat-s5pc1xx/setup-sdhci-gpio.c [new file with mode: 0644]
arch/arm/plat-samsung/Kconfig [new file with mode: 0644]
arch/arm/plat-samsung/Makefile [new file with mode: 0644]
arch/avr32/Kconfig
arch/avr32/include/asm/cacheflush.h
arch/blackfin/include/asm/cacheflush.h
arch/cris/include/asm/cacheflush.h
arch/frv/include/asm/cacheflush.h
arch/frv/kernel/pm.c
arch/frv/kernel/sysctl.c
arch/h8300/include/asm/cacheflush.h
arch/ia64/ia32/ia32_entry.S
arch/ia64/ia32/sys_ia32.c
arch/ia64/include/asm/cacheflush.h
arch/ia64/include/asm/kvm.h
arch/ia64/include/asm/kvm_host.h
arch/ia64/kernel/crash.c
arch/ia64/kernel/perfmon.c
arch/ia64/kvm/Makefile
arch/ia64/kvm/kvm-ia64.c
arch/m32r/include/asm/cacheflush.h
arch/m68k/include/asm/cacheflush_mm.h
arch/m68k/include/asm/cacheflush_no.h
arch/m68k/include/asm/ptrace.h
arch/m68k/include/asm/thread_info_mm.h
arch/m68k/kernel/entry.S
arch/m68k/kernel/process.c
arch/m68k/kernel/ptrace.c
arch/m68k/kernel/vmlinux-std.lds
arch/m68k/kernel/vmlinux-sun3.lds
arch/m68knommu/kernel/ptrace.c
arch/microblaze/include/asm/cacheflush.h
arch/microblaze/include/asm/prom.h
arch/microblaze/kernel/head.S
arch/microblaze/kernel/prom.c
arch/mips/include/asm/cacheflush.h
arch/mips/kernel/linux32.c
arch/mips/kernel/scall64-n32.S
arch/mips/kernel/scall64-o32.S
arch/mips/lasat/sysctl.c
arch/mn10300/include/asm/cacheflush.h
arch/parisc/include/asm/cacheflush.h
arch/parisc/kernel/sys_parisc32.c
arch/parisc/kernel/syscall_table.S
arch/powerpc/Kconfig.debug
arch/powerpc/configs/pseries_defconfig
arch/powerpc/include/asm/cacheflush.h
arch/powerpc/include/asm/emulated_ops.h
arch/powerpc/include/asm/hvcall.h
arch/powerpc/include/asm/pmac_low_i2c.h
arch/powerpc/include/asm/prom.h
arch/powerpc/include/asm/reg.h
arch/powerpc/include/asm/trace.h [new file with mode: 0644]
arch/powerpc/kernel/align.c
arch/powerpc/kernel/entry_64.S
arch/powerpc/kernel/exceptions-64s.S
arch/powerpc/kernel/idle.c
arch/powerpc/kernel/irq.c
arch/powerpc/kernel/perf_event.c
arch/powerpc/kernel/power5+-pmu.c
arch/powerpc/kernel/power5-pmu.c
arch/powerpc/kernel/power6-pmu.c
arch/powerpc/kernel/power7-pmu.c
arch/powerpc/kernel/ppc970-pmu.c
arch/powerpc/kernel/prom.c
arch/powerpc/kernel/setup-common.c
arch/powerpc/kernel/sys_ppc32.c
arch/powerpc/kernel/time.c
arch/powerpc/kernel/traps.c
arch/powerpc/kvm/powerpc.c
arch/powerpc/kvm/timing.h
arch/powerpc/lib/copypage_64.S
arch/powerpc/platforms/powermac/low_i2c.c
arch/powerpc/platforms/pseries/hvCall.S
arch/powerpc/platforms/pseries/hvCall_inst.c
arch/powerpc/platforms/pseries/lpar.c
arch/s390/appldata/appldata_base.c
arch/s390/include/asm/cacheflush.h
arch/s390/include/asm/kvm.h
arch/s390/kernel/compat_linux.c
arch/s390/kernel/compat_linux.h
arch/s390/kernel/compat_wrapper.S
arch/s390/kernel/debug.c
arch/s390/kvm/kvm-s390.c
arch/s390/kvm/sigp.c
arch/s390/mm/cmm.c
arch/score/include/asm/cacheflush.h
arch/sh/boards/mach-hp6xx/setup.c
arch/sh/boards/mach-se/7724/setup.c
arch/sh/include/asm/cacheflush.h
arch/sh/include/mach-common/mach/hp6xx.h
arch/sh/kernel/traps_64.c
arch/sparc/Kconfig
arch/sparc/Makefile
arch/sparc/include/asm/btext.h [new file with mode: 0644]
arch/sparc/include/asm/cacheflush_32.h
arch/sparc/include/asm/cacheflush_64.h
arch/sparc/include/asm/leon.h
arch/sparc/include/asm/prom.h
arch/sparc/include/asm/rwsem.h
arch/sparc/include/asm/smp_32.h
arch/sparc/kernel/Makefile
arch/sparc/kernel/apc.c
arch/sparc/kernel/auxio_32.c
arch/sparc/kernel/btext.c [new file with mode: 0644]
arch/sparc/kernel/cpu.c
arch/sparc/kernel/entry.S
arch/sparc/kernel/head_32.S
arch/sparc/kernel/ioport.c
arch/sparc/kernel/irq_64.c
arch/sparc/kernel/leon_kernel.c
arch/sparc/kernel/leon_smp.c [new file with mode: 0644]
arch/sparc/kernel/pci_msi.c
arch/sparc/kernel/setup_64.c
arch/sparc/kernel/smp_32.c
arch/sparc/kernel/sys_sparc32.c
arch/sparc/kernel/systbls_64.S
arch/sparc/kernel/time_32.c
arch/sparc/kernel/trampoline_32.S
arch/sparc/mm/srmmu.c
arch/x86/Kconfig
arch/x86/Kconfig.cpu
arch/x86/Kconfig.debug
arch/x86/Makefile
arch/x86/Makefile_32.cpu
arch/x86/ia32/ia32entry.S
arch/x86/ia32/sys_ia32.c
arch/x86/include/asm/Kbuild
arch/x86/include/asm/a.out-core.h
arch/x86/include/asm/alternative-asm.h
arch/x86/include/asm/alternative.h
arch/x86/include/asm/apic.h
arch/x86/include/asm/apicdef.h
arch/x86/include/asm/apicnum.h [deleted file]
arch/x86/include/asm/cacheflush.h
arch/x86/include/asm/cmpxchg_32.h
arch/x86/include/asm/cmpxchg_64.h
arch/x86/include/asm/debugreg.h
arch/x86/include/asm/hardirq.h
arch/x86/include/asm/hw_breakpoint.h [new file with mode: 0644]
arch/x86/include/asm/hw_irq.h
arch/x86/include/asm/inat.h [new file with mode: 0644]
arch/x86/include/asm/inat_types.h [new file with mode: 0644]
arch/x86/include/asm/insn.h [new file with mode: 0644]
arch/x86/include/asm/irq.h
arch/x86/include/asm/kvm.h
arch/x86/include/asm/kvm_emulate.h
arch/x86/include/asm/kvm_host.h
arch/x86/include/asm/mce.h
arch/x86/include/asm/mpspec.h
arch/x86/include/asm/msr.h
arch/x86/include/asm/perf_event.h
arch/x86/include/asm/processor.h
arch/x86/include/asm/ptrace.h
arch/x86/include/asm/string_32.h
arch/x86/include/asm/svm.h
arch/x86/include/asm/sys_ia32.h
arch/x86/include/asm/system.h
arch/x86/include/asm/thread_info.h
arch/x86/include/asm/uaccess.h
arch/x86/include/asm/uaccess_32.h
arch/x86/include/asm/uaccess_64.h
arch/x86/include/asm/uv/uv_irq.h
arch/x86/include/asm/vmx.h
arch/x86/kernel/Makefile
arch/x86/kernel/apic/Makefile
arch/x86/kernel/apic/apic.c
arch/x86/kernel/apic/apic_noop.c [new file with mode: 0644]
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/nmi.c
arch/x86/kernel/apic/numaq_32.c
arch/x86/kernel/apic/probe_32.c
arch/x86/kernel/apic/summit_32.c
arch/x86/kernel/apic/x2apic_uv_x.c
arch/x86/kernel/apm_32.c
arch/x86/kernel/cpu/Makefile
arch/x86/kernel/cpu/amd.c
arch/x86/kernel/cpu/centaur.c
arch/x86/kernel/cpu/common.c
arch/x86/kernel/cpu/cpu.h
arch/x86/kernel/cpu/cyrix.c
arch/x86/kernel/cpu/intel_cacheinfo.c
arch/x86/kernel/cpu/mcheck/mce.c
arch/x86/kernel/cpu/mcheck/therm_throt.c
arch/x86/kernel/cpu/perf_event.c
arch/x86/kernel/cpu/perfctr-watchdog.c
arch/x86/kernel/cpu/transmeta.c
arch/x86/kernel/cpuid.c
arch/x86/kernel/dumpstack.c
arch/x86/kernel/dumpstack_32.c
arch/x86/kernel/dumpstack_64.c
arch/x86/kernel/entry_32.S
arch/x86/kernel/entry_64.S
arch/x86/kernel/head_64.S
arch/x86/kernel/hw_breakpoint.c [new file with mode: 0644]
arch/x86/kernel/irq.c
arch/x86/kernel/irq_32.c
arch/x86/kernel/irq_64.c
arch/x86/kernel/kgdb.c
arch/x86/kernel/kprobes.c
arch/x86/kernel/machine_kexec_32.c
arch/x86/kernel/machine_kexec_64.c
arch/x86/kernel/microcode_core.c
arch/x86/kernel/msr.c
arch/x86/kernel/process.c
arch/x86/kernel/process_32.c
arch/x86/kernel/process_64.c
arch/x86/kernel/ptrace.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_sync.c
arch/x86/kernel/uv_irq.c
arch/x86/kernel/visws_quirks.c
arch/x86/kernel/vsyscall_64.c
arch/x86/kernel/x8664_ksyms_64.c
arch/x86/kvm/Kconfig
arch/x86/kvm/Makefile
arch/x86/kvm/emulate.c
arch/x86/kvm/i8254.c
arch/x86/kvm/i8259.c
arch/x86/kvm/irq.h
arch/x86/kvm/lapic.c
arch/x86/kvm/mmu.c
arch/x86/kvm/paging_tmpl.h
arch/x86/kvm/svm.c
arch/x86/kvm/trace.h
arch/x86/kvm/vmx.c
arch/x86/kvm/x86.c
arch/x86/lib/.gitignore [new file with mode: 0644]
arch/x86/lib/Makefile
arch/x86/lib/copy_user_64.S
arch/x86/lib/inat.c [new file with mode: 0644]
arch/x86/lib/insn.c [new file with mode: 0644]
arch/x86/lib/msr.c
arch/x86/lib/usercopy_32.c
arch/x86/lib/x86-opcode-map.txt [new file with mode: 0644]
arch/x86/mm/extable.c
arch/x86/mm/fault.c
arch/x86/mm/kmmio.c
arch/x86/mm/srat_64.c
arch/x86/power/cpu.c
arch/x86/tools/Makefile [new file with mode: 0644]
arch/x86/tools/chkobjdump.awk [new file with mode: 0644]
arch/x86/tools/distill.awk [new file with mode: 0644]
arch/x86/tools/gen-insn-attr-x86.awk [new file with mode: 0644]
arch/x86/tools/test_get_len.c [new file with mode: 0644]
arch/x86/vdso/vdso32-setup.c
arch/xtensa/include/asm/cacheflush.h
block/Kconfig
block/Kconfig.iosched
block/Makefile
block/as-iosched.c [deleted file]
block/blk-cgroup.c [new file with mode: 0644]
block/blk-cgroup.h [new file with mode: 0644]
block/blk-core.c
block/blk-ioc.c
block/blk-settings.c
block/blk-sysfs.c
block/bsg.c
block/cfq-iosched.c
block/compat_ioctl.c
block/elevator.c
block/genhd.c
block/ioctl.c
block/scsi_ioctl.c
crypto/proc.c
drivers/ata/Kconfig
drivers/ata/Makefile
drivers/ata/ahci.c
drivers/ata/ata_generic.c
drivers/ata/ata_piix.c
drivers/ata/libata-acpi.c
drivers/ata/libata-core.c
drivers/ata/libata-eh.c
drivers/ata/libata-scsi.c
drivers/ata/libata-sff.c
drivers/ata/pata_ali.c
drivers/ata/pata_cmd64x.c
drivers/ata/pata_cs5520.c
drivers/ata/pata_cs5536.c
drivers/ata/pata_efar.c
drivers/ata/pata_hpt366.c
drivers/ata/pata_hpt37x.c
drivers/ata/pata_hpt3x2n.c
drivers/ata/pata_hpt3x3.c
drivers/ata/pata_it8213.c
drivers/ata/pata_it821x.c
drivers/ata/pata_legacy.c
drivers/ata/pata_marvell.c
drivers/ata/pata_ns87415.c
drivers/ata/pata_oldpiix.c
drivers/ata/pata_piccolo.c [new file with mode: 0644]
drivers/ata/pata_radisys.c
drivers/ata/pata_rdc.c
drivers/ata/pata_rz1000.c
drivers/ata/pata_sil680.c
drivers/ata/pata_sis.c
drivers/ata/pata_via.c
drivers/ata/sata_fsl.c
drivers/ata/sata_mv.c
drivers/ata/sata_sil24.c
drivers/base/power/runtime.c
drivers/block/Kconfig
drivers/block/Makefile
drivers/block/cciss.c
drivers/block/cciss.h
drivers/block/cciss_cmd.h
drivers/block/cciss_scsi.c
drivers/block/drbd/Kconfig [new file with mode: 0644]
drivers/block/drbd/Makefile [new file with mode: 0644]
drivers/block/drbd/drbd_actlog.c [new file with mode: 0644]
drivers/block/drbd/drbd_bitmap.c [new file with mode: 0644]
drivers/block/drbd/drbd_int.h [new file with mode: 0644]
drivers/block/drbd/drbd_main.c [new file with mode: 0644]
drivers/block/drbd/drbd_nl.c [new file with mode: 0644]
drivers/block/drbd/drbd_proc.c [new file with mode: 0644]
drivers/block/drbd/drbd_receiver.c [new file with mode: 0644]
drivers/block/drbd/drbd_req.c [new file with mode: 0644]
drivers/block/drbd/drbd_req.h [new file with mode: 0644]
drivers/block/drbd/drbd_strings.c [new file with mode: 0644]
drivers/block/drbd/drbd_vli.h [new file with mode: 0644]
drivers/block/drbd/drbd_worker.c [new file with mode: 0644]
drivers/block/drbd/drbd_wrappers.h [new file with mode: 0644]
drivers/block/ps3vram.c
drivers/cdrom/cdrom.c
drivers/char/hpet.c
drivers/char/ipmi/ipmi_poweroff.c
drivers/char/pty.c
drivers/char/random.c
drivers/char/rtc.c
drivers/dio/dio-driver.c
drivers/dma/Kconfig
drivers/edac/edac_mce_amd.c
drivers/firewire/core-card.c
drivers/firewire/core-cdev.c
drivers/firewire/core-topology.c
drivers/firewire/core-transaction.c
drivers/firewire/core.h
drivers/firewire/ohci.c
drivers/firewire/sbp2.c
drivers/i2c/Kconfig
drivers/i2c/busses/Kconfig
drivers/i2c/busses/Makefile
drivers/i2c/busses/i2c-ali1535.c
drivers/i2c/busses/i2c-ali15x3.c
drivers/i2c/busses/i2c-i801.c
drivers/i2c/busses/i2c-iop3xx.c
drivers/i2c/busses/i2c-mv64xxx.c
drivers/i2c/busses/i2c-powermac.c
drivers/i2c/busses/i2c-sis5595.c
drivers/i2c/busses/i2c-sis630.c
drivers/i2c/busses/i2c-stub.c
drivers/i2c/busses/i2c-voodoo3.c [deleted file]
drivers/i2c/chips/Kconfig
drivers/i2c/chips/Makefile
drivers/i2c/i2c-core.c
drivers/i2c/i2c-dev.c
drivers/ide/ide-pci-generic.c
drivers/ieee1394/ohci1394.c
drivers/input/keyboard/omap-keypad.c
drivers/leds/leds-ams-delta.c
drivers/leds/leds-locomo.c
drivers/macintosh/mac_hid.c
drivers/md/md.c
drivers/media/radio/Kconfig
drivers/media/radio/Makefile
drivers/media/radio/radio-miropcm20.c [new file with mode: 0644]
drivers/mfd/Kconfig
drivers/mfd/Makefile
drivers/mfd/mcp-core.c
drivers/mfd/mcp-sa11x0.c
drivers/mfd/menelaus.c
drivers/mfd/twl4030-codec.c [new file with mode: 0644]
drivers/mfd/twl4030-core.c
drivers/mfd/ucb1x00-assabet.c
drivers/mfd/ucb1x00-core.c
drivers/mfd/ucb1x00-ts.c
drivers/misc/Kconfig
drivers/misc/Makefile
drivers/misc/ds1682.c [moved from drivers/i2c/chips/ds1682.c with 100% similarity]
drivers/misc/ics932s401.c
drivers/misc/sgi-xp/xpc_main.c
drivers/misc/sgi-xp/xpc_uv.c
drivers/mmc/host/mmci.c
drivers/mmc/host/omap.c
drivers/mmc/host/omap_hsmmc.c
drivers/mmc/host/pxamci.c
drivers/mtd/maps/omap_nor.c
drivers/mtd/mtd_blkdevs.c
drivers/mtd/nand/Kconfig
drivers/mtd/nand/ams-delta.c
drivers/mtd/nand/omap2.c
drivers/mtd/nand/pxa3xx_nand.c
drivers/mtd/onenand/omap2.c
drivers/of/base.c
drivers/parport/parport_mfc3.c
drivers/parport/procfs.c
drivers/pcmcia/Kconfig
drivers/pcmcia/omap_cf.c
drivers/pcmcia/sa1100_generic.c
drivers/pcmcia/sa1100_h3600.c
drivers/power/Kconfig
drivers/power/Makefile
drivers/power/collie_battery.c [new file with mode: 0644]
drivers/rtc/Kconfig
drivers/rtc/Makefile
drivers/rtc/rtc-msm6242.c [new file with mode: 0644]
drivers/rtc/rtc-rp5c01.c [new file with mode: 0644]
drivers/s390/char/sclp_async.c
drivers/scsi/scsi_sysctl.c
drivers/serial/Kconfig
drivers/serial/Makefile
drivers/serial/apbuart.c [new file with mode: 0644]
drivers/serial/apbuart.h [new file with mode: 0644]
drivers/serial/s3c2410.c
drivers/serial/s3c2412.c
drivers/serial/s3c2440.c
drivers/serial/s3c24a0.c
drivers/serial/samsung.c
drivers/serial/samsung.h
drivers/spi/omap2_mcspi.c
drivers/spi/omap_uwire.c
drivers/staging/arlan/arlan-proc.c
drivers/staging/pohmelfs/inode.c
drivers/usb/gadget/omap_udc.c
drivers/usb/host/ohci-omap.c
drivers/usb/musb/omap2430.c
drivers/usb/musb/omap2430.h
drivers/usb/musb/tusb6010_omap.c
drivers/usb/otg/isp1301_omap.c
drivers/video/Kconfig
drivers/video/atafb.c
drivers/video/backlight/da903x_bl.c
drivers/video/backlight/omap1_bl.c
drivers/video/backlight/tdo24m.c
drivers/video/omap/Makefile
drivers/video/omap/blizzard.c
drivers/video/omap/dispc.c
drivers/video/omap/hwa742.c
drivers/video/omap/lcd_2430sdp.c
drivers/video/omap/lcd_ams_delta.c
drivers/video/omap/lcd_apollon.c
drivers/video/omap/lcd_h3.c
drivers/video/omap/lcd_h4.c
drivers/video/omap/lcd_htcherald.c [new file with mode: 0644]
drivers/video/omap/lcd_inn1510.c
drivers/video/omap/lcd_inn1610.c
drivers/video/omap/lcd_ldp.c
drivers/video/omap/lcd_mipid.c
drivers/video/omap/lcd_omap2evm.c
drivers/video/omap/lcd_omap3beagle.c
drivers/video/omap/lcd_omap3evm.c
drivers/video/omap/lcd_osk.c
drivers/video/omap/lcd_overo.c
drivers/video/omap/lcd_palmte.c
drivers/video/omap/lcd_palmtt.c
drivers/video/omap/lcd_palmz71.c
drivers/video/omap/lcdc.c
drivers/video/omap/omapfb_main.c
drivers/video/omap/rfbi.c
drivers/video/omap/sossi.c
drivers/video/pxa168fb.c
drivers/video/pxafb.c
drivers/watchdog/omap_wdt.c
drivers/watchdog/riowd.c
drivers/zorro/zorro-driver.c
fs/aio.c
fs/bio.c
fs/block_dev.c
fs/coda/sysctl.c
fs/direct-io.c
fs/eventpoll.c
fs/fs-writeback.c
fs/lockd/svc.c
fs/nfs/sysctl.c
fs/nfs/write.c
fs/notify/inotify/inotify_user.c
fs/ntfs/sysctl.c
fs/ocfs2/stackglue.c
fs/partitions/check.c
fs/partitions/efi.c
fs/partitions/efi.h
fs/proc/array.c
fs/proc/proc_sysctl.c
fs/proc/stat.c
fs/quota/dquot.c
fs/read_write.c
fs/splice.c
fs/xfs/linux-2.6/xfs_aops.c
fs/xfs/linux-2.6/xfs_sysctl.c
include/asm-generic/cacheflush.h
include/linux/ata.h
include/linux/backing-dev.h
include/linux/bio.h
include/linux/blkdev.h
include/linux/cgroup_subsys.h
include/linux/compiler-gcc4.h
include/linux/compiler.h
include/linux/connector.h
include/linux/drbd.h [new file with mode: 0644]
include/linux/drbd_limits.h [new file with mode: 0644]
include/linux/drbd_nl.h [new file with mode: 0644]
include/linux/drbd_tag_magic.h [new file with mode: 0644]
include/linux/firewire.h
include/linux/fs.h
include/linux/ftrace_event.h
include/linux/genhd.h
include/linux/hw_breakpoint.h [new file with mode: 0644]
include/linux/i2c.h
include/linux/i2c/twl4030.h
include/linux/input.h
include/linux/iocontext.h
include/linux/jiffies.h
include/linux/kernel_stat.h
include/linux/kprobes.h
include/linux/kvm.h
include/linux/kvm_host.h
include/linux/libata.h
include/linux/lru_cache.h [new file with mode: 0644]
include/linux/mfd/da903x.h
include/linux/mfd/mcp.h [moved from drivers/mfd/mcp.h with 97% similarity]
include/linux/mfd/twl4030-codec.h [new file with mode: 0644]
include/linux/mfd/ucb1x00.h [moved from drivers/mfd/ucb1x00.h with 98% similarity]
include/linux/of.h
include/linux/of_fdt.h [new file with mode: 0644]
include/linux/pci_ids.h
include/linux/perf_counter.h
include/linux/perf_event.h
include/linux/pm.h
include/linux/pm_runtime.h
include/linux/preempt.h
include/linux/sched.h
include/linux/serial_core.h
include/linux/syscalls.h
include/linux/sysctl.h
include/linux/tracepoint.h
include/linux/user-return-notifier.h [new file with mode: 0644]
include/linux/writeback.h
include/net/dn_dev.h
include/net/neighbour.h
include/sound/Kbuild
include/sound/aci.h [moved from sound/isa/opti9xx/miro.h with 85% similarity]
include/sound/ak4113.h [new file with mode: 0644]
include/sound/ak4114.h
include/sound/ak4xxx-adda.h
include/sound/control.h
include/sound/cs4231-regs.h
include/sound/pcm.h
include/sound/rawmidi.h
include/sound/sh_dac_audio.h [new file with mode: 0644]
include/sound/soc-dai.h
include/sound/soc-dapm.h
include/sound/soc.h
include/sound/sscape_ioctl.h [deleted file]
include/sound/tlv320dac33-plat.h [new file with mode: 0644]
include/sound/tpa6130a2-plat.h [new file with mode: 0644]
include/sound/wss.h
include/trace/define_trace.h
include/trace/events/bkl.h
include/trace/events/block.h
include/trace/events/ext4.h
include/trace/events/irq.h
include/trace/events/jbd2.h
include/trace/events/kmem.h
include/trace/events/lock.h [moved from include/trace/events/lockdep.h with 92% similarity]
include/trace/events/mce.h [new file with mode: 0644]
include/trace/events/module.h
include/trace/events/power.h
include/trace/events/sched.h
include/trace/events/signal.h [new file with mode: 0644]
include/trace/events/timer.h
include/trace/events/workqueue.h
include/trace/ftrace.h
include/trace/syscall.h
include/video/pxa168fb.h
init/Kconfig
ipc/ipc_sysctl.c
ipc/mq_sysctl.c
kernel/Makefile
kernel/cpuset.c
kernel/exit.c
kernel/fork.c
kernel/hw_breakpoint.c [new file with mode: 0644]
kernel/kallsyms.c
kernel/kgdb.c
kernel/kprobes.c
kernel/lockdep.c
kernel/notifier.c
kernel/perf_event.c
kernel/power/Makefile
kernel/power/hibernate.c
kernel/power/main.c
kernel/power/process.c
kernel/power/swap.c
kernel/power/swsusp.c
kernel/sched.c
kernel/sched_debug.c
kernel/sched_fair.c
kernel/sched_rt.c
kernel/signal.c
kernel/slow-work.c
kernel/sys.c
kernel/sys_ni.c
kernel/sysctl.c
kernel/sysctl_binary.c [new file with mode: 0644]
kernel/sysctl_check.c
kernel/time.c
kernel/trace/Kconfig
kernel/trace/Makefile
kernel/trace/ring_buffer.c
kernel/trace/trace.h
kernel/trace/trace_entries.h
kernel/trace/trace_event_profile.c
kernel/trace/trace_events.c
kernel/trace/trace_events_filter.c
kernel/trace/trace_export.c
kernel/trace/trace_kprobe.c [new file with mode: 0644]
kernel/trace/trace_ksym.c [new file with mode: 0644]
kernel/trace/trace_selftest.c
kernel/trace/trace_syscalls.c
kernel/user-return-notifier.c [new file with mode: 0644]
kernel/utsname_sysctl.c
lib/Kconfig
lib/Kconfig.debug
lib/Makefile
lib/lru_cache.c [new file with mode: 0644]
mm/backing-dev.c
mm/page-writeback.c
net/802/tr.c
net/appletalk/sysctl_net_atalk.c
net/ax25/sysctl_net_ax25.c
net/bridge/br_netfilter.c
net/core/neighbour.c
net/core/sysctl_net_core.c
net/dccp/sysctl.c
net/decnet/dn_dev.c
net/decnet/sysctl_net_decnet.c
net/ipv4/arp.c
net/ipv4/devinet.c
net/ipv4/ip_fragment.c
net/ipv4/netfilter.c
net/ipv4/netfilter/ip_queue.c
net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
net/ipv4/netfilter/nf_conntrack_proto_icmp.c
net/ipv4/route.c
net/ipv4/sysctl_net_ipv4.c
net/ipv4/xfrm4_policy.c
net/ipv6/addrconf.c
net/ipv6/icmp.c
net/ipv6/ndisc.c
net/ipv6/netfilter/ip6_queue.c
net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c
net/ipv6/netfilter/nf_conntrack_reasm.c
net/ipv6/reassembly.c
net/ipv6/route.c
net/ipv6/sysctl_net_ipv6.c
net/ipv6/xfrm6_policy.c
net/ipx/sysctl_net_ipx.c
net/irda/irsysctl.c
net/llc/sysctl_net_llc.c
net/netfilter/core.c
net/netfilter/ipvs/ip_vs_ctl.c
net/netfilter/ipvs/ip_vs_lblc.c
net/netfilter/ipvs/ip_vs_lblcr.c
net/netfilter/nf_conntrack_acct.c
net/netfilter/nf_conntrack_ecache.c
net/netfilter/nf_conntrack_proto_dccp.c
net/netfilter/nf_conntrack_proto_generic.c
net/netfilter/nf_conntrack_proto_sctp.c
net/netfilter/nf_conntrack_proto_tcp.c
net/netfilter/nf_conntrack_proto_udp.c
net/netfilter/nf_conntrack_proto_udplite.c
net/netfilter/nf_conntrack_standalone.c
net/netfilter/nf_log.c
net/netrom/sysctl_net_netrom.c
net/phonet/sysctl.c
net/rds/ib_sysctl.c
net/rds/iw_sysctl.c
net/rds/sysctl.c
net/rose/sysctl_net_rose.c
net/sctp/sysctl.c
net/sunrpc/sysctl.c
net/sunrpc/xprtrdma/svc_rdma.c
net/sunrpc/xprtrdma/transport.c
net/sunrpc/xprtsock.c
net/unix/sysctl_net_unix.c
net/x25/sysctl_net_x25.c
net/xfrm/xfrm_sysctl.c
samples/Kconfig
samples/Makefile
samples/hw_breakpoint/Makefile [new file with mode: 0644]
samples/hw_breakpoint/data_breakpoint.c [new file with mode: 0644]
scripts/kernel-doc
security/keys/sysctl.c
security/tomoyo/file.c
security/tomoyo/realpath.c
security/tomoyo/tomoyo.c
security/tomoyo/tomoyo.h
sound/Kconfig
sound/arm/Makefile
sound/arm/aaci.c
sound/arm/devdma.c [deleted file]
sound/arm/devdma.h [deleted file]
sound/core/control.c
sound/core/isadma.c
sound/core/oss/mixer_oss.c
sound/core/pcm.c
sound/core/pcm_native.c
sound/core/rawmidi.c
sound/drivers/pcsp/pcsp.c
sound/drivers/pcsp/pcsp.h
sound/drivers/pcsp/pcsp_mixer.c
sound/i2c/cs8427.c
sound/i2c/other/Makefile
sound/i2c/other/ak4113.c [new file with mode: 0644]
sound/i2c/other/ak4xxx-adda.c
sound/i2c/other/tea575x-tuner.c
sound/isa/Kconfig
sound/isa/cmi8330.c
sound/isa/cs423x/cs4236.c
sound/isa/cs423x/cs4236_lib.c
sound/isa/es1688/es1688_lib.c
sound/isa/es18xx.c
sound/isa/opti9xx/miro.c
sound/isa/opti9xx/opti92x-ad1848.c
sound/isa/sb/sb_mixer.c
sound/isa/sscape.c
sound/isa/wss/wss_lib.c
sound/oss/Kconfig
sound/oss/Makefile
sound/oss/audio.c
sound/oss/midi_synth.c
sound/oss/mpu401.c
sound/oss/sh_dac_audio.c
sound/oss/sscape.c [deleted file]
sound/pci/Kconfig
sound/pci/ac97/ac97_codec.c
sound/pci/ac97/ac97_patch.c
sound/pci/azt3328.c
sound/pci/ca0106/ca0106_mixer.c
sound/pci/ca0106/ca0106_proc.c
sound/pci/cmipci.c
sound/pci/ctxfi/ctatc.c
sound/pci/emu10k1/emu10k1x.c
sound/pci/emu10k1/emumixer.c
sound/pci/emu10k1/emuproc.c
sound/pci/emu10k1/io.c
sound/pci/es1938.c
sound/pci/fm801.c
sound/pci/hda/Kconfig
sound/pci/hda/hda_beep.c
sound/pci/hda/hda_beep.h
sound/pci/hda/hda_codec.c
sound/pci/hda/hda_codec.h
sound/pci/hda/hda_eld.c
sound/pci/hda/hda_generic.c
sound/pci/hda/hda_hwdep.c
sound/pci/hda/hda_intel.c
sound/pci/hda/hda_local.h
sound/pci/hda/hda_proc.c
sound/pci/hda/patch_analog.c
sound/pci/hda/patch_ca0110.c
sound/pci/hda/patch_cirrus.c
sound/pci/hda/patch_cmedia.c
sound/pci/hda/patch_conexant.c
sound/pci/hda/patch_intelhdmi.c
sound/pci/hda/patch_realtek.c
sound/pci/hda/patch_sigmatel.c
sound/pci/hda/patch_via.c
sound/pci/ice1712/Makefile
sound/pci/ice1712/ice1712.c
sound/pci/ice1712/ice1712.h
sound/pci/ice1712/ice1724.c
sound/pci/ice1712/juli.c
sound/pci/ice1712/quartet.c [new file with mode: 0644]
sound/pci/ice1712/quartet.h [new file with mode: 0644]
sound/pci/intel8x0.c
sound/pci/oxygen/Makefile
sound/pci/oxygen/cs2000.h [new file with mode: 0644]
sound/pci/oxygen/hifier.c
sound/pci/oxygen/oxygen.c
sound/pci/oxygen/oxygen.h
sound/pci/oxygen/oxygen_lib.c
sound/pci/oxygen/oxygen_mixer.c
sound/pci/oxygen/oxygen_pcm.c
sound/pci/oxygen/virtuoso.c
sound/pci/oxygen/xonar.h [new file with mode: 0644]
sound/pci/oxygen/xonar_cs43xx.c [new file with mode: 0644]
sound/pci/oxygen/xonar_hdmi.c [new file with mode: 0644]
sound/pci/oxygen/xonar_lib.c [new file with mode: 0644]
sound/pci/oxygen/xonar_pcm179x.c [new file with mode: 0644]
sound/ppc/awacs.c
sound/ppc/burgundy.c
sound/ppc/tumbler.c
sound/sh/Kconfig
sound/sh/Makefile
sound/sh/sh_dac_audio.c [new file with mode: 0644]
sound/soc/Makefile
sound/soc/atmel/playpaq_wm8510.c
sound/soc/atmel/sam9g20_wm8731.c
sound/soc/au1x/dbdma2.c
sound/soc/au1x/psc-ac97.c
sound/soc/au1x/psc-i2s.c
sound/soc/au1x/psc.h
sound/soc/blackfin/bf5xx-ad1836.c
sound/soc/blackfin/bf5xx-ad1938.c
sound/soc/blackfin/bf5xx-i2s.c
sound/soc/blackfin/bf5xx-tdm-pcm.c
sound/soc/blackfin/bf5xx-tdm.c
sound/soc/blackfin/bf5xx-tdm.h
sound/soc/codecs/Kconfig
sound/soc/codecs/Makefile
sound/soc/codecs/ac97.c
sound/soc/codecs/ad1836.c
sound/soc/codecs/ad1938.c
sound/soc/codecs/ad1980.c
sound/soc/codecs/ad73311.c
sound/soc/codecs/ads117x.c [new file with mode: 0644]
sound/soc/codecs/ads117x.h [new file with mode: 0644]
sound/soc/codecs/ak4104.c
sound/soc/codecs/ak4535.c
sound/soc/codecs/ak4642.c
sound/soc/codecs/ak4671.c [new file with mode: 0644]
sound/soc/codecs/ak4671.h [new file with mode: 0644]
sound/soc/codecs/cs4270.c
sound/soc/codecs/cx20442.c
sound/soc/codecs/pcm3008.c
sound/soc/codecs/ssm2602.c
sound/soc/codecs/stac9766.c
sound/soc/codecs/tlv320aic23.c
sound/soc/codecs/tlv320aic26.c
sound/soc/codecs/tlv320aic3x.c
sound/soc/codecs/tlv320dac33.c [new file with mode: 0644]
sound/soc/codecs/tlv320dac33.h [new file with mode: 0644]
sound/soc/codecs/tpa6130a2.c [new file with mode: 0644]
sound/soc/codecs/tpa6130a2.h [new file with mode: 0644]
sound/soc/codecs/twl4030.c
sound/soc/codecs/twl4030.h
sound/soc/codecs/uda134x.c
sound/soc/codecs/uda1380.c
sound/soc/codecs/wm8350.c
sound/soc/codecs/wm8400.c
sound/soc/codecs/wm8510.c
sound/soc/codecs/wm8523.c
sound/soc/codecs/wm8580.c
sound/soc/codecs/wm8711.c [new file with mode: 0644]
sound/soc/codecs/wm8711.h [new file with mode: 0644]
sound/soc/codecs/wm8727.c [new file with mode: 0644]
sound/soc/codecs/wm8727.h [new file with mode: 0644]
sound/soc/codecs/wm8728.c
sound/soc/codecs/wm8731.c
sound/soc/codecs/wm8750.c
sound/soc/codecs/wm8753.c
sound/soc/codecs/wm8776.c
sound/soc/codecs/wm8900.c
sound/soc/codecs/wm8903.c
sound/soc/codecs/wm8940.c
sound/soc/codecs/wm8960.c
sound/soc/codecs/wm8961.c
sound/soc/codecs/wm8971.c
sound/soc/codecs/wm8974.c
sound/soc/codecs/wm8988.c
sound/soc/codecs/wm8990.c
sound/soc/codecs/wm8993.c
sound/soc/codecs/wm9081.c
sound/soc/codecs/wm9705.c
sound/soc/codecs/wm9712.c
sound/soc/codecs/wm9713.c
sound/soc/codecs/wm_hubs.c
sound/soc/codecs/wm_hubs.h
sound/soc/davinci/Kconfig
sound/soc/davinci/davinci-evm.c
sound/soc/davinci/davinci-i2s.c
sound/soc/davinci/davinci-mcasp.c
sound/soc/davinci/davinci-mcasp.h
sound/soc/davinci/davinci-pcm.c
sound/soc/davinci/davinci-pcm.h
sound/soc/fsl/mpc5200_dma.c
sound/soc/fsl/mpc5200_dma.h
sound/soc/fsl/mpc5200_psc_ac97.c
sound/soc/imx/mx27vis_wm8974.c
sound/soc/omap/Kconfig
sound/soc/omap/Makefile
sound/soc/omap/am3517evm.c [new file with mode: 0644]
sound/soc/omap/ams-delta.c
sound/soc/omap/igep0020.c [new file with mode: 0644]
sound/soc/omap/n810.c
sound/soc/omap/omap-mcbsp.c
sound/soc/omap/omap-pcm.c
sound/soc/omap/omap2evm.c
sound/soc/omap/omap3beagle.c
sound/soc/omap/omap3evm.c
sound/soc/omap/omap3pandora.c
sound/soc/omap/osk5912.c
sound/soc/omap/overo.c
sound/soc/omap/sdp3430.c
sound/soc/omap/zoom2.c
sound/soc/pxa/Kconfig
sound/soc/pxa/Makefile
sound/soc/pxa/magician.c
sound/soc/pxa/pxa-ssp.c
sound/soc/pxa/raumfeld.c [new file with mode: 0644]
sound/soc/pxa/zylonite.c
sound/soc/s3c24xx/Kconfig
sound/soc/s3c24xx/Makefile
sound/soc/s3c24xx/jive_wm8750.c
sound/soc/s3c24xx/ln2440sbc_alc650.c
sound/soc/s3c24xx/neo1973_gta02_wm8753.c
sound/soc/s3c24xx/neo1973_wm8753.c
sound/soc/s3c24xx/s3c-dma.c [moved from sound/soc/s3c24xx/s3c24xx-pcm.c with 82% similarity]
sound/soc/s3c24xx/s3c-dma.h [moved from sound/soc/s3c24xx/s3c24xx-pcm.h with 87% similarity]
sound/soc/s3c24xx/s3c-i2s-v2.c
sound/soc/s3c24xx/s3c-i2s-v2.h
sound/soc/s3c24xx/s3c-pcm.c [new file with mode: 0644]
sound/soc/s3c24xx/s3c-pcm.h [new file with mode: 0644]
sound/soc/s3c24xx/s3c2412-i2s.c
sound/soc/s3c24xx/s3c2443-ac97.c
sound/soc/s3c24xx/s3c24xx-i2s.c
sound/soc/s3c24xx/s3c24xx_simtec.c
sound/soc/s3c24xx/s3c24xx_simtec_hermes.c
sound/soc/s3c24xx/s3c24xx_simtec_tlv320aic23.c
sound/soc/s3c24xx/s3c24xx_uda134x.c
sound/soc/s3c24xx/s3c64xx-i2s.c
sound/soc/s3c24xx/s3c64xx-i2s.h
sound/soc/s3c24xx/smdk2443_wm9710.c
sound/soc/s3c24xx/smdk64xx_wm8580.c [new file with mode: 0644]
sound/soc/s6000/s6000-pcm.c
sound/soc/sh/Kconfig
sound/soc/sh/fsi.c
sound/soc/soc-cache.c
sound/soc/soc-core.c
sound/soc/soc-dapm.c
sound/soc/soc-jack.c
sound/soc/soc-utils.c [new file with mode: 0644]
sound/usb/usbaudio.c
sound/usb/usbaudio.h
sound/usb/usbmidi.c
sound/usb/usbmixer_maps.c
sound/usb/usbquirks.h
sound/usb/usx2y/us122l.c
sound/usb/usx2y/us122l.h
sound/usb/usx2y/usX2Yhwdep.c
sound/usb/usx2y/usbusx2y.c
sound/usb/usx2y/usbusx2y.h
sound/usb/usx2y/usbusx2yaudio.c
sound/usb/usx2y/usx2yhwdeppcm.c
tools/perf/.gitignore
tools/perf/Documentation/perf-bench.txt [new file with mode: 0644]
tools/perf/Documentation/perf-buildid-list.txt [new file with mode: 0644]
tools/perf/Documentation/perf-kmem.txt [new file with mode: 0644]
tools/perf/Documentation/perf-probe.txt [new file with mode: 0644]
tools/perf/Documentation/perf-record.txt
tools/perf/Documentation/perf-report.txt
tools/perf/Documentation/perf-timechart.txt
tools/perf/Documentation/perf-trace-perl.txt [new file with mode: 0644]
tools/perf/Documentation/perf-trace.txt
tools/perf/Makefile
tools/perf/bench/bench.h [new file with mode: 0644]
tools/perf/bench/mem-memcpy.c [new file with mode: 0644]
tools/perf/bench/sched-messaging.c [new file with mode: 0644]
tools/perf/bench/sched-pipe.c [new file with mode: 0644]
tools/perf/builtin-annotate.c
tools/perf/builtin-bench.c [new file with mode: 0644]
tools/perf/builtin-buildid-list.c [new file with mode: 0644]
tools/perf/builtin-help.c
tools/perf/builtin-kmem.c [new file with mode: 0644]
tools/perf/builtin-probe.c [new file with mode: 0644]
tools/perf/builtin-record.c
tools/perf/builtin-report.c
tools/perf/builtin-sched.c
tools/perf/builtin-stat.c
tools/perf/builtin-timechart.c
tools/perf/builtin-top.c
tools/perf/builtin-trace.c
tools/perf/builtin.h
tools/perf/command-list.txt
tools/perf/design.txt
tools/perf/perf.c
tools/perf/perf.h
tools/perf/scripts/perl/Perf-Trace-Util/Context.c [new file with mode: 0644]
tools/perf/scripts/perl/Perf-Trace-Util/Context.xs [new file with mode: 0644]
tools/perf/scripts/perl/Perf-Trace-Util/Makefile.PL [new file with mode: 0644]
tools/perf/scripts/perl/Perf-Trace-Util/README [new file with mode: 0644]
tools/perf/scripts/perl/Perf-Trace-Util/lib/Perf/Trace/Context.pm [new file with mode: 0644]
tools/perf/scripts/perl/Perf-Trace-Util/lib/Perf/Trace/Core.pm [new file with mode: 0644]
tools/perf/scripts/perl/Perf-Trace-Util/lib/Perf/Trace/Util.pm [new file with mode: 0644]
tools/perf/scripts/perl/Perf-Trace-Util/typemap [new file with mode: 0644]
tools/perf/scripts/perl/bin/check-perf-trace-record [new file with mode: 0644]
tools/perf/scripts/perl/bin/check-perf-trace-report [new file with mode: 0644]
tools/perf/scripts/perl/bin/rw-by-file-record [new file with mode: 0644]
tools/perf/scripts/perl/bin/rw-by-file-report [new file with mode: 0644]
tools/perf/scripts/perl/bin/rw-by-pid-record [new file with mode: 0644]
tools/perf/scripts/perl/bin/rw-by-pid-report [new file with mode: 0644]
tools/perf/scripts/perl/bin/wakeup-latency-record [new file with mode: 0644]
tools/perf/scripts/perl/bin/wakeup-latency-report [new file with mode: 0644]
tools/perf/scripts/perl/bin/workqueue-stats-record [new file with mode: 0644]
tools/perf/scripts/perl/bin/workqueue-stats-report [new file with mode: 0644]
tools/perf/scripts/perl/check-perf-trace.pl [new file with mode: 0644]
tools/perf/scripts/perl/rw-by-file.pl [new file with mode: 0644]
tools/perf/scripts/perl/rw-by-pid.pl [new file with mode: 0644]
tools/perf/scripts/perl/wakeup-latency.pl [new file with mode: 0644]
tools/perf/scripts/perl/workqueue-stats.pl [new file with mode: 0644]
tools/perf/util/cache.h
tools/perf/util/callchain.c
tools/perf/util/callchain.h
tools/perf/util/color.h
tools/perf/util/ctype.c
tools/perf/util/data_map.c [new file with mode: 0644]
tools/perf/util/data_map.h [new file with mode: 0644]
tools/perf/util/debug.c
tools/perf/util/debug.h
tools/perf/util/debugfs.c [new file with mode: 0644]
tools/perf/util/debugfs.h [new file with mode: 0644]
tools/perf/util/event.c [new file with mode: 0644]
tools/perf/util/event.h
tools/perf/util/exec_cmd.h
tools/perf/util/header.c
tools/perf/util/header.h
tools/perf/util/help.h
tools/perf/util/hist.c [new file with mode: 0644]
tools/perf/util/hist.h [new file with mode: 0644]
tools/perf/util/include/asm/asm-offsets.h [new file with mode: 0644]
tools/perf/util/include/asm/bitops.h [new file with mode: 0644]
tools/perf/util/include/asm/bug.h [new file with mode: 0644]
tools/perf/util/include/asm/byteorder.h [new file with mode: 0644]
tools/perf/util/include/asm/swab.h [new file with mode: 0644]
tools/perf/util/include/asm/uaccess.h [new file with mode: 0644]
tools/perf/util/include/linux/bitmap.h [new file with mode: 0644]
tools/perf/util/include/linux/bitops.h [new file with mode: 0644]
tools/perf/util/include/linux/compiler.h [new file with mode: 0644]
tools/perf/util/include/linux/ctype.h [new file with mode: 0644]
tools/perf/util/include/linux/kernel.h
tools/perf/util/include/linux/string.h [new file with mode: 0644]
tools/perf/util/include/linux/types.h [new file with mode: 0644]
tools/perf/util/levenshtein.h
tools/perf/util/map.c
tools/perf/util/module.c [deleted file]
tools/perf/util/module.h [deleted file]
tools/perf/util/parse-events.c
tools/perf/util/parse-events.h
tools/perf/util/parse-options.h
tools/perf/util/probe-event.c [new file with mode: 0644]
tools/perf/util/probe-event.h [new file with mode: 0644]
tools/perf/util/probe-finder.c [new file with mode: 0644]
tools/perf/util/probe-finder.h [new file with mode: 0644]
tools/perf/util/quote.h
tools/perf/util/run-command.h
tools/perf/util/sigchain.h
tools/perf/util/sort.c [new file with mode: 0644]
tools/perf/util/sort.h [new file with mode: 0644]
tools/perf/util/strbuf.h
tools/perf/util/string.c
tools/perf/util/string.h
tools/perf/util/strlist.h
tools/perf/util/svghelper.h
tools/perf/util/symbol.c
tools/perf/util/symbol.h
tools/perf/util/thread.c
tools/perf/util/thread.h
tools/perf/util/trace-event-info.c
tools/perf/util/trace-event-parse.c
tools/perf/util/trace-event-perl.c [new file with mode: 0644]
tools/perf/util/trace-event-perl.h [new file with mode: 0644]
tools/perf/util/trace-event-read.c
tools/perf/util/trace-event.h
tools/perf/util/types.h
tools/perf/util/util.h
tools/perf/util/values.h
tools/perf/util/wrapper.c
virt/kvm/assigned-dev.c [new file with mode: 0644]
virt/kvm/eventfd.c
virt/kvm/ioapic.c
virt/kvm/ioapic.h
virt/kvm/irq_comm.c
virt/kvm/kvm_main.c

index b0756d0..8bca1d5 100644 (file)
@@ -86,4 +86,9 @@
 !Iinclude/trace/events/irq.h
   </chapter>
 
+  <chapter id="signal">
+   <title>SIGNAL</title>
+!Iinclude/trace/events/signal.h
+  </chapter>
+
 </book>
index 26422f0..b87292e 100644 (file)
@@ -55,4 +55,4 @@ Maintainers
   This board is maintained by Simtec Electronics.
 
 
-(c) 2004 Ben Dooks, Simtec Electronics
+Copyright 2004 Ben Dooks, Simtec Electronics
index 948c871..2af2cf3 100644 (file)
@@ -134,4 +134,4 @@ Authour
 
 
 Ben Dooks, 03 October 2004
-(c) 2004 Ben Dooks, Simtec Electronics
+Copyright 2004 Ben Dooks, Simtec Electronics
index cff6227..081892d 100644 (file)
@@ -299,4 +299,4 @@ Port Contributors
 Document Author
 ---------------
 
-Ben Dooks, (c) 2004-2005,2006 Simtec Electronics
+Ben Dooks, Copyright 2004-2006 Simtec Electronics
index 295d971..f057876 100644 (file)
@@ -117,4 +117,4 @@ ATA
 Document Author
 ---------------
 
-Ben Dooks, (c) 2006 Simtec Electronics
+Ben Dooks, Copyright 2006 Simtec Electronics
index ab2a888..909bdc7 100644 (file)
@@ -18,4 +18,4 @@ Camera Interface
 Document Author
 ---------------
 
-Ben Dooks, (c) 2006 Simtec Electronics
+Ben Dooks, Copyright 2006 Simtec Electronics
index a30fe51..7edd0e2 100644 (file)
@@ -133,5 +133,5 @@ Configuration
 Document Author
 ---------------
 
-Ben Dooks, (c) 2004 Simtec Electronics
+Ben Dooks, Copyright 2004 Simtec Electronics
 
index 67671eb..f82b1fa 100644 (file)
@@ -90,4 +90,4 @@ Platform Data
 Document Author
 ---------------
 
-Ben Dooks, (c) 2005 Simtec Electronics
+Ben Dooks, Copyright 2005 Simtec Electronics
diff --git a/Documentation/blockdev/drbd/DRBD-8.3-data-packets.svg b/Documentation/blockdev/drbd/DRBD-8.3-data-packets.svg
new file mode 100644 (file)
index 0000000..f87cfa0
--- /dev/null
@@ -0,0 +1,588 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   version="1.0"
+   width="210mm"
+   height="297mm"
+   viewBox="0 0 21000 29700"
+   id="svg2"
+   style="fill-rule:evenodd">
+  <defs
+     id="defs4" />
+  <g
+     id="Default"
+     style="visibility:visible">
+    <desc
+       id="desc180">Master slide</desc>
+  </g>
+  <path
+     d="M 11999,8601 L 11899,8301 L 12099,8301 L 11999,8601 z"
+     id="path193"
+     style="fill:#008000;visibility:visible" />
+  <path
+     d="M 11999,7801 L 11999,8361"
+     id="path197"
+     style="fill:none;stroke:#008000;visibility:visible" />
+  <path
+     d="M 7999,10401 L 7899,10101 L 8099,10101 L 7999,10401 z"
+     id="path209"
+     style="fill:#008000;visibility:visible" />
+  <path
+     d="M 7999,9601 L 7999,10161"
+     id="path213"
+     style="fill:none;stroke:#008000;visibility:visible" />
+  <path
+     d="M 11999,7801 L 11685,7840 L 11724,7644 L 11999,7801 z"
+     id="path225"
+     style="fill:#008000;visibility:visible" />
+  <path
+     d="M 7999,7001 L 11764,7754"
+     id="path229"
+     style="fill:none;stroke:#008000;visibility:visible" />
+  <g
+     transform="matrix(0.9895258,-0.1443562,0.1443562,0.9895258,-1244.4792,1416.5139)"
+     id="g245"
+     style="font-size:318px;font-weight:400;fill:#008000;visibility:visible;font-family:Helvetica embedded">
+    <text
+       id="text247">
+      <tspan
+         x="9139 9368 9579 9808 9986 10075 10252 10481 10659 10837 10909"
+         y="9284"
+         id="tspan249">RSDataReply</tspan>
+    </text>
+  </g>
+  <path
+     d="M 7999,9601 L 8281,9458 L 8311,9655 L 7999,9601 z"
+     id="path259"
+     style="fill:#008000;visibility:visible" />
+  <path
+     d="M 11999,9001 L 8236,9565"
+     id="path263"
+     style="fill:none;stroke:#008000;visibility:visible" />
+  <g
+     transform="matrix(0.9788674,0.2044961,-0.2044961,0.9788674,1620.9382,-1639.4947)"
+     id="g279"
+     style="font-size:318px;font-weight:400;fill:#008000;visibility:visible;font-family:Helvetica embedded">
+    <text
+       id="text281">
+      <tspan
+         x="8743 8972 9132 9310 9573 9801 10013 10242 10419 10597 10775 10953 11114"
+         y="7023"
+         id="tspan283">CsumRSRequest</tspan>
+    </text>
+  </g>
+  <text
+     id="text297"
+     style="font-size:318px;font-weight:400;fill:#008000;visibility:visible;font-family:Helvetica embedded">
+    <tspan
+       x="4034 4263 4440 4703 4881 5042 5219 5397 5503 5681 5842 6003 6180 6341 6519 6625 6803 6980 7158 7336 7497 7586 7692"
+       y="5707"
+       id="tspan299">w_make_resync_request()</tspan>
+  </text>
+  <text
+     id="text313"
+     style="font-size:318px;font-weight:400;fill:#008000;visibility:visible;font-family:Helvetica embedded">
+    <tspan
+       x="12199 12305 12483 12644 12821 12893 13054 13232 13410 13638 13816 13905 14083 14311 14489 14667 14845 15023 15184 15272 15378"
+       y="7806"
+       id="tspan315">receive_DataRequest()</tspan>
+  </text>
+  <text
+     id="text329"
+     style="font-size:318px;font-weight:400;fill:#008000;visibility:visible;font-family:Helvetica embedded">
+    <tspan
+       x="12199 12377 12483 12660 12838 13016 13194 13372 13549 13621 13799 13977 14083 14261 14438 14616 14794 14955 15133 15294 15399"
+       y="8606"
+       id="tspan331">drbd_endio_read_sec()</tspan>
+  </text>
+  <text
+     id="text345"
+     style="font-size:318px;font-weight:400;fill:#008000;visibility:visible;font-family:Helvetica embedded">
+    <tspan
+       x="12191 12420 12597 12775 12953 13131 13309 13486 13664 13825 13986 14164 14426 14604 14710 14871 15049 15154 15332 15510 15616"
+       y="9007"
+       id="tspan347">w_e_end_csum_rs_req()</tspan>
+  </text>
+  <text
+     id="text361"
+     style="font-size:318px;font-weight:400;fill:#008000;visibility:visible;font-family:Helvetica embedded">
+    <tspan
+       x="4444 4550 4728 4889 5066 5138 5299 5477 5655 5883 6095 6324 6501 6590 6768 6997 7175 7352 7424 7585 7691"
+       y="9507"
+       id="tspan363">receive_RSDataReply()</tspan>
+  </text>
+  <text
+     id="text377"
+     style="font-size:318px;font-weight:400;fill:#008000;visibility:visible;font-family:Helvetica embedded">
+    <tspan
+       x="4457 4635 4741 4918 5096 5274 5452 5630 5807 5879 6057 6235 6464 6569 6641 6730 6908 7086 7247 7425 7585 7691"
+       y="10407"
+       id="tspan379">drbd_endio_write_sec()</tspan>
+  </text>
+  <text
+     id="text393"
+     style="font-size:318px;font-weight:400;fill:#008000;visibility:visible;font-family:Helvetica embedded">
+    <tspan
+       x="4647 4825 5003 5180 5358 5536 5714 5820 5997 6158 6319 6497 6658 6836 7013 7085 7263 7424 7585 7691"
+       y="10907"
+       id="tspan395">e_end_resync_block()</tspan>
+  </text>
+  <path
+     d="M 11999,11601 L 11685,11640 L 11724,11444 L 11999,11601 z"
+     id="path405"
+     style="fill:#000080;visibility:visible" />
+  <path
+     d="M 7999,10801 L 11764,11554"
+     id="path409"
+     style="fill:none;stroke:#000080;visibility:visible" />
+  <g
+     transform="matrix(0.9788674,0.2044961,-0.2044961,0.9788674,2434.7562,-1674.649)"
+     id="g425"
+     style="font-size:318px;font-weight:400;fill:#000080;visibility:visible;font-family:Helvetica embedded">
+    <text
+       id="text427">
+      <tspan
+         x="9320 9621 9726 9798 9887 10065 10277 10438"
+         y="10943"
+         id="tspan429">WriteAck</tspan>
+    </text>
+  </g>
+  <text
+     id="text443"
+     style="font-size:318px;font-weight:400;fill:#000080;visibility:visible;font-family:Helvetica embedded">
+    <tspan
+       x="12199 12377 12555 12644 12821 13033 13105 13283 13444 13604 13816 13977 14138 14244"
+       y="11559"
+       id="tspan445">got_BlockAck()</tspan>
+  </text>
+  <text
+     id="text459"
+     style="font-size:423px;font-weight:400;fill:#000000;visibility:visible;font-family:Helvetica embedded">
+    <tspan
+       x="7999 8304 8541 8778 8990 9201 9413 9650 10001 10120 10357 10594 10806 11043 11280 11398 11703 11940 12152 12364 12601 12812 12931 13049 13261 13498 13710 13947 14065 14302 14540 14658 14777 14870 15107 15225 15437 15649 15886"
+       y="4877"
+       id="tspan461">Checksum based Resync, case not in sync</tspan>
+  </text>
+  <text
+     id="text475"
+     style="font-size:423px;font-weight:400;fill:#000000;visibility:visible;font-family:Helvetica embedded">
+    <tspan
+       x="6961 7266 7571 7854 8159 8299 8536 8654 8891 9010 9247 9484 9603 9840 9958 10077 10170 10407"
+       y="2806"
+       id="tspan477">DRBD-8.3 data flow</tspan>
+  </text>
+  <text
+     id="text491"
+     style="font-size:318px;font-weight:400;fill:#008000;visibility:visible;font-family:Helvetica embedded">
+    <tspan
+       x="5190 5419 5596 5774 5952 6113 6291 6468 6646 6824 6985 7146 7324 7586 7692"
+       y="7005"
+       id="tspan493">w_e_send_csum()</tspan>
+  </text>
+  <path
+     d="M 11999,17601 L 11899,17301 L 12099,17301 L 11999,17601 z"
+     id="path503"
+     style="fill:#008000;visibility:visible" />
+  <path
+     d="M 11999,16801 L 11999,17361"
+     id="path507"
+     style="fill:none;stroke:#008000;visibility:visible" />
+  <path
+     d="M 11999,16801 L 11685,16840 L 11724,16644 L 11999,16801 z"
+     id="path519"
+     style="fill:#008000;visibility:visible" />
+  <path
+     d="M 7999,16001 L 11764,16754"
+     id="path523"
+     style="fill:none;stroke:#008000;visibility:visible" />
+  <g
+     transform="matrix(0.9895258,-0.1443562,0.1443562,0.9895258,-2539.5806,1529.3491)"
+     id="g539"
+     style="font-size:318px;font-weight:400;fill:#000080;visibility:visible;font-family:Helvetica embedded">
+    <text
+       id="text541">
+      <tspan
+         x="9269 9498 9709 9798 9959 10048 10226 10437 10598 10776"
+         y="18265"
+         id="tspan543">RSIsInSync</tspan>
+    </text>
+  </g>
+  <path
+     d="M 7999,18601 L 8281,18458 L 8311,18655 L 7999,18601 z"
+     id="path553"
+     style="fill:#000080;visibility:visible" />
+  <path
+     d="M 11999,18001 L 8236,18565"
+     id="path557"
+     style="fill:none;stroke:#000080;visibility:visible" />
+  <g
+     transform="matrix(0.9788674,0.2044961,-0.2044961,0.9788674,3461.4027,-1449.3012)"
+     id="g573"
+     style="font-size:318px;font-weight:400;fill:#008000;visibility:visible;font-family:Helvetica embedded">
+    <text
+       id="text575">
+      <tspan
+         x="8743 8972 9132 9310 9573 9801 10013 10242 10419 10597 10775 10953 11114"
+         y="16023"
+         id="tspan577">CsumRSRequest</tspan>
+    </text>
+  </g>
+  <text
+     id="text591"
+     style="font-size:318px;font-weight:400;fill:#008000;visibility:visible;font-family:Helvetica embedded">
+    <tspan
+       x="12199 12305 12483 12644 12821 12893 13054 13232 13410 13638 13816 13905 14083 14311 14489 14667 14845 15023 15184 15272 15378"
+       y="16806"
+       id="tspan593">receive_DataRequest()</tspan>
+  </text>
+  <text
+     id="text607"
+     style="font-size:318px;font-weight:400;fill:#008000;visibility:visible;font-family:Helvetica embedded">
+    <tspan
+       x="12199 12377 12483 12660 12838 13016 13194 13372 13549 13621 13799 13977 14083 14261 14438 14616 14794 14955 15133 15294 15399"
+       y="17606"
+       id="tspan609">drbd_endio_read_sec()</tspan>
+  </text>
+  <text
+     id="text623"
+     style="font-size:318px;font-weight:400;fill:#008000;visibility:visible;font-family:Helvetica embedded">
+    <tspan
+       x="12191 12420 12597 12775 12953 13131 13309 13486 13664 13825 13986 14164 14426 14604 14710 14871 15049 15154 15332 15510 15616"
+       y="18007"
+       id="tspan625">w_e_end_csum_rs_req()</tspan>
+  </text>
+  <text
+     id="text639"
+     style="font-size:318px;font-weight:400;fill:#000080;visibility:visible;font-family:Helvetica embedded">
+    <tspan
+       x="5735 5913 6091 6180 6357 6446 6607 6696 6874 7085 7246 7424 7585 7691"
+       y="18507"
+       id="tspan641">got_IsInSync()</tspan>
+  </text>
+  <text
+     id="text655"
+     style="font-size:423px;font-weight:400;fill:#000000;visibility:visible;font-family:Helvetica embedded">
+    <tspan
+       x="7999 8304 8541 8778 8990 9201 9413 9650 10001 10120 10357 10594 10806 11043 11280 11398 11703 11940 12152 12364 12601 12812 12931 13049 13261 13498 13710 13947 14065 14159 14396 14514 14726 14937 15175"
+       y="13877"
+       id="tspan657">Checksum based Resync, case in sync</tspan>
+  </text>
+  <path
+     d="M 12000,24601 L 11900,24301 L 12100,24301 L 12000,24601 z"
+     id="path667"
+     style="fill:#008000;visibility:visible" />
+  <path
+     d="M 12000,23801 L 12000,24361"
+     id="path671"
+     style="fill:none;stroke:#008000;visibility:visible" />
+  <path
+     d="M 8000,26401 L 7900,26101 L 8100,26101 L 8000,26401 z"
+     id="path683"
+     style="fill:#008000;visibility:visible" />
+  <path
+     d="M 8000,25601 L 8000,26161"
+     id="path687"
+     style="fill:none;stroke:#008000;visibility:visible" />
+  <path
+     d="M 12000,23801 L 11686,23840 L 11725,23644 L 12000,23801 z"
+     id="path699"
+     style="fill:#008000;visibility:visible" />
+  <path
+     d="M 8000,23001 L 11765,23754"
+     id="path703"
+     style="fill:none;stroke:#008000;visibility:visible" />
+  <g
+     transform="matrix(0.9895258,-0.1443562,0.1443562,0.9895258,-3543.8452,1630.5143)"
+     id="g719"
+     style="font-size:318px;font-weight:400;fill:#008000;visibility:visible;font-family:Helvetica embedded">
+    <text
+       id="text721">
+      <tspan
+         x="9464 9710 9921 10150 10328 10505 10577"
+         y="25236"
+         id="tspan723">OVReply</tspan>
+    </text>
+  </g>
+  <path
+     d="M 8000,25601 L 8282,25458 L 8312,25655 L 8000,25601 z"
+     id="path733"
+     style="fill:#008000;visibility:visible" />
+  <path
+     d="M 12000,25001 L 8237,25565"
+     id="path737"
+     style="fill:none;stroke:#008000;visibility:visible" />
+  <g
+     transform="matrix(0.9788674,0.2044961,-0.2044961,0.9788674,4918.2801,-1381.2128)"
+     id="g753"
+     style="font-size:318px;font-weight:400;fill:#008000;visibility:visible;font-family:Helvetica embedded">
+    <text
+       id="text755">
+      <tspan
+         x="9142 9388 9599 9828 10006 10183 10361 10539 10700"
+         y="23106"
+         id="tspan757">OVRequest</tspan>
+    </text>
+  </g>
+  <text
+     id="text771"
+     style="font-size:318px;font-weight:400;fill:#008000;visibility:visible;font-family:Helvetica embedded">
+    <tspan
+       x="12200 12306 12484 12645 12822 12894 13055 13233 13411 13656 13868 14097 14274 14452 14630 14808 14969 15058 15163"
+       y="23806"
+       id="tspan773">receive_OVRequest()</tspan>
+  </text>
+  <text
+     id="text787"
+     style="font-size:318px;font-weight:400;fill:#008000;visibility:visible;font-family:Helvetica embedded">
+    <tspan
+       x="12200 12378 12484 12661 12839 13017 13195 13373 13550 13622 13800 13978 14084 14262 14439 14617 14795 14956 15134 15295 15400"
+       y="24606"
+       id="tspan789">drbd_endio_read_sec()</tspan>
+  </text>
+  <text
+     id="text803"
+     style="font-size:318px;font-weight:400;fill:#008000;visibility:visible;font-family:Helvetica embedded">
+    <tspan
+       x="12192 12421 12598 12776 12954 13132 13310 13487 13665 13843 14004 14182 14288 14465 14643 14749"
+       y="25007"
+       id="tspan805">w_e_end_ov_req()</tspan>
+  </text>
+  <text
+     id="text819"
+     style="font-size:318px;font-weight:400;fill:#008000;visibility:visible;font-family:Helvetica embedded">
+    <tspan
+       x="5101 5207 5385 5546 5723 5795 5956 6134 6312 6557 6769 6998 7175 7353 7425 7586 7692"
+       y="25507"
+       id="tspan821">receive_OVReply()</tspan>
+  </text>
+  <text
+     id="text835"
+     style="font-size:318px;font-weight:400;fill:#008000;visibility:visible;font-family:Helvetica embedded">
+    <tspan
+       x="4492 4670 4776 4953 5131 5309 5487 5665 5842 5914 6092 6270 6376 6554 6731 6909 7087 7248 7426 7587 7692"
+       y="26407"
+       id="tspan837">drbd_endio_read_sec()</tspan>
+  </text>
+  <text
+     id="text851"
+     style="font-size:318px;font-weight:400;fill:#008000;visibility:visible;font-family:Helvetica embedded">
+    <tspan
+       x="4902 5131 5308 5486 5664 5842 6020 6197 6375 6553 6714 6892 6998 7175 7353 7425 7586 7692"
+       y="26907"
+       id="tspan853">w_e_end_ov_reply()</tspan>
+  </text>
+  <path
+     d="M 12000,27601 L 11686,27640 L 11725,27444 L 12000,27601 z"
+     id="path863"
+     style="fill:#000080;visibility:visible" />
+  <path
+     d="M 8000,26801 L 11765,27554"
+     id="path867"
+     style="fill:none;stroke:#000080;visibility:visible" />
+  <g
+     transform="matrix(0.9788674,0.2044961,-0.2044961,0.9788674,5704.1907,-1328.312)"
+     id="g883"
+     style="font-size:318px;font-weight:400;fill:#000080;visibility:visible;font-family:Helvetica embedded">
+    <text
+       id="text885">
+      <tspan
+         x="9279 9525 9736 9965 10143 10303 10481 10553"
+         y="26935"
+         id="tspan887">OVResult</tspan>
+    </text>
+  </g>
+  <text
+     id="text901"
+     style="font-size:318px;font-weight:400;fill:#000080;visibility:visible;font-family:Helvetica embedded">
+    <tspan
+       x="12200 12378 12556 12645 12822 13068 13280 13508 13686 13847 14025 14097 14185 14291"
+       y="27559"
+       id="tspan903">got_OVResult()</tspan>
+  </text>
+  <text
+     id="text917"
+     style="font-size:423px;font-weight:400;fill:#000000;visibility:visible;font-family:Helvetica embedded">
+    <tspan
+       x="8000 8330 8567 8660 8754 8991 9228 9346 9558 9795 9935 10028 10146"
+       y="21877"
+       id="tspan919">Online verify</tspan>
+  </text>
+  <text
+     id="text933"
+     style="font-size:318px;font-weight:400;fill:#008000;visibility:visible;font-family:Helvetica embedded">
+    <tspan
+       x="4641 4870 5047 5310 5488 5649 5826 6004 6182 6343 6521 6626 6804 6982 7160 7338 7499 7587 7693"
+       y="23005"
+       id="tspan935">w_make_ov_request()</tspan>
+  </text>
+  <path
+     d="M 8000,6500 L 7900,6200 L 8100,6200 L 8000,6500 z"
+     id="path945"
+     style="fill:#008000;visibility:visible" />
+  <path
+     d="M 8000,5700 L 8000,6260"
+     id="path949"
+     style="fill:none;stroke:#008000;visibility:visible" />
+  <path
+     d="M 3900,5500 L 3700,5500 L 3700,11000 L 3900,11000"
+     id="path961"
+     style="fill:none;stroke:#000000;visibility:visible" />
+  <path
+     d="M 3900,14500 L 3700,14500 L 3700,18600 L 3900,18600"
+     id="path973"
+     style="fill:none;stroke:#000000;visibility:visible" />
+  <path
+     d="M 3900,22800 L 3700,22800 L 3700,26900 L 3900,26900"
+     id="path985"
+     style="fill:none;stroke:#000000;visibility:visible" />
+  <text
+     id="text1001"
+     style="font-size:318px;font-weight:400;fill:#008000;visibility:visible;font-family:Helvetica embedded">
+    <tspan
+       x="4492 4670 4776 4953 5131 5309 5487 5665 5842 5914 6092 6270 6376 6554 6731 6909 7087 7248 7426 7587 7692"
+       y="6506"
+       id="tspan1003">drbd_endio_read_sec()</tspan>
+  </text>
+  <text
+     id="text1017"
+     style="font-size:318px;font-weight:400;fill:#008000;visibility:visible;font-family:Helvetica embedded">
+    <tspan
+       x="4034 4263 4440 4703 4881 5042 5219 5397 5503 5681 5842 6003 6180 6341 6519 6625 6803 6980 7158 7336 7497 7586 7692"
+       y="14708"
+       id="tspan1019">w_make_resync_request()</tspan>
+  </text>
+  <text
+     id="text1033"
+     style="font-size:318px;font-weight:400;fill:#008000;visibility:visible;font-family:Helvetica embedded">
+    <tspan
+       x="5190 5419 5596 5774 5952 6113 6291 6468 6646 6824 6985 7146 7324 7586 7692"
+       y="16006"
+       id="tspan1035">w_e_send_csum()</tspan>
+  </text>
+  <path
+     d="M 8000,15501 L 7900,15201 L 8100,15201 L 8000,15501 z"
+     id="path1045"
+     style="fill:#008000;visibility:visible" />
+  <path
+     d="M 8000,14701 L 8000,15261"
+     id="path1049"
+     style="fill:none;stroke:#008000;visibility:visible" />
+  <text
+     id="text1065"
+     style="font-size:318px;font-weight:400;fill:#008000;visibility:visible;font-family:Helvetica embedded">
+    <tspan
+       x="4492 4670 4776 4953 5131 5309 5487 5665 5842 5914 6092 6270 6376 6554 6731 6909 7087 7248 7426 7587 7692"
+       y="15507"
+       id="tspan1067">drbd_endio_read_sec()</tspan>
+  </text>
+  <path
+     d="M 16100,9000 L 16300,9000 L 16300,7500 L 16100,7500"
+     id="path1077"
+     style="fill:none;stroke:#000000;visibility:visible" />
+  <path
+     d="M 16100,18000 L 16300,18000 L 16300,16500 L 16100,16500"
+     id="path1089"
+     style="fill:none;stroke:#000000;visibility:visible" />
+  <path
+     d="M 16100,25000 L 16300,25000 L 16300,23500 L 16100,23500"
+     id="path1101"
+     style="fill:none;stroke:#000000;visibility:visible" />
+  <text
+     id="text1117"
+     style="font-size:318px;font-weight:400;fill:#000000;visibility:visible;font-family:Helvetica embedded">
+    <tspan
+       x="2026 2132 2293 2471 2648 2826 3004 3076 3254 3431 3503 3681 3787"
+       y="5402"
+       id="tspan1119">rs_begin_io()</tspan>
+  </text>
+  <text
+     id="text1133"
+     style="font-size:318px;font-weight:400;fill:#000000;visibility:visible;font-family:Helvetica embedded">
+    <tspan
+       x="2027 2133 2294 2472 2649 2827 3005 3077 3255 3432 3504 3682 3788"
+       y="14402"
+       id="tspan1135">rs_begin_io()</tspan>
+  </text>
+  <text
+     id="text1149"
+     style="font-size:318px;font-weight:400;fill:#000000;visibility:visible;font-family:Helvetica embedded">
+    <tspan
+       x="2026 2132 2293 2471 2648 2826 3004 3076 3254 3431 3503 3681 3787"
+       y="22602"
+       id="tspan1151">rs_begin_io()</tspan>
+  </text>
+  <text
+     id="text1165"
+     style="font-size:318px;font-weight:400;fill:#000000;visibility:visible;font-family:Helvetica embedded">
+    <tspan
+       x="1426 1532 1693 1871 2031 2209 2472 2649 2721 2899 2988 3166 3344 3416 3593 3699"
+       y="11302"
+       id="tspan1167">rs_complete_io()</tspan>
+  </text>
+  <text
+     id="text1181"
+     style="font-size:318px;font-weight:400;fill:#000000;visibility:visible;font-family:Helvetica embedded">
+    <tspan
+       x="1526 1632 1793 1971 2131 2309 2572 2749 2821 2999 3088 3266 3444 3516 3693 3799"
+       y="18931"
+       id="tspan1183">rs_complete_io()</tspan>
+  </text>
+  <text
+     id="text1197"
+     style="font-size:318px;font-weight:400;fill:#000000;visibility:visible;font-family:Helvetica embedded">
+    <tspan
+       x="1526 1632 1793 1971 2131 2309 2572 2749 2821 2999 3088 3266 3444 3516 3693 3799"
+       y="27231"
+       id="tspan1199">rs_complete_io()</tspan>
+  </text>
+  <text
+     id="text1213"
+     style="font-size:318px;font-weight:400;fill:#000000;visibility:visible;font-family:Helvetica embedded">
+    <tspan
+       x="16126 16232 16393 16571 16748 16926 17104 17176 17354 17531 17603 17781 17887"
+       y="7402"
+       id="tspan1215">rs_begin_io()</tspan>
+  </text>
+  <text
+     id="text1229"
+     style="font-size:318px;font-weight:400;fill:#000000;visibility:visible;font-family:Helvetica embedded">
+    <tspan
+       x="16127 16233 16394 16572 16749 16927 17105 17177 17355 17532 17604 17782 17888"
+       y="16331"
+       id="tspan1231">rs_begin_io()</tspan>
+  </text>
+  <text
+     id="text1245"
+     style="font-size:318px;font-weight:400;fill:#000000;visibility:visible;font-family:Helvetica embedded">
+    <tspan
+       x="16127 16233 16394 16572 16749 16927 17105 17177 17355 17532 17604 17782 17888"
+       y="23302"
+       id="tspan1247">rs_begin_io()</tspan>
+  </text>
+  <text
+     id="text1261"
+     style="font-size:318px;font-weight:400;fill:#000000;visibility:visible;font-family:Helvetica embedded">
+    <tspan
+       x="16115 16221 16382 16560 16720 16898 17161 17338 17410 17588 17677 17855 18033 18105 18282 18388"
+       y="9302"
+       id="tspan1263">rs_complete_io()</tspan>
+  </text>
+  <text
+     id="text1277"
+     style="font-size:318px;font-weight:400;fill:#000000;visibility:visible;font-family:Helvetica embedded">
+    <tspan
+       x="16115 16221 16382 16560 16720 16898 17161 17338 17410 17588 17677 17855 18033 18105 18282 18388"
+       y="18331"
+       id="tspan1279">rs_complete_io()</tspan>
+  </text>
+  <text
+     id="text1293"
+     style="font-size:318px;font-weight:400;fill:#000000;visibility:visible;font-family:Helvetica embedded">
+    <tspan
+       x="16126 16232 16393 16571 16731 16909 17172 17349 17421 17599 17688 17866 18044 18116 18293 18399"
+       y="25302"
+       id="tspan1295">rs_complete_io()</tspan>
+  </text>
+</svg>
diff --git a/Documentation/blockdev/drbd/DRBD-data-packets.svg b/Documentation/blockdev/drbd/DRBD-data-packets.svg
new file mode 100644 (file)
index 0000000..48a1e21
--- /dev/null
@@ -0,0 +1,459 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   version="1.0"
+   width="210mm"
+   height="297mm"
+   viewBox="0 0 21000 29700"
+   id="svg2"
+   style="fill-rule:evenodd">
+  <defs
+     id="defs4" />
+  <g
+     id="Default"
+     style="visibility:visible">
+    <desc
+       id="desc176">Master slide</desc>
+  </g>
+  <path
+     d="M 11999,19601 L 11899,19301 L 12099,19301 L 11999,19601 z"
+     id="path189"
+     style="fill:#008000;visibility:visible" />
+  <path
+     d="M 11999,18801 L 11999,19361"
+     id="path193"
+     style="fill:none;stroke:#008000;visibility:visible" />
+  <path
+     d="M 7999,21401 L 7899,21101 L 8099,21101 L 7999,21401 z"
+     id="path205"
+     style="fill:#008000;visibility:visible" />
+  <path
+     d="M 7999,20601 L 7999,21161"
+     id="path209"
+     style="fill:none;stroke:#008000;visibility:visible" />
+  <path
+     d="M 11999,18801 L 11685,18840 L 11724,18644 L 11999,18801 z"
+     id="path221"
+     style="fill:#008000;visibility:visible" />
+  <path
+     d="M 7999,18001 L 11764,18754"
+     id="path225"
+     style="fill:none;stroke:#008000;visibility:visible" />
+  <text
+     x="-3023.845"
+     y="1106.8124"
+     transform="matrix(0.9895258,-0.1443562,0.1443562,0.9895258,0,0)"
+     id="text243"
+     style="font-size:318px;font-weight:400;fill:#008000;visibility:visible;font-family:Helvetica embedded">
+    <tspan
+       x="6115.1553 6344.1553 6555.1553 6784.1553 6962.1553 7051.1553 7228.1553 7457.1553 7635.1553 7813.1553 7885.1553"
+       y="21390.812"
+       id="tspan245">RSDataReply</tspan>
+  </text>
+  <path
+     d="M 7999,20601 L 8281,20458 L 8311,20655 L 7999,20601 z"
+     id="path255"
+     style="fill:#008000;visibility:visible" />
+  <path
+     d="M 11999,20001 L 8236,20565"
+     id="path259"
+     style="fill:none;stroke:#008000;visibility:visible" />
+  <text
+     x="3502.5356"
+     y="-2184.6621"
+     transform="matrix(0.9788674,0.2044961,-0.2044961,0.9788674,0,0)"
+     id="text277"
+     style="font-size:318px;font-weight:400;fill:#008000;visibility:visible;font-family:Helvetica embedded">
+    <tspan
+       x="12321.536 12550.536 12761.536 12990.536 13168.536 13257.536 13434.536 13663.536 13841.536 14019.536 14196.536 14374.536 14535.536"
+       y="15854.338"
+       id="tspan279">RSDataRequest</tspan>
+  </text>
+  <text
+     id="text293"
+     style="font-size:318px;font-weight:400;fill:#008000;visibility:visible;font-family:Helvetica embedded">
+    <tspan
+       x="4034 4263 4440 4703 4881 5042 5219 5397 5503 5681 5842 6003 6180 6341 6519 6625 6803 6980 7158 7336 7497 7586 7692"
+       y="17807"
+       id="tspan295">w_make_resync_request()</tspan>
+  </text>
+  <text
+     id="text309"
+     style="font-size:318px;font-weight:400;fill:#008000;visibility:visible;font-family:Helvetica embedded">
+    <tspan
+       x="12199 12305 12483 12644 12821 12893 13054 13232 13410 13638 13816 13905 14083 14311 14489 14667 14845 15023 15184 15272 15378"
+       y="18806"
+       id="tspan311">receive_DataRequest()</tspan>
+  </text>
+  <text
+     id="text325"
+     style="font-size:318px;font-weight:400;fill:#008000;visibility:visible;font-family:Helvetica embedded">
+    <tspan
+       x="12199 12377 12483 12660 12838 13016 13194 13372 13549 13621 13799 13977 14083 14261 14438 14616 14794 14955 15133 15294 15399"
+       y="19606"
+       id="tspan327">drbd_endio_read_sec()</tspan>
+  </text>
+  <text
+     id="text341"
+     style="font-size:318px;font-weight:400;fill:#008000;visibility:visible;font-family:Helvetica embedded">
+    <tspan
+       x="12191 12420 12597 12775 12953 13131 13309 13486 13664 13770 13931 14109 14287 14375 14553 14731 14837 15015 15192 15298"
+       y="20007"
+       id="tspan343">w_e_end_rsdata_req()</tspan>
+  </text>
+  <text
+     id="text357"
+     style="font-size:318px;font-weight:400;fill:#008000;visibility:visible;font-family:Helvetica embedded">
+    <tspan
+       x="4444 4550 4728 4889 5066 5138 5299 5477 5655 5883 6095 6324 6501 6590 6768 6997 7175 7352 7424 7585 7691"
+       y="20507"
+       id="tspan359">receive_RSDataReply()</tspan>
+  </text>
+  <text
+     id="text373"
+     style="font-size:318px;font-weight:400;fill:#008000;visibility:visible;font-family:Helvetica embedded">
+    <tspan
+       x="4457 4635 4741 4918 5096 5274 5452 5630 5807 5879 6057 6235 6464 6569 6641 6730 6908 7086 7247 7425 7585 7691"
+       y="21407"
+       id="tspan375">drbd_endio_write_sec()</tspan>
+  </text>
+  <text
+     id="text389"
+     style="font-size:318px;font-weight:400;fill:#008000;visibility:visible;font-family:Helvetica embedded">
+    <tspan
+       x="4647 4825 5003 5180 5358 5536 5714 5820 5997 6158 6319 6497 6658 6836 7013 7085 7263 7424 7585 7691"
+       y="21907"
+       id="tspan391">e_end_resync_block()</tspan>
+  </text>
+  <path
+     d="M 11999,22601 L 11685,22640 L 11724,22444 L 11999,22601 z"
+     id="path401"
+     style="fill:#000080;visibility:visible" />
+  <path
+     d="M 7999,21801 L 11764,22554"
+     id="path405"
+     style="fill:none;stroke:#000080;visibility:visible" />
+  <text
+     x="4290.3008"
+     y="-2369.6162"
+     transform="matrix(0.9788674,0.2044961,-0.2044961,0.9788674,0,0)"
+     id="text423"
+     style="font-size:318px;font-weight:400;fill:#000080;visibility:visible;font-family:Helvetica embedded">
+    <tspan
+       x="13610.301 13911.301 14016.301 14088.301 14177.301 14355.301 14567.301 14728.301"
+       y="19573.385"
+       id="tspan425">WriteAck</tspan>
+  </text>
+  <text
+     id="text439"
+     style="font-size:318px;font-weight:400;fill:#000080;visibility:visible;font-family:Helvetica embedded">
+    <tspan
+       x="12199 12377 12555 12644 12821 13033 13105 13283 13444 13604 13816 13977 14138 14244"
+       y="22559"
+       id="tspan441">got_BlockAck()</tspan>
+  </text>
+  <text
+     id="text455"
+     style="font-size:423px;font-weight:400;fill:#000000;visibility:visible;font-family:Helvetica embedded">
+    <tspan
+       x="7999 8304 8541 8753 8964 9201 9413 9531 9769 9862 10099 10310 10522 10734 10852 10971 11208 11348 11585 11822"
+       y="16877"
+       id="tspan457">Resync blocks, 4-32K</tspan>
+  </text>
+  <path
+     d="M 12000,7601 L 11900,7301 L 12100,7301 L 12000,7601 z"
+     id="path467"
+     style="fill:#008000;visibility:visible" />
+  <path
+     d="M 12000,6801 L 12000,7361"
+     id="path471"
+     style="fill:none;stroke:#008000;visibility:visible" />
+  <path
+     d="M 12000,6801 L 11686,6840 L 11725,6644 L 12000,6801 z"
+     id="path483"
+     style="fill:#008000;visibility:visible" />
+  <path
+     d="M 8000,6001 L 11765,6754"
+     id="path487"
+     style="fill:none;stroke:#008000;visibility:visible" />
+  <text
+     x="-1288.1796"
+     y="1279.7666"
+     transform="matrix(0.9895258,-0.1443562,0.1443562,0.9895258,0,0)"
+     id="text505"
+     style="font-size:318px;font-weight:400;fill:#000080;visibility:visible;font-family:Helvetica embedded">
+    <tspan
+       x="8174.8208 8475.8203 8580.8203 8652.8203 8741.8203 8919.8203 9131.8203 9292.8203"
+       y="9516.7666"
+       id="tspan507">WriteAck</tspan>
+  </text>
+  <path
+     d="M 8000,8601 L 8282,8458 L 8312,8655 L 8000,8601 z"
+     id="path517"
+     style="fill:#000080;visibility:visible" />
+  <path
+     d="M 12000,8001 L 8237,8565"
+     id="path521"
+     style="fill:none;stroke:#000080;visibility:visible" />
+  <text
+     x="1065.6655"
+     y="-2097.7664"
+     transform="matrix(0.9788674,0.2044961,-0.2044961,0.9788674,0,0)"
+     id="text539"
+     style="font-size:318px;font-weight:400;fill:#008000;visibility:visible;font-family:Helvetica embedded">
+    <tspan
+       x="10682.666 10911.666 11088.666 11177.666"
+       y="4107.2339"
+       id="tspan541">Data</tspan>
+  </text>
+  <text
+     id="text555"
+     style="font-size:318px;font-weight:400;fill:#008000;visibility:visible;font-family:Helvetica embedded">
+    <tspan
+       x="4746 4924 5030 5207 5385 5563 5826 6003 6164 6342 6520 6626 6803 6981 7159 7337 7498 7587 7692"
+       y="5505"
+       id="tspan557">drbd_make_request()</tspan>
+  </text>
+  <text
+     id="text571"
+     style="font-size:318px;font-weight:400;fill:#008000;visibility:visible;font-family:Helvetica embedded">
+    <tspan
+       x="12200 12306 12484 12645 12822 12894 13055 13233 13411 13639 13817 13906 14084 14190"
+       y="6806"
+       id="tspan573">receive_Data()</tspan>
+  </text>
+  <text
+     id="text587"
+     style="font-size:318px;font-weight:400;fill:#008000;visibility:visible;font-family:Helvetica embedded">
+    <tspan
+       x="12200 12378 12484 12661 12839 13017 13195 13373 13550 13622 13800 13978 14207 14312 14384 14473 14651 14829 14990 15168 15328 15434"
+       y="7606"
+       id="tspan589">drbd_endio_write_sec()</tspan>
+  </text>
+  <text
+     id="text603"
+     style="font-size:318px;font-weight:400;fill:#008000;visibility:visible;font-family:Helvetica embedded">
+    <tspan
+       x="12192 12370 12548 12725 12903 13081 13259 13437 13509 13686 13847 14008 14114"
+       y="8007"
+       id="tspan605">e_end_block()</tspan>
+  </text>
+  <text
+     id="text619"
+     style="font-size:318px;font-weight:400;fill:#000080;visibility:visible;font-family:Helvetica embedded">
+    <tspan
+       x="5647 5825 6003 6092 6269 6481 6553 6731 6892 7052 7264 7425 7586 7692"
+       y="8606"
+       id="tspan621">got_BlockAck()</tspan>
+  </text>
+  <text
+     id="text635"
+     style="font-size:423px;font-weight:400;fill:#000000;visibility:visible;font-family:Helvetica embedded">
+    <tspan
+       x="8000 8305 8542 8779 9016 9109 9346 9486 9604 9956 10049 10189 10328 10565 10705 10942 11179 11298 11603 11742 11835 11954 12191 12310 12428 12665 12902 13139 13279 13516 13753"
+       y="4877"
+       id="tspan637">Regular mirrored write, 512-32K</tspan>
+  </text>
+  <text
+     id="text651"
+     style="font-size:318px;font-weight:400;fill:#008000;visibility:visible;font-family:Helvetica embedded">
+    <tspan
+       x="5381 5610 5787 5948 6126 6304 6482 6659 6837 7015 7087 7265 7426 7587 7692"
+       y="6003"
+       id="tspan653">w_send_dblock()</tspan>
+  </text>
+  <path
+     d="M 8000,6800 L 7900,6500 L 8100,6500 L 8000,6800 z"
+     id="path663"
+     style="fill:#008000;visibility:visible" />
+  <path
+     d="M 8000,6000 L 8000,6560"
+     id="path667"
+     style="fill:none;stroke:#008000;visibility:visible" />
+  <text
+     id="text683"
+     style="font-size:318px;font-weight:400;fill:#008000;visibility:visible;font-family:Helvetica embedded">
+    <tspan
+       x="4602 4780 4886 5063 5241 5419 5597 5775 5952 6024 6202 6380 6609 6714 6786 6875 7053 7231 7409 7515 7587 7692"
+       y="6905"
+       id="tspan685">drbd_endio_write_pri()</tspan>
+  </text>
+  <path
+     d="M 12000,13602 L 11900,13302 L 12100,13302 L 12000,13602 z"
+     id="path695"
+     style="fill:#008000;visibility:visible" />
+  <path
+     d="M 12000,12802 L 12000,13362"
+     id="path699"
+     style="fill:none;stroke:#008000;visibility:visible" />
+  <path
+     d="M 12000,12802 L 11686,12841 L 11725,12645 L 12000,12802 z"
+     id="path711"
+     style="fill:#008000;visibility:visible" />
+  <path
+     d="M 8000,12002 L 11765,12755"
+     id="path715"
+     style="fill:none;stroke:#008000;visibility:visible" />
+  <text
+     x="-2155.5266"
+     y="1201.5964"
+     transform="matrix(0.9895258,-0.1443562,0.1443562,0.9895258,0,0)"
+     id="text733"
+     style="font-size:318px;font-weight:400;fill:#008000;visibility:visible;font-family:Helvetica embedded">
+    <tspan
+       x="7202.4736 7431.4736 7608.4736 7697.4736 7875.4736 8104.4736 8282.4736 8459.4736 8531.4736"
+       y="15454.597"
+       id="tspan735">DataReply</tspan>
+  </text>
+  <path
+     d="M 8000,14602 L 8282,14459 L 8312,14656 L 8000,14602 z"
+     id="path745"
+     style="fill:#008000;visibility:visible" />
+  <path
+     d="M 12000,14002 L 8237,14566"
+     id="path749"
+     style="fill:none;stroke:#008000;visibility:visible" />
+  <text
+     x="2280.3804"
+     y="-2103.2141"
+     transform="matrix(0.9788674,0.2044961,-0.2044961,0.9788674,0,0)"
+     id="text767"
+     style="font-size:318px;font-weight:400;fill:#008000;visibility:visible;font-family:Helvetica embedded">
+    <tspan
+       x="11316.381 11545.381 11722.381 11811.381 11989.381 12218.381 12396.381 12573.381 12751.381 12929.381 13090.381"
+       y="9981.7861"
+       id="tspan769">DataRequest</tspan>
+  </text>
+  <text
+     id="text783"
+     style="font-size:318px;font-weight:400;fill:#008000;visibility:visible;font-family:Helvetica embedded">
+    <tspan
+       x="4746 4924 5030 5207 5385 5563 5826 6003 6164 6342 6520 6626 6803 6981 7159 7337 7498 7587 7692"
+       y="11506"
+       id="tspan785">drbd_make_request()</tspan>
+  </text>
+  <text
+     id="text799"
+     style="font-size:318px;font-weight:400;fill:#008000;visibility:visible;font-family:Helvetica embedded">
+    <tspan
+       x="12200 12306 12484 12645 12822 12894 13055 13233 13411 13639 13817 13906 14084 14312 14490 14668 14846 15024 15185 15273 15379"
+       y="12807"
+       id="tspan801">receive_DataRequest()</tspan>
+  </text>
+  <text
+     id="text815"
+     style="font-size:318px;font-weight:400;fill:#008000;visibility:visible;font-family:Helvetica embedded">
+    <tspan
+       x="12200 12378 12484 12661 12839 13017 13195 13373 13550 13622 13800 13978 14084 14262 14439 14617 14795 14956 15134 15295 15400"
+       y="13607"
+       id="tspan817">drbd_endio_read_sec()</tspan>
+  </text>
+  <text
+     id="text831"
+     style="font-size:318px;font-weight:400;fill:#008000;visibility:visible;font-family:Helvetica embedded">
+    <tspan
+       x="12192 12421 12598 12776 12954 13132 13310 13487 13665 13843 14021 14110 14288 14465 14571 14749 14927 15033"
+       y="14008"
+       id="tspan833">w_e_end_data_req()</tspan>
+  </text>
+  <g
+     id="g835"
+     style="visibility:visible">
+    <desc
+       id="desc837">Drawing</desc>
+    <text
+       id="text847"
+       style="font-size:318px;font-weight:400;fill:#008000;font-family:Helvetica embedded">
+      <tspan
+         x="4885 4991 5169 5330 5507 5579 5740 5918 6096 6324 6502 6591 6769 6997 7175 7353 7425 7586 7692"
+         y="14607"
+         id="tspan849">receive_DataReply()</tspan>
+    </text>
+  </g>
+  <text
+     id="text863"
+     style="font-size:423px;font-weight:400;fill:#000000;visibility:visible;font-family:Helvetica embedded">
+    <tspan
+       x="8000 8305 8398 8610 8821 8914 9151 9363 9575 9693 9833 10070 10307 10544 10663 10781 11018 11255 11493 11632 11869 12106"
+       y="10878"
+       id="tspan865">Diskless read, 512-32K</tspan>
+  </text>
+  <text
+     id="text879"
+     style="font-size:318px;font-weight:400;fill:#008000;visibility:visible;font-family:Helvetica embedded">
+    <tspan
+       x="5029 5258 5435 5596 5774 5952 6130 6307 6413 6591 6769 6947 7125 7230 7408 7586 7692"
+       y="12004"
+       id="tspan881">w_send_read_req()</tspan>
+  </text>
+  <text
+     id="text895"
+     style="font-size:423px;font-weight:400;fill:#000000;visibility:visible;font-family:Helvetica embedded">
+    <tspan
+       x="6961 7266 7571 7854 8159 8278 8515 8633 8870 9107 9226 9463 9581 9700 9793 10030"
+       y="2806"
+       id="tspan897">DRBD 8 data flow</tspan>
+  </text>
+  <path
+     d="M 3900,5300 L 3700,5300 L 3700,7000 L 3900,7000"
+     id="path907"
+     style="fill:none;stroke:#000000;visibility:visible" />
+  <path
+     d="M 3900,17600 L 3700,17600 L 3700,22000 L 3900,22000"
+     id="path919"
+     style="fill:none;stroke:#000000;visibility:visible" />
+  <path
+     d="M 16100,20000 L 16300,20000 L 16300,18500 L 16100,18500"
+     id="path931"
+     style="fill:none;stroke:#000000;visibility:visible" />
+  <text
+     id="text947"
+     style="font-size:318px;font-weight:400;fill:#000000;visibility:visible;font-family:Helvetica embedded">
+    <tspan
+       x="2126 2304 2376 2554 2731 2909 3087 3159 3337 3515 3587 3764 3870"
+       y="5202"
+       id="tspan949">al_begin_io()</tspan>
+  </text>
+  <text
+     id="text963"
+     style="font-size:318px;font-weight:400;fill:#000000;visibility:visible;font-family:Helvetica embedded">
+    <tspan
+       x="1632 1810 1882 2060 2220 2398 2661 2839 2910 3088 3177 3355 3533 3605 3783 3888"
+       y="7331"
+       id="tspan965">al_complete_io()</tspan>
+  </text>
+  <text
+     id="text979"
+     style="font-size:318px;font-weight:400;fill:#000000;visibility:visible;font-family:Helvetica embedded">
+    <tspan
+       x="2126 2232 2393 2571 2748 2926 3104 3176 3354 3531 3603 3781 3887"
+       y="17431"
+       id="tspan981">rs_begin_io()</tspan>
+  </text>
+  <text
+     id="text995"
+     style="font-size:318px;font-weight:400;fill:#000000;visibility:visible;font-family:Helvetica embedded">
+    <tspan
+       x="1626 1732 1893 2071 2231 2409 2672 2849 2921 3099 3188 3366 3544 3616 3793 3899"
+       y="22331"
+       id="tspan997">rs_complete_io()</tspan>
+  </text>
+  <text
+     id="text1011"
+     style="font-size:318px;font-weight:400;fill:#000000;visibility:visible;font-family:Helvetica embedded">
+    <tspan
+       x="16027 16133 16294 16472 16649 16827 17005 17077 17255 17432 17504 17682 17788"
+       y="18402"
+       id="tspan1013">rs_begin_io()</tspan>
+  </text>
+  <text
+     id="text1027"
+     style="font-size:318px;font-weight:400;fill:#000000;visibility:visible;font-family:Helvetica embedded">
+    <tspan
+       x="16115 16221 16382 16560 16720 16898 17161 17338 17410 17588 17677 17855 18033 18105 18282 18388"
+       y="20331"
+       id="tspan1029">rs_complete_io()</tspan>
+  </text>
+</svg>
diff --git a/Documentation/blockdev/drbd/README.txt b/Documentation/blockdev/drbd/README.txt
new file mode 100644 (file)
index 0000000..627b0a1
--- /dev/null
@@ -0,0 +1,16 @@
+Description
+
+  DRBD is a shared-nothing, synchronously replicated block device. It
+  is designed to serve as a building block for high availability
+  clusters and in this context, is a "drop-in" replacement for shared
+  storage. Simplistically, you could see it as a network RAID 1.
+
+  Please visit http://www.drbd.org to find out more.
+
+The here included files are intended to help understand the implementation
+
+DRBD-8.3-data-packets.svg, DRBD-data-packets.svg  
+  relates some functions, and write packets.
+
+conn-states-8.dot, disk-states-8.dot, node-states-8.dot
+  The sub graphs of DRBD's state transitions
diff --git a/Documentation/blockdev/drbd/conn-states-8.dot b/Documentation/blockdev/drbd/conn-states-8.dot
new file mode 100644 (file)
index 0000000..025e8cf
--- /dev/null
@@ -0,0 +1,18 @@
+digraph conn_states {
+       StandAllone  -> WFConnection   [ label = "ioctl_set_net()" ]
+       WFConnection -> Unconnected    [ label = "unable to bind()" ]
+       WFConnection -> WFReportParams [ label = "in connect() after accept" ]
+       WFReportParams -> StandAllone  [ label = "checks in receive_param()" ]
+       WFReportParams -> Connected    [ label = "in receive_param()" ]
+       WFReportParams -> WFBitMapS    [ label = "sync_handshake()" ]
+       WFReportParams -> WFBitMapT    [ label = "sync_handshake()" ]
+       WFBitMapS -> SyncSource        [ label = "receive_bitmap()" ]
+       WFBitMapT -> SyncTarget        [ label = "receive_bitmap()" ]
+       SyncSource -> Connected
+       SyncTarget -> Connected
+       SyncSource -> PausedSyncS
+       SyncTarget -> PausedSyncT
+       PausedSyncS -> SyncSource
+       PausedSyncT -> SyncTarget
+       Connected   -> WFConnection    [ label = "* on network error" ]
+}
diff --git a/Documentation/blockdev/drbd/disk-states-8.dot b/Documentation/blockdev/drbd/disk-states-8.dot
new file mode 100644 (file)
index 0000000..d06cfb4
--- /dev/null
@@ -0,0 +1,16 @@
+digraph disk_states {
+       Diskless -> Inconsistent       [ label = "ioctl_set_disk()" ]
+       Diskless -> Consistent         [ label = "ioctl_set_disk()" ]
+       Diskless -> Outdated           [ label = "ioctl_set_disk()" ]
+       Consistent -> Outdated         [ label = "receive_param()" ]
+       Consistent -> UpToDate         [ label = "receive_param()" ]
+       Consistent -> Inconsistent     [ label = "start resync" ]
+       Outdated   -> Inconsistent     [ label = "start resync" ]
+       UpToDate   -> Inconsistent     [ label = "ioctl_replicate" ]
+       Inconsistent -> UpToDate       [ label = "resync completed" ]
+       Consistent -> Failed           [ label = "io completion error" ]
+       Outdated   -> Failed           [ label = "io completion error" ]
+       UpToDate   -> Failed           [ label = "io completion error" ]
+       Inconsistent -> Failed         [ label = "io completion error" ]
+       Failed -> Diskless             [ label = "sending notify to peer" ]
+}
diff --git a/Documentation/blockdev/drbd/drbd-connection-state-overview.dot b/Documentation/blockdev/drbd/drbd-connection-state-overview.dot
new file mode 100644 (file)
index 0000000..6d9cf0a
--- /dev/null
@@ -0,0 +1,85 @@
+// vim: set sw=2 sts=2 :
+digraph {
+  rankdir=BT
+  bgcolor=white
+
+  node [shape=plaintext]
+  node [fontcolor=black]
+
+  StandAlone     [ style=filled,fillcolor=gray,label=StandAlone ]
+
+  node [fontcolor=lightgray]
+
+  Unconnected    [ label=Unconnected ]
+
+  CommTrouble [ shape=record,
+    label="{communication loss|{Timeout|BrokenPipe|NetworkFailure}}" ]
+
+  node [fontcolor=gray]
+
+  subgraph cluster_try_connect {
+    label="try to connect, handshake"
+    rank=max
+    WFConnection   [ label=WFConnection ]
+    WFReportParams [ label=WFReportParams ]
+  }
+
+  TearDown       [ label=TearDown ]
+
+  Connected      [ label=Connected,style=filled,fillcolor=green,fontcolor=black ]
+
+  node [fontcolor=lightblue]
+
+  StartingSyncS  [ label=StartingSyncS ]
+  StartingSyncT  [ label=StartingSyncT ]
+
+  subgraph cluster_bitmap_exchange {
+    node [fontcolor=red]
+    fontcolor=red
+    label="new application (WRITE?) requests blocked\lwhile bitmap is exchanged"
+
+    WFBitMapT      [ label=WFBitMapT ]
+    WFSyncUUID     [ label=WFSyncUUID ]
+    WFBitMapS      [ label=WFBitMapS ]
+  }
+
+  node [fontcolor=blue]
+
+  cluster_resync [ shape=record,label="{<any>resynchronisation process running\l'concurrent' application requests allowed|{{<T>PausedSyncT\nSyncTarget}|{<S>PausedSyncS\nSyncSource}}}" ]
+
+  node [shape=box,fontcolor=black]
+
+  // drbdadm [label="drbdadm connect"]
+  // handshake [label="drbd_connect()\ndrbd_do_handshake\ndrbd_sync_handshake() etc."]
+  // comm_error [label="communication trouble"]
+
+  //
+  // edges
+  // --------------------------------------
+
+  StandAlone -> Unconnected [ label="drbdadm connect" ]
+  Unconnected -> StandAlone  [ label="drbdadm disconnect\lor serious communication trouble" ]
+  Unconnected -> WFConnection [ label="receiver thread is started" ]
+  WFConnection -> WFReportParams [ headlabel="accept()\land/or                        \lconnect()\l" ]
+
+  WFReportParams -> StandAlone [ label="during handshake\lpeers do not agree\labout something essential" ]
+  WFReportParams -> Connected [ label="data identical\lno sync needed",color=green,fontcolor=green ]
+
+    WFReportParams -> WFBitMapS
+    WFReportParams -> WFBitMapT
+    WFBitMapT -> WFSyncUUID [minlen=0.1,constraint=false]
+
+      WFBitMapS -> cluster_resync:S
+      WFSyncUUID -> cluster_resync:T
+
+  edge [color=green]
+  cluster_resync:any -> Connected [ label="resnyc done",fontcolor=green ]
+
+  edge [color=red]
+  WFReportParams -> CommTrouble
+  Connected -> CommTrouble
+  cluster_resync:any -> CommTrouble
+  edge [color=black]
+  CommTrouble -> Unconnected [label="receiver thread is stopped" ]
+
+}
diff --git a/Documentation/blockdev/drbd/node-states-8.dot b/Documentation/blockdev/drbd/node-states-8.dot
new file mode 100644 (file)
index 0000000..4a2b00c
--- /dev/null
@@ -0,0 +1,14 @@
+digraph node_states {
+       Secondary -> Primary           [ label = "ioctl_set_state()" ]
+       Primary   -> Secondary         [ label = "ioctl_set_state()" ]
+}
+
+digraph peer_states {
+       Secondary -> Primary           [ label = "recv state packet" ]
+       Primary   -> Secondary         [ label = "recv state packet" ]
+       Primary   -> Unknown           [ label = "connection lost" ]
+       Secondary  -> Unknown          [ label = "connection lost" ]
+       Unknown   -> Primary           [ label = "connected" ]
+       Unknown   -> Secondary         [ label = "connected" ]
+}
+
diff --git a/Documentation/cgroups/blkio-controller.txt b/Documentation/cgroups/blkio-controller.txt
new file mode 100644 (file)
index 0000000..630879c
--- /dev/null
@@ -0,0 +1,135 @@
+                               Block IO Controller
+                               ===================
+Overview
+========
+cgroup subsys "blkio" implements the block io controller. There seems to be
+a need of various kinds of IO control policies (like proportional BW, max BW)
+both at leaf nodes as well as at intermediate nodes in a storage hierarchy.
+Plan is to use the same cgroup based management interface for blkio controller
+and based on user options switch IO policies in the background.
+
+In the first phase, this patchset implements proportional weight time based
+division of disk policy. It is implemented in CFQ. Hence this policy takes
+effect only on leaf nodes when CFQ is being used.
+
+HOWTO
+=====
+You can do a very simple testing of running two dd threads in two different
+cgroups. Here is what you can do.
+
+- Enable group scheduling in CFQ
+       CONFIG_CFQ_GROUP_IOSCHED=y
+
+- Compile and boot into kernel and mount IO controller (blkio).
+
+       mount -t cgroup -o blkio none /cgroup
+
+- Create two cgroups
+       mkdir -p /cgroup/test1/ /cgroup/test2
+
+- Set weights of group test1 and test2
+       echo 1000 > /cgroup/test1/blkio.weight
+       echo 500 > /cgroup/test2/blkio.weight
+
+- Create two same size files (say 512MB each) on same disk (file1, file2) and
+  launch two dd threads in different cgroup to read those files.
+
+       sync
+       echo 3 > /proc/sys/vm/drop_caches
+
+       dd if=/mnt/sdb/zerofile1 of=/dev/null &
+       echo $! > /cgroup/test1/tasks
+       cat /cgroup/test1/tasks
+
+       dd if=/mnt/sdb/zerofile2 of=/dev/null &
+       echo $! > /cgroup/test2/tasks
+       cat /cgroup/test2/tasks
+
+- At macro level, first dd should finish first. To get more precise data, keep
+  on looking at (with the help of script), at blkio.disk_time and
+  blkio.disk_sectors files of both test1 and test2 groups. This will tell how
+  much disk time (in milli seconds), each group got and how many secotors each
+  group dispatched to the disk. We provide fairness in terms of disk time, so
+  ideally io.disk_time of cgroups should be in proportion to the weight.
+
+Various user visible config options
+===================================
+CONFIG_CFQ_GROUP_IOSCHED
+       - Enables group scheduling in CFQ. Currently only 1 level of group
+         creation is allowed.
+
+CONFIG_DEBUG_CFQ_IOSCHED
+       - Enables some debugging messages in blktrace. Also creates extra
+         cgroup file blkio.dequeue.
+
+Config options selected automatically
+=====================================
+These config options are not user visible and are selected/deselected
+automatically based on IO scheduler configuration.
+
+CONFIG_BLK_CGROUP
+       - Block IO controller. Selected by CONFIG_CFQ_GROUP_IOSCHED.
+
+CONFIG_DEBUG_BLK_CGROUP
+       - Debug help. Selected by CONFIG_DEBUG_CFQ_IOSCHED.
+
+Details of cgroup files
+=======================
+- blkio.weight
+       - Specifies per cgroup weight.
+
+         Currently allowed range of weights is from 100 to 1000.
+
+- blkio.time
+       - disk time allocated to cgroup per device in milliseconds. First
+         two fields specify the major and minor number of the device and
+         third field specifies the disk time allocated to group in
+         milliseconds.
+
+- blkio.sectors
+       - number of sectors transferred to/from disk by the group. First
+         two fields specify the major and minor number of the device and
+         third field specifies the number of sectors transferred by the
+         group to/from the device.
+
+- blkio.dequeue
+       - Debugging aid only enabled if CONFIG_DEBUG_CFQ_IOSCHED=y. This
+         gives the statistics about how many a times a group was dequeued
+         from service tree of the device. First two fields specify the major
+         and minor number of the device and third field specifies the number
+         of times a group was dequeued from a particular device.
+
+CFQ sysfs tunable
+=================
+/sys/block/<disk>/queue/iosched/group_isolation
+
+If group_isolation=1, it provides stronger isolation between groups at the
+expense of throughput. By default group_isolation is 0. In general that
+means that if group_isolation=0, expect fairness for sequential workload
+only. Set group_isolation=1 to see fairness for random IO workload also.
+
+Generally CFQ will put random seeky workload in sync-noidle category. CFQ
+will disable idling on these queues and it does a collective idling on group
+of such queues. Generally these are slow moving queues and if there is a
+sync-noidle service tree in each group, that group gets exclusive access to
+disk for certain period. That means it will bring the throughput down if
+group does not have enough IO to drive deeper queue depths and utilize disk
+capacity to the fullest in the slice allocated to it. But the flip side is
+that even a random reader should get better latencies and overall throughput
+if there are lots of sequential readers/sync-idle workload running in the
+system.
+
+If group_isolation=0, then CFQ automatically moves all the random seeky queues
+in the root group. That means there will be no service differentiation for
+that kind of workload. This leads to better throughput as we do collective
+idling on root sync-noidle tree.
+
+By default one should run with group_isolation=0. If that is not sufficient
+and one wants stronger isolation between groups, then set group_isolation=1
+but this will come at cost of reduced throughput.
+
+What works
+==========
+- Currently only sync IO queues are support. All the buffered writes are
+  still system wide and not per group. Hence we will not see service
+  differentiation between buffered writes between groups.
index 72ae06f..591e944 100644 (file)
@@ -6,6 +6,21 @@ be removed from this file.
 
 ---------------------------
 
+What:  USER_SCHED
+When:  2.6.34
+
+Why:   USER_SCHED was implemented as a proof of concept for group scheduling.
+       The effect of USER_SCHED can already be achieved from userspace with
+       the help of libcgroup. The removal of USER_SCHED will also simplify
+       the scheduler code with the removal of one major ifdef. There are also
+       issues USER_SCHED has with USER_NS. A decision was taken not to fix
+       those and instead remove USER_SCHED. Also new group scheduling
+       features will not be implemented for USER_SCHED.
+
+Who:   Dhaval Giani <dhaval@linux.vnet.ibm.com>
+
+---------------------------
+
 What:  PRISM54
 When:  2.6.34
 
@@ -392,15 +407,6 @@ Who:       Alex Chiang <achiang@hp.com>
 
 ---------------------------
 
-What:  i2c-voodoo3 driver
-When:  October 2009
-Why:   Superseded by tdfxfb. I2C/DDC support used to live in a separate
-       driver but this caused driver conflicts.
-Who:   Jean Delvare <khali@linux-fr.org>
-       Krzysztof Helt <krzysztof.h1@wp.pl>
-
----------------------------
-
 What:  CONFIG_RFKILL_INPUT
 When:  2.6.33
 Why:   Should be implemented in userspace, policy daemon.
index 2c48f94..4af0018 100644 (file)
@@ -1072,7 +1072,8 @@ second).  The meanings of the columns are as follows, from left to right:
 - irq: servicing interrupts
 - softirq: servicing softirqs
 - steal: involuntary wait
-- guest: running a guest
+- guest: running a normal guest
+- guest_nice: running a niced guest
 
 The "intr" line gives counts of interrupts  serviced since boot time, for each
 of the  possible system interrupts.   The first  column  is the  total of  all
diff --git a/Documentation/i2c/busses/i2c-voodoo3 b/Documentation/i2c/busses/i2c-voodoo3
deleted file mode 100644 (file)
index 62d90a4..0000000
+++ /dev/null
@@ -1,62 +0,0 @@
-Kernel driver i2c-voodoo3
-
-Supported adapters:
-  * 3dfx Voodoo3 based cards
-  * Voodoo Banshee based cards
-
-Authors: 
-       Frodo Looijaard <frodol@dds.nl>, 
-       Philip Edelbrock <phil@netroedge.com>, 
-       Ralph Metzler <rjkm@thp.uni-koeln.de>,
-       Mark D. Studebaker <mdsxyz123@yahoo.com>
-
-Main contact: Philip Edelbrock <phil@netroedge.com>
-       
-The code is based upon Ralph's test code (he did the hard stuff ;')
-
-Description
------------
-
-The 3dfx Voodoo3 chip contains two I2C interfaces (aka a I2C 'master' or
-'host'). 
-
-The first interface is used for DDC (Data Display Channel) which is a
-serial channel through the VGA monitor connector to a DDC-compliant
-monitor. This interface is defined by the Video Electronics Standards
-Association (VESA). The standards are available for purchase at
-http://www.vesa.org .
-
-The second interface is a general-purpose I2C bus. The intent by 3dfx was
-to allow manufacturers to add extra chips to the video card such as a
-TV-out chip such as the BT869 or possibly even I2C based temperature
-sensors like the ADM1021 or LM75.
-
-Stability
----------
-
-Seems to be stable on the test machine, but needs more testing on other
-machines. Simultaneous accesses of the DDC and I2C busses may cause errors.
-
-Supported Devices
------------------
-
-Specifically, this driver was written and tested on the '3dfx Voodoo3 AGP
-3000' which has a tv-out feature (s-video or composite).  According to the
-docs and discussions, this code should work for any Voodoo3 based cards as
-well as Voodoo Banshee based cards.  The DDC interface has been tested on a
-Voodoo Banshee card.
-       
-Issues
-------
-
-Probably many, but it seems to work OK on my system. :')
-
-
-External Device Connection
---------------------------
-
-The digital video input jumpers give availability to the I2C bus. 
-Specifically, pins 13 and 25 (bottom row middle, and bottom right-end) are     
-the I2C clock and I2C data lines, respectively. +5V and GND are probably
-also easily available making the addition of extra I2C/SMBus devices easy
-to implement.
index 0d8be1c..fa4b669 100644 (file)
@@ -2,9 +2,9 @@ MODULE: i2c-stub
 
 DESCRIPTION:
 
-This module is a very simple fake I2C/SMBus driver.  It implements four
-types of SMBus commands: write quick, (r/w) byte, (r/w) byte data, and
-(r/w) word data.
+This module is a very simple fake I2C/SMBus driver.  It implements five
+types of SMBus commands: write quick, (r/w) byte, (r/w) byte data, (r/w)
+word data, and (r/w) I2C block data.
 
 You need to provide chip addresses as a module parameter when loading this
 driver, which will then only react to SMBus commands to these addresses.
@@ -21,8 +21,8 @@ EEPROMs, among others.
 
 The typical use-case is like this:
        1. load this module
-       2. use i2cset (from lm_sensors project) to pre-load some data
-       3. load the target sensors chip driver module
+       2. use i2cset (from the i2c-tools project) to pre-load some data
+       3. load the target chip driver module
        4. observe its behavior in the kernel log
 
 There's a script named i2c-stub-from-dump in the i2c-tools package which
@@ -33,6 +33,12 @@ PARAMETERS:
 int chip_addr[10]:
        The SMBus addresses to emulate chips at.
 
+unsigned long functionality:
+       Functionality override, to disable some commands. See I2C_FUNC_*
+       constants in <linux/i2c.h> for the suitable values. For example,
+       value 0x1f0000 would only enable the quick, byte and byte data
+       commands.
+
 CAVEATS:
 
 If your target driver polls some byte or word waiting for it to change, the
diff --git a/Documentation/i2c/old-module-parameters b/Documentation/i2c/old-module-parameters
new file mode 100644 (file)
index 0000000..8e2b629
--- /dev/null
@@ -0,0 +1,44 @@
+I2C device driver binding control from user-space
+=================================================
+
+Up to kernel 2.6.32, many i2c drivers used helper macros provided by
+<linux/i2c.h> which created standard module parameters to let the user
+control how the driver would probe i2c buses and attach to devices. These
+parameters were known as "probe" (to let the driver probe for an extra
+address), "force" (to forcibly attach the driver to a given device) and
+"ignore" (to prevent a driver from probing a given address).
+
+With the conversion of the i2c subsystem to the standard device driver
+binding model, it became clear that these per-module parameters were no
+longer needed, and that a centralized implementation was possible. The new,
+sysfs-based interface is described in the documentation file
+"instantiating-devices", section "Method 4: Instantiate from user-space".
+
+Below is a mapping from the old module parameters to the new interface.
+
+Attaching a driver to an I2C device
+-----------------------------------
+
+Old method (module parameters):
+# modprobe <driver> probe=1,0x2d
+# modprobe <driver> force=1,0x2d
+# modprobe <driver> force_<device>=1,0x2d
+
+New method (sysfs interface):
+# echo <device> 0x2d > /sys/bus/i2c/devices/i2c-1/new_device
+
+Preventing a driver from attaching to an I2C device
+---------------------------------------------------
+
+Old method (module parameters):
+# modprobe <driver> ignore=1,0x2f
+
+New method (sysfs interface):
+# echo dummy 0x2f > /sys/bus/i2c/devices/i2c-1/new_device
+# modprobe <driver>
+
+Of course, it is important to instantiate the "dummy" device before loading
+the driver. The dummy device will be handled by i2c-core itself, preventing
+other drivers from binding to it later on. If there is a real device at the
+problematic address, and you want another driver to bind to it, then simply
+pass the name of the device in question instead of "dummy".
index d8ce217..495a39a 100644 (file)
@@ -344,6 +344,15 @@ and is between 256 and 4096 characters. It is defined in the file
                        Change the amount of debugging information output
                        when initialising the APIC and IO-APIC components.
 
+       show_lapic=     [APIC,X86] Advanced Programmable Interrupt Controller
+                       Limit apic dumping. The parameter defines the maximal
+                       number of local apics being dumped. Also it is possible
+                       to set it to "all" by meaning -- no limit here.
+                       Format: { 1 (default) | 2 | ... | all }.
+                       The parameter valid if only apic=debug or
+                       apic=verbose is specified.
+                       Example: apic=debug show_lapic=all
+
        apm=            [APM] Advanced Power Management
                        See header of arch/x86/kernel/apm_32.c.
 
@@ -2186,6 +2195,8 @@ and is between 256 and 4096 characters. It is defined in the file
 
        sbni=           [NET] Granch SBNI12 leased line adapter
 
+       sched_debug     [KNL] Enables verbose scheduler debug messages.
+
        sc1200wdt=      [HW,WDT] SC1200 WDT (watchdog) driver
                        Format: <io>[,<timeout>[,<isapnp>]]
 
index 5a4bc8c..e1a1141 100644 (file)
@@ -593,6 +593,115 @@ struct kvm_irqchip {
        } chip;
 };
 
+4.27 KVM_XEN_HVM_CONFIG
+
+Capability: KVM_CAP_XEN_HVM
+Architectures: x86
+Type: vm ioctl
+Parameters: struct kvm_xen_hvm_config (in)
+Returns: 0 on success, -1 on error
+
+Sets the MSR that the Xen HVM guest uses to initialize its hypercall
+page, and provides the starting address and size of the hypercall
+blobs in userspace.  When the guest writes the MSR, kvm copies one
+page of a blob (32- or 64-bit, depending on the vcpu mode) to guest
+memory.
+
+struct kvm_xen_hvm_config {
+       __u32 flags;
+       __u32 msr;
+       __u64 blob_addr_32;
+       __u64 blob_addr_64;
+       __u8 blob_size_32;
+       __u8 blob_size_64;
+       __u8 pad2[30];
+};
+
+4.27 KVM_GET_CLOCK
+
+Capability: KVM_CAP_ADJUST_CLOCK
+Architectures: x86
+Type: vm ioctl
+Parameters: struct kvm_clock_data (out)
+Returns: 0 on success, -1 on error
+
+Gets the current timestamp of kvmclock as seen by the current guest. In
+conjunction with KVM_SET_CLOCK, it is used to ensure monotonicity on scenarios
+such as migration.
+
+struct kvm_clock_data {
+       __u64 clock;  /* kvmclock current value */
+       __u32 flags;
+       __u32 pad[9];
+};
+
+4.28 KVM_SET_CLOCK
+
+Capability: KVM_CAP_ADJUST_CLOCK
+Architectures: x86
+Type: vm ioctl
+Parameters: struct kvm_clock_data (in)
+Returns: 0 on success, -1 on error
+
+Sets the current timestamp of kvmclock to the valued specific in its parameter.
+In conjunction with KVM_GET_CLOCK, it is used to ensure monotonicity on scenarios
+such as migration.
+
+struct kvm_clock_data {
+       __u64 clock;  /* kvmclock current value */
+       __u32 flags;
+       __u32 pad[9];
+};
+
+4.29 KVM_GET_VCPU_EVENTS
+
+Capability: KVM_CAP_VCPU_EVENTS
+Architectures: x86
+Type: vm ioctl
+Parameters: struct kvm_vcpu_event (out)
+Returns: 0 on success, -1 on error
+
+Gets currently pending exceptions, interrupts, and NMIs as well as related
+states of the vcpu.
+
+struct kvm_vcpu_events {
+       struct {
+               __u8 injected;
+               __u8 nr;
+               __u8 has_error_code;
+               __u8 pad;
+               __u32 error_code;
+       } exception;
+       struct {
+               __u8 injected;
+               __u8 nr;
+               __u8 soft;
+               __u8 pad;
+       } interrupt;
+       struct {
+               __u8 injected;
+               __u8 pending;
+               __u8 masked;
+               __u8 pad;
+       } nmi;
+       __u32 sipi_vector;
+       __u32 flags;   /* must be zero */
+};
+
+4.30 KVM_SET_VCPU_EVENTS
+
+Capability: KVM_CAP_VCPU_EVENTS
+Architectures: x86
+Type: vm ioctl
+Parameters: struct kvm_vcpu_event (in)
+Returns: 0 on success, -1 on error
+
+Set pending exceptions, interrupts, and NMIs as well as related states of the
+vcpu.
+
+See KVM_GET_VCPU_EVENTS for the data structure.
+
+
 5. The kvm_run structure
 
 Application code obtains a pointer to the kvm_run structure by
index f49a33b..4a3109b 100644 (file)
@@ -38,7 +38,7 @@ struct dev_pm_ops {
        ...
        int (*runtime_suspend)(struct device *dev);
        int (*runtime_resume)(struct device *dev);
-       void (*runtime_idle)(struct device *dev);
+       int (*runtime_idle)(struct device *dev);
        ...
 };
 
@@ -71,9 +71,9 @@ what to do to handle the device).
     purpose).
 
 In particular, if the driver requires remote wakeup capability for proper
-functioning and device_may_wakeup() returns 'false' for the device, then
+functioning and device_run_wake() returns 'false' for the device, then
 ->runtime_suspend() should return -EBUSY.  On the other hand, if
-device_may_wakeup() returns 'true' for the device and the device is put
+device_run_wake() returns 'true' for the device and the device is put
 into a low power state during the execution of its bus type's
 ->runtime_suspend(), it is expected that remote wake-up (i.e. hardware mechanism
 allowing the device to request a change of its power state, such as PCI PME)
@@ -114,7 +114,8 @@ The action performed by a bus type's ->runtime_idle() callback is totally
 dependent on the bus type in question, but the expected and recommended action
 is to check if the device can be suspended (i.e. if all of the conditions
 necessary for suspending the device are satisfied) and to queue up a suspend
-request for the device in that case.
+request for the device in that case.  The value returned by this callback is
+ignored by the PM core.
 
 The helper functions provided by the PM core, described in Section 4, guarantee
 that the following constraints are met with respect to the bus type's run-time
@@ -214,6 +215,9 @@ defined in include/linux/pm.h:
       being executed for that device and it is not practical to wait for the
       suspend to complete; means "start a resume as soon as you've suspended"
 
+  unsigned int run_wake;
+    - set if the device is capable of generating run-time wake-up events
+
   enum rpm_status runtime_status;
     - the run-time PM status of the device; this field's initial value is
       RPM_SUSPENDED, which means that each device is initially regarded by the
index fd9a2f6..8923597 100644 (file)
@@ -798,6 +798,9 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
                setup before initializing the codecs.  This option is
                available only when CONFIG_SND_HDA_PATCH_LOADER=y is set.
                See HD-Audio.txt for details.
+    beep_mode  - Selects the beep registration mode (0=off, 1=on, 2=
+               dynamic registration via mute switch on/off); the default
+               value is set via CONFIG_SND_HDA_INPUT_BEEP_MODE kconfig.
     
     [Single (global) options]
     single_cmd  - Use single immediate commands to communicate with
@@ -1454,6 +1457,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
 
     Module for internal PC-Speaker.
 
+    nopcm      - Disable PC-Speaker PCM sound. Only beeps remain.
     nforce_wa  - enable NForce chipset workaround. Expect bad sound.
 
     This module supports system beeps, some kind of PCM playback and
@@ -1631,7 +1635,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
   Module snd-sscape
   -----------------
 
-    Module for ENSONIQ SoundScape PnP cards.
+    Module for ENSONIQ SoundScape cards.
 
     port       - Port # (PnP setup)
     wss_port   - WSS Port # (PnP setup)
@@ -1639,10 +1643,11 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
     mpu_irq    - MPU-401 IRQ # (PnP setup)
     dma                - DMA # (PnP setup)
     dma2       - 2nd DMA # (PnP setup, -1 to disable)
+    joystick   - Enable gameport - 0 = disable (default), 1 = enable
+
+    This module supports multiple cards.
 
-    This module supports multiple cards.  ISA PnP must be enabled.
-    You need sscape_ctl tool in alsa-tools package for loading
-    the microcode.
+    The driver requires the firmware loader support on kernel.
 
   Module snd-sun-amd7930 (on sparc only)
   --------------------------------------
index 5b18298..fea65bb 100644 (file)
@@ -18,8 +18,9 @@ SOURCE:
   Master
   Master Mono
   Hardware Master
+  Speaker      (internal speaker)
   Headphone
-  PC Speaker
+  Beep         (beep generator)
   Phone
   Phone Input
   Phone Output
index 4c7f9ae..9000cd8 100644 (file)
@@ -391,6 +391,7 @@ STAC92HD83*
   ref          Reference board
   mic-ref      Reference board with power management for ports
   dell-s14     Dell laptop
+  hp           HP laptops with (inverted) mute-LED
   auto         BIOS setup (default)
 
 STAC9872
diff --git a/Documentation/sysctl/ctl_unnumbered.txt b/Documentation/sysctl/ctl_unnumbered.txt
deleted file mode 100644 (file)
index 23003a8..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-
-Except for a few extremely rare exceptions user space applications do not use
-the binary sysctl interface.  Instead everyone uses /proc/sys/...  with
-readable ascii names.
-
-Recently the kernel has started supporting setting the binary sysctl value to
-CTL_UNNUMBERED so we no longer need to assign a binary sysctl path to allow
-sysctls to show up in /proc/sys.
-
-Assigning binary sysctl numbers is an endless source of conflicts in sysctl.h,
-breaking of the user space ABI (because of those conflicts), and maintenance
-problems.  A complete pass through all of the sysctl users revealed multiple
-instances where the sysctl binary interface was broken and had gone undetected
-for years.
-
-So please do not add new binary sysctl numbers.  They are unneeded and
-problematic.
-
-If you really need a new binary sysctl number please first merge your sysctl
-into the kernel and then as a separate patch allocate a binary sysctl number.
-
-(ebiederm@xmission.com, June 2007)
diff --git a/Documentation/trace/kprobetrace.txt b/Documentation/trace/kprobetrace.txt
new file mode 100644 (file)
index 0000000..47aabee
--- /dev/null
@@ -0,0 +1,149 @@
+                        Kprobe-based Event Tracing
+                        ==========================
+
+                 Documentation is written by Masami Hiramatsu
+
+
+Overview
+--------
+These events are similar to tracepoint based events. Instead of Tracepoint,
+this is based on kprobes (kprobe and kretprobe). So it can probe wherever
+kprobes can probe (this means, all functions body except for __kprobes
+functions). Unlike the Tracepoint based event, this can be added and removed
+dynamically, on the fly.
+
+To enable this feature, build your kernel with CONFIG_KPROBE_TRACING=y.
+
+Similar to the events tracer, this doesn't need to be activated via
+current_tracer. Instead of that, add probe points via
+/sys/kernel/debug/tracing/kprobe_events, and enable it via
+/sys/kernel/debug/tracing/events/kprobes/<EVENT>/enabled.
+
+
+Synopsis of kprobe_events
+-------------------------
+  p[:[GRP/]EVENT] SYMBOL[+offs]|MEMADDR [FETCHARGS]    : Set a probe
+  r[:[GRP/]EVENT] SYMBOL[+0] [FETCHARGS]               : Set a return probe
+
+ GRP           : Group name. If omitted, use "kprobes" for it.
+ EVENT         : Event name. If omitted, the event name is generated
+                 based on SYMBOL+offs or MEMADDR.
+ SYMBOL[+offs] : Symbol+offset where the probe is inserted.
+ MEMADDR       : Address where the probe is inserted.
+
+ FETCHARGS     : Arguments. Each probe can have up to 128 args.
+  %REG         : Fetch register REG
+  @ADDR                : Fetch memory at ADDR (ADDR should be in kernel)
+  @SYM[+|-offs]        : Fetch memory at SYM +|- offs (SYM should be a data symbol)
+  $stackN      : Fetch Nth entry of stack (N >= 0)
+  $stack       : Fetch stack address.
+  $argN                : Fetch function argument. (N >= 0)(*)
+  $retval      : Fetch return value.(**)
+  +|-offs(FETCHARG) : Fetch memory at FETCHARG +|- offs address.(***)
+  NAME=FETCHARG: Set NAME as the argument name of FETCHARG.
+
+  (*) aN may not correct on asmlinkaged functions and at the middle of
+      function body.
+  (**) only for return probe.
+  (***) this is useful for fetching a field of data structures.
+
+
+Per-Probe Event Filtering
+-------------------------
+ Per-probe event filtering feature allows you to set different filter on each
+probe and gives you what arguments will be shown in trace buffer. If an event
+name is specified right after 'p:' or 'r:' in kprobe_events, it adds an event
+under tracing/events/kprobes/<EVENT>, at the directory you can see 'id',
+'enabled', 'format' and 'filter'.
+
+enabled:
+  You can enable/disable the probe by writing 1 or 0 on it.
+
+format:
+  This shows the format of this probe event.
+
+filter:
+  You can write filtering rules of this event.
+
+id:
+  This shows the id of this probe event.
+
+
+Event Profiling
+---------------
+ You can check the total number of probe hits and probe miss-hits via
+/sys/kernel/debug/tracing/kprobe_profile.
+ The first column is event name, the second is the number of probe hits,
+the third is the number of probe miss-hits.
+
+
+Usage examples
+--------------
+To add a probe as a new event, write a new definition to kprobe_events
+as below.
+
+  echo p:myprobe do_sys_open dfd=$arg0 filename=$arg1 flags=$arg2 mode=$arg3 > /sys/kernel/debug/tracing/kprobe_events
+
+ This sets a kprobe on the top of do_sys_open() function with recording
+1st to 4th arguments as "myprobe" event. As this example shows, users can
+choose more familiar names for each arguments.
+
+  echo r:myretprobe do_sys_open $retval >> /sys/kernel/debug/tracing/kprobe_events
+
+ This sets a kretprobe on the return point of do_sys_open() function with
+recording return value as "myretprobe" event.
+ You can see the format of these events via
+/sys/kernel/debug/tracing/events/kprobes/<EVENT>/format.
+
+  cat /sys/kernel/debug/tracing/events/kprobes/myprobe/format
+name: myprobe
+ID: 75
+format:
+       field:unsigned short common_type;       offset:0;       size:2;
+       field:unsigned char common_flags;       offset:2;       size:1;
+       field:unsigned char common_preempt_count;       offset:3;       size:1;
+       field:int common_pid;   offset:4;       size:4;
+       field:int common_tgid;  offset:8;       size:4;
+
+       field: unsigned long ip;        offset:16;tsize:8;
+       field: int nargs;       offset:24;tsize:4;
+       field: unsigned long dfd;       offset:32;tsize:8;
+       field: unsigned long filename;  offset:40;tsize:8;
+       field: unsigned long flags;     offset:48;tsize:8;
+       field: unsigned long mode;      offset:56;tsize:8;
+
+print fmt: "(%lx) dfd=%lx filename=%lx flags=%lx mode=%lx", REC->ip, REC->dfd, REC->filename, REC->flags, REC->mode
+
+
+ You can see that the event has 4 arguments as in the expressions you specified.
+
+  echo > /sys/kernel/debug/tracing/kprobe_events
+
+ This clears all probe points.
+
+ Right after definition, each event is disabled by default. For tracing these
+events, you need to enable it.
+
+  echo 1 > /sys/kernel/debug/tracing/events/kprobes/myprobe/enable
+  echo 1 > /sys/kernel/debug/tracing/events/kprobes/myretprobe/enable
+
+ And you can see the traced information via /sys/kernel/debug/tracing/trace.
+
+  cat /sys/kernel/debug/tracing/trace
+# tracer: nop
+#
+#           TASK-PID    CPU#    TIMESTAMP  FUNCTION
+#              | |       |          |         |
+           <...>-1447  [001] 1038282.286875: myprobe: (do_sys_open+0x0/0xd6) dfd=3 filename=7fffd1ec4440 flags=8000 mode=0
+           <...>-1447  [001] 1038282.286878: myretprobe: (sys_openat+0xc/0xe <- do_sys_open) $retval=fffffffffffffffe
+           <...>-1447  [001] 1038282.286885: myprobe: (do_sys_open+0x0/0xd6) dfd=ffffff9c filename=40413c flags=8000 mode=1b6
+           <...>-1447  [001] 1038282.286915: myretprobe: (sys_open+0x1b/0x1d <- do_sys_open) $retval=3
+           <...>-1447  [001] 1038282.286969: myprobe: (do_sys_open+0x0/0xd6) dfd=ffffff9c filename=4041c6 flags=98800 mode=10
+           <...>-1447  [001] 1038282.286976: myretprobe: (sys_open+0x1b/0x1d <- do_sys_open) $retval=3
+
+
+ Each line shows when the kernel hits an event, and <- SYMBOL means kernel
+returns from SYMBOL(e.g. "sys_open+0x1b/0x1d <- do_sys_open" means kernel
+returns from do_sys_open to sys_open+0x1b).
+
+
index 89ceb40..ea781c1 100644 (file)
@@ -659,6 +659,9 @@ ARM/FREESCALE IMX / MXC ARM ARCHITECTURE
 M:     Sascha Hauer <kernel@pengutronix.de>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:     Maintained
+T:     git://git.pengutronix.de/git/imx/linux-2.6.git
+F:     arch/arm/mach-mx*/
+F:     arch/arm/plat-mxc/
 
 ARM/GLOMATION GESBC9312SX MACHINE SUPPORT
 M:     Lennert Buytenhek <kernel@wantstofly.org>
@@ -729,6 +732,19 @@ L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:     Maintained
 F:     arch/arm/mach-ixp4xx/
 
+ARM/INTEL RESEARCH IMOTE 2 MACHINE SUPPORT
+M:     Jonathan Cameron <jic23@cam.ac.uk>
+L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
+S:     Maintained
+F:     arch/arm/mach-pxa/imote2.c
+
+ARM/INTEL RESEARCH STARGATE 2 MACHINE SUPPORT
+M:     Jonathan Cameron <jic23@cam.ac.uk>
+L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
+S:     Maintained
+F:     arch/arm/mach-pxa/stargate2.c
+F:     drivers/pcmcia/pxa2xx_stargate2.c
+
 ARM/INTEL XSC3 (MANZANO) ARM CORE
 M:     Lennert Buytenhek <kernel@wantstofly.org>
 M:     Dan Williams <dan.j.williams@intel.com>
@@ -771,6 +787,14 @@ ARM/NEC MOBILEPRO 900/c MACHINE SUPPORT
 M:     Michael Petchkovsky <mkpetch@internode.on.net>
 S:     Maintained
 
+ARM/NOMADIK ARCHITECTURE
+M:     Alessandro Rubini <rubini@unipv.it>
+M:     STEricsson <STEricsson_nomadik_linux@list.st.com>
+L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
+S:     Maintained
+F:     arch/arm/mach-nomadik/
+F:     arch/arm/plat-nomadik/
+
 ARM/OPENMOKO NEO FREERUNNER (GTA02) MACHINE SUPPORT
 M:     Nelson Castillo <arhuaco@freaks-unidos.net>
 L:     openmoko-kernel@lists.openmoko.org (subscribers-only)
@@ -915,6 +939,12 @@ L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 W:     http://www.mcuos.com
 S:     Maintained
 
+ARM/U8500 ARM ARCHITECTURE
+M:     Srinidhi Kasagar <srinidhi.kasagar@stericsson.com>
+L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
+S:     Maintained
+F:     arch/arm/mach-ux500/
+
 ARM/VFP SUPPORT
 M:     Russell King <linux@arm.linux.org.uk>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
@@ -1818,6 +1848,19 @@ S:       Maintained
 F:     drivers/scsi/dpt*
 F:     drivers/scsi/dpt/
 
+DRBD DRIVER
+P:     Philipp Reisner
+P:     Lars Ellenberg
+M:     drbd-dev@lists.linbit.com
+L:     drbd-user@lists.linbit.com
+W:     http://www.drbd.org
+T:     git git://git.drbd.org/linux-2.6-drbd.git drbd
+T:     git git://git.drbd.org/drbd-8.3.git
+S:     Supported
+F:     drivers/block/drbd/
+F:     lib/lru_cache.c
+F:     Documentation/blockdev/drbd/
+
 DRIVER CORE, KOBJECTS, AND SYSFS
 M:     Greg Kroah-Hartman <gregkh@suse.de>
 T:     quilt kernel.org/pub/linux/kernel/people/gregkh/gregkh-2.6/
index 7f418bb..d828758 100644 (file)
@@ -83,6 +83,13 @@ config KRETPROBES
        def_bool y
        depends on KPROBES && HAVE_KRETPROBES
 
+config USER_RETURN_NOTIFIER
+       bool
+       depends on HAVE_USER_RETURN_NOTIFIER
+       help
+         Provide a kernel-internal notification when a cpu is about to
+         switch to user mode.
+
 config HAVE_IOREMAP_PROT
        bool
 
@@ -126,4 +133,13 @@ config HAVE_DMA_API_DEBUG
 config HAVE_DEFAULT_NO_SPIN_MUTEXES
        bool
 
+config HAVE_HW_BREAKPOINT
+       bool
+       depends on HAVE_PERF_EVENTS
+       select ANON_INODES
+       select PERF_EVENTS
+
+config HAVE_USER_RETURN_NOTIFIER
+       bool
+
 source "kernel/gcov/Kconfig"
index b686cc7..01d71e1 100644 (file)
@@ -9,6 +9,7 @@
 #define flush_cache_dup_mm(mm)                 do { } while (0)
 #define flush_cache_range(vma, start, end)     do { } while (0)
 #define flush_cache_page(vma, vmaddr, pfn)     do { } while (0)
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 0
 #define flush_dcache_page(page)                        do { } while (0)
 #define flush_dcache_mmap_lock(mapping)                do { } while (0)
 #define flush_dcache_mmap_unlock(mapping)      do { } while (0)
index 1c4119c..cf8a99f 100644 (file)
@@ -433,6 +433,17 @@ config ARCH_L7200
          If you have any questions or comments about the Linux kernel port
          to this board, send e-mail to <sjhill@cotw.com>.
 
+config ARCH_DOVE
+       bool "Marvell Dove"
+       select PCI
+       select GENERIC_GPIO
+       select ARCH_REQUIRE_GPIOLIB
+       select GENERIC_TIME
+       select GENERIC_CLOCKEVENTS
+       select PLAT_ORION
+       help
+         Support for the Marvell Dove SoC 88AP510
+
 config ARCH_KIRKWOOD
        bool "Marvell Kirkwood"
        select CPU_FEROCEON
@@ -702,6 +713,16 @@ config ARCH_BCMRING
        help
          Support for Broadcom's BCMRing platform.
 
+config ARCH_U8500
+       bool "ST-Ericsson U8500 Series"
+       select CPU_V7
+       select ARM_AMBA
+       select GENERIC_TIME
+       select GENERIC_CLOCKEVENTS
+       select COMMON_CLKDEV
+       help
+         Support for ST-Ericsson's Ux500 architecture
+
 endchoice
 
 source "arch/arm/mach-clps711x/Kconfig"
@@ -747,6 +768,9 @@ source "arch/arm/mach-orion5x/Kconfig"
 
 source "arch/arm/mach-kirkwood/Kconfig"
 
+source "arch/arm/mach-dove/Kconfig"
+
+source "arch/arm/plat-samsung/Kconfig"
 source "arch/arm/plat-s3c24xx/Kconfig"
 source "arch/arm/plat-s3c64xx/Kconfig"
 source "arch/arm/plat-s3c/Kconfig"
@@ -787,6 +811,7 @@ source "arch/arm/mach-at91/Kconfig"
 source "arch/arm/plat-mxc/Kconfig"
 
 source "arch/arm/mach-nomadik/Kconfig"
+source "arch/arm/plat-nomadik/Kconfig"
 
 source "arch/arm/mach-netx/Kconfig"
 
@@ -804,12 +829,16 @@ source "arch/arm/mach-w90x900/Kconfig"
 
 source "arch/arm/mach-bcmring/Kconfig"
 
+source "arch/arm/mach-ux500/Kconfig"
+
 # Definitions to make life easier
 config ARCH_ACORN
        bool
 
 config PLAT_IOP
        bool
+       select GENERIC_CLOCKEVENTS
+       select GENERIC_TIME
 
 config PLAT_ORION
        bool
@@ -955,10 +984,10 @@ source "kernel/time/Kconfig"
 config SMP
        bool "Symmetric Multi-Processing (EXPERIMENTAL)"
        depends on EXPERIMENTAL && (REALVIEW_EB_ARM11MP || REALVIEW_EB_A9MP ||\
-                MACH_REALVIEW_PB11MP || MACH_REALVIEW_PBX || ARCH_OMAP4)
+                MACH_REALVIEW_PB11MP || MACH_REALVIEW_PBX || ARCH_OMAP4 || ARCH_U8500)
        depends on GENERIC_CLOCKEVENTS
        select USE_GENERIC_SMP_HELPERS
-       select HAVE_ARM_SCU if (ARCH_REALVIEW || ARCH_OMAP4)
+       select HAVE_ARM_SCU if (ARCH_REALVIEW || ARCH_OMAP4 || ARCH_U8500)
        help
          This enables support for systems with more than one CPU. If you have
          a system with only one CPU, like most personal computers, say N. If
@@ -1027,9 +1056,9 @@ config HOTPLUG_CPU
 config LOCAL_TIMERS
        bool "Use local timer interrupts"
        depends on SMP && (REALVIEW_EB_ARM11MP || MACH_REALVIEW_PB11MP || \
-               REALVIEW_EB_A9MP || MACH_REALVIEW_PBX || ARCH_OMAP4)
+               REALVIEW_EB_A9MP || MACH_REALVIEW_PBX || ARCH_OMAP4 || ARCH_U8500)
        default y
-       select HAVE_ARM_TWD if (ARCH_REALVIEW || ARCH_OMAP4)
+       select HAVE_ARM_TWD if (ARCH_REALVIEW || ARCH_OMAP4 || ARCH_U8500)
        help
          Enable support for local timers on SMP platforms, rather then the
          legacy IPI broadcast method.  Local timers allows the system
index 1a6f70e..ff54c23 100644 (file)
@@ -83,6 +83,14 @@ config DEBUG_ICEDCC
          It does include a timeout to ensure that the system does not
          totally freeze when there is nothing connected to read.
 
+config OC_ETM
+       bool "On-chip ETM and ETB"
+       select ARM_AMBA
+       help
+         Enables the on-chip embedded trace macrocell and embedded trace
+         buffer driver that will allow you to collect traces of the
+         kernel code.
+
 config DEBUG_DC21285_PORT
        bool "Kernel low-level debugging messages via footbridge serial port"
        depends on DEBUG_LL && FOOTBRIDGE
index a73caaf..fa0cdab 100644 (file)
@@ -122,6 +122,7 @@ machine-$(CONFIG_ARCH_AT91)         := at91
 machine-$(CONFIG_ARCH_BCMRING)         := bcmring
 machine-$(CONFIG_ARCH_CLPS711X)                := clps711x
 machine-$(CONFIG_ARCH_DAVINCI)         := davinci
+machine-$(CONFIG_ARCH_DOVE)            := dove
 machine-$(CONFIG_ARCH_EBSA110)         := ebsa110
 machine-$(CONFIG_ARCH_EP93XX)          := ep93xx
 machine-$(CONFIG_ARCH_GEMINI)          := gemini
@@ -166,6 +167,7 @@ machine-$(CONFIG_ARCH_SHARK)                := shark
 machine-$(CONFIG_ARCH_STMP378X)                := stmp378x
 machine-$(CONFIG_ARCH_STMP37XX)                := stmp37xx
 machine-$(CONFIG_ARCH_U300)            := u300
+machine-$(CONFIG_ARCH_U8500)           := ux500
 machine-$(CONFIG_ARCH_VERSATILE)       := versatile
 machine-$(CONFIG_ARCH_W90X900)         := w90x900
 machine-$(CONFIG_FOOTBRIDGE)           := footbridge
@@ -176,11 +178,12 @@ machine-$(CONFIG_ARCH_MXC91231)           := mxc91231
 plat-$(CONFIG_ARCH_MXC)                := mxc
 plat-$(CONFIG_ARCH_OMAP)       := omap
 plat-$(CONFIG_PLAT_IOP)                := iop
+plat-$(CONFIG_PLAT_NOMADIK)    := nomadik
 plat-$(CONFIG_PLAT_ORION)      := orion
 plat-$(CONFIG_PLAT_PXA)                := pxa
-plat-$(CONFIG_PLAT_S3C24XX)    := s3c24xx s3c
-plat-$(CONFIG_PLAT_S3C64XX)    := s3c64xx s3c
-plat-$(CONFIG_PLAT_S5PC1XX)    := s5pc1xx s3c
+plat-$(CONFIG_PLAT_S3C24XX)    := s3c24xx s3c samsung
+plat-$(CONFIG_PLAT_S3C64XX)    := s3c64xx s3c samsung
+plat-$(CONFIG_PLAT_S5PC1XX)    := s5pc1xx s3c samsung
 plat-$(CONFIG_ARCH_STMP3XXX)   := stmp3xxx
 
 ifeq ($(CONFIG_ARCH_EBSA110),y)
index fa6fbf4..d356af7 100644 (file)
@@ -743,6 +743,12 @@ proc_types:
                W(b)    __armv4_mmu_cache_off
                W(b)    __armv6_mmu_cache_flush
 
+               .word   0x560f5810              @ Marvell PJ4 ARMv6
+               .word   0xff0ffff0
+               W(b)    __armv4_mmu_cache_on
+               W(b)    __armv4_mmu_cache_off
+               W(b)    __armv6_mmu_cache_flush
+
                .word   0x000f0000              @ new CPU Id
                .word   0x000f0000
                W(b)    __armv7_mmu_cache_on
index 734ac91..5a375e5 100644 (file)
@@ -342,6 +342,22 @@ dma_addr_t dma_map_single(struct device *dev, void *ptr, size_t size,
 }
 EXPORT_SYMBOL(dma_map_single);
 
+/*
+ * see if a mapped address was really a "safe" buffer and if so, copy
+ * the data from the safe buffer back to the unsafe buffer and free up
+ * the safe buffer.  (basically return things back to the way they
+ * should be)
+ */
+void dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size,
+               enum dma_data_direction dir)
+{
+       dev_dbg(dev, "%s(ptr=%p,size=%d,dir=%x)\n",
+               __func__, (void *) dma_addr, size, dir);
+
+       unmap_single(dev, dma_addr, size, dir);
+}
+EXPORT_SYMBOL(dma_unmap_single);
+
 dma_addr_t dma_map_page(struct device *dev, struct page *page,
                unsigned long offset, size_t size, enum dma_data_direction dir)
 {
@@ -366,8 +382,7 @@ EXPORT_SYMBOL(dma_map_page);
  * the safe buffer.  (basically return things back to the way they
  * should be)
  */
-
-void dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size,
+void dma_unmap_page(struct device *dev, dma_addr_t dma_addr, size_t size,
                enum dma_data_direction dir)
 {
        dev_dbg(dev, "%s(ptr=%p,size=%d,dir=%x)\n",
@@ -375,7 +390,7 @@ void dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size,
 
        unmap_single(dev, dma_addr, size, dir);
 }
-EXPORT_SYMBOL(dma_unmap_single);
+EXPORT_SYMBOL(dma_unmap_page);
 
 int dmabounce_sync_for_cpu(struct device *dev, dma_addr_t addr,
                unsigned long off, size_t sz, enum dma_data_direction dir)
diff --git a/arch/arm/configs/am3517_evm_defconfig b/arch/arm/configs/am3517_evm_defconfig
new file mode 100644 (file)
index 0000000..ad54e92
--- /dev/null
@@ -0,0 +1,1207 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.32-rc5
+# Wed Oct 28 15:47:47 2009
+#
+CONFIG_ARM=y
+CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+CONFIG_GENERIC_GPIO=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_ARCH_HAS_CPUFREQ=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
+CONFIG_VECTORS_BASE=0xffff0000
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+# CONFIG_POSIX_MQUEUE is not set
+CONFIG_BSD_PROCESS_ACCT=y
+# CONFIG_BSD_PROCESS_ACCT_V3 is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_AUDIT is not set
+
+#
+# RCU Subsystem
+#
+CONFIG_TREE_RCU=y
+# CONFIG_TREE_PREEMPT_RCU is not set
+# CONFIG_RCU_TRACE is not set
+CONFIG_RCU_FANOUT=32
+# CONFIG_RCU_FANOUT_EXACT is not set
+# CONFIG_TREE_RCU_TRACE is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_GROUP_SCHED=y
+CONFIG_FAIR_GROUP_SCHED=y
+# CONFIG_RT_GROUP_SCHED is not set
+CONFIG_USER_SCHED=y
+# CONFIG_CGROUP_SCHED is not set
+# CONFIG_CGROUPS is not set
+CONFIG_SYSFS_DEPRECATED=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+# CONFIG_RELAY is not set
+# CONFIG_NAMESPACES is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_RD_GZIP=y
+# CONFIG_RD_BZIP2 is not set
+# CONFIG_RD_LZMA is not set
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+CONFIG_ANON_INODES=y
+CONFIG_EMBEDDED=y
+CONFIG_UID16=y
+# CONFIG_SYSCTL_SYSCALL is not set
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+CONFIG_KALLSYMS_EXTRA_PASS=y
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_AIO=y
+
+#
+# Kernel Performance Events And Counters
+#
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_COMPAT_BRK=y
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
+# CONFIG_PROFILING is not set
+CONFIG_HAVE_OPROFILE=y
+# CONFIG_KPROBES is not set
+CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_KRETPROBES=y
+CONFIG_HAVE_CLK=y
+
+#
+# GCOV-based kernel profiling
+#
+# CONFIG_SLOW_WORK is not set
+CONFIG_HAVE_GENERIC_DMA_COHERENT=y
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+# CONFIG_MODULE_FORCE_LOAD is not set
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+CONFIG_MODVERSIONS=y
+CONFIG_MODULE_SRCVERSION_ALL=y
+CONFIG_BLOCK=y
+CONFIG_LBDAF=y
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_BLK_DEV_INTEGRITY is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+CONFIG_DEFAULT_AS=y
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="anticipatory"
+# CONFIG_FREEZER is not set
+
+#
+# System Type
+#
+CONFIG_MMU=y
+# CONFIG_ARCH_AAEC2000 is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_REALVIEW is not set
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_AT91 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_GEMINI is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_EP93XX is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_MXC is not set
+# CONFIG_ARCH_STMP3XXX is not set
+# CONFIG_ARCH_NETX is not set
+# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_NOMADIK is not set
+# CONFIG_ARCH_IOP13XX is not set
+# CONFIG_ARCH_IOP32X is not set
+# CONFIG_ARCH_IOP33X is not set
+# CONFIG_ARCH_IXP23XX is not set
+# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_KIRKWOOD is not set
+# CONFIG_ARCH_LOKI is not set
+# CONFIG_ARCH_MV78XX0 is not set
+# CONFIG_ARCH_ORION5X is not set
+# CONFIG_ARCH_MMP is not set
+# CONFIG_ARCH_KS8695 is not set
+# CONFIG_ARCH_NS9XXX is not set
+# CONFIG_ARCH_W90X900 is not set
+# CONFIG_ARCH_PNX4008 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_MSM is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_S3C64XX is not set
+# CONFIG_ARCH_S5PC1XX is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_U300 is not set
+# CONFIG_ARCH_DAVINCI is not set
+CONFIG_ARCH_OMAP=y
+# CONFIG_ARCH_BCMRING is not set
+
+#
+# TI OMAP Implementations
+#
+CONFIG_ARCH_OMAP_OTG=y
+# CONFIG_ARCH_OMAP1 is not set
+# CONFIG_ARCH_OMAP2 is not set
+CONFIG_ARCH_OMAP3=y
+# CONFIG_ARCH_OMAP4 is not set
+
+#
+# OMAP Feature Selections
+#
+# CONFIG_OMAP_DEBUG_POWERDOMAIN is not set
+# CONFIG_OMAP_DEBUG_CLOCKDOMAIN is not set
+CONFIG_OMAP_RESET_CLOCKS=y
+# CONFIG_OMAP_MUX is not set
+# CONFIG_OMAP_MCBSP is not set
+# CONFIG_OMAP_MBOX_FWK is not set
+# CONFIG_OMAP_MPU_TIMER is not set
+CONFIG_OMAP_32K_TIMER=y
+CONFIG_OMAP_32K_TIMER_HZ=128
+CONFIG_OMAP_DM_TIMER=y
+# CONFIG_OMAP_LL_DEBUG_UART1 is not set
+# CONFIG_OMAP_LL_DEBUG_UART2 is not set
+CONFIG_OMAP_LL_DEBUG_UART3=y
+# CONFIG_OMAP_PM_NONE is not set
+CONFIG_OMAP_PM_NOOP=y
+CONFIG_ARCH_OMAP34XX=y
+CONFIG_ARCH_OMAP3430=y
+
+#
+# OMAP Board Type
+#
+# CONFIG_MACH_OMAP3_BEAGLE is not set
+# CONFIG_MACH_OMAP_LDP is not set
+# CONFIG_MACH_OVERO is not set
+# CONFIG_MACH_OMAP3EVM is not set
+CONFIG_MACH_OMAP3517EVM=y
+# CONFIG_MACH_OMAP3_PANDORA is not set
+# CONFIG_MACH_OMAP_3430SDP is not set
+# CONFIG_MACH_NOKIA_RX51 is not set
+# CONFIG_MACH_OMAP_ZOOM2 is not set
+# CONFIG_MACH_CM_T35 is not set
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_32v6K=y
+CONFIG_CPU_V7=y
+CONFIG_CPU_32v7=y
+CONFIG_CPU_ABRT_EV7=y
+CONFIG_CPU_PABRT_V7=y
+CONFIG_CPU_CACHE_V7=y
+CONFIG_CPU_CACHE_VIPT=y
+CONFIG_CPU_COPY_V6=y
+CONFIG_CPU_TLB_V7=y
+CONFIG_CPU_HAS_ASID=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
+
+#
+# Processor Features
+#
+CONFIG_ARM_THUMB=y
+# CONFIG_ARM_THUMBEE is not set
+# CONFIG_CPU_ICACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_DISABLE is not set
+# CONFIG_CPU_BPREDICT_DISABLE is not set
+CONFIG_HAS_TLS_REG=y
+CONFIG_ARM_L1_CACHE_SHIFT=6
+# CONFIG_ARM_ERRATA_430973 is not set
+# CONFIG_ARM_ERRATA_458693 is not set
+# CONFIG_ARM_ERRATA_460075 is not set
+CONFIG_COMMON_CLKDEV=y
+
+#
+# Bus support
+#
+# CONFIG_PCI_SYSCALL is not set
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+CONFIG_TICK_ONESHOT=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+CONFIG_VMSPLIT_3G=y
+# CONFIG_VMSPLIT_2G is not set
+# CONFIG_VMSPLIT_1G is not set
+CONFIG_PAGE_OFFSET=0xC0000000
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+CONFIG_HZ=128
+# CONFIG_THUMB2_KERNEL is not set
+CONFIG_AEABI=y
+CONFIG_OABI_COMPAT=y
+# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set
+# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set
+# CONFIG_HIGHMEM is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+CONFIG_PAGEFLAGS_EXTENDED=y
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_PHYS_ADDR_T_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=0
+CONFIG_VIRT_TO_BUS=y
+CONFIG_HAVE_MLOCK=y
+CONFIG_HAVE_MLOCKED_PAGE_BIT=y
+# CONFIG_KSM is not set
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
+# CONFIG_LEDS is not set
+CONFIG_ALIGNMENT_TRAP=y
+# CONFIG_UACCESS_WITH_MEMCPY is not set
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="root=/dev/nfs nfsroot=192.168.0.1:/home/user/buildroot ip=192.168.0.2:192.168.0.1:192.168.0.1:255.255.255.0:tgt:eth0:off rw console=ttyS2,115200n8"
+# CONFIG_XIP_KERNEL is not set
+# CONFIG_KEXEC is not set
+
+#
+# CPU Power Management
+#
+# CONFIG_CPU_FREQ is not set
+# CONFIG_CPU_IDLE is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
+# CONFIG_FPE_FASTFPE is not set
+CONFIG_VFP=y
+CONFIG_VFPv3=y
+CONFIG_NEON=y
+
+#
+# Userspace binary formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_HAVE_AOUT=y
+# CONFIG_BINFMT_AOUT is not set
+CONFIG_BINFMT_MISC=y
+
+#
+# Power management options
+#
+# CONFIG_PM is not set
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_MIGRATE is not set
+# CONFIG_XFRM_STATISTICS is not set
+CONFIG_NET_KEY=y
+# CONFIG_NET_KEY_MIGRATE is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+CONFIG_IP_PNP_RARP=y
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
+# CONFIG_INET_LRO is not set
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# CONFIG_RDS is not set
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_NET_DSA is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_PHONET is not set
+# CONFIG_IEEE802154 is not set
+# CONFIG_NET_SCHED is not set
+# CONFIG_DCB is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_CAN is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+CONFIG_WIRELESS=y
+# CONFIG_CFG80211 is not set
+CONFIG_CFG80211_DEFAULT_PS_VALUE=0
+# CONFIG_WIRELESS_OLD_REGULATORY is not set
+# CONFIG_WIRELESS_EXT is not set
+# CONFIG_LIB80211 is not set
+
+#
+# CFG80211 needs to be enabled for MAC80211
+#
+# CONFIG_WIMAX is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+# CONFIG_DEVTMPFS is not set
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES is not set
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_CONNECTOR is not set
+# CONFIG_MTD is not set
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_UB is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=16384
+# CONFIG_BLK_DEV_XIP is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+# CONFIG_MG_DISK is not set
+# CONFIG_MISC_DEVICES is not set
+CONFIG_HAVE_IDE=y
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=y
+CONFIG_SCSI_DMA=y
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+# CONFIG_BLK_DEV_SR is not set
+# CONFIG_CHR_DEV_SG is not set
+# CONFIG_CHR_DEV_SCH is not set
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC is not set
+CONFIG_SCSI_WAIT_SCAN=m
+
+#
+# SCSI Transports
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+# CONFIG_SCSI_SRP_ATTRS is not set
+CONFIG_SCSI_LOWLEVEL=y
+# CONFIG_ISCSI_TCP is not set
+# CONFIG_LIBFC is not set
+# CONFIG_LIBFCOE is not set
+# CONFIG_SCSI_DEBUG is not set
+# CONFIG_SCSI_DH is not set
+# CONFIG_SCSI_OSD_INITIATOR is not set
+# CONFIG_ATA is not set
+# CONFIG_MD is not set
+# CONFIG_NETDEVICES is not set
+# CONFIG_ISDN is not set
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
+
+#
+# Userland interfaces
+#
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_CONSOLE_TRANSLATIONS=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
+CONFIG_DEVKMEM=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=32
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+CONFIG_SERIAL_8250_EXTENDED=y
+CONFIG_SERIAL_8250_MANY_PORTS=y
+CONFIG_SERIAL_8250_SHARE_IRQ=y
+CONFIG_SERIAL_8250_DETECT_IRQ=y
+CONFIG_SERIAL_8250_RSA=y
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_IPMI_HANDLER is not set
+CONFIG_HW_RANDOM=y
+# CONFIG_HW_RANDOM_TIMERIOMEM is not set
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+# CONFIG_I2C is not set
+# CONFIG_SPI is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
+CONFIG_ARCH_REQUIRE_GPIOLIB=y
+CONFIG_GPIOLIB=y
+# CONFIG_DEBUG_GPIO is not set
+# CONFIG_GPIO_SYSFS is not set
+
+#
+# Memory mapped GPIO expanders:
+#
+
+#
+# I2C GPIO expanders:
+#
+
+#
+# PCI GPIO expanders:
+#
+
+#
+# SPI GPIO expanders:
+#
+
+#
+# AC97 GPIO expanders:
+#
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+# CONFIG_HWMON is not set
+# CONFIG_THERMAL is not set
+# CONFIG_WATCHDOG is not set
+CONFIG_SSB_POSSIBLE=y
+
+#
+# Sonics Silicon Backplane
+#
+# CONFIG_SSB is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_CORE is not set
+# CONFIG_MFD_SM501 is not set
+# CONFIG_MFD_ASIC3 is not set
+# CONFIG_HTC_EGPIO is not set
+# CONFIG_HTC_PASIC3 is not set
+# CONFIG_MFD_TMIO is not set
+# CONFIG_MFD_T7L66XB is not set
+# CONFIG_MFD_TC6387XB is not set
+# CONFIG_MFD_TC6393XB is not set
+# CONFIG_REGULATOR is not set
+# CONFIG_MEDIA_SUPPORT is not set
+
+#
+# Graphics support
+#
+# CONFIG_VGASTATE is not set
+# CONFIG_VIDEO_OUTPUT_CONTROL is not set
+# CONFIG_FB is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+# CONFIG_SOUND is not set
+CONFIG_HID_SUPPORT=y
+CONFIG_HID=y
+# CONFIG_HIDRAW is not set
+
+#
+# USB Input Devices
+#
+CONFIG_USB_HID=y
+# CONFIG_HID_PID is not set
+# CONFIG_USB_HIDDEV is not set
+
+#
+# Special HID drivers
+#
+# CONFIG_HID_A4TECH is not set
+# CONFIG_HID_APPLE is not set
+# CONFIG_HID_BELKIN is not set
+# CONFIG_HID_CHERRY is not set
+# CONFIG_HID_CHICONY is not set
+# CONFIG_HID_CYPRESS is not set
+# CONFIG_HID_DRAGONRISE is not set
+# CONFIG_HID_EZKEY is not set
+# CONFIG_HID_KYE is not set
+# CONFIG_HID_GYRATION is not set
+# CONFIG_HID_TWINHAN is not set
+# CONFIG_HID_KENSINGTON is not set
+# CONFIG_HID_LOGITECH is not set
+# CONFIG_HID_MICROSOFT is not set
+# CONFIG_HID_MONTEREY is not set
+# CONFIG_HID_NTRIG is not set
+# CONFIG_HID_PANTHERLORD is not set
+# CONFIG_HID_PETALYNX is not set
+# CONFIG_HID_SAMSUNG is not set
+# CONFIG_HID_SONY is not set
+# CONFIG_HID_SUNPLUS is not set
+# CONFIG_HID_GREENASIA is not set
+# CONFIG_HID_SMARTJOYPLUS is not set
+# CONFIG_HID_TOPSEED is not set
+# CONFIG_HID_THRUSTMASTER is not set
+# CONFIG_HID_ZEROPLUS is not set
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+CONFIG_USB_ARCH_HAS_EHCI=y
+CONFIG_USB=y
+# CONFIG_USB_DEBUG is not set
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
+
+#
+# Miscellaneous USB options
+#
+# CONFIG_USB_DEVICEFS is not set
+# CONFIG_USB_DEVICE_CLASS is not set
+# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_OTG is not set
+# CONFIG_USB_OTG_WHITELIST is not set
+# CONFIG_USB_OTG_BLACKLIST_HUB is not set
+# CONFIG_USB_MON is not set
+# CONFIG_USB_WUSB is not set
+# CONFIG_USB_WUSB_CBAF is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_C67X00_HCD is not set
+CONFIG_USB_EHCI_HCD=y
+# CONFIG_USB_EHCI_ROOT_HUB_TT is not set
+# CONFIG_USB_EHCI_TT_NEWSCHED is not set
+# CONFIG_USB_OXU210HP_HCD is not set
+# CONFIG_USB_ISP116X_HCD is not set
+# CONFIG_USB_ISP1760_HCD is not set
+# CONFIG_USB_ISP1362_HCD is not set
+# CONFIG_USB_OHCI_HCD is not set
+# CONFIG_USB_SL811_HCD is not set
+# CONFIG_USB_R8A66597_HCD is not set
+# CONFIG_USB_HWA_HCD is not set
+# CONFIG_USB_MUSB_HDRC is not set
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+# CONFIG_USB_WDM is not set
+# CONFIG_USB_TMC is not set
+
+#
+# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may
+#
+
+#
+# also be needed; see USB_STORAGE Help for more info
+#
+CONFIG_USB_STORAGE=y
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_ISD200 is not set
+# CONFIG_USB_STORAGE_USBAT is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_SDDR55 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_STORAGE_ALAUDA is not set
+# CONFIG_USB_STORAGE_ONETOUCH is not set
+# CONFIG_USB_STORAGE_KARMA is not set
+# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set
+# CONFIG_USB_LIBUSUAL is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+
+#
+# USB port drivers
+#
+# CONFIG_USB_SERIAL is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_ADUTUX is not set
+# CONFIG_USB_SEVSEG is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_BERRY_CHARGE is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYPRESS_CY7C63 is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_FTDI_ELAN is not set
+# CONFIG_USB_APPLEDISPLAY is not set
+# CONFIG_USB_SISUSBVGA is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
+# CONFIG_USB_IOWARRIOR is not set
+# CONFIG_USB_TEST is not set
+# CONFIG_USB_ISIGHTFW is not set
+# CONFIG_USB_VST is not set
+# CONFIG_USB_GADGET is not set
+
+#
+# OTG and related infrastructure
+#
+# CONFIG_USB_GPIO_VBUS is not set
+# CONFIG_NOP_USB_XCEIV is not set
+# CONFIG_MMC is not set
+# CONFIG_MEMSTICK is not set
+# CONFIG_NEW_LEDS is not set
+# CONFIG_ACCESSIBILITY is not set
+CONFIG_RTC_LIB=y
+# CONFIG_RTC_CLASS is not set
+# CONFIG_DMADEVICES is not set
+# CONFIG_AUXDISPLAY is not set
+# CONFIG_UIO is not set
+
+#
+# TI VLYNQ
+#
+# CONFIG_STAGING is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
+# CONFIG_EXT3_FS_XATTR is not set
+# CONFIG_EXT4_FS is not set
+CONFIG_JBD=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_BTRFS_FS is not set
+# CONFIG_NILFS2_FS is not set
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
+CONFIG_DNOTIFY=y
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+CONFIG_QUOTA=y
+# CONFIG_QUOTA_NETLINK_INTERFACE is not set
+CONFIG_PRINT_QUOTA_WARNING=y
+CONFIG_QUOTA_TREE=y
+# CONFIG_QFMT_V1 is not set
+CONFIG_QFMT_V2=y
+CONFIG_QUOTACTL=y
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# Caches
+#
+# CONFIG_FSCACHE is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLB_PAGE is not set
+# CONFIG_CONFIGFS_FS is not set
+CONFIG_MISC_FILESYSTEMS=y
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_SQUASHFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_OMFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+CONFIG_NETWORK_FILESYSTEMS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+CONFIG_NFS_V4=y
+# CONFIG_NFS_V4_1 is not set
+CONFIG_ROOT_NFS=y
+# CONFIG_NFSD is not set
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+CONFIG_SUNRPC_GSS=y
+CONFIG_RPCSEC_GSS_KRB5=y
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_KARMA_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+# CONFIG_SYSV68_PARTITION is not set
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+CONFIG_NLS_ISO8859_1=y
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+# CONFIG_DLM is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_WARN_DEPRECATED=y
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_FRAME_WARN=1024
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_STRIP_ASM_SYMS is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SHIRQ is not set
+CONFIG_DETECT_SOFTLOCKUP=y
+# CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set
+CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0
+CONFIG_DETECT_HUNG_TASK=y
+# CONFIG_BOOTPARAM_HUNG_TASK_PANIC is not set
+CONFIG_BOOTPARAM_HUNG_TASK_PANIC_VALUE=0
+# CONFIG_SCHED_DEBUG is not set
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_TIMER_STATS is not set
+# CONFIG_DEBUG_OBJECTS is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_KMEMLEAK is not set
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+CONFIG_DEBUG_MUTEXES=y
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_LOCK_STAT is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_DEBUG_KOBJECT is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+CONFIG_DEBUG_INFO=y
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_WRITECOUNT is not set
+# CONFIG_DEBUG_MEMORY_INIT is not set
+# CONFIG_DEBUG_LIST is not set
+# CONFIG_DEBUG_SG is not set
+# CONFIG_DEBUG_NOTIFIERS is not set
+# CONFIG_DEBUG_CREDENTIALS is not set
+# CONFIG_BOOT_PRINTK_DELAY is not set
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_RCU_CPU_STALL_DETECTOR is not set
+# CONFIG_BACKTRACE_SELF_TEST is not set
+# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
+# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
+# CONFIG_FAULT_INJECTION is not set
+# CONFIG_LATENCYTOP is not set
+# CONFIG_PAGE_POISONING is not set
+CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_TRACING_SUPPORT=y
+CONFIG_FTRACE=y
+# CONFIG_FUNCTION_TRACER is not set
+# CONFIG_IRQSOFF_TRACER is not set
+# CONFIG_SCHED_TRACER is not set
+# CONFIG_ENABLE_DEFAULT_TRACERS is not set
+# CONFIG_BOOT_TRACER is not set
+CONFIG_BRANCH_PROFILE_NONE=y
+# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set
+# CONFIG_PROFILE_ALL_BRANCHES is not set
+# CONFIG_STACK_TRACER is not set
+# CONFIG_KMEMTRACE is not set
+# CONFIG_WORKQUEUE_TRACER is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_SAMPLES is not set
+CONFIG_HAVE_ARCH_KGDB=y
+# CONFIG_KGDB is not set
+CONFIG_ARM_UNWIND=y
+# CONFIG_DEBUG_USER is not set
+# CONFIG_DEBUG_ERRORS is not set
+# CONFIG_DEBUG_STACK_USAGE is not set
+CONFIG_DEBUG_LL=y
+# CONFIG_DEBUG_ICEDCC is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+# CONFIG_SECURITYFS is not set
+# CONFIG_SECURITY_FILE_CAPABILITIES is not set
+CONFIG_CRYPTO=y
+
+#
+# Crypto core or helper
+#
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_ALGAPI2=y
+CONFIG_CRYPTO_AEAD2=y
+CONFIG_CRYPTO_BLKCIPHER=y
+CONFIG_CRYPTO_BLKCIPHER2=y
+CONFIG_CRYPTO_HASH=y
+CONFIG_CRYPTO_HASH2=y
+CONFIG_CRYPTO_RNG2=y
+CONFIG_CRYPTO_PCOMP=y
+CONFIG_CRYPTO_MANAGER=y
+CONFIG_CRYPTO_MANAGER2=y
+# CONFIG_CRYPTO_GF128MUL is not set
+# CONFIG_CRYPTO_NULL is not set
+CONFIG_CRYPTO_WORKQUEUE=y
+# CONFIG_CRYPTO_CRYPTD is not set
+# CONFIG_CRYPTO_AUTHENC is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Authenticated Encryption with Associated Data
+#
+# CONFIG_CRYPTO_CCM is not set
+# CONFIG_CRYPTO_GCM is not set
+# CONFIG_CRYPTO_SEQIV is not set
+
+#
+# Block modes
+#
+CONFIG_CRYPTO_CBC=y
+# CONFIG_CRYPTO_CTR is not set
+# CONFIG_CRYPTO_CTS is not set
+CONFIG_CRYPTO_ECB=m
+# CONFIG_CRYPTO_LRW is not set
+CONFIG_CRYPTO_PCBC=m
+# CONFIG_CRYPTO_XTS is not set
+
+#
+# Hash modes
+#
+# CONFIG_CRYPTO_HMAC is not set
+# CONFIG_CRYPTO_XCBC is not set
+# CONFIG_CRYPTO_VMAC is not set
+
+#
+# Digest
+#
+CONFIG_CRYPTO_CRC32C=y
+# CONFIG_CRYPTO_GHASH is not set
+# CONFIG_CRYPTO_MD4 is not set
+CONFIG_CRYPTO_MD5=y
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_RMD128 is not set
+# CONFIG_CRYPTO_RMD160 is not set
+# CONFIG_CRYPTO_RMD256 is not set
+# CONFIG_CRYPTO_RMD320 is not set
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_WP512 is not set
+
+#
+# Ciphers
+#
+# CONFIG_CRYPTO_AES is not set
+# CONFIG_CRYPTO_ANUBIS is not set
+# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_CAMELLIA is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+CONFIG_CRYPTO_DES=y
+# CONFIG_CRYPTO_FCRYPT is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_SALSA20 is not set
+# CONFIG_CRYPTO_SEED is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+
+#
+# Compression
+#
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_ZLIB is not set
+# CONFIG_CRYPTO_LZO is not set
+
+#
+# Random Number Generation
+#
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
+CONFIG_CRYPTO_HW=y
+# CONFIG_BINARY_PRINTF is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+CONFIG_GENERIC_FIND_LAST_BIT=y
+CONFIG_CRC_CCITT=y
+# CONFIG_CRC16 is not set
+# CONFIG_CRC_T10DIF is not set
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+CONFIG_LIBCRC32C=y
+CONFIG_ZLIB_INFLATE=y
+CONFIG_DECOMPRESS_GZIP=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
+CONFIG_NLATTR=y
index 238b218..c97e102 100644 (file)
@@ -120,6 +120,7 @@ CONFIG_ARCH_AT91RM9200DK=y
 # CONFIG_MACH_CARMEVA is not set
 # CONFIG_MACH_KB9200 is not set
 # CONFIG_MACH_ATEB9200 is not set
+CONFIG_MACH_ECO920=y
 
 #
 # AT91RM9200 Feature Selections
diff --git a/arch/arm/configs/cm_t35_defconfig b/arch/arm/configs/cm_t35_defconfig
new file mode 100644 (file)
index 0000000..e42c5c8
--- /dev/null
@@ -0,0 +1,1733 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.32-rc4
+# Tue Oct 13 17:10:40 2009
+#
+CONFIG_ARM=y
+CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+CONFIG_GENERIC_GPIO=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_ARCH_HAS_CPUFREQ=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
+CONFIG_VECTORS_BASE=0xffff0000
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+# CONFIG_POSIX_MQUEUE is not set
+CONFIG_BSD_PROCESS_ACCT=y
+# CONFIG_BSD_PROCESS_ACCT_V3 is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_AUDIT is not set
+
+#
+# RCU Subsystem
+#
+CONFIG_TREE_RCU=y
+# CONFIG_TREE_PREEMPT_RCU is not set
+# CONFIG_RCU_TRACE is not set
+CONFIG_RCU_FANOUT=32
+# CONFIG_RCU_FANOUT_EXACT is not set
+# CONFIG_TREE_RCU_TRACE is not set
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_BUF_SHIFT=17
+CONFIG_GROUP_SCHED=y
+CONFIG_FAIR_GROUP_SCHED=y
+# CONFIG_RT_GROUP_SCHED is not set
+CONFIG_USER_SCHED=y
+# CONFIG_CGROUP_SCHED is not set
+# CONFIG_CGROUPS is not set
+CONFIG_SYSFS_DEPRECATED=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+# CONFIG_RELAY is not set
+# CONFIG_NAMESPACES is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_RD_GZIP=y
+# CONFIG_RD_BZIP2 is not set
+# CONFIG_RD_LZMA is not set
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+CONFIG_ANON_INODES=y
+CONFIG_EMBEDDED=y
+CONFIG_UID16=y
+# CONFIG_SYSCTL_SYSCALL is not set
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+CONFIG_KALLSYMS_EXTRA_PASS=y
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_AIO=y
+
+#
+# Kernel Performance Events And Counters
+#
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_COMPAT_BRK=y
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
+# CONFIG_PROFILING is not set
+CONFIG_HAVE_OPROFILE=y
+# CONFIG_KPROBES is not set
+CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_KRETPROBES=y
+CONFIG_HAVE_CLK=y
+
+#
+# GCOV-based kernel profiling
+#
+# CONFIG_GCOV_KERNEL is not set
+# CONFIG_SLOW_WORK is not set
+CONFIG_HAVE_GENERIC_DMA_COHERENT=y
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+# CONFIG_MODULE_FORCE_LOAD is not set
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+CONFIG_MODVERSIONS=y
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_BLOCK=y
+CONFIG_LBDAF=y
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_BLK_DEV_INTEGRITY is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+CONFIG_DEFAULT_AS=y
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="anticipatory"
+CONFIG_FREEZER=y
+
+#
+# System Type
+#
+CONFIG_MMU=y
+# CONFIG_ARCH_AAEC2000 is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_REALVIEW is not set
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_AT91 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_GEMINI is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_EP93XX is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_MXC is not set
+# CONFIG_ARCH_STMP3XXX is not set
+# CONFIG_ARCH_NETX is not set
+# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_NOMADIK is not set
+# CONFIG_ARCH_IOP13XX is not set
+# CONFIG_ARCH_IOP32X is not set
+# CONFIG_ARCH_IOP33X is not set
+# CONFIG_ARCH_IXP23XX is not set
+# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_KIRKWOOD is not set
+# CONFIG_ARCH_LOKI is not set
+# CONFIG_ARCH_MV78XX0 is not set
+# CONFIG_ARCH_ORION5X is not set
+# CONFIG_ARCH_MMP is not set
+# CONFIG_ARCH_KS8695 is not set
+# CONFIG_ARCH_NS9XXX is not set
+# CONFIG_ARCH_W90X900 is not set
+# CONFIG_ARCH_PNX4008 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_MSM is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_S3C64XX is not set
+# CONFIG_ARCH_S5PC1XX is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_U300 is not set
+# CONFIG_ARCH_DAVINCI is not set
+CONFIG_ARCH_OMAP=y
+# CONFIG_ARCH_BCMRING is not set
+
+#
+# TI OMAP Implementations
+#
+CONFIG_ARCH_OMAP_OTG=y
+# CONFIG_ARCH_OMAP1 is not set
+# CONFIG_ARCH_OMAP2 is not set
+CONFIG_ARCH_OMAP3=y
+# CONFIG_ARCH_OMAP4 is not set
+
+#
+# OMAP Feature Selections
+#
+# CONFIG_OMAP_DEBUG_POWERDOMAIN is not set
+# CONFIG_OMAP_DEBUG_CLOCKDOMAIN is not set
+CONFIG_OMAP_RESET_CLOCKS=y
+CONFIG_OMAP_MUX=y
+# CONFIG_OMAP_MUX_DEBUG is not set
+CONFIG_OMAP_MUX_WARNINGS=y
+CONFIG_OMAP_MCBSP=y
+# CONFIG_OMAP_MBOX_FWK is not set
+# CONFIG_OMAP_MPU_TIMER is not set
+CONFIG_OMAP_32K_TIMER=y
+CONFIG_OMAP_32K_TIMER_HZ=128
+CONFIG_OMAP_DM_TIMER=y
+# CONFIG_OMAP_LL_DEBUG_UART1 is not set
+# CONFIG_OMAP_LL_DEBUG_UART2 is not set
+CONFIG_OMAP_LL_DEBUG_UART3=y
+# CONFIG_OMAP_PM_NONE is not set
+CONFIG_OMAP_PM_NOOP=y
+CONFIG_ARCH_OMAP34XX=y
+CONFIG_ARCH_OMAP3430=y
+
+#
+# OMAP Board Type
+#
+# CONFIG_MACH_OMAP3_BEAGLE is not set
+# CONFIG_MACH_OMAP_LDP is not set
+# CONFIG_MACH_OVERO is not set
+# CONFIG_MACH_OMAP3EVM is not set
+# CONFIG_MACH_OMAP3_PANDORA is not set
+# CONFIG_MACH_OMAP_3430SDP is not set
+# CONFIG_MACH_NOKIA_RX51 is not set
+# CONFIG_MACH_OMAP_ZOOM2 is not set
+CONFIG_MACH_CM_T35=y
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_32v6K=y
+CONFIG_CPU_V7=y
+CONFIG_CPU_32v7=y
+CONFIG_CPU_ABRT_EV7=y
+CONFIG_CPU_PABRT_V7=y
+CONFIG_CPU_CACHE_V7=y
+CONFIG_CPU_CACHE_VIPT=y
+CONFIG_CPU_COPY_V6=y
+CONFIG_CPU_TLB_V7=y
+CONFIG_CPU_HAS_ASID=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
+
+#
+# Processor Features
+#
+CONFIG_ARM_THUMB=y
+# CONFIG_ARM_THUMBEE is not set
+# CONFIG_CPU_ICACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_DISABLE is not set
+# CONFIG_CPU_BPREDICT_DISABLE is not set
+CONFIG_HAS_TLS_REG=y
+CONFIG_ARM_L1_CACHE_SHIFT=6
+# CONFIG_ARM_ERRATA_430973 is not set
+# CONFIG_ARM_ERRATA_458693 is not set
+# CONFIG_ARM_ERRATA_460075 is not set
+CONFIG_COMMON_CLKDEV=y
+
+#
+# Bus support
+#
+# CONFIG_PCI_SYSCALL is not set
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+CONFIG_TICK_ONESHOT=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+CONFIG_VMSPLIT_3G=y
+# CONFIG_VMSPLIT_2G is not set
+# CONFIG_VMSPLIT_1G is not set
+CONFIG_PAGE_OFFSET=0xC0000000
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+CONFIG_HZ=128
+# CONFIG_THUMB2_KERNEL is not set
+CONFIG_AEABI=y
+CONFIG_OABI_COMPAT=y
+# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set
+# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set
+# CONFIG_HIGHMEM is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+CONFIG_PAGEFLAGS_EXTENDED=y
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_PHYS_ADDR_T_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=0
+CONFIG_VIRT_TO_BUS=y
+CONFIG_HAVE_MLOCK=y
+CONFIG_HAVE_MLOCKED_PAGE_BIT=y
+# CONFIG_KSM is not set
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
+# CONFIG_LEDS is not set
+CONFIG_ALIGNMENT_TRAP=y
+# CONFIG_UACCESS_WITH_MEMCPY is not set
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE=""
+# CONFIG_XIP_KERNEL is not set
+# CONFIG_KEXEC is not set
+
+#
+# CPU Power Management
+#
+# CONFIG_CPU_FREQ is not set
+# CONFIG_CPU_IDLE is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
+# CONFIG_FPE_FASTFPE is not set
+CONFIG_VFP=y
+CONFIG_VFPv3=y
+CONFIG_NEON=y
+
+#
+# Userspace binary formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_HAVE_AOUT=y
+# CONFIG_BINFMT_AOUT is not set
+CONFIG_BINFMT_MISC=y
+
+#
+# Power management options
+#
+CONFIG_PM=y
+# CONFIG_PM_DEBUG is not set
+CONFIG_PM_SLEEP=y
+CONFIG_SUSPEND=y
+CONFIG_SUSPEND_FREEZER=y
+# CONFIG_APM_EMULATION is not set
+# CONFIG_PM_RUNTIME is not set
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_MIGRATE is not set
+# CONFIG_XFRM_STATISTICS is not set
+CONFIG_NET_KEY=y
+# CONFIG_NET_KEY_MIGRATE is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+CONFIG_IP_PNP_RARP=y
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
+# CONFIG_INET_LRO is not set
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# CONFIG_RDS is not set
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_NET_DSA is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_PHONET is not set
+# CONFIG_IEEE802154 is not set
+# CONFIG_NET_SCHED is not set
+# CONFIG_DCB is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_CAN is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+CONFIG_WIRELESS=y
+# CONFIG_CFG80211 is not set
+CONFIG_CFG80211_DEFAULT_PS_VALUE=0
+# CONFIG_WIRELESS_OLD_REGULATORY is not set
+CONFIG_WIRELESS_EXT=y
+CONFIG_WIRELESS_EXT_SYSFS=y
+CONFIG_LIB80211=m
+# CONFIG_LIB80211_DEBUG is not set
+
+#
+# CFG80211 needs to be enabled for MAC80211
+#
+# CONFIG_WIMAX is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+# CONFIG_DEVTMPFS is not set
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=m
+CONFIG_FIRMWARE_IN_KERNEL=y
+CONFIG_EXTRA_FIRMWARE=""
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES is not set
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_CONNECTOR is not set
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_TESTS is not set
+CONFIG_MTD_CONCAT=y
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+# CONFIG_MTD_AFS_PARTS is not set
+# CONFIG_MTD_AR7_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+# CONFIG_MTD_OOPS is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+CONFIG_MTD_CFI_INTELEXT=y
+# CONFIG_MTD_CFI_AMDSTD is not set
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PHYSMAP is not set
+# CONFIG_MTD_ARM_INTEGRATOR is not set
+# CONFIG_MTD_OMAP_NOR is not set
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_DATAFLASH is not set
+# CONFIG_MTD_M25P80 is not set
+# CONFIG_MTD_SST25L is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+CONFIG_MTD_NAND=y
+# CONFIG_MTD_NAND_VERIFY_WRITE is not set
+# CONFIG_MTD_NAND_ECC_SMC is not set
+# CONFIG_MTD_NAND_MUSEUM_IDS is not set
+# CONFIG_MTD_NAND_GPIO is not set
+CONFIG_MTD_NAND_OMAP2=y
+CONFIG_MTD_NAND_OMAP_PREFETCH=y
+# CONFIG_MTD_NAND_OMAP_PREFETCH_DMA is not set
+CONFIG_MTD_NAND_IDS=y
+# CONFIG_MTD_NAND_DISKONCHIP is not set
+# CONFIG_MTD_NAND_NANDSIM is not set
+# CONFIG_MTD_NAND_PLATFORM is not set
+# CONFIG_MTD_ALAUDA is not set
+# CONFIG_MTD_ONENAND is not set
+
+#
+# LPDDR flash memory drivers
+#
+# CONFIG_MTD_LPDDR is not set
+
+#
+# UBI - Unsorted block images
+#
+# CONFIG_MTD_UBI is not set
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_UB is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=16384
+# CONFIG_BLK_DEV_XIP is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+# CONFIG_MG_DISK is not set
+CONFIG_MISC_DEVICES=y
+# CONFIG_ICS932S401 is not set
+# CONFIG_ENCLOSURE_SERVICES is not set
+# CONFIG_ISL29003 is not set
+# CONFIG_C2PORT is not set
+
+#
+# EEPROM support
+#
+# CONFIG_EEPROM_AT24 is not set
+# CONFIG_EEPROM_AT25 is not set
+# CONFIG_EEPROM_LEGACY is not set
+# CONFIG_EEPROM_MAX6875 is not set
+# CONFIG_EEPROM_93CX6 is not set
+CONFIG_HAVE_IDE=y
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=y
+CONFIG_SCSI_DMA=y
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+# CONFIG_BLK_DEV_SR is not set
+# CONFIG_CHR_DEV_SG is not set
+# CONFIG_CHR_DEV_SCH is not set
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC is not set
+CONFIG_SCSI_WAIT_SCAN=m
+
+#
+# SCSI Transports
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+# CONFIG_SCSI_SRP_ATTRS is not set
+CONFIG_SCSI_LOWLEVEL=y
+# CONFIG_ISCSI_TCP is not set
+# CONFIG_LIBFC is not set
+# CONFIG_LIBFCOE is not set
+# CONFIG_SCSI_DEBUG is not set
+# CONFIG_SCSI_DH is not set
+# CONFIG_SCSI_OSD_INITIATOR is not set
+# CONFIG_ATA is not set
+# CONFIG_MD is not set
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_VETH is not set
+CONFIG_PHYLIB=y
+
+#
+# MII PHY device drivers
+#
+# CONFIG_MARVELL_PHY is not set
+# CONFIG_DAVICOM_PHY is not set
+# CONFIG_QSEMI_PHY is not set
+# CONFIG_LXT_PHY is not set
+# CONFIG_CICADA_PHY is not set
+# CONFIG_VITESSE_PHY is not set
+# CONFIG_SMSC_PHY is not set
+# CONFIG_BROADCOM_PHY is not set
+# CONFIG_ICPLUS_PHY is not set
+# CONFIG_REALTEK_PHY is not set
+# CONFIG_NATIONAL_PHY is not set
+# CONFIG_STE10XP is not set
+# CONFIG_LSI_ET1011C_PHY is not set
+# CONFIG_FIXED_PHY is not set
+# CONFIG_MDIO_BITBANG is not set
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_AX88796 is not set
+# CONFIG_SMC91X is not set
+# CONFIG_DM9000 is not set
+# CONFIG_ENC28J60 is not set
+# CONFIG_ETHOC is not set
+# CONFIG_SMC911X is not set
+CONFIG_SMSC911X=y
+# CONFIG_DNET is not set
+# CONFIG_IBM_NEW_EMAC_ZMII is not set
+# CONFIG_IBM_NEW_EMAC_RGMII is not set
+# CONFIG_IBM_NEW_EMAC_TAH is not set
+# CONFIG_IBM_NEW_EMAC_EMAC4 is not set
+# CONFIG_IBM_NEW_EMAC_NO_FLOW_CTRL is not set
+# CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT is not set
+# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
+# CONFIG_B44 is not set
+# CONFIG_KS8842 is not set
+# CONFIG_KS8851 is not set
+# CONFIG_KS8851_MLL is not set
+# CONFIG_NETDEV_1000 is not set
+# CONFIG_NETDEV_10000 is not set
+CONFIG_WLAN=y
+# CONFIG_WLAN_PRE80211 is not set
+CONFIG_WLAN_80211=y
+CONFIG_LIBERTAS=m
+# CONFIG_LIBERTAS_USB is not set
+CONFIG_LIBERTAS_SDIO=m
+# CONFIG_LIBERTAS_SPI is not set
+# CONFIG_LIBERTAS_DEBUG is not set
+# CONFIG_USB_ZD1201 is not set
+# CONFIG_HOSTAP is not set
+
+#
+# Enable WiMAX (Networking options) to see the WiMAX drivers
+#
+
+#
+# USB Network Adapters
+#
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RTL8150 is not set
+# CONFIG_USB_USBNET is not set
+# CONFIG_WAN is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_ISDN is not set
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+# CONFIG_KEYBOARD_ADP5588 is not set
+CONFIG_KEYBOARD_ATKBD=y
+# CONFIG_QT2160 is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_GPIO is not set
+# CONFIG_KEYBOARD_MATRIX is not set
+# CONFIG_KEYBOARD_LM8323 is not set
+# CONFIG_KEYBOARD_MAX7359 is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+# CONFIG_KEYBOARD_OPENCORES is not set
+# CONFIG_KEYBOARD_STOWAWAY is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+CONFIG_KEYBOARD_TWL4030=m
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_ADS7846=m
+# CONFIG_TOUCHSCREEN_AD7877 is not set
+# CONFIG_TOUCHSCREEN_AD7879_I2C is not set
+# CONFIG_TOUCHSCREEN_AD7879_SPI is not set
+# CONFIG_TOUCHSCREEN_AD7879 is not set
+# CONFIG_TOUCHSCREEN_EETI is not set
+# CONFIG_TOUCHSCREEN_FUJITSU is not set
+# CONFIG_TOUCHSCREEN_GUNZE is not set
+# CONFIG_TOUCHSCREEN_ELO is not set
+# CONFIG_TOUCHSCREEN_WACOM_W8001 is not set
+# CONFIG_TOUCHSCREEN_MCS5000 is not set
+# CONFIG_TOUCHSCREEN_MTOUCH is not set
+# CONFIG_TOUCHSCREEN_INEXIO is not set
+# CONFIG_TOUCHSCREEN_MK712 is not set
+# CONFIG_TOUCHSCREEN_PENMOUNT is not set
+# CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set
+# CONFIG_TOUCHSCREEN_TOUCHWIN is not set
+# CONFIG_TOUCHSCREEN_USB_COMPOSITE is not set
+# CONFIG_TOUCHSCREEN_TOUCHIT213 is not set
+# CONFIG_TOUCHSCREEN_TSC2007 is not set
+# CONFIG_TOUCHSCREEN_W90X900 is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+CONFIG_SERIO_SERPORT=y
+CONFIG_SERIO_LIBPS2=y
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_CONSOLE_TRANSLATIONS=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
+CONFIG_DEVKMEM=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=32
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+CONFIG_SERIAL_8250_EXTENDED=y
+CONFIG_SERIAL_8250_MANY_PORTS=y
+CONFIG_SERIAL_8250_SHARE_IRQ=y
+CONFIG_SERIAL_8250_DETECT_IRQ=y
+CONFIG_SERIAL_8250_RSA=y
+
+#
+# Non-8250 serial port support
+#
+# CONFIG_SERIAL_MAX3100 is not set
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_IPMI_HANDLER is not set
+CONFIG_HW_RANDOM=y
+# CONFIG_HW_RANDOM_TIMERIOMEM is not set
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+CONFIG_I2C=y
+CONFIG_I2C_BOARDINFO=y
+CONFIG_I2C_COMPAT=y
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_HELPER_AUTO=y
+
+#
+# I2C Hardware Bus support
+#
+
+#
+# I2C system bus drivers (mostly embedded / system-on-chip)
+#
+# CONFIG_I2C_DESIGNWARE is not set
+# CONFIG_I2C_GPIO is not set
+# CONFIG_I2C_OCORES is not set
+CONFIG_I2C_OMAP=y
+# CONFIG_I2C_SIMTEC is not set
+
+#
+# External I2C/SMBus adapter drivers
+#
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_TAOS_EVM is not set
+# CONFIG_I2C_TINY_USB is not set
+
+#
+# Other I2C/SMBus bus drivers
+#
+# CONFIG_I2C_PCA_PLATFORM is not set
+# CONFIG_I2C_STUB is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_DS1682 is not set
+# CONFIG_SENSORS_TSL2550 is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+CONFIG_SPI=y
+# CONFIG_SPI_DEBUG is not set
+CONFIG_SPI_MASTER=y
+
+#
+# SPI Master Controller Drivers
+#
+# CONFIG_SPI_BITBANG is not set
+# CONFIG_SPI_GPIO is not set
+CONFIG_SPI_OMAP24XX=y
+
+#
+# SPI Protocol Masters
+#
+# CONFIG_SPI_SPIDEV is not set
+# CONFIG_SPI_TLE62X0 is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
+CONFIG_ARCH_REQUIRE_GPIOLIB=y
+CONFIG_GPIOLIB=y
+# CONFIG_DEBUG_GPIO is not set
+CONFIG_GPIO_SYSFS=y
+
+#
+# Memory mapped GPIO expanders:
+#
+
+#
+# I2C GPIO expanders:
+#
+# CONFIG_GPIO_MAX732X is not set
+# CONFIG_GPIO_PCA953X is not set
+# CONFIG_GPIO_PCF857X is not set
+CONFIG_GPIO_TWL4030=y
+
+#
+# PCI GPIO expanders:
+#
+
+#
+# SPI GPIO expanders:
+#
+# CONFIG_GPIO_MAX7301 is not set
+# CONFIG_GPIO_MCP23S08 is not set
+# CONFIG_GPIO_MC33880 is not set
+
+#
+# AC97 GPIO expanders:
+#
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+# CONFIG_HWMON is not set
+# CONFIG_THERMAL is not set
+CONFIG_WATCHDOG=y
+CONFIG_WATCHDOG_NOWAYOUT=y
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+CONFIG_OMAP_WATCHDOG=y
+# CONFIG_TWL4030_WATCHDOG is not set
+
+#
+# USB-based Watchdog Cards
+#
+# CONFIG_USBPCWATCHDOG is not set
+CONFIG_SSB_POSSIBLE=y
+
+#
+# Sonics Silicon Backplane
+#
+# CONFIG_SSB is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_CORE is not set
+# CONFIG_MFD_SM501 is not set
+# CONFIG_MFD_ASIC3 is not set
+# CONFIG_HTC_EGPIO is not set
+# CONFIG_HTC_PASIC3 is not set
+# CONFIG_TPS65010 is not set
+CONFIG_TWL4030_CORE=y
+# CONFIG_TWL4030_POWER is not set
+# CONFIG_MFD_TMIO is not set
+# CONFIG_MFD_T7L66XB is not set
+# CONFIG_MFD_TC6387XB is not set
+# CONFIG_MFD_TC6393XB is not set
+# CONFIG_PMIC_DA903X is not set
+# CONFIG_MFD_WM8400 is not set
+# CONFIG_MFD_WM831X is not set
+# CONFIG_MFD_WM8350_I2C is not set
+# CONFIG_MFD_PCF50633 is not set
+# CONFIG_MFD_MC13783 is not set
+# CONFIG_AB3100_CORE is not set
+# CONFIG_EZX_PCAP is not set
+CONFIG_REGULATOR=y
+# CONFIG_REGULATOR_DEBUG is not set
+# CONFIG_REGULATOR_FIXED_VOLTAGE is not set
+# CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set
+# CONFIG_REGULATOR_USERSPACE_CONSUMER is not set
+# CONFIG_REGULATOR_BQ24022 is not set
+# CONFIG_REGULATOR_MAX1586 is not set
+CONFIG_REGULATOR_TWL4030=y
+# CONFIG_REGULATOR_LP3971 is not set
+# CONFIG_REGULATOR_TPS65023 is not set
+# CONFIG_REGULATOR_TPS6507X is not set
+# CONFIG_MEDIA_SUPPORT is not set
+
+#
+# Graphics support
+#
+# CONFIG_VGASTATE is not set
+# CONFIG_VIDEO_OUTPUT_CONTROL is not set
+# CONFIG_FB is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+# CONFIG_SOUND is not set
+CONFIG_HID_SUPPORT=y
+CONFIG_HID=y
+# CONFIG_HIDRAW is not set
+
+#
+# USB Input Devices
+#
+CONFIG_USB_HID=y
+# CONFIG_HID_PID is not set
+# CONFIG_USB_HIDDEV is not set
+
+#
+# Special HID drivers
+#
+# CONFIG_HID_A4TECH is not set
+# CONFIG_HID_APPLE is not set
+# CONFIG_HID_BELKIN is not set
+# CONFIG_HID_CHERRY is not set
+# CONFIG_HID_CHICONY is not set
+# CONFIG_HID_CYPRESS is not set
+# CONFIG_HID_DRAGONRISE is not set
+# CONFIG_HID_EZKEY is not set
+# CONFIG_HID_KYE is not set
+# CONFIG_HID_GYRATION is not set
+# CONFIG_HID_TWINHAN is not set
+# CONFIG_HID_KENSINGTON is not set
+# CONFIG_HID_LOGITECH is not set
+# CONFIG_HID_MICROSOFT is not set
+# CONFIG_HID_MONTEREY is not set
+# CONFIG_HID_NTRIG is not set
+# CONFIG_HID_PANTHERLORD is not set
+# CONFIG_HID_PETALYNX is not set
+# CONFIG_HID_SAMSUNG is not set
+# CONFIG_HID_SONY is not set
+# CONFIG_HID_SUNPLUS is not set
+# CONFIG_HID_GREENASIA is not set
+# CONFIG_HID_SMARTJOYPLUS is not set
+# CONFIG_HID_TOPSEED is not set
+# CONFIG_HID_THRUSTMASTER is not set
+# CONFIG_HID_ZEROPLUS is not set
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+CONFIG_USB_ARCH_HAS_EHCI=y
+CONFIG_USB=y
+# CONFIG_USB_DEBUG is not set
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+# CONFIG_USB_DEVICE_CLASS is not set
+# CONFIG_USB_DYNAMIC_MINORS is not set
+CONFIG_USB_SUSPEND=y
+CONFIG_USB_OTG=y
+# CONFIG_USB_OTG_WHITELIST is not set
+# CONFIG_USB_OTG_BLACKLIST_HUB is not set
+CONFIG_USB_MON=y
+# CONFIG_USB_WUSB is not set
+# CONFIG_USB_WUSB_CBAF is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_C67X00_HCD is not set
+CONFIG_USB_EHCI_HCD=y
+# CONFIG_USB_EHCI_ROOT_HUB_TT is not set
+# CONFIG_USB_EHCI_TT_NEWSCHED is not set
+# CONFIG_USB_OXU210HP_HCD is not set
+# CONFIG_USB_ISP116X_HCD is not set
+# CONFIG_USB_ISP1760_HCD is not set
+# CONFIG_USB_ISP1362_HCD is not set
+# CONFIG_USB_OHCI_HCD is not set
+# CONFIG_USB_SL811_HCD is not set
+# CONFIG_USB_R8A66597_HCD is not set
+# CONFIG_USB_HWA_HCD is not set
+CONFIG_USB_MUSB_HDRC=y
+CONFIG_USB_MUSB_SOC=y
+
+#
+# OMAP 343x high speed USB support
+#
+# CONFIG_USB_MUSB_HOST is not set
+# CONFIG_USB_MUSB_PERIPHERAL is not set
+CONFIG_USB_MUSB_OTG=y
+CONFIG_USB_GADGET_MUSB_HDRC=y
+CONFIG_USB_MUSB_HDRC_HCD=y
+# CONFIG_MUSB_PIO_ONLY is not set
+CONFIG_USB_INVENTRA_DMA=y
+# CONFIG_USB_TI_CPPI_DMA is not set
+# CONFIG_USB_MUSB_DEBUG is not set
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+# CONFIG_USB_WDM is not set
+# CONFIG_USB_TMC is not set
+
+#
+# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may
+#
+
+#
+# also be needed; see USB_STORAGE Help for more info
+#
+CONFIG_USB_STORAGE=y
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_ISD200 is not set
+# CONFIG_USB_STORAGE_USBAT is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_SDDR55 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_STORAGE_ALAUDA is not set
+# CONFIG_USB_STORAGE_ONETOUCH is not set
+# CONFIG_USB_STORAGE_KARMA is not set
+# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set
+# CONFIG_USB_LIBUSUAL is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+
+#
+# USB port drivers
+#
+# CONFIG_USB_SERIAL is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_ADUTUX is not set
+# CONFIG_USB_SEVSEG is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_BERRY_CHARGE is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYPRESS_CY7C63 is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_FTDI_ELAN is not set
+# CONFIG_USB_APPLEDISPLAY is not set
+# CONFIG_USB_SISUSBVGA is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
+# CONFIG_USB_IOWARRIOR is not set
+CONFIG_USB_TEST=y
+# CONFIG_USB_ISIGHTFW is not set
+# CONFIG_USB_VST is not set
+CONFIG_USB_GADGET=y
+# CONFIG_USB_GADGET_DEBUG is not set
+# CONFIG_USB_GADGET_DEBUG_FILES is not set
+# CONFIG_USB_GADGET_DEBUG_FS is not set
+CONFIG_USB_GADGET_VBUS_DRAW=2
+CONFIG_USB_GADGET_SELECTED=y
+# CONFIG_USB_GADGET_AT91 is not set
+# CONFIG_USB_GADGET_ATMEL_USBA is not set
+# CONFIG_USB_GADGET_FSL_USB2 is not set
+# CONFIG_USB_GADGET_LH7A40X is not set
+# CONFIG_USB_GADGET_OMAP is not set
+# CONFIG_USB_GADGET_PXA25X is not set
+# CONFIG_USB_GADGET_R8A66597 is not set
+# CONFIG_USB_GADGET_PXA27X is not set
+# CONFIG_USB_GADGET_S3C_HSOTG is not set
+# CONFIG_USB_GADGET_IMX is not set
+# CONFIG_USB_GADGET_S3C2410 is not set
+# CONFIG_USB_GADGET_M66592 is not set
+# CONFIG_USB_GADGET_AMD5536UDC is not set
+# CONFIG_USB_GADGET_FSL_QE is not set
+# CONFIG_USB_GADGET_CI13XXX is not set
+# CONFIG_USB_GADGET_NET2280 is not set
+# CONFIG_USB_GADGET_GOKU is not set
+# CONFIG_USB_GADGET_LANGWELL is not set
+# CONFIG_USB_GADGET_DUMMY_HCD is not set
+CONFIG_USB_GADGET_DUALSPEED=y
+# CONFIG_USB_ZERO is not set
+# CONFIG_USB_AUDIO is not set
+CONFIG_USB_ETH=y
+CONFIG_USB_ETH_RNDIS=y
+# CONFIG_USB_ETH_EEM is not set
+# CONFIG_USB_GADGETFS is not set
+# CONFIG_USB_FILE_STORAGE is not set
+# CONFIG_USB_G_SERIAL is not set
+# CONFIG_USB_MIDI_GADGET is not set
+# CONFIG_USB_G_PRINTER is not set
+# CONFIG_USB_CDC_COMPOSITE is not set
+
+#
+# OTG and related infrastructure
+#
+CONFIG_USB_OTG_UTILS=y
+# CONFIG_USB_GPIO_VBUS is not set
+# CONFIG_ISP1301_OMAP is not set
+CONFIG_TWL4030_USB=y
+# CONFIG_NOP_USB_XCEIV is not set
+CONFIG_MMC=y
+# CONFIG_MMC_DEBUG is not set
+# CONFIG_MMC_UNSAFE_RESUME is not set
+
+#
+# MMC/SD/SDIO Card Drivers
+#
+CONFIG_MMC_BLOCK=y
+CONFIG_MMC_BLOCK_BOUNCE=y
+# CONFIG_SDIO_UART is not set
+# CONFIG_MMC_TEST is not set
+
+#
+# MMC/SD/SDIO Host Controller Drivers
+#
+# CONFIG_MMC_SDHCI is not set
+# CONFIG_MMC_OMAP is not set
+CONFIG_MMC_OMAP_HS=y
+# CONFIG_MMC_AT91 is not set
+# CONFIG_MMC_ATMELMCI is not set
+# CONFIG_MMC_SPI is not set
+# CONFIG_MEMSTICK is not set
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+
+#
+# LED drivers
+#
+# CONFIG_LEDS_PCA9532 is not set
+CONFIG_LEDS_GPIO=y
+CONFIG_LEDS_GPIO_PLATFORM=y
+# CONFIG_LEDS_LP3944 is not set
+# CONFIG_LEDS_PCA955X is not set
+# CONFIG_LEDS_DAC124S085 is not set
+# CONFIG_LEDS_BD2802 is not set
+
+#
+# LED Triggers
+#
+CONFIG_LEDS_TRIGGERS=y
+# CONFIG_LEDS_TRIGGER_TIMER is not set
+CONFIG_LEDS_TRIGGER_HEARTBEAT=y
+# CONFIG_LEDS_TRIGGER_BACKLIGHT is not set
+# CONFIG_LEDS_TRIGGER_GPIO is not set
+# CONFIG_LEDS_TRIGGER_DEFAULT_ON is not set
+
+#
+# iptables trigger is under Netfilter config (LED target)
+#
+# CONFIG_ACCESSIBILITY is not set
+CONFIG_RTC_LIB=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_HCTOSYS=y
+CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
+# CONFIG_RTC_DEBUG is not set
+
+#
+# RTC interfaces
+#
+CONFIG_RTC_INTF_SYSFS=y
+CONFIG_RTC_INTF_PROC=y
+CONFIG_RTC_INTF_DEV=y
+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+# CONFIG_RTC_DRV_TEST is not set
+
+#
+# I2C RTC drivers
+#
+# CONFIG_RTC_DRV_DS1307 is not set
+# CONFIG_RTC_DRV_DS1374 is not set
+# CONFIG_RTC_DRV_DS1672 is not set
+# CONFIG_RTC_DRV_MAX6900 is not set
+# CONFIG_RTC_DRV_RS5C372 is not set
+# CONFIG_RTC_DRV_ISL1208 is not set
+# CONFIG_RTC_DRV_X1205 is not set
+# CONFIG_RTC_DRV_PCF8563 is not set
+# CONFIG_RTC_DRV_PCF8583 is not set
+# CONFIG_RTC_DRV_M41T80 is not set
+CONFIG_RTC_DRV_TWL4030=y
+# CONFIG_RTC_DRV_S35390A is not set
+# CONFIG_RTC_DRV_FM3130 is not set
+# CONFIG_RTC_DRV_RX8581 is not set
+# CONFIG_RTC_DRV_RX8025 is not set
+
+#
+# SPI RTC drivers
+#
+# CONFIG_RTC_DRV_M41T94 is not set
+# CONFIG_RTC_DRV_DS1305 is not set
+# CONFIG_RTC_DRV_DS1390 is not set
+# CONFIG_RTC_DRV_MAX6902 is not set
+# CONFIG_RTC_DRV_R9701 is not set
+# CONFIG_RTC_DRV_RS5C348 is not set
+# CONFIG_RTC_DRV_DS3234 is not set
+# CONFIG_RTC_DRV_PCF2123 is not set
+
+#
+# Platform RTC drivers
+#
+# CONFIG_RTC_DRV_CMOS is not set
+# CONFIG_RTC_DRV_DS1286 is not set
+# CONFIG_RTC_DRV_DS1511 is not set
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+# CONFIG_RTC_DRV_STK17TA8 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_M48T35 is not set
+# CONFIG_RTC_DRV_M48T59 is not set
+# CONFIG_RTC_DRV_BQ4802 is not set
+# CONFIG_RTC_DRV_V3020 is not set
+
+#
+# on-CPU RTC drivers
+#
+# CONFIG_DMADEVICES is not set
+# CONFIG_AUXDISPLAY is not set
+# CONFIG_UIO is not set
+
+#
+# TI VLYNQ
+#
+# CONFIG_STAGING is not set
+
+#
+# CBUS support
+#
+# CONFIG_CBUS is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
+# CONFIG_EXT3_FS_XATTR is not set
+# CONFIG_EXT4_FS is not set
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_BTRFS_FS is not set
+# CONFIG_NILFS2_FS is not set
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
+CONFIG_DNOTIFY=y
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+CONFIG_QUOTA=y
+# CONFIG_QUOTA_NETLINK_INTERFACE is not set
+CONFIG_PRINT_QUOTA_WARNING=y
+CONFIG_QUOTA_TREE=y
+# CONFIG_QFMT_V1 is not set
+CONFIG_QFMT_V2=y
+CONFIG_QUOTACTL=y
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# Caches
+#
+# CONFIG_FSCACHE is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+CONFIG_NTFS_FS=m
+# CONFIG_NTFS_DEBUG is not set
+# CONFIG_NTFS_RW is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLB_PAGE is not set
+# CONFIG_CONFIGFS_FS is not set
+CONFIG_MISC_FILESYSTEMS=y
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+# CONFIG_JFFS2_FS_WBUF_VERIFY is not set
+CONFIG_JFFS2_SUMMARY=y
+# CONFIG_JFFS2_FS_XATTR is not set
+CONFIG_JFFS2_COMPRESSION_OPTIONS=y
+CONFIG_JFFS2_ZLIB=y
+# CONFIG_JFFS2_LZO is not set
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
+# CONFIG_JFFS2_CMODE_NONE is not set
+CONFIG_JFFS2_CMODE_PRIORITY=y
+# CONFIG_JFFS2_CMODE_SIZE is not set
+# CONFIG_JFFS2_CMODE_FAVOURLZO is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_SQUASHFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_OMFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+CONFIG_NETWORK_FILESYSTEMS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+CONFIG_NFS_V4=y
+# CONFIG_NFS_V4_1 is not set
+CONFIG_ROOT_NFS=y
+# CONFIG_NFSD is not set
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+CONFIG_SUNRPC_GSS=y
+CONFIG_RPCSEC_GSS_KRB5=y
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_KARMA_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+# CONFIG_SYSV68_PARTITION is not set
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+CONFIG_NLS_ISO8859_1=y
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+CONFIG_NLS_UTF8=m
+# CONFIG_DLM is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_WARN_DEPRECATED=y
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_FRAME_WARN=1024
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_STRIP_ASM_SYMS is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+CONFIG_DEBUG_FS=y
+# CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SHIRQ is not set
+CONFIG_DETECT_SOFTLOCKUP=y
+# CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set
+CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0
+CONFIG_DETECT_HUNG_TASK=y
+# CONFIG_BOOTPARAM_HUNG_TASK_PANIC is not set
+CONFIG_BOOTPARAM_HUNG_TASK_PANIC_VALUE=0
+# CONFIG_SCHED_DEBUG is not set
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_TIMER_STATS is not set
+# CONFIG_DEBUG_OBJECTS is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_KMEMLEAK is not set
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+CONFIG_DEBUG_MUTEXES=y
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_LOCK_STAT is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_DEBUG_KOBJECT is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+CONFIG_DEBUG_INFO=y
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_WRITECOUNT is not set
+# CONFIG_DEBUG_MEMORY_INIT is not set
+# CONFIG_DEBUG_LIST is not set
+# CONFIG_DEBUG_SG is not set
+# CONFIG_DEBUG_NOTIFIERS is not set
+# CONFIG_DEBUG_CREDENTIALS is not set
+# CONFIG_BOOT_PRINTK_DELAY is not set
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_RCU_CPU_STALL_DETECTOR is not set
+# CONFIG_BACKTRACE_SELF_TEST is not set
+# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
+# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
+# CONFIG_FAULT_INJECTION is not set
+# CONFIG_LATENCYTOP is not set
+# CONFIG_PAGE_POISONING is not set
+CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_TRACING_SUPPORT=y
+CONFIG_FTRACE=y
+# CONFIG_FUNCTION_TRACER is not set
+# CONFIG_IRQSOFF_TRACER is not set
+# CONFIG_SCHED_TRACER is not set
+# CONFIG_ENABLE_DEFAULT_TRACERS is not set
+# CONFIG_BOOT_TRACER is not set
+CONFIG_BRANCH_PROFILE_NONE=y
+# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set
+# CONFIG_PROFILE_ALL_BRANCHES is not set
+# CONFIG_STACK_TRACER is not set
+# CONFIG_KMEMTRACE is not set
+# CONFIG_WORKQUEUE_TRACER is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_DYNAMIC_DEBUG is not set
+# CONFIG_SAMPLES is not set
+CONFIG_HAVE_ARCH_KGDB=y
+# CONFIG_KGDB is not set
+CONFIG_ARM_UNWIND=y
+# CONFIG_DEBUG_USER is not set
+# CONFIG_DEBUG_ERRORS is not set
+# CONFIG_DEBUG_STACK_USAGE is not set
+CONFIG_DEBUG_LL=y
+# CONFIG_DEBUG_ICEDCC is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+# CONFIG_SECURITYFS is not set
+# CONFIG_SECURITY_FILE_CAPABILITIES is not set
+CONFIG_CRYPTO=y
+
+#
+# Crypto core or helper
+#
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_ALGAPI2=y
+CONFIG_CRYPTO_AEAD2=y
+CONFIG_CRYPTO_BLKCIPHER=y
+CONFIG_CRYPTO_BLKCIPHER2=y
+CONFIG_CRYPTO_HASH=y
+CONFIG_CRYPTO_HASH2=y
+CONFIG_CRYPTO_RNG2=y
+CONFIG_CRYPTO_PCOMP=y
+CONFIG_CRYPTO_MANAGER=y
+CONFIG_CRYPTO_MANAGER2=y
+# CONFIG_CRYPTO_GF128MUL is not set
+# CONFIG_CRYPTO_NULL is not set
+CONFIG_CRYPTO_WORKQUEUE=y
+# CONFIG_CRYPTO_CRYPTD is not set
+# CONFIG_CRYPTO_AUTHENC is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Authenticated Encryption with Associated Data
+#
+# CONFIG_CRYPTO_CCM is not set
+# CONFIG_CRYPTO_GCM is not set
+# CONFIG_CRYPTO_SEQIV is not set
+
+#
+# Block modes
+#
+CONFIG_CRYPTO_CBC=y
+# CONFIG_CRYPTO_CTR is not set
+# CONFIG_CRYPTO_CTS is not set
+CONFIG_CRYPTO_ECB=m
+# CONFIG_CRYPTO_LRW is not set
+CONFIG_CRYPTO_PCBC=m
+# CONFIG_CRYPTO_XTS is not set
+
+#
+# Hash modes
+#
+# CONFIG_CRYPTO_HMAC is not set
+# CONFIG_CRYPTO_XCBC is not set
+# CONFIG_CRYPTO_VMAC is not set
+
+#
+# Digest
+#
+CONFIG_CRYPTO_CRC32C=y
+# CONFIG_CRYPTO_GHASH is not set
+# CONFIG_CRYPTO_MD4 is not set
+CONFIG_CRYPTO_MD5=y
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_RMD128 is not set
+# CONFIG_CRYPTO_RMD160 is not set
+# CONFIG_CRYPTO_RMD256 is not set
+# CONFIG_CRYPTO_RMD320 is not set
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_WP512 is not set
+
+#
+# Ciphers
+#
+# CONFIG_CRYPTO_AES is not set
+# CONFIG_CRYPTO_ANUBIS is not set
+# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_CAMELLIA is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+CONFIG_CRYPTO_DES=y
+# CONFIG_CRYPTO_FCRYPT is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_SALSA20 is not set
+# CONFIG_CRYPTO_SEED is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+
+#
+# Compression
+#
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_ZLIB is not set
+# CONFIG_CRYPTO_LZO is not set
+
+#
+# Random Number Generation
+#
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
+CONFIG_CRYPTO_HW=y
+# CONFIG_BINARY_PRINTF is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+CONFIG_GENERIC_FIND_LAST_BIT=y
+CONFIG_CRC_CCITT=y
+# CONFIG_CRC16 is not set
+# CONFIG_CRC_T10DIF is not set
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+CONFIG_LIBCRC32C=y
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_DECOMPRESS_GZIP=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
+CONFIG_NLATTR=y
index d18d21b..a017086 100644 (file)
@@ -1,15 +1,13 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.30-rc8
-# Thu Jun  4 09:53:21 2009
+# Linux kernel version: 2.6.32-rc4
+# Tue Oct 13 19:03:13 2009
 #
 CONFIG_ARM=y
 CONFIG_SYS_SUPPORTS_APM_EMULATION=y
 CONFIG_GENERIC_GPIO=y
 CONFIG_GENERIC_TIME=y
 CONFIG_GENERIC_CLOCKEVENTS=y
-CONFIG_MMU=y
-# CONFIG_NO_IOPORT is not set
 CONFIG_GENERIC_HARDIRQS=y
 CONFIG_STACKTRACE_SUPPORT=y
 CONFIG_HAVE_LATENCYTOP_SUPPORT=y
@@ -18,14 +16,14 @@ CONFIG_TRACE_IRQFLAGS_SUPPORT=y
 CONFIG_HARDIRQS_SW_RESEND=y
 CONFIG_GENERIC_IRQ_PROBE=y
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
-# CONFIG_ARCH_HAS_ILOG2_U32 is not set
-# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_ARCH_HAS_CPUFREQ=y
 CONFIG_GENERIC_HWEIGHT=y
 CONFIG_GENERIC_CALIBRATE_DELAY=y
 CONFIG_ARCH_MTD_XIP=y
 CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
 CONFIG_VECTORS_BASE=0xffff0000
 CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
 
 #
 # General setup
@@ -46,11 +44,12 @@ CONFIG_SYSVIPC_SYSCTL=y
 #
 # RCU Subsystem
 #
-CONFIG_CLASSIC_RCU=y
-# CONFIG_TREE_RCU is not set
-# CONFIG_PREEMPT_RCU is not set
+CONFIG_TREE_RCU=y
+# CONFIG_TREE_PREEMPT_RCU is not set
+# CONFIG_RCU_TRACE is not set
+CONFIG_RCU_FANOUT=32
+# CONFIG_RCU_FANOUT_EXACT is not set
 # CONFIG_TREE_RCU_TRACE is not set
-# CONFIG_PREEMPT_RCU_TRACE is not set
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=18
@@ -83,7 +82,6 @@ CONFIG_SYSCTL_SYSCALL=y
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_ALL is not set
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
-# CONFIG_STRIP_ASM_SYMS is not set
 CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
@@ -96,6 +94,10 @@ CONFIG_TIMERFD=y
 CONFIG_EVENTFD=y
 CONFIG_SHMEM=y
 CONFIG_AIO=y
+
+#
+# Kernel Performance Events And Counters
+#
 CONFIG_VM_EVENT_COUNTERS=y
 CONFIG_SLUB_DEBUG=y
 CONFIG_COMPAT_BRK=y
@@ -103,13 +105,17 @@ CONFIG_COMPAT_BRK=y
 CONFIG_SLUB=y
 # CONFIG_SLOB is not set
 # CONFIG_PROFILING is not set
-# CONFIG_MARKERS is not set
 CONFIG_HAVE_OPROFILE=y
 # CONFIG_KPROBES is not set
 CONFIG_HAVE_KPROBES=y
 CONFIG_HAVE_KRETPROBES=y
 CONFIG_HAVE_CLK=y
-# CONFIG_SLOW_WORK is not set
+
+#
+# GCOV-based kernel profiling
+#
+# CONFIG_GCOV_KERNEL is not set
+CONFIG_SLOW_WORK=y
 CONFIG_HAVE_GENERIC_DMA_COHERENT=y
 CONFIG_SLABINFO=y
 CONFIG_RT_MUTEXES=y
@@ -117,11 +123,11 @@ CONFIG_BASE_SMALL=0
 CONFIG_MODULES=y
 # CONFIG_MODULE_FORCE_LOAD is not set
 CONFIG_MODULE_UNLOAD=y
-# CONFIG_MODULE_FORCE_UNLOAD is not set
+CONFIG_MODULE_FORCE_UNLOAD=y
 # CONFIG_MODVERSIONS is not set
 # CONFIG_MODULE_SRCVERSION_ALL is not set
 CONFIG_BLOCK=y
-# CONFIG_LBD is not set
+CONFIG_LBDAF=y
 # CONFIG_BLK_DEV_BSG is not set
 # CONFIG_BLK_DEV_INTEGRITY is not set
 
@@ -142,19 +148,22 @@ CONFIG_FREEZER=y
 #
 # System Type
 #
+CONFIG_MMU=y
 # CONFIG_ARCH_AAEC2000 is not set
 # CONFIG_ARCH_INTEGRATOR is not set
 # CONFIG_ARCH_REALVIEW is not set
 # CONFIG_ARCH_VERSATILE is not set
 # CONFIG_ARCH_AT91 is not set
 # CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_GEMINI is not set
 # CONFIG_ARCH_EBSA110 is not set
 # CONFIG_ARCH_EP93XX is not set
-# CONFIG_ARCH_GEMINI is not set
 # CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_MXC is not set
+# CONFIG_ARCH_STMP3XXX is not set
 # CONFIG_ARCH_NETX is not set
 # CONFIG_ARCH_H720X is not set
-# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_NOMADIK is not set
 # CONFIG_ARCH_IOP13XX is not set
 # CONFIG_ARCH_IOP32X is not set
 # CONFIG_ARCH_IOP33X is not set
@@ -163,25 +172,27 @@ CONFIG_FREEZER=y
 # CONFIG_ARCH_IXP4XX is not set
 # CONFIG_ARCH_L7200 is not set
 # CONFIG_ARCH_KIRKWOOD is not set
-# CONFIG_ARCH_KS8695 is not set
-# CONFIG_ARCH_NS9XXX is not set
 # CONFIG_ARCH_LOKI is not set
 # CONFIG_ARCH_MV78XX0 is not set
-# CONFIG_ARCH_MXC is not set
 # CONFIG_ARCH_ORION5X is not set
+# CONFIG_ARCH_MMP is not set
+# CONFIG_ARCH_KS8695 is not set
+# CONFIG_ARCH_NS9XXX is not set
+# CONFIG_ARCH_W90X900 is not set
 # CONFIG_ARCH_PNX4008 is not set
 CONFIG_ARCH_PXA=y
-# CONFIG_ARCH_MMP is not set
+# CONFIG_ARCH_MSM is not set
 # CONFIG_ARCH_RPC is not set
 # CONFIG_ARCH_SA1100 is not set
 # CONFIG_ARCH_S3C2410 is not set
 # CONFIG_ARCH_S3C64XX is not set
+# CONFIG_ARCH_S5PC1XX is not set
 # CONFIG_ARCH_SHARK is not set
 # CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_U300 is not set
 # CONFIG_ARCH_DAVINCI is not set
 # CONFIG_ARCH_OMAP is not set
-# CONFIG_ARCH_MSM is not set
-# CONFIG_ARCH_W90X900 is not set
+# CONFIG_ARCH_BCMRING is not set
 
 #
 # Intel PXA2xx/PXA3xx Implementations
@@ -191,16 +202,19 @@ CONFIG_ARCH_PXA=y
 # Supported PXA3xx Processor Variants
 #
 CONFIG_CPU_PXA300=y
-# CONFIG_CPU_PXA310 is not set
+CONFIG_CPU_PXA310=y
 # CONFIG_CPU_PXA320 is not set
 # CONFIG_CPU_PXA930 is not set
 # CONFIG_CPU_PXA935 is not set
+# CONFIG_CPU_PXA950 is not set
 # CONFIG_ARCH_GUMSTIX is not set
 # CONFIG_MACH_INTELMOTE2 is not set
+# CONFIG_MACH_STARGATE2 is not set
 # CONFIG_ARCH_LUBBOCK is not set
 # CONFIG_MACH_LOGICPD_PXA270 is not set
 # CONFIG_MACH_MAINSTONE is not set
 # CONFIG_MACH_MP900C is not set
+# CONFIG_MACH_BALLOON3 is not set
 # CONFIG_ARCH_PXA_IDP is not set
 # CONFIG_PXA_SHARPSL is not set
 # CONFIG_ARCH_VIPER is not set
@@ -218,6 +232,7 @@ CONFIG_CPU_PXA300=y
 # CONFIG_MACH_SAAR is not set
 # CONFIG_MACH_ARMCORE is not set
 CONFIG_MACH_CM_X300=y
+# CONFIG_MACH_H4700 is not set
 # CONFIG_MACH_MAGICIAN is not set
 # CONFIG_MACH_HIMALAYA is not set
 # CONFIG_MACH_MIOA701 is not set
@@ -225,8 +240,8 @@ CONFIG_MACH_CM_X300=y
 # CONFIG_ARCH_PXA_PALM is not set
 # CONFIG_MACH_CSB726 is not set
 # CONFIG_PXA_EZX is not set
+# CONFIG_MACH_XCEP is not set
 CONFIG_PXA3xx=y
-# CONFIG_PXA_PWM is not set
 CONFIG_PLAT_PXA=y
 
 #
@@ -236,7 +251,7 @@ CONFIG_CPU_32=y
 CONFIG_CPU_XSC3=y
 CONFIG_CPU_32v5=y
 CONFIG_CPU_ABRT_EV5T=y
-CONFIG_CPU_PABRT_NOIFAR=y
+CONFIG_CPU_PABRT_LEGACY=y
 CONFIG_CPU_CACHE_VIVT=y
 CONFIG_CPU_TLB_V4WBI=y
 CONFIG_CPU_CP15=y
@@ -246,11 +261,12 @@ CONFIG_IO_36=y
 #
 # Processor Features
 #
-# CONFIG_ARM_THUMB is not set
+CONFIG_ARM_THUMB=y
 # CONFIG_CPU_DCACHE_DISABLE is not set
 # CONFIG_CPU_BPREDICT_DISABLE is not set
 CONFIG_OUTER_CACHE=y
 CONFIG_CACHE_XSC3L2=y
+CONFIG_ARM_L1_CACHE_SHIFT=5
 CONFIG_IWMMXT=y
 CONFIG_COMMON_CLKDEV=y
 
@@ -272,11 +288,12 @@ CONFIG_VMSPLIT_3G=y
 # CONFIG_VMSPLIT_2G is not set
 # CONFIG_VMSPLIT_1G is not set
 CONFIG_PAGE_OFFSET=0xC0000000
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
 # CONFIG_PREEMPT is not set
 CONFIG_HZ=100
 CONFIG_AEABI=y
 CONFIG_OABI_COMPAT=y
-# CONFIG_ARCH_HAS_HOLES_MEMORYMODEL is not set
 # CONFIG_ARCH_SPARSEMEM_DEFAULT is not set
 # CONFIG_ARCH_SELECT_MEMORY_MODEL is not set
 CONFIG_HIGHMEM=y
@@ -292,17 +309,19 @@ CONFIG_SPLIT_PTLOCK_CPUS=4096
 CONFIG_ZONE_DMA_FLAG=0
 CONFIG_BOUNCE=y
 CONFIG_VIRT_TO_BUS=y
-CONFIG_UNEVICTABLE_LRU=y
 CONFIG_HAVE_MLOCK=y
 CONFIG_HAVE_MLOCKED_PAGE_BIT=y
+# CONFIG_KSM is not set
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
 CONFIG_ALIGNMENT_TRAP=y
+# CONFIG_UACCESS_WITH_MEMCPY is not set
 
 #
 # Boot options
 #
 CONFIG_ZBOOT_ROM_TEXT=0x0
 CONFIG_ZBOOT_ROM_BSS=0x0
-CONFIG_CMDLINE="root=/dev/mtdblock5 rootfstype=jffs2 console=ttyS2,38400"
+CONFIG_CMDLINE="root=/dev/mtdblock5 rootfstype=ubifs console=ttyS2,38400"
 # CONFIG_XIP_KERNEL is not set
 # CONFIG_KEXEC is not set
 
@@ -355,6 +374,7 @@ CONFIG_PM_SLEEP=y
 CONFIG_SUSPEND=y
 CONFIG_SUSPEND_FREEZER=y
 CONFIG_APM_EMULATION=y
+# CONFIG_PM_RUNTIME is not set
 CONFIG_ARCH_SUSPEND_POSSIBLE=y
 CONFIG_NET=y
 
@@ -396,6 +416,7 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
 # CONFIG_NETFILTER is not set
 # CONFIG_IP_DCCP is not set
 # CONFIG_IP_SCTP is not set
+# CONFIG_RDS is not set
 # CONFIG_TIPC is not set
 # CONFIG_ATM is not set
 # CONFIG_BRIDGE is not set
@@ -410,6 +431,7 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
 # CONFIG_PHONET is not set
+# CONFIG_IEEE802154 is not set
 # CONFIG_NET_SCHED is not set
 # CONFIG_DCB is not set
 
@@ -433,22 +455,27 @@ CONFIG_BT_HIDP=m
 #
 # Bluetooth device drivers
 #
-# CONFIG_BT_HCIBTUSB is not set
+CONFIG_BT_HCIBTUSB=m
 # CONFIG_BT_HCIBTSDIO is not set
 # CONFIG_BT_HCIUART is not set
 # CONFIG_BT_HCIBCM203X is not set
 # CONFIG_BT_HCIBPA10X is not set
 # CONFIG_BT_HCIBFUSB is not set
 # CONFIG_BT_HCIVHCI is not set
+# CONFIG_BT_MRVL is not set
 # CONFIG_AF_RXRPC is not set
 CONFIG_WIRELESS=y
 # CONFIG_CFG80211 is not set
+CONFIG_CFG80211_DEFAULT_PS_VALUE=0
 # CONFIG_WIRELESS_OLD_REGULATORY is not set
 CONFIG_WIRELESS_EXT=y
 CONFIG_WIRELESS_EXT_SYSFS=y
 CONFIG_LIB80211=m
 # CONFIG_LIB80211_DEBUG is not set
-# CONFIG_MAC80211 is not set
+
+#
+# CFG80211 needs to be enabled for MAC80211
+#
 # CONFIG_WIMAX is not set
 # CONFIG_RFKILL is not set
 # CONFIG_NET_9P is not set
@@ -461,6 +488,7 @@ CONFIG_LIB80211=m
 # Generic Driver Options
 #
 CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+# CONFIG_DEVTMPFS is not set
 CONFIG_STANDALONE=y
 CONFIG_PREVENT_FIRMWARE_BUILD=y
 CONFIG_FW_LOADER=y
@@ -472,9 +500,9 @@ CONFIG_EXTRA_FIRMWARE=""
 # CONFIG_CONNECTOR is not set
 CONFIG_MTD=y
 # CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_TESTS is not set
 # CONFIG_MTD_CONCAT is not set
 CONFIG_MTD_PARTITIONS=y
-# CONFIG_MTD_TESTS is not set
 # CONFIG_MTD_REDBOOT_PARTS is not set
 # CONFIG_MTD_CMDLINE_PARTS is not set
 # CONFIG_MTD_AFS_PARTS is not set
@@ -521,6 +549,9 @@ CONFIG_MTD_CFI_I2=y
 #
 # Self-contained MTD device drivers
 #
+# CONFIG_MTD_DATAFLASH is not set
+# CONFIG_MTD_M25P80 is not set
+# CONFIG_MTD_SST25L is not set
 # CONFIG_MTD_SLRAM is not set
 # CONFIG_MTD_PHRAM is not set
 # CONFIG_MTD_MTDRAM is not set
@@ -556,7 +587,15 @@ CONFIG_MTD_NAND_PXA3xx=y
 #
 # UBI - Unsorted block images
 #
-# CONFIG_MTD_UBI is not set
+CONFIG_MTD_UBI=y
+CONFIG_MTD_UBI_WL_THRESHOLD=4096
+CONFIG_MTD_UBI_BEB_RESERVE=1
+# CONFIG_MTD_UBI_GLUEBI is not set
+
+#
+# UBI debugging options
+#
+# CONFIG_MTD_UBI_DEBUG is not set
 # CONFIG_PARPORT is not set
 CONFIG_BLK_DEV=y
 # CONFIG_BLK_DEV_COW_COMMON is not set
@@ -570,6 +609,7 @@ CONFIG_BLK_DEV_RAM_SIZE=4096
 # CONFIG_BLK_DEV_XIP is not set
 # CONFIG_CDROM_PKTCDVD is not set
 # CONFIG_ATA_OVER_ETH is not set
+# CONFIG_MG_DISK is not set
 # CONFIG_MISC_DEVICES is not set
 CONFIG_HAVE_IDE=y
 # CONFIG_IDE is not set
@@ -593,10 +633,6 @@ CONFIG_BLK_DEV_SD=y
 # CONFIG_BLK_DEV_SR is not set
 # CONFIG_CHR_DEV_SG is not set
 # CONFIG_CHR_DEV_SCH is not set
-
-#
-# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
-#
 # CONFIG_SCSI_MULTI_LUN is not set
 # CONFIG_SCSI_CONSTANTS is not set
 # CONFIG_SCSI_LOGGING is not set
@@ -621,7 +657,6 @@ CONFIG_SCSI_LOWLEVEL=y
 # CONFIG_ATA is not set
 # CONFIG_MD is not set
 CONFIG_NETDEVICES=y
-CONFIG_COMPAT_NET_DEV_OPS=y
 # CONFIG_DUMMY is not set
 # CONFIG_BONDING is not set
 # CONFIG_MACVLAN is not set
@@ -636,6 +671,7 @@ CONFIG_MII=y
 CONFIG_DM9000=y
 CONFIG_DM9000_DEBUGLEVEL=0
 CONFIG_DM9000_FORCE_SIMPLE_PHY_POLL=y
+# CONFIG_ENC28J60 is not set
 # CONFIG_ETHOC is not set
 # CONFIG_SMC911X is not set
 # CONFIG_SMSC911X is not set
@@ -648,20 +684,20 @@ CONFIG_DM9000_FORCE_SIMPLE_PHY_POLL=y
 # CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT is not set
 # CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
 # CONFIG_B44 is not set
+# CONFIG_KS8842 is not set
+# CONFIG_KS8851 is not set
+# CONFIG_KS8851_MLL is not set
 # CONFIG_NETDEV_1000 is not set
 # CONFIG_NETDEV_10000 is not set
-
-#
-# Wireless LAN
-#
+CONFIG_WLAN=y
 # CONFIG_WLAN_PRE80211 is not set
 CONFIG_WLAN_80211=y
 CONFIG_LIBERTAS=m
 # CONFIG_LIBERTAS_USB is not set
 CONFIG_LIBERTAS_SDIO=m
+# CONFIG_LIBERTAS_SPI is not set
 # CONFIG_LIBERTAS_DEBUG is not set
 # CONFIG_USB_ZD1201 is not set
-# CONFIG_USB_NET_RNDIS_WLAN is not set
 # CONFIG_HOSTAP is not set
 
 #
@@ -683,6 +719,7 @@ CONFIG_LIBERTAS_SDIO=m
 # CONFIG_NETPOLL is not set
 # CONFIG_NET_POLL_CONTROLLER is not set
 # CONFIG_ISDN is not set
+# CONFIG_PHONE is not set
 
 #
 # Input device support
@@ -706,33 +743,51 @@ CONFIG_INPUT_EVDEV=y
 # Input Device Drivers
 #
 CONFIG_INPUT_KEYBOARD=y
+# CONFIG_KEYBOARD_ADP5588 is not set
 # CONFIG_KEYBOARD_ATKBD is not set
-# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_QT2160 is not set
 # CONFIG_KEYBOARD_LKKBD is not set
-# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_GPIO is not set
+# CONFIG_KEYBOARD_MATRIX is not set
+# CONFIG_KEYBOARD_LM8323 is not set
+# CONFIG_KEYBOARD_MAX7359 is not set
 # CONFIG_KEYBOARD_NEWTON is not set
-# CONFIG_KEYBOARD_STOWAWAY is not set
+# CONFIG_KEYBOARD_OPENCORES is not set
 CONFIG_KEYBOARD_PXA27x=m
-# CONFIG_KEYBOARD_GPIO is not set
+# CONFIG_KEYBOARD_STOWAWAY is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
 # CONFIG_INPUT_MOUSE is not set
 # CONFIG_INPUT_JOYSTICK is not set
 # CONFIG_INPUT_TABLET is not set
 CONFIG_INPUT_TOUCHSCREEN=y
+# CONFIG_TOUCHSCREEN_ADS7846 is not set
+# CONFIG_TOUCHSCREEN_AD7877 is not set
 # CONFIG_TOUCHSCREEN_AD7879_I2C is not set
+# CONFIG_TOUCHSCREEN_AD7879_SPI is not set
 # CONFIG_TOUCHSCREEN_AD7879 is not set
+# CONFIG_TOUCHSCREEN_DA9034 is not set
+# CONFIG_TOUCHSCREEN_EETI is not set
 # CONFIG_TOUCHSCREEN_FUJITSU is not set
 # CONFIG_TOUCHSCREEN_GUNZE is not set
 # CONFIG_TOUCHSCREEN_ELO is not set
 # CONFIG_TOUCHSCREEN_WACOM_W8001 is not set
+# CONFIG_TOUCHSCREEN_MCS5000 is not set
 # CONFIG_TOUCHSCREEN_MTOUCH is not set
 # CONFIG_TOUCHSCREEN_INEXIO is not set
 # CONFIG_TOUCHSCREEN_MK712 is not set
 # CONFIG_TOUCHSCREEN_PENMOUNT is not set
 # CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set
 # CONFIG_TOUCHSCREEN_TOUCHWIN is not set
+CONFIG_TOUCHSCREEN_WM97XX=m
+# CONFIG_TOUCHSCREEN_WM9705 is not set
+CONFIG_TOUCHSCREEN_WM9712=y
+# CONFIG_TOUCHSCREEN_WM9713 is not set
+# CONFIG_TOUCHSCREEN_WM97XX_MAINSTONE is not set
 # CONFIG_TOUCHSCREEN_USB_COMPOSITE is not set
 # CONFIG_TOUCHSCREEN_TOUCHIT213 is not set
 # CONFIG_TOUCHSCREEN_TSC2007 is not set
+# CONFIG_TOUCHSCREEN_W90X900 is not set
 # CONFIG_INPUT_MISC is not set
 
 #
@@ -760,6 +815,7 @@ CONFIG_DEVKMEM=y
 #
 # Non-8250 serial port support
 #
+# CONFIG_SERIAL_MAX3100 is not set
 CONFIG_SERIAL_PXA=y
 CONFIG_SERIAL_PXA_CONSOLE=y
 CONFIG_SERIAL_CORE=y
@@ -774,6 +830,7 @@ CONFIG_UNIX98_PTYS=y
 # CONFIG_TCG_TPM is not set
 CONFIG_I2C=y
 CONFIG_I2C_BOARDINFO=y
+CONFIG_I2C_COMPAT=y
 # CONFIG_I2C_CHARDEV is not set
 CONFIG_I2C_HELPER_AUTO=y
 
@@ -784,6 +841,7 @@ CONFIG_I2C_HELPER_AUTO=y
 #
 # I2C system bus drivers (mostly embedded / system-on-chip)
 #
+# CONFIG_I2C_DESIGNWARE is not set
 # CONFIG_I2C_GPIO is not set
 # CONFIG_I2C_OCORES is not set
 CONFIG_I2C_PXA=y
@@ -807,19 +865,36 @@ CONFIG_I2C_PXA=y
 # Miscellaneous I2C Chip support
 #
 # CONFIG_DS1682 is not set
-# CONFIG_SENSORS_PCF8574 is not set
-# CONFIG_PCF8575 is not set
-# CONFIG_SENSORS_MAX6875 is not set
 # CONFIG_SENSORS_TSL2550 is not set
 # CONFIG_I2C_DEBUG_CORE is not set
 # CONFIG_I2C_DEBUG_ALGO is not set
 # CONFIG_I2C_DEBUG_BUS is not set
 # CONFIG_I2C_DEBUG_CHIP is not set
-# CONFIG_SPI is not set
+CONFIG_SPI=y
+# CONFIG_SPI_DEBUG is not set
+CONFIG_SPI_MASTER=y
+
+#
+# SPI Master Controller Drivers
+#
+CONFIG_SPI_BITBANG=y
+CONFIG_SPI_GPIO=y
+# CONFIG_SPI_PXA2XX is not set
+
+#
+# SPI Protocol Masters
+#
+# CONFIG_SPI_SPIDEV is not set
+# CONFIG_SPI_TLE62X0 is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
 CONFIG_ARCH_REQUIRE_GPIOLIB=y
 CONFIG_GPIOLIB=y
 # CONFIG_DEBUG_GPIO is not set
-# CONFIG_GPIO_SYSFS is not set
+CONFIG_GPIO_SYSFS=y
 
 #
 # Memory mapped GPIO expanders:
@@ -839,11 +914,17 @@ CONFIG_GPIO_PCA953X=y
 #
 # SPI GPIO expanders:
 #
+# CONFIG_GPIO_MAX7301 is not set
+# CONFIG_GPIO_MCP23S08 is not set
+# CONFIG_GPIO_MC33880 is not set
+
+#
+# AC97 GPIO expanders:
+#
 # CONFIG_W1 is not set
 # CONFIG_POWER_SUPPLY is not set
 # CONFIG_HWMON is not set
 # CONFIG_THERMAL is not set
-# CONFIG_THERMAL_HWMON is not set
 # CONFIG_WATCHDOG is not set
 CONFIG_SSB_POSSIBLE=y
 
@@ -860,32 +941,33 @@ CONFIG_SSB_POSSIBLE=y
 # CONFIG_MFD_ASIC3 is not set
 # CONFIG_HTC_EGPIO is not set
 # CONFIG_HTC_PASIC3 is not set
+# CONFIG_UCB1400_CORE is not set
 # CONFIG_TPS65010 is not set
 # CONFIG_TWL4030_CORE is not set
 # CONFIG_MFD_TMIO is not set
 # CONFIG_MFD_T7L66XB is not set
 # CONFIG_MFD_TC6387XB is not set
 # CONFIG_MFD_TC6393XB is not set
-# CONFIG_PMIC_DA903X is not set
+CONFIG_PMIC_DA903X=y
 # CONFIG_MFD_WM8400 is not set
+# CONFIG_MFD_WM831X is not set
 # CONFIG_MFD_WM8350_I2C is not set
 # CONFIG_MFD_PCF50633 is not set
-
-#
-# Multimedia devices
-#
-
-#
-# Multimedia core support
-#
-# CONFIG_VIDEO_DEV is not set
-# CONFIG_DVB_CORE is not set
-# CONFIG_VIDEO_MEDIA is not set
-
-#
-# Multimedia drivers
-#
-# CONFIG_DAB is not set
+# CONFIG_MFD_MC13783 is not set
+# CONFIG_AB3100_CORE is not set
+# CONFIG_EZX_PCAP is not set
+CONFIG_REGULATOR=y
+# CONFIG_REGULATOR_DEBUG is not set
+# CONFIG_REGULATOR_FIXED_VOLTAGE is not set
+# CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set
+# CONFIG_REGULATOR_USERSPACE_CONSUMER is not set
+# CONFIG_REGULATOR_BQ24022 is not set
+# CONFIG_REGULATOR_MAX1586 is not set
+CONFIG_REGULATOR_DA903X=y
+# CONFIG_REGULATOR_LP3971 is not set
+# CONFIG_REGULATOR_TPS65023 is not set
+# CONFIG_REGULATOR_TPS6507X is not set
+# CONFIG_MEDIA_SUPPORT is not set
 
 #
 # Graphics support
@@ -925,7 +1007,17 @@ CONFIG_FB_PXA=y
 # CONFIG_FB_METRONOME is not set
 # CONFIG_FB_MB862XX is not set
 # CONFIG_FB_BROADSHEET is not set
-# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+CONFIG_LCD_CLASS_DEVICE=y
+# CONFIG_LCD_LMS283GF05 is not set
+# CONFIG_LCD_LTV350QV is not set
+# CONFIG_LCD_ILI9320 is not set
+CONFIG_LCD_TDO24M=y
+# CONFIG_LCD_VGG2432A4 is not set
+# CONFIG_LCD_PLATFORM is not set
+CONFIG_BACKLIGHT_CLASS_DEVICE=m
+# CONFIG_BACKLIGHT_GENERIC is not set
+CONFIG_BACKLIGHT_DA903X=m
 
 #
 # Display device support
@@ -956,38 +1048,48 @@ CONFIG_LOGO_LINUX_MONO=y
 CONFIG_LOGO_LINUX_VGA16=y
 CONFIG_LOGO_LINUX_CLUT224=y
 CONFIG_SOUND=m
-# CONFIG_SOUND_OSS_CORE is not set
+CONFIG_SOUND_OSS_CORE=y
+CONFIG_SOUND_OSS_CORE_PRECLAIM=y
 CONFIG_SND=m
 CONFIG_SND_TIMER=m
 CONFIG_SND_PCM=m
 CONFIG_SND_JACK=y
 # CONFIG_SND_SEQUENCER is not set
-# CONFIG_SND_MIXER_OSS is not set
-# CONFIG_SND_PCM_OSS is not set
+CONFIG_SND_OSSEMUL=y
+CONFIG_SND_MIXER_OSS=m
+CONFIG_SND_PCM_OSS=m
+CONFIG_SND_PCM_OSS_PLUGINS=y
 # CONFIG_SND_DYNAMIC_MINORS is not set
 CONFIG_SND_SUPPORT_OLD_API=y
 CONFIG_SND_VERBOSE_PROCFS=y
 # CONFIG_SND_VERBOSE_PRINTK is not set
 # CONFIG_SND_DEBUG is not set
-CONFIG_SND_DRIVERS=y
-# CONFIG_SND_DUMMY is not set
-# CONFIG_SND_MTPAV is not set
-# CONFIG_SND_SERIAL_U16550 is not set
-# CONFIG_SND_MPU401 is not set
+CONFIG_SND_VMASTER=y
+# CONFIG_SND_RAWMIDI_SEQ is not set
+# CONFIG_SND_OPL3_LIB_SEQ is not set
+# CONFIG_SND_OPL4_LIB_SEQ is not set
+# CONFIG_SND_SBAWE_SEQ is not set
+# CONFIG_SND_EMU10K1_SEQ is not set
+CONFIG_SND_AC97_CODEC=m
+# CONFIG_SND_DRIVERS is not set
 CONFIG_SND_ARM=y
 CONFIG_SND_PXA2XX_LIB=m
+CONFIG_SND_PXA2XX_LIB_AC97=y
 # CONFIG_SND_PXA2XX_AC97 is not set
-CONFIG_SND_USB=y
-# CONFIG_SND_USB_AUDIO is not set
-# CONFIG_SND_USB_CAIAQ is not set
+# CONFIG_SND_SPI is not set
+# CONFIG_SND_USB is not set
 CONFIG_SND_SOC=m
+CONFIG_SND_SOC_AC97_BUS=y
 CONFIG_SND_PXA2XX_SOC=m
+CONFIG_SND_PXA2XX_SOC_AC97=m
+CONFIG_SND_PXA2XX_SOC_EM_X270=m
 CONFIG_SND_SOC_I2C_AND_SPI=m
 # CONFIG_SND_SOC_ALL_CODECS is not set
+CONFIG_SND_SOC_WM9712=m
 # CONFIG_SOUND_PRIME is not set
+CONFIG_AC97_BUS=m
 CONFIG_HID_SUPPORT=y
 CONFIG_HID=y
-CONFIG_HID_DEBUG=y
 # CONFIG_HIDRAW is not set
 
 #
@@ -1006,10 +1108,12 @@ CONFIG_HID_BELKIN=y
 CONFIG_HID_CHERRY=y
 CONFIG_HID_CHICONY=y
 CONFIG_HID_CYPRESS=y
+CONFIG_HID_DRAGONRISE=y
 # CONFIG_DRAGONRISE_FF is not set
 CONFIG_HID_EZKEY=y
 CONFIG_HID_KYE=y
 CONFIG_HID_GYRATION=y
+CONFIG_HID_TWINHAN=y
 CONFIG_HID_KENSINGTON=y
 CONFIG_HID_LOGITECH=y
 # CONFIG_LOGITECH_FF is not set
@@ -1023,9 +1127,15 @@ CONFIG_HID_PETALYNX=y
 CONFIG_HID_SAMSUNG=y
 CONFIG_HID_SONY=y
 CONFIG_HID_SUNPLUS=y
+CONFIG_HID_GREENASIA=y
 # CONFIG_GREENASIA_FF is not set
+CONFIG_HID_SMARTJOYPLUS=y
+# CONFIG_SMARTJOYPLUS_FF is not set
 CONFIG_HID_TOPSEED=y
+CONFIG_HID_THRUSTMASTER=y
 # CONFIG_THRUSTMASTER_FF is not set
+CONFIG_HID_WACOM=m
+CONFIG_HID_ZEROPLUS=y
 # CONFIG_ZEROPLUS_FF is not set
 CONFIG_USB_SUPPORT=y
 CONFIG_USB_ARCH_HAS_HCD=y
@@ -1054,6 +1164,7 @@ CONFIG_USB_MON=y
 # CONFIG_USB_OXU210HP_HCD is not set
 # CONFIG_USB_ISP116X_HCD is not set
 # CONFIG_USB_ISP1760_HCD is not set
+# CONFIG_USB_ISP1362_HCD is not set
 CONFIG_USB_OHCI_HCD=y
 # CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set
 # CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set
@@ -1151,8 +1262,9 @@ CONFIG_MMC_BLOCK_BOUNCE=y
 #
 CONFIG_MMC_PXA=m
 # CONFIG_MMC_SDHCI is not set
+# CONFIG_MMC_AT91 is not set
+# CONFIG_MMC_ATMELMCI is not set
 # CONFIG_MEMSTICK is not set
-# CONFIG_ACCESSIBILITY is not set
 CONFIG_NEW_LEDS=y
 CONFIG_LEDS_CLASS=y
 
@@ -1162,8 +1274,10 @@ CONFIG_LEDS_CLASS=y
 # CONFIG_LEDS_PCA9532 is not set
 CONFIG_LEDS_GPIO=y
 CONFIG_LEDS_GPIO_PLATFORM=y
-# CONFIG_LEDS_LP5521 is not set
+# CONFIG_LEDS_LP3944 is not set
 # CONFIG_LEDS_PCA955X is not set
+# CONFIG_LEDS_DA903X is not set
+# CONFIG_LEDS_DAC124S085 is not set
 # CONFIG_LEDS_BD2802 is not set
 
 #
@@ -1179,6 +1293,7 @@ CONFIG_LEDS_TRIGGER_HEARTBEAT=y
 #
 # iptables trigger is under Netfilter config (LED target)
 #
+# CONFIG_ACCESSIBILITY is not set
 CONFIG_RTC_LIB=y
 CONFIG_RTC_CLASS=y
 CONFIG_RTC_HCTOSYS=y
@@ -1210,10 +1325,19 @@ CONFIG_RTC_INTF_DEV=y
 # CONFIG_RTC_DRV_S35390A is not set
 # CONFIG_RTC_DRV_FM3130 is not set
 # CONFIG_RTC_DRV_RX8581 is not set
+# CONFIG_RTC_DRV_RX8025 is not set
 
 #
 # SPI RTC drivers
 #
+# CONFIG_RTC_DRV_M41T94 is not set
+# CONFIG_RTC_DRV_DS1305 is not set
+# CONFIG_RTC_DRV_DS1390 is not set
+# CONFIG_RTC_DRV_MAX6902 is not set
+# CONFIG_RTC_DRV_R9701 is not set
+# CONFIG_RTC_DRV_RS5C348 is not set
+# CONFIG_RTC_DRV_DS3234 is not set
+# CONFIG_RTC_DRV_PCF2123 is not set
 
 #
 # Platform RTC drivers
@@ -1233,12 +1357,15 @@ CONFIG_RTC_DRV_V3020=y
 #
 # on-CPU RTC drivers
 #
-CONFIG_RTC_DRV_SA1100=y
-# CONFIG_RTC_DRV_PXA is not set
+# CONFIG_RTC_DRV_SA1100 is not set
+CONFIG_RTC_DRV_PXA=y
 # CONFIG_DMADEVICES is not set
 # CONFIG_AUXDISPLAY is not set
-# CONFIG_REGULATOR is not set
 # CONFIG_UIO is not set
+
+#
+# TI VLYNQ
+#
 # CONFIG_STAGING is not set
 
 #
@@ -1256,10 +1383,13 @@ CONFIG_JBD=y
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
 CONFIG_FS_POSIX_ACL=y
-CONFIG_FILE_LOCKING=y
 # CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
 # CONFIG_OCFS2_FS is not set
 # CONFIG_BTRFS_FS is not set
+# CONFIG_NILFS2_FS is not set
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
 CONFIG_DNOTIFY=y
 CONFIG_INOTIFY=y
 CONFIG_INOTIFY_USER=y
@@ -1319,6 +1449,12 @@ CONFIG_JFFS2_ZLIB=y
 # CONFIG_JFFS2_LZO is not set
 CONFIG_JFFS2_RTIME=y
 # CONFIG_JFFS2_RUBIN is not set
+CONFIG_UBIFS_FS=y
+# CONFIG_UBIFS_FS_XATTR is not set
+# CONFIG_UBIFS_FS_ADVANCED_COMPR is not set
+CONFIG_UBIFS_FS_LZO=y
+CONFIG_UBIFS_FS_ZLIB=y
+# CONFIG_UBIFS_FS_DEBUG is not set
 # CONFIG_CRAMFS is not set
 # CONFIG_SQUASHFS is not set
 # CONFIG_VXFS_FS is not set
@@ -1329,12 +1465,12 @@ CONFIG_JFFS2_RTIME=y
 # CONFIG_ROMFS_FS is not set
 # CONFIG_SYSV_FS is not set
 # CONFIG_UFS_FS is not set
-# CONFIG_NILFS2_FS is not set
 CONFIG_NETWORK_FILESYSTEMS=y
 CONFIG_NFS_FS=y
 CONFIG_NFS_V3=y
 CONFIG_NFS_V3_ACL=y
 CONFIG_NFS_V4=y
+# CONFIG_NFS_V4_1 is not set
 CONFIG_ROOT_NFS=y
 # CONFIG_NFSD is not set
 CONFIG_LOCKD=y
@@ -1378,7 +1514,7 @@ CONFIG_MSDOS_PARTITION=y
 # CONFIG_KARMA_PARTITION is not set
 # CONFIG_EFI_PARTITION is not set
 # CONFIG_SYSV68_PARTITION is not set
-CONFIG_NLS=m
+CONFIG_NLS=y
 CONFIG_NLS_DEFAULT="iso8859-1"
 CONFIG_NLS_CODEPAGE_437=m
 # CONFIG_NLS_CODEPAGE_737 is not set
@@ -1428,6 +1564,7 @@ CONFIG_ENABLE_WARN_DEPRECATED=y
 CONFIG_ENABLE_MUST_CHECK=y
 CONFIG_FRAME_WARN=1024
 # CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_STRIP_ASM_SYMS is not set
 # CONFIG_UNUSED_SYMBOLS is not set
 CONFIG_DEBUG_FS=y
 # CONFIG_HEADERS_CHECK is not set
@@ -1441,6 +1578,7 @@ CONFIG_DEBUG_KERNEL=y
 # CONFIG_DEBUG_OBJECTS is not set
 # CONFIG_SLUB_DEBUG_ON is not set
 # CONFIG_SLUB_STATS is not set
+# CONFIG_DEBUG_KMEMLEAK is not set
 # CONFIG_DEBUG_RT_MUTEXES is not set
 # CONFIG_RT_MUTEX_TESTER is not set
 # CONFIG_DEBUG_SPINLOCK is not set
@@ -1460,32 +1598,20 @@ CONFIG_DEBUG_MEMORY_INIT=y
 # CONFIG_DEBUG_LIST is not set
 # CONFIG_DEBUG_SG is not set
 # CONFIG_DEBUG_NOTIFIERS is not set
+# CONFIG_DEBUG_CREDENTIALS is not set
 # CONFIG_BOOT_PRINTK_DELAY is not set
 # CONFIG_RCU_TORTURE_TEST is not set
 # CONFIG_RCU_CPU_STALL_DETECTOR is not set
 # CONFIG_BACKTRACE_SELF_TEST is not set
 # CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
+# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
 # CONFIG_FAULT_INJECTION is not set
 # CONFIG_LATENCYTOP is not set
 CONFIG_SYSCTL_SYSCALL_CHECK=y
 # CONFIG_PAGE_POISONING is not set
 CONFIG_HAVE_FUNCTION_TRACER=y
 CONFIG_TRACING_SUPPORT=y
-
-#
-# Tracers
-#
-# CONFIG_FUNCTION_TRACER is not set
-# CONFIG_IRQSOFF_TRACER is not set
-# CONFIG_SCHED_TRACER is not set
-# CONFIG_CONTEXT_SWITCH_TRACER is not set
-# CONFIG_EVENT_TRACER is not set
-# CONFIG_BOOT_TRACER is not set
-# CONFIG_TRACE_BRANCH_PROFILING is not set
-# CONFIG_STACK_TRACER is not set
-# CONFIG_KMEMTRACE is not set
-# CONFIG_WORKQUEUE_TRACER is not set
-# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_FTRACE is not set
 # CONFIG_DYNAMIC_DEBUG is not set
 # CONFIG_SAMPLES is not set
 CONFIG_HAVE_ARCH_KGDB=y
@@ -1509,7 +1635,6 @@ CONFIG_CRYPTO=y
 #
 # Crypto core or helper
 #
-# CONFIG_CRYPTO_FIPS is not set
 CONFIG_CRYPTO_ALGAPI=y
 CONFIG_CRYPTO_ALGAPI2=y
 CONFIG_CRYPTO_AEAD2=y
@@ -1551,11 +1676,13 @@ CONFIG_CRYPTO_ECB=m
 #
 # CONFIG_CRYPTO_HMAC is not set
 # CONFIG_CRYPTO_XCBC is not set
+# CONFIG_CRYPTO_VMAC is not set
 
 #
 # Digest
 #
 # CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_GHASH is not set
 # CONFIG_CRYPTO_MD4 is not set
 CONFIG_CRYPTO_MD5=y
 CONFIG_CRYPTO_MICHAEL_MIC=m
@@ -1591,9 +1718,9 @@ CONFIG_CRYPTO_DES=y
 #
 # Compression
 #
-# CONFIG_CRYPTO_DEFLATE is not set
+CONFIG_CRYPTO_DEFLATE=y
 # CONFIG_CRYPTO_ZLIB is not set
-# CONFIG_CRYPTO_LZO is not set
+CONFIG_CRYPTO_LZO=y
 
 #
 # Random Number Generation
@@ -1608,7 +1735,7 @@ CONFIG_CRYPTO_DES=y
 CONFIG_BITREVERSE=y
 CONFIG_GENERIC_FIND_LAST_BIT=y
 # CONFIG_CRC_CCITT is not set
-# CONFIG_CRC16 is not set
+CONFIG_CRC16=y
 CONFIG_CRC_T10DIF=y
 # CONFIG_CRC_ITU_T is not set
 CONFIG_CRC32=y
@@ -1616,6 +1743,8 @@ CONFIG_CRC32=y
 # CONFIG_LIBCRC32C is not set
 CONFIG_ZLIB_INFLATE=y
 CONFIG_ZLIB_DEFLATE=y
+CONFIG_LZO_COMPRESS=y
+CONFIG_LZO_DECOMPRESS=y
 CONFIG_DECOMPRESS_GZIP=y
 CONFIG_DECOMPRESS_BZIP2=y
 CONFIG_DECOMPRESS_LZMA=y
diff --git a/arch/arm/configs/dove_defconfig b/arch/arm/configs/dove_defconfig
new file mode 100644 (file)
index 0000000..b3a4916
--- /dev/null
@@ -0,0 +1,1620 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.32-rc6
+# Tue Nov 24 13:53:37 2009
+#
+CONFIG_ARM=y
+CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+CONFIG_GENERIC_GPIO=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
+CONFIG_VECTORS_BASE=0xffff0000
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_AUDIT is not set
+
+#
+# RCU Subsystem
+#
+CONFIG_TREE_RCU=y
+# CONFIG_TREE_PREEMPT_RCU is not set
+# CONFIG_RCU_TRACE is not set
+CONFIG_RCU_FANOUT=32
+# CONFIG_RCU_FANOUT_EXACT is not set
+# CONFIG_TREE_RCU_TRACE is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_GROUP_SCHED is not set
+# CONFIG_CGROUPS is not set
+# CONFIG_SYSFS_DEPRECATED_V2 is not set
+# CONFIG_RELAY is not set
+# CONFIG_NAMESPACES is not set
+# CONFIG_BLK_DEV_INITRD is not set
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+CONFIG_ANON_INODES=y
+CONFIG_EMBEDDED=y
+CONFIG_UID16=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_AIO=y
+
+#
+# Kernel Performance Events And Counters
+#
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_PCI_QUIRKS=y
+CONFIG_COMPAT_BRK=y
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
+# CONFIG_PROFILING is not set
+CONFIG_HAVE_OPROFILE=y
+# CONFIG_KPROBES is not set
+CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_KRETPROBES=y
+
+#
+# GCOV-based kernel profiling
+#
+# CONFIG_GCOV_KERNEL is not set
+# CONFIG_SLOW_WORK is not set
+CONFIG_HAVE_GENERIC_DMA_COHERENT=y
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+# CONFIG_MODULE_FORCE_LOAD is not set
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_BLOCK=y
+CONFIG_LBDAF=y
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_BLK_DEV_INTEGRITY is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_DEFAULT_AS is not set
+# CONFIG_DEFAULT_DEADLINE is not set
+CONFIG_DEFAULT_CFQ=y
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="cfq"
+# CONFIG_FREEZER is not set
+
+#
+# System Type
+#
+CONFIG_MMU=y
+# CONFIG_ARCH_AAEC2000 is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_REALVIEW is not set
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_AT91 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_GEMINI is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_EP93XX is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_MXC is not set
+# CONFIG_ARCH_STMP3XXX is not set
+# CONFIG_ARCH_NETX is not set
+# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_NOMADIK is not set
+# CONFIG_ARCH_IOP13XX is not set
+# CONFIG_ARCH_IOP32X is not set
+# CONFIG_ARCH_IOP33X is not set
+# CONFIG_ARCH_IXP23XX is not set
+# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_L7200 is not set
+CONFIG_ARCH_DOVE=y
+# CONFIG_ARCH_KIRKWOOD is not set
+# CONFIG_ARCH_LOKI is not set
+# CONFIG_ARCH_MV78XX0 is not set
+# CONFIG_ARCH_ORION5X is not set
+# CONFIG_ARCH_MMP is not set
+# CONFIG_ARCH_KS8695 is not set
+# CONFIG_ARCH_NS9XXX is not set
+# CONFIG_ARCH_W90X900 is not set
+# CONFIG_ARCH_PNX4008 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_MSM is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_S3C64XX is not set
+# CONFIG_ARCH_S5PC1XX is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_U300 is not set
+# CONFIG_ARCH_DAVINCI is not set
+# CONFIG_ARCH_OMAP is not set
+# CONFIG_ARCH_BCMRING is not set
+
+#
+# Marvell Dove Implementations
+#
+CONFIG_MACH_DOVE_DB=y
+CONFIG_PLAT_ORION=y
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_V6=y
+CONFIG_CPU_32v6K=y
+CONFIG_CPU_32v6=y
+CONFIG_CPU_ABRT_EV6=y
+CONFIG_CPU_PABRT_V6=y
+CONFIG_CPU_CACHE_V6=y
+CONFIG_CPU_CACHE_VIPT=y
+CONFIG_CPU_COPY_V6=y
+CONFIG_CPU_TLB_V6=y
+CONFIG_CPU_HAS_ASID=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
+
+#
+# Processor Features
+#
+CONFIG_ARM_THUMB=y
+# CONFIG_CPU_ICACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_DISABLE is not set
+# CONFIG_CPU_BPREDICT_DISABLE is not set
+CONFIG_OUTER_CACHE=y
+CONFIG_CACHE_TAUROS2=y
+CONFIG_ARM_L1_CACHE_SHIFT=5
+# CONFIG_ARM_ERRATA_411920 is not set
+
+#
+# Bus support
+#
+CONFIG_PCI=y
+CONFIG_PCI_SYSCALL=y
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+CONFIG_PCI_LEGACY=y
+# CONFIG_PCI_DEBUG is not set
+# CONFIG_PCI_STUB is not set
+# CONFIG_PCI_IOV is not set
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+CONFIG_TICK_ONESHOT=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+CONFIG_VMSPLIT_3G=y
+# CONFIG_VMSPLIT_2G is not set
+# CONFIG_VMSPLIT_1G is not set
+CONFIG_PAGE_OFFSET=0xC0000000
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+CONFIG_HZ=100
+CONFIG_AEABI=y
+CONFIG_OABI_COMPAT=y
+# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set
+# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set
+# CONFIG_HIGHMEM is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+CONFIG_PAGEFLAGS_EXTENDED=y
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_PHYS_ADDR_T_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=0
+CONFIG_VIRT_TO_BUS=y
+CONFIG_HAVE_MLOCK=y
+CONFIG_HAVE_MLOCKED_PAGE_BIT=y
+# CONFIG_KSM is not set
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
+CONFIG_ALIGNMENT_TRAP=y
+# CONFIG_UACCESS_WITH_MEMCPY is not set
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE=""
+# CONFIG_XIP_KERNEL is not set
+# CONFIG_KEXEC is not set
+
+#
+# CPU Power Management
+#
+# CONFIG_CPU_IDLE is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+# CONFIG_FPE_NWFPE is not set
+# CONFIG_FPE_FASTFPE is not set
+CONFIG_VFP=y
+
+#
+# Userspace binary formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_HAVE_AOUT=y
+# CONFIG_BINFMT_AOUT is not set
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Power management options
+#
+# CONFIG_PM is not set
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+CONFIG_PACKET_MMAP=y
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_MIGRATE is not set
+# CONFIG_XFRM_STATISTICS is not set
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
+CONFIG_INET_LRO=y
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# CONFIG_RDS is not set
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_NET_DSA is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_PHONET is not set
+# CONFIG_IEEE802154 is not set
+# CONFIG_NET_SCHED is not set
+# CONFIG_DCB is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_CAN is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+# CONFIG_WIRELESS is not set
+# CONFIG_WIMAX is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+# CONFIG_DEVTMPFS is not set
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=y
+CONFIG_FIRMWARE_IN_KERNEL=y
+CONFIG_EXTRA_FIRMWARE=""
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES is not set
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_CONNECTOR is not set
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_TESTS is not set
+# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+# CONFIG_MTD_AFS_PARTS is not set
+# CONFIG_MTD_AR7_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+# CONFIG_MTD_OOPS is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+CONFIG_MTD_JEDECPROBE=y
+CONFIG_MTD_GEN_PROBE=y
+CONFIG_MTD_CFI_ADV_OPTIONS=y
+CONFIG_MTD_CFI_NOSWAP=y
+# CONFIG_MTD_CFI_BE_BYTE_SWAP is not set
+# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set
+CONFIG_MTD_CFI_GEOMETRY=y
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+# CONFIG_MTD_MAP_BANK_WIDTH_4 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_OTP is not set
+CONFIG_MTD_CFI_INTELEXT=y
+# CONFIG_MTD_CFI_AMDSTD is not set
+CONFIG_MTD_CFI_STAA=y
+CONFIG_MTD_CFI_UTIL=y
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+CONFIG_MTD_PHYSMAP=y
+# CONFIG_MTD_PHYSMAP_COMPAT is not set
+# CONFIG_MTD_ARM_INTEGRATOR is not set
+# CONFIG_MTD_IMPA7 is not set
+# CONFIG_MTD_INTEL_VR_NOR is not set
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_PMC551 is not set
+# CONFIG_MTD_DATAFLASH is not set
+CONFIG_MTD_M25P80=y
+CONFIG_M25PXX_USE_FAST_READ=y
+# CONFIG_MTD_SST25L is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+# CONFIG_MTD_NAND is not set
+# CONFIG_MTD_ONENAND is not set
+
+#
+# LPDDR flash memory drivers
+#
+# CONFIG_MTD_LPDDR is not set
+
+#
+# UBI - Unsorted block images
+#
+CONFIG_MTD_UBI=y
+CONFIG_MTD_UBI_WL_THRESHOLD=4096
+CONFIG_MTD_UBI_BEB_RESERVE=1
+# CONFIG_MTD_UBI_GLUEBI is not set
+
+#
+# UBI debugging options
+#
+# CONFIG_MTD_UBI_DEBUG is not set
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_SX8 is not set
+# CONFIG_BLK_DEV_UB is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=1
+CONFIG_BLK_DEV_RAM_SIZE=4096
+# CONFIG_BLK_DEV_XIP is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+# CONFIG_MG_DISK is not set
+# CONFIG_MISC_DEVICES is not set
+CONFIG_HAVE_IDE=y
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=y
+CONFIG_SCSI_DMA=y
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
+# CONFIG_SCSI_PROC_FS is not set
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+# CONFIG_BLK_DEV_SR is not set
+# CONFIG_CHR_DEV_SG is not set
+# CONFIG_CHR_DEV_SCH is not set
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC is not set
+CONFIG_SCSI_WAIT_SCAN=m
+
+#
+# SCSI Transports
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+# CONFIG_SCSI_SRP_ATTRS is not set
+# CONFIG_SCSI_LOWLEVEL is not set
+# CONFIG_SCSI_DH is not set
+# CONFIG_SCSI_OSD_INITIATOR is not set
+CONFIG_ATA=y
+# CONFIG_ATA_NONSTANDARD is not set
+CONFIG_ATA_VERBOSE_ERROR=y
+CONFIG_SATA_PMP=y
+# CONFIG_SATA_AHCI is not set
+# CONFIG_SATA_SIL24 is not set
+CONFIG_ATA_SFF=y
+# CONFIG_SATA_SVW is not set
+# CONFIG_ATA_PIIX is not set
+CONFIG_SATA_MV=y
+# CONFIG_SATA_NV is not set
+# CONFIG_PDC_ADMA is not set
+# CONFIG_SATA_QSTOR is not set
+# CONFIG_SATA_PROMISE is not set
+# CONFIG_SATA_SX4 is not set
+# CONFIG_SATA_SIL is not set
+# CONFIG_SATA_SIS is not set
+# CONFIG_SATA_ULI is not set
+# CONFIG_SATA_VIA is not set
+# CONFIG_SATA_VITESSE is not set
+# CONFIG_SATA_INIC162X is not set
+# CONFIG_PATA_ALI is not set
+# CONFIG_PATA_AMD is not set
+# CONFIG_PATA_ARTOP is not set
+# CONFIG_PATA_ATP867X is not set
+# CONFIG_PATA_ATIIXP is not set
+# CONFIG_PATA_CMD640_PCI is not set
+# CONFIG_PATA_CMD64X is not set
+# CONFIG_PATA_CS5520 is not set
+# CONFIG_PATA_CS5530 is not set
+# CONFIG_PATA_CYPRESS is not set
+# CONFIG_PATA_EFAR is not set
+# CONFIG_ATA_GENERIC is not set
+# CONFIG_PATA_HPT366 is not set
+# CONFIG_PATA_HPT37X is not set
+# CONFIG_PATA_HPT3X2N is not set
+# CONFIG_PATA_HPT3X3 is not set
+# CONFIG_PATA_IT821X is not set
+# CONFIG_PATA_IT8213 is not set
+# CONFIG_PATA_JMICRON is not set
+# CONFIG_PATA_TRIFLEX is not set
+# CONFIG_PATA_MARVELL is not set
+# CONFIG_PATA_MPIIX is not set
+# CONFIG_PATA_OLDPIIX is not set
+# CONFIG_PATA_NETCELL is not set
+# CONFIG_PATA_NINJA32 is not set
+# CONFIG_PATA_NS87410 is not set
+# CONFIG_PATA_NS87415 is not set
+# CONFIG_PATA_OPTI is not set
+# CONFIG_PATA_OPTIDMA is not set
+# CONFIG_PATA_PDC_OLD is not set
+# CONFIG_PATA_RADISYS is not set
+# CONFIG_PATA_RDC is not set
+# CONFIG_PATA_RZ1000 is not set
+# CONFIG_PATA_SC1200 is not set
+# CONFIG_PATA_SERVERWORKS is not set
+# CONFIG_PATA_PDC2027X is not set
+# CONFIG_PATA_SIL680 is not set
+# CONFIG_PATA_SIS is not set
+# CONFIG_PATA_VIA is not set
+# CONFIG_PATA_WINBOND is not set
+# CONFIG_PATA_PLATFORM is not set
+# CONFIG_PATA_SCH is not set
+# CONFIG_MD is not set
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+
+#
+# You can enable one or both FireWire driver stacks.
+#
+
+#
+# See the help texts for more information.
+#
+# CONFIG_FIREWIRE is not set
+# CONFIG_IEEE1394 is not set
+# CONFIG_I2O is not set
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_VETH is not set
+# CONFIG_ARCNET is not set
+CONFIG_PHYLIB=y
+
+#
+# MII PHY device drivers
+#
+# CONFIG_MARVELL_PHY is not set
+# CONFIG_DAVICOM_PHY is not set
+# CONFIG_QSEMI_PHY is not set
+# CONFIG_LXT_PHY is not set
+# CONFIG_CICADA_PHY is not set
+# CONFIG_VITESSE_PHY is not set
+# CONFIG_SMSC_PHY is not set
+# CONFIG_BROADCOM_PHY is not set
+# CONFIG_ICPLUS_PHY is not set
+# CONFIG_REALTEK_PHY is not set
+# CONFIG_NATIONAL_PHY is not set
+# CONFIG_STE10XP is not set
+# CONFIG_LSI_ET1011C_PHY is not set
+# CONFIG_FIXED_PHY is not set
+# CONFIG_MDIO_BITBANG is not set
+# CONFIG_NET_ETHERNET is not set
+CONFIG_NETDEV_1000=y
+# CONFIG_ACENIC is not set
+# CONFIG_DL2K is not set
+# CONFIG_E1000 is not set
+# CONFIG_E1000E is not set
+# CONFIG_IP1000 is not set
+# CONFIG_IGB is not set
+# CONFIG_IGBVF is not set
+# CONFIG_NS83820 is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
+# CONFIG_R8169 is not set
+# CONFIG_SIS190 is not set
+# CONFIG_SKGE is not set
+# CONFIG_SKY2 is not set
+# CONFIG_VIA_VELOCITY is not set
+# CONFIG_TIGON3 is not set
+# CONFIG_BNX2 is not set
+# CONFIG_CNIC is not set
+CONFIG_MV643XX_ETH=y
+# CONFIG_QLA3XXX is not set
+# CONFIG_ATL1 is not set
+# CONFIG_ATL1E is not set
+# CONFIG_ATL1C is not set
+# CONFIG_JME is not set
+# CONFIG_NETDEV_10000 is not set
+# CONFIG_TR is not set
+CONFIG_WLAN=y
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
+
+#
+# Enable WiMAX (Networking options) to see the WiMAX drivers
+#
+
+#
+# USB Network Adapters
+#
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RTL8150 is not set
+# CONFIG_USB_USBNET is not set
+# CONFIG_WAN is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_NET_FC is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_ISDN is not set
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+CONFIG_INPUT_POLLDEV=y
+
+#
+# Userland interfaces
+#
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+# CONFIG_KEYBOARD_ADP5588 is not set
+# CONFIG_KEYBOARD_ATKBD is not set
+# CONFIG_QT2160 is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_GPIO is not set
+# CONFIG_KEYBOARD_MATRIX is not set
+# CONFIG_KEYBOARD_MAX7359 is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+# CONFIG_KEYBOARD_OPENCORES is not set
+# CONFIG_KEYBOARD_STOWAWAY is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+CONFIG_INPUT_MOUSE=y
+# CONFIG_MOUSE_PS2 is not set
+# CONFIG_MOUSE_SERIAL is not set
+# CONFIG_MOUSE_APPLETOUCH is not set
+# CONFIG_MOUSE_BCM5974 is not set
+# CONFIG_MOUSE_VSXXXAA is not set
+# CONFIG_MOUSE_GPIO is not set
+# CONFIG_MOUSE_SYNAPTICS_I2C is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_CONSOLE_TRANSLATIONS=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
+# CONFIG_DEVKMEM is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+# CONFIG_NOZOMI is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+# CONFIG_SERIAL_8250_PCI is not set
+CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=2
+# CONFIG_SERIAL_8250_EXTENDED is not set
+
+#
+# Non-8250 serial port support
+#
+# CONFIG_SERIAL_MAX3100 is not set
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_JSM is not set
+CONFIG_UNIX98_PTYS=y
+# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=16
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_HW_RANDOM is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+CONFIG_DEVPORT=y
+CONFIG_I2C=y
+CONFIG_I2C_BOARDINFO=y
+CONFIG_I2C_COMPAT=y
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_HELPER_AUTO=y
+
+#
+# I2C Hardware Bus support
+#
+
+#
+# PC SMBus host controller drivers
+#
+# CONFIG_I2C_ALI1535 is not set
+# CONFIG_I2C_ALI1563 is not set
+# CONFIG_I2C_ALI15X3 is not set
+# CONFIG_I2C_AMD756 is not set
+# CONFIG_I2C_AMD8111 is not set
+# CONFIG_I2C_I801 is not set
+# CONFIG_I2C_ISCH is not set
+# CONFIG_I2C_PIIX4 is not set
+# CONFIG_I2C_NFORCE2 is not set
+# CONFIG_I2C_SIS5595 is not set
+# CONFIG_I2C_SIS630 is not set
+# CONFIG_I2C_SIS96X is not set
+# CONFIG_I2C_VIA is not set
+# CONFIG_I2C_VIAPRO is not set
+
+#
+# I2C system bus drivers (mostly embedded / system-on-chip)
+#
+# CONFIG_I2C_GPIO is not set
+CONFIG_I2C_MV64XXX=y
+# CONFIG_I2C_OCORES is not set
+# CONFIG_I2C_SIMTEC is not set
+
+#
+# External I2C/SMBus adapter drivers
+#
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_TAOS_EVM is not set
+# CONFIG_I2C_TINY_USB is not set
+
+#
+# Graphics adapter I2C/DDC channel drivers
+#
+# CONFIG_I2C_VOODOO3 is not set
+
+#
+# Other I2C/SMBus bus drivers
+#
+# CONFIG_I2C_PCA_PLATFORM is not set
+# CONFIG_I2C_STUB is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_DS1682 is not set
+# CONFIG_SENSORS_TSL2550 is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+CONFIG_SPI=y
+# CONFIG_SPI_DEBUG is not set
+CONFIG_SPI_MASTER=y
+
+#
+# SPI Master Controller Drivers
+#
+# CONFIG_SPI_BITBANG is not set
+# CONFIG_SPI_GPIO is not set
+CONFIG_SPI_ORION=y
+
+#
+# SPI Protocol Masters
+#
+# CONFIG_SPI_SPIDEV is not set
+# CONFIG_SPI_TLE62X0 is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
+CONFIG_ARCH_REQUIRE_GPIOLIB=y
+CONFIG_GPIOLIB=y
+# CONFIG_DEBUG_GPIO is not set
+# CONFIG_GPIO_SYSFS is not set
+
+#
+# Memory mapped GPIO expanders:
+#
+
+#
+# I2C GPIO expanders:
+#
+# CONFIG_GPIO_MAX732X is not set
+# CONFIG_GPIO_PCA953X is not set
+# CONFIG_GPIO_PCF857X is not set
+
+#
+# PCI GPIO expanders:
+#
+# CONFIG_GPIO_BT8XX is not set
+# CONFIG_GPIO_LANGWELL is not set
+
+#
+# SPI GPIO expanders:
+#
+# CONFIG_GPIO_MAX7301 is not set
+# CONFIG_GPIO_MCP23S08 is not set
+# CONFIG_GPIO_MC33880 is not set
+
+#
+# AC97 GPIO expanders:
+#
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+# CONFIG_HWMON is not set
+# CONFIG_THERMAL is not set
+# CONFIG_WATCHDOG is not set
+CONFIG_SSB_POSSIBLE=y
+
+#
+# Sonics Silicon Backplane
+#
+# CONFIG_SSB is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_CORE is not set
+# CONFIG_MFD_SM501 is not set
+# CONFIG_MFD_ASIC3 is not set
+# CONFIG_HTC_EGPIO is not set
+# CONFIG_HTC_PASIC3 is not set
+# CONFIG_TPS65010 is not set
+# CONFIG_TWL4030_CORE is not set
+# CONFIG_MFD_TMIO is not set
+# CONFIG_MFD_TC6393XB is not set
+# CONFIG_PMIC_DA903X is not set
+# CONFIG_MFD_WM8400 is not set
+# CONFIG_MFD_WM831X is not set
+# CONFIG_MFD_WM8350_I2C is not set
+# CONFIG_MFD_PCF50633 is not set
+# CONFIG_MFD_MC13783 is not set
+# CONFIG_AB3100_CORE is not set
+# CONFIG_EZX_PCAP is not set
+# CONFIG_REGULATOR is not set
+# CONFIG_MEDIA_SUPPORT is not set
+
+#
+# Graphics support
+#
+CONFIG_VGA_ARB=y
+# CONFIG_DRM is not set
+# CONFIG_VGASTATE is not set
+# CONFIG_VIDEO_OUTPUT_CONTROL is not set
+# CONFIG_FB is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+# CONFIG_SOUND is not set
+CONFIG_HID_SUPPORT=y
+CONFIG_HID=y
+# CONFIG_HIDRAW is not set
+
+#
+# USB Input Devices
+#
+CONFIG_USB_HID=y
+# CONFIG_HID_PID is not set
+# CONFIG_USB_HIDDEV is not set
+
+#
+# Special HID drivers
+#
+# CONFIG_HID_A4TECH is not set
+# CONFIG_HID_APPLE is not set
+# CONFIG_HID_BELKIN is not set
+# CONFIG_HID_CHERRY is not set
+# CONFIG_HID_CHICONY is not set
+# CONFIG_HID_CYPRESS is not set
+# CONFIG_HID_DRAGONRISE is not set
+# CONFIG_HID_EZKEY is not set
+# CONFIG_HID_KYE is not set
+# CONFIG_HID_GYRATION is not set
+# CONFIG_HID_TWINHAN is not set
+# CONFIG_HID_KENSINGTON is not set
+# CONFIG_HID_LOGITECH is not set
+# CONFIG_HID_MICROSOFT is not set
+# CONFIG_HID_MONTEREY is not set
+# CONFIG_HID_NTRIG is not set
+# CONFIG_HID_PANTHERLORD is not set
+# CONFIG_HID_PETALYNX is not set
+# CONFIG_HID_SAMSUNG is not set
+# CONFIG_HID_SONY is not set
+# CONFIG_HID_SUNPLUS is not set
+# CONFIG_HID_GREENASIA is not set
+# CONFIG_HID_SMARTJOYPLUS is not set
+# CONFIG_HID_TOPSEED is not set
+# CONFIG_HID_THRUSTMASTER is not set
+# CONFIG_HID_ZEROPLUS is not set
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+CONFIG_USB_ARCH_HAS_EHCI=y
+CONFIG_USB=y
+# CONFIG_USB_DEBUG is not set
+# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+CONFIG_USB_DEVICE_CLASS=y
+# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_OTG is not set
+# CONFIG_USB_OTG_WHITELIST is not set
+# CONFIG_USB_OTG_BLACKLIST_HUB is not set
+# CONFIG_USB_MON is not set
+# CONFIG_USB_WUSB is not set
+# CONFIG_USB_WUSB_CBAF is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_C67X00_HCD is not set
+# CONFIG_USB_XHCI_HCD is not set
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_EHCI_ROOT_HUB_TT=y
+CONFIG_USB_EHCI_TT_NEWSCHED=y
+# CONFIG_USB_OXU210HP_HCD is not set
+# CONFIG_USB_ISP116X_HCD is not set
+# CONFIG_USB_ISP1760_HCD is not set
+# CONFIG_USB_ISP1362_HCD is not set
+# CONFIG_USB_OHCI_HCD is not set
+# CONFIG_USB_UHCI_HCD is not set
+# CONFIG_USB_SL811_HCD is not set
+# CONFIG_USB_R8A66597_HCD is not set
+# CONFIG_USB_WHCI_HCD is not set
+# CONFIG_USB_HWA_HCD is not set
+# CONFIG_USB_MUSB_HDRC is not set
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+# CONFIG_USB_WDM is not set
+# CONFIG_USB_TMC is not set
+
+#
+# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may
+#
+
+#
+# also be needed; see USB_STORAGE Help for more info
+#
+CONFIG_USB_STORAGE=y
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_ISD200 is not set
+# CONFIG_USB_STORAGE_USBAT is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_SDDR55 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_STORAGE_ALAUDA is not set
+# CONFIG_USB_STORAGE_ONETOUCH is not set
+# CONFIG_USB_STORAGE_KARMA is not set
+# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set
+# CONFIG_USB_LIBUSUAL is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+
+#
+# USB port drivers
+#
+# CONFIG_USB_SERIAL is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_ADUTUX is not set
+# CONFIG_USB_SEVSEG is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_BERRY_CHARGE is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYPRESS_CY7C63 is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_FTDI_ELAN is not set
+# CONFIG_USB_APPLEDISPLAY is not set
+# CONFIG_USB_SISUSBVGA is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
+# CONFIG_USB_IOWARRIOR is not set
+# CONFIG_USB_TEST is not set
+# CONFIG_USB_ISIGHTFW is not set
+# CONFIG_USB_VST is not set
+# CONFIG_USB_GADGET is not set
+
+#
+# OTG and related infrastructure
+#
+# CONFIG_USB_GPIO_VBUS is not set
+# CONFIG_NOP_USB_XCEIV is not set
+# CONFIG_UWB is not set
+# CONFIG_MMC is not set
+# CONFIG_MEMSTICK is not set
+# CONFIG_NEW_LEDS is not set
+# CONFIG_ACCESSIBILITY is not set
+# CONFIG_INFINIBAND is not set
+CONFIG_RTC_LIB=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_HCTOSYS=y
+CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
+# CONFIG_RTC_DEBUG is not set
+
+#
+# RTC interfaces
+#
+CONFIG_RTC_INTF_SYSFS=y
+CONFIG_RTC_INTF_PROC=y
+CONFIG_RTC_INTF_DEV=y
+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+# CONFIG_RTC_DRV_TEST is not set
+
+#
+# I2C RTC drivers
+#
+# CONFIG_RTC_DRV_DS1307 is not set
+# CONFIG_RTC_DRV_DS1374 is not set
+# CONFIG_RTC_DRV_DS1672 is not set
+# CONFIG_RTC_DRV_MAX6900 is not set
+# CONFIG_RTC_DRV_RS5C372 is not set
+# CONFIG_RTC_DRV_ISL1208 is not set
+# CONFIG_RTC_DRV_X1205 is not set
+# CONFIG_RTC_DRV_PCF8563 is not set
+# CONFIG_RTC_DRV_PCF8583 is not set
+# CONFIG_RTC_DRV_M41T80 is not set
+# CONFIG_RTC_DRV_S35390A is not set
+# CONFIG_RTC_DRV_FM3130 is not set
+# CONFIG_RTC_DRV_RX8581 is not set
+# CONFIG_RTC_DRV_RX8025 is not set
+
+#
+# SPI RTC drivers
+#
+# CONFIG_RTC_DRV_M41T94 is not set
+# CONFIG_RTC_DRV_DS1305 is not set
+# CONFIG_RTC_DRV_DS1390 is not set
+# CONFIG_RTC_DRV_MAX6902 is not set
+# CONFIG_RTC_DRV_R9701 is not set
+# CONFIG_RTC_DRV_RS5C348 is not set
+# CONFIG_RTC_DRV_DS3234 is not set
+# CONFIG_RTC_DRV_PCF2123 is not set
+
+#
+# Platform RTC drivers
+#
+# CONFIG_RTC_DRV_CMOS is not set
+# CONFIG_RTC_DRV_DS1286 is not set
+# CONFIG_RTC_DRV_DS1511 is not set
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+# CONFIG_RTC_DRV_STK17TA8 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_M48T35 is not set
+# CONFIG_RTC_DRV_M48T59 is not set
+# CONFIG_RTC_DRV_BQ4802 is not set
+# CONFIG_RTC_DRV_V3020 is not set
+
+#
+# on-CPU RTC drivers
+#
+CONFIG_RTC_DRV_MV=y
+CONFIG_DMADEVICES=y
+
+#
+# DMA Devices
+#
+CONFIG_MV_XOR=y
+CONFIG_DMA_ENGINE=y
+
+#
+# DMA Clients
+#
+# CONFIG_NET_DMA is not set
+# CONFIG_ASYNC_TX_DMA is not set
+# CONFIG_DMATEST is not set
+# CONFIG_AUXDISPLAY is not set
+# CONFIG_UIO is not set
+
+#
+# TI VLYNQ
+#
+# CONFIG_STAGING is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
+# CONFIG_EXT3_FS_XATTR is not set
+# CONFIG_EXT4_FS is not set
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_BTRFS_FS is not set
+# CONFIG_NILFS2_FS is not set
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
+CONFIG_DNOTIFY=y
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# Caches
+#
+# CONFIG_FSCACHE is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+CONFIG_ISO9660_FS=y
+CONFIG_JOLIET=y
+# CONFIG_ZISOFS is not set
+CONFIG_UDF_FS=m
+CONFIG_UDF_NLS=y
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLB_PAGE is not set
+# CONFIG_CONFIGFS_FS is not set
+CONFIG_MISC_FILESYSTEMS=y
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+# CONFIG_JFFS2_FS_WBUF_VERIFY is not set
+# CONFIG_JFFS2_SUMMARY is not set
+# CONFIG_JFFS2_FS_XATTR is not set
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+# CONFIG_JFFS2_LZO is not set
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
+# CONFIG_UBIFS_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_SQUASHFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_OMFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+CONFIG_NETWORK_FILESYSTEMS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+# CONFIG_NFS_V4 is not set
+CONFIG_ROOT_NFS=y
+# CONFIG_NFSD is not set
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_KARMA_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+# CONFIG_SYSV68_PARTITION is not set
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+CONFIG_NLS_CODEPAGE_850=y
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+CONFIG_NLS_ISO8859_1=y
+CONFIG_NLS_ISO8859_2=y
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+CONFIG_NLS_UTF8=y
+# CONFIG_DLM is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_WARN_DEPRECATED=y
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_FRAME_WARN=1024
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_STRIP_ASM_SYMS is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+CONFIG_DEBUG_FS=y
+# CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SHIRQ is not set
+CONFIG_DETECT_SOFTLOCKUP=y
+# CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set
+CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0
+CONFIG_DETECT_HUNG_TASK=y
+# CONFIG_BOOTPARAM_HUNG_TASK_PANIC is not set
+CONFIG_BOOTPARAM_HUNG_TASK_PANIC_VALUE=0
+# CONFIG_SCHED_DEBUG is not set
+# CONFIG_SCHEDSTATS is not set
+CONFIG_TIMER_STATS=y
+# CONFIG_DEBUG_OBJECTS is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_KMEMLEAK is not set
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_LOCK_STAT is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_DEBUG_KOBJECT is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+CONFIG_DEBUG_INFO=y
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_WRITECOUNT is not set
+# CONFIG_DEBUG_MEMORY_INIT is not set
+# CONFIG_DEBUG_LIST is not set
+# CONFIG_DEBUG_SG is not set
+# CONFIG_DEBUG_NOTIFIERS is not set
+# CONFIG_DEBUG_CREDENTIALS is not set
+# CONFIG_BOOT_PRINTK_DELAY is not set
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_RCU_CPU_STALL_DETECTOR is not set
+# CONFIG_BACKTRACE_SELF_TEST is not set
+# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
+# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
+# CONFIG_FAULT_INJECTION is not set
+# CONFIG_LATENCYTOP is not set
+CONFIG_SYSCTL_SYSCALL_CHECK=y
+# CONFIG_PAGE_POISONING is not set
+CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_TRACING_SUPPORT=y
+CONFIG_FTRACE=y
+# CONFIG_FUNCTION_TRACER is not set
+# CONFIG_IRQSOFF_TRACER is not set
+# CONFIG_SCHED_TRACER is not set
+# CONFIG_ENABLE_DEFAULT_TRACERS is not set
+# CONFIG_BOOT_TRACER is not set
+CONFIG_BRANCH_PROFILE_NONE=y
+# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set
+# CONFIG_PROFILE_ALL_BRANCHES is not set
+# CONFIG_STACK_TRACER is not set
+# CONFIG_KMEMTRACE is not set
+# CONFIG_WORKQUEUE_TRACER is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_DYNAMIC_DEBUG is not set
+# CONFIG_SAMPLES is not set
+CONFIG_HAVE_ARCH_KGDB=y
+# CONFIG_KGDB is not set
+CONFIG_ARM_UNWIND=y
+CONFIG_DEBUG_USER=y
+CONFIG_DEBUG_ERRORS=y
+# CONFIG_DEBUG_STACK_USAGE is not set
+# CONFIG_DEBUG_LL is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+# CONFIG_SECURITYFS is not set
+# CONFIG_SECURITY_FILE_CAPABILITIES is not set
+CONFIG_CRYPTO=y
+
+#
+# Crypto core or helper
+#
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_ALGAPI2=y
+CONFIG_CRYPTO_AEAD2=y
+CONFIG_CRYPTO_BLKCIPHER=y
+CONFIG_CRYPTO_BLKCIPHER2=y
+CONFIG_CRYPTO_HASH=y
+CONFIG_CRYPTO_HASH2=y
+CONFIG_CRYPTO_RNG2=y
+CONFIG_CRYPTO_PCOMP=y
+CONFIG_CRYPTO_MANAGER=y
+CONFIG_CRYPTO_MANAGER2=y
+# CONFIG_CRYPTO_GF128MUL is not set
+CONFIG_CRYPTO_NULL=y
+CONFIG_CRYPTO_WORKQUEUE=y
+# CONFIG_CRYPTO_CRYPTD is not set
+# CONFIG_CRYPTO_AUTHENC is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Authenticated Encryption with Associated Data
+#
+# CONFIG_CRYPTO_CCM is not set
+# CONFIG_CRYPTO_GCM is not set
+# CONFIG_CRYPTO_SEQIV is not set
+
+#
+# Block modes
+#
+CONFIG_CRYPTO_CBC=y
+# CONFIG_CRYPTO_CTR is not set
+# CONFIG_CRYPTO_CTS is not set
+CONFIG_CRYPTO_ECB=m
+# CONFIG_CRYPTO_LRW is not set
+CONFIG_CRYPTO_PCBC=m
+# CONFIG_CRYPTO_XTS is not set
+
+#
+# Hash modes
+#
+CONFIG_CRYPTO_HMAC=y
+# CONFIG_CRYPTO_XCBC is not set
+# CONFIG_CRYPTO_VMAC is not set
+
+#
+# Digest
+#
+CONFIG_CRYPTO_CRC32C=y
+# CONFIG_CRYPTO_GHASH is not set
+CONFIG_CRYPTO_MD4=y
+CONFIG_CRYPTO_MD5=y
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_RMD128 is not set
+# CONFIG_CRYPTO_RMD160 is not set
+# CONFIG_CRYPTO_RMD256 is not set
+# CONFIG_CRYPTO_RMD320 is not set
+CONFIG_CRYPTO_SHA1=y
+CONFIG_CRYPTO_SHA256=y
+CONFIG_CRYPTO_SHA512=y
+# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_WP512 is not set
+
+#
+# Ciphers
+#
+CONFIG_CRYPTO_AES=y
+# CONFIG_CRYPTO_ANUBIS is not set
+# CONFIG_CRYPTO_ARC4 is not set
+CONFIG_CRYPTO_BLOWFISH=y
+# CONFIG_CRYPTO_CAMELLIA is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+CONFIG_CRYPTO_DES=y
+# CONFIG_CRYPTO_FCRYPT is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_SALSA20 is not set
+# CONFIG_CRYPTO_SEED is not set
+# CONFIG_CRYPTO_SERPENT is not set
+CONFIG_CRYPTO_TEA=y
+CONFIG_CRYPTO_TWOFISH=y
+CONFIG_CRYPTO_TWOFISH_COMMON=y
+
+#
+# Compression
+#
+CONFIG_CRYPTO_DEFLATE=y
+# CONFIG_CRYPTO_ZLIB is not set
+CONFIG_CRYPTO_LZO=y
+
+#
+# Random Number Generation
+#
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
+CONFIG_CRYPTO_HW=y
+# CONFIG_CRYPTO_DEV_MV_CESA is not set
+# CONFIG_CRYPTO_DEV_HIFN_795X is not set
+# CONFIG_BINARY_PRINTF is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+CONFIG_GENERIC_FIND_LAST_BIT=y
+CONFIG_CRC_CCITT=y
+CONFIG_CRC16=y
+# CONFIG_CRC_T10DIF is not set
+CONFIG_CRC_ITU_T=m
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+CONFIG_LIBCRC32C=y
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_LZO_COMPRESS=y
+CONFIG_LZO_DECOMPRESS=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
+CONFIG_NLATTR=y
index d5ee16e..492f29a 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.26-rc3
-# Mon Jul  7 17:52:21 2008
+# Linux kernel version: 2.6.32-rc5
+# Mon Nov  2 13:18:50 2009
 #
 CONFIG_ARM=y
 CONFIG_HAVE_PWM=y
@@ -9,24 +9,22 @@ CONFIG_SYS_SUPPORTS_APM_EMULATION=y
 CONFIG_GENERIC_GPIO=y
 CONFIG_GENERIC_TIME=y
 CONFIG_GENERIC_CLOCKEVENTS=y
-CONFIG_MMU=y
-# CONFIG_NO_IOPORT is not set
 CONFIG_GENERIC_HARDIRQS=y
 CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_HAVE_LATENCYTOP_SUPPORT=y
 CONFIG_LOCKDEP_SUPPORT=y
 CONFIG_TRACE_IRQFLAGS_SUPPORT=y
 CONFIG_HARDIRQS_SW_RESEND=y
 CONFIG_GENERIC_IRQ_PROBE=y
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
-# CONFIG_ARCH_HAS_ILOG2_U32 is not set
-# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_ARCH_HAS_CPUFREQ=y
 CONFIG_GENERIC_HWEIGHT=y
 CONFIG_GENERIC_CALIBRATE_DELAY=y
-CONFIG_ARCH_SUPPORTS_AOUT=y
-CONFIG_ZONE_DMA=y
 CONFIG_ARCH_MTD_XIP=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
 CONFIG_VECTORS_BASE=0xffff0000
 CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
 
 #
 # General setup
@@ -35,7 +33,7 @@ CONFIG_EXPERIMENTAL=y
 CONFIG_BROKEN_ON_SMP=y
 CONFIG_LOCK_KERNEL=y
 CONFIG_INIT_ENV_ARG_LIMIT=32
-CONFIG_LOCALVERSION="-ezxdev"
+CONFIG_LOCALVERSION="-ezx200910312315"
 # CONFIG_LOCALVERSION_AUTO is not set
 CONFIG_SWAP=y
 CONFIG_SYSVIPC=y
@@ -44,56 +42,78 @@ CONFIG_SYSVIPC_SYSCTL=y
 # CONFIG_BSD_PROCESS_ACCT is not set
 # CONFIG_TASKSTATS is not set
 # CONFIG_AUDIT is not set
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
+
+#
+# RCU Subsystem
+#
+CONFIG_TREE_RCU=y
+# CONFIG_TREE_PREEMPT_RCU is not set
+# CONFIG_RCU_TRACE is not set
+CONFIG_RCU_FANOUT=32
+# CONFIG_RCU_FANOUT_EXACT is not set
+# CONFIG_TREE_RCU_TRACE is not set
+# CONFIG_IKCONFIG is not set
 CONFIG_LOG_BUF_SHIFT=14
-# CONFIG_CGROUPS is not set
 CONFIG_GROUP_SCHED=y
 CONFIG_FAIR_GROUP_SCHED=y
 # CONFIG_RT_GROUP_SCHED is not set
 CONFIG_USER_SCHED=y
 # CONFIG_CGROUP_SCHED is not set
+# CONFIG_CGROUPS is not set
 CONFIG_SYSFS_DEPRECATED=y
 CONFIG_SYSFS_DEPRECATED_V2=y
 # CONFIG_RELAY is not set
 # CONFIG_NAMESPACES is not set
-# CONFIG_BLK_DEV_INITRD is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_RD_GZIP=y
+CONFIG_RD_BZIP2=y
+CONFIG_RD_LZMA=y
 CONFIG_CC_OPTIMIZE_FOR_SIZE=y
 CONFIG_SYSCTL=y
+CONFIG_ANON_INODES=y
 CONFIG_EMBEDDED=y
 CONFIG_UID16=y
 CONFIG_SYSCTL_SYSCALL=y
-CONFIG_SYSCTL_SYSCALL_CHECK=y
 CONFIG_KALLSYMS=y
+CONFIG_KALLSYMS_ALL=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
 CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
 CONFIG_ELF_CORE=y
-# CONFIG_COMPAT_BRK is not set
 CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
-CONFIG_ANON_INODES=y
 CONFIG_EPOLL=y
 CONFIG_SIGNALFD=y
 CONFIG_TIMERFD=y
 CONFIG_EVENTFD=y
 CONFIG_SHMEM=y
+CONFIG_AIO=y
+
+#
+# Kernel Performance Events And Counters
+#
 CONFIG_VM_EVENT_COUNTERS=y
+# CONFIG_COMPAT_BRK is not set
 CONFIG_SLAB=y
 # CONFIG_SLUB is not set
 # CONFIG_SLOB is not set
 # CONFIG_PROFILING is not set
-# CONFIG_MARKERS is not set
 CONFIG_HAVE_OPROFILE=y
 # CONFIG_KPROBES is not set
 CONFIG_HAVE_KPROBES=y
 CONFIG_HAVE_KRETPROBES=y
-# CONFIG_HAVE_DMA_ATTRS is not set
-CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_HAVE_CLK=y
+
+#
+# GCOV-based kernel profiling
+#
+# CONFIG_GCOV_KERNEL is not set
+CONFIG_SLOW_WORK=y
+CONFIG_HAVE_GENERIC_DMA_COHERENT=y
 CONFIG_SLABINFO=y
 CONFIG_RT_MUTEXES=y
-# CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
 CONFIG_MODULES=y
 # CONFIG_MODULE_FORCE_LOAD is not set
@@ -101,12 +121,10 @@ CONFIG_MODULE_UNLOAD=y
 CONFIG_MODULE_FORCE_UNLOAD=y
 CONFIG_MODVERSIONS=y
 # CONFIG_MODULE_SRCVERSION_ALL is not set
-CONFIG_KMOD=y
 CONFIG_BLOCK=y
-# CONFIG_LBD is not set
-# CONFIG_BLK_DEV_IO_TRACE is not set
-# CONFIG_LSF is not set
+# CONFIG_LBDAF is not set
 # CONFIG_BLK_DEV_BSG is not set
+# CONFIG_BLK_DEV_INTEGRITY is not set
 
 #
 # IO Schedulers
@@ -120,25 +138,27 @@ CONFIG_DEFAULT_DEADLINE=y
 # CONFIG_DEFAULT_CFQ is not set
 # CONFIG_DEFAULT_NOOP is not set
 CONFIG_DEFAULT_IOSCHED="deadline"
-CONFIG_CLASSIC_RCU=y
+CONFIG_FREEZER=y
 
 #
 # System Type
 #
+CONFIG_MMU=y
 # CONFIG_ARCH_AAEC2000 is not set
 # CONFIG_ARCH_INTEGRATOR is not set
 # CONFIG_ARCH_REALVIEW is not set
 # CONFIG_ARCH_VERSATILE is not set
 # CONFIG_ARCH_AT91 is not set
-# CONFIG_ARCH_CLPS7500 is not set
 # CONFIG_ARCH_CLPS711X is not set
-# CONFIG_ARCH_CO285 is not set
+# CONFIG_ARCH_GEMINI is not set
 # CONFIG_ARCH_EBSA110 is not set
 # CONFIG_ARCH_EP93XX is not set
 # CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_MXC is not set
+# CONFIG_ARCH_STMP3XXX is not set
 # CONFIG_ARCH_NETX is not set
 # CONFIG_ARCH_H720X is not set
-# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_NOMADIK is not set
 # CONFIG_ARCH_IOP13XX is not set
 # CONFIG_ARCH_IOP32X is not set
 # CONFIG_ARCH_IOP33X is not set
@@ -146,39 +166,64 @@ CONFIG_CLASSIC_RCU=y
 # CONFIG_ARCH_IXP2000 is not set
 # CONFIG_ARCH_IXP4XX is not set
 # CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_KIRKWOOD is not set
+# CONFIG_ARCH_LOKI is not set
+# CONFIG_ARCH_MV78XX0 is not set
+# CONFIG_ARCH_ORION5X is not set
+# CONFIG_ARCH_MMP is not set
 # CONFIG_ARCH_KS8695 is not set
 # CONFIG_ARCH_NS9XXX is not set
-# CONFIG_ARCH_MXC is not set
-# CONFIG_ARCH_ORION5X is not set
+# CONFIG_ARCH_W90X900 is not set
 # CONFIG_ARCH_PNX4008 is not set
 CONFIG_ARCH_PXA=y
+# CONFIG_ARCH_MSM is not set
 # CONFIG_ARCH_RPC is not set
 # CONFIG_ARCH_SA1100 is not set
 # CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_S3C64XX is not set
+# CONFIG_ARCH_S5PC1XX is not set
 # CONFIG_ARCH_SHARK is not set
 # CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_U300 is not set
 # CONFIG_ARCH_DAVINCI is not set
 # CONFIG_ARCH_OMAP is not set
-# CONFIG_ARCH_MSM7X00A is not set
+# CONFIG_ARCH_BCMRING is not set
 
 #
 # Intel PXA2xx/PXA3xx Implementations
 #
 # CONFIG_ARCH_GUMSTIX is not set
+# CONFIG_MACH_INTELMOTE2 is not set
+# CONFIG_MACH_STARGATE2 is not set
 # CONFIG_ARCH_LUBBOCK is not set
 # CONFIG_MACH_LOGICPD_PXA270 is not set
 # CONFIG_MACH_MAINSTONE is not set
+# CONFIG_MACH_MP900C is not set
+# CONFIG_MACH_BALLOON3 is not set
 # CONFIG_ARCH_PXA_IDP is not set
 # CONFIG_PXA_SHARPSL is not set
+# CONFIG_ARCH_VIPER is not set
 # CONFIG_ARCH_PXA_ESERIES is not set
-# CONFIG_MACH_TRIZEPS4 is not set
+# CONFIG_TRIZEPS_PXA is not set
+# CONFIG_MACH_H5000 is not set
 # CONFIG_MACH_EM_X270 is not set
+# CONFIG_MACH_EXEDA is not set
 # CONFIG_MACH_COLIBRI is not set
+# CONFIG_MACH_COLIBRI300 is not set
+# CONFIG_MACH_COLIBRI320 is not set
 # CONFIG_MACH_ZYLONITE is not set
 # CONFIG_MACH_LITTLETON is not set
+# CONFIG_MACH_TAVOREVB is not set
+# CONFIG_MACH_SAAR is not set
 # CONFIG_MACH_ARMCORE is not set
+# CONFIG_MACH_CM_X300 is not set
+# CONFIG_MACH_H4700 is not set
 # CONFIG_MACH_MAGICIAN is not set
+# CONFIG_MACH_HIMALAYA is not set
+# CONFIG_MACH_MIOA701 is not set
 # CONFIG_MACH_PCM027 is not set
+# CONFIG_ARCH_PXA_PALM is not set
+# CONFIG_MACH_CSB726 is not set
 CONFIG_PXA_EZX=y
 CONFIG_MACH_EZX_A780=y
 CONFIG_MACH_EZX_E680=y
@@ -186,17 +231,11 @@ CONFIG_MACH_EZX_A1200=y
 CONFIG_MACH_EZX_A910=y
 CONFIG_MACH_EZX_E6=y
 CONFIG_MACH_EZX_E2=y
+# CONFIG_MACH_XCEP is not set
 CONFIG_PXA27x=y
 CONFIG_PXA_SSP=y
-CONFIG_PXA_PWM=y
-
-#
-# Boot options
-#
-
-#
-# Power management
-#
+CONFIG_PXA_HAVE_BOARD_IRQS=y
+CONFIG_PLAT_PXA=y
 
 #
 # Processor Type
@@ -205,7 +244,7 @@ CONFIG_CPU_32=y
 CONFIG_CPU_XSCALE=y
 CONFIG_CPU_32v5=y
 CONFIG_CPU_ABRT_EV5T=y
-CONFIG_CPU_PABRT_NOIFAR=y
+CONFIG_CPU_PABRT_LEGACY=y
 CONFIG_CPU_CACHE_VIVT=y
 CONFIG_CPU_TLB_V4WBI=y
 CONFIG_CPU_CP15=y
@@ -216,9 +255,10 @@ CONFIG_CPU_CP15_MMU=y
 #
 CONFIG_ARM_THUMB=y
 # CONFIG_CPU_DCACHE_DISABLE is not set
-# CONFIG_OUTER_CACHE is not set
+CONFIG_ARM_L1_CACHE_SHIFT=5
 CONFIG_IWMMXT=y
 CONFIG_XSCALE_PMU=y
+CONFIG_COMMON_CLKDEV=y
 
 #
 # Bus support
@@ -231,44 +271,71 @@ CONFIG_XSCALE_PMU=y
 # Kernel Features
 #
 CONFIG_TICK_ONESHOT=y
-# CONFIG_NO_HZ is not set
+CONFIG_NO_HZ=y
 CONFIG_HIGH_RES_TIMERS=y
 CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+CONFIG_VMSPLIT_3G=y
+# CONFIG_VMSPLIT_2G is not set
+# CONFIG_VMSPLIT_1G is not set
+CONFIG_PAGE_OFFSET=0xC0000000
+# CONFIG_PREEMPT_NONE is not set
+# CONFIG_PREEMPT_VOLUNTARY is not set
 CONFIG_PREEMPT=y
 CONFIG_HZ=100
 CONFIG_AEABI=y
 CONFIG_OABI_COMPAT=y
-# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
+# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set
+# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set
+# CONFIG_HIGHMEM is not set
 CONFIG_SELECT_MEMORY_MODEL=y
 CONFIG_FLATMEM_MANUAL=y
 # CONFIG_DISCONTIGMEM_MANUAL is not set
 # CONFIG_SPARSEMEM_MANUAL is not set
 CONFIG_FLATMEM=y
 CONFIG_FLAT_NODE_MEM_MAP=y
-# CONFIG_SPARSEMEM_STATIC is not set
-# CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set
 CONFIG_PAGEFLAGS_EXTENDED=y
 CONFIG_SPLIT_PTLOCK_CPUS=4096
-# CONFIG_RESOURCES_64BIT is not set
-CONFIG_ZONE_DMA_FLAG=1
-CONFIG_BOUNCE=y
+# CONFIG_PHYS_ADDR_T_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=0
 CONFIG_VIRT_TO_BUS=y
+CONFIG_HAVE_MLOCK=y
+CONFIG_HAVE_MLOCKED_PAGE_BIT=y
+# CONFIG_KSM is not set
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
 CONFIG_ALIGNMENT_TRAP=y
+# CONFIG_UACCESS_WITH_MEMCPY is not set
 
 #
 # Boot options
 #
 CONFIG_ZBOOT_ROM_TEXT=0x0
 CONFIG_ZBOOT_ROM_BSS=0x0
-CONFIG_CMDLINE="console=tty1 root=/dev/mmcblk0p2 rootfstype=ext2 rootdelay=1 ip=192.168.0.202:192.168.0.200:192.168.0.200:255.255.255.0 debug"
+CONFIG_CMDLINE="console=tty1 root=/dev/mmcblk0p2 rootfstype=ext2 rootdelay=3 ip=192.168.0.202:192.168.0.200:192.168.0.200:255.255.255.0 debug"
 # CONFIG_XIP_KERNEL is not set
 CONFIG_KEXEC=y
 CONFIG_ATAGS_PROC=y
 
 #
-# CPU Frequency scaling
-#
-# CONFIG_CPU_FREQ is not set
+# CPU Power Management
+#
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_TABLE=y
+CONFIG_CPU_FREQ_DEBUG=y
+CONFIG_CPU_FREQ_STAT=y
+# CONFIG_CPU_FREQ_STAT_DETAILS is not set
+CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y
+# CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set
+CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
+CONFIG_CPU_FREQ_GOV_POWERSAVE=m
+CONFIG_CPU_FREQ_GOV_USERSPACE=m
+CONFIG_CPU_FREQ_GOV_ONDEMAND=m
+CONFIG_CPU_FREQ_GOV_CONSERVATIVE=m
+CONFIG_CPU_IDLE=y
+CONFIG_CPU_IDLE_GOV_LADDER=y
+CONFIG_CPU_IDLE_GOV_MENU=y
 
 #
 # Floating point emulation
@@ -285,6 +352,8 @@ CONFIG_FPE_NWFPE=y
 # Userspace binary formats
 #
 CONFIG_BINFMT_ELF=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_HAVE_AOUT=y
 CONFIG_BINFMT_AOUT=m
 CONFIG_BINFMT_MISC=m
 
@@ -297,11 +366,8 @@ CONFIG_PM_SLEEP=y
 CONFIG_SUSPEND=y
 CONFIG_SUSPEND_FREEZER=y
 CONFIG_APM_EMULATION=y
+CONFIG_PM_RUNTIME=y
 CONFIG_ARCH_SUSPEND_POSSIBLE=y
-
-#
-# Networking
-#
 CONFIG_NET=y
 
 #
@@ -315,6 +381,7 @@ CONFIG_XFRM=y
 # CONFIG_XFRM_SUB_POLICY is not set
 # CONFIG_XFRM_MIGRATE is not set
 # CONFIG_XFRM_STATISTICS is not set
+CONFIG_XFRM_IPCOMP=m
 # CONFIG_NET_KEY is not set
 CONFIG_INET=y
 # CONFIG_IP_MULTICAST is not set
@@ -342,7 +409,6 @@ CONFIG_INET_TUNNEL=m
 CONFIG_TCP_CONG_CUBIC=y
 CONFIG_DEFAULT_TCP_CONG="cubic"
 # CONFIG_TCP_MD5SIG is not set
-# CONFIG_IP_VS is not set
 CONFIG_IPV6=m
 # CONFIG_IPV6_PRIVACY is not set
 # CONFIG_IPV6_ROUTER_PREF is not set
@@ -393,18 +459,22 @@ CONFIG_NF_CONNTRACK_SANE=m
 CONFIG_NF_CONNTRACK_SIP=m
 CONFIG_NF_CONNTRACK_TFTP=m
 CONFIG_NF_CT_NETLINK=m
+# CONFIG_NETFILTER_TPROXY is not set
 CONFIG_NETFILTER_XTABLES=m
 CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
 # CONFIG_NETFILTER_XT_TARGET_CONNMARK is not set
 # CONFIG_NETFILTER_XT_TARGET_DSCP is not set
+CONFIG_NETFILTER_XT_TARGET_HL=m
+CONFIG_NETFILTER_XT_TARGET_LED=m
 CONFIG_NETFILTER_XT_TARGET_MARK=m
-CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m
 CONFIG_NETFILTER_XT_TARGET_NFLOG=m
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m
 # CONFIG_NETFILTER_XT_TARGET_NOTRACK is not set
 # CONFIG_NETFILTER_XT_TARGET_RATEEST is not set
 # CONFIG_NETFILTER_XT_TARGET_TRACE is not set
 CONFIG_NETFILTER_XT_TARGET_TCPMSS=m
 # CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP is not set
+# CONFIG_NETFILTER_XT_MATCH_CLUSTER is not set
 CONFIG_NETFILTER_XT_MATCH_COMMENT=m
 CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m
 CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=m
@@ -413,20 +483,23 @@ CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m
 CONFIG_NETFILTER_XT_MATCH_DCCP=m
 CONFIG_NETFILTER_XT_MATCH_DSCP=m
 CONFIG_NETFILTER_XT_MATCH_ESP=m
+CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m
 CONFIG_NETFILTER_XT_MATCH_HELPER=m
+CONFIG_NETFILTER_XT_MATCH_HL=m
 # CONFIG_NETFILTER_XT_MATCH_IPRANGE is not set
 CONFIG_NETFILTER_XT_MATCH_LENGTH=m
 CONFIG_NETFILTER_XT_MATCH_LIMIT=m
 CONFIG_NETFILTER_XT_MATCH_MAC=m
 CONFIG_NETFILTER_XT_MATCH_MARK=m
+CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m
 # CONFIG_NETFILTER_XT_MATCH_OWNER is not set
 CONFIG_NETFILTER_XT_MATCH_POLICY=m
-CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m
 # CONFIG_NETFILTER_XT_MATCH_PHYSDEV is not set
 CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
 CONFIG_NETFILTER_XT_MATCH_QUOTA=m
 # CONFIG_NETFILTER_XT_MATCH_RATEEST is not set
 CONFIG_NETFILTER_XT_MATCH_REALM=m
+# CONFIG_NETFILTER_XT_MATCH_RECENT is not set
 CONFIG_NETFILTER_XT_MATCH_SCTP=m
 CONFIG_NETFILTER_XT_MATCH_STATE=m
 CONFIG_NETFILTER_XT_MATCH_STATISTIC=m
@@ -434,20 +507,21 @@ CONFIG_NETFILTER_XT_MATCH_STRING=m
 CONFIG_NETFILTER_XT_MATCH_TCPMSS=m
 CONFIG_NETFILTER_XT_MATCH_TIME=m
 CONFIG_NETFILTER_XT_MATCH_U32=m
-CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m
+# CONFIG_NETFILTER_XT_MATCH_OSF is not set
+# CONFIG_IP_VS is not set
 
 #
 # IP: Netfilter Configuration
 #
+CONFIG_NF_DEFRAG_IPV4=m
 CONFIG_NF_CONNTRACK_IPV4=m
 CONFIG_NF_CONNTRACK_PROC_COMPAT=y
 CONFIG_IP_NF_QUEUE=m
 CONFIG_IP_NF_IPTABLES=m
-CONFIG_IP_NF_MATCH_RECENT=m
-CONFIG_IP_NF_MATCH_ECN=m
+CONFIG_IP_NF_MATCH_ADDRTYPE=m
 CONFIG_IP_NF_MATCH_AH=m
+CONFIG_IP_NF_MATCH_ECN=m
 CONFIG_IP_NF_MATCH_TTL=m
-CONFIG_IP_NF_MATCH_ADDRTYPE=m
 CONFIG_IP_NF_FILTER=m
 CONFIG_IP_NF_TARGET_REJECT=m
 CONFIG_IP_NF_TARGET_LOG=m
@@ -455,8 +529,8 @@ CONFIG_IP_NF_TARGET_ULOG=m
 CONFIG_NF_NAT=m
 CONFIG_NF_NAT_NEEDED=y
 CONFIG_IP_NF_TARGET_MASQUERADE=m
-CONFIG_IP_NF_TARGET_REDIRECT=m
 CONFIG_IP_NF_TARGET_NETMAP=m
+CONFIG_IP_NF_TARGET_REDIRECT=m
 CONFIG_NF_NAT_SNMP_BASIC=m
 CONFIG_NF_NAT_PROTO_GRE=m
 CONFIG_NF_NAT_PROTO_UDPLITE=m
@@ -469,9 +543,9 @@ CONFIG_NF_NAT_PPTP=m
 CONFIG_NF_NAT_H323=m
 CONFIG_NF_NAT_SIP=m
 CONFIG_IP_NF_MANGLE=m
+CONFIG_IP_NF_TARGET_CLUSTERIP=m
 CONFIG_IP_NF_TARGET_ECN=m
 CONFIG_IP_NF_TARGET_TTL=m
-CONFIG_IP_NF_TARGET_CLUSTERIP=m
 CONFIG_IP_NF_RAW=m
 CONFIG_IP_NF_ARPTABLES=m
 CONFIG_IP_NF_ARPFILTER=m
@@ -483,30 +557,29 @@ CONFIG_IP_NF_ARP_MANGLE=m
 CONFIG_NF_CONNTRACK_IPV6=m
 CONFIG_IP6_NF_QUEUE=m
 CONFIG_IP6_NF_IPTABLES=m
-CONFIG_IP6_NF_MATCH_RT=m
-CONFIG_IP6_NF_MATCH_OPTS=m
+CONFIG_IP6_NF_MATCH_AH=m
+CONFIG_IP6_NF_MATCH_EUI64=m
 CONFIG_IP6_NF_MATCH_FRAG=m
+CONFIG_IP6_NF_MATCH_OPTS=m
 CONFIG_IP6_NF_MATCH_HL=m
 CONFIG_IP6_NF_MATCH_IPV6HEADER=m
-CONFIG_IP6_NF_MATCH_AH=m
 CONFIG_IP6_NF_MATCH_MH=m
-CONFIG_IP6_NF_MATCH_EUI64=m
-CONFIG_IP6_NF_FILTER=m
+CONFIG_IP6_NF_MATCH_RT=m
+CONFIG_IP6_NF_TARGET_HL=m
 CONFIG_IP6_NF_TARGET_LOG=m
+CONFIG_IP6_NF_FILTER=m
 CONFIG_IP6_NF_TARGET_REJECT=m
 CONFIG_IP6_NF_MANGLE=m
-CONFIG_IP6_NF_TARGET_HL=m
 CONFIG_IP6_NF_RAW=m
-
-#
-# Bridge: Netfilter Configuration
-#
 # CONFIG_BRIDGE_NF_EBTABLES is not set
 # CONFIG_IP_DCCP is not set
 # CONFIG_IP_SCTP is not set
+# CONFIG_RDS is not set
 # CONFIG_TIPC is not set
 # CONFIG_ATM is not set
+CONFIG_STP=m
 CONFIG_BRIDGE=m
+# CONFIG_NET_DSA is not set
 # CONFIG_VLAN_8021Q is not set
 # CONFIG_DECNET is not set
 CONFIG_LLC=m
@@ -517,9 +590,11 @@ CONFIG_LLC=m
 # CONFIG_LAPB is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
+# CONFIG_PHONET is not set
+# CONFIG_IEEE802154 is not set
 # CONFIG_NET_SCHED is not set
 CONFIG_NET_CLS_ROUTE=y
-CONFIG_NET_SCH_FIFO=y
+# CONFIG_DCB is not set
 
 #
 # Network testing
@@ -529,64 +604,34 @@ CONFIG_NET_SCH_FIFO=y
 # CONFIG_CAN is not set
 # CONFIG_IRDA is not set
 CONFIG_BT=y
-CONFIG_BT_L2CAP=m
+CONFIG_BT_L2CAP=y
 CONFIG_BT_SCO=y
-CONFIG_BT_RFCOMM=m
+CONFIG_BT_RFCOMM=y
 CONFIG_BT_RFCOMM_TTY=y
-CONFIG_BT_BNEP=m
+CONFIG_BT_BNEP=y
 CONFIG_BT_BNEP_MC_FILTER=y
 CONFIG_BT_BNEP_PROTO_FILTER=y
-CONFIG_BT_HIDP=m
+CONFIG_BT_HIDP=y
 
 #
 # Bluetooth device drivers
 #
-# CONFIG_BT_HCIUSB is not set
-# CONFIG_BT_HCIBTUSB is not set
-# CONFIG_BT_HCIBTSDIO is not set
+CONFIG_BT_HCIBTUSB=m
+CONFIG_BT_HCIBTSDIO=m
 CONFIG_BT_HCIUART=y
 CONFIG_BT_HCIUART_H4=y
 # CONFIG_BT_HCIUART_BCSP is not set
 # CONFIG_BT_HCIUART_LL is not set
-# CONFIG_BT_HCIBCM203X is not set
-# CONFIG_BT_HCIBPA10X is not set
-# CONFIG_BT_HCIBFUSB is not set
-# CONFIG_BT_HCIVHCI is not set
+CONFIG_BT_HCIBCM203X=m
+CONFIG_BT_HCIBPA10X=m
+CONFIG_BT_HCIBFUSB=m
+CONFIG_BT_HCIVHCI=m
+CONFIG_BT_MRVL=m
+CONFIG_BT_MRVL_SDIO=m
 # CONFIG_AF_RXRPC is not set
 CONFIG_FIB_RULES=y
-
-#
-# Wireless
-#
-CONFIG_CFG80211=m
-CONFIG_NL80211=y
-CONFIG_WIRELESS_EXT=y
-CONFIG_MAC80211=m
-
-#
-# Rate control algorithm selection
-#
-CONFIG_MAC80211_RC_DEFAULT_PID=y
-# CONFIG_MAC80211_RC_DEFAULT_NONE is not set
-
-#
-# Selecting 'y' for an algorithm will
-#
-
-#
-# build the algorithm into mac80211.
-#
-CONFIG_MAC80211_RC_DEFAULT="pid"
-CONFIG_MAC80211_RC_PID=y
-# CONFIG_MAC80211_MESH is not set
-CONFIG_MAC80211_LEDS=y
-# CONFIG_MAC80211_DEBUG_PACKET_ALIGNMENT is not set
-# CONFIG_MAC80211_DEBUG is not set
-CONFIG_IEEE80211=m
-# CONFIG_IEEE80211_DEBUG is not set
-CONFIG_IEEE80211_CRYPT_WEP=m
-CONFIG_IEEE80211_CRYPT_CCMP=m
-CONFIG_IEEE80211_CRYPT_TKIP=m
+# CONFIG_WIRELESS is not set
+# CONFIG_WIMAX is not set
 # CONFIG_RFKILL is not set
 # CONFIG_NET_9P is not set
 
@@ -598,13 +643,19 @@ CONFIG_IEEE80211_CRYPT_TKIP=m
 # Generic Driver Options
 #
 CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+# CONFIG_DEVTMPFS is not set
 CONFIG_STANDALONE=y
 CONFIG_PREVENT_FIRMWARE_BUILD=y
 CONFIG_FW_LOADER=m
+CONFIG_FIRMWARE_IN_KERNEL=y
+CONFIG_EXTRA_FIRMWARE=""
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES is not set
 # CONFIG_SYS_HYPERVISOR is not set
 CONFIG_CONNECTOR=m
 CONFIG_MTD=y
 # CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_TESTS is not set
 # CONFIG_MTD_CONCAT is not set
 CONFIG_MTD_PARTITIONS=y
 # CONFIG_MTD_REDBOOT_PARTS is not set
@@ -616,9 +667,9 @@ CONFIG_MTD_PARTITIONS=y
 # User Modules And Translation Layers
 #
 CONFIG_MTD_CHAR=y
-# CONFIG_MTD_BLKDEVS is not set
-# CONFIG_MTD_BLOCK is not set
-# CONFIG_MTD_BLOCK_RO is not set
+CONFIG_HAVE_MTD_OTP=y
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
 # CONFIG_FTL is not set
 # CONFIG_NFTL is not set
 # CONFIG_INFTL is not set
@@ -647,7 +698,7 @@ CONFIG_MTD_CFI_I1=y
 # CONFIG_MTD_CFI_I2 is not set
 # CONFIG_MTD_CFI_I4 is not set
 # CONFIG_MTD_CFI_I8 is not set
-# CONFIG_MTD_OTP is not set
+CONFIG_MTD_OTP=y
 CONFIG_MTD_CFI_INTELEXT=y
 # CONFIG_MTD_CFI_AMDSTD is not set
 # CONFIG_MTD_CFI_STAA is not set
@@ -655,19 +706,15 @@ CONFIG_MTD_CFI_UTIL=y
 # CONFIG_MTD_RAM is not set
 # CONFIG_MTD_ROM is not set
 # CONFIG_MTD_ABSENT is not set
-CONFIG_MTD_XIP=y
+# CONFIG_MTD_XIP is not set
 
 #
 # Mapping drivers for chip access
 #
 # CONFIG_MTD_COMPLEX_MAPPINGS is not set
-CONFIG_MTD_PHYSMAP=y
-CONFIG_MTD_PHYSMAP_START=0x0
-CONFIG_MTD_PHYSMAP_LEN=0x0
-CONFIG_MTD_PHYSMAP_BANKWIDTH=2
-# CONFIG_MTD_PXA2XX is not set
+# CONFIG_MTD_PHYSMAP is not set
+CONFIG_MTD_PXA2XX=y
 # CONFIG_MTD_ARM_INTEGRATOR is not set
-# CONFIG_MTD_SHARP_SL is not set
 # CONFIG_MTD_PLATRAM is not set
 
 #
@@ -675,6 +722,7 @@ CONFIG_MTD_PHYSMAP_BANKWIDTH=2
 #
 # CONFIG_MTD_DATAFLASH is not set
 # CONFIG_MTD_M25P80 is not set
+# CONFIG_MTD_SST25L is not set
 # CONFIG_MTD_SLRAM is not set
 # CONFIG_MTD_PHRAM is not set
 # CONFIG_MTD_MTDRAM is not set
@@ -690,6 +738,11 @@ CONFIG_MTD_PHYSMAP_BANKWIDTH=2
 # CONFIG_MTD_ONENAND is not set
 
 #
+# LPDDR flash memory drivers
+#
+# CONFIG_MTD_LPDDR is not set
+
+#
 # UBI - Unsorted block images
 #
 # CONFIG_MTD_UBI is not set
@@ -700,15 +753,14 @@ CONFIG_BLK_DEV_LOOP=m
 CONFIG_BLK_DEV_CRYPTOLOOP=m
 CONFIG_BLK_DEV_NBD=m
 # CONFIG_BLK_DEV_UB is not set
-CONFIG_BLK_DEV_RAM=m
+CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_RAM_COUNT=16
 CONFIG_BLK_DEV_RAM_SIZE=4096
 # CONFIG_BLK_DEV_XIP is not set
 # CONFIG_CDROM_PKTCDVD is not set
 # CONFIG_ATA_OVER_ETH is not set
-CONFIG_MISC_DEVICES=y
-# CONFIG_EEPROM_93CX6 is not set
-# CONFIG_ENCLOSURE_SERVICES is not set
+# CONFIG_MG_DISK is not set
+# CONFIG_MISC_DEVICES is not set
 CONFIG_HAVE_IDE=y
 # CONFIG_IDE is not set
 
@@ -722,7 +774,6 @@ CONFIG_HAVE_IDE=y
 # CONFIG_ATA is not set
 # CONFIG_MD is not set
 CONFIG_NETDEVICES=y
-# CONFIG_NETDEVICES_MULTIQUEUE is not set
 CONFIG_DUMMY=y
 # CONFIG_BONDING is not set
 # CONFIG_MACVLAN is not set
@@ -732,13 +783,11 @@ CONFIG_DUMMY=y
 # CONFIG_NET_ETHERNET is not set
 # CONFIG_NETDEV_1000 is not set
 # CONFIG_NETDEV_10000 is not set
+# CONFIG_WLAN is not set
 
 #
-# Wireless LAN
+# Enable WiMAX (Networking options) to see the WiMAX drivers
 #
-# CONFIG_WLAN_PRE80211 is not set
-# CONFIG_WLAN_80211 is not set
-# CONFIG_IWLWIFI_LEDS is not set
 
 #
 # USB Network Adapters
@@ -765,6 +814,7 @@ CONFIG_SLHC=m
 # CONFIG_NETPOLL is not set
 # CONFIG_NET_POLL_CONTROLLER is not set
 # CONFIG_ISDN is not set
+# CONFIG_PHONE is not set
 
 #
 # Input device support
@@ -786,29 +836,45 @@ CONFIG_INPUT_EVDEV=y
 # Input Device Drivers
 #
 CONFIG_INPUT_KEYBOARD=y
+# CONFIG_KEYBOARD_ADP5588 is not set
 # CONFIG_KEYBOARD_ATKBD is not set
-# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_QT2160 is not set
 # CONFIG_KEYBOARD_LKKBD is not set
-# CONFIG_KEYBOARD_XTKBD is not set
+CONFIG_KEYBOARD_GPIO=y
+# CONFIG_KEYBOARD_MATRIX is not set
+# CONFIG_KEYBOARD_LM8323 is not set
+# CONFIG_KEYBOARD_MAX7359 is not set
 # CONFIG_KEYBOARD_NEWTON is not set
-# CONFIG_KEYBOARD_STOWAWAY is not set
+# CONFIG_KEYBOARD_OPENCORES is not set
 CONFIG_KEYBOARD_PXA27x=y
-CONFIG_KEYBOARD_GPIO=y
+# CONFIG_KEYBOARD_STOWAWAY is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
 # CONFIG_INPUT_MOUSE is not set
 # CONFIG_INPUT_JOYSTICK is not set
 # CONFIG_INPUT_TABLET is not set
 CONFIG_INPUT_TOUCHSCREEN=y
 # CONFIG_TOUCHSCREEN_ADS7846 is not set
+# CONFIG_TOUCHSCREEN_AD7877 is not set
+# CONFIG_TOUCHSCREEN_AD7879_I2C is not set
+# CONFIG_TOUCHSCREEN_AD7879_SPI is not set
+# CONFIG_TOUCHSCREEN_AD7879 is not set
+# CONFIG_TOUCHSCREEN_EETI is not set
 # CONFIG_TOUCHSCREEN_FUJITSU is not set
 # CONFIG_TOUCHSCREEN_GUNZE is not set
 # CONFIG_TOUCHSCREEN_ELO is not set
+# CONFIG_TOUCHSCREEN_WACOM_W8001 is not set
+# CONFIG_TOUCHSCREEN_MCS5000 is not set
 # CONFIG_TOUCHSCREEN_MTOUCH is not set
+# CONFIG_TOUCHSCREEN_INEXIO is not set
 # CONFIG_TOUCHSCREEN_MK712 is not set
 # CONFIG_TOUCHSCREEN_PENMOUNT is not set
 # CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set
 # CONFIG_TOUCHSCREEN_TOUCHWIN is not set
-# CONFIG_TOUCHSCREEN_UCB1400 is not set
 # CONFIG_TOUCHSCREEN_USB_COMPOSITE is not set
+# CONFIG_TOUCHSCREEN_TOUCHIT213 is not set
+# CONFIG_TOUCHSCREEN_TSC2007 is not set
+# CONFIG_TOUCHSCREEN_W90X900 is not set
 CONFIG_TOUCHSCREEN_PCAP=y
 CONFIG_INPUT_MISC=y
 # CONFIG_INPUT_ATI_REMOTE is not set
@@ -816,7 +882,10 @@ CONFIG_INPUT_MISC=y
 # CONFIG_INPUT_KEYSPAN_REMOTE is not set
 # CONFIG_INPUT_POWERMATE is not set
 # CONFIG_INPUT_YEALINK is not set
+# CONFIG_INPUT_CM109 is not set
 CONFIG_INPUT_UINPUT=y
+# CONFIG_INPUT_GPIO_ROTARY_ENCODER is not set
+CONFIG_INPUT_PCAP=y
 
 #
 # Hardware I/O ports
@@ -828,6 +897,7 @@ CONFIG_INPUT_UINPUT=y
 # Character devices
 #
 CONFIG_VT=y
+CONFIG_CONSOLE_TRANSLATIONS=y
 CONFIG_VT_CONSOLE=y
 CONFIG_HW_CONSOLE=y
 # CONFIG_VT_HW_CONSOLE_BINDING is not set
@@ -842,92 +912,130 @@ CONFIG_DEVKMEM=y
 #
 # Non-8250 serial port support
 #
+# CONFIG_SERIAL_MAX3100 is not set
 CONFIG_SERIAL_PXA=y
 CONFIG_SERIAL_PXA_CONSOLE=y
 CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
 CONFIG_UNIX98_PTYS=y
+# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
 CONFIG_LEGACY_PTYS=y
 CONFIG_LEGACY_PTY_COUNT=8
 # CONFIG_IPMI_HANDLER is not set
-CONFIG_HW_RANDOM=y
-# CONFIG_NVRAM is not set
+# CONFIG_HW_RANDOM is not set
 # CONFIG_R3964 is not set
 # CONFIG_RAW_DRIVER is not set
 # CONFIG_TCG_TPM is not set
 CONFIG_I2C=y
 CONFIG_I2C_BOARDINFO=y
+CONFIG_I2C_COMPAT=y
 CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_HELPER_AUTO=y
 
 #
 # I2C Hardware Bus support
 #
+
+#
+# I2C system bus drivers (mostly embedded / system-on-chip)
+#
+# CONFIG_I2C_DESIGNWARE is not set
 # CONFIG_I2C_GPIO is not set
+# CONFIG_I2C_OCORES is not set
 CONFIG_I2C_PXA=y
 # CONFIG_I2C_PXA_SLAVE is not set
-# CONFIG_I2C_OCORES is not set
-# CONFIG_I2C_PARPORT_LIGHT is not set
 # CONFIG_I2C_SIMTEC is not set
+
+#
+# External I2C/SMBus adapter drivers
+#
+# CONFIG_I2C_PARPORT_LIGHT is not set
 # CONFIG_I2C_TAOS_EVM is not set
-# CONFIG_I2C_STUB is not set
 # CONFIG_I2C_TINY_USB is not set
+
+#
+# Other I2C/SMBus bus drivers
+#
 # CONFIG_I2C_PCA_PLATFORM is not set
+# CONFIG_I2C_STUB is not set
 
 #
 # Miscellaneous I2C Chip support
 #
 # CONFIG_DS1682 is not set
-# CONFIG_EEPROM_LEGACY is not set
-# CONFIG_SENSORS_PCF8574 is not set
-# CONFIG_PCF8575 is not set
-# CONFIG_SENSORS_PCF8591 is not set
-# CONFIG_TPS65010 is not set
-# CONFIG_SENSORS_MAX6875 is not set
 # CONFIG_SENSORS_TSL2550 is not set
 # CONFIG_I2C_DEBUG_CORE is not set
 # CONFIG_I2C_DEBUG_ALGO is not set
 # CONFIG_I2C_DEBUG_BUS is not set
 # CONFIG_I2C_DEBUG_CHIP is not set
 CONFIG_SPI=y
+# CONFIG_SPI_DEBUG is not set
 CONFIG_SPI_MASTER=y
 
 #
 # SPI Master Controller Drivers
 #
 # CONFIG_SPI_BITBANG is not set
-CONFIG_SPI_PXA2XX=m
+# CONFIG_SPI_GPIO is not set
+CONFIG_SPI_PXA2XX=y
 
 #
 # SPI Protocol Masters
 #
-# CONFIG_EEPROM_AT25 is not set
 # CONFIG_SPI_SPIDEV is not set
 # CONFIG_SPI_TLE62X0 is not set
-CONFIG_HAVE_GPIO_LIB=y
 
 #
-# GPIO Support
+# PPS support
+#
+# CONFIG_PPS is not set
+CONFIG_ARCH_REQUIRE_GPIOLIB=y
+CONFIG_GPIOLIB=y
+# CONFIG_DEBUG_GPIO is not set
+CONFIG_GPIO_SYSFS=y
+
+#
+# Memory mapped GPIO expanders:
 #
 
 #
 # I2C GPIO expanders:
 #
+# CONFIG_GPIO_MAX732X is not set
 # CONFIG_GPIO_PCA953X is not set
 # CONFIG_GPIO_PCF857X is not set
 
 #
+# PCI GPIO expanders:
+#
+
+#
 # SPI GPIO expanders:
 #
+# CONFIG_GPIO_MAX7301 is not set
 # CONFIG_GPIO_MCP23S08 is not set
+# CONFIG_GPIO_MC33880 is not set
+
+#
+# AC97 GPIO expanders:
+#
 # CONFIG_W1 is not set
-# CONFIG_POWER_SUPPLY is not set
+CONFIG_POWER_SUPPLY=y
+# CONFIG_POWER_SUPPLY_DEBUG is not set
+# CONFIG_PDA_POWER is not set
+# CONFIG_APM_POWER is not set
+# CONFIG_BATTERY_DS2760 is not set
+# CONFIG_BATTERY_DS2782 is not set
+# CONFIG_BATTERY_BQ27x00 is not set
+# CONFIG_BATTERY_MAX17040 is not set
 # CONFIG_HWMON is not set
+# CONFIG_THERMAL is not set
 # CONFIG_WATCHDOG is not set
+CONFIG_SSB_POSSIBLE=y
 
 #
 # Sonics Silicon Backplane
 #
-CONFIG_SSB_POSSIBLE=y
 # CONFIG_SSB is not set
 
 #
@@ -938,54 +1046,170 @@ CONFIG_SSB_POSSIBLE=y
 # CONFIG_MFD_ASIC3 is not set
 # CONFIG_HTC_EGPIO is not set
 # CONFIG_HTC_PASIC3 is not set
+# CONFIG_TPS65010 is not set
+# CONFIG_TWL4030_CORE is not set
+# CONFIG_MFD_TMIO is not set
+# CONFIG_MFD_T7L66XB is not set
+# CONFIG_MFD_TC6387XB is not set
 # CONFIG_MFD_TC6393XB is not set
+# CONFIG_PMIC_DA903X is not set
+# CONFIG_MFD_WM8400 is not set
+# CONFIG_MFD_WM831X is not set
+# CONFIG_MFD_WM8350_I2C is not set
+# CONFIG_MFD_PCF50633 is not set
+# CONFIG_MFD_MC13783 is not set
+# CONFIG_AB3100_CORE is not set
 CONFIG_EZX_PCAP=y
-
-#
-# Multimedia devices
-#
+CONFIG_REGULATOR=y
+CONFIG_REGULATOR_DEBUG=y
+# CONFIG_REGULATOR_FIXED_VOLTAGE is not set
+CONFIG_REGULATOR_VIRTUAL_CONSUMER=y
+CONFIG_REGULATOR_USERSPACE_CONSUMER=y
+# CONFIG_REGULATOR_BQ24022 is not set
+# CONFIG_REGULATOR_MAX1586 is not set
+# CONFIG_REGULATOR_LP3971 is not set
+CONFIG_REGULATOR_PCAP=y
+# CONFIG_REGULATOR_TPS65023 is not set
+# CONFIG_REGULATOR_TPS6507X is not set
+CONFIG_MEDIA_SUPPORT=y
 
 #
 # Multimedia core support
 #
-CONFIG_VIDEO_DEV=m
-CONFIG_VIDEO_V4L2_COMMON=m
+CONFIG_VIDEO_DEV=y
+CONFIG_VIDEO_V4L2_COMMON=y
 CONFIG_VIDEO_ALLOW_V4L1=y
 CONFIG_VIDEO_V4L1_COMPAT=y
 # CONFIG_DVB_CORE is not set
-CONFIG_VIDEO_MEDIA=m
+CONFIG_VIDEO_MEDIA=y
 
 #
 # Multimedia drivers
 #
 # CONFIG_MEDIA_ATTACH is not set
-CONFIG_MEDIA_TUNER=m
-# CONFIG_MEDIA_TUNER_CUSTOMIZE is not set
-CONFIG_MEDIA_TUNER_SIMPLE=m
-CONFIG_MEDIA_TUNER_TDA8290=m
-CONFIG_MEDIA_TUNER_TDA9887=m
-CONFIG_MEDIA_TUNER_TEA5761=m
-CONFIG_MEDIA_TUNER_TEA5767=m
-CONFIG_MEDIA_TUNER_MT20XX=m
-CONFIG_MEDIA_TUNER_XC2028=m
-CONFIG_MEDIA_TUNER_XC5000=m
-CONFIG_VIDEO_V4L2=m
-CONFIG_VIDEO_V4L1=m
+CONFIG_MEDIA_TUNER=y
+CONFIG_MEDIA_TUNER_CUSTOMISE=y
+# CONFIG_MEDIA_TUNER_SIMPLE is not set
+# CONFIG_MEDIA_TUNER_TDA8290 is not set
+# CONFIG_MEDIA_TUNER_TDA827X is not set
+# CONFIG_MEDIA_TUNER_TDA18271 is not set
+# CONFIG_MEDIA_TUNER_TDA9887 is not set
+# CONFIG_MEDIA_TUNER_TEA5761 is not set
+# CONFIG_MEDIA_TUNER_TEA5767 is not set
+# CONFIG_MEDIA_TUNER_MT20XX is not set
+# CONFIG_MEDIA_TUNER_MT2060 is not set
+# CONFIG_MEDIA_TUNER_MT2266 is not set
+# CONFIG_MEDIA_TUNER_MT2131 is not set
+# CONFIG_MEDIA_TUNER_QT1010 is not set
+# CONFIG_MEDIA_TUNER_XC2028 is not set
+# CONFIG_MEDIA_TUNER_XC5000 is not set
+# CONFIG_MEDIA_TUNER_MXL5005S is not set
+# CONFIG_MEDIA_TUNER_MXL5007T is not set
+# CONFIG_MEDIA_TUNER_MC44S803 is not set
+CONFIG_VIDEO_V4L2=y
+CONFIG_VIDEO_V4L1=y
+CONFIG_VIDEOBUF_GEN=y
+CONFIG_VIDEOBUF_DMA_SG=y
 CONFIG_VIDEO_CAPTURE_DRIVERS=y
 # CONFIG_VIDEO_ADV_DEBUG is not set
-CONFIG_VIDEO_HELPER_CHIPS_AUTO=y
+# CONFIG_VIDEO_FIXED_MINOR_RANGES is not set
+# CONFIG_VIDEO_HELPER_CHIPS_AUTO is not set
+
+#
+# Encoders/decoders and other helper chips
+#
+
+#
+# Audio decoders
+#
+# CONFIG_VIDEO_TVAUDIO is not set
+# CONFIG_VIDEO_TDA7432 is not set
+# CONFIG_VIDEO_TDA9840 is not set
+# CONFIG_VIDEO_TDA9875 is not set
+# CONFIG_VIDEO_TEA6415C is not set
+# CONFIG_VIDEO_TEA6420 is not set
+# CONFIG_VIDEO_MSP3400 is not set
+# CONFIG_VIDEO_CS5345 is not set
+# CONFIG_VIDEO_CS53L32A is not set
+# CONFIG_VIDEO_M52790 is not set
+# CONFIG_VIDEO_TLV320AIC23B is not set
+# CONFIG_VIDEO_WM8775 is not set
+# CONFIG_VIDEO_WM8739 is not set
+# CONFIG_VIDEO_VP27SMPX is not set
+
+#
+# RDS decoders
+#
+# CONFIG_VIDEO_SAA6588 is not set
+
+#
+# Video decoders
+#
+# CONFIG_VIDEO_ADV7180 is not set
+# CONFIG_VIDEO_BT819 is not set
+# CONFIG_VIDEO_BT856 is not set
+# CONFIG_VIDEO_BT866 is not set
+# CONFIG_VIDEO_KS0127 is not set
+# CONFIG_VIDEO_OV7670 is not set
+# CONFIG_VIDEO_MT9V011 is not set
+# CONFIG_VIDEO_TCM825X is not set
+# CONFIG_VIDEO_SAA7110 is not set
+# CONFIG_VIDEO_SAA711X is not set
+# CONFIG_VIDEO_SAA717X is not set
+# CONFIG_VIDEO_SAA7191 is not set
+# CONFIG_VIDEO_TVP514X is not set
+# CONFIG_VIDEO_TVP5150 is not set
+# CONFIG_VIDEO_VPX3220 is not set
+
+#
+# Video and audio decoders
+#
+# CONFIG_VIDEO_CX25840 is not set
+
+#
+# MPEG video encoders
+#
+# CONFIG_VIDEO_CX2341X is not set
+
+#
+# Video encoders
+#
+# CONFIG_VIDEO_SAA7127 is not set
+# CONFIG_VIDEO_SAA7185 is not set
+# CONFIG_VIDEO_ADV7170 is not set
+# CONFIG_VIDEO_ADV7175 is not set
+# CONFIG_VIDEO_THS7303 is not set
+# CONFIG_VIDEO_ADV7343 is not set
+
+#
+# Video improvement chips
+#
+# CONFIG_VIDEO_UPD64031A is not set
+# CONFIG_VIDEO_UPD64083 is not set
 # CONFIG_VIDEO_VIVI is not set
 # CONFIG_VIDEO_CPIA is not set
 # CONFIG_VIDEO_CPIA2 is not set
 # CONFIG_VIDEO_SAA5246A is not set
 # CONFIG_VIDEO_SAA5249 is not set
-# CONFIG_TUNER_3036 is not set
+CONFIG_SOC_CAMERA=y
+# CONFIG_SOC_CAMERA_MT9M001 is not set
+CONFIG_SOC_CAMERA_MT9M111=y
+# CONFIG_SOC_CAMERA_MT9T031 is not set
+# CONFIG_SOC_CAMERA_MT9V022 is not set
+# CONFIG_SOC_CAMERA_TW9910 is not set
+# CONFIG_SOC_CAMERA_PLATFORM is not set
+# CONFIG_SOC_CAMERA_OV772X is not set
+CONFIG_VIDEO_PXA27x=y
+# CONFIG_VIDEO_SH_MOBILE_CEU is not set
 # CONFIG_V4L_USB_DRIVERS is not set
-# CONFIG_SOC_CAMERA is not set
-# CONFIG_VIDEO_PXA27x is not set
 CONFIG_RADIO_ADAPTERS=y
+# CONFIG_I2C_SI4713 is not set
+# CONFIG_RADIO_SI4713 is not set
 # CONFIG_USB_DSBR is not set
-# CONFIG_USB_SI470X is not set
+# CONFIG_RADIO_SI470X is not set
+# CONFIG_USB_MR800 is not set
+CONFIG_RADIO_TEA5764=y
+CONFIG_RADIO_TEA5764_XTAL=y
 # CONFIG_DAB is not set
 
 #
@@ -996,6 +1220,7 @@ CONFIG_RADIO_ADAPTERS=y
 CONFIG_FB=y
 # CONFIG_FIRMWARE_EDID is not set
 # CONFIG_FB_DDC is not set
+# CONFIG_FB_BOOT_VESA_SUPPORT is not set
 CONFIG_FB_CFB_FILLRECT=y
 CONFIG_FB_CFB_COPYAREA=y
 CONFIG_FB_CFB_IMAGEBLIT=y
@@ -1017,15 +1242,19 @@ CONFIG_FB_CFB_IMAGEBLIT=y
 # CONFIG_FB_UVESA is not set
 # CONFIG_FB_S1D13XXX is not set
 CONFIG_FB_PXA=y
+CONFIG_FB_PXA_OVERLAY=y
 # CONFIG_FB_PXA_SMARTPANEL is not set
 CONFIG_FB_PXA_PARAMETERS=y
 # CONFIG_FB_MBX is not set
-# CONFIG_FB_AM200EPD is not set
+# CONFIG_FB_W100 is not set
 # CONFIG_FB_VIRTUAL is not set
+# CONFIG_FB_METRONOME is not set
+# CONFIG_FB_MB862XX is not set
+# CONFIG_FB_BROADSHEET is not set
 CONFIG_BACKLIGHT_LCD_SUPPORT=y
 # CONFIG_LCD_CLASS_DEVICE is not set
 CONFIG_BACKLIGHT_CLASS_DEVICE=y
-# CONFIG_BACKLIGHT_CORGI is not set
+CONFIG_BACKLIGHT_GENERIC=y
 CONFIG_BACKLIGHT_PWM=y
 
 #
@@ -1053,85 +1282,60 @@ CONFIG_FONT_MINI_4x6=y
 # CONFIG_FONT_SUN12x22 is not set
 # CONFIG_FONT_10x18 is not set
 # CONFIG_LOGO is not set
-
-#
-# Sound
-#
 CONFIG_SOUND=y
-
-#
-# Advanced Linux Sound Architecture
-#
+CONFIG_SOUND_OSS_CORE=y
+CONFIG_SOUND_OSS_CORE_PRECLAIM=y
 CONFIG_SND=y
 CONFIG_SND_TIMER=y
 CONFIG_SND_PCM=y
+CONFIG_SND_JACK=y
 # CONFIG_SND_SEQUENCER is not set
 CONFIG_SND_OSSEMUL=y
 CONFIG_SND_MIXER_OSS=y
 CONFIG_SND_PCM_OSS=y
 CONFIG_SND_PCM_OSS_PLUGINS=y
+# CONFIG_SND_HRTIMER is not set
 # CONFIG_SND_DYNAMIC_MINORS is not set
 CONFIG_SND_SUPPORT_OLD_API=y
 CONFIG_SND_VERBOSE_PROCFS=y
 # CONFIG_SND_VERBOSE_PRINTK is not set
 # CONFIG_SND_DEBUG is not set
-
-#
-# Generic devices
-#
-# CONFIG_SND_DUMMY is not set
-# CONFIG_SND_MTPAV is not set
-# CONFIG_SND_SERIAL_U16550 is not set
-# CONFIG_SND_MPU401 is not set
-
-#
-# ALSA ARM devices
-#
-# CONFIG_SND_PXA2XX_AC97 is not set
-
-#
-# SPI devices
-#
-
-#
-# USB devices
-#
-# CONFIG_SND_USB_AUDIO is not set
-# CONFIG_SND_USB_CAIAQ is not set
-
-#
-# System on Chip audio support
-#
+# CONFIG_SND_RAWMIDI_SEQ is not set
+# CONFIG_SND_OPL3_LIB_SEQ is not set
+# CONFIG_SND_OPL4_LIB_SEQ is not set
+# CONFIG_SND_SBAWE_SEQ is not set
+# CONFIG_SND_EMU10K1_SEQ is not set
+# CONFIG_SND_DRIVERS is not set
+# CONFIG_SND_ARM is not set
+CONFIG_SND_PXA2XX_LIB=y
+# CONFIG_SND_SPI is not set
+# CONFIG_SND_USB is not set
 CONFIG_SND_SOC=y
 CONFIG_SND_PXA2XX_SOC=y
-
-#
-# ALSA SoC audio for Freescale SOCs
-#
-
-#
-# SoC Audio for the Texas Instruments OMAP
-#
-
-#
-# Open Sound System
-#
+CONFIG_SND_SOC_I2C_AND_SPI=y
+# CONFIG_SND_SOC_ALL_CODECS is not set
 # CONFIG_SOUND_PRIME is not set
 CONFIG_HID_SUPPORT=y
 CONFIG_HID=y
-# CONFIG_HID_DEBUG is not set
 # CONFIG_HIDRAW is not set
 
 #
 # USB Input Devices
 #
 # CONFIG_USB_HID is not set
+# CONFIG_HID_PID is not set
 
 #
 # USB HID Boot Protocol drivers
 #
 # CONFIG_USB_KBD is not set
 # CONFIG_USB_MOUSE is not set
+
+#
+# Special HID drivers
+#
+CONFIG_HID_APPLE=m
+# CONFIG_HID_WACOM is not set
 CONFIG_USB_SUPPORT=y
 CONFIG_USB_ARCH_HAS_HCD=y
 CONFIG_USB_ARCH_HAS_OHCI=y
@@ -1150,32 +1354,42 @@ CONFIG_USB=y
 # CONFIG_USB_OTG is not set
 # CONFIG_USB_OTG_WHITELIST is not set
 # CONFIG_USB_OTG_BLACKLIST_HUB is not set
+# CONFIG_USB_MON is not set
+# CONFIG_USB_WUSB is not set
+# CONFIG_USB_WUSB_CBAF is not set
 
 #
 # USB Host Controller Drivers
 #
 # CONFIG_USB_C67X00_HCD is not set
+# CONFIG_USB_OXU210HP_HCD is not set
 # CONFIG_USB_ISP116X_HCD is not set
 # CONFIG_USB_ISP1760_HCD is not set
+# CONFIG_USB_ISP1362_HCD is not set
 CONFIG_USB_OHCI_HCD=y
 # CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set
 # CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set
 CONFIG_USB_OHCI_LITTLE_ENDIAN=y
 # CONFIG_USB_SL811_HCD is not set
 # CONFIG_USB_R8A66597_HCD is not set
+# CONFIG_USB_HWA_HCD is not set
+# CONFIG_USB_MUSB_HDRC is not set
+# CONFIG_USB_GADGET_MUSB_HDRC is not set
 
 #
 # USB Device Class drivers
 #
 # CONFIG_USB_ACM is not set
 # CONFIG_USB_PRINTER is not set
+# CONFIG_USB_WDM is not set
+# CONFIG_USB_TMC is not set
 
 #
-# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may
 #
 
 #
-# may also be needed; see USB_STORAGE Help for more information
+# also be needed; see USB_STORAGE Help for more info
 #
 # CONFIG_USB_LIBUSUAL is not set
 
@@ -1183,7 +1397,6 @@ CONFIG_USB_OHCI_LITTLE_ENDIAN=y
 # USB Imaging devices
 #
 # CONFIG_USB_MDC800 is not set
-# CONFIG_USB_MON is not set
 
 #
 # USB port drivers
@@ -1196,7 +1409,7 @@ CONFIG_USB_OHCI_LITTLE_ENDIAN=y
 # CONFIG_USB_EMI62 is not set
 # CONFIG_USB_EMI26 is not set
 # CONFIG_USB_ADUTUX is not set
-# CONFIG_USB_AUERSWALD is not set
+# CONFIG_USB_SEVSEG is not set
 # CONFIG_USB_RIO500 is not set
 # CONFIG_USB_LEGOTOWER is not set
 # CONFIG_USB_LCD is not set
@@ -1204,62 +1417,94 @@ CONFIG_USB_OHCI_LITTLE_ENDIAN=y
 # CONFIG_USB_LED is not set
 # CONFIG_USB_CYPRESS_CY7C63 is not set
 # CONFIG_USB_CYTHERM is not set
-# CONFIG_USB_PHIDGET is not set
 # CONFIG_USB_IDMOUSE is not set
 # CONFIG_USB_FTDI_ELAN is not set
 # CONFIG_USB_APPLEDISPLAY is not set
 # CONFIG_USB_LD is not set
 # CONFIG_USB_TRANCEVIBRATOR is not set
 # CONFIG_USB_IOWARRIOR is not set
+# CONFIG_USB_TEST is not set
+# CONFIG_USB_ISIGHTFW is not set
+# CONFIG_USB_VST is not set
 CONFIG_USB_GADGET=y
+# CONFIG_USB_GADGET_DEBUG is not set
 # CONFIG_USB_GADGET_DEBUG_FILES is not set
+# CONFIG_USB_GADGET_DEBUG_FS is not set
+CONFIG_USB_GADGET_VBUS_DRAW=2
 CONFIG_USB_GADGET_SELECTED=y
-# CONFIG_USB_GADGET_AMD5536UDC is not set
+# CONFIG_USB_GADGET_AT91 is not set
 # CONFIG_USB_GADGET_ATMEL_USBA is not set
 # CONFIG_USB_GADGET_FSL_USB2 is not set
-# CONFIG_USB_GADGET_NET2280 is not set
+# CONFIG_USB_GADGET_LH7A40X is not set
+# CONFIG_USB_GADGET_OMAP is not set
 # CONFIG_USB_GADGET_PXA25X is not set
-# CONFIG_USB_GADGET_M66592 is not set
+# CONFIG_USB_GADGET_R8A66597 is not set
 CONFIG_USB_GADGET_PXA27X=y
 CONFIG_USB_PXA27X=y
-# CONFIG_USB_GADGET_GOKU is not set
-# CONFIG_USB_GADGET_LH7A40X is not set
-# CONFIG_USB_GADGET_OMAP is not set
+# CONFIG_USB_GADGET_S3C_HSOTG is not set
+# CONFIG_USB_GADGET_IMX is not set
 # CONFIG_USB_GADGET_S3C2410 is not set
-# CONFIG_USB_GADGET_AT91 is not set
+# CONFIG_USB_GADGET_M66592 is not set
+# CONFIG_USB_GADGET_AMD5536UDC is not set
+# CONFIG_USB_GADGET_FSL_QE is not set
+# CONFIG_USB_GADGET_CI13XXX is not set
+# CONFIG_USB_GADGET_NET2280 is not set
+# CONFIG_USB_GADGET_GOKU is not set
+# CONFIG_USB_GADGET_LANGWELL is not set
 # CONFIG_USB_GADGET_DUMMY_HCD is not set
 # CONFIG_USB_GADGET_DUALSPEED is not set
 # CONFIG_USB_ZERO is not set
+# CONFIG_USB_AUDIO is not set
 CONFIG_USB_ETH=y
 # CONFIG_USB_ETH_RNDIS is not set
+# CONFIG_USB_ETH_EEM is not set
 # CONFIG_USB_GADGETFS is not set
 # CONFIG_USB_FILE_STORAGE is not set
 # CONFIG_USB_G_SERIAL is not set
 # CONFIG_USB_MIDI_GADGET is not set
 # CONFIG_USB_G_PRINTER is not set
+# CONFIG_USB_CDC_COMPOSITE is not set
+
+#
+# OTG and related infrastructure
+#
+CONFIG_USB_OTG_UTILS=y
+# CONFIG_USB_GPIO_VBUS is not set
+# CONFIG_NOP_USB_XCEIV is not set
 CONFIG_MMC=y
 # CONFIG_MMC_DEBUG is not set
 CONFIG_MMC_UNSAFE_RESUME=y
 
 #
-# MMC/SD Card Drivers
+# MMC/SD/SDIO Card Drivers
 #
 CONFIG_MMC_BLOCK=y
 CONFIG_MMC_BLOCK_BOUNCE=y
-CONFIG_SDIO_UART=y
+CONFIG_SDIO_UART=m
+# CONFIG_MMC_TEST is not set
 
 #
-# MMC/SD Host Controller Drivers
+# MMC/SD/SDIO Host Controller Drivers
 #
 CONFIG_MMC_PXA=y
-# CONFIG_MMC_SPI is not set
+# CONFIG_MMC_SDHCI is not set
+# CONFIG_MMC_AT91 is not set
+# CONFIG_MMC_ATMELMCI is not set
+CONFIG_MMC_SPI=y
+# CONFIG_MEMSTICK is not set
 CONFIG_NEW_LEDS=y
 CONFIG_LEDS_CLASS=y
 
 #
 # LED drivers
 #
+# CONFIG_LEDS_PCA9532 is not set
 # CONFIG_LEDS_GPIO is not set
+CONFIG_LEDS_LP3944=y
+# CONFIG_LEDS_PCA955X is not set
+# CONFIG_LEDS_DAC124S085 is not set
+# CONFIG_LEDS_PWM is not set
+# CONFIG_LEDS_BD2802 is not set
 
 #
 # LED Triggers
@@ -1267,7 +1512,14 @@ CONFIG_LEDS_CLASS=y
 CONFIG_LEDS_TRIGGERS=y
 CONFIG_LEDS_TRIGGER_TIMER=y
 CONFIG_LEDS_TRIGGER_HEARTBEAT=y
-# CONFIG_LEDS_TRIGGER_DEFAULT_ON is not set
+CONFIG_LEDS_TRIGGER_BACKLIGHT=y
+CONFIG_LEDS_TRIGGER_GPIO=y
+CONFIG_LEDS_TRIGGER_DEFAULT_ON=y
+
+#
+# iptables trigger is under Netfilter config (LED target)
+#
+# CONFIG_ACCESSIBILITY is not set
 CONFIG_RTC_LIB=y
 CONFIG_RTC_CLASS=y
 CONFIG_RTC_HCTOSYS=y
@@ -1297,45 +1549,67 @@ CONFIG_RTC_INTF_DEV=y
 # CONFIG_RTC_DRV_PCF8583 is not set
 # CONFIG_RTC_DRV_M41T80 is not set
 # CONFIG_RTC_DRV_S35390A is not set
+# CONFIG_RTC_DRV_FM3130 is not set
+# CONFIG_RTC_DRV_RX8581 is not set
+# CONFIG_RTC_DRV_RX8025 is not set
 
 #
 # SPI RTC drivers
 #
+# CONFIG_RTC_DRV_M41T94 is not set
+# CONFIG_RTC_DRV_DS1305 is not set
+# CONFIG_RTC_DRV_DS1390 is not set
 # CONFIG_RTC_DRV_MAX6902 is not set
 # CONFIG_RTC_DRV_R9701 is not set
 # CONFIG_RTC_DRV_RS5C348 is not set
+# CONFIG_RTC_DRV_DS3234 is not set
+# CONFIG_RTC_DRV_PCF2123 is not set
 
 #
 # Platform RTC drivers
 #
 # CONFIG_RTC_DRV_CMOS is not set
+# CONFIG_RTC_DRV_DS1286 is not set
 # CONFIG_RTC_DRV_DS1511 is not set
 # CONFIG_RTC_DRV_DS1553 is not set
 # CONFIG_RTC_DRV_DS1742 is not set
 # CONFIG_RTC_DRV_STK17TA8 is not set
 # CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_M48T35 is not set
 # CONFIG_RTC_DRV_M48T59 is not set
+# CONFIG_RTC_DRV_BQ4802 is not set
 # CONFIG_RTC_DRV_V3020 is not set
 
 #
 # on-CPU RTC drivers
 #
-CONFIG_RTC_DRV_SA1100=m
+# CONFIG_RTC_DRV_SA1100 is not set
+# CONFIG_RTC_DRV_PXA is not set
+CONFIG_RTC_DRV_PCAP=y
+# CONFIG_DMADEVICES is not set
+# CONFIG_AUXDISPLAY is not set
 # CONFIG_UIO is not set
 
 #
+# TI VLYNQ
+#
+# CONFIG_STAGING is not set
+
+#
 # File systems
 #
 CONFIG_EXT2_FS=y
 # CONFIG_EXT2_FS_XATTR is not set
 # CONFIG_EXT2_FS_XIP is not set
 CONFIG_EXT3_FS=m
+# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
 CONFIG_EXT3_FS_XATTR=y
 # CONFIG_EXT3_FS_POSIX_ACL is not set
 # CONFIG_EXT3_FS_SECURITY is not set
-# CONFIG_EXT4DEV_FS is not set
+# CONFIG_EXT4_FS is not set
 CONFIG_JBD=m
-CONFIG_FS_MBCACHE=y
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FS_MBCACHE=m
 CONFIG_REISERFS_FS=m
 # CONFIG_REISERFS_CHECK is not set
 # CONFIG_REISERFS_PROC_INFO is not set
@@ -1350,6 +1624,10 @@ CONFIG_XFS_FS=m
 # CONFIG_XFS_RT is not set
 # CONFIG_XFS_DEBUG is not set
 # CONFIG_OCFS2_FS is not set
+# CONFIG_BTRFS_FS is not set
+# CONFIG_NILFS2_FS is not set
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
 CONFIG_DNOTIFY=y
 CONFIG_INOTIFY=y
 CONFIG_INOTIFY_USER=y
@@ -1357,6 +1635,12 @@ CONFIG_INOTIFY_USER=y
 CONFIG_AUTOFS_FS=y
 CONFIG_AUTOFS4_FS=y
 CONFIG_FUSE_FS=m
+CONFIG_CUSE=m
+
+#
+# Caches
+#
+# CONFIG_FSCACHE is not set
 
 #
 # CD-ROM/DVD Filesystems
@@ -1381,15 +1665,13 @@ CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
 #
 CONFIG_PROC_FS=y
 CONFIG_PROC_SYSCTL=y
+CONFIG_PROC_PAGE_MONITOR=y
 CONFIG_SYSFS=y
 CONFIG_TMPFS=y
 # CONFIG_TMPFS_POSIX_ACL is not set
 # CONFIG_HUGETLB_PAGE is not set
 # CONFIG_CONFIGFS_FS is not set
-
-#
-# Miscellaneous filesystems
-#
+CONFIG_MISC_FILESYSTEMS=y
 # CONFIG_ADFS_FS is not set
 # CONFIG_AFFS_FS is not set
 # CONFIG_HFS_FS is not set
@@ -1397,13 +1679,35 @@ CONFIG_TMPFS=y
 # CONFIG_BEFS_FS is not set
 # CONFIG_BFS_FS is not set
 # CONFIG_EFS_FS is not set
-# CONFIG_JFFS2_FS is not set
+CONFIG_JFFS2_FS=m
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+# CONFIG_JFFS2_FS_WBUF_VERIFY is not set
+# CONFIG_JFFS2_SUMMARY is not set
+# CONFIG_JFFS2_FS_XATTR is not set
+CONFIG_JFFS2_COMPRESSION_OPTIONS=y
+CONFIG_JFFS2_ZLIB=y
+CONFIG_JFFS2_LZO=y
+CONFIG_JFFS2_RTIME=y
+CONFIG_JFFS2_RUBIN=y
+# CONFIG_JFFS2_CMODE_NONE is not set
+CONFIG_JFFS2_CMODE_PRIORITY=y
+# CONFIG_JFFS2_CMODE_SIZE is not set
+# CONFIG_JFFS2_CMODE_FAVOURLZO is not set
 CONFIG_CRAMFS=m
+CONFIG_SQUASHFS=m
+# CONFIG_SQUASHFS_EMBEDDED is not set
+CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE=3
 # CONFIG_VXFS_FS is not set
 # CONFIG_MINIX_FS is not set
+# CONFIG_OMFS_FS is not set
 # CONFIG_HPFS_FS is not set
 # CONFIG_QNX4FS_FS is not set
-# CONFIG_ROMFS_FS is not set
+CONFIG_ROMFS_FS=m
+CONFIG_ROMFS_BACKED_BY_BLOCK=y
+# CONFIG_ROMFS_BACKED_BY_MTD is not set
+# CONFIG_ROMFS_BACKED_BY_BOTH is not set
+CONFIG_ROMFS_ON_BLOCK=y
 # CONFIG_SYSV_FS is not set
 # CONFIG_UFS_FS is not set
 CONFIG_NETWORK_FILESYSTEMS=y
@@ -1411,19 +1715,18 @@ CONFIG_NFS_FS=y
 CONFIG_NFS_V3=y
 CONFIG_NFS_V3_ACL=y
 # CONFIG_NFS_V4 is not set
+# CONFIG_ROOT_NFS is not set
 CONFIG_NFSD=m
 CONFIG_NFSD_V2_ACL=y
 CONFIG_NFSD_V3=y
 CONFIG_NFSD_V3_ACL=y
 # CONFIG_NFSD_V4 is not set
-# CONFIG_ROOT_NFS is not set
 CONFIG_LOCKD=y
 CONFIG_LOCKD_V4=y
 CONFIG_EXPORTFS=m
 CONFIG_NFS_ACL_SUPPORT=y
 CONFIG_NFS_COMMON=y
 CONFIG_SUNRPC=y
-# CONFIG_SUNRPC_BIND34 is not set
 # CONFIG_RPCSEC_GSS_KRB5 is not set
 # CONFIG_RPCSEC_GSS_SPKM3 is not set
 CONFIG_SMB_FS=m
@@ -1490,25 +1793,83 @@ CONFIG_NLS_UTF8=m
 #
 # Kernel hacking
 #
-# CONFIG_PRINTK_TIME is not set
+CONFIG_PRINTK_TIME=y
 CONFIG_ENABLE_WARN_DEPRECATED=y
-# CONFIG_ENABLE_MUST_CHECK is not set
+CONFIG_ENABLE_MUST_CHECK=y
 CONFIG_FRAME_WARN=1024
 # CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_STRIP_ASM_SYMS is not set
 # CONFIG_UNUSED_SYMBOLS is not set
-# CONFIG_DEBUG_FS is not set
+CONFIG_DEBUG_FS=y
 # CONFIG_HEADERS_CHECK is not set
-# CONFIG_DEBUG_KERNEL is not set
-# CONFIG_DEBUG_BUGVERBOSE is not set
-CONFIG_FRAME_POINTER=y
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SHIRQ is not set
+CONFIG_DETECT_SOFTLOCKUP=y
+# CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set
+CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0
+CONFIG_DETECT_HUNG_TASK=y
+# CONFIG_BOOTPARAM_HUNG_TASK_PANIC is not set
+CONFIG_BOOTPARAM_HUNG_TASK_PANIC_VALUE=0
+# CONFIG_SCHED_DEBUG is not set
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_TIMER_STATS is not set
+# CONFIG_DEBUG_OBJECTS is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_KMEMLEAK is not set
+CONFIG_DEBUG_PREEMPT=y
+CONFIG_DEBUG_RT_MUTEXES=y
+CONFIG_DEBUG_PI_LIST=y
+# CONFIG_RT_MUTEX_TESTER is not set
+CONFIG_DEBUG_SPINLOCK=y
+CONFIG_DEBUG_MUTEXES=y
+CONFIG_DEBUG_LOCK_ALLOC=y
+CONFIG_PROVE_LOCKING=y
+CONFIG_LOCKDEP=y
+# CONFIG_LOCK_STAT is not set
+# CONFIG_DEBUG_LOCKDEP is not set
+CONFIG_TRACE_IRQFLAGS=y
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+CONFIG_STACKTRACE=y
+# CONFIG_DEBUG_KOBJECT is not set
+CONFIG_DEBUG_BUGVERBOSE=y
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_WRITECOUNT is not set
+# CONFIG_DEBUG_MEMORY_INIT is not set
+# CONFIG_DEBUG_LIST is not set
+# CONFIG_DEBUG_SG is not set
+# CONFIG_DEBUG_NOTIFIERS is not set
+# CONFIG_DEBUG_CREDENTIALS is not set
+# CONFIG_BOOT_PRINTK_DELAY is not set
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_RCU_CPU_STALL_DETECTOR is not set
+# CONFIG_BACKTRACE_SELF_TEST is not set
+# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
+# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
+# CONFIG_FAULT_INJECTION is not set
+# CONFIG_LATENCYTOP is not set
+# CONFIG_SYSCTL_SYSCALL_CHECK is not set
+# CONFIG_PAGE_POISONING is not set
+CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_TRACING_SUPPORT=y
+# CONFIG_FTRACE is not set
+# CONFIG_DYNAMIC_DEBUG is not set
 # CONFIG_SAMPLES is not set
-# CONFIG_DEBUG_USER is not set
+CONFIG_HAVE_ARCH_KGDB=y
+# CONFIG_KGDB is not set
+CONFIG_ARM_UNWIND=y
+CONFIG_DEBUG_USER=y
+CONFIG_DEBUG_ERRORS=y
+# CONFIG_DEBUG_STACK_USAGE is not set
+# CONFIG_DEBUG_LL is not set
 
 #
 # Security options
 #
 # CONFIG_KEYS is not set
 # CONFIG_SECURITY is not set
+# CONFIG_SECURITYFS is not set
 # CONFIG_SECURITY_FILE_CAPABILITIES is not set
 CONFIG_CRYPTO=y
 
@@ -1516,12 +1877,20 @@ CONFIG_CRYPTO=y
 # Crypto core or helper
 #
 CONFIG_CRYPTO_ALGAPI=m
+CONFIG_CRYPTO_ALGAPI2=m
 CONFIG_CRYPTO_AEAD=m
+CONFIG_CRYPTO_AEAD2=m
 CONFIG_CRYPTO_BLKCIPHER=m
+CONFIG_CRYPTO_BLKCIPHER2=m
 CONFIG_CRYPTO_HASH=m
+CONFIG_CRYPTO_HASH2=m
+CONFIG_CRYPTO_RNG2=m
+CONFIG_CRYPTO_PCOMP=m
 CONFIG_CRYPTO_MANAGER=m
+CONFIG_CRYPTO_MANAGER2=m
 CONFIG_CRYPTO_GF128MUL=m
 CONFIG_CRYPTO_NULL=m
+CONFIG_CRYPTO_WORKQUEUE=m
 CONFIG_CRYPTO_CRYPTD=m
 CONFIG_CRYPTO_AUTHENC=m
 CONFIG_CRYPTO_TEST=m
@@ -1549,14 +1918,20 @@ CONFIG_CRYPTO_XTS=m
 #
 CONFIG_CRYPTO_HMAC=m
 CONFIG_CRYPTO_XCBC=m
+CONFIG_CRYPTO_VMAC=m
 
 #
 # Digest
 #
 CONFIG_CRYPTO_CRC32C=m
+CONFIG_CRYPTO_GHASH=m
 CONFIG_CRYPTO_MD4=m
 CONFIG_CRYPTO_MD5=m
 CONFIG_CRYPTO_MICHAEL_MIC=m
+# CONFIG_CRYPTO_RMD128 is not set
+# CONFIG_CRYPTO_RMD160 is not set
+# CONFIG_CRYPTO_RMD256 is not set
+# CONFIG_CRYPTO_RMD320 is not set
 CONFIG_CRYPTO_SHA1=m
 CONFIG_CRYPTO_SHA256=m
 CONFIG_CRYPTO_SHA512=m
@@ -1587,28 +1962,40 @@ CONFIG_CRYPTO_TWOFISH_COMMON=m
 # Compression
 #
 CONFIG_CRYPTO_DEFLATE=m
+# CONFIG_CRYPTO_ZLIB is not set
 # CONFIG_CRYPTO_LZO is not set
+
+#
+# Random Number Generation
+#
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
 CONFIG_CRYPTO_HW=y
+# CONFIG_BINARY_PRINTF is not set
 
 #
 # Library routines
 #
 CONFIG_BITREVERSE=y
-# CONFIG_GENERIC_FIND_FIRST_BIT is not set
-# CONFIG_GENERIC_FIND_NEXT_BIT is not set
+CONFIG_GENERIC_FIND_LAST_BIT=y
 CONFIG_CRC_CCITT=m
-CONFIG_CRC16=m
-# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC16=y
+# CONFIG_CRC_T10DIF is not set
+CONFIG_CRC_ITU_T=y
 CONFIG_CRC32=y
-# CONFIG_CRC7 is not set
+CONFIG_CRC7=y
 CONFIG_LIBCRC32C=m
-CONFIG_ZLIB_INFLATE=m
+CONFIG_ZLIB_INFLATE=y
 CONFIG_ZLIB_DEFLATE=m
+CONFIG_LZO_COMPRESS=m
+CONFIG_LZO_DECOMPRESS=m
+CONFIG_DECOMPRESS_GZIP=y
+CONFIG_DECOMPRESS_BZIP2=y
+CONFIG_DECOMPRESS_LZMA=y
 CONFIG_TEXTSEARCH=y
 CONFIG_TEXTSEARCH_KMP=m
 CONFIG_TEXTSEARCH_BM=m
 CONFIG_TEXTSEARCH_FSM=m
-CONFIG_PLIST=y
 CONFIG_HAS_IOMEM=y
 CONFIG_HAS_IOPORT=y
 CONFIG_HAS_DMA=y
+CONFIG_NLATTR=y
index f6aed77..efa78e1 100644 (file)
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.12-rc4
-# Thu Jun  9 01:59:03 2005
+# Linux kernel version: 2.6.32-rc5
+# Sat Oct 24 00:09:30 2009
 #
 CONFIG_ARM=y
-CONFIG_MMU=y
-CONFIG_UID16=y
+CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+CONFIG_GENERIC_GPIO=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_GENERIC_IRQ_PROBE=y
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_ARCH_HAS_CPUFREQ=y
+CONFIG_GENERIC_HWEIGHT=y
 CONFIG_GENERIC_CALIBRATE_DELAY=y
-CONFIG_GENERIC_IOMAP=y
+CONFIG_ARCH_MTD_XIP=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
+CONFIG_VECTORS_BASE=0xffff0000
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
 
 #
-# Code maturity level options
+# General setup
 #
 CONFIG_EXPERIMENTAL=y
-CONFIG_CLEAN_COMPILE=y
 CONFIG_BROKEN_ON_SMP=y
 CONFIG_INIT_ENV_ARG_LIMIT=32
-
-#
-# General setup
-#
 CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
 CONFIG_SWAP=y
 CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
 # CONFIG_POSIX_MQUEUE is not set
 # CONFIG_BSD_PROCESS_ACCT is not set
-CONFIG_SYSCTL=y
+# CONFIG_TASKSTATS is not set
 # CONFIG_AUDIT is not set
-CONFIG_HOTPLUG=y
-CONFIG_KOBJECT_UEVENT=y
+
+#
+# RCU Subsystem
+#
+CONFIG_TREE_RCU=y
+# CONFIG_TREE_PREEMPT_RCU is not set
+# CONFIG_RCU_TRACE is not set
+CONFIG_RCU_FANOUT=32
+# CONFIG_RCU_FANOUT_EXACT is not set
+# CONFIG_TREE_RCU_TRACE is not set
 # CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_GROUP_SCHED is not set
+# CONFIG_CGROUPS is not set
+# CONFIG_SYSFS_DEPRECATED_V2 is not set
+# CONFIG_RELAY is not set
+CONFIG_NAMESPACES=y
+# CONFIG_UTS_NS is not set
+# CONFIG_IPC_NS is not set
+# CONFIG_USER_NS is not set
+# CONFIG_PID_NS is not set
+# CONFIG_NET_NS is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_RD_GZIP=y
+CONFIG_RD_BZIP2=y
+CONFIG_RD_LZMA=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+CONFIG_ANON_INODES=y
 # CONFIG_EMBEDDED is not set
+CONFIG_UID16=y
+CONFIG_SYSCTL_SYSCALL=y
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
+CONFIG_ELF_CORE=y
 CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
-CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
 CONFIG_SHMEM=y
-CONFIG_CC_ALIGN_FUNCTIONS=0
-CONFIG_CC_ALIGN_LABELS=0
-CONFIG_CC_ALIGN_LOOPS=0
-CONFIG_CC_ALIGN_JUMPS=0
-# CONFIG_TINY_SHMEM is not set
-CONFIG_BASE_SMALL=0
+CONFIG_AIO=y
+
+#
+# Kernel Performance Events And Counters
+#
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_SLUB_DEBUG=y
+CONFIG_COMPAT_BRK=y
+# CONFIG_SLAB is not set
+CONFIG_SLUB=y
+# CONFIG_SLOB is not set
+# CONFIG_PROFILING is not set
+CONFIG_HAVE_OPROFILE=y
+# CONFIG_KPROBES is not set
+CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_KRETPROBES=y
+CONFIG_HAVE_CLK=y
 
 #
-# Loadable module support
+# GCOV-based kernel profiling
 #
+# CONFIG_SLOW_WORK is not set
+CONFIG_HAVE_GENERIC_DMA_COHERENT=y
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
+CONFIG_BASE_SMALL=0
 CONFIG_MODULES=y
+# CONFIG_MODULE_FORCE_LOAD is not set
 # CONFIG_MODULE_UNLOAD is not set
-CONFIG_OBSOLETE_MODPARM=y
 # CONFIG_MODVERSIONS is not set
 # CONFIG_MODULE_SRCVERSION_ALL is not set
-# CONFIG_KMOD is not set
+CONFIG_BLOCK=y
+# CONFIG_LBDAF is not set
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_BLK_DEV_INTEGRITY is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+# CONFIG_IOSCHED_AS is not set
+# CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
+# CONFIG_DEFAULT_AS is not set
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+CONFIG_DEFAULT_NOOP=y
+CONFIG_DEFAULT_IOSCHED="noop"
+CONFIG_FREEZER=y
 
 #
 # System Type
 #
-# CONFIG_ARCH_CLPS7500 is not set
+CONFIG_MMU=y
+# CONFIG_ARCH_AAEC2000 is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_REALVIEW is not set
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_AT91 is not set
 # CONFIG_ARCH_CLPS711X is not set
-# CONFIG_ARCH_CO285 is not set
+# CONFIG_ARCH_GEMINI is not set
 # CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_EP93XX is not set
 # CONFIG_ARCH_FOOTBRIDGE is not set
-# CONFIG_ARCH_INTEGRATOR is not set
-# CONFIG_ARCH_IOP3XX is not set
-# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_MXC is not set
+# CONFIG_ARCH_STMP3XXX is not set
+# CONFIG_ARCH_NETX is not set
+# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_NOMADIK is not set
+# CONFIG_ARCH_IOP13XX is not set
+# CONFIG_ARCH_IOP32X is not set
+# CONFIG_ARCH_IOP33X is not set
+# CONFIG_ARCH_IXP23XX is not set
 # CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_IXP4XX is not set
 # CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_KIRKWOOD is not set
+# CONFIG_ARCH_LOKI is not set
+# CONFIG_ARCH_MV78XX0 is not set
+# CONFIG_ARCH_ORION5X is not set
+# CONFIG_ARCH_MMP is not set
+# CONFIG_ARCH_KS8695 is not set
+# CONFIG_ARCH_NS9XXX is not set
+# CONFIG_ARCH_W90X900 is not set
+# CONFIG_ARCH_PNX4008 is not set
 # CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_MSM is not set
 # CONFIG_ARCH_RPC is not set
 CONFIG_ARCH_SA1100=y
 # CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_S3C64XX is not set
+# CONFIG_ARCH_S5PC1XX is not set
 # CONFIG_ARCH_SHARK is not set
 # CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_U300 is not set
+# CONFIG_ARCH_DAVINCI is not set
 # CONFIG_ARCH_OMAP is not set
-# CONFIG_ARCH_VERSATILE is not set
-# CONFIG_ARCH_IMX is not set
-# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_BCMRING is not set
 
 #
 # SA11x0 Implementations
@@ -106,27 +209,31 @@ CONFIG_CPU_32=y
 CONFIG_CPU_SA1100=y
 CONFIG_CPU_32v4=y
 CONFIG_CPU_ABRT_EV4=y
+CONFIG_CPU_PABRT_LEGACY=y
 CONFIG_CPU_CACHE_V4WB=y
 CONFIG_CPU_CACHE_VIVT=y
 CONFIG_CPU_TLB_V4WB=y
-CONFIG_CPU_MINICACHE=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
 
 #
 # Processor Features
 #
+# CONFIG_CPU_ICACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_DISABLE is not set
+CONFIG_ARM_L1_CACHE_SHIFT=5
 
 #
 # Bus support
 #
 CONFIG_ISA=y
-CONFIG_ISA_DMA_API=y
-
-#
-# PCCARD (PCMCIA/CardBus) support
-#
+# CONFIG_PCI_SYSCALL is not set
+# CONFIG_ARCH_SUPPORTS_MSI is not set
 CONFIG_PCCARD=y
 # CONFIG_PCMCIA_DEBUG is not set
 CONFIG_PCMCIA=y
+CONFIG_PCMCIA_LOAD_CIS=y
+CONFIG_PCMCIA_IOCTL=y
 
 #
 # PC-card bridges
@@ -138,11 +245,41 @@ CONFIG_PCMCIA_SA1100=y
 #
 # Kernel Features
 #
-# CONFIG_SMP is not set
+CONFIG_TICK_ONESHOT=y
+# CONFIG_NO_HZ is not set
+# CONFIG_HIGH_RES_TIMERS is not set
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+CONFIG_VMSPLIT_3G=y
+# CONFIG_VMSPLIT_2G is not set
+# CONFIG_VMSPLIT_1G is not set
+CONFIG_PAGE_OFFSET=0xC0000000
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
 # CONFIG_PREEMPT is not set
-CONFIG_DISCONTIGMEM=y
+CONFIG_HZ=100
+# CONFIG_AEABI is not set
+CONFIG_ARCH_SPARSEMEM_ENABLE=y
+CONFIG_ARCH_SPARSEMEM_DEFAULT=y
+# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set
+# CONFIG_HIGHMEM is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+# CONFIG_FLATMEM_MANUAL is not set
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+CONFIG_SPARSEMEM_MANUAL=y
+CONFIG_SPARSEMEM=y
+CONFIG_HAVE_MEMORY_PRESENT=y
+CONFIG_SPARSEMEM_EXTREME=y
+CONFIG_SPLIT_PTLOCK_CPUS=4096
+# CONFIG_PHYS_ADDR_T_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=0
+CONFIG_VIRT_TO_BUS=y
+CONFIG_HAVE_MLOCK=y
+CONFIG_HAVE_MLOCKED_PAGE_BIT=y
+# CONFIG_KSM is not set
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
 # CONFIG_LEDS is not set
 CONFIG_ALIGNMENT_TRAP=y
+# CONFIG_UACCESS_WITH_MEMCPY is not set
 
 #
 # Boot options
@@ -151,22 +288,26 @@ CONFIG_ZBOOT_ROM_TEXT=0x0
 CONFIG_ZBOOT_ROM_BSS=0x0
 CONFIG_CMDLINE=""
 # CONFIG_XIP_KERNEL is not set
+# CONFIG_KEXEC is not set
 
 #
-# CPU Frequency scaling
+# CPU Power Management
 #
 CONFIG_CPU_FREQ=y
-CONFIG_CPU_FREQ_TABLE=y
 # CONFIG_CPU_FREQ_DEBUG is not set
-CONFIG_CPU_FREQ_STAT=y
-# CONFIG_CPU_FREQ_STAT_DETAILS is not set
+# CONFIG_CPU_FREQ_STAT is not set
 # CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE is not set
 CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE=y
+# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set
 # CONFIG_CPU_FREQ_GOV_PERFORMANCE is not set
 # CONFIG_CPU_FREQ_GOV_POWERSAVE is not set
 CONFIG_CPU_FREQ_GOV_USERSPACE=y
 # CONFIG_CPU_FREQ_GOV_ONDEMAND is not set
+# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set
 CONFIG_CPU_FREQ_SA1100=y
+# CONFIG_CPU_IDLE is not set
 
 #
 # Floating point emulation
@@ -183,6 +324,8 @@ CONFIG_FPE_NWFPE=y
 # Userspace binary formats
 #
 CONFIG_BINFMT_ELF=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_HAVE_AOUT=y
 # CONFIG_BINFMT_AOUT is not set
 # CONFIG_BINFMT_MISC is not set
 # CONFIG_ARTHUR is not set
@@ -191,8 +334,120 @@ CONFIG_BINFMT_ELF=y
 # Power management options
 #
 CONFIG_PM=y
-# CONFIG_PM_LEGACY is not set
-# CONFIG_APM is not set
+# CONFIG_PM_DEBUG is not set
+CONFIG_PM_SLEEP=y
+CONFIG_SUSPEND=y
+CONFIG_SUSPEND_FREEZER=y
+# CONFIG_APM_EMULATION is not set
+# CONFIG_PM_RUNTIME is not set
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+CONFIG_NET=y
+
+#
+# Networking options
+#
+# CONFIG_PACKET is not set
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_MIGRATE is not set
+# CONFIG_XFRM_STATISTICS is not set
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+# CONFIG_IP_PNP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
+CONFIG_INET_LRO=y
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# CONFIG_RDS is not set
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_NET_DSA is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_PHONET is not set
+# CONFIG_IEEE802154 is not set
+# CONFIG_NET_SCHED is not set
+# CONFIG_DCB is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_CAN is not set
+CONFIG_IRDA=m
+
+#
+# IrDA protocols
+#
+CONFIG_IRLAN=m
+CONFIG_IRNET=m
+CONFIG_IRCOMM=m
+# CONFIG_IRDA_ULTRA is not set
+
+#
+# IrDA options
+#
+# CONFIG_IRDA_CACHE_LAST_LSAP is not set
+# CONFIG_IRDA_FAST_RR is not set
+# CONFIG_IRDA_DEBUG is not set
+
+#
+# Infrared-port device drivers
+#
+
+#
+# SIR device drivers
+#
+# CONFIG_IRTTY_SIR is not set
+
+#
+# Dongle support
+#
+
+#
+# FIR device drivers
+#
+CONFIG_SA1100_FIR=m
+# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+# CONFIG_WIRELESS is not set
+# CONFIG_WIMAX is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
 
 #
 # Device Drivers
@@ -201,15 +456,17 @@ CONFIG_PM=y
 #
 # Generic Driver Options
 #
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_STANDALONE=y
 CONFIG_PREVENT_FIRMWARE_BUILD=y
-# CONFIG_FW_LOADER is not set
-
-#
-# Memory Technology Devices (MTD)
-#
+CONFIG_FW_LOADER=y
+CONFIG_FIRMWARE_IN_KERNEL=y
+CONFIG_EXTRA_FIRMWARE=""
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_CONNECTOR is not set
 CONFIG_MTD=y
 # CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_TESTS is not set
 # CONFIG_MTD_CONCAT is not set
 CONFIG_MTD_PARTITIONS=y
 CONFIG_MTD_REDBOOT_PARTS=y
@@ -218,15 +475,20 @@ CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-1
 # CONFIG_MTD_REDBOOT_PARTS_READONLY is not set
 # CONFIG_MTD_CMDLINE_PARTS is not set
 # CONFIG_MTD_AFS_PARTS is not set
+# CONFIG_MTD_AR7_PARTS is not set
 
 #
 # User Modules And Translation Layers
 #
 CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=y
 CONFIG_MTD_BLOCK=y
 # CONFIG_FTL is not set
 # CONFIG_NFTL is not set
 # CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+# CONFIG_MTD_OOPS is not set
 
 #
 # RAM/ROM/Flash chip drivers
@@ -249,6 +511,7 @@ CONFIG_MTD_MAP_BANK_WIDTH_4=y
 CONFIG_MTD_CFI_I2=y
 # CONFIG_MTD_CFI_I4 is not set
 # CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_OTP is not set
 CONFIG_MTD_CFI_INTELEXT=y
 # CONFIG_MTD_CFI_AMDSTD is not set
 # CONFIG_MTD_CFI_STAA is not set
@@ -265,7 +528,7 @@ CONFIG_MTD_CFI_UTIL=y
 # CONFIG_MTD_PHYSMAP is not set
 # CONFIG_MTD_ARM_INTEGRATOR is not set
 CONFIG_MTD_SA1100=y
-# CONFIG_MTD_EDB7312 is not set
+# CONFIG_MTD_PLATRAM is not set
 
 #
 # Self-contained MTD device drivers
@@ -273,7 +536,6 @@ CONFIG_MTD_SA1100=y
 # CONFIG_MTD_SLRAM is not set
 # CONFIG_MTD_PHRAM is not set
 # CONFIG_MTD_MTDRAM is not set
-# CONFIG_MTD_BLKMTD is not set
 # CONFIG_MTD_BLOCK2MTD is not set
 
 #
@@ -282,26 +544,21 @@ CONFIG_MTD_SA1100=y
 # CONFIG_MTD_DOC2000 is not set
 # CONFIG_MTD_DOC2001 is not set
 # CONFIG_MTD_DOC2001PLUS is not set
-
-#
-# NAND Flash Device Drivers
-#
 # CONFIG_MTD_NAND is not set
+# CONFIG_MTD_ONENAND is not set
 
 #
-# Parallel port support
+# LPDDR flash memory drivers
 #
-# CONFIG_PARPORT is not set
+# CONFIG_MTD_LPDDR is not set
 
 #
-# Plug and Play support
+# UBI - Unsorted block images
 #
+# CONFIG_MTD_UBI is not set
+# CONFIG_PARPORT is not set
 # CONFIG_PNP is not set
-
-#
-# Block devices
-#
-# CONFIG_BLK_DEV_XD is not set
+CONFIG_BLK_DEV=y
 # CONFIG_BLK_DEV_COW_COMMON is not set
 CONFIG_BLK_DEV_LOOP=m
 # CONFIG_BLK_DEV_CRYPTOLOOP is not set
@@ -309,212 +566,58 @@ CONFIG_BLK_DEV_LOOP=m
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_RAM_COUNT=16
 CONFIG_BLK_DEV_RAM_SIZE=8192
-CONFIG_BLK_DEV_INITRD=y
-CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_BLK_DEV_XIP is not set
 # CONFIG_CDROM_PKTCDVD is not set
-
-#
-# IO Schedulers
-#
-CONFIG_IOSCHED_NOOP=y
-CONFIG_IOSCHED_AS=y
-CONFIG_IOSCHED_DEADLINE=y
-CONFIG_IOSCHED_CFQ=y
 # CONFIG_ATA_OVER_ETH is not set
+# CONFIG_MG_DISK is not set
+# CONFIG_MISC_DEVICES is not set
+CONFIG_HAVE_IDE=y
+CONFIG_IDE=y
 
 #
-# ATA/ATAPI/MFM/RLL support
-#
-CONFIG_IDE=m
-CONFIG_BLK_DEV_IDE=m
-
-#
-# Please see Documentation/ide.txt for help/info on IDE drives
+# Please see Documentation/ide/ide.txt for help/info on IDE drives
 #
 # CONFIG_BLK_DEV_IDE_SATA is not set
-CONFIG_BLK_DEV_IDEDISK=m
-# CONFIG_IDEDISK_MULTI_MODE is not set
-# CONFIG_BLK_DEV_IDECS is not set
-CONFIG_BLK_DEV_IDECD=m
+CONFIG_IDE_GD=y
+CONFIG_IDE_GD_ATA=y
+# CONFIG_IDE_GD_ATAPI is not set
+CONFIG_BLK_DEV_IDECS=y
+# CONFIG_BLK_DEV_IDECD is not set
 # CONFIG_BLK_DEV_IDETAPE is not set
-# CONFIG_BLK_DEV_IDEFLOPPY is not set
 # CONFIG_IDE_TASK_IOCTL is not set
+CONFIG_IDE_PROC_FS=y
 
 #
 # IDE chipset support/bugfixes
 #
-CONFIG_IDE_GENERIC=m
-# CONFIG_IDE_ARM is not set
-# CONFIG_IDE_CHIPSETS is not set
+# CONFIG_BLK_DEV_PLATFORM is not set
 # CONFIG_BLK_DEV_IDEDMA is not set
-# CONFIG_IDEDMA_AUTO is not set
-# CONFIG_BLK_DEV_HD is not set
 
 #
 # SCSI device support
 #
+# CONFIG_RAID_ATTRS is not set
 # CONFIG_SCSI is not set
-
-#
-# Multi-device support (RAID and LVM)
-#
+# CONFIG_SCSI_DMA is not set
+# CONFIG_SCSI_NETLINK is not set
+# CONFIG_ATA is not set
 # CONFIG_MD is not set
-
-#
-# Fusion MPT device support
-#
-
-#
-# IEEE 1394 (FireWire) support
-#
-
-#
-# I2O device support
-#
-
-#
-# Networking support
-#
-CONFIG_NET=y
-
-#
-# Networking options
-#
-# CONFIG_PACKET is not set
-CONFIG_UNIX=y
-# CONFIG_NET_KEY is not set
-CONFIG_INET=y
-# CONFIG_IP_MULTICAST is not set
-# CONFIG_IP_ADVANCED_ROUTER is not set
-# CONFIG_IP_PNP is not set
-# CONFIG_NET_IPIP is not set
-# CONFIG_NET_IPGRE is not set
-# CONFIG_ARPD is not set
-# CONFIG_SYN_COOKIES is not set
-# CONFIG_INET_AH is not set
-# CONFIG_INET_ESP is not set
-# CONFIG_INET_IPCOMP is not set
-# CONFIG_INET_TUNNEL is not set
-# CONFIG_IP_TCPDIAG is not set
-# CONFIG_IP_TCPDIAG_IPV6 is not set
-# CONFIG_IPV6 is not set
-# CONFIG_NETFILTER is not set
-
-#
-# SCTP Configuration (EXPERIMENTAL)
-#
-# CONFIG_IP_SCTP is not set
-# CONFIG_ATM is not set
-# CONFIG_BRIDGE is not set
-# CONFIG_VLAN_8021Q is not set
-# CONFIG_DECNET is not set
-# CONFIG_LLC2 is not set
-# CONFIG_IPX is not set
-# CONFIG_ATALK is not set
-# CONFIG_X25 is not set
-# CONFIG_LAPB is not set
-# CONFIG_NET_DIVERT is not set
-# CONFIG_ECONET is not set
-# CONFIG_WAN_ROUTER is not set
-
-#
-# QoS and/or fair queueing
-#
-# CONFIG_NET_SCHED is not set
-# CONFIG_NET_CLS_ROUTE is not set
-
-#
-# Network testing
-#
-# CONFIG_NET_PKTGEN is not set
-# CONFIG_NETPOLL is not set
-# CONFIG_NET_POLL_CONTROLLER is not set
-# CONFIG_HAMRADIO is not set
-CONFIG_IRDA=m
-
-#
-# IrDA protocols
-#
-CONFIG_IRLAN=m
-CONFIG_IRNET=m
-CONFIG_IRCOMM=m
-# CONFIG_IRDA_ULTRA is not set
-
-#
-# IrDA options
-#
-# CONFIG_IRDA_CACHE_LAST_LSAP is not set
-# CONFIG_IRDA_FAST_RR is not set
-# CONFIG_IRDA_DEBUG is not set
-
-#
-# Infrared-port device drivers
-#
-
-#
-# SIR device drivers
-#
-# CONFIG_IRTTY_SIR is not set
-
-#
-# Dongle support
-#
-
-#
-# Old SIR device drivers
-#
-# CONFIG_IRPORT_SIR is not set
-
-#
-# Old Serial dongle support
-#
-
-#
-# FIR device drivers
-#
-# CONFIG_NSC_FIR is not set
-# CONFIG_WINBOND_FIR is not set
-# CONFIG_SMC_IRCC_FIR is not set
-# CONFIG_ALI_FIR is not set
-CONFIG_SA1100_FIR=m
-# CONFIG_VIA_FIR is not set
-# CONFIG_BT is not set
 CONFIG_NETDEVICES=y
 # CONFIG_DUMMY is not set
 # CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
 # CONFIG_EQUALIZER is not set
 # CONFIG_TUN is not set
-
-#
-# ARCnet devices
-#
+# CONFIG_VETH is not set
 # CONFIG_ARCNET is not set
-
-#
-# Ethernet (10 or 100Mbit)
-#
 # CONFIG_NET_ETHERNET is not set
-
-#
-# Ethernet (1000 Mbit)
-#
-
-#
-# Ethernet (10000 Mbit)
-#
-
-#
-# Token Ring devices
-#
+# CONFIG_NETDEV_1000 is not set
+# CONFIG_NETDEV_10000 is not set
 # CONFIG_TR is not set
+# CONFIG_WLAN is not set
 
 #
-# Wireless LAN (non-hamradio)
-#
-# CONFIG_NET_RADIO is not set
-
-#
-# PCMCIA network device support
+# Enable WiMAX (Networking options) to see the WiMAX drivers
 #
 CONFIG_NET_PCMCIA=y
 # CONFIG_PCMCIA_3C589 is not set
@@ -525,10 +628,6 @@ CONFIG_PCMCIA_PCNET=y
 # CONFIG_PCMCIA_SMC91C92 is not set
 # CONFIG_PCMCIA_XIRC2PS is not set
 # CONFIG_PCMCIA_AXNET is not set
-
-#
-# Wan interfaces
-#
 # CONFIG_WAN is not set
 CONFIG_PPP=m
 # CONFIG_PPP_MULTILINK is not set
@@ -537,20 +636,23 @@ CONFIG_PPP_ASYNC=m
 # CONFIG_PPP_SYNC_TTY is not set
 CONFIG_PPP_DEFLATE=m
 CONFIG_PPP_BSDCOMP=m
+# CONFIG_PPP_MPPE is not set
 # CONFIG_PPPOE is not set
+# CONFIG_PPPOL2TP is not set
 # CONFIG_SLIP is not set
-# CONFIG_SHAPER is not set
+CONFIG_SLHC=m
 # CONFIG_NETCONSOLE is not set
-
-#
-# ISDN subsystem
-#
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
 # CONFIG_ISDN is not set
+# CONFIG_PHONE is not set
 
 #
 # Input device support
 #
 CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
 
 #
 # Userland interfaces
@@ -560,7 +662,6 @@ CONFIG_INPUT_MOUSEDEV_PSAUX=y
 CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
 CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
 # CONFIG_INPUT_JOYDEV is not set
-# CONFIG_INPUT_TSDEV is not set
 # CONFIG_INPUT_EVDEV is not set
 # CONFIG_INPUT_EVBUG is not set
 
@@ -568,47 +669,42 @@ CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
 # Input Device Drivers
 #
 CONFIG_INPUT_KEYBOARD=y
-CONFIG_KEYBOARD_ATKBD=y
-# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_ATKBD is not set
 # CONFIG_KEYBOARD_LKKBD is not set
-# CONFIG_KEYBOARD_XTKBD is not set
+CONFIG_KEYBOARD_GPIO=y
+# CONFIG_KEYBOARD_MATRIX is not set
 # CONFIG_KEYBOARD_NEWTON is not set
-CONFIG_INPUT_MOUSE=y
-CONFIG_MOUSE_PS2=y
-# CONFIG_MOUSE_SERIAL is not set
-# CONFIG_MOUSE_INPORT is not set
-# CONFIG_MOUSE_LOGIBM is not set
-# CONFIG_MOUSE_PC110PAD is not set
-# CONFIG_MOUSE_VSXXXAA is not set
+# CONFIG_KEYBOARD_OPENCORES is not set
+# CONFIG_KEYBOARD_STOWAWAY is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_INPUT_MOUSE is not set
 # CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
 # CONFIG_INPUT_TOUCHSCREEN is not set
 # CONFIG_INPUT_MISC is not set
 
 #
 # Hardware I/O ports
 #
-CONFIG_SERIO=y
-CONFIG_SERIO_SERPORT=y
-CONFIG_SERIO_LIBPS2=y
-# CONFIG_SERIO_RAW is not set
+# CONFIG_SERIO is not set
 # CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
 
 #
 # Character devices
 #
 CONFIG_VT=y
+CONFIG_CONSOLE_TRANSLATIONS=y
 CONFIG_VT_CONSOLE=y
 CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
+CONFIG_DEVKMEM=y
 # CONFIG_SERIAL_NONSTANDARD is not set
 
 #
 # Serial drivers
 #
-CONFIG_SERIAL_8250=m
-# CONFIG_SERIAL_8250_CS is not set
-CONFIG_SERIAL_8250_NR_UARTS=4
-# CONFIG_SERIAL_8250_EXTENDED is not set
+# CONFIG_SERIAL_8250 is not set
 
 #
 # Non-8250 serial port support
@@ -618,71 +714,125 @@ CONFIG_SERIAL_SA1100_CONSOLE=y
 CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
 CONFIG_UNIX98_PTYS=y
+# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
 CONFIG_LEGACY_PTYS=y
 CONFIG_LEGACY_PTY_COUNT=256
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_HW_RANDOM is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
 
 #
-# IPMI
+# PCMCIA character devices
 #
-# CONFIG_IPMI_HANDLER is not set
+# CONFIG_SYNCLINK_CS is not set
+# CONFIG_CARDMAN_4000 is not set
+# CONFIG_CARDMAN_4040 is not set
+# CONFIG_IPWIRELESS is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+CONFIG_DEVPORT=y
+# CONFIG_I2C is not set
+# CONFIG_SPI is not set
 
 #
-# Watchdog Cards
+# PPS support
 #
-# CONFIG_WATCHDOG is not set
-# CONFIG_NVRAM is not set
-# CONFIG_RTC is not set
-# CONFIG_DTLK is not set
-# CONFIG_R3964 is not set
+# CONFIG_PPS is not set
+CONFIG_ARCH_REQUIRE_GPIOLIB=y
+CONFIG_GPIOLIB=y
+# CONFIG_GPIO_SYSFS is not set
 
 #
-# Ftape, the floppy tape device driver
+# Memory mapped GPIO expanders:
 #
-# CONFIG_DRM is not set
 
 #
-# PCMCIA character devices
+# I2C GPIO expanders:
 #
-# CONFIG_SYNCLINK_CS is not set
-# CONFIG_RAW_DRIVER is not set
 
 #
-# TPM devices
+# PCI GPIO expanders:
 #
 
 #
-# I2C support
+# SPI GPIO expanders:
 #
-# CONFIG_I2C is not set
 
 #
-# Misc devices
+# AC97 GPIO expanders:
 #
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+# CONFIG_HWMON is not set
+# CONFIG_THERMAL is not set
+# CONFIG_WATCHDOG is not set
+CONFIG_SSB_POSSIBLE=y
 
 #
-# Multimedia devices
+# Sonics Silicon Backplane
 #
-# CONFIG_VIDEO_DEV is not set
+# CONFIG_SSB is not set
 
 #
-# Digital Video Broadcasting Devices
+# Multifunction device drivers
 #
-# CONFIG_DVB is not set
+# CONFIG_MFD_CORE is not set
+# CONFIG_MFD_SM501 is not set
+# CONFIG_MFD_ASIC3 is not set
+CONFIG_HTC_EGPIO=y
+# CONFIG_HTC_PASIC3 is not set
+# CONFIG_MFD_TMIO is not set
+# CONFIG_MFD_T7L66XB is not set
+# CONFIG_MFD_TC6387XB is not set
+# CONFIG_MFD_TC6393XB is not set
+
+#
+# Multimedia Capabilities Port drivers
+#
+# CONFIG_MCP_SA11X0 is not set
+# CONFIG_REGULATOR is not set
+# CONFIG_MEDIA_SUPPORT is not set
 
 #
 # Graphics support
 #
+# CONFIG_VGASTATE is not set
+# CONFIG_VIDEO_OUTPUT_CONTROL is not set
 CONFIG_FB=y
+# CONFIG_FIRMWARE_EDID is not set
+# CONFIG_FB_DDC is not set
+# CONFIG_FB_BOOT_VESA_SUPPORT is not set
 CONFIG_FB_CFB_FILLRECT=y
 CONFIG_FB_CFB_COPYAREA=y
 CONFIG_FB_CFB_IMAGEBLIT=y
-CONFIG_FB_SOFT_CURSOR=y
+# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
+# CONFIG_FB_SYS_FILLRECT is not set
+# CONFIG_FB_SYS_COPYAREA is not set
+# CONFIG_FB_SYS_IMAGEBLIT is not set
+# CONFIG_FB_FOREIGN_ENDIAN is not set
+# CONFIG_FB_SYS_FOPS is not set
+# CONFIG_FB_SVGALIB is not set
 # CONFIG_FB_MACMODES is not set
+# CONFIG_FB_BACKLIGHT is not set
 # CONFIG_FB_MODE_HELPERS is not set
 # CONFIG_FB_TILEBLITTING is not set
+
+#
+# Frame buffer hardware drivers
+#
 CONFIG_FB_SA1100=y
 # CONFIG_FB_S1D13XXX is not set
 # CONFIG_FB_VIRTUAL is not set
+# CONFIG_FB_METRONOME is not set
+# CONFIG_FB_MB862XX is not set
+# CONFIG_FB_BROADSHEET is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
 
 #
 # Console display driver support
@@ -691,65 +841,54 @@ CONFIG_FB_SA1100=y
 # CONFIG_MDA_CONSOLE is not set
 CONFIG_DUMMY_CONSOLE=y
 # CONFIG_FRAMEBUFFER_CONSOLE is not set
-
-#
-# Logo configuration
-#
 # CONFIG_LOGO is not set
-# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
-
-#
-# Sound
-#
-CONFIG_SOUND=y
-
-#
-# Advanced Linux Sound Architecture
-#
-# CONFIG_SND is not set
-
-#
-# Open Sound System
-#
-# CONFIG_SOUND_PRIME is not set
-
-#
-# USB support
-#
-CONFIG_USB_ARCH_HAS_HCD=y
-# CONFIG_USB_ARCH_HAS_OHCI is not set
-# CONFIG_USB is not set
+# CONFIG_SOUND is not set
+# CONFIG_HID_SUPPORT is not set
+# CONFIG_USB_SUPPORT is not set
+# CONFIG_MMC is not set
+# CONFIG_MEMSTICK is not set
+# CONFIG_NEW_LEDS is not set
+# CONFIG_ACCESSIBILITY is not set
+CONFIG_RTC_LIB=y
+# CONFIG_RTC_CLASS is not set
+# CONFIG_DMADEVICES is not set
+# CONFIG_AUXDISPLAY is not set
+# CONFIG_UIO is not set
 
 #
-# USB Gadget Support
+# TI VLYNQ
 #
-# CONFIG_USB_GADGET is not set
-
-#
-# MMC/SD Card support
-#
-# CONFIG_MMC is not set
+# CONFIG_STAGING is not set
 
 #
 # File systems
 #
 CONFIG_EXT2_FS=y
 # CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
 # CONFIG_EXT3_FS is not set
-# CONFIG_JBD is not set
+# CONFIG_EXT4_FS is not set
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
-
-#
-# XFS support
-#
+# CONFIG_FS_POSIX_ACL is not set
 # CONFIG_XFS_FS is not set
-# CONFIG_MINIX_FS is not set
-# CONFIG_ROMFS_FS is not set
-# CONFIG_QUOTA is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_BTRFS_FS is not set
+# CONFIG_NILFS2_FS is not set
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
 CONFIG_DNOTIFY=y
+# CONFIG_INOTIFY is not set
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA is not set
 # CONFIG_AUTOFS_FS is not set
 # CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# Caches
+#
+# CONFIG_FSCACHE is not set
 
 #
 # CD-ROM/DVD Filesystems
@@ -771,16 +910,13 @@ CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
 # Pseudo filesystems
 #
 CONFIG_PROC_FS=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_PROC_PAGE_MONITOR=y
 CONFIG_SYSFS=y
-# CONFIG_DEVFS_FS is not set
-# CONFIG_DEVPTS_FS_XATTR is not set
 # CONFIG_TMPFS is not set
 # CONFIG_HUGETLB_PAGE is not set
-CONFIG_RAMFS=y
-
-#
-# Miscellaneous filesystems
-#
+# CONFIG_CONFIGFS_FS is not set
+CONFIG_MISC_FILESYSTEMS=y
 # CONFIG_ADFS_FS is not set
 # CONFIG_AFFS_FS is not set
 # CONFIG_HFS_FS is not set
@@ -788,34 +924,37 @@ CONFIG_RAMFS=y
 # CONFIG_BEFS_FS is not set
 # CONFIG_BFS_FS is not set
 # CONFIG_EFS_FS is not set
-# CONFIG_JFFS_FS is not set
 CONFIG_JFFS2_FS=y
 CONFIG_JFFS2_FS_DEBUG=0
-# CONFIG_JFFS2_FS_NAND is not set
-# CONFIG_JFFS2_FS_NOR_ECC is not set
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+# CONFIG_JFFS2_FS_WBUF_VERIFY is not set
+# CONFIG_JFFS2_SUMMARY is not set
+# CONFIG_JFFS2_FS_XATTR is not set
 # CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
 CONFIG_JFFS2_ZLIB=y
+# CONFIG_JFFS2_LZO is not set
 CONFIG_JFFS2_RTIME=y
 # CONFIG_JFFS2_RUBIN is not set
 CONFIG_CRAMFS=m
+# CONFIG_SQUASHFS is not set
 # CONFIG_VXFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_OMFS_FS is not set
 # CONFIG_HPFS_FS is not set
 # CONFIG_QNX4FS_FS is not set
+# CONFIG_ROMFS_FS is not set
 # CONFIG_SYSV_FS is not set
 # CONFIG_UFS_FS is not set
-
-#
-# Network File Systems
-#
+CONFIG_NETWORK_FILESYSTEMS=y
 CONFIG_NFS_FS=y
 # CONFIG_NFS_V3 is not set
 # CONFIG_NFS_V4 is not set
-# CONFIG_NFS_DIRECTIO is not set
 CONFIG_NFSD=m
 # CONFIG_NFSD_V3 is not set
-CONFIG_NFSD_TCP=y
+# CONFIG_NFSD_V4 is not set
 CONFIG_LOCKD=y
 CONFIG_EXPORTFS=m
+CONFIG_NFS_COMMON=y
 CONFIG_SUNRPC=y
 # CONFIG_RPCSEC_GSS_KRB5 is not set
 # CONFIG_RPCSEC_GSS_SPKM3 is not set
@@ -831,10 +970,6 @@ CONFIG_SMB_FS=m
 #
 # CONFIG_PARTITION_ADVANCED is not set
 CONFIG_MSDOS_PARTITION=y
-
-#
-# Native Language Support
-#
 CONFIG_NLS=y
 CONFIG_NLS_DEFAULT="iso8859-1"
 # CONFIG_NLS_CODEPAGE_437 is not set
@@ -875,20 +1010,34 @@ CONFIG_NLS_DEFAULT="iso8859-1"
 # CONFIG_NLS_KOI8_R is not set
 # CONFIG_NLS_KOI8_U is not set
 # CONFIG_NLS_UTF8 is not set
-
-#
-# Profiling support
-#
-# CONFIG_PROFILING is not set
+# CONFIG_DLM is not set
 
 #
 # Kernel hacking
 #
 # CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_WARN_DEPRECATED=y
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_FRAME_WARN=1024
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_STRIP_ASM_SYMS is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
 # CONFIG_DEBUG_KERNEL is not set
-CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_SLUB_DEBUG_ON is not set
+# CONFIG_SLUB_STATS is not set
 CONFIG_DEBUG_BUGVERBOSE=y
+CONFIG_DEBUG_MEMORY_INIT=y
 CONFIG_FRAME_POINTER=y
+# CONFIG_RCU_CPU_STALL_DETECTOR is not set
+# CONFIG_LATENCYTOP is not set
+# CONFIG_SYSCTL_SYSCALL_CHECK is not set
+CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_TRACING_SUPPORT=y
+# CONFIG_FTRACE is not set
+# CONFIG_SAMPLES is not set
+CONFIG_HAVE_ARCH_KGDB=y
 # CONFIG_DEBUG_USER is not set
 
 #
@@ -896,21 +1045,120 @@ CONFIG_FRAME_POINTER=y
 #
 # CONFIG_KEYS is not set
 # CONFIG_SECURITY is not set
+# CONFIG_SECURITYFS is not set
+# CONFIG_SECURITY_FILE_CAPABILITIES is not set
+CONFIG_CRYPTO=y
+
+#
+# Crypto core or helper
+#
+# CONFIG_CRYPTO_FIPS is not set
+CONFIG_CRYPTO_ALGAPI=m
+CONFIG_CRYPTO_ALGAPI2=m
+CONFIG_CRYPTO_RNG=m
+CONFIG_CRYPTO_RNG2=m
+# CONFIG_CRYPTO_MANAGER is not set
+# CONFIG_CRYPTO_MANAGER2 is not set
+# CONFIG_CRYPTO_GF128MUL is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_CRYPTD is not set
+# CONFIG_CRYPTO_AUTHENC is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Authenticated Encryption with Associated Data
+#
+# CONFIG_CRYPTO_CCM is not set
+# CONFIG_CRYPTO_GCM is not set
+# CONFIG_CRYPTO_SEQIV is not set
+
+#
+# Block modes
+#
+# CONFIG_CRYPTO_CBC is not set
+# CONFIG_CRYPTO_CTR is not set
+# CONFIG_CRYPTO_CTS is not set
+# CONFIG_CRYPTO_ECB is not set
+# CONFIG_CRYPTO_LRW is not set
+# CONFIG_CRYPTO_PCBC is not set
+# CONFIG_CRYPTO_XTS is not set
+
+#
+# Hash modes
+#
+# CONFIG_CRYPTO_HMAC is not set
+# CONFIG_CRYPTO_XCBC is not set
+# CONFIG_CRYPTO_VMAC is not set
+
+#
+# Digest
+#
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_GHASH is not set
+# CONFIG_CRYPTO_MD4 is not set
+# CONFIG_CRYPTO_MD5 is not set
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_RMD128 is not set
+# CONFIG_CRYPTO_RMD160 is not set
+# CONFIG_CRYPTO_RMD256 is not set
+# CONFIG_CRYPTO_RMD320 is not set
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_WP512 is not set
+
+#
+# Ciphers
+#
+CONFIG_CRYPTO_AES=m
+# CONFIG_CRYPTO_ANUBIS is not set
+# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_CAMELLIA is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_DES is not set
+# CONFIG_CRYPTO_FCRYPT is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_SALSA20 is not set
+# CONFIG_CRYPTO_SEED is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_TWOFISH is not set
 
 #
-# Cryptographic options
+# Compression
 #
-# CONFIG_CRYPTO is not set
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_ZLIB is not set
+# CONFIG_CRYPTO_LZO is not set
 
 #
-# Hardware crypto devices
+# Random Number Generation
 #
+CONFIG_CRYPTO_ANSI_CPRNG=m
+CONFIG_CRYPTO_HW=y
+# CONFIG_BINARY_PRINTF is not set
 
 #
 # Library routines
 #
+CONFIG_BITREVERSE=y
+CONFIG_GENERIC_FIND_LAST_BIT=y
 CONFIG_CRC_CCITT=m
+# CONFIG_CRC16 is not set
+# CONFIG_CRC_T10DIF is not set
+# CONFIG_CRC_ITU_T is not set
 CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
 # CONFIG_LIBCRC32C is not set
 CONFIG_ZLIB_INFLATE=y
 CONFIG_ZLIB_DEFLATE=y
+CONFIG_DECOMPRESS_GZIP=y
+CONFIG_DECOMPRESS_BZIP2=y
+CONFIG_DECOMPRESS_LZMA=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
+CONFIG_NLATTR=y
diff --git a/arch/arm/configs/htcherald_defconfig b/arch/arm/configs/htcherald_defconfig
new file mode 100644 (file)
index 0000000..3382676
--- /dev/null
@@ -0,0 +1,1142 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.32-rc6
+# Sat Nov 14 10:56:01 2009
+#
+CONFIG_ARM=y
+CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+CONFIG_GENERIC_GPIO=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_ARCH_HAS_CPUFREQ=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
+CONFIG_VECTORS_BASE=0xffff0000
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_LOCK_KERNEL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_AUDIT is not set
+
+#
+# RCU Subsystem
+#
+CONFIG_TREE_RCU=y
+# CONFIG_TREE_PREEMPT_RCU is not set
+# CONFIG_RCU_TRACE is not set
+CONFIG_RCU_FANOUT=32
+# CONFIG_RCU_FANOUT_EXACT is not set
+# CONFIG_TREE_RCU_TRACE is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_GROUP_SCHED is not set
+# CONFIG_CGROUPS is not set
+# CONFIG_SYSFS_DEPRECATED_V2 is not set
+# CONFIG_RELAY is not set
+CONFIG_NAMESPACES=y
+# CONFIG_UTS_NS is not set
+# CONFIG_IPC_NS is not set
+# CONFIG_USER_NS is not set
+# CONFIG_PID_NS is not set
+# CONFIG_NET_NS is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_RD_GZIP=y
+CONFIG_RD_BZIP2=y
+CONFIG_RD_LZMA=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+CONFIG_ANON_INODES=y
+# CONFIG_EMBEDDED is not set
+CONFIG_UID16=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_AIO=y
+
+#
+# Kernel Performance Events And Counters
+#
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_COMPAT_BRK=y
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
+# CONFIG_PROFILING is not set
+CONFIG_HAVE_OPROFILE=y
+# CONFIG_KPROBES is not set
+CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_KRETPROBES=y
+CONFIG_HAVE_CLK=y
+
+#
+# GCOV-based kernel profiling
+#
+# CONFIG_SLOW_WORK is not set
+CONFIG_HAVE_GENERIC_DMA_COHERENT=y
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+# CONFIG_MODULE_FORCE_LOAD is not set
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_BLOCK=y
+CONFIG_LBDAF=y
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_BLK_DEV_INTEGRITY is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_DEFAULT_AS is not set
+# CONFIG_DEFAULT_DEADLINE is not set
+CONFIG_DEFAULT_CFQ=y
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="cfq"
+CONFIG_FREEZER=y
+
+#
+# System Type
+#
+CONFIG_MMU=y
+# CONFIG_ARCH_AAEC2000 is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_REALVIEW is not set
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_AT91 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_GEMINI is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_EP93XX is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_MXC is not set
+# CONFIG_ARCH_STMP3XXX is not set
+# CONFIG_ARCH_NETX is not set
+# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_NOMADIK is not set
+# CONFIG_ARCH_IOP13XX is not set
+# CONFIG_ARCH_IOP32X is not set
+# CONFIG_ARCH_IOP33X is not set
+# CONFIG_ARCH_IXP23XX is not set
+# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_KIRKWOOD is not set
+# CONFIG_ARCH_LOKI is not set
+# CONFIG_ARCH_MV78XX0 is not set
+# CONFIG_ARCH_ORION5X is not set
+# CONFIG_ARCH_MMP is not set
+# CONFIG_ARCH_KS8695 is not set
+# CONFIG_ARCH_NS9XXX is not set
+# CONFIG_ARCH_W90X900 is not set
+# CONFIG_ARCH_PNX4008 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_MSM is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_S3C64XX is not set
+# CONFIG_ARCH_S5PC1XX is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_U300 is not set
+# CONFIG_ARCH_DAVINCI is not set
+CONFIG_ARCH_OMAP=y
+# CONFIG_ARCH_BCMRING is not set
+
+#
+# TI OMAP Implementations
+#
+CONFIG_ARCH_OMAP_OTG=y
+CONFIG_ARCH_OMAP1=y
+# CONFIG_ARCH_OMAP2 is not set
+# CONFIG_ARCH_OMAP3 is not set
+# CONFIG_ARCH_OMAP4 is not set
+
+#
+# OMAP Feature Selections
+#
+# CONFIG_OMAP_RESET_CLOCKS is not set
+# CONFIG_OMAP_MUX is not set
+CONFIG_OMAP_MCBSP=y
+# CONFIG_OMAP_MBOX_FWK is not set
+CONFIG_OMAP_MPU_TIMER=y
+# CONFIG_OMAP_32K_TIMER is not set
+CONFIG_OMAP_LL_DEBUG_UART1=y
+# CONFIG_OMAP_LL_DEBUG_UART2 is not set
+# CONFIG_OMAP_LL_DEBUG_UART3 is not set
+# CONFIG_OMAP_LL_DEBUG_NONE is not set
+# CONFIG_OMAP_PM_NONE is not set
+CONFIG_OMAP_PM_NOOP=y
+
+#
+# OMAP Core Type
+#
+# CONFIG_ARCH_OMAP730 is not set
+CONFIG_ARCH_OMAP850=y
+# CONFIG_ARCH_OMAP15XX is not set
+# CONFIG_ARCH_OMAP16XX is not set
+
+#
+# OMAP Board Type
+#
+# CONFIG_MACH_OMAP_HTCWIZARD is not set
+CONFIG_MACH_HERALD=y
+
+#
+# OMAP CPU Speed
+#
+# CONFIG_OMAP_CLOCKS_SET_BY_BOOTLOADER is not set
+CONFIG_OMAP_ARM_195MHZ=y
+# CONFIG_OMAP_ARM_182MHZ is not set
+# CONFIG_OMAP_ARM_168MHZ is not set
+# CONFIG_OMAP_ARM_120MHZ is not set
+# CONFIG_OMAP_ARM_60MHZ is not set
+# CONFIG_OMAP_ARM_30MHZ is not set
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_ARM925T=y
+CONFIG_CPU_ARM926T=y
+CONFIG_CPU_32v4T=y
+CONFIG_CPU_32v5=y
+CONFIG_CPU_ABRT_EV4T=y
+CONFIG_CPU_ABRT_EV5TJ=y
+CONFIG_CPU_PABRT_LEGACY=y
+CONFIG_CPU_CACHE_V4WT=y
+CONFIG_CPU_CACHE_VIVT=y
+CONFIG_CPU_COPY_V4WB=y
+CONFIG_CPU_TLB_V4WBI=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
+
+#
+# Processor Features
+#
+CONFIG_ARM_THUMB=y
+# CONFIG_CPU_ICACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_DISABLE is not set
+CONFIG_CPU_DCACHE_WRITETHROUGH=y
+# CONFIG_CPU_CACHE_ROUND_ROBIN is not set
+CONFIG_ARM_L1_CACHE_SHIFT=5
+CONFIG_COMMON_CLKDEV=y
+
+#
+# Bus support
+#
+# CONFIG_PCI_SYSCALL is not set
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+# CONFIG_NO_HZ is not set
+# CONFIG_HIGH_RES_TIMERS is not set
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+CONFIG_VMSPLIT_3G=y
+# CONFIG_VMSPLIT_2G is not set
+# CONFIG_VMSPLIT_1G is not set
+CONFIG_PAGE_OFFSET=0xC0000000
+# CONFIG_PREEMPT_NONE is not set
+# CONFIG_PREEMPT_VOLUNTARY is not set
+CONFIG_PREEMPT=y
+CONFIG_HZ=100
+CONFIG_AEABI=y
+CONFIG_OABI_COMPAT=y
+# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set
+# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set
+# CONFIG_HIGHMEM is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+CONFIG_PAGEFLAGS_EXTENDED=y
+CONFIG_SPLIT_PTLOCK_CPUS=4096
+# CONFIG_PHYS_ADDR_T_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=0
+CONFIG_VIRT_TO_BUS=y
+CONFIG_HAVE_MLOCK=y
+CONFIG_HAVE_MLOCKED_PAGE_BIT=y
+# CONFIG_KSM is not set
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
+CONFIG_LEDS=y
+CONFIG_ALIGNMENT_TRAP=y
+# CONFIG_UACCESS_WITH_MEMCPY is not set
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="mem=32M console=ttyS0,115200 ip=dhcp"
+# CONFIG_XIP_KERNEL is not set
+# CONFIG_KEXEC is not set
+
+#
+# CPU Power Management
+#
+# CONFIG_CPU_FREQ is not set
+# CONFIG_CPU_IDLE is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
+# CONFIG_FPE_FASTFPE is not set
+# CONFIG_VFP is not set
+
+#
+# Userspace binary formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_HAVE_AOUT=y
+# CONFIG_BINFMT_AOUT is not set
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Power management options
+#
+CONFIG_PM=y
+# CONFIG_PM_DEBUG is not set
+CONFIG_PM_SLEEP=y
+CONFIG_SUSPEND=y
+CONFIG_SUSPEND_FREEZER=y
+# CONFIG_APM_EMULATION is not set
+# CONFIG_PM_RUNTIME is not set
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_MIGRATE is not set
+# CONFIG_XFRM_STATISTICS is not set
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
+CONFIG_INET_LRO=y
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# CONFIG_RDS is not set
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_NET_DSA is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_PHONET is not set
+# CONFIG_IEEE802154 is not set
+# CONFIG_NET_SCHED is not set
+# CONFIG_DCB is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_CAN is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+CONFIG_WIRELESS=y
+# CONFIG_CFG80211 is not set
+CONFIG_CFG80211_DEFAULT_PS_VALUE=0
+# CONFIG_WIRELESS_OLD_REGULATORY is not set
+# CONFIG_WIRELESS_EXT is not set
+# CONFIG_LIB80211 is not set
+
+#
+# CFG80211 needs to be enabled for MAC80211
+#
+# CONFIG_WIMAX is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+# CONFIG_DEVTMPFS is not set
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=y
+CONFIG_FIRMWARE_IN_KERNEL=y
+CONFIG_EXTRA_FIRMWARE=""
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_CONNECTOR is not set
+# CONFIG_MTD is not set
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=8192
+# CONFIG_BLK_DEV_XIP is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+# CONFIG_MG_DISK is not set
+CONFIG_MISC_DEVICES=y
+# CONFIG_ENCLOSURE_SERVICES is not set
+# CONFIG_C2PORT is not set
+
+#
+# EEPROM support
+#
+# CONFIG_EEPROM_93CX6 is not set
+CONFIG_HAVE_IDE=y
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+# CONFIG_SCSI is not set
+# CONFIG_SCSI_DMA is not set
+# CONFIG_SCSI_NETLINK is not set
+# CONFIG_ATA is not set
+# CONFIG_MD is not set
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_VETH is not set
+# CONFIG_PHYLIB is not set
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_AX88796 is not set
+CONFIG_SMC91X=y
+# CONFIG_DM9000 is not set
+# CONFIG_ETHOC is not set
+# CONFIG_SMC911X is not set
+# CONFIG_SMSC911X is not set
+# CONFIG_DNET is not set
+# CONFIG_IBM_NEW_EMAC_ZMII is not set
+# CONFIG_IBM_NEW_EMAC_RGMII is not set
+# CONFIG_IBM_NEW_EMAC_TAH is not set
+# CONFIG_IBM_NEW_EMAC_EMAC4 is not set
+# CONFIG_IBM_NEW_EMAC_NO_FLOW_CTRL is not set
+# CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT is not set
+# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
+# CONFIG_B44 is not set
+# CONFIG_KS8842 is not set
+# CONFIG_KS8851_MLL is not set
+CONFIG_NETDEV_1000=y
+CONFIG_NETDEV_10000=y
+CONFIG_WLAN=y
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
+
+#
+# Enable WiMAX (Networking options) to see the WiMAX drivers
+#
+# CONFIG_WAN is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_ISDN is not set
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+# CONFIG_KEYBOARD_ATKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_GPIO is not set
+# CONFIG_KEYBOARD_MATRIX is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+# CONFIG_KEYBOARD_OPENCORES is not set
+# CONFIG_KEYBOARD_STOWAWAY is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+CONFIG_KEYBOARD_OMAP=y
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+CONFIG_SERIO_SERPORT=y
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_CONSOLE_TRANSLATIONS=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
+CONFIG_DEVKMEM=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=m
+CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+# CONFIG_SERIAL_8250_EXTENDED is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=m
+CONFIG_UNIX98_PTYS=y
+# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_IPMI_HANDLER is not set
+CONFIG_HW_RANDOM=m
+# CONFIG_HW_RANDOM_TIMERIOMEM is not set
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+# CONFIG_I2C is not set
+# CONFIG_SPI is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
+CONFIG_ARCH_REQUIRE_GPIOLIB=y
+CONFIG_GPIOLIB=y
+# CONFIG_GPIO_SYSFS is not set
+
+#
+# Memory mapped GPIO expanders:
+#
+
+#
+# I2C GPIO expanders:
+#
+
+#
+# PCI GPIO expanders:
+#
+
+#
+# SPI GPIO expanders:
+#
+
+#
+# AC97 GPIO expanders:
+#
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
+
+#
+# Native drivers
+#
+# CONFIG_SENSORS_F71805F is not set
+# CONFIG_SENSORS_F71882FG is not set
+# CONFIG_SENSORS_IT87 is not set
+# CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_PC87427 is not set
+# CONFIG_SENSORS_SHT15 is not set
+# CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_VT1211 is not set
+# CONFIG_SENSORS_W83627HF is not set
+# CONFIG_SENSORS_W83627EHF is not set
+# CONFIG_THERMAL is not set
+# CONFIG_WATCHDOG is not set
+CONFIG_SSB_POSSIBLE=y
+
+#
+# Sonics Silicon Backplane
+#
+# CONFIG_SSB is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_CORE is not set
+# CONFIG_MFD_SM501 is not set
+# CONFIG_MFD_ASIC3 is not set
+# CONFIG_HTC_EGPIO is not set
+# CONFIG_HTC_PASIC3 is not set
+# CONFIG_MFD_TMIO is not set
+# CONFIG_MFD_T7L66XB is not set
+# CONFIG_MFD_TC6387XB is not set
+# CONFIG_MFD_TC6393XB is not set
+# CONFIG_REGULATOR is not set
+# CONFIG_MEDIA_SUPPORT is not set
+
+#
+# Graphics support
+#
+# CONFIG_VGASTATE is not set
+CONFIG_VIDEO_OUTPUT_CONTROL=m
+CONFIG_FB=y
+# CONFIG_FIRMWARE_EDID is not set
+# CONFIG_FB_DDC is not set
+# CONFIG_FB_BOOT_VESA_SUPPORT is not set
+CONFIG_FB_CFB_FILLRECT=y
+CONFIG_FB_CFB_COPYAREA=y
+CONFIG_FB_CFB_IMAGEBLIT=y
+# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
+# CONFIG_FB_SYS_FILLRECT is not set
+# CONFIG_FB_SYS_COPYAREA is not set
+# CONFIG_FB_SYS_IMAGEBLIT is not set
+# CONFIG_FB_FOREIGN_ENDIAN is not set
+# CONFIG_FB_SYS_FOPS is not set
+# CONFIG_FB_SVGALIB is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_BACKLIGHT is not set
+CONFIG_FB_MODE_HELPERS=y
+# CONFIG_FB_TILEBLITTING is not set
+
+#
+# Frame buffer hardware drivers
+#
+# CONFIG_FB_S1D13XXX is not set
+# CONFIG_FB_VIRTUAL is not set
+# CONFIG_FB_METRONOME is not set
+# CONFIG_FB_MB862XX is not set
+# CONFIG_FB_BROADSHEET is not set
+CONFIG_FB_OMAP=y
+# CONFIG_FB_OMAP_LCDC_EXTERNAL is not set
+# CONFIG_FB_OMAP_BOOTLOADER_INIT is not set
+CONFIG_FB_OMAP_CONSISTENT_DMA_SIZE=2
+# CONFIG_FB_OMAP_DMA_TUNE is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set
+CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y
+CONFIG_FONTS=y
+# CONFIG_FONT_8x8 is not set
+# CONFIG_FONT_8x16 is not set
+# CONFIG_FONT_6x11 is not set
+# CONFIG_FONT_7x14 is not set
+# CONFIG_FONT_PEARL_8x8 is not set
+# CONFIG_FONT_ACORN_8x8 is not set
+CONFIG_FONT_MINI_4x6=y
+# CONFIG_FONT_SUN8x16 is not set
+# CONFIG_FONT_SUN12x22 is not set
+# CONFIG_FONT_10x18 is not set
+# CONFIG_LOGO is not set
+# CONFIG_SOUND is not set
+CONFIG_HID_SUPPORT=y
+CONFIG_HID=y
+# CONFIG_HIDRAW is not set
+# CONFIG_HID_PID is not set
+
+#
+# Special HID drivers
+#
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+# CONFIG_USB_ARCH_HAS_EHCI is not set
+# CONFIG_USB is not set
+# CONFIG_USB_MUSB_HDRC is not set
+# CONFIG_USB_GADGET_MUSB_HDRC is not set
+
+#
+# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may
+#
+CONFIG_USB_GADGET=y
+# CONFIG_USB_GADGET_DEBUG_FILES is not set
+CONFIG_USB_GADGET_VBUS_DRAW=2
+CONFIG_USB_GADGET_SELECTED=y
+# CONFIG_USB_GADGET_AT91 is not set
+# CONFIG_USB_GADGET_ATMEL_USBA is not set
+# CONFIG_USB_GADGET_FSL_USB2 is not set
+# CONFIG_USB_GADGET_LH7A40X is not set
+CONFIG_USB_GADGET_OMAP=y
+CONFIG_USB_OMAP=y
+# CONFIG_USB_GADGET_PXA25X is not set
+# CONFIG_USB_GADGET_R8A66597 is not set
+# CONFIG_USB_GADGET_PXA27X is not set
+# CONFIG_USB_GADGET_S3C_HSOTG is not set
+# CONFIG_USB_GADGET_IMX is not set
+# CONFIG_USB_GADGET_S3C2410 is not set
+# CONFIG_USB_GADGET_M66592 is not set
+# CONFIG_USB_GADGET_AMD5536UDC is not set
+# CONFIG_USB_GADGET_FSL_QE is not set
+# CONFIG_USB_GADGET_CI13XXX is not set
+# CONFIG_USB_GADGET_NET2280 is not set
+# CONFIG_USB_GADGET_GOKU is not set
+# CONFIG_USB_GADGET_LANGWELL is not set
+# CONFIG_USB_GADGET_DUMMY_HCD is not set
+# CONFIG_USB_GADGET_DUALSPEED is not set
+# CONFIG_USB_ZERO is not set
+# CONFIG_USB_AUDIO is not set
+CONFIG_USB_ETH=y
+# CONFIG_USB_ETH_RNDIS is not set
+# CONFIG_USB_ETH_EEM is not set
+# CONFIG_USB_GADGETFS is not set
+# CONFIG_USB_FILE_STORAGE is not set
+# CONFIG_USB_G_SERIAL is not set
+# CONFIG_USB_MIDI_GADGET is not set
+# CONFIG_USB_G_PRINTER is not set
+# CONFIG_USB_CDC_COMPOSITE is not set
+
+#
+# OTG and related infrastructure
+#
+CONFIG_USB_OTG_UTILS=y
+# CONFIG_USB_GPIO_VBUS is not set
+# CONFIG_NOP_USB_XCEIV is not set
+CONFIG_MMC=y
+# CONFIG_MMC_DEBUG is not set
+# CONFIG_MMC_UNSAFE_RESUME is not set
+
+#
+# MMC/SD/SDIO Card Drivers
+#
+CONFIG_MMC_BLOCK=y
+CONFIG_MMC_BLOCK_BOUNCE=y
+# CONFIG_SDIO_UART is not set
+# CONFIG_MMC_TEST is not set
+
+#
+# MMC/SD/SDIO Host Controller Drivers
+#
+CONFIG_MMC_SDHCI=y
+CONFIG_MMC_SDHCI_PLTFM=y
+CONFIG_MMC_OMAP=y
+# CONFIG_MMC_AT91 is not set
+# CONFIG_MMC_ATMELMCI is not set
+# CONFIG_MEMSTICK is not set
+# CONFIG_NEW_LEDS is not set
+# CONFIG_ACCESSIBILITY is not set
+CONFIG_RTC_LIB=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_HCTOSYS=y
+CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
+# CONFIG_RTC_DEBUG is not set
+
+#
+# RTC interfaces
+#
+CONFIG_RTC_INTF_SYSFS=y
+CONFIG_RTC_INTF_PROC=y
+CONFIG_RTC_INTF_DEV=y
+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+# CONFIG_RTC_DRV_TEST is not set
+
+#
+# SPI RTC drivers
+#
+
+#
+# Platform RTC drivers
+#
+# CONFIG_RTC_DRV_CMOS is not set
+# CONFIG_RTC_DRV_DS1286 is not set
+# CONFIG_RTC_DRV_DS1511 is not set
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+# CONFIG_RTC_DRV_STK17TA8 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_M48T35 is not set
+# CONFIG_RTC_DRV_M48T59 is not set
+# CONFIG_RTC_DRV_BQ4802 is not set
+# CONFIG_RTC_DRV_V3020 is not set
+
+#
+# on-CPU RTC drivers
+#
+# CONFIG_DMADEVICES is not set
+# CONFIG_AUXDISPLAY is not set
+# CONFIG_UIO is not set
+
+#
+# TI VLYNQ
+#
+# CONFIG_STAGING is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
+CONFIG_EXT3_FS_XATTR=y
+# CONFIG_EXT3_FS_POSIX_ACL is not set
+# CONFIG_EXT3_FS_SECURITY is not set
+# CONFIG_EXT4_FS is not set
+CONFIG_JBD=y
+CONFIG_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_BTRFS_FS is not set
+# CONFIG_NILFS2_FS is not set
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
+CONFIG_DNOTIFY=y
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# Caches
+#
+# CONFIG_FSCACHE is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+# CONFIG_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLB_PAGE is not set
+# CONFIG_CONFIGFS_FS is not set
+CONFIG_MISC_FILESYSTEMS=y
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_SQUASHFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_OMFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+CONFIG_NETWORK_FILESYSTEMS=y
+CONFIG_NFS_FS=y
+# CONFIG_NFS_V3 is not set
+# CONFIG_NFS_V4 is not set
+CONFIG_ROOT_NFS=y
+# CONFIG_NFSD is not set
+CONFIG_LOCKD=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_NLS is not set
+# CONFIG_DLM is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_WARN_DEPRECATED=y
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_FRAME_WARN=1024
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_STRIP_ASM_SYMS is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+# CONFIG_DEBUG_KERNEL is not set
+CONFIG_DEBUG_BUGVERBOSE=y
+CONFIG_DEBUG_MEMORY_INIT=y
+# CONFIG_RCU_CPU_STALL_DETECTOR is not set
+# CONFIG_LATENCYTOP is not set
+# CONFIG_SYSCTL_SYSCALL_CHECK is not set
+CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_TRACING_SUPPORT=y
+# CONFIG_FTRACE is not set
+# CONFIG_SAMPLES is not set
+CONFIG_HAVE_ARCH_KGDB=y
+CONFIG_ARM_UNWIND=y
+# CONFIG_DEBUG_USER is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+# CONFIG_SECURITYFS is not set
+# CONFIG_SECURITY_FILE_CAPABILITIES is not set
+CONFIG_CRYPTO=y
+
+#
+# Crypto core or helper
+#
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_ALGAPI2=y
+CONFIG_CRYPTO_PCOMP=y
+# CONFIG_CRYPTO_MANAGER is not set
+# CONFIG_CRYPTO_MANAGER2 is not set
+# CONFIG_CRYPTO_GF128MUL is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_CRYPTD is not set
+# CONFIG_CRYPTO_AUTHENC is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Authenticated Encryption with Associated Data
+#
+# CONFIG_CRYPTO_CCM is not set
+# CONFIG_CRYPTO_GCM is not set
+# CONFIG_CRYPTO_SEQIV is not set
+
+#
+# Block modes
+#
+# CONFIG_CRYPTO_CBC is not set
+# CONFIG_CRYPTO_CTR is not set
+# CONFIG_CRYPTO_CTS is not set
+# CONFIG_CRYPTO_ECB is not set
+# CONFIG_CRYPTO_LRW is not set
+# CONFIG_CRYPTO_PCBC is not set
+# CONFIG_CRYPTO_XTS is not set
+
+#
+# Hash modes
+#
+# CONFIG_CRYPTO_HMAC is not set
+# CONFIG_CRYPTO_XCBC is not set
+# CONFIG_CRYPTO_VMAC is not set
+
+#
+# Digest
+#
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_GHASH is not set
+# CONFIG_CRYPTO_MD4 is not set
+# CONFIG_CRYPTO_MD5 is not set
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_RMD128 is not set
+# CONFIG_CRYPTO_RMD160 is not set
+# CONFIG_CRYPTO_RMD256 is not set
+# CONFIG_CRYPTO_RMD320 is not set
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_WP512 is not set
+
+#
+# Ciphers
+#
+# CONFIG_CRYPTO_AES is not set
+# CONFIG_CRYPTO_ANUBIS is not set
+# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_CAMELLIA is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_DES is not set
+# CONFIG_CRYPTO_FCRYPT is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_SALSA20 is not set
+# CONFIG_CRYPTO_SEED is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+
+#
+# Compression
+#
+CONFIG_CRYPTO_DEFLATE=y
+CONFIG_CRYPTO_ZLIB=y
+CONFIG_CRYPTO_LZO=y
+
+#
+# Random Number Generation
+#
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
+CONFIG_CRYPTO_HW=y
+# CONFIG_BINARY_PRINTF is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+CONFIG_GENERIC_FIND_LAST_BIT=y
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+# CONFIG_CRC_T10DIF is not set
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_LZO_COMPRESS=y
+CONFIG_LZO_DECOMPRESS=y
+CONFIG_DECOMPRESS_GZIP=y
+CONFIG_DECOMPRESS_BZIP2=y
+CONFIG_DECOMPRESS_LZMA=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
+CONFIG_NLATTR=y
diff --git a/arch/arm/configs/igep0020_defconfig b/arch/arm/configs/igep0020_defconfig
new file mode 100644 (file)
index 0000000..c97f8d0
--- /dev/null
@@ -0,0 +1,1554 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.32-rc6
+# Fri Nov 13 12:01:17 2009
+#
+CONFIG_ARM=y
+CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+CONFIG_GENERIC_GPIO=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_ARCH_HAS_CPUFREQ=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
+CONFIG_VECTORS_BASE=0xffff0000
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+# CONFIG_POSIX_MQUEUE is not set
+CONFIG_BSD_PROCESS_ACCT=y
+# CONFIG_BSD_PROCESS_ACCT_V3 is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_AUDIT is not set
+
+#
+# RCU Subsystem
+#
+CONFIG_TREE_RCU=y
+# CONFIG_TREE_PREEMPT_RCU is not set
+# CONFIG_RCU_TRACE is not set
+CONFIG_RCU_FANOUT=32
+# CONFIG_RCU_FANOUT_EXACT is not set
+# CONFIG_TREE_RCU_TRACE is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=17
+CONFIG_GROUP_SCHED=y
+CONFIG_FAIR_GROUP_SCHED=y
+# CONFIG_RT_GROUP_SCHED is not set
+CONFIG_USER_SCHED=y
+# CONFIG_CGROUP_SCHED is not set
+# CONFIG_CGROUPS is not set
+# CONFIG_SYSFS_DEPRECATED_V2 is not set
+# CONFIG_RELAY is not set
+# CONFIG_NAMESPACES is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_RD_GZIP=y
+# CONFIG_RD_BZIP2 is not set
+# CONFIG_RD_LZMA is not set
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+CONFIG_ANON_INODES=y
+CONFIG_EMBEDDED=y
+CONFIG_UID16=y
+# CONFIG_SYSCTL_SYSCALL is not set
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+CONFIG_KALLSYMS_EXTRA_PASS=y
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_AIO=y
+
+#
+# Kernel Performance Events And Counters
+#
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_COMPAT_BRK=y
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
+# CONFIG_PROFILING is not set
+CONFIG_HAVE_OPROFILE=y
+# CONFIG_KPROBES is not set
+CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_KRETPROBES=y
+CONFIG_HAVE_CLK=y
+
+#
+# GCOV-based kernel profiling
+#
+# CONFIG_SLOW_WORK is not set
+CONFIG_HAVE_GENERIC_DMA_COHERENT=y
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+# CONFIG_MODULE_FORCE_LOAD is not set
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_BLOCK=y
+CONFIG_LBDAF=y
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_BLK_DEV_INTEGRITY is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+CONFIG_DEFAULT_AS=y
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="anticipatory"
+# CONFIG_FREEZER is not set
+
+#
+# System Type
+#
+CONFIG_MMU=y
+# CONFIG_ARCH_AAEC2000 is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_REALVIEW is not set
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_AT91 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_GEMINI is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_EP93XX is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_MXC is not set
+# CONFIG_ARCH_STMP3XXX is not set
+# CONFIG_ARCH_NETX is not set
+# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_NOMADIK is not set
+# CONFIG_ARCH_IOP13XX is not set
+# CONFIG_ARCH_IOP32X is not set
+# CONFIG_ARCH_IOP33X is not set
+# CONFIG_ARCH_IXP23XX is not set
+# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_KIRKWOOD is not set
+# CONFIG_ARCH_LOKI is not set
+# CONFIG_ARCH_MV78XX0 is not set
+# CONFIG_ARCH_ORION5X is not set
+# CONFIG_ARCH_MMP is not set
+# CONFIG_ARCH_KS8695 is not set
+# CONFIG_ARCH_NS9XXX is not set
+# CONFIG_ARCH_W90X900 is not set
+# CONFIG_ARCH_PNX4008 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_MSM is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_S3C64XX is not set
+# CONFIG_ARCH_S5PC1XX is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_U300 is not set
+# CONFIG_ARCH_DAVINCI is not set
+CONFIG_ARCH_OMAP=y
+# CONFIG_ARCH_BCMRING is not set
+
+#
+# TI OMAP Implementations
+#
+CONFIG_ARCH_OMAP_OTG=y
+# CONFIG_ARCH_OMAP1 is not set
+# CONFIG_ARCH_OMAP2 is not set
+CONFIG_ARCH_OMAP3=y
+# CONFIG_ARCH_OMAP4 is not set
+
+#
+# OMAP Feature Selections
+#
+# CONFIG_OMAP_DEBUG_POWERDOMAIN is not set
+# CONFIG_OMAP_DEBUG_CLOCKDOMAIN is not set
+# CONFIG_OMAP_RESET_CLOCKS is not set
+CONFIG_OMAP_MUX=y
+CONFIG_OMAP_MUX_DEBUG=y
+CONFIG_OMAP_MUX_WARNINGS=y
+CONFIG_OMAP_MCBSP=y
+# CONFIG_OMAP_MBOX_FWK is not set
+# CONFIG_OMAP_MPU_TIMER is not set
+CONFIG_OMAP_32K_TIMER=y
+CONFIG_OMAP_32K_TIMER_HZ=128
+CONFIG_OMAP_DM_TIMER=y
+# CONFIG_OMAP_LL_DEBUG_UART1 is not set
+# CONFIG_OMAP_LL_DEBUG_UART2 is not set
+CONFIG_OMAP_LL_DEBUG_UART3=y
+# CONFIG_OMAP_LL_DEBUG_NONE is not set
+# CONFIG_OMAP_PM_NONE is not set
+CONFIG_OMAP_PM_NOOP=y
+CONFIG_ARCH_OMAP34XX=y
+CONFIG_ARCH_OMAP3430=y
+
+#
+# OMAP Board Type
+#
+# CONFIG_MACH_OMAP3_BEAGLE is not set
+# CONFIG_MACH_OMAP_LDP is not set
+# CONFIG_MACH_OVERO is not set
+# CONFIG_MACH_OMAP3EVM is not set
+# CONFIG_MACH_OMAP3517EVM is not set
+# CONFIG_MACH_OMAP3_PANDORA is not set
+# CONFIG_MACH_OMAP_3430SDP is not set
+# CONFIG_MACH_NOKIA_RX51 is not set
+# CONFIG_MACH_OMAP_ZOOM2 is not set
+# CONFIG_MACH_CM_T35 is not set
+# CONFIG_MACH_OMAP_ZOOM3 is not set
+# CONFIG_MACH_OMAP_3630SDP is not set
+CONFIG_MACH_IGEP0020=y
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_32v6K=y
+CONFIG_CPU_V7=y
+CONFIG_CPU_32v7=y
+CONFIG_CPU_ABRT_EV7=y
+CONFIG_CPU_PABRT_V7=y
+CONFIG_CPU_CACHE_V7=y
+CONFIG_CPU_CACHE_VIPT=y
+CONFIG_CPU_COPY_V6=y
+CONFIG_CPU_TLB_V7=y
+CONFIG_CPU_HAS_ASID=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
+
+#
+# Processor Features
+#
+CONFIG_ARM_THUMB=y
+CONFIG_ARM_THUMBEE=y
+# CONFIG_CPU_ICACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_DISABLE is not set
+# CONFIG_CPU_BPREDICT_DISABLE is not set
+CONFIG_HAS_TLS_REG=y
+CONFIG_ARM_L1_CACHE_SHIFT=6
+# CONFIG_ARM_ERRATA_430973 is not set
+# CONFIG_ARM_ERRATA_458693 is not set
+# CONFIG_ARM_ERRATA_460075 is not set
+CONFIG_COMMON_CLKDEV=y
+
+#
+# Bus support
+#
+# CONFIG_PCI_SYSCALL is not set
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+CONFIG_TICK_ONESHOT=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+CONFIG_VMSPLIT_3G=y
+# CONFIG_VMSPLIT_2G is not set
+# CONFIG_VMSPLIT_1G is not set
+CONFIG_PAGE_OFFSET=0xC0000000
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+CONFIG_HZ=128
+# CONFIG_THUMB2_KERNEL is not set
+CONFIG_AEABI=y
+# CONFIG_OABI_COMPAT is not set
+# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set
+# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set
+# CONFIG_HIGHMEM is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+CONFIG_PAGEFLAGS_EXTENDED=y
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_PHYS_ADDR_T_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=0
+CONFIG_VIRT_TO_BUS=y
+CONFIG_HAVE_MLOCK=y
+CONFIG_HAVE_MLOCKED_PAGE_BIT=y
+# CONFIG_KSM is not set
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
+# CONFIG_LEDS is not set
+CONFIG_ALIGNMENT_TRAP=y
+# CONFIG_UACCESS_WITH_MEMCPY is not set
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE=""
+# CONFIG_XIP_KERNEL is not set
+# CONFIG_KEXEC is not set
+
+#
+# CPU Power Management
+#
+# CONFIG_CPU_FREQ is not set
+# CONFIG_CPU_IDLE is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+CONFIG_VFP=y
+CONFIG_VFPv3=y
+CONFIG_NEON=y
+
+#
+# Userspace binary formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_HAVE_AOUT=y
+# CONFIG_BINFMT_AOUT is not set
+CONFIG_BINFMT_MISC=y
+
+#
+# Power management options
+#
+# CONFIG_PM is not set
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+CONFIG_XFRM_USER=y
+# CONFIG_XFRM_SUB_POLICY is not set
+CONFIG_XFRM_MIGRATE=y
+# CONFIG_XFRM_STATISTICS is not set
+CONFIG_NET_KEY=y
+CONFIG_NET_KEY_MIGRATE=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+CONFIG_IP_PNP_RARP=y
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
+# CONFIG_INET_LRO is not set
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# CONFIG_RDS is not set
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_NET_DSA is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_PHONET is not set
+# CONFIG_IEEE802154 is not set
+# CONFIG_NET_SCHED is not set
+# CONFIG_DCB is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_CAN is not set
+# CONFIG_IRDA is not set
+CONFIG_BT=m
+CONFIG_BT_L2CAP=m
+CONFIG_BT_SCO=m
+CONFIG_BT_RFCOMM=m
+CONFIG_BT_RFCOMM_TTY=y
+CONFIG_BT_BNEP=m
+CONFIG_BT_BNEP_MC_FILTER=y
+CONFIG_BT_BNEP_PROTO_FILTER=y
+CONFIG_BT_HIDP=m
+
+#
+# Bluetooth device drivers
+#
+CONFIG_BT_HCIBTUSB=m
+# CONFIG_BT_HCIBTSDIO is not set
+CONFIG_BT_HCIUART=m
+CONFIG_BT_HCIUART_H4=y
+CONFIG_BT_HCIUART_BCSP=y
+CONFIG_BT_HCIUART_LL=y
+CONFIG_BT_HCIBCM203X=m
+CONFIG_BT_HCIBPA10X=m
+CONFIG_BT_HCIBFUSB=m
+CONFIG_BT_HCIVHCI=m
+CONFIG_BT_MRVL=m
+CONFIG_BT_MRVL_SDIO=m
+# CONFIG_AF_RXRPC is not set
+CONFIG_WIRELESS=y
+CONFIG_CFG80211=m
+# CONFIG_NL80211_TESTMODE is not set
+# CONFIG_CFG80211_DEVELOPER_WARNINGS is not set
+# CONFIG_CFG80211_REG_DEBUG is not set
+CONFIG_CFG80211_DEFAULT_PS=y
+CONFIG_CFG80211_DEFAULT_PS_VALUE=1
+# CONFIG_WIRELESS_OLD_REGULATORY is not set
+CONFIG_WIRELESS_EXT=y
+CONFIG_WIRELESS_EXT_SYSFS=y
+CONFIG_LIB80211=m
+CONFIG_LIB80211_CRYPT_WEP=m
+CONFIG_LIB80211_CRYPT_CCMP=m
+CONFIG_LIB80211_CRYPT_TKIP=m
+# CONFIG_LIB80211_DEBUG is not set
+CONFIG_MAC80211=m
+# CONFIG_MAC80211_RC_PID is not set
+CONFIG_MAC80211_RC_MINSTREL=y
+# CONFIG_MAC80211_RC_DEFAULT_PID is not set
+CONFIG_MAC80211_RC_DEFAULT_MINSTREL=y
+CONFIG_MAC80211_RC_DEFAULT="minstrel"
+# CONFIG_MAC80211_MESH is not set
+# CONFIG_MAC80211_LEDS is not set
+# CONFIG_MAC80211_DEBUG_MENU is not set
+# CONFIG_WIMAX is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+# CONFIG_DEVTMPFS is not set
+# CONFIG_STANDALONE is not set
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=y
+CONFIG_FIRMWARE_IN_KERNEL=y
+CONFIG_EXTRA_FIRMWARE=""
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES is not set
+# CONFIG_SYS_HYPERVISOR is not set
+CONFIG_CONNECTOR=y
+CONFIG_PROC_EVENTS=y
+# CONFIG_MTD is not set
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_UB is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=16384
+# CONFIG_BLK_DEV_XIP is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+# CONFIG_MG_DISK is not set
+# CONFIG_MISC_DEVICES is not set
+CONFIG_EEPROM_93CX6=m
+CONFIG_HAVE_IDE=y
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=y
+CONFIG_SCSI_DMA=y
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+# CONFIG_BLK_DEV_SR is not set
+# CONFIG_CHR_DEV_SG is not set
+# CONFIG_CHR_DEV_SCH is not set
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC is not set
+CONFIG_SCSI_WAIT_SCAN=m
+
+#
+# SCSI Transports
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+# CONFIG_SCSI_SRP_ATTRS is not set
+CONFIG_SCSI_LOWLEVEL=y
+# CONFIG_ISCSI_TCP is not set
+# CONFIG_LIBFC is not set
+# CONFIG_LIBFCOE is not set
+# CONFIG_SCSI_DEBUG is not set
+# CONFIG_SCSI_DH is not set
+# CONFIG_SCSI_OSD_INITIATOR is not set
+# CONFIG_ATA is not set
+# CONFIG_MD is not set
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_VETH is not set
+CONFIG_PHYLIB=y
+
+#
+# MII PHY device drivers
+#
+# CONFIG_MARVELL_PHY is not set
+# CONFIG_DAVICOM_PHY is not set
+# CONFIG_QSEMI_PHY is not set
+# CONFIG_LXT_PHY is not set
+# CONFIG_CICADA_PHY is not set
+# CONFIG_VITESSE_PHY is not set
+# CONFIG_SMSC_PHY is not set
+# CONFIG_BROADCOM_PHY is not set
+# CONFIG_ICPLUS_PHY is not set
+# CONFIG_REALTEK_PHY is not set
+# CONFIG_NATIONAL_PHY is not set
+# CONFIG_STE10XP is not set
+# CONFIG_LSI_ET1011C_PHY is not set
+# CONFIG_FIXED_PHY is not set
+# CONFIG_MDIO_BITBANG is not set
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_AX88796 is not set
+# CONFIG_SMC91X is not set
+# CONFIG_DM9000 is not set
+# CONFIG_ENC28J60 is not set
+# CONFIG_ETHOC is not set
+# CONFIG_SMC911X is not set
+CONFIG_SMSC911X=y
+# CONFIG_DNET is not set
+# CONFIG_IBM_NEW_EMAC_ZMII is not set
+# CONFIG_IBM_NEW_EMAC_RGMII is not set
+# CONFIG_IBM_NEW_EMAC_TAH is not set
+# CONFIG_IBM_NEW_EMAC_EMAC4 is not set
+# CONFIG_IBM_NEW_EMAC_NO_FLOW_CTRL is not set
+# CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT is not set
+# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
+# CONFIG_B44 is not set
+# CONFIG_KS8842 is not set
+# CONFIG_KS8851 is not set
+# CONFIG_KS8851_MLL is not set
+# CONFIG_NETDEV_1000 is not set
+# CONFIG_NETDEV_10000 is not set
+CONFIG_WLAN=y
+# CONFIG_WLAN_PRE80211 is not set
+CONFIG_WLAN_80211=y
+CONFIG_LIBERTAS=m
+CONFIG_LIBERTAS_USB=m
+CONFIG_LIBERTAS_SDIO=m
+# CONFIG_LIBERTAS_SPI is not set
+# CONFIG_LIBERTAS_DEBUG is not set
+# CONFIG_LIBERTAS_THINFIRM is not set
+CONFIG_AT76C50X_USB=m
+CONFIG_USB_ZD1201=m
+CONFIG_USB_NET_RNDIS_WLAN=m
+CONFIG_RTL8187=m
+# CONFIG_MAC80211_HWSIM is not set
+CONFIG_P54_COMMON=m
+CONFIG_P54_USB=m
+CONFIG_P54_SPI=m
+CONFIG_ATH_COMMON=m
+CONFIG_AR9170_USB=m
+CONFIG_HOSTAP=m
+CONFIG_HOSTAP_FIRMWARE=y
+CONFIG_HOSTAP_FIRMWARE_NVRAM=y
+CONFIG_B43=m
+# CONFIG_B43_SDIO is not set
+# CONFIG_B43_PHY_LP is not set
+CONFIG_B43_HWRNG=y
+# CONFIG_B43_DEBUG is not set
+CONFIG_B43LEGACY=m
+CONFIG_B43LEGACY_HWRNG=y
+# CONFIG_B43LEGACY_DEBUG is not set
+CONFIG_B43LEGACY_DMA=y
+CONFIG_B43LEGACY_PIO=y
+CONFIG_B43LEGACY_DMA_AND_PIO_MODE=y
+# CONFIG_B43LEGACY_DMA_MODE is not set
+# CONFIG_B43LEGACY_PIO_MODE is not set
+CONFIG_ZD1211RW=m
+# CONFIG_ZD1211RW_DEBUG is not set
+CONFIG_RT2X00=m
+CONFIG_RT2500USB=m
+CONFIG_RT73USB=m
+CONFIG_RT2800USB=m
+CONFIG_RT2X00_LIB_USB=m
+CONFIG_RT2X00_LIB=m
+CONFIG_RT2X00_LIB_HT=y
+CONFIG_RT2X00_LIB_FIRMWARE=y
+CONFIG_RT2X00_LIB_CRYPTO=y
+# CONFIG_RT2X00_DEBUG is not set
+CONFIG_WL12XX=m
+# CONFIG_WL1251 is not set
+# CONFIG_WL1271 is not set
+# CONFIG_IWM is not set
+
+#
+# Enable WiMAX (Networking options) to see the WiMAX drivers
+#
+
+#
+# USB Network Adapters
+#
+# CONFIG_USB_CATC is not set
+CONFIG_USB_KAWETH=m
+CONFIG_USB_PEGASUS=m
+# CONFIG_USB_RTL8150 is not set
+CONFIG_USB_USBNET=m
+CONFIG_USB_NET_AX8817X=m
+CONFIG_USB_NET_CDCETHER=m
+CONFIG_USB_NET_CDC_EEM=m
+CONFIG_USB_NET_DM9601=m
+CONFIG_USB_NET_SMSC95XX=m
+CONFIG_USB_NET_GL620A=m
+CONFIG_USB_NET_NET1080=m
+CONFIG_USB_NET_PLUSB=m
+CONFIG_USB_NET_MCS7830=m
+CONFIG_USB_NET_RNDIS_HOST=m
+CONFIG_USB_NET_CDC_SUBSET=m
+# CONFIG_USB_ALI_M5632 is not set
+# CONFIG_USB_AN2720 is not set
+CONFIG_USB_BELKIN=y
+CONFIG_USB_ARMLINUX=y
+# CONFIG_USB_EPSON2888 is not set
+# CONFIG_USB_KC2190 is not set
+CONFIG_USB_NET_ZAURUS=m
+# CONFIG_USB_NET_INT51X1 is not set
+# CONFIG_WAN is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_ISDN is not set
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
+
+#
+# Userland interfaces
+#
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_CONSOLE_TRANSLATIONS=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
+CONFIG_DEVKMEM=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=32
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+CONFIG_SERIAL_8250_EXTENDED=y
+CONFIG_SERIAL_8250_MANY_PORTS=y
+CONFIG_SERIAL_8250_SHARE_IRQ=y
+CONFIG_SERIAL_8250_DETECT_IRQ=y
+CONFIG_SERIAL_8250_RSA=y
+
+#
+# Non-8250 serial port support
+#
+# CONFIG_SERIAL_MAX3100 is not set
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_IPMI_HANDLER is not set
+CONFIG_HW_RANDOM=y
+# CONFIG_HW_RANDOM_TIMERIOMEM is not set
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+CONFIG_I2C=y
+CONFIG_I2C_BOARDINFO=y
+CONFIG_I2C_COMPAT=y
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_HELPER_AUTO=y
+
+#
+# I2C Hardware Bus support
+#
+
+#
+# I2C system bus drivers (mostly embedded / system-on-chip)
+#
+# CONFIG_I2C_DESIGNWARE is not set
+# CONFIG_I2C_GPIO is not set
+# CONFIG_I2C_OCORES is not set
+CONFIG_I2C_OMAP=y
+# CONFIG_I2C_SIMTEC is not set
+
+#
+# External I2C/SMBus adapter drivers
+#
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_TAOS_EVM is not set
+# CONFIG_I2C_TINY_USB is not set
+
+#
+# Other I2C/SMBus bus drivers
+#
+# CONFIG_I2C_PCA_PLATFORM is not set
+# CONFIG_I2C_STUB is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_DS1682 is not set
+# CONFIG_SENSORS_TSL2550 is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+CONFIG_SPI=y
+# CONFIG_SPI_DEBUG is not set
+CONFIG_SPI_MASTER=y
+
+#
+# SPI Master Controller Drivers
+#
+# CONFIG_SPI_BITBANG is not set
+# CONFIG_SPI_GPIO is not set
+CONFIG_SPI_OMAP24XX=y
+
+#
+# SPI Protocol Masters
+#
+# CONFIG_SPI_SPIDEV is not set
+# CONFIG_SPI_TLE62X0 is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
+CONFIG_ARCH_REQUIRE_GPIOLIB=y
+CONFIG_GPIOLIB=y
+# CONFIG_DEBUG_GPIO is not set
+CONFIG_GPIO_SYSFS=y
+
+#
+# Memory mapped GPIO expanders:
+#
+
+#
+# I2C GPIO expanders:
+#
+# CONFIG_GPIO_MAX732X is not set
+# CONFIG_GPIO_PCA953X is not set
+# CONFIG_GPIO_PCF857X is not set
+CONFIG_GPIO_TWL4030=y
+
+#
+# PCI GPIO expanders:
+#
+
+#
+# SPI GPIO expanders:
+#
+# CONFIG_GPIO_MAX7301 is not set
+# CONFIG_GPIO_MCP23S08 is not set
+# CONFIG_GPIO_MC33880 is not set
+
+#
+# AC97 GPIO expanders:
+#
+# CONFIG_W1 is not set
+CONFIG_POWER_SUPPLY=y
+# CONFIG_POWER_SUPPLY_DEBUG is not set
+# CONFIG_PDA_POWER is not set
+# CONFIG_BATTERY_DS2760 is not set
+# CONFIG_BATTERY_DS2782 is not set
+# CONFIG_BATTERY_BQ27x00 is not set
+# CONFIG_BATTERY_MAX17040 is not set
+# CONFIG_HWMON is not set
+# CONFIG_THERMAL is not set
+# CONFIG_WATCHDOG is not set
+CONFIG_SSB_POSSIBLE=y
+
+#
+# Sonics Silicon Backplane
+#
+CONFIG_SSB=m
+CONFIG_SSB_SDIOHOST_POSSIBLE=y
+# CONFIG_SSB_SDIOHOST is not set
+# CONFIG_SSB_SILENT is not set
+# CONFIG_SSB_DEBUG is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_CORE is not set
+# CONFIG_MFD_SM501 is not set
+# CONFIG_MFD_ASIC3 is not set
+# CONFIG_HTC_EGPIO is not set
+# CONFIG_HTC_PASIC3 is not set
+# CONFIG_TPS65010 is not set
+CONFIG_TWL4030_CORE=y
+# CONFIG_TWL4030_POWER is not set
+# CONFIG_MFD_TMIO is not set
+# CONFIG_MFD_T7L66XB is not set
+# CONFIG_MFD_TC6387XB is not set
+# CONFIG_MFD_TC6393XB is not set
+# CONFIG_PMIC_DA903X is not set
+# CONFIG_MFD_WM8400 is not set
+# CONFIG_MFD_WM831X is not set
+# CONFIG_MFD_WM8350_I2C is not set
+# CONFIG_MFD_PCF50633 is not set
+# CONFIG_MFD_MC13783 is not set
+# CONFIG_AB3100_CORE is not set
+# CONFIG_EZX_PCAP is not set
+CONFIG_REGULATOR=y
+# CONFIG_REGULATOR_DEBUG is not set
+# CONFIG_REGULATOR_FIXED_VOLTAGE is not set
+# CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set
+# CONFIG_REGULATOR_USERSPACE_CONSUMER is not set
+# CONFIG_REGULATOR_BQ24022 is not set
+# CONFIG_REGULATOR_MAX1586 is not set
+CONFIG_REGULATOR_TWL4030=y
+# CONFIG_REGULATOR_LP3971 is not set
+# CONFIG_REGULATOR_TPS65023 is not set
+# CONFIG_REGULATOR_TPS6507X is not set
+# CONFIG_MEDIA_SUPPORT is not set
+
+#
+# Graphics support
+#
+# CONFIG_VGASTATE is not set
+# CONFIG_VIDEO_OUTPUT_CONTROL is not set
+# CONFIG_FB is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+# CONFIG_SOUND is not set
+CONFIG_HID_SUPPORT=y
+CONFIG_HID=y
+# CONFIG_HIDRAW is not set
+
+#
+# USB Input Devices
+#
+CONFIG_USB_HID=y
+# CONFIG_HID_PID is not set
+# CONFIG_USB_HIDDEV is not set
+
+#
+# Special HID drivers
+#
+# CONFIG_HID_A4TECH is not set
+# CONFIG_HID_APPLE is not set
+# CONFIG_HID_BELKIN is not set
+# CONFIG_HID_CHERRY is not set
+# CONFIG_HID_CHICONY is not set
+# CONFIG_HID_CYPRESS is not set
+# CONFIG_HID_DRAGONRISE is not set
+# CONFIG_HID_EZKEY is not set
+# CONFIG_HID_KYE is not set
+# CONFIG_HID_GYRATION is not set
+# CONFIG_HID_TWINHAN is not set
+# CONFIG_HID_KENSINGTON is not set
+# CONFIG_HID_LOGITECH is not set
+# CONFIG_HID_MICROSOFT is not set
+# CONFIG_HID_MONTEREY is not set
+# CONFIG_HID_NTRIG is not set
+# CONFIG_HID_PANTHERLORD is not set
+# CONFIG_HID_PETALYNX is not set
+# CONFIG_HID_SAMSUNG is not set
+# CONFIG_HID_SONY is not set
+# CONFIG_HID_SUNPLUS is not set
+# CONFIG_HID_GREENASIA is not set
+# CONFIG_HID_SMARTJOYPLUS is not set
+# CONFIG_HID_TOPSEED is not set
+# CONFIG_HID_THRUSTMASTER is not set
+# CONFIG_HID_WACOM is not set
+# CONFIG_HID_ZEROPLUS is not set
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+# CONFIG_USB_ARCH_HAS_EHCI is not set
+CONFIG_USB=y
+# CONFIG_USB_DEBUG is not set
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
+
+#
+# Miscellaneous USB options
+#
+# CONFIG_USB_DEVICEFS is not set
+# CONFIG_USB_DEVICE_CLASS is not set
+# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_OTG is not set
+# CONFIG_USB_OTG_WHITELIST is not set
+# CONFIG_USB_OTG_BLACKLIST_HUB is not set
+CONFIG_USB_MON=m
+# CONFIG_USB_WUSB is not set
+# CONFIG_USB_WUSB_CBAF is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_C67X00_HCD is not set
+# CONFIG_USB_OXU210HP_HCD is not set
+# CONFIG_USB_ISP116X_HCD is not set
+# CONFIG_USB_ISP1760_HCD is not set
+# CONFIG_USB_ISP1362_HCD is not set
+# CONFIG_USB_OHCI_HCD is not set
+# CONFIG_USB_SL811_HCD is not set
+# CONFIG_USB_R8A66597_HCD is not set
+# CONFIG_USB_HWA_HCD is not set
+CONFIG_USB_MUSB_HDRC=y
+CONFIG_USB_MUSB_SOC=y
+
+#
+# OMAP 343x high speed USB support
+#
+CONFIG_USB_MUSB_HOST=y
+# CONFIG_USB_MUSB_PERIPHERAL is not set
+# CONFIG_USB_MUSB_OTG is not set
+# CONFIG_USB_GADGET_MUSB_HDRC is not set
+CONFIG_USB_MUSB_HDRC_HCD=y
+# CONFIG_MUSB_PIO_ONLY is not set
+CONFIG_USB_INVENTRA_DMA=y
+# CONFIG_USB_TI_CPPI_DMA is not set
+# CONFIG_USB_MUSB_DEBUG is not set
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+# CONFIG_USB_WDM is not set
+# CONFIG_USB_TMC is not set
+
+#
+# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may
+#
+
+#
+# also be needed; see USB_STORAGE Help for more info
+#
+CONFIG_USB_STORAGE=m
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_ISD200 is not set
+# CONFIG_USB_STORAGE_USBAT is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_SDDR55 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_STORAGE_ALAUDA is not set
+# CONFIG_USB_STORAGE_ONETOUCH is not set
+# CONFIG_USB_STORAGE_KARMA is not set
+# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set
+# CONFIG_USB_LIBUSUAL is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+
+#
+# USB port drivers
+#
+# CONFIG_USB_SERIAL is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_ADUTUX is not set
+# CONFIG_USB_SEVSEG is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_BERRY_CHARGE is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYPRESS_CY7C63 is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_FTDI_ELAN is not set
+# CONFIG_USB_APPLEDISPLAY is not set
+# CONFIG_USB_SISUSBVGA is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
+# CONFIG_USB_IOWARRIOR is not set
+# CONFIG_USB_TEST is not set
+# CONFIG_USB_ISIGHTFW is not set
+# CONFIG_USB_VST is not set
+CONFIG_USB_GADGET=y
+CONFIG_USB_GADGET_DEBUG=y
+CONFIG_USB_GADGET_DEBUG_FILES=y
+CONFIG_USB_GADGET_VBUS_DRAW=2
+CONFIG_USB_GADGET_SELECTED=y
+# CONFIG_USB_GADGET_AT91 is not set
+# CONFIG_USB_GADGET_ATMEL_USBA is not set
+# CONFIG_USB_GADGET_FSL_USB2 is not set
+# CONFIG_USB_GADGET_LH7A40X is not set
+CONFIG_USB_GADGET_OMAP=y
+CONFIG_USB_OMAP=y
+# CONFIG_USB_GADGET_PXA25X is not set
+# CONFIG_USB_GADGET_R8A66597 is not set
+# CONFIG_USB_GADGET_PXA27X is not set
+# CONFIG_USB_GADGET_S3C_HSOTG is not set
+# CONFIG_USB_GADGET_IMX is not set
+# CONFIG_USB_GADGET_S3C2410 is not set
+# CONFIG_USB_GADGET_M66592 is not set
+# CONFIG_USB_GADGET_AMD5536UDC is not set
+# CONFIG_USB_GADGET_FSL_QE is not set
+# CONFIG_USB_GADGET_CI13XXX is not set
+# CONFIG_USB_GADGET_NET2280 is not set
+# CONFIG_USB_GADGET_GOKU is not set
+# CONFIG_USB_GADGET_LANGWELL is not set
+# CONFIG_USB_GADGET_DUMMY_HCD is not set
+# CONFIG_USB_GADGET_DUALSPEED is not set
+CONFIG_USB_ZERO=m
+# CONFIG_USB_AUDIO is not set
+# CONFIG_USB_ETH is not set
+# CONFIG_USB_GADGETFS is not set
+# CONFIG_USB_FILE_STORAGE is not set
+# CONFIG_USB_G_SERIAL is not set
+# CONFIG_USB_MIDI_GADGET is not set
+# CONFIG_USB_G_PRINTER is not set
+# CONFIG_USB_CDC_COMPOSITE is not set
+
+#
+# OTG and related infrastructure
+#
+CONFIG_USB_OTG_UTILS=y
+# CONFIG_USB_GPIO_VBUS is not set
+# CONFIG_ISP1301_OMAP is not set
+CONFIG_TWL4030_USB=y
+# CONFIG_NOP_USB_XCEIV is not set
+CONFIG_MMC=y
+# CONFIG_MMC_DEBUG is not set
+# CONFIG_MMC_UNSAFE_RESUME is not set
+
+#
+# MMC/SD/SDIO Card Drivers
+#
+CONFIG_MMC_BLOCK=y
+CONFIG_MMC_BLOCK_BOUNCE=y
+# CONFIG_SDIO_UART is not set
+# CONFIG_MMC_TEST is not set
+
+#
+# MMC/SD/SDIO Host Controller Drivers
+#
+# CONFIG_MMC_SDHCI is not set
+# CONFIG_MMC_OMAP is not set
+CONFIG_MMC_OMAP_HS=y
+# CONFIG_MMC_AT91 is not set
+# CONFIG_MMC_ATMELMCI is not set
+# CONFIG_MMC_SPI is not set
+# CONFIG_MEMSTICK is not set
+# CONFIG_NEW_LEDS is not set
+# CONFIG_ACCESSIBILITY is not set
+CONFIG_RTC_LIB=y
+# CONFIG_RTC_CLASS is not set
+# CONFIG_DMADEVICES is not set
+# CONFIG_AUXDISPLAY is not set
+# CONFIG_UIO is not set
+
+#
+# TI VLYNQ
+#
+# CONFIG_STAGING is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
+# CONFIG_EXT3_FS_XATTR is not set
+# CONFIG_EXT4_FS is not set
+CONFIG_JBD=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+CONFIG_FS_POSIX_ACL=y
+# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_BTRFS_FS is not set
+# CONFIG_NILFS2_FS is not set
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
+CONFIG_DNOTIFY=y
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+CONFIG_QUOTA=y
+# CONFIG_QUOTA_NETLINK_INTERFACE is not set
+CONFIG_PRINT_QUOTA_WARNING=y
+CONFIG_QUOTA_TREE=y
+# CONFIG_QFMT_V1 is not set
+CONFIG_QFMT_V2=y
+CONFIG_QUOTACTL=y
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# Caches
+#
+# CONFIG_FSCACHE is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLB_PAGE is not set
+# CONFIG_CONFIGFS_FS is not set
+CONFIG_MISC_FILESYSTEMS=y
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_SQUASHFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_OMFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+CONFIG_NETWORK_FILESYSTEMS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+CONFIG_NFS_V3_ACL=y
+CONFIG_NFS_V4=y
+# CONFIG_NFS_V4_1 is not set
+CONFIG_ROOT_NFS=y
+# CONFIG_NFSD is not set
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_ACL_SUPPORT=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+CONFIG_SUNRPC_GSS=y
+CONFIG_RPCSEC_GSS_KRB5=y
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_KARMA_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+# CONFIG_SYSV68_PARTITION is not set
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+CONFIG_NLS_ISO8859_1=y
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+# CONFIG_DLM is not set
+
+#
+# Kernel hacking
+#
+CONFIG_PRINTK_TIME=y
+CONFIG_ENABLE_WARN_DEPRECATED=y
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_FRAME_WARN=1024
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_STRIP_ASM_SYMS is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SHIRQ is not set
+CONFIG_DETECT_SOFTLOCKUP=y
+# CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set
+CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0
+CONFIG_DETECT_HUNG_TASK=y
+# CONFIG_BOOTPARAM_HUNG_TASK_PANIC is not set
+CONFIG_BOOTPARAM_HUNG_TASK_PANIC_VALUE=0
+CONFIG_SCHED_DEBUG=y
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_TIMER_STATS is not set
+# CONFIG_DEBUG_OBJECTS is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_KMEMLEAK is not set
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+CONFIG_DEBUG_MUTEXES=y
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_LOCK_STAT is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_DEBUG_KOBJECT is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+CONFIG_DEBUG_INFO=y
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_WRITECOUNT is not set
+# CONFIG_DEBUG_MEMORY_INIT is not set
+# CONFIG_DEBUG_LIST is not set
+# CONFIG_DEBUG_SG is not set
+# CONFIG_DEBUG_NOTIFIERS is not set
+# CONFIG_DEBUG_CREDENTIALS is not set
+# CONFIG_BOOT_PRINTK_DELAY is not set
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_RCU_CPU_STALL_DETECTOR is not set
+# CONFIG_BACKTRACE_SELF_TEST is not set
+# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
+# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
+# CONFIG_FAULT_INJECTION is not set
+# CONFIG_LATENCYTOP is not set
+# CONFIG_PAGE_POISONING is not set
+CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_TRACING_SUPPORT=y
+CONFIG_FTRACE=y
+# CONFIG_FUNCTION_TRACER is not set
+# CONFIG_IRQSOFF_TRACER is not set
+# CONFIG_SCHED_TRACER is not set
+# CONFIG_ENABLE_DEFAULT_TRACERS is not set
+# CONFIG_BOOT_TRACER is not set
+CONFIG_BRANCH_PROFILE_NONE=y
+# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set
+# CONFIG_PROFILE_ALL_BRANCHES is not set
+# CONFIG_STACK_TRACER is not set
+# CONFIG_KMEMTRACE is not set
+# CONFIG_WORKQUEUE_TRACER is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_SAMPLES is not set
+CONFIG_HAVE_ARCH_KGDB=y
+# CONFIG_KGDB is not set
+CONFIG_ARM_UNWIND=y
+# CONFIG_DEBUG_USER is not set
+# CONFIG_DEBUG_ERRORS is not set
+# CONFIG_DEBUG_STACK_USAGE is not set
+CONFIG_DEBUG_LL=y
+# CONFIG_DEBUG_ICEDCC is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+# CONFIG_SECURITYFS is not set
+# CONFIG_SECURITY_FILE_CAPABILITIES is not set
+CONFIG_CRYPTO=y
+
+#
+# Crypto core or helper
+#
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_ALGAPI2=y
+CONFIG_CRYPTO_AEAD2=y
+CONFIG_CRYPTO_BLKCIPHER=y
+CONFIG_CRYPTO_BLKCIPHER2=y
+CONFIG_CRYPTO_HASH=y
+CONFIG_CRYPTO_HASH2=y
+CONFIG_CRYPTO_RNG2=y
+CONFIG_CRYPTO_PCOMP=y
+CONFIG_CRYPTO_MANAGER=y
+CONFIG_CRYPTO_MANAGER2=y
+# CONFIG_CRYPTO_GF128MUL is not set
+# CONFIG_CRYPTO_NULL is not set
+CONFIG_CRYPTO_WORKQUEUE=y
+# CONFIG_CRYPTO_CRYPTD is not set
+# CONFIG_CRYPTO_AUTHENC is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Authenticated Encryption with Associated Data
+#
+# CONFIG_CRYPTO_CCM is not set
+# CONFIG_CRYPTO_GCM is not set
+# CONFIG_CRYPTO_SEQIV is not set
+
+#
+# Block modes
+#
+CONFIG_CRYPTO_CBC=y
+# CONFIG_CRYPTO_CTR is not set
+# CONFIG_CRYPTO_CTS is not set
+CONFIG_CRYPTO_ECB=y
+# CONFIG_CRYPTO_LRW is not set
+CONFIG_CRYPTO_PCBC=m
+# CONFIG_CRYPTO_XTS is not set
+
+#
+# Hash modes
+#
+# CONFIG_CRYPTO_HMAC is not set
+# CONFIG_CRYPTO_XCBC is not set
+# CONFIG_CRYPTO_VMAC is not set
+
+#
+# Digest
+#
+CONFIG_CRYPTO_CRC32C=y
+# CONFIG_CRYPTO_GHASH is not set
+# CONFIG_CRYPTO_MD4 is not set
+CONFIG_CRYPTO_MD5=y
+CONFIG_CRYPTO_MICHAEL_MIC=m
+# CONFIG_CRYPTO_RMD128 is not set
+# CONFIG_CRYPTO_RMD160 is not set
+# CONFIG_CRYPTO_RMD256 is not set
+# CONFIG_CRYPTO_RMD320 is not set
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_WP512 is not set
+
+#
+# Ciphers
+#
+CONFIG_CRYPTO_AES=y
+# CONFIG_CRYPTO_ANUBIS is not set
+CONFIG_CRYPTO_ARC4=y
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_CAMELLIA is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+CONFIG_CRYPTO_DES=y
+# CONFIG_CRYPTO_FCRYPT is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_SALSA20 is not set
+# CONFIG_CRYPTO_SEED is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+
+#
+# Compression
+#
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_ZLIB is not set
+# CONFIG_CRYPTO_LZO is not set
+
+#
+# Random Number Generation
+#
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
+CONFIG_CRYPTO_HW=y
+# CONFIG_BINARY_PRINTF is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+CONFIG_GENERIC_FIND_LAST_BIT=y
+CONFIG_CRC_CCITT=y
+CONFIG_CRC16=m
+CONFIG_CRC_T10DIF=y
+CONFIG_CRC_ITU_T=m
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+CONFIG_LIBCRC32C=y
+CONFIG_ZLIB_INFLATE=y
+CONFIG_DECOMPRESS_GZIP=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
+CONFIG_NLATTR=y
index a4f9a2a..7734cca 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.31-rc4
-# Tue Jul 28 14:11:34 2009
+# Linux kernel version: 2.6.32-rc5
+# Sun Nov  1 22:56:24 2009
 #
 CONFIG_ARM=y
 CONFIG_HAVE_PWM=y
@@ -9,7 +9,6 @@ CONFIG_SYS_SUPPORTS_APM_EMULATION=y
 CONFIG_GENERIC_GPIO=y
 CONFIG_GENERIC_TIME=y
 CONFIG_GENERIC_CLOCKEVENTS=y
-CONFIG_MMU=y
 CONFIG_GENERIC_HARDIRQS=y
 CONFIG_STACKTRACE_SUPPORT=y
 CONFIG_HAVE_LATENCYTOP_SUPPORT=y
@@ -46,11 +45,12 @@ CONFIG_SYSVIPC_SYSCTL=y
 #
 # RCU Subsystem
 #
-CONFIG_CLASSIC_RCU=y
-# CONFIG_TREE_RCU is not set
-# CONFIG_PREEMPT_RCU is not set
+CONFIG_TREE_RCU=y
+# CONFIG_TREE_PREEMPT_RCU is not set
+# CONFIG_RCU_TRACE is not set
+CONFIG_RCU_FANOUT=32
+# CONFIG_RCU_FANOUT_EXACT is not set
 # CONFIG_TREE_RCU_TRACE is not set
-# CONFIG_PREEMPT_RCU_TRACE is not set
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=14
@@ -87,16 +87,14 @@ CONFIG_SHMEM=y
 CONFIG_AIO=y
 
 #
-# Performance Counters
+# Kernel Performance Events And Counters
 #
 CONFIG_VM_EVENT_COUNTERS=y
-# CONFIG_STRIP_ASM_SYMS is not set
 CONFIG_COMPAT_BRK=y
 CONFIG_SLAB=y
 # CONFIG_SLUB is not set
 # CONFIG_SLOB is not set
 # CONFIG_PROFILING is not set
-# CONFIG_MARKERS is not set
 CONFIG_HAVE_OPROFILE=y
 # CONFIG_KPROBES is not set
 CONFIG_HAVE_KPROBES=y
@@ -139,6 +137,7 @@ CONFIG_FREEZER=y
 #
 # System Type
 #
+CONFIG_MMU=y
 # CONFIG_ARCH_AAEC2000 is not set
 # CONFIG_ARCH_INTEGRATOR is not set
 # CONFIG_ARCH_REALVIEW is not set
@@ -153,6 +152,7 @@ CONFIG_ARCH_MXC=y
 # CONFIG_ARCH_STMP3XXX is not set
 # CONFIG_ARCH_NETX is not set
 # CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_NOMADIK is not set
 # CONFIG_ARCH_IOP13XX is not set
 # CONFIG_ARCH_IOP32X is not set
 # CONFIG_ARCH_IOP33X is not set
@@ -175,18 +175,22 @@ CONFIG_ARCH_MXC=y
 # CONFIG_ARCH_SA1100 is not set
 # CONFIG_ARCH_S3C2410 is not set
 # CONFIG_ARCH_S3C64XX is not set
+# CONFIG_ARCH_S5PC1XX is not set
 # CONFIG_ARCH_SHARK is not set
 # CONFIG_ARCH_LH7A40X is not set
 # CONFIG_ARCH_U300 is not set
 # CONFIG_ARCH_DAVINCI is not set
 # CONFIG_ARCH_OMAP is not set
+# CONFIG_ARCH_BCMRING is not set
 
 #
 # Freescale MXC Implementations
 #
 # CONFIG_ARCH_MX1 is not set
 # CONFIG_ARCH_MX2 is not set
+# CONFIG_ARCH_MX25 is not set
 CONFIG_ARCH_MX3=y
+# CONFIG_ARCH_MXC91231 is not set
 CONFIG_ARCH_MX31=y
 CONFIG_ARCH_MX35=y
 
@@ -205,6 +209,7 @@ CONFIG_MACH_QONG=y
 CONFIG_MACH_PCM043=y
 CONFIG_MACH_ARMADILLO5X0=y
 CONFIG_MACH_MX35_3DS=y
+CONFIG_MACH_KZM_ARM11_01=y
 CONFIG_MXC_IRQ_PRIOR=y
 CONFIG_MXC_PWM=y
 CONFIG_ARCH_HAS_RNGA=y
@@ -218,7 +223,7 @@ CONFIG_CPU_V6=y
 # CONFIG_CPU_32v6K is not set
 CONFIG_CPU_32v6=y
 CONFIG_CPU_ABRT_EV6=y
-CONFIG_CPU_PABRT_NOIFAR=y
+CONFIG_CPU_PABRT_V6=y
 CONFIG_CPU_CACHE_V6=y
 CONFIG_CPU_CACHE_VIPT=y
 CONFIG_CPU_COPY_V6=y
@@ -236,6 +241,7 @@ CONFIG_ARM_THUMB=y
 # CONFIG_CPU_BPREDICT_DISABLE is not set
 CONFIG_OUTER_CACHE=y
 CONFIG_CACHE_L2X0=y
+CONFIG_ARM_L1_CACHE_SHIFT=5
 # CONFIG_ARM_ERRATA_411920 is not set
 CONFIG_COMMON_CLKDEV=y
 
@@ -257,6 +263,8 @@ CONFIG_VMSPLIT_3G=y
 # CONFIG_VMSPLIT_2G is not set
 # CONFIG_VMSPLIT_1G is not set
 CONFIG_PAGE_OFFSET=0xC0000000
+# CONFIG_PREEMPT_NONE is not set
+# CONFIG_PREEMPT_VOLUNTARY is not set
 CONFIG_PREEMPT=y
 CONFIG_HZ=100
 CONFIG_AEABI=y
@@ -277,6 +285,7 @@ CONFIG_ZONE_DMA_FLAG=0
 CONFIG_VIRT_TO_BUS=y
 CONFIG_HAVE_MLOCK=y
 CONFIG_HAVE_MLOCKED_PAGE_BIT=y
+# CONFIG_KSM is not set
 CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
 CONFIG_ALIGNMENT_TRAP=y
 # CONFIG_UACCESS_WITH_MEMCPY is not set
@@ -326,6 +335,7 @@ CONFIG_PM_SLEEP=y
 CONFIG_SUSPEND=y
 CONFIG_SUSPEND_FREEZER=y
 # CONFIG_APM_EMULATION is not set
+# CONFIG_PM_RUNTIME is not set
 CONFIG_ARCH_SUSPEND_POSSIBLE=y
 CONFIG_NET=y
 
@@ -367,6 +377,7 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
 # CONFIG_NETFILTER is not set
 # CONFIG_IP_DCCP is not set
 # CONFIG_IP_SCTP is not set
+# CONFIG_RDS is not set
 # CONFIG_TIPC is not set
 # CONFIG_ATM is not set
 # CONFIG_BRIDGE is not set
@@ -407,6 +418,7 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
 # Generic Driver Options
 #
 CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+# CONFIG_DEVTMPFS is not set
 CONFIG_STANDALONE=y
 CONFIG_PREVENT_FIRMWARE_BUILD=y
 CONFIG_FW_LOADER=m
@@ -416,9 +428,9 @@ CONFIG_EXTRA_FIRMWARE=""
 # CONFIG_CONNECTOR is not set
 CONFIG_MTD=y
 # CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_TESTS is not set
 # CONFIG_MTD_CONCAT is not set
 CONFIG_MTD_PARTITIONS=y
-# CONFIG_MTD_TESTS is not set
 # CONFIG_MTD_REDBOOT_PARTS is not set
 CONFIG_MTD_CMDLINE_PARTS=y
 # CONFIG_MTD_AFS_PARTS is not set
@@ -587,14 +599,12 @@ CONFIG_DNET=y
 # CONFIG_B44 is not set
 # CONFIG_CS89x0 is not set
 # CONFIG_KS8842 is not set
+# CONFIG_KS8851_MLL is not set
 CONFIG_FEC=y
 # CONFIG_FEC2 is not set
 # CONFIG_NETDEV_1000 is not set
 # CONFIG_NETDEV_10000 is not set
-
-#
-# Wireless LAN
-#
+CONFIG_WLAN=y
 # CONFIG_WLAN_PRE80211 is not set
 # CONFIG_WLAN_80211 is not set
 
@@ -608,6 +618,7 @@ CONFIG_FEC=y
 # CONFIG_NETPOLL is not set
 # CONFIG_NET_POLL_CONTROLLER is not set
 # CONFIG_ISDN is not set
+# CONFIG_PHONE is not set
 
 #
 # Input device support
@@ -630,7 +641,14 @@ CONFIG_DEVKMEM=y
 #
 # Serial drivers
 #
-# CONFIG_SERIAL_8250 is not set
+CONFIG_SERIAL_8250=m
+CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+CONFIG_SERIAL_8250_EXTENDED=y
+# CONFIG_SERIAL_8250_MANY_PORTS is not set
+CONFIG_SERIAL_8250_SHARE_IRQ=y
+# CONFIG_SERIAL_8250_DETECT_IRQ is not set
+# CONFIG_SERIAL_8250_RSA is not set
 
 #
 # Non-8250 serial port support
@@ -649,6 +667,7 @@ CONFIG_UNIX98_PTYS=y
 # CONFIG_TCG_TPM is not set
 CONFIG_I2C=y
 CONFIG_I2C_BOARDINFO=y
+CONFIG_I2C_COMPAT=y
 CONFIG_I2C_CHARDEV=y
 CONFIG_I2C_HELPER_AUTO=y
 
@@ -681,15 +700,17 @@ CONFIG_I2C_IMX=y
 # Miscellaneous I2C Chip support
 #
 # CONFIG_DS1682 is not set
-# CONFIG_SENSORS_PCF8574 is not set
-# CONFIG_PCF8575 is not set
-# CONFIG_SENSORS_PCA9539 is not set
 # CONFIG_SENSORS_TSL2550 is not set
 # CONFIG_I2C_DEBUG_CORE is not set
 # CONFIG_I2C_DEBUG_ALGO is not set
 # CONFIG_I2C_DEBUG_BUS is not set
 # CONFIG_I2C_DEBUG_CHIP is not set
 # CONFIG_SPI is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
 CONFIG_ARCH_REQUIRE_GPIOLIB=y
 CONFIG_GPIOLIB=y
 # CONFIG_GPIO_SYSFS is not set
@@ -712,6 +733,10 @@ CONFIG_GPIOLIB=y
 #
 # SPI GPIO expanders:
 #
+
+#
+# AC97 GPIO expanders:
+#
 CONFIG_W1=y
 
 #
@@ -734,7 +759,6 @@ CONFIG_W1_SLAVE_THERM=y
 # CONFIG_POWER_SUPPLY is not set
 # CONFIG_HWMON is not set
 # CONFIG_THERMAL is not set
-# CONFIG_THERMAL_HWMON is not set
 # CONFIG_WATCHDOG is not set
 CONFIG_SSB_POSSIBLE=y
 
@@ -759,12 +783,24 @@ CONFIG_SSB_POSSIBLE=y
 # CONFIG_MFD_TC6393XB is not set
 # CONFIG_PMIC_DA903X is not set
 # CONFIG_MFD_WM8400 is not set
+# CONFIG_MFD_WM831X is not set
 CONFIG_MFD_WM8350=y
 CONFIG_MFD_WM8350_CONFIG_MODE_0=y
 CONFIG_MFD_WM8352_CONFIG_MODE_0=y
 CONFIG_MFD_WM8350_I2C=y
 # CONFIG_MFD_PCF50633 is not set
 # CONFIG_AB3100_CORE is not set
+CONFIG_REGULATOR=y
+# CONFIG_REGULATOR_DEBUG is not set
+# CONFIG_REGULATOR_FIXED_VOLTAGE is not set
+# CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set
+# CONFIG_REGULATOR_USERSPACE_CONSUMER is not set
+# CONFIG_REGULATOR_BQ24022 is not set
+# CONFIG_REGULATOR_MAX1586 is not set
+CONFIG_REGULATOR_WM8350=y
+# CONFIG_REGULATOR_LP3971 is not set
+# CONFIG_REGULATOR_TPS65023 is not set
+# CONFIG_REGULATOR_TPS6507X is not set
 CONFIG_MEDIA_SUPPORT=y
 
 #
@@ -874,10 +910,12 @@ CONFIG_MMC_BLOCK_BOUNCE=y
 # MMC/SD/SDIO Host Controller Drivers
 #
 # CONFIG_MMC_SDHCI is not set
+# CONFIG_MMC_AT91 is not set
+# CONFIG_MMC_ATMELMCI is not set
 CONFIG_MMC_MXC=y
 # CONFIG_MEMSTICK is not set
-# CONFIG_ACCESSIBILITY is not set
 # CONFIG_NEW_LEDS is not set
+# CONFIG_ACCESSIBILITY is not set
 CONFIG_RTC_LIB=y
 # CONFIG_RTC_CLASS is not set
 CONFIG_DMADEVICES=y
@@ -896,16 +934,11 @@ CONFIG_DMA_ENGINE=y
 # CONFIG_ASYNC_TX_DMA is not set
 # CONFIG_DMATEST is not set
 # CONFIG_AUXDISPLAY is not set
-CONFIG_REGULATOR=y
-# CONFIG_REGULATOR_DEBUG is not set
-# CONFIG_REGULATOR_FIXED_VOLTAGE is not set
-# CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set
-# CONFIG_REGULATOR_USERSPACE_CONSUMER is not set
-# CONFIG_REGULATOR_BQ24022 is not set
-# CONFIG_REGULATOR_MAX1586 is not set
-CONFIG_REGULATOR_WM8350=y
-# CONFIG_REGULATOR_LP3971 is not set
 # CONFIG_UIO is not set
+
+#
+# TI VLYNQ
+#
 # CONFIG_STAGING is not set
 
 #
@@ -921,6 +954,7 @@ CONFIG_REGULATOR_WM8350=y
 # CONFIG_GFS2_FS is not set
 # CONFIG_OCFS2_FS is not set
 # CONFIG_BTRFS_FS is not set
+# CONFIG_NILFS2_FS is not set
 CONFIG_FILE_LOCKING=y
 CONFIG_FSNOTIFY=y
 # CONFIG_DNOTIFY is not set
@@ -995,7 +1029,6 @@ CONFIG_UBIFS_FS_ZLIB=y
 # CONFIG_ROMFS_FS is not set
 # CONFIG_SYSV_FS is not set
 # CONFIG_UFS_FS is not set
-# CONFIG_NILFS2_FS is not set
 CONFIG_NETWORK_FILESYSTEMS=y
 CONFIG_NFS_FS=y
 CONFIG_NFS_V3=y
@@ -1033,6 +1066,7 @@ CONFIG_MSDOS_PARTITION=y
 # CONFIG_ENABLE_MUST_CHECK is not set
 CONFIG_FRAME_WARN=1024
 # CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_STRIP_ASM_SYMS is not set
 # CONFIG_UNUSED_SYMBOLS is not set
 # CONFIG_DEBUG_FS is not set
 # CONFIG_HEADERS_CHECK is not set
@@ -1062,7 +1096,6 @@ CONFIG_CRYPTO=y
 #
 # Crypto core or helper
 #
-# CONFIG_CRYPTO_FIPS is not set
 CONFIG_CRYPTO_ALGAPI=y
 CONFIG_CRYPTO_ALGAPI2=y
 CONFIG_CRYPTO_AEAD2=y
@@ -1104,11 +1137,13 @@ CONFIG_CRYPTO_CBC=y
 #
 # CONFIG_CRYPTO_HMAC is not set
 # CONFIG_CRYPTO_XCBC is not set
+# CONFIG_CRYPTO_VMAC is not set
 
 #
 # Digest
 #
 # CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_GHASH is not set
 # CONFIG_CRYPTO_MD4 is not set
 CONFIG_CRYPTO_MD5=y
 # CONFIG_CRYPTO_MICHAEL_MIC is not set
diff --git a/arch/arm/configs/nuc950_defconfig b/arch/arm/configs/nuc950_defconfig
new file mode 100644 (file)
index 0000000..df1de9b
--- /dev/null
@@ -0,0 +1,922 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.32-rc7
+# Tue Nov 17 12:31:33 2009
+#
+CONFIG_ARM=y
+CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+CONFIG_GENERIC_GPIO=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
+CONFIG_VECTORS_BASE=0xffff0000
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_LOCK_KERNEL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+CONFIG_BSD_PROCESS_ACCT=y
+# CONFIG_BSD_PROCESS_ACCT_V3 is not set
+
+#
+# RCU Subsystem
+#
+CONFIG_TREE_RCU=y
+# CONFIG_TREE_PREEMPT_RCU is not set
+# CONFIG_RCU_TRACE is not set
+CONFIG_RCU_FANOUT=32
+# CONFIG_RCU_FANOUT_EXACT is not set
+# CONFIG_TREE_RCU_TRACE is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=17
+# CONFIG_GROUP_SCHED is not set
+# CONFIG_CGROUPS is not set
+CONFIG_SYSFS_DEPRECATED=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+CONFIG_RELAY=y
+CONFIG_NAMESPACES=y
+# CONFIG_UTS_NS is not set
+# CONFIG_IPC_NS is not set
+CONFIG_USER_NS=y
+# CONFIG_PID_NS is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_RD_GZIP=y
+CONFIG_RD_BZIP2=y
+CONFIG_RD_LZMA=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+CONFIG_ANON_INODES=y
+# CONFIG_EMBEDDED is not set
+CONFIG_UID16=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+CONFIG_KALLSYMS_EXTRA_PASS=y
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_AIO=y
+
+#
+# Kernel Performance Events And Counters
+#
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_COMPAT_BRK=y
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
+# CONFIG_PROFILING is not set
+CONFIG_HAVE_OPROFILE=y
+CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_KRETPROBES=y
+CONFIG_HAVE_CLK=y
+
+#
+# GCOV-based kernel profiling
+#
+# CONFIG_GCOV_KERNEL is not set
+# CONFIG_SLOW_WORK is not set
+CONFIG_HAVE_GENERIC_DMA_COHERENT=y
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
+CONFIG_BASE_SMALL=0
+# CONFIG_MODULES is not set
+CONFIG_BLOCK=y
+CONFIG_LBDAF=y
+CONFIG_BLK_DEV_BSG=y
+# CONFIG_BLK_DEV_INTEGRITY is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_DEFAULT_AS is not set
+# CONFIG_DEFAULT_DEADLINE is not set
+CONFIG_DEFAULT_CFQ=y
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="cfq"
+# CONFIG_FREEZER is not set
+
+#
+# System Type
+#
+CONFIG_MMU=y
+# CONFIG_ARCH_AAEC2000 is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_REALVIEW is not set
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_AT91 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_GEMINI is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_EP93XX is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_MXC is not set
+# CONFIG_ARCH_STMP3XXX is not set
+# CONFIG_ARCH_NETX is not set
+# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_NOMADIK is not set
+# CONFIG_ARCH_IOP13XX is not set
+# CONFIG_ARCH_IOP32X is not set
+# CONFIG_ARCH_IOP33X is not set
+# CONFIG_ARCH_IXP23XX is not set
+# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_KIRKWOOD is not set
+# CONFIG_ARCH_LOKI is not set
+# CONFIG_ARCH_MV78XX0 is not set
+# CONFIG_ARCH_ORION5X is not set
+# CONFIG_ARCH_MMP is not set
+# CONFIG_ARCH_KS8695 is not set
+# CONFIG_ARCH_NS9XXX is not set
+CONFIG_ARCH_W90X900=y
+# CONFIG_ARCH_PNX4008 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_MSM is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_S3C64XX is not set
+# CONFIG_ARCH_S5PC1XX is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_U300 is not set
+# CONFIG_ARCH_DAVINCI is not set
+# CONFIG_ARCH_OMAP is not set
+# CONFIG_ARCH_BCMRING is not set
+CONFIG_CPU_NUC950=y
+
+#
+# W90P910 Machines
+#
+# CONFIG_MACH_W90P910EVB is not set
+
+#
+# NUC950 Machines
+#
+CONFIG_MACH_W90P950EVB=y
+
+#
+# NUC960 Machines
+#
+# CONFIG_MACH_W90N960EVB is not set
+
+#
+# NUC932 Machines
+#
+# CONFIG_MACH_NUC932EVB is not set
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_ARM926T=y
+CONFIG_CPU_32v5=y
+CONFIG_CPU_ABRT_EV5TJ=y
+CONFIG_CPU_PABRT_LEGACY=y
+CONFIG_CPU_CACHE_VIVT=y
+CONFIG_CPU_COPY_V4WB=y
+CONFIG_CPU_TLB_V4WBI=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
+
+#
+# Processor Features
+#
+CONFIG_ARM_THUMB=y
+# CONFIG_CPU_ICACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_WRITETHROUGH is not set
+# CONFIG_CPU_CACHE_ROUND_ROBIN is not set
+CONFIG_ARM_L1_CACHE_SHIFT=5
+CONFIG_COMMON_CLKDEV=y
+
+#
+# Bus support
+#
+# CONFIG_PCI_SYSCALL is not set
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+CONFIG_TICK_ONESHOT=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+CONFIG_VMSPLIT_3G=y
+# CONFIG_VMSPLIT_2G is not set
+# CONFIG_VMSPLIT_1G is not set
+CONFIG_PAGE_OFFSET=0xC0000000
+# CONFIG_PREEMPT_NONE is not set
+# CONFIG_PREEMPT_VOLUNTARY is not set
+CONFIG_PREEMPT=y
+CONFIG_HZ=100
+CONFIG_AEABI=y
+CONFIG_OABI_COMPAT=y
+# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set
+# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set
+# CONFIG_HIGHMEM is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+CONFIG_PAGEFLAGS_EXTENDED=y
+CONFIG_SPLIT_PTLOCK_CPUS=4096
+# CONFIG_PHYS_ADDR_T_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=0
+CONFIG_VIRT_TO_BUS=y
+CONFIG_HAVE_MLOCK=y
+CONFIG_HAVE_MLOCKED_PAGE_BIT=y
+# CONFIG_KSM is not set
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
+CONFIG_ALIGNMENT_TRAP=y
+# CONFIG_UACCESS_WITH_MEMCPY is not set
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0
+CONFIG_ZBOOT_ROM_BSS=0
+CONFIG_CMDLINE="root=/dev/ram0 console=ttyS0,115200n8 rdinit=/sbin/init mem=64M"
+# CONFIG_XIP_KERNEL is not set
+CONFIG_KEXEC=y
+CONFIG_ATAGS_PROC=y
+
+#
+# CPU Power Management
+#
+# CONFIG_CPU_IDLE is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
+# CONFIG_FPE_FASTFPE is not set
+# CONFIG_VFP is not set
+
+#
+# Userspace binary formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_HAVE_AOUT=y
+CONFIG_BINFMT_AOUT=y
+CONFIG_BINFMT_MISC=y
+
+#
+# Power management options
+#
+# CONFIG_PM is not set
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+# CONFIG_NET is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+# CONFIG_DEVTMPFS is not set
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=y
+CONFIG_FIRMWARE_IN_KERNEL=y
+CONFIG_EXTRA_FIRMWARE=""
+# CONFIG_SYS_HYPERVISOR is not set
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+CONFIG_MTD_CONCAT=y
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+# CONFIG_MTD_CMDLINE_PARTS is not set
+# CONFIG_MTD_AFS_PARTS is not set
+# CONFIG_MTD_AR7_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+# CONFIG_MTD_OOPS is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_CFI_INTELEXT is not set
+CONFIG_MTD_CFI_AMDSTD=y
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+CONFIG_MTD_PHYSMAP=y
+# CONFIG_MTD_PHYSMAP_COMPAT is not set
+# CONFIG_MTD_ARM_INTEGRATOR is not set
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+# CONFIG_MTD_NAND is not set
+# CONFIG_MTD_ONENAND is not set
+
+#
+# LPDDR flash memory drivers
+#
+# CONFIG_MTD_LPDDR is not set
+
+#
+# UBI - Unsorted block images
+#
+# CONFIG_MTD_UBI is not set
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_DEV_COW_COMMON is not set
+# CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_UB is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=16384
+# CONFIG_BLK_DEV_XIP is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_MG_DISK is not set
+# CONFIG_MISC_DEVICES is not set
+CONFIG_HAVE_IDE=y
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=y
+CONFIG_SCSI_DMA=y
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
+# CONFIG_SCSI_PROC_FS is not set
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+# CONFIG_BLK_DEV_SR is not set
+# CONFIG_CHR_DEV_SG is not set
+# CONFIG_CHR_DEV_SCH is not set
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC is not set
+
+#
+# SCSI Transports
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_SAS_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+# CONFIG_SCSI_SRP_ATTRS is not set
+# CONFIG_SCSI_LOWLEVEL is not set
+# CONFIG_SCSI_DH is not set
+# CONFIG_SCSI_OSD_INITIATOR is not set
+# CONFIG_ATA is not set
+# CONFIG_MD is not set
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_CONSOLE_TRANSLATIONS=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
+# CONFIG_DEVKMEM is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=1
+CONFIG_SERIAL_8250_RUNTIME_UARTS=1
+# CONFIG_SERIAL_8250_EXTENDED is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_HW_RANDOM is not set
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+# CONFIG_I2C is not set
+# CONFIG_SPI is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
+CONFIG_ARCH_REQUIRE_GPIOLIB=y
+CONFIG_GPIOLIB=y
+# CONFIG_GPIO_SYSFS is not set
+
+#
+# Memory mapped GPIO expanders:
+#
+
+#
+# I2C GPIO expanders:
+#
+
+#
+# PCI GPIO expanders:
+#
+
+#
+# SPI GPIO expanders:
+#
+
+#
+# AC97 GPIO expanders:
+#
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+# CONFIG_HWMON is not set
+# CONFIG_THERMAL is not set
+# CONFIG_WATCHDOG is not set
+CONFIG_SSB_POSSIBLE=y
+
+#
+# Sonics Silicon Backplane
+#
+# CONFIG_SSB is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_CORE is not set
+# CONFIG_MFD_SM501 is not set
+# CONFIG_MFD_ASIC3 is not set
+# CONFIG_HTC_EGPIO is not set
+# CONFIG_HTC_PASIC3 is not set
+# CONFIG_MFD_TMIO is not set
+# CONFIG_MFD_T7L66XB is not set
+# CONFIG_MFD_TC6387XB is not set
+# CONFIG_MFD_TC6393XB is not set
+# CONFIG_REGULATOR is not set
+# CONFIG_MEDIA_SUPPORT is not set
+
+#
+# Graphics support
+#
+# CONFIG_VGASTATE is not set
+# CONFIG_VIDEO_OUTPUT_CONTROL is not set
+# CONFIG_FB is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+# CONFIG_SOUND is not set
+# CONFIG_HID_SUPPORT is not set
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+CONFIG_USB_ARCH_HAS_EHCI=y
+CONFIG_USB=y
+# CONFIG_USB_DEBUG is not set
+# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set
+
+#
+# Miscellaneous USB options
+#
+# CONFIG_USB_DEVICEFS is not set
+CONFIG_USB_DEVICE_CLASS=y
+# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_OTG is not set
+CONFIG_USB_MON=y
+# CONFIG_USB_WUSB is not set
+# CONFIG_USB_WUSB_CBAF is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_C67X00_HCD is not set
+# CONFIG_USB_EHCI_HCD is not set
+# CONFIG_USB_OXU210HP_HCD is not set
+# CONFIG_USB_ISP116X_HCD is not set
+# CONFIG_USB_ISP1760_HCD is not set
+# CONFIG_USB_ISP1362_HCD is not set
+# CONFIG_USB_OHCI_HCD is not set
+# CONFIG_USB_SL811_HCD is not set
+# CONFIG_USB_R8A66597_HCD is not set
+# CONFIG_USB_HWA_HCD is not set
+# CONFIG_USB_MUSB_HDRC is not set
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+# CONFIG_USB_WDM is not set
+# CONFIG_USB_TMC is not set
+
+#
+# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may
+#
+
+#
+# also be needed; see USB_STORAGE Help for more info
+#
+CONFIG_USB_STORAGE=y
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_ISD200 is not set
+# CONFIG_USB_STORAGE_USBAT is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_SDDR55 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_STORAGE_ALAUDA is not set
+# CONFIG_USB_STORAGE_ONETOUCH is not set
+# CONFIG_USB_STORAGE_KARMA is not set
+# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set
+# CONFIG_USB_LIBUSUAL is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+
+#
+# USB port drivers
+#
+# CONFIG_USB_SERIAL is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_ADUTUX is not set
+# CONFIG_USB_SEVSEG is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_BERRY_CHARGE is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYPRESS_CY7C63 is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_FTDI_ELAN is not set
+# CONFIG_USB_APPLEDISPLAY is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
+# CONFIG_USB_IOWARRIOR is not set
+# CONFIG_USB_TEST is not set
+# CONFIG_USB_ISIGHTFW is not set
+# CONFIG_USB_VST is not set
+# CONFIG_USB_GADGET is not set
+
+#
+# OTG and related infrastructure
+#
+# CONFIG_USB_GPIO_VBUS is not set
+# CONFIG_NOP_USB_XCEIV is not set
+# CONFIG_MMC is not set
+# CONFIG_MEMSTICK is not set
+# CONFIG_NEW_LEDS is not set
+# CONFIG_ACCESSIBILITY is not set
+CONFIG_RTC_LIB=y
+# CONFIG_RTC_CLASS is not set
+# CONFIG_DMADEVICES is not set
+# CONFIG_AUXDISPLAY is not set
+# CONFIG_UIO is not set
+
+#
+# TI VLYNQ
+#
+# CONFIG_STAGING is not set
+
+#
+# File systems
+#
+# CONFIG_EXT2_FS is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_EXT4_FS is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+CONFIG_FS_POSIX_ACL=y
+# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_BTRFS_FS is not set
+# CONFIG_NILFS2_FS is not set
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
+# CONFIG_DNOTIFY is not set
+# CONFIG_INOTIFY is not set
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+CONFIG_GENERIC_ACL=y
+
+#
+# Caches
+#
+# CONFIG_FSCACHE is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+# CONFIG_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+CONFIG_TMPFS_POSIX_ACL=y
+# CONFIG_HUGETLB_PAGE is not set
+# CONFIG_CONFIGFS_FS is not set
+CONFIG_MISC_FILESYSTEMS=y
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS2_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_SQUASHFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_OMFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+CONFIG_ROMFS_FS=y
+CONFIG_ROMFS_BACKED_BY_BLOCK=y
+# CONFIG_ROMFS_BACKED_BY_MTD is not set
+# CONFIG_ROMFS_BACKED_BY_BOTH is not set
+CONFIG_ROMFS_ON_BLOCK=y
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_KARMA_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+# CONFIG_SYSV68_PARTITION is not set
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+CONFIG_NLS_ISO8859_1=y
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+# CONFIG_ENABLE_WARN_DEPRECATED is not set
+# CONFIG_ENABLE_MUST_CHECK is not set
+CONFIG_FRAME_WARN=1024
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_STRIP_ASM_SYMS is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+CONFIG_DEBUG_FS=y
+# CONFIG_HEADERS_CHECK is not set
+# CONFIG_DEBUG_KERNEL is not set
+CONFIG_DEBUG_BUGVERBOSE=y
+CONFIG_DEBUG_MEMORY_INIT=y
+# CONFIG_RCU_CPU_STALL_DETECTOR is not set
+# CONFIG_LATENCYTOP is not set
+# CONFIG_SYSCTL_SYSCALL_CHECK is not set
+CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_TRACING_SUPPORT=y
+# CONFIG_FTRACE is not set
+# CONFIG_DYNAMIC_DEBUG is not set
+# CONFIG_SAMPLES is not set
+CONFIG_HAVE_ARCH_KGDB=y
+CONFIG_ARM_UNWIND=y
+# CONFIG_DEBUG_USER is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+# CONFIG_SECURITYFS is not set
+# CONFIG_SECURITY_FILE_CAPABILITIES is not set
+# CONFIG_CRYPTO is not set
+# CONFIG_BINARY_PRINTF is not set
+
+#
+# Library routines
+#
+CONFIG_GENERIC_FIND_LAST_BIT=y
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+# CONFIG_CRC_T10DIF is not set
+# CONFIG_CRC_ITU_T is not set
+# CONFIG_CRC32 is not set
+# CONFIG_CRC7 is not set
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_DECOMPRESS_GZIP=y
+CONFIG_DECOMPRESS_BZIP2=y
+CONFIG_DECOMPRESS_LZMA=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
diff --git a/arch/arm/configs/nuc960_defconfig b/arch/arm/configs/nuc960_defconfig
new file mode 100644 (file)
index 0000000..4b2cd9e
--- /dev/null
@@ -0,0 +1,922 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.32-rc7
+# Tue Nov 17 12:20:11 2009
+#
+CONFIG_ARM=y
+CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+CONFIG_GENERIC_GPIO=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
+CONFIG_VECTORS_BASE=0xffff0000
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_LOCK_KERNEL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+CONFIG_BSD_PROCESS_ACCT=y
+# CONFIG_BSD_PROCESS_ACCT_V3 is not set
+
+#
+# RCU Subsystem
+#
+CONFIG_TREE_RCU=y
+# CONFIG_TREE_PREEMPT_RCU is not set
+# CONFIG_RCU_TRACE is not set
+CONFIG_RCU_FANOUT=32
+# CONFIG_RCU_FANOUT_EXACT is not set
+# CONFIG_TREE_RCU_TRACE is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=17
+# CONFIG_GROUP_SCHED is not set
+# CONFIG_CGROUPS is not set
+CONFIG_SYSFS_DEPRECATED=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+CONFIG_RELAY=y
+CONFIG_NAMESPACES=y
+# CONFIG_UTS_NS is not set
+# CONFIG_IPC_NS is not set
+CONFIG_USER_NS=y
+# CONFIG_PID_NS is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_RD_GZIP=y
+CONFIG_RD_BZIP2=y
+CONFIG_RD_LZMA=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+CONFIG_ANON_INODES=y
+# CONFIG_EMBEDDED is not set
+CONFIG_UID16=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+CONFIG_KALLSYMS_EXTRA_PASS=y
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_AIO=y
+
+#
+# Kernel Performance Events And Counters
+#
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_COMPAT_BRK=y
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
+# CONFIG_PROFILING is not set
+CONFIG_HAVE_OPROFILE=y
+CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_KRETPROBES=y
+CONFIG_HAVE_CLK=y
+
+#
+# GCOV-based kernel profiling
+#
+# CONFIG_GCOV_KERNEL is not set
+# CONFIG_SLOW_WORK is not set
+CONFIG_HAVE_GENERIC_DMA_COHERENT=y
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
+CONFIG_BASE_SMALL=0
+# CONFIG_MODULES is not set
+CONFIG_BLOCK=y
+CONFIG_LBDAF=y
+CONFIG_BLK_DEV_BSG=y
+# CONFIG_BLK_DEV_INTEGRITY is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_DEFAULT_AS is not set
+# CONFIG_DEFAULT_DEADLINE is not set
+CONFIG_DEFAULT_CFQ=y
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="cfq"
+# CONFIG_FREEZER is not set
+
+#
+# System Type
+#
+CONFIG_MMU=y
+# CONFIG_ARCH_AAEC2000 is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_REALVIEW is not set
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_AT91 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_GEMINI is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_EP93XX is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_MXC is not set
+# CONFIG_ARCH_STMP3XXX is not set
+# CONFIG_ARCH_NETX is not set
+# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_NOMADIK is not set
+# CONFIG_ARCH_IOP13XX is not set
+# CONFIG_ARCH_IOP32X is not set
+# CONFIG_ARCH_IOP33X is not set
+# CONFIG_ARCH_IXP23XX is not set
+# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_KIRKWOOD is not set
+# CONFIG_ARCH_LOKI is not set
+# CONFIG_ARCH_MV78XX0 is not set
+# CONFIG_ARCH_ORION5X is not set
+# CONFIG_ARCH_MMP is not set
+# CONFIG_ARCH_KS8695 is not set
+# CONFIG_ARCH_NS9XXX is not set
+CONFIG_ARCH_W90X900=y
+# CONFIG_ARCH_PNX4008 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_MSM is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_S3C64XX is not set
+# CONFIG_ARCH_S5PC1XX is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_U300 is not set
+# CONFIG_ARCH_DAVINCI is not set
+# CONFIG_ARCH_OMAP is not set
+# CONFIG_ARCH_BCMRING is not set
+CONFIG_CPU_NUC960=y
+
+#
+# W90P910 Machines
+#
+# CONFIG_MACH_W90P910EVB is not set
+
+#
+# NUC950 Machines
+#
+# CONFIG_MACH_W90P950EVB is not set
+
+#
+# NUC960 Machines
+#
+CONFIG_MACH_W90N960EVB=y
+
+#
+# NUC932 Machines
+#
+# CONFIG_MACH_NUC932EVB is not set
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_ARM926T=y
+CONFIG_CPU_32v5=y
+CONFIG_CPU_ABRT_EV5TJ=y
+CONFIG_CPU_PABRT_LEGACY=y
+CONFIG_CPU_CACHE_VIVT=y
+CONFIG_CPU_COPY_V4WB=y
+CONFIG_CPU_TLB_V4WBI=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
+
+#
+# Processor Features
+#
+CONFIG_ARM_THUMB=y
+# CONFIG_CPU_ICACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_WRITETHROUGH is not set
+# CONFIG_CPU_CACHE_ROUND_ROBIN is not set
+CONFIG_ARM_L1_CACHE_SHIFT=5
+CONFIG_COMMON_CLKDEV=y
+
+#
+# Bus support
+#
+# CONFIG_PCI_SYSCALL is not set
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+CONFIG_TICK_ONESHOT=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+CONFIG_VMSPLIT_3G=y
+# CONFIG_VMSPLIT_2G is not set
+# CONFIG_VMSPLIT_1G is not set
+CONFIG_PAGE_OFFSET=0xC0000000
+# CONFIG_PREEMPT_NONE is not set
+# CONFIG_PREEMPT_VOLUNTARY is not set
+CONFIG_PREEMPT=y
+CONFIG_HZ=100
+CONFIG_AEABI=y
+CONFIG_OABI_COMPAT=y
+# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set
+# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set
+# CONFIG_HIGHMEM is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+CONFIG_PAGEFLAGS_EXTENDED=y
+CONFIG_SPLIT_PTLOCK_CPUS=4096
+# CONFIG_PHYS_ADDR_T_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=0
+CONFIG_VIRT_TO_BUS=y
+CONFIG_HAVE_MLOCK=y
+CONFIG_HAVE_MLOCKED_PAGE_BIT=y
+# CONFIG_KSM is not set
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
+CONFIG_ALIGNMENT_TRAP=y
+# CONFIG_UACCESS_WITH_MEMCPY is not set
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0
+CONFIG_ZBOOT_ROM_BSS=0
+CONFIG_CMDLINE="root=/dev/ram0 console=ttyS0,115200n8 rdinit=/sbin/init mem=64M"
+# CONFIG_XIP_KERNEL is not set
+CONFIG_KEXEC=y
+CONFIG_ATAGS_PROC=y
+
+#
+# CPU Power Management
+#
+# CONFIG_CPU_IDLE is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
+# CONFIG_FPE_FASTFPE is not set
+# CONFIG_VFP is not set
+
+#
+# Userspace binary formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_HAVE_AOUT=y
+CONFIG_BINFMT_AOUT=y
+CONFIG_BINFMT_MISC=y
+
+#
+# Power management options
+#
+# CONFIG_PM is not set
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+# CONFIG_NET is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+# CONFIG_DEVTMPFS is not set
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=y
+CONFIG_FIRMWARE_IN_KERNEL=y
+CONFIG_EXTRA_FIRMWARE=""
+# CONFIG_SYS_HYPERVISOR is not set
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+CONFIG_MTD_CONCAT=y
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+# CONFIG_MTD_CMDLINE_PARTS is not set
+# CONFIG_MTD_AFS_PARTS is not set
+# CONFIG_MTD_AR7_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+# CONFIG_MTD_OOPS is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_CFI_INTELEXT is not set
+CONFIG_MTD_CFI_AMDSTD=y
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+CONFIG_MTD_PHYSMAP=y
+# CONFIG_MTD_PHYSMAP_COMPAT is not set
+# CONFIG_MTD_ARM_INTEGRATOR is not set
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+# CONFIG_MTD_NAND is not set
+# CONFIG_MTD_ONENAND is not set
+
+#
+# LPDDR flash memory drivers
+#
+# CONFIG_MTD_LPDDR is not set
+
+#
+# UBI - Unsorted block images
+#
+# CONFIG_MTD_UBI is not set
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_DEV_COW_COMMON is not set
+# CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_UB is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=16384
+# CONFIG_BLK_DEV_XIP is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_MG_DISK is not set
+# CONFIG_MISC_DEVICES is not set
+CONFIG_HAVE_IDE=y
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=y
+CONFIG_SCSI_DMA=y
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
+# CONFIG_SCSI_PROC_FS is not set
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+# CONFIG_BLK_DEV_SR is not set
+# CONFIG_CHR_DEV_SG is not set
+# CONFIG_CHR_DEV_SCH is not set
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC is not set
+
+#
+# SCSI Transports
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_SAS_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+# CONFIG_SCSI_SRP_ATTRS is not set
+# CONFIG_SCSI_LOWLEVEL is not set
+# CONFIG_SCSI_DH is not set
+# CONFIG_SCSI_OSD_INITIATOR is not set
+# CONFIG_ATA is not set
+# CONFIG_MD is not set
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_CONSOLE_TRANSLATIONS=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
+# CONFIG_DEVKMEM is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=1
+CONFIG_SERIAL_8250_RUNTIME_UARTS=1
+# CONFIG_SERIAL_8250_EXTENDED is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_HW_RANDOM is not set
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+# CONFIG_I2C is not set
+# CONFIG_SPI is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
+CONFIG_ARCH_REQUIRE_GPIOLIB=y
+CONFIG_GPIOLIB=y
+# CONFIG_GPIO_SYSFS is not set
+
+#
+# Memory mapped GPIO expanders:
+#
+
+#
+# I2C GPIO expanders:
+#
+
+#
+# PCI GPIO expanders:
+#
+
+#
+# SPI GPIO expanders:
+#
+
+#
+# AC97 GPIO expanders:
+#
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+# CONFIG_HWMON is not set
+# CONFIG_THERMAL is not set
+# CONFIG_WATCHDOG is not set
+CONFIG_SSB_POSSIBLE=y
+
+#
+# Sonics Silicon Backplane
+#
+# CONFIG_SSB is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_CORE is not set
+# CONFIG_MFD_SM501 is not set
+# CONFIG_MFD_ASIC3 is not set
+# CONFIG_HTC_EGPIO is not set
+# CONFIG_HTC_PASIC3 is not set
+# CONFIG_MFD_TMIO is not set
+# CONFIG_MFD_T7L66XB is not set
+# CONFIG_MFD_TC6387XB is not set
+# CONFIG_MFD_TC6393XB is not set
+# CONFIG_REGULATOR is not set
+# CONFIG_MEDIA_SUPPORT is not set
+
+#
+# Graphics support
+#
+# CONFIG_VGASTATE is not set
+# CONFIG_VIDEO_OUTPUT_CONTROL is not set
+# CONFIG_FB is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+# CONFIG_SOUND is not set
+# CONFIG_HID_SUPPORT is not set
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+CONFIG_USB_ARCH_HAS_EHCI=y
+CONFIG_USB=y
+# CONFIG_USB_DEBUG is not set
+# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set
+
+#
+# Miscellaneous USB options
+#
+# CONFIG_USB_DEVICEFS is not set
+CONFIG_USB_DEVICE_CLASS=y
+# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_OTG is not set
+CONFIG_USB_MON=y
+# CONFIG_USB_WUSB is not set
+# CONFIG_USB_WUSB_CBAF is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_C67X00_HCD is not set
+# CONFIG_USB_EHCI_HCD is not set
+# CONFIG_USB_OXU210HP_HCD is not set
+# CONFIG_USB_ISP116X_HCD is not set
+# CONFIG_USB_ISP1760_HCD is not set
+# CONFIG_USB_ISP1362_HCD is not set
+# CONFIG_USB_OHCI_HCD is not set
+# CONFIG_USB_SL811_HCD is not set
+# CONFIG_USB_R8A66597_HCD is not set
+# CONFIG_USB_HWA_HCD is not set
+# CONFIG_USB_MUSB_HDRC is not set
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+# CONFIG_USB_WDM is not set
+# CONFIG_USB_TMC is not set
+
+#
+# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may
+#
+
+#
+# also be needed; see USB_STORAGE Help for more info
+#
+CONFIG_USB_STORAGE=y
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_ISD200 is not set
+# CONFIG_USB_STORAGE_USBAT is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_SDDR55 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_STORAGE_ALAUDA is not set
+# CONFIG_USB_STORAGE_ONETOUCH is not set
+# CONFIG_USB_STORAGE_KARMA is not set
+# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set
+# CONFIG_USB_LIBUSUAL is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+
+#
+# USB port drivers
+#
+# CONFIG_USB_SERIAL is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_ADUTUX is not set
+# CONFIG_USB_SEVSEG is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_BERRY_CHARGE is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYPRESS_CY7C63 is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_FTDI_ELAN is not set
+# CONFIG_USB_APPLEDISPLAY is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
+# CONFIG_USB_IOWARRIOR is not set
+# CONFIG_USB_TEST is not set
+# CONFIG_USB_ISIGHTFW is not set
+# CONFIG_USB_VST is not set
+# CONFIG_USB_GADGET is not set
+
+#
+# OTG and related infrastructure
+#
+# CONFIG_USB_GPIO_VBUS is not set
+# CONFIG_NOP_USB_XCEIV is not set
+# CONFIG_MMC is not set
+# CONFIG_MEMSTICK is not set
+# CONFIG_NEW_LEDS is not set
+# CONFIG_ACCESSIBILITY is not set
+CONFIG_RTC_LIB=y
+# CONFIG_RTC_CLASS is not set
+# CONFIG_DMADEVICES is not set
+# CONFIG_AUXDISPLAY is not set
+# CONFIG_UIO is not set
+
+#
+# TI VLYNQ
+#
+# CONFIG_STAGING is not set
+
+#
+# File systems
+#
+# CONFIG_EXT2_FS is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_EXT4_FS is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+CONFIG_FS_POSIX_ACL=y
+# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_BTRFS_FS is not set
+# CONFIG_NILFS2_FS is not set
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
+# CONFIG_DNOTIFY is not set
+# CONFIG_INOTIFY is not set
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+CONFIG_GENERIC_ACL=y
+
+#
+# Caches
+#
+# CONFIG_FSCACHE is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+# CONFIG_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+CONFIG_TMPFS_POSIX_ACL=y
+# CONFIG_HUGETLB_PAGE is not set
+# CONFIG_CONFIGFS_FS is not set
+CONFIG_MISC_FILESYSTEMS=y
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS2_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_SQUASHFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_OMFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+CONFIG_ROMFS_FS=y
+CONFIG_ROMFS_BACKED_BY_BLOCK=y
+# CONFIG_ROMFS_BACKED_BY_MTD is not set
+# CONFIG_ROMFS_BACKED_BY_BOTH is not set
+CONFIG_ROMFS_ON_BLOCK=y
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_KARMA_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+# CONFIG_SYSV68_PARTITION is not set
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+CONFIG_NLS_ISO8859_1=y
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+# CONFIG_ENABLE_WARN_DEPRECATED is not set
+# CONFIG_ENABLE_MUST_CHECK is not set
+CONFIG_FRAME_WARN=1024
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_STRIP_ASM_SYMS is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+CONFIG_DEBUG_FS=y
+# CONFIG_HEADERS_CHECK is not set
+# CONFIG_DEBUG_KERNEL is not set
+CONFIG_DEBUG_BUGVERBOSE=y
+CONFIG_DEBUG_MEMORY_INIT=y
+# CONFIG_RCU_CPU_STALL_DETECTOR is not set
+# CONFIG_LATENCYTOP is not set
+# CONFIG_SYSCTL_SYSCALL_CHECK is not set
+CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_TRACING_SUPPORT=y
+# CONFIG_FTRACE is not set
+# CONFIG_DYNAMIC_DEBUG is not set
+# CONFIG_SAMPLES is not set
+CONFIG_HAVE_ARCH_KGDB=y
+CONFIG_ARM_UNWIND=y
+# CONFIG_DEBUG_USER is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+# CONFIG_SECURITYFS is not set
+# CONFIG_SECURITY_FILE_CAPABILITIES is not set
+# CONFIG_CRYPTO is not set
+# CONFIG_BINARY_PRINTF is not set
+
+#
+# Library routines
+#
+CONFIG_GENERIC_FIND_LAST_BIT=y
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+# CONFIG_CRC_T10DIF is not set
+# CONFIG_CRC_ITU_T is not set
+# CONFIG_CRC32 is not set
+# CONFIG_CRC7 is not set
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_DECOMPRESS_GZIP=y
+CONFIG_DECOMPRESS_BZIP2=y
+CONFIG_DECOMPRESS_LZMA=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
index b3c8cce..9cfae37 100644 (file)
@@ -52,8 +52,8 @@ CONFIG_FAIR_GROUP_SCHED=y
 # CONFIG_RT_GROUP_SCHED is not set
 CONFIG_USER_SCHED=y
 # CONFIG_CGROUP_SCHED is not set
-CONFIG_SYSFS_DEPRECATED=y
-CONFIG_SYSFS_DEPRECATED_V2=y
+# CONFIG_SYSFS_DEPRECATED=y is not set
+# CONFIG_SYSFS_DEPRECATED_V2=y is not set
 # CONFIG_RELAY is not set
 # CONFIG_NAMESPACES is not set
 CONFIG_BLK_DEV_INITRD=y
diff --git a/arch/arm/configs/omap3_defconfig b/arch/arm/configs/omap3_defconfig
new file mode 100644 (file)
index 0000000..2af28ea
--- /dev/null
@@ -0,0 +1,2119 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.32-rc8
+# Tue Dec  1 14:04:02 2009
+#
+CONFIG_ARM=y
+CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+CONFIG_GENERIC_GPIO=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_ARCH_HAS_CPUFREQ=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
+CONFIG_OPROFILE_ARMV7=y
+CONFIG_VECTORS_BASE=0xffff0000
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_POSIX_MQUEUE_SYSCTL=y
+CONFIG_BSD_PROCESS_ACCT=y
+# CONFIG_BSD_PROCESS_ACCT_V3 is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_AUDIT is not set
+
+#
+# RCU Subsystem
+#
+CONFIG_TREE_RCU=y
+# CONFIG_TREE_PREEMPT_RCU is not set
+# CONFIG_RCU_TRACE is not set
+CONFIG_RCU_FANOUT=32
+# CONFIG_RCU_FANOUT_EXACT is not set
+# CONFIG_TREE_RCU_TRACE is not set
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_GROUP_SCHED=y
+CONFIG_FAIR_GROUP_SCHED=y
+# CONFIG_RT_GROUP_SCHED is not set
+CONFIG_USER_SCHED=y
+# CONFIG_CGROUP_SCHED is not set
+# CONFIG_CGROUPS is not set
+# CONFIG_SYSFS_DEPRECATED_V2 is not set
+# CONFIG_RELAY is not set
+# CONFIG_NAMESPACES is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_RD_GZIP=y
+# CONFIG_RD_BZIP2 is not set
+# CONFIG_RD_LZMA is not set
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+CONFIG_ANON_INODES=y
+CONFIG_EMBEDDED=y
+CONFIG_UID16=y
+# CONFIG_SYSCTL_SYSCALL is not set
+CONFIG_KALLSYMS=y
+CONFIG_KALLSYMS_ALL=y
+CONFIG_KALLSYMS_EXTRA_PASS=y
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_AIO=y
+
+#
+# Kernel Performance Events And Counters
+#
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_COMPAT_BRK=y
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
+CONFIG_PROFILING=y
+CONFIG_TRACEPOINTS=y
+CONFIG_OPROFILE=y
+CONFIG_HAVE_OPROFILE=y
+CONFIG_KPROBES=y
+CONFIG_KRETPROBES=y
+CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_KRETPROBES=y
+CONFIG_HAVE_CLK=y
+
+#
+# GCOV-based kernel profiling
+#
+# CONFIG_GCOV_KERNEL is not set
+# CONFIG_SLOW_WORK is not set
+CONFIG_HAVE_GENERIC_DMA_COHERENT=y
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+CONFIG_MODULE_FORCE_LOAD=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+CONFIG_MODVERSIONS=y
+CONFIG_MODULE_SRCVERSION_ALL=y
+CONFIG_BLOCK=y
+CONFIG_LBDAF=y
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_BLK_DEV_INTEGRITY is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_DEFAULT_AS is not set
+# CONFIG_DEFAULT_DEADLINE is not set
+CONFIG_DEFAULT_CFQ=y
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="cfq"
+CONFIG_FREEZER=y
+
+#
+# System Type
+#
+CONFIG_MMU=y
+# CONFIG_ARCH_AAEC2000 is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_REALVIEW is not set
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_AT91 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_GEMINI is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_EP93XX is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_MXC is not set
+# CONFIG_ARCH_STMP3XXX is not set
+# CONFIG_ARCH_NETX is not set
+# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_NOMADIK is not set
+# CONFIG_ARCH_IOP13XX is not set
+# CONFIG_ARCH_IOP32X is not set
+# CONFIG_ARCH_IOP33X is not set
+# CONFIG_ARCH_IXP23XX is not set
+# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_KIRKWOOD is not set
+# CONFIG_ARCH_LOKI is not set
+# CONFIG_ARCH_MV78XX0 is not set
+# CONFIG_ARCH_ORION5X is not set
+# CONFIG_ARCH_MMP is not set
+# CONFIG_ARCH_KS8695 is not set
+# CONFIG_ARCH_NS9XXX is not set
+# CONFIG_ARCH_W90X900 is not set
+# CONFIG_ARCH_PNX4008 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_MSM is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_S3C64XX is not set
+# CONFIG_ARCH_S5PC1XX is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_U300 is not set
+# CONFIG_ARCH_DAVINCI is not set
+CONFIG_ARCH_OMAP=y
+# CONFIG_ARCH_BCMRING is not set
+
+#
+# TI OMAP Implementations
+#
+CONFIG_ARCH_OMAP_OTG=y
+# CONFIG_ARCH_OMAP1 is not set
+# CONFIG_ARCH_OMAP2 is not set
+CONFIG_ARCH_OMAP3=y
+# CONFIG_ARCH_OMAP4 is not set
+
+#
+# OMAP Feature Selections
+#
+# CONFIG_OMAP_DEBUG_POWERDOMAIN is not set
+# CONFIG_OMAP_DEBUG_CLOCKDOMAIN is not set
+CONFIG_OMAP_RESET_CLOCKS=y
+CONFIG_OMAP_MUX=y
+CONFIG_OMAP_MUX_DEBUG=y
+CONFIG_OMAP_MUX_WARNINGS=y
+CONFIG_OMAP_MCBSP=y
+# CONFIG_OMAP_MBOX_FWK is not set
+# CONFIG_OMAP_MPU_TIMER is not set
+CONFIG_OMAP_32K_TIMER=y
+CONFIG_OMAP_32K_TIMER_HZ=128
+CONFIG_OMAP_DM_TIMER=y
+# CONFIG_OMAP_LL_DEBUG_UART1 is not set
+# CONFIG_OMAP_LL_DEBUG_UART2 is not set
+# CONFIG_OMAP_LL_DEBUG_UART3 is not set
+CONFIG_OMAP_LL_DEBUG_NONE=y
+# CONFIG_OMAP_PM_NONE is not set
+CONFIG_OMAP_PM_NOOP=y
+CONFIG_ARCH_OMAP34XX=y
+CONFIG_ARCH_OMAP3430=y
+
+#
+# OMAP Board Type
+#
+CONFIG_MACH_OMAP3_BEAGLE=y
+CONFIG_MACH_OMAP_LDP=y
+CONFIG_MACH_OVERO=y
+CONFIG_MACH_OMAP3EVM=y
+CONFIG_MACH_OMAP3517EVM=y
+CONFIG_MACH_OMAP3_PANDORA=y
+CONFIG_MACH_OMAP_3430SDP=y
+CONFIG_MACH_NOKIA_RX51=y
+CONFIG_MACH_OMAP_ZOOM2=y
+CONFIG_MACH_OMAP_ZOOM3=y
+CONFIG_MACH_CM_T35=y
+CONFIG_MACH_IGEP0020=y
+CONFIG_MACH_OMAP_3630SDP=y
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_32v6K=y
+CONFIG_CPU_V7=y
+CONFIG_CPU_32v7=y
+CONFIG_CPU_ABRT_EV7=y
+CONFIG_CPU_PABRT_V7=y
+CONFIG_CPU_CACHE_V7=y
+CONFIG_CPU_CACHE_VIPT=y
+CONFIG_CPU_COPY_V6=y
+CONFIG_CPU_TLB_V7=y
+CONFIG_CPU_HAS_ASID=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
+
+#
+# Processor Features
+#
+CONFIG_ARM_THUMB=y
+CONFIG_ARM_THUMBEE=y
+# CONFIG_CPU_ICACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_DISABLE is not set
+# CONFIG_CPU_BPREDICT_DISABLE is not set
+CONFIG_HAS_TLS_REG=y
+CONFIG_ARM_L1_CACHE_SHIFT=6
+# CONFIG_ARM_ERRATA_430973 is not set
+# CONFIG_ARM_ERRATA_458693 is not set
+# CONFIG_ARM_ERRATA_460075 is not set
+CONFIG_COMMON_CLKDEV=y
+
+#
+# Bus support
+#
+# CONFIG_PCI_SYSCALL is not set
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+CONFIG_TICK_ONESHOT=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+CONFIG_VMSPLIT_3G=y
+# CONFIG_VMSPLIT_2G is not set
+# CONFIG_VMSPLIT_1G is not set
+CONFIG_PAGE_OFFSET=0xC0000000
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+CONFIG_HZ=128
+# CONFIG_THUMB2_KERNEL is not set
+CONFIG_AEABI=y
+CONFIG_OABI_COMPAT=y
+# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set
+# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set
+# CONFIG_HIGHMEM is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+CONFIG_PAGEFLAGS_EXTENDED=y
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_PHYS_ADDR_T_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=0
+CONFIG_VIRT_TO_BUS=y
+CONFIG_HAVE_MLOCK=y
+CONFIG_HAVE_MLOCKED_PAGE_BIT=y
+# CONFIG_KSM is not set
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
+CONFIG_LEDS=y
+CONFIG_ALIGNMENT_TRAP=y
+# CONFIG_UACCESS_WITH_MEMCPY is not set
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="root=/dev/nfs nfsroot=192.168.0.1:/home/user/buildroot ip=192.168.0.2:192.168.0.1:192.168.0.1:255.255.255.0:tgt:eth0:off rw console=ttyS2,115200n8"
+# CONFIG_XIP_KERNEL is not set
+CONFIG_KEXEC=y
+CONFIG_ATAGS_PROC=y
+
+#
+# CPU Power Management
+#
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_TABLE=y
+# CONFIG_CPU_FREQ_DEBUG is not set
+CONFIG_CPU_FREQ_STAT=y
+CONFIG_CPU_FREQ_STAT_DETAILS=y
+CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y
+# CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set
+CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
+# CONFIG_CPU_FREQ_GOV_POWERSAVE is not set
+CONFIG_CPU_FREQ_GOV_USERSPACE=y
+CONFIG_CPU_FREQ_GOV_ONDEMAND=y
+# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set
+# CONFIG_CPU_IDLE is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
+# CONFIG_FPE_FASTFPE is not set
+CONFIG_VFP=y
+CONFIG_VFPv3=y
+CONFIG_NEON=y
+
+#
+# Userspace binary formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_HAVE_AOUT=y
+# CONFIG_BINFMT_AOUT is not set
+CONFIG_BINFMT_MISC=y
+
+#
+# Power management options
+#
+CONFIG_PM=y
+CONFIG_PM_DEBUG=y
+CONFIG_PM_VERBOSE=y
+CONFIG_CAN_PM_TRACE=y
+CONFIG_PM_SLEEP=y
+CONFIG_SUSPEND=y
+# CONFIG_PM_TEST_SUSPEND is not set
+CONFIG_SUSPEND_FREEZER=y
+# CONFIG_APM_EMULATION is not set
+# CONFIG_PM_RUNTIME is not set
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+CONFIG_PACKET_MMAP=y
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+CONFIG_XFRM_USER=y
+# CONFIG_XFRM_SUB_POLICY is not set
+CONFIG_XFRM_MIGRATE=y
+# CONFIG_XFRM_STATISTICS is not set
+CONFIG_NET_KEY=y
+CONFIG_NET_KEY_MIGRATE=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+CONFIG_IP_PNP_RARP=y
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
+# CONFIG_INET_LRO is not set
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_NETLABEL is not set
+# CONFIG_NETWORK_SECMARK is not set
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+CONFIG_NETFILTER_ADVANCED=y
+
+#
+# Core Netfilter Configuration
+#
+# CONFIG_NETFILTER_NETLINK_QUEUE is not set
+# CONFIG_NETFILTER_NETLINK_LOG is not set
+# CONFIG_NF_CONNTRACK is not set
+# CONFIG_NETFILTER_XTABLES is not set
+# CONFIG_IP_VS is not set
+
+#
+# IP: Netfilter Configuration
+#
+# CONFIG_NF_DEFRAG_IPV4 is not set
+# CONFIG_IP_NF_QUEUE is not set
+# CONFIG_IP_NF_IPTABLES is not set
+# CONFIG_IP_NF_ARPTABLES is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# CONFIG_RDS is not set
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_NET_DSA is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_PHONET is not set
+# CONFIG_IEEE802154 is not set
+# CONFIG_NET_SCHED is not set
+# CONFIG_DCB is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_NET_TCPPROBE is not set
+# CONFIG_NET_DROP_MONITOR is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_CAN is not set
+# CONFIG_IRDA is not set
+CONFIG_BT=y
+CONFIG_BT_L2CAP=y
+CONFIG_BT_SCO=y
+CONFIG_BT_RFCOMM=y
+CONFIG_BT_RFCOMM_TTY=y
+CONFIG_BT_BNEP=y
+CONFIG_BT_BNEP_MC_FILTER=y
+CONFIG_BT_BNEP_PROTO_FILTER=y
+CONFIG_BT_HIDP=y
+
+#
+# Bluetooth device drivers
+#
+# CONFIG_BT_HCIBTUSB is not set
+# CONFIG_BT_HCIBTSDIO is not set
+CONFIG_BT_HCIUART=y
+CONFIG_BT_HCIUART_H4=y
+CONFIG_BT_HCIUART_BCSP=y
+CONFIG_BT_HCIUART_LL=y
+CONFIG_BT_HCIBCM203X=y
+CONFIG_BT_HCIBPA10X=y
+# CONFIG_BT_HCIBFUSB is not set
+# CONFIG_BT_HCIVHCI is not set
+# CONFIG_BT_MRVL is not set
+# CONFIG_AF_RXRPC is not set
+CONFIG_WIRELESS=y
+CONFIG_CFG80211=y
+# CONFIG_NL80211_TESTMODE is not set
+# CONFIG_CFG80211_DEVELOPER_WARNINGS is not set
+# CONFIG_CFG80211_REG_DEBUG is not set
+CONFIG_CFG80211_DEFAULT_PS=y
+CONFIG_CFG80211_DEFAULT_PS_VALUE=1
+# CONFIG_CFG80211_DEBUGFS is not set
+CONFIG_WIRELESS_OLD_REGULATORY=y
+CONFIG_WIRELESS_EXT=y
+CONFIG_WIRELESS_EXT_SYSFS=y
+CONFIG_LIB80211=y
+# CONFIG_LIB80211_DEBUG is not set
+CONFIG_MAC80211=y
+CONFIG_MAC80211_RC_PID=y
+CONFIG_MAC80211_RC_MINSTREL=y
+CONFIG_MAC80211_RC_DEFAULT_PID=y
+# CONFIG_MAC80211_RC_DEFAULT_MINSTREL is not set
+CONFIG_MAC80211_RC_DEFAULT="pid"
+# CONFIG_MAC80211_MESH is not set
+CONFIG_MAC80211_LEDS=y
+# CONFIG_MAC80211_DEBUGFS is not set
+# CONFIG_MAC80211_DEBUG_MENU is not set
+# CONFIG_WIMAX is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+# CONFIG_DEVTMPFS is not set
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=y
+CONFIG_FIRMWARE_IN_KERNEL=y
+CONFIG_EXTRA_FIRMWARE=""
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES is not set
+# CONFIG_SYS_HYPERVISOR is not set
+CONFIG_CONNECTOR=y
+CONFIG_PROC_EVENTS=y
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_TESTS is not set
+CONFIG_MTD_CONCAT=y
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+# CONFIG_MTD_AFS_PARTS is not set
+# CONFIG_MTD_AR7_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+CONFIG_MTD_OOPS=y
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+CONFIG_MTD_CFI_INTELEXT=y
+# CONFIG_MTD_CFI_AMDSTD is not set
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PHYSMAP is not set
+# CONFIG_MTD_ARM_INTEGRATOR is not set
+CONFIG_MTD_OMAP_NOR=y
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_DATAFLASH is not set
+# CONFIG_MTD_M25P80 is not set
+# CONFIG_MTD_SST25L is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+CONFIG_MTD_NAND=y
+# CONFIG_MTD_NAND_VERIFY_WRITE is not set
+# CONFIG_MTD_NAND_ECC_SMC is not set
+# CONFIG_MTD_NAND_MUSEUM_IDS is not set
+# CONFIG_MTD_NAND_GPIO is not set
+CONFIG_MTD_NAND_OMAP2=y
+CONFIG_MTD_NAND_OMAP_PREFETCH=y
+# CONFIG_MTD_NAND_OMAP_PREFETCH_DMA is not set
+CONFIG_MTD_NAND_IDS=y
+# CONFIG_MTD_NAND_DISKONCHIP is not set
+# CONFIG_MTD_NAND_NANDSIM is not set
+# CONFIG_MTD_NAND_PLATFORM is not set
+# CONFIG_MTD_ALAUDA is not set
+CONFIG_MTD_ONENAND=y
+CONFIG_MTD_ONENAND_VERIFY_WRITE=y
+# CONFIG_MTD_ONENAND_GENERIC is not set
+CONFIG_MTD_ONENAND_OMAP2=y
+# CONFIG_MTD_ONENAND_OTP is not set
+# CONFIG_MTD_ONENAND_2X_PROGRAM is not set
+# CONFIG_MTD_ONENAND_SIM is not set
+
+#
+# LPDDR flash memory drivers
+#
+# CONFIG_MTD_LPDDR is not set
+
+#
+# UBI - Unsorted block images
+#
+CONFIG_MTD_UBI=y
+CONFIG_MTD_UBI_WL_THRESHOLD=4096
+CONFIG_MTD_UBI_BEB_RESERVE=1
+# CONFIG_MTD_UBI_GLUEBI is not set
+
+#
+# UBI debugging options
+#
+# CONFIG_MTD_UBI_DEBUG is not set
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_UB is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=16384
+# CONFIG_BLK_DEV_XIP is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+# CONFIG_MG_DISK is not set
+CONFIG_MISC_DEVICES=y
+# CONFIG_ICS932S401 is not set
+# CONFIG_ENCLOSURE_SERVICES is not set
+# CONFIG_ISL29003 is not set
+# CONFIG_C2PORT is not set
+
+#
+# EEPROM support
+#
+# CONFIG_EEPROM_AT24 is not set
+# CONFIG_EEPROM_AT25 is not set
+CONFIG_EEPROM_LEGACY=y
+# CONFIG_EEPROM_MAX6875 is not set
+# CONFIG_EEPROM_93CX6 is not set
+CONFIG_HAVE_IDE=y
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=y
+CONFIG_SCSI_DMA=y
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+# CONFIG_BLK_DEV_SR is not set
+# CONFIG_CHR_DEV_SG is not set
+# CONFIG_CHR_DEV_SCH is not set
+CONFIG_SCSI_MULTI_LUN=y
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+CONFIG_SCSI_SCAN_ASYNC=y
+CONFIG_SCSI_WAIT_SCAN=m
+
+#
+# SCSI Transports
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+# CONFIG_SCSI_SRP_ATTRS is not set
+CONFIG_SCSI_LOWLEVEL=y
+# CONFIG_ISCSI_TCP is not set
+# CONFIG_LIBFC is not set
+# CONFIG_LIBFCOE is not set
+# CONFIG_SCSI_DEBUG is not set
+# CONFIG_SCSI_DH is not set
+# CONFIG_SCSI_OSD_INITIATOR is not set
+# CONFIG_ATA is not set
+CONFIG_MD=y
+# CONFIG_BLK_DEV_MD is not set
+# CONFIG_BLK_DEV_DM is not set
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_VETH is not set
+CONFIG_PHYLIB=y
+
+#
+# MII PHY device drivers
+#
+# CONFIG_MARVELL_PHY is not set
+# CONFIG_DAVICOM_PHY is not set
+# CONFIG_QSEMI_PHY is not set
+# CONFIG_LXT_PHY is not set
+# CONFIG_CICADA_PHY is not set
+# CONFIG_VITESSE_PHY is not set
+CONFIG_SMSC_PHY=y
+# CONFIG_BROADCOM_PHY is not set
+# CONFIG_ICPLUS_PHY is not set
+# CONFIG_REALTEK_PHY is not set
+# CONFIG_NATIONAL_PHY is not set
+# CONFIG_STE10XP is not set
+# CONFIG_LSI_ET1011C_PHY is not set
+# CONFIG_FIXED_PHY is not set
+# CONFIG_MDIO_BITBANG is not set
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_AX88796 is not set
+CONFIG_SMC91X=y
+# CONFIG_DM9000 is not set
+# CONFIG_ENC28J60 is not set
+# CONFIG_ETHOC is not set
+# CONFIG_SMC911X is not set
+CONFIG_SMSC911X=y
+# CONFIG_DNET is not set
+# CONFIG_IBM_NEW_EMAC_ZMII is not set
+# CONFIG_IBM_NEW_EMAC_RGMII is not set
+# CONFIG_IBM_NEW_EMAC_TAH is not set
+# CONFIG_IBM_NEW_EMAC_EMAC4 is not set
+# CONFIG_IBM_NEW_EMAC_NO_FLOW_CTRL is not set
+# CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT is not set
+# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
+# CONFIG_B44 is not set
+# CONFIG_KS8842 is not set
+# CONFIG_KS8851 is not set
+# CONFIG_KS8851_MLL is not set
+CONFIG_NETDEV_1000=y
+CONFIG_NETDEV_10000=y
+CONFIG_WLAN=y
+# CONFIG_WLAN_PRE80211 is not set
+CONFIG_WLAN_80211=y
+CONFIG_LIBERTAS=y
+CONFIG_LIBERTAS_USB=y
+CONFIG_LIBERTAS_SDIO=y
+# CONFIG_LIBERTAS_SPI is not set
+CONFIG_LIBERTAS_DEBUG=y
+# CONFIG_LIBERTAS_THINFIRM is not set
+# CONFIG_AT76C50X_USB is not set
+# CONFIG_USB_ZD1201 is not set
+# CONFIG_USB_NET_RNDIS_WLAN is not set
+# CONFIG_RTL8187 is not set
+# CONFIG_MAC80211_HWSIM is not set
+# CONFIG_P54_COMMON is not set
+# CONFIG_ATH_COMMON is not set
+# CONFIG_HOSTAP is not set
+# CONFIG_B43 is not set
+# CONFIG_B43LEGACY is not set
+# CONFIG_ZD1211RW is not set
+# CONFIG_RT2X00 is not set
+# CONFIG_WL12XX is not set
+# CONFIG_IWM is not set
+
+#
+# Enable WiMAX (Networking options) to see the WiMAX drivers
+#
+
+#
+# USB Network Adapters
+#
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RTL8150 is not set
+CONFIG_USB_USBNET=y
+CONFIG_USB_NET_AX8817X=y
+CONFIG_USB_NET_CDCETHER=y
+# CONFIG_USB_NET_CDC_EEM is not set
+# CONFIG_USB_NET_DM9601 is not set
+# CONFIG_USB_NET_SMSC95XX is not set
+# CONFIG_USB_NET_GL620A is not set
+CONFIG_USB_NET_NET1080=y
+# CONFIG_USB_NET_PLUSB is not set
+# CONFIG_USB_NET_MCS7830 is not set
+# CONFIG_USB_NET_RNDIS_HOST is not set
+CONFIG_USB_NET_CDC_SUBSET=y
+CONFIG_USB_ALI_M5632=y
+CONFIG_USB_AN2720=y
+CONFIG_USB_BELKIN=y
+CONFIG_USB_ARMLINUX=y
+CONFIG_USB_EPSON2888=y
+CONFIG_USB_KC2190=y
+CONFIG_USB_NET_ZAURUS=y
+# CONFIG_USB_NET_INT51X1 is not set
+# CONFIG_WAN is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_ISDN is not set
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+CONFIG_INPUT_JOYDEV=y
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+# CONFIG_KEYBOARD_ADP5588 is not set
+CONFIG_KEYBOARD_ATKBD=y
+# CONFIG_QT2160 is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+CONFIG_KEYBOARD_GPIO=y
+# CONFIG_KEYBOARD_MATRIX is not set
+# CONFIG_KEYBOARD_LM8323 is not set
+# CONFIG_KEYBOARD_MAX7359 is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+# CONFIG_KEYBOARD_OPENCORES is not set
+# CONFIG_KEYBOARD_STOWAWAY is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+CONFIG_KEYBOARD_TWL4030=y
+# CONFIG_KEYBOARD_XTKBD is not set
+CONFIG_INPUT_MOUSE=y
+CONFIG_MOUSE_PS2=y
+CONFIG_MOUSE_PS2_ALPS=y
+CONFIG_MOUSE_PS2_LOGIPS2PP=y
+CONFIG_MOUSE_PS2_SYNAPTICS=y
+CONFIG_MOUSE_PS2_TRACKPOINT=y
+# CONFIG_MOUSE_PS2_ELANTECH is not set
+# CONFIG_MOUSE_PS2_SENTELIC is not set
+# CONFIG_MOUSE_PS2_TOUCHKIT is not set
+# CONFIG_MOUSE_SERIAL is not set
+# CONFIG_MOUSE_APPLETOUCH is not set
+# CONFIG_MOUSE_BCM5974 is not set
+# CONFIG_MOUSE_VSXXXAA is not set
+# CONFIG_MOUSE_GPIO is not set
+# CONFIG_MOUSE_SYNAPTICS_I2C is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_ADS7846=y
+# CONFIG_TOUCHSCREEN_AD7877 is not set
+# CONFIG_TOUCHSCREEN_AD7879_I2C is not set
+# CONFIG_TOUCHSCREEN_AD7879_SPI is not set
+# CONFIG_TOUCHSCREEN_AD7879 is not set
+# CONFIG_TOUCHSCREEN_EETI is not set
+# CONFIG_TOUCHSCREEN_FUJITSU is not set
+# CONFIG_TOUCHSCREEN_GUNZE is not set
+# CONFIG_TOUCHSCREEN_ELO is not set
+# CONFIG_TOUCHSCREEN_WACOM_W8001 is not set
+# CONFIG_TOUCHSCREEN_MCS5000 is not set
+# CONFIG_TOUCHSCREEN_MTOUCH is not set
+# CONFIG_TOUCHSCREEN_INEXIO is not set
+# CONFIG_TOUCHSCREEN_MK712 is not set
+# CONFIG_TOUCHSCREEN_PENMOUNT is not set
+# CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set
+# CONFIG_TOUCHSCREEN_TOUCHWIN is not set
+# CONFIG_TOUCHSCREEN_USB_COMPOSITE is not set
+# CONFIG_TOUCHSCREEN_TOUCHIT213 is not set
+# CONFIG_TOUCHSCREEN_TSC2007 is not set
+# CONFIG_TOUCHSCREEN_W90X900 is not set
+CONFIG_INPUT_MISC=y
+# CONFIG_INPUT_ATI_REMOTE is not set
+# CONFIG_INPUT_ATI_REMOTE2 is not set
+# CONFIG_INPUT_KEYSPAN_REMOTE is not set
+# CONFIG_INPUT_POWERMATE is not set
+# CONFIG_INPUT_YEALINK is not set
+# CONFIG_INPUT_CM109 is not set
+CONFIG_INPUT_TWL4030_PWRBUTTON=y
+# CONFIG_INPUT_UINPUT is not set
+# CONFIG_INPUT_GPIO_ROTARY_ENCODER is not set
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+CONFIG_SERIO_SERPORT=y
+CONFIG_SERIO_LIBPS2=y
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_CONSOLE_TRANSLATIONS=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+CONFIG_VT_HW_CONSOLE_BINDING=y
+CONFIG_DEVKMEM=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=32
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+CONFIG_SERIAL_8250_EXTENDED=y
+CONFIG_SERIAL_8250_MANY_PORTS=y
+CONFIG_SERIAL_8250_SHARE_IRQ=y
+CONFIG_SERIAL_8250_DETECT_IRQ=y
+CONFIG_SERIAL_8250_RSA=y
+
+#
+# Non-8250 serial port support
+#
+# CONFIG_SERIAL_MAX3100 is not set
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_IPMI_HANDLER is not set
+CONFIG_HW_RANDOM=y
+# CONFIG_HW_RANDOM_TIMERIOMEM is not set
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+CONFIG_I2C=y
+CONFIG_I2C_BOARDINFO=y
+CONFIG_I2C_COMPAT=y
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_HELPER_AUTO=y
+
+#
+# I2C Hardware Bus support
+#
+
+#
+# I2C system bus drivers (mostly embedded / system-on-chip)
+#
+# CONFIG_I2C_DESIGNWARE is not set
+# CONFIG_I2C_GPIO is not set
+# CONFIG_I2C_OCORES is not set
+CONFIG_I2C_OMAP=y
+# CONFIG_I2C_SIMTEC is not set
+
+#
+# External I2C/SMBus adapter drivers
+#
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_TAOS_EVM is not set
+# CONFIG_I2C_TINY_USB is not set
+
+#
+# Other I2C/SMBus bus drivers
+#
+# CONFIG_I2C_PCA_PLATFORM is not set
+# CONFIG_I2C_STUB is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_DS1682 is not set
+# CONFIG_SENSORS_TSL2550 is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+CONFIG_SPI=y
+# CONFIG_SPI_DEBUG is not set
+CONFIG_SPI_MASTER=y
+
+#
+# SPI Master Controller Drivers
+#
+# CONFIG_SPI_BITBANG is not set
+# CONFIG_SPI_GPIO is not set
+CONFIG_SPI_OMAP24XX=y
+
+#
+# SPI Protocol Masters
+#
+# CONFIG_SPI_SPIDEV is not set
+# CONFIG_SPI_TLE62X0 is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
+CONFIG_ARCH_REQUIRE_GPIOLIB=y
+CONFIG_GPIOLIB=y
+CONFIG_DEBUG_GPIO=y
+CONFIG_GPIO_SYSFS=y
+
+#
+# Memory mapped GPIO expanders:
+#
+
+#
+# I2C GPIO expanders:
+#
+# CONFIG_GPIO_MAX732X is not set
+# CONFIG_GPIO_PCA953X is not set
+# CONFIG_GPIO_PCF857X is not set
+CONFIG_GPIO_TWL4030=y
+
+#
+# PCI GPIO expanders:
+#
+
+#
+# SPI GPIO expanders:
+#
+# CONFIG_GPIO_MAX7301 is not set
+# CONFIG_GPIO_MCP23S08 is not set
+# CONFIG_GPIO_MC33880 is not set
+
+#
+# AC97 GPIO expanders:
+#
+CONFIG_W1=y
+CONFIG_W1_CON=y
+
+#
+# 1-wire Bus Masters
+#
+# CONFIG_W1_MASTER_DS2490 is not set
+# CONFIG_W1_MASTER_DS2482 is not set
+# CONFIG_W1_MASTER_DS1WM is not set
+# CONFIG_W1_MASTER_GPIO is not set
+# CONFIG_HDQ_MASTER_OMAP is not set
+
+#
+# 1-wire Slaves
+#
+# CONFIG_W1_SLAVE_THERM is not set
+# CONFIG_W1_SLAVE_SMEM is not set
+# CONFIG_W1_SLAVE_DS2431 is not set
+# CONFIG_W1_SLAVE_DS2433 is not set
+# CONFIG_W1_SLAVE_DS2760 is not set
+# CONFIG_W1_SLAVE_BQ27000 is not set
+CONFIG_POWER_SUPPLY=y
+# CONFIG_POWER_SUPPLY_DEBUG is not set
+# CONFIG_PDA_POWER is not set
+# CONFIG_BATTERY_DS2760 is not set
+# CONFIG_BATTERY_DS2782 is not set
+# CONFIG_BATTERY_BQ27x00 is not set
+# CONFIG_BATTERY_MAX17040 is not set
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
+
+#
+# Native drivers
+#
+# CONFIG_SENSORS_AD7414 is not set
+# CONFIG_SENSORS_AD7418 is not set
+# CONFIG_SENSORS_ADCXX is not set
+# CONFIG_SENSORS_ADM1021 is not set
+# CONFIG_SENSORS_ADM1025 is not set
+# CONFIG_SENSORS_ADM1026 is not set
+# CONFIG_SENSORS_ADM1029 is not set
+# CONFIG_SENSORS_ADM1031 is not set
+# CONFIG_SENSORS_ADM9240 is not set
+# CONFIG_SENSORS_ADT7462 is not set
+# CONFIG_SENSORS_ADT7470 is not set
+# CONFIG_SENSORS_ADT7473 is not set
+# CONFIG_SENSORS_ADT7475 is not set
+# CONFIG_SENSORS_ATXP1 is not set
+# CONFIG_SENSORS_DS1621 is not set
+# CONFIG_SENSORS_F71805F is not set
+# CONFIG_SENSORS_F71882FG is not set
+# CONFIG_SENSORS_F75375S is not set
+# CONFIG_SENSORS_G760A is not set
+# CONFIG_SENSORS_GL518SM is not set
+# CONFIG_SENSORS_GL520SM is not set
+# CONFIG_SENSORS_IT87 is not set
+# CONFIG_SENSORS_LM63 is not set
+# CONFIG_SENSORS_LM70 is not set
+# CONFIG_SENSORS_LM75 is not set
+# CONFIG_SENSORS_LM77 is not set
+# CONFIG_SENSORS_LM78 is not set
+# CONFIG_SENSORS_LM80 is not set
+# CONFIG_SENSORS_LM83 is not set
+# CONFIG_SENSORS_LM85 is not set
+# CONFIG_SENSORS_LM87 is not set
+# CONFIG_SENSORS_LM90 is not set
+# CONFIG_SENSORS_LM92 is not set
+# CONFIG_SENSORS_LM93 is not set
+# CONFIG_SENSORS_LTC4215 is not set
+# CONFIG_SENSORS_LTC4245 is not set
+# CONFIG_SENSORS_LM95241 is not set
+# CONFIG_SENSORS_MAX1111 is not set
+# CONFIG_SENSORS_MAX1619 is not set
+# CONFIG_SENSORS_MAX6650 is not set
+# CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_PC87427 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_SENSORS_SHT15 is not set
+# CONFIG_SENSORS_DME1737 is not set
+# CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_SMSC47M192 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_ADS7828 is not set
+# CONFIG_SENSORS_THMC50 is not set
+# CONFIG_SENSORS_TMP401 is not set
+# CONFIG_SENSORS_TMP421 is not set
+# CONFIG_SENSORS_VT1211 is not set
+# CONFIG_SENSORS_W83781D is not set
+# CONFIG_SENSORS_W83791D is not set
+# CONFIG_SENSORS_W83792D is not set
+# CONFIG_SENSORS_W83793 is not set
+# CONFIG_SENSORS_W83L785TS is not set
+# CONFIG_SENSORS_W83L786NG is not set
+# CONFIG_SENSORS_W83627HF is not set
+# CONFIG_SENSORS_W83627EHF is not set
+# CONFIG_SENSORS_LIS3_SPI is not set
+# CONFIG_THERMAL is not set
+CONFIG_WATCHDOG=y
+CONFIG_WATCHDOG_NOWAYOUT=y
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+CONFIG_OMAP_WATCHDOG=y
+CONFIG_TWL4030_WATCHDOG=y
+
+#
+# USB-based Watchdog Cards
+#
+# CONFIG_USBPCWATCHDOG is not set
+CONFIG_SSB_POSSIBLE=y
+
+#
+# Sonics Silicon Backplane
+#
+# CONFIG_SSB is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_CORE is not set
+# CONFIG_MFD_SM501 is not set
+# CONFIG_MFD_ASIC3 is not set
+# CONFIG_HTC_EGPIO is not set
+# CONFIG_HTC_PASIC3 is not set
+# CONFIG_TPS65010 is not set
+CONFIG_TWL4030_CORE=y
+# CONFIG_TWL4030_POWER is not set
+# CONFIG_TWL4030_CODEC is not set
+# CONFIG_MFD_TMIO is not set
+# CONFIG_MFD_T7L66XB is not set
+# CONFIG_MFD_TC6387XB is not set
+# CONFIG_MFD_TC6393XB is not set
+# CONFIG_PMIC_DA903X is not set
+# CONFIG_MFD_WM8400 is not set
+# CONFIG_MFD_WM831X is not set
+# CONFIG_MFD_WM8350_I2C is not set
+# CONFIG_MFD_PCF50633 is not set
+# CONFIG_MFD_MC13783 is not set
+# CONFIG_AB3100_CORE is not set
+# CONFIG_EZX_PCAP is not set
+CONFIG_REGULATOR=y
+# CONFIG_REGULATOR_DEBUG is not set
+CONFIG_REGULATOR_FIXED_VOLTAGE=y
+# CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set
+# CONFIG_REGULATOR_USERSPACE_CONSUMER is not set
+# CONFIG_REGULATOR_BQ24022 is not set
+# CONFIG_REGULATOR_MAX1586 is not set
+CONFIG_REGULATOR_TWL4030=y
+# CONFIG_REGULATOR_LP3971 is not set
+# CONFIG_REGULATOR_TPS65023 is not set
+# CONFIG_REGULATOR_TPS6507X is not set
+# CONFIG_MEDIA_SUPPORT is not set
+
+#
+# Graphics support
+#
+# CONFIG_VGASTATE is not set
+# CONFIG_VIDEO_OUTPUT_CONTROL is not set
+CONFIG_FB=y
+CONFIG_FIRMWARE_EDID=y
+# CONFIG_FB_DDC is not set
+# CONFIG_FB_BOOT_VESA_SUPPORT is not set
+CONFIG_FB_CFB_FILLRECT=y
+CONFIG_FB_CFB_COPYAREA=y
+CONFIG_FB_CFB_IMAGEBLIT=y
+# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
+# CONFIG_FB_SYS_FILLRECT is not set
+# CONFIG_FB_SYS_COPYAREA is not set
+# CONFIG_FB_SYS_IMAGEBLIT is not set
+# CONFIG_FB_FOREIGN_ENDIAN is not set
+# CONFIG_FB_SYS_FOPS is not set
+# CONFIG_FB_SVGALIB is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_BACKLIGHT is not set
+CONFIG_FB_MODE_HELPERS=y
+CONFIG_FB_TILEBLITTING=y
+
+#
+# Frame buffer hardware drivers
+#
+# CONFIG_FB_UVESA is not set
+# CONFIG_FB_S1D13XXX is not set
+# CONFIG_FB_VIRTUAL is not set
+# CONFIG_FB_METRONOME is not set
+# CONFIG_FB_MB862XX is not set
+# CONFIG_FB_BROADSHEET is not set
+CONFIG_FB_OMAP=y
+CONFIG_FB_OMAP_LCD_VGA=y
+# CONFIG_FB_OMAP_031M3R is not set
+# CONFIG_FB_OMAP_048M3R is not set
+CONFIG_FB_OMAP_079M3R=y
+# CONFIG_FB_OMAP_092M9R is not set
+# CONFIG_FB_OMAP_LCDC_EXTERNAL is not set
+# CONFIG_FB_OMAP_LCD_MIPID is not set
+# CONFIG_FB_OMAP_BOOTLOADER_INIT is not set
+CONFIG_FB_OMAP_CONSISTENT_DMA_SIZE=2
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+CONFIG_LCD_CLASS_DEVICE=y
+# CONFIG_LCD_LMS283GF05 is not set
+# CONFIG_LCD_LTV350QV is not set
+# CONFIG_LCD_ILI9320 is not set
+# CONFIG_LCD_TDO24M is not set
+# CONFIG_LCD_VGG2432A4 is not set
+CONFIG_LCD_PLATFORM=y
+CONFIG_BACKLIGHT_CLASS_DEVICE=y
+CONFIG_BACKLIGHT_GENERIC=y
+
+#
+# Display device support
+#
+CONFIG_DISPLAY_SUPPORT=y
+
+#
+# Display hardware drivers
+#
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set
+CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y
+CONFIG_FONTS=y
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+# CONFIG_FONT_6x11 is not set
+# CONFIG_FONT_7x14 is not set
+# CONFIG_FONT_PEARL_8x8 is not set
+# CONFIG_FONT_ACORN_8x8 is not set
+# CONFIG_FONT_MINI_4x6 is not set
+# CONFIG_FONT_SUN8x16 is not set
+# CONFIG_FONT_SUN12x22 is not set
+# CONFIG_FONT_10x18 is not set
+CONFIG_LOGO=y
+CONFIG_LOGO_LINUX_MONO=y
+CONFIG_LOGO_LINUX_VGA16=y
+CONFIG_LOGO_LINUX_CLUT224=y
+CONFIG_SOUND=y
+CONFIG_SOUND_OSS_CORE=y
+CONFIG_SOUND_OSS_CORE_PRECLAIM=y
+CONFIG_SND=y
+CONFIG_SND_TIMER=y
+CONFIG_SND_PCM=y
+CONFIG_SND_HWDEP=y
+CONFIG_SND_RAWMIDI=y
+CONFIG_SND_JACK=y
+# CONFIG_SND_SEQUENCER is not set
+CONFIG_SND_OSSEMUL=y
+CONFIG_SND_MIXER_OSS=y
+CONFIG_SND_PCM_OSS=y
+CONFIG_SND_PCM_OSS_PLUGINS=y
+# CONFIG_SND_HRTIMER is not set
+# CONFIG_SND_DYNAMIC_MINORS is not set
+CONFIG_SND_SUPPORT_OLD_API=y
+CONFIG_SND_VERBOSE_PROCFS=y
+CONFIG_SND_VERBOSE_PRINTK=y
+CONFIG_SND_DEBUG=y
+# CONFIG_SND_DEBUG_VERBOSE is not set
+# CONFIG_SND_PCM_XRUN_DEBUG is not set
+# CONFIG_SND_RAWMIDI_SEQ is not set
+# CONFIG_SND_OPL3_LIB_SEQ is not set
+# CONFIG_SND_OPL4_LIB_SEQ is not set
+# CONFIG_SND_SBAWE_SEQ is not set
+# CONFIG_SND_EMU10K1_SEQ is not set
+CONFIG_SND_DRIVERS=y
+# CONFIG_SND_DUMMY is not set
+# CONFIG_SND_MTPAV is not set
+# CONFIG_SND_SERIAL_U16550 is not set
+# CONFIG_SND_MPU401 is not set
+CONFIG_SND_ARM=y
+CONFIG_SND_SPI=y
+CONFIG_SND_USB=y
+CONFIG_SND_USB_AUDIO=y
+# CONFIG_SND_USB_CAIAQ is not set
+CONFIG_SND_SOC=y
+CONFIG_SND_OMAP_SOC=y
+CONFIG_SND_OMAP_SOC_MCBSP=y
+# CONFIG_SND_OMAP_SOC_OVERO is not set
+# CONFIG_SND_OMAP_SOC_OMAP3EVM is not set
+# CONFIG_SND_OMAP_SOC_SDP3430 is not set
+CONFIG_SND_OMAP_SOC_OMAP3_PANDORA=y
+# CONFIG_SND_OMAP_SOC_OMAP3_BEAGLE is not set
+# CONFIG_SND_OMAP_SOC_ZOOM2 is not set
+CONFIG_SND_SOC_I2C_AND_SPI=y
+# CONFIG_SND_SOC_ALL_CODECS is not set
+CONFIG_SND_SOC_TWL4030=y
+# CONFIG_SOUND_PRIME is not set
+CONFIG_HID_SUPPORT=y
+CONFIG_HID=y
+# CONFIG_HIDRAW is not set
+
+#
+# USB Input Devices
+#
+CONFIG_USB_HID=y
+# CONFIG_HID_PID is not set
+# CONFIG_USB_HIDDEV is not set
+
+#
+# Special HID drivers
+#
+# CONFIG_HID_A4TECH is not set
+# CONFIG_HID_APPLE is not set
+# CONFIG_HID_BELKIN is not set
+# CONFIG_HID_CHERRY is not set
+# CONFIG_HID_CHICONY is not set
+# CONFIG_HID_CYPRESS is not set
+# CONFIG_HID_DRAGONRISE is not set
+# CONFIG_HID_EZKEY is not set
+# CONFIG_HID_KYE is not set
+# CONFIG_HID_GYRATION is not set
+# CONFIG_HID_TWINHAN is not set
+# CONFIG_HID_KENSINGTON is not set
+# CONFIG_HID_LOGITECH is not set
+# CONFIG_HID_MICROSOFT is not set
+# CONFIG_HID_MONTEREY is not set
+# CONFIG_HID_NTRIG is not set
+# CONFIG_HID_PANTHERLORD is not set
+# CONFIG_HID_PETALYNX is not set
+# CONFIG_HID_SAMSUNG is not set
+# CONFIG_HID_SONY is not set
+# CONFIG_HID_SUNPLUS is not set
+# CONFIG_HID_GREENASIA is not set
+# CONFIG_HID_SMARTJOYPLUS is not set
+# CONFIG_HID_TOPSEED is not set
+# CONFIG_HID_THRUSTMASTER is not set
+# CONFIG_HID_WACOM is not set
+# CONFIG_HID_ZEROPLUS is not set
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+# CONFIG_USB_ARCH_HAS_EHCI is not set
+CONFIG_USB=y
+CONFIG_USB_DEBUG=y
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+CONFIG_USB_DEVICE_CLASS=y
+# CONFIG_USB_DYNAMIC_MINORS is not set
+CONFIG_USB_SUSPEND=y
+CONFIG_USB_OTG=y
+# CONFIG_USB_OTG_WHITELIST is not set
+# CONFIG_USB_OTG_BLACKLIST_HUB is not set
+CONFIG_USB_MON=y
+# CONFIG_USB_WUSB is not set
+# CONFIG_USB_WUSB_CBAF is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_C67X00_HCD is not set
+# CONFIG_USB_OXU210HP_HCD is not set
+# CONFIG_USB_ISP116X_HCD is not set
+# CONFIG_USB_ISP1760_HCD is not set
+# CONFIG_USB_ISP1362_HCD is not set
+# CONFIG_USB_OHCI_HCD is not set
+# CONFIG_USB_SL811_HCD is not set
+# CONFIG_USB_R8A66597_HCD is not set
+# CONFIG_USB_HWA_HCD is not set
+CONFIG_USB_MUSB_HDRC=y
+CONFIG_USB_MUSB_SOC=y
+
+#
+# OMAP 343x high speed USB support
+#
+# CONFIG_USB_MUSB_HOST is not set
+# CONFIG_USB_MUSB_PERIPHERAL is not set
+CONFIG_USB_MUSB_OTG=y
+CONFIG_USB_GADGET_MUSB_HDRC=y
+CONFIG_USB_MUSB_HDRC_HCD=y
+# CONFIG_MUSB_PIO_ONLY is not set
+CONFIG_USB_INVENTRA_DMA=y
+# CONFIG_USB_TI_CPPI_DMA is not set
+CONFIG_USB_MUSB_DEBUG=y
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+CONFIG_USB_WDM=y
+# CONFIG_USB_TMC is not set
+
+#
+# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may
+#
+
+#
+# also be needed; see USB_STORAGE Help for more info
+#
+CONFIG_USB_STORAGE=y
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_ISD200 is not set
+# CONFIG_USB_STORAGE_USBAT is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_SDDR55 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_STORAGE_ALAUDA is not set
+# CONFIG_USB_STORAGE_ONETOUCH is not set
+# CONFIG_USB_STORAGE_KARMA is not set
+# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set
+CONFIG_USB_LIBUSUAL=y
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+
+#
+# USB port drivers
+#
+# CONFIG_USB_SERIAL is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_ADUTUX is not set
+# CONFIG_USB_SEVSEG is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_BERRY_CHARGE is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYPRESS_CY7C63 is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_FTDI_ELAN is not set
+# CONFIG_USB_APPLEDISPLAY is not set
+# CONFIG_USB_SISUSBVGA is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
+# CONFIG_USB_IOWARRIOR is not set
+CONFIG_USB_TEST=y
+# CONFIG_USB_ISIGHTFW is not set
+# CONFIG_USB_VST is not set
+CONFIG_USB_GADGET=y
+CONFIG_USB_GADGET_DEBUG=y
+CONFIG_USB_GADGET_DEBUG_FILES=y
+CONFIG_USB_GADGET_DEBUG_FS=y
+CONFIG_USB_GADGET_VBUS_DRAW=2
+CONFIG_USB_GADGET_SELECTED=y
+# CONFIG_USB_GADGET_AT91 is not set
+# CONFIG_USB_GADGET_ATMEL_USBA is not set
+# CONFIG_USB_GADGET_FSL_USB2 is not set
+# CONFIG_USB_GADGET_LH7A40X is not set
+# CONFIG_USB_GADGET_OMAP is not set
+# CONFIG_USB_GADGET_PXA25X is not set
+# CONFIG_USB_GADGET_R8A66597 is not set
+# CONFIG_USB_GADGET_PXA27X is not set
+# CONFIG_USB_GADGET_S3C_HSOTG is not set
+# CONFIG_USB_GADGET_IMX is not set
+# CONFIG_USB_GADGET_S3C2410 is not set
+# CONFIG_USB_GADGET_M66592 is not set
+# CONFIG_USB_GADGET_AMD5536UDC is not set
+# CONFIG_USB_GADGET_FSL_QE is not set
+# CONFIG_USB_GADGET_CI13XXX is not set
+# CONFIG_USB_GADGET_NET2280 is not set
+# CONFIG_USB_GADGET_GOKU is not set
+# CONFIG_USB_GADGET_LANGWELL is not set
+# CONFIG_USB_GADGET_DUMMY_HCD is not set
+CONFIG_USB_GADGET_DUALSPEED=y
+CONFIG_USB_ZERO=y
+# CONFIG_USB_ZERO_HNPTEST is not set
+# CONFIG_USB_AUDIO is not set
+# CONFIG_USB_ETH is not set
+# CONFIG_USB_GADGETFS is not set
+# CONFIG_USB_FILE_STORAGE is not set
+# CONFIG_USB_G_SERIAL is not set
+# CONFIG_USB_MIDI_GADGET is not set
+# CONFIG_USB_G_PRINTER is not set
+# CONFIG_USB_CDC_COMPOSITE is not set
+
+#
+# OTG and related infrastructure
+#
+CONFIG_USB_OTG_UTILS=y
+# CONFIG_USB_GPIO_VBUS is not set
+# CONFIG_ISP1301_OMAP is not set
+CONFIG_TWL4030_USB=y
+CONFIG_NOP_USB_XCEIV=y
+CONFIG_MMC=y
+# CONFIG_MMC_DEBUG is not set
+CONFIG_MMC_UNSAFE_RESUME=y
+
+#
+# MMC/SD/SDIO Card Drivers
+#
+CONFIG_MMC_BLOCK=y
+CONFIG_MMC_BLOCK_BOUNCE=y
+CONFIG_SDIO_UART=y
+# CONFIG_MMC_TEST is not set
+
+#
+# MMC/SD/SDIO Host Controller Drivers
+#
+# CONFIG_MMC_SDHCI is not set
+# CONFIG_MMC_OMAP is not set
+CONFIG_MMC_OMAP_HS=y
+# CONFIG_MMC_AT91 is not set
+# CONFIG_MMC_ATMELMCI is not set
+# CONFIG_MMC_SPI is not set
+# CONFIG_MEMSTICK is not set
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+
+#
+# LED drivers
+#
+# CONFIG_LEDS_PCA9532 is not set
+CONFIG_LEDS_GPIO=y
+CONFIG_LEDS_GPIO_PLATFORM=y
+# CONFIG_LEDS_LP3944 is not set
+# CONFIG_LEDS_PCA955X is not set
+# CONFIG_LEDS_DAC124S085 is not set
+# CONFIG_LEDS_BD2802 is not set
+
+#
+# LED Triggers
+#
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_LEDS_TRIGGER_TIMER=y
+CONFIG_LEDS_TRIGGER_HEARTBEAT=y
+# CONFIG_LEDS_TRIGGER_BACKLIGHT is not set
+# CONFIG_LEDS_TRIGGER_GPIO is not set
+CONFIG_LEDS_TRIGGER_DEFAULT_ON=y
+
+#
+# iptables trigger is under Netfilter config (LED target)
+#
+# CONFIG_ACCESSIBILITY is not set
+CONFIG_RTC_LIB=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_HCTOSYS=y
+CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
+# CONFIG_RTC_DEBUG is not set
+
+#
+# RTC interfaces
+#
+CONFIG_RTC_INTF_SYSFS=y
+CONFIG_RTC_INTF_PROC=y
+CONFIG_RTC_INTF_DEV=y
+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+# CONFIG_RTC_DRV_TEST is not set
+
+#
+# I2C RTC drivers
+#
+# CONFIG_RTC_DRV_DS1307 is not set
+# CONFIG_RTC_DRV_DS1374 is not set
+# CONFIG_RTC_DRV_DS1672 is not set
+# CONFIG_RTC_DRV_MAX6900 is not set
+# CONFIG_RTC_DRV_RS5C372 is not set
+# CONFIG_RTC_DRV_ISL1208 is not set
+# CONFIG_RTC_DRV_X1205 is not set
+# CONFIG_RTC_DRV_PCF8563 is not set
+# CONFIG_RTC_DRV_PCF8583 is not set
+# CONFIG_RTC_DRV_M41T80 is not set
+CONFIG_RTC_DRV_TWL4030=y
+# CONFIG_RTC_DRV_S35390A is not set
+# CONFIG_RTC_DRV_FM3130 is not set
+# CONFIG_RTC_DRV_RX8581 is not set
+# CONFIG_RTC_DRV_RX8025 is not set
+
+#
+# SPI RTC drivers
+#
+# CONFIG_RTC_DRV_M41T94 is not set
+# CONFIG_RTC_DRV_DS1305 is not set
+# CONFIG_RTC_DRV_DS1390 is not set
+# CONFIG_RTC_DRV_MAX6902 is not set
+# CONFIG_RTC_DRV_R9701 is not set
+# CONFIG_RTC_DRV_RS5C348 is not set
+# CONFIG_RTC_DRV_DS3234 is not set
+# CONFIG_RTC_DRV_PCF2123 is not set
+
+#
+# Platform RTC drivers
+#
+# CONFIG_RTC_DRV_CMOS is not set
+# CONFIG_RTC_DRV_DS1286 is not set
+# CONFIG_RTC_DRV_DS1511 is not set
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+# CONFIG_RTC_DRV_STK17TA8 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_M48T35 is not set
+# CONFIG_RTC_DRV_M48T59 is not set
+# CONFIG_RTC_DRV_BQ4802 is not set
+# CONFIG_RTC_DRV_V3020 is not set
+
+#
+# on-CPU RTC drivers
+#
+# CONFIG_DMADEVICES is not set
+# CONFIG_AUXDISPLAY is not set
+# CONFIG_UIO is not set
+
+#
+# TI VLYNQ
+#
+# CONFIG_STAGING is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
+# CONFIG_EXT3_FS_XATTR is not set
+# CONFIG_EXT4_FS is not set
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+CONFIG_FS_POSIX_ACL=y
+# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_BTRFS_FS is not set
+# CONFIG_NILFS2_FS is not set
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
+CONFIG_DNOTIFY=y
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+CONFIG_QUOTA=y
+# CONFIG_QUOTA_NETLINK_INTERFACE is not set
+CONFIG_PRINT_QUOTA_WARNING=y
+CONFIG_QUOTA_TREE=y
+# CONFIG_QFMT_V1 is not set
+CONFIG_QFMT_V2=y
+CONFIG_QUOTACTL=y
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# Caches
+#
+# CONFIG_FSCACHE is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLB_PAGE is not set
+# CONFIG_CONFIGFS_FS is not set
+CONFIG_MISC_FILESYSTEMS=y
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+# CONFIG_JFFS2_FS_WBUF_VERIFY is not set
+CONFIG_JFFS2_SUMMARY=y
+CONFIG_JFFS2_FS_XATTR=y
+CONFIG_JFFS2_FS_POSIX_ACL=y
+CONFIG_JFFS2_FS_SECURITY=y
+CONFIG_JFFS2_COMPRESSION_OPTIONS=y
+CONFIG_JFFS2_ZLIB=y
+CONFIG_JFFS2_LZO=y
+CONFIG_JFFS2_RTIME=y
+CONFIG_JFFS2_RUBIN=y
+# CONFIG_JFFS2_CMODE_NONE is not set
+CONFIG_JFFS2_CMODE_PRIORITY=y
+# CONFIG_JFFS2_CMODE_SIZE is not set
+# CONFIG_JFFS2_CMODE_FAVOURLZO is not set
+CONFIG_UBIFS_FS=y
+# CONFIG_UBIFS_FS_XATTR is not set
+# CONFIG_UBIFS_FS_ADVANCED_COMPR is not set
+CONFIG_UBIFS_FS_LZO=y
+CONFIG_UBIFS_FS_ZLIB=y
+# CONFIG_UBIFS_FS_DEBUG is not set
+CONFIG_CRAMFS=y
+# CONFIG_SQUASHFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_OMFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+CONFIG_NETWORK_FILESYSTEMS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+CONFIG_NFS_V3_ACL=y
+CONFIG_NFS_V4=y
+# CONFIG_NFS_V4_1 is not set
+CONFIG_ROOT_NFS=y
+# CONFIG_NFSD is not set
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_ACL_SUPPORT=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+CONFIG_SUNRPC_GSS=y
+CONFIG_RPCSEC_GSS_KRB5=y
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_KARMA_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+# CONFIG_SYSV68_PARTITION is not set
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+CONFIG_NLS_ISO8859_1=y
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+# CONFIG_DLM is not set
+
+#
+# Kernel hacking
+#
+CONFIG_PRINTK_TIME=y
+CONFIG_ENABLE_WARN_DEPRECATED=y
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_FRAME_WARN=1024
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_STRIP_ASM_SYMS is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+CONFIG_DEBUG_FS=y
+# CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SHIRQ is not set
+CONFIG_DETECT_SOFTLOCKUP=y
+# CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set
+CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0
+CONFIG_DETECT_HUNG_TASK=y
+# CONFIG_BOOTPARAM_HUNG_TASK_PANIC is not set
+CONFIG_BOOTPARAM_HUNG_TASK_PANIC_VALUE=0
+CONFIG_SCHED_DEBUG=y
+CONFIG_SCHEDSTATS=y
+CONFIG_TIMER_STATS=y
+# CONFIG_DEBUG_OBJECTS is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_KMEMLEAK is not set
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
+CONFIG_DEBUG_SPINLOCK=y
+CONFIG_DEBUG_MUTEXES=y
+CONFIG_DEBUG_LOCK_ALLOC=y
+CONFIG_PROVE_LOCKING=y
+CONFIG_LOCKDEP=y
+CONFIG_LOCK_STAT=y
+# CONFIG_DEBUG_LOCKDEP is not set
+CONFIG_TRACE_IRQFLAGS=y
+CONFIG_DEBUG_SPINLOCK_SLEEP=y
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+CONFIG_STACKTRACE=y
+# CONFIG_DEBUG_KOBJECT is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+CONFIG_DEBUG_INFO=y
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_WRITECOUNT is not set
+# CONFIG_DEBUG_MEMORY_INIT is not set
+# CONFIG_DEBUG_LIST is not set
+# CONFIG_DEBUG_SG is not set
+# CONFIG_DEBUG_NOTIFIERS is not set
+# CONFIG_DEBUG_CREDENTIALS is not set
+# CONFIG_BOOT_PRINTK_DELAY is not set
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_RCU_CPU_STALL_DETECTOR is not set
+# CONFIG_KPROBES_SANITY_TEST is not set
+# CONFIG_BACKTRACE_SELF_TEST is not set
+# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
+# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
+# CONFIG_LKDTM is not set
+# CONFIG_FAULT_INJECTION is not set
+# CONFIG_LATENCYTOP is not set
+# CONFIG_PAGE_POISONING is not set
+CONFIG_NOP_TRACER=y
+CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_RING_BUFFER=y
+CONFIG_EVENT_TRACING=y
+CONFIG_CONTEXT_SWITCH_TRACER=y
+CONFIG_RING_BUFFER_ALLOW_SWAP=y
+CONFIG_TRACING=y
+CONFIG_TRACING_SUPPORT=y
+CONFIG_FTRACE=y
+# CONFIG_FUNCTION_TRACER is not set
+# CONFIG_IRQSOFF_TRACER is not set
+# CONFIG_SCHED_TRACER is not set
+# CONFIG_ENABLE_DEFAULT_TRACERS is not set
+# CONFIG_BOOT_TRACER is not set
+CONFIG_BRANCH_PROFILE_NONE=y
+# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set
+# CONFIG_PROFILE_ALL_BRANCHES is not set
+# CONFIG_STACK_TRACER is not set
+# CONFIG_KMEMTRACE is not set
+# CONFIG_WORKQUEUE_TRACER is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_RING_BUFFER_BENCHMARK is not set
+# CONFIG_DYNAMIC_DEBUG is not set
+# CONFIG_SAMPLES is not set
+CONFIG_HAVE_ARCH_KGDB=y
+# CONFIG_KGDB is not set
+CONFIG_ARM_UNWIND=y
+# CONFIG_DEBUG_USER is not set
+# CONFIG_DEBUG_ERRORS is not set
+# CONFIG_DEBUG_STACK_USAGE is not set
+CONFIG_DEBUG_LL=y
+# CONFIG_DEBUG_ICEDCC is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+CONFIG_SECURITY=y
+# CONFIG_SECURITYFS is not set
+# CONFIG_SECURITY_NETWORK is not set
+# CONFIG_SECURITY_PATH is not set
+# CONFIG_SECURITY_FILE_CAPABILITIES is not set
+# CONFIG_SECURITY_ROOTPLUG is not set
+# CONFIG_SECURITY_TOMOYO is not set
+CONFIG_CRYPTO=y
+
+#
+# Crypto core or helper
+#
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_ALGAPI2=y
+CONFIG_CRYPTO_AEAD2=y
+CONFIG_CRYPTO_BLKCIPHER=y
+CONFIG_CRYPTO_BLKCIPHER2=y
+CONFIG_CRYPTO_HASH=y
+CONFIG_CRYPTO_HASH2=y
+CONFIG_CRYPTO_RNG2=y
+CONFIG_CRYPTO_PCOMP=y
+CONFIG_CRYPTO_MANAGER=y
+CONFIG_CRYPTO_MANAGER2=y
+# CONFIG_CRYPTO_GF128MUL is not set
+# CONFIG_CRYPTO_NULL is not set
+CONFIG_CRYPTO_WORKQUEUE=y
+# CONFIG_CRYPTO_CRYPTD is not set
+# CONFIG_CRYPTO_AUTHENC is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Authenticated Encryption with Associated Data
+#
+# CONFIG_CRYPTO_CCM is not set
+# CONFIG_CRYPTO_GCM is not set
+# CONFIG_CRYPTO_SEQIV is not set
+
+#
+# Block modes
+#
+CONFIG_CRYPTO_CBC=y
+# CONFIG_CRYPTO_CTR is not set
+# CONFIG_CRYPTO_CTS is not set
+CONFIG_CRYPTO_ECB=y
+# CONFIG_CRYPTO_LRW is not set
+# CONFIG_CRYPTO_PCBC is not set
+# CONFIG_CRYPTO_XTS is not set
+
+#
+# Hash modes
+#
+# CONFIG_CRYPTO_HMAC is not set
+# CONFIG_CRYPTO_XCBC is not set
+# CONFIG_CRYPTO_VMAC is not set
+
+#
+# Digest
+#
+CONFIG_CRYPTO_CRC32C=y
+# CONFIG_CRYPTO_GHASH is not set
+# CONFIG_CRYPTO_MD4 is not set
+CONFIG_CRYPTO_MD5=y
+CONFIG_CRYPTO_MICHAEL_MIC=y
+# CONFIG_CRYPTO_RMD128 is not set
+# CONFIG_CRYPTO_RMD160 is not set
+# CONFIG_CRYPTO_RMD256 is not set
+# CONFIG_CRYPTO_RMD320 is not set
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_WP512 is not set
+
+#
+# Ciphers
+#
+CONFIG_CRYPTO_AES=y
+# CONFIG_CRYPTO_ANUBIS is not set
+CONFIG_CRYPTO_ARC4=y
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_CAMELLIA is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+CONFIG_CRYPTO_DES=y
+# CONFIG_CRYPTO_FCRYPT is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_SALSA20 is not set
+# CONFIG_CRYPTO_SEED is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+
+#
+# Compression
+#
+CONFIG_CRYPTO_DEFLATE=y
+# CONFIG_CRYPTO_ZLIB is not set
+CONFIG_CRYPTO_LZO=y
+
+#
+# Random Number Generation
+#
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
+CONFIG_CRYPTO_HW=y
+CONFIG_BINARY_PRINTF=y
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+CONFIG_GENERIC_FIND_LAST_BIT=y
+CONFIG_CRC_CCITT=y
+CONFIG_CRC16=y
+CONFIG_CRC_T10DIF=y
+CONFIG_CRC_ITU_T=y
+CONFIG_CRC32=y
+CONFIG_CRC7=y
+CONFIG_LIBCRC32C=y
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_LZO_COMPRESS=y
+CONFIG_LZO_DECOMPRESS=y
+CONFIG_DECOMPRESS_GZIP=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
+CONFIG_NLATTR=y
index d5ff477..e190fc8 100644 (file)
@@ -59,8 +59,8 @@ CONFIG_FAIR_GROUP_SCHED=y
 CONFIG_USER_SCHED=y
 # CONFIG_CGROUP_SCHED is not set
 # CONFIG_CGROUPS is not set
-CONFIG_SYSFS_DEPRECATED=y
-CONFIG_SYSFS_DEPRECATED_V2=y
+# CONFIG_SYSFS_DEPRECATED=y is not set
+# CONFIG_SYSFS_DEPRECATED_V2=y is not set
 # CONFIG_RELAY is not set
 # CONFIG_NAMESPACES is not set
 CONFIG_BLK_DEV_INITRD=y
@@ -617,8 +617,8 @@ CONFIG_MII=y
 # CONFIG_DM9000 is not set
 # CONFIG_ENC28J60 is not set
 # CONFIG_ETHOC is not set
-CONFIG_SMC911X=y
-# CONFIG_SMSC911X is not set
+# CONFIG_SMC911X is not set
+CONFIG_SMSC911X=y
 # CONFIG_DNET is not set
 # CONFIG_IBM_NEW_EMAC_ZMII is not set
 # CONFIG_IBM_NEW_EMAC_RGMII is not set
@@ -676,13 +676,19 @@ CONFIG_INPUT_EVDEV=y
 # Input Device Drivers
 #
 CONFIG_INPUT_KEYBOARD=y
+# CONFIG_KEYBOARD_ADP5588 is not set
 # CONFIG_KEYBOARD_ATKBD is not set
-# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_QT2160 is not set
 # CONFIG_KEYBOARD_LKKBD is not set
-# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_GPIO is not set
+# CONFIG_KEYBOARD_MATRIX is not set
+# CONFIG_KEYBOARD_MAX7359 is not set
 # CONFIG_KEYBOARD_NEWTON is not set
+# CONFIG_KEYBOARD_OPENCORES is not set
 # CONFIG_KEYBOARD_STOWAWAY is not set
-# CONFIG_KEYBOARD_GPIO is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+CONFIG_KEYBOARD_TWL4030=y
+# CONFIG_KEYBOARD_XTKBD is not set
 # CONFIG_INPUT_MOUSE is not set
 # CONFIG_INPUT_JOYSTICK is not set
 # CONFIG_INPUT_TABLET is not set
@@ -1126,7 +1132,7 @@ CONFIG_MMC_BLOCK_BOUNCE=y
 #
 # CONFIG_MMC_SDHCI is not set
 # CONFIG_MMC_OMAP is not set
-CONFIG_MMC_OMAP_HS=m
+CONFIG_MMC_OMAP_HS=y
 # CONFIG_MMC_SPI is not set
 # CONFIG_MEMSTICK is not set
 # CONFIG_ACCESSIBILITY is not set
index 150deaf..b7a8d9f 100644 (file)
@@ -51,8 +51,9 @@ CONFIG_FAIR_GROUP_SCHED=y
 # CONFIG_RT_GROUP_SCHED is not set
 CONFIG_USER_SCHED=y
 # CONFIG_CGROUP_SCHED is not set
-CONFIG_SYSFS_DEPRECATED=y
-CONFIG_SYSFS_DEPRECATED_V2=y
+# CONFIG_SYSFS_DEPRECATED=y is not set
+# CONFIG_SYSFS_DEPRECATED_V2=y is not set
+
 # CONFIG_RELAY is not set
 # CONFIG_NAMESPACES is not set
 CONFIG_BLK_DEV_INITRD=y
index 5a305f0..8482958 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.30-omap1
-# Tue Jun 23 10:36:45 2009
+# Linux kernel version: 2.6.31-rc9-omap1
+# Tue Sep 15 16:48:34 2009
 #
 CONFIG_ARM=y
 CONFIG_SYS_SUPPORTS_APM_EMULATION=y
@@ -9,7 +9,6 @@ CONFIG_GENERIC_GPIO=y
 CONFIG_GENERIC_TIME=y
 CONFIG_GENERIC_CLOCKEVENTS=y
 CONFIG_MMU=y
-# CONFIG_NO_IOPORT is not set
 CONFIG_GENERIC_HARDIRQS=y
 CONFIG_STACKTRACE_SUPPORT=y
 CONFIG_HAVE_LATENCYTOP_SUPPORT=y
@@ -18,14 +17,12 @@ CONFIG_TRACE_IRQFLAGS_SUPPORT=y
 CONFIG_HARDIRQS_SW_RESEND=y
 CONFIG_GENERIC_IRQ_PROBE=y
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
-# CONFIG_ARCH_HAS_ILOG2_U32 is not set
-# CONFIG_ARCH_HAS_ILOG2_U64 is not set
 CONFIG_GENERIC_HWEIGHT=y
 CONFIG_GENERIC_CALIBRATE_DELAY=y
 CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
-CONFIG_OPROFILE_ARMV7=y
 CONFIG_VECTORS_BASE=0xffff0000
 CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
 
 #
 # General setup
@@ -61,12 +58,15 @@ CONFIG_FAIR_GROUP_SCHED=y
 CONFIG_USER_SCHED=y
 # CONFIG_CGROUP_SCHED is not set
 # CONFIG_CGROUPS is not set
-CONFIG_SYSFS_DEPRECATED=y
-CONFIG_SYSFS_DEPRECATED_V2=y
+# CONFIG_SYSFS_DEPRECATED=y is not set
+# CONFIG_SYSFS_DEPRECATED_V2=y is not set
 # CONFIG_RELAY is not set
 # CONFIG_NAMESPACES is not set
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_INITRAMFS_SOURCE=""
+CONFIG_RD_GZIP=y
+# CONFIG_RD_BZIP2 is not set
+# CONFIG_RD_LZMA is not set
 CONFIG_CC_OPTIMIZE_FOR_SIZE=y
 CONFIG_SYSCTL=y
 CONFIG_ANON_INODES=y
@@ -79,7 +79,7 @@ CONFIG_KALLSYMS=y
 CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
-# CONFIG_ELF_CORE is not set
+CONFIG_ELF_CORE=y
 CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
@@ -88,21 +88,29 @@ CONFIG_TIMERFD=y
 CONFIG_EVENTFD=y
 CONFIG_SHMEM=y
 CONFIG_AIO=y
+
+#
+# Performance Counters
+#
 CONFIG_VM_EVENT_COUNTERS=y
-CONFIG_SLUB_DEBUG=y
-# CONFIG_COMPAT_BRK is not set
-# CONFIG_SLAB is not set
-CONFIG_SLUB=y
+# CONFIG_STRIP_ASM_SYMS is not set
+CONFIG_COMPAT_BRK=y
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
 # CONFIG_SLOB is not set
-CONFIG_PROFILING=y
-CONFIG_TRACEPOINTS=y
+# CONFIG_PROFILING is not set
 # CONFIG_MARKERS is not set
-CONFIG_OPROFILE=y
 CONFIG_HAVE_OPROFILE=y
 # CONFIG_KPROBES is not set
 CONFIG_HAVE_KPROBES=y
 CONFIG_HAVE_KRETPROBES=y
 CONFIG_HAVE_CLK=y
+
+#
+# GCOV-based kernel profiling
+#
+# CONFIG_GCOV_KERNEL is not set
+# CONFIG_SLOW_WORK is not set
 CONFIG_HAVE_GENERIC_DMA_COHERENT=y
 CONFIG_SLABINFO=y
 CONFIG_RT_MUTEXES=y
@@ -110,12 +118,11 @@ CONFIG_BASE_SMALL=0
 CONFIG_MODULES=y
 # CONFIG_MODULE_FORCE_LOAD is not set
 CONFIG_MODULE_UNLOAD=y
-CONFIG_MODULE_FORCE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
 CONFIG_MODVERSIONS=y
 CONFIG_MODULE_SRCVERSION_ALL=y
 CONFIG_BLOCK=y
-CONFIG_LBD=y
-# CONFIG_BLK_DEV_IO_TRACE is not set
+CONFIG_LBDAF=y
 # CONFIG_BLK_DEV_BSG is not set
 # CONFIG_BLK_DEV_INTEGRITY is not set
 
@@ -126,11 +133,11 @@ CONFIG_IOSCHED_NOOP=y
 CONFIG_IOSCHED_AS=y
 CONFIG_IOSCHED_DEADLINE=y
 CONFIG_IOSCHED_CFQ=y
-# CONFIG_DEFAULT_AS is not set
+CONFIG_DEFAULT_AS=y
 # CONFIG_DEFAULT_DEADLINE is not set
-CONFIG_DEFAULT_CFQ=y
+# CONFIG_DEFAULT_CFQ is not set
 # CONFIG_DEFAULT_NOOP is not set
-CONFIG_DEFAULT_IOSCHED="cfq"
+CONFIG_DEFAULT_IOSCHED="anticipatory"
 CONFIG_FREEZER=y
 
 #
@@ -142,12 +149,14 @@ CONFIG_FREEZER=y
 # CONFIG_ARCH_VERSATILE is not set
 # CONFIG_ARCH_AT91 is not set
 # CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_GEMINI is not set
 # CONFIG_ARCH_EBSA110 is not set
 # CONFIG_ARCH_EP93XX is not set
 # CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_MXC is not set
+# CONFIG_ARCH_STMP3XXX is not set
 # CONFIG_ARCH_NETX is not set
 # CONFIG_ARCH_H720X is not set
-# CONFIG_ARCH_IMX is not set
 # CONFIG_ARCH_IOP13XX is not set
 # CONFIG_ARCH_IOP32X is not set
 # CONFIG_ARCH_IOP33X is not set
@@ -156,24 +165,25 @@ CONFIG_FREEZER=y
 # CONFIG_ARCH_IXP4XX is not set
 # CONFIG_ARCH_L7200 is not set
 # CONFIG_ARCH_KIRKWOOD is not set
-# CONFIG_ARCH_KS8695 is not set
-# CONFIG_ARCH_NS9XXX is not set
 # CONFIG_ARCH_LOKI is not set
 # CONFIG_ARCH_MV78XX0 is not set
-# CONFIG_ARCH_MXC is not set
 # CONFIG_ARCH_ORION5X is not set
+# CONFIG_ARCH_MMP is not set
+# CONFIG_ARCH_KS8695 is not set
+# CONFIG_ARCH_NS9XXX is not set
+# CONFIG_ARCH_W90X900 is not set
 # CONFIG_ARCH_PNX4008 is not set
 # CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_MSM is not set
 # CONFIG_ARCH_RPC is not set
 # CONFIG_ARCH_SA1100 is not set
 # CONFIG_ARCH_S3C2410 is not set
 # CONFIG_ARCH_S3C64XX is not set
 # CONFIG_ARCH_SHARK is not set
 # CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_U300 is not set
 # CONFIG_ARCH_DAVINCI is not set
 CONFIG_ARCH_OMAP=y
-# CONFIG_ARCH_MSM is not set
-# CONFIG_ARCH_W90X900 is not set
 
 #
 # TI OMAP Implementations
@@ -182,17 +192,19 @@ CONFIG_ARCH_OMAP_OTG=y
 # CONFIG_ARCH_OMAP1 is not set
 # CONFIG_ARCH_OMAP2 is not set
 CONFIG_ARCH_OMAP3=y
+# CONFIG_ARCH_OMAP4 is not set
 
 #
 # OMAP Feature Selections
 #
 # CONFIG_OMAP_DEBUG_POWERDOMAIN is not set
 # CONFIG_OMAP_DEBUG_CLOCKDOMAIN is not set
-# CONFIG_OMAP_RESET_CLOCKS is not set
+CONFIG_OMAP_RESET_CLOCKS=y
 CONFIG_OMAP_MUX=y
 CONFIG_OMAP_MUX_DEBUG=y
 CONFIG_OMAP_MUX_WARNINGS=y
 CONFIG_OMAP_MCBSP=y
+# CONFIG_OMAP_MBOX_FWK is not set
 # CONFIG_OMAP_MPU_TIMER is not set
 CONFIG_OMAP_32K_TIMER=y
 CONFIG_OMAP_32K_TIMER_HZ=128
@@ -200,7 +212,8 @@ CONFIG_OMAP_DM_TIMER=y
 CONFIG_OMAP_LL_DEBUG_UART1=y
 # CONFIG_OMAP_LL_DEBUG_UART2 is not set
 # CONFIG_OMAP_LL_DEBUG_UART3 is not set
-CONFIG_OMAP_SERIAL_WAKE=y
+# CONFIG_OMAP_PM_NONE is not set
+CONFIG_OMAP_PM_NOOP=y
 CONFIG_ARCH_OMAP34XX=y
 CONFIG_ARCH_OMAP3430=y
 
@@ -210,8 +223,11 @@ CONFIG_ARCH_OMAP3430=y
 # CONFIG_MACH_OMAP3_BEAGLE is not set
 # CONFIG_MACH_OMAP_LDP is not set
 # CONFIG_MACH_OVERO is not set
+# CONFIG_MACH_OMAP3EVM is not set
 # CONFIG_MACH_OMAP3_PANDORA is not set
 CONFIG_MACH_OMAP_3430SDP=y
+# CONFIG_MACH_NOKIA_RX51 is not set
+# CONFIG_MACH_OMAP_ZOOM2 is not set
 
 #
 # Processor Type
@@ -234,12 +250,15 @@ CONFIG_CPU_CP15_MMU=y
 # Processor Features
 #
 CONFIG_ARM_THUMB=y
-CONFIG_ARM_THUMBEE=y
+# CONFIG_ARM_THUMBEE is not set
 # CONFIG_CPU_ICACHE_DISABLE is not set
 # CONFIG_CPU_DCACHE_DISABLE is not set
 # CONFIG_CPU_BPREDICT_DISABLE is not set
 CONFIG_HAS_TLS_REG=y
-# CONFIG_OUTER_CACHE is not set
+# CONFIG_ARM_ERRATA_430973 is not set
+# CONFIG_ARM_ERRATA_458693 is not set
+# CONFIG_ARM_ERRATA_460075 is not set
+CONFIG_COMMON_CLKDEV=y
 
 #
 # Bus support
@@ -262,10 +281,10 @@ CONFIG_PAGE_OFFSET=0xC0000000
 # CONFIG_PREEMPT is not set
 CONFIG_HZ=128
 CONFIG_AEABI=y
-# CONFIG_OABI_COMPAT is not set
-CONFIG_ARCH_FLATMEM_HAS_HOLES=y
+CONFIG_OABI_COMPAT=y
 # CONFIG_ARCH_SPARSEMEM_DEFAULT is not set
 # CONFIG_ARCH_SELECT_MEMORY_MODEL is not set
+# CONFIG_HIGHMEM is not set
 CONFIG_SELECT_MEMORY_MODEL=y
 CONFIG_FLATMEM_MANUAL=y
 # CONFIG_DISCONTIGMEM_MANUAL is not set
@@ -277,9 +296,12 @@ CONFIG_SPLIT_PTLOCK_CPUS=4
 # CONFIG_PHYS_ADDR_T_64BIT is not set
 CONFIG_ZONE_DMA_FLAG=0
 CONFIG_VIRT_TO_BUS=y
-CONFIG_UNEVICTABLE_LRU=y
-CONFIG_LEDS=y
+CONFIG_HAVE_MLOCK=y
+CONFIG_HAVE_MLOCKED_PAGE_BIT=y
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
+# CONFIG_LEDS is not set
 CONFIG_ALIGNMENT_TRAP=y
+# CONFIG_UACCESS_WITH_MEMCPY is not set
 
 #
 # Boot options
@@ -288,8 +310,7 @@ CONFIG_ZBOOT_ROM_TEXT=0x0
 CONFIG_ZBOOT_ROM_BSS=0x0
 CONFIG_CMDLINE="console=ttyS2,115200 root=/dev/mmcblk0p3 rootwait debug"
 # CONFIG_XIP_KERNEL is not set
-CONFIG_KEXEC=y
-CONFIG_ATAGS_PROC=y
+# CONFIG_KEXEC is not set
 
 #
 # CPU Power Management
@@ -318,6 +339,9 @@ CONFIG_CPU_FREQ_GOV_ONDEMAND=y
 #
 # At least one emulation must be selected
 #
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
+# CONFIG_FPE_FASTFPE is not set
 CONFIG_VFP=y
 CONFIG_VFPv3=y
 CONFIG_NEON=y
@@ -326,8 +350,9 @@ CONFIG_NEON=y
 # Userspace binary formats
 #
 CONFIG_BINFMT_ELF=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
 CONFIG_HAVE_AOUT=y
-CONFIG_BINFMT_AOUT=m
+# CONFIG_BINFMT_AOUT is not set
 CONFIG_BINFMT_MISC=y
 
 #
@@ -345,9 +370,8 @@ CONFIG_NET=y
 #
 # Networking options
 #
-CONFIG_COMPAT_NET_DEV_OPS=y
 CONFIG_PACKET=y
-CONFIG_PACKET_MMAP=y
+# CONFIG_PACKET_MMAP is not set
 CONFIG_UNIX=y
 CONFIG_XFRM=y
 # CONFIG_XFRM_USER is not set
@@ -372,7 +396,7 @@ CONFIG_IP_PNP_RARP=y
 # CONFIG_INET_ESP is not set
 # CONFIG_INET_IPCOMP is not set
 # CONFIG_INET_XFRM_TUNNEL is not set
-CONFIG_INET_TUNNEL=m
+# CONFIG_INET_TUNNEL is not set
 CONFIG_INET_XFRM_MODE_TRANSPORT=y
 CONFIG_INET_XFRM_MODE_TUNNEL=y
 CONFIG_INET_XFRM_MODE_BEET=y
@@ -383,25 +407,7 @@ CONFIG_INET_TCP_DIAG=y
 CONFIG_TCP_CONG_CUBIC=y
 CONFIG_DEFAULT_TCP_CONG="cubic"
 # CONFIG_TCP_MD5SIG is not set
-CONFIG_IPV6=m
-# CONFIG_IPV6_PRIVACY is not set
-# CONFIG_IPV6_ROUTER_PREF is not set
-# CONFIG_IPV6_OPTIMISTIC_DAD is not set
-# CONFIG_INET6_AH is not set
-# CONFIG_INET6_ESP is not set
-# CONFIG_INET6_IPCOMP is not set
-# CONFIG_IPV6_MIP6 is not set
-# CONFIG_INET6_XFRM_TUNNEL is not set
-# CONFIG_INET6_TUNNEL is not set
-CONFIG_INET6_XFRM_MODE_TRANSPORT=m
-CONFIG_INET6_XFRM_MODE_TUNNEL=m
-CONFIG_INET6_XFRM_MODE_BEET=m
-# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set
-CONFIG_IPV6_SIT=m
-CONFIG_IPV6_NDISC_NODETYPE=y
-# CONFIG_IPV6_TUNNEL is not set
-# CONFIG_IPV6_MULTIPLE_TABLES is not set
-# CONFIG_IPV6_MROUTE is not set
+# CONFIG_IPV6 is not set
 # CONFIG_NETWORK_SECMARK is not set
 # CONFIG_NETFILTER is not set
 # CONFIG_IP_DCCP is not set
@@ -419,6 +425,8 @@ CONFIG_IPV6_NDISC_NODETYPE=y
 # CONFIG_LAPB is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
+# CONFIG_PHONET is not set
+# CONFIG_IEEE802154 is not set
 # CONFIG_NET_SCHED is not set
 # CONFIG_DCB is not set
 
@@ -429,56 +437,9 @@ CONFIG_IPV6_NDISC_NODETYPE=y
 # CONFIG_HAMRADIO is not set
 # CONFIG_CAN is not set
 # CONFIG_IRDA is not set
-CONFIG_BT=y
-CONFIG_BT_L2CAP=y
-CONFIG_BT_SCO=y
-CONFIG_BT_RFCOMM=y
-CONFIG_BT_RFCOMM_TTY=y
-CONFIG_BT_BNEP=y
-CONFIG_BT_BNEP_MC_FILTER=y
-CONFIG_BT_BNEP_PROTO_FILTER=y
-CONFIG_BT_HIDP=y
-
-#
-# Bluetooth device drivers
-#
-# CONFIG_BT_HCIBTUSB is not set
-# CONFIG_BT_HCIBTSDIO is not set
-CONFIG_BT_HCIUART=y
-CONFIG_BT_HCIUART_H4=y
-CONFIG_BT_HCIUART_BCSP=y
-# CONFIG_BT_HCIUART_LL is not set
-CONFIG_BT_HCIBCM203X=y
-CONFIG_BT_HCIBPA10X=y
-# CONFIG_BT_HCIBFUSB is not set
-# CONFIG_BT_HCIVHCI is not set
+# CONFIG_BT is not set
 # CONFIG_AF_RXRPC is not set
-# CONFIG_PHONET is not set
-CONFIG_WIRELESS=y
-CONFIG_CFG80211=y
-# CONFIG_CFG80211_REG_DEBUG is not set
-CONFIG_NL80211=y
-CONFIG_WIRELESS_OLD_REGULATORY=y
-CONFIG_WIRELESS_EXT=y
-CONFIG_WIRELESS_EXT_SYSFS=y
-CONFIG_LIB80211=y
-CONFIG_LIB80211_CRYPT_WEP=m
-CONFIG_LIB80211_CRYPT_CCMP=m
-CONFIG_LIB80211_CRYPT_TKIP=m
-CONFIG_MAC80211=y
-
-#
-# Rate control algorithm selection
-#
-CONFIG_MAC80211_RC_PID=y
-# CONFIG_MAC80211_RC_MINSTREL is not set
-CONFIG_MAC80211_RC_DEFAULT_PID=y
-# CONFIG_MAC80211_RC_DEFAULT_MINSTREL is not set
-CONFIG_MAC80211_RC_DEFAULT="pid"
-# CONFIG_MAC80211_MESH is not set
-CONFIG_MAC80211_LEDS=y
-# CONFIG_MAC80211_DEBUGFS is not set
-# CONFIG_MAC80211_DEBUG_MENU is not set
+# CONFIG_WIRELESS is not set
 # CONFIG_WIMAX is not set
 # CONFIG_RFKILL is not set
 # CONFIG_NET_9P is not set
@@ -493,9 +454,7 @@ CONFIG_MAC80211_LEDS=y
 CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_STANDALONE=y
 CONFIG_PREVENT_FIRMWARE_BUILD=y
-CONFIG_FW_LOADER=y
-CONFIG_FIRMWARE_IN_KERNEL=y
-CONFIG_EXTRA_FIRMWARE=""
+# CONFIG_FW_LOADER is not set
 # CONFIG_DEBUG_DRIVER is not set
 # CONFIG_DEBUG_DEVRES is not set
 # CONFIG_SYS_HYPERVISOR is not set
@@ -506,7 +465,7 @@ CONFIG_MTD_CONCAT=y
 CONFIG_MTD_PARTITIONS=y
 # CONFIG_MTD_TESTS is not set
 # CONFIG_MTD_REDBOOT_PARTS is not set
-# CONFIG_MTD_CMDLINE_PARTS is not set
+CONFIG_MTD_CMDLINE_PARTS=y
 # CONFIG_MTD_AFS_PARTS is not set
 # CONFIG_MTD_AR7_PARTS is not set
 
@@ -526,8 +485,10 @@ CONFIG_MTD_BLOCK=y
 #
 # RAM/ROM/Flash chip drivers
 #
-# CONFIG_MTD_CFI is not set
+CONFIG_MTD_CFI=y
 # CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
 CONFIG_MTD_MAP_BANK_WIDTH_1=y
 CONFIG_MTD_MAP_BANK_WIDTH_2=y
 CONFIG_MTD_MAP_BANK_WIDTH_4=y
@@ -538,6 +499,10 @@ CONFIG_MTD_CFI_I1=y
 CONFIG_MTD_CFI_I2=y
 # CONFIG_MTD_CFI_I4 is not set
 # CONFIG_MTD_CFI_I8 is not set
+CONFIG_MTD_CFI_INTELEXT=y
+# CONFIG_MTD_CFI_AMDSTD is not set
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
 # CONFIG_MTD_RAM is not set
 # CONFIG_MTD_ROM is not set
 # CONFIG_MTD_ABSENT is not set
@@ -546,6 +511,9 @@ CONFIG_MTD_CFI_I2=y
 # Mapping drivers for chip access
 #
 # CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PHYSMAP is not set
+# CONFIG_MTD_ARM_INTEGRATOR is not set
+CONFIG_MTD_OMAP_NOR=y
 # CONFIG_MTD_PLATRAM is not set
 
 #
@@ -569,6 +537,7 @@ CONFIG_MTD_NAND=y
 # CONFIG_MTD_NAND_ECC_SMC is not set
 # CONFIG_MTD_NAND_MUSEUM_IDS is not set
 # CONFIG_MTD_NAND_GPIO is not set
+# CONFIG_MTD_NAND_OMAP2 is not set
 CONFIG_MTD_NAND_IDS=y
 # CONFIG_MTD_NAND_DISKONCHIP is not set
 # CONFIG_MTD_NAND_NANDSIM is not set
@@ -589,20 +558,21 @@ CONFIG_MTD_NAND_IDS=y
 CONFIG_BLK_DEV=y
 # CONFIG_BLK_DEV_COW_COMMON is not set
 CONFIG_BLK_DEV_LOOP=y
-CONFIG_BLK_DEV_CRYPTOLOOP=m
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
 # CONFIG_BLK_DEV_NBD is not set
 # CONFIG_BLK_DEV_UB is not set
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_RAM_COUNT=16
 CONFIG_BLK_DEV_RAM_SIZE=16384
 # CONFIG_BLK_DEV_XIP is not set
-CONFIG_CDROM_PKTCDVD=m
-CONFIG_CDROM_PKTCDVD_BUFFERS=8
-# CONFIG_CDROM_PKTCDVD_WCACHE is not set
+# CONFIG_CDROM_PKTCDVD is not set
 # CONFIG_ATA_OVER_ETH is not set
+# CONFIG_MG_DISK is not set
 CONFIG_MISC_DEVICES=y
 # CONFIG_ICS932S401 is not set
+# CONFIG_OMAP_STI is not set
 # CONFIG_ENCLOSURE_SERVICES is not set
+# CONFIG_ISL29003 is not set
 # CONFIG_C2PORT is not set
 
 #
@@ -611,14 +581,15 @@ CONFIG_MISC_DEVICES=y
 # CONFIG_EEPROM_AT24 is not set
 # CONFIG_EEPROM_AT25 is not set
 # CONFIG_EEPROM_LEGACY is not set
-CONFIG_EEPROM_93CX6=m
+# CONFIG_EEPROM_MAX6875 is not set
+# CONFIG_EEPROM_93CX6 is not set
 CONFIG_HAVE_IDE=y
 # CONFIG_IDE is not set
 
 #
 # SCSI device support
 #
-CONFIG_RAID_ATTRS=m
+# CONFIG_RAID_ATTRS is not set
 CONFIG_SCSI=y
 CONFIG_SCSI_DMA=y
 # CONFIG_SCSI_TGT is not set
@@ -632,12 +603,8 @@ CONFIG_BLK_DEV_SD=y
 # CONFIG_CHR_DEV_ST is not set
 # CONFIG_CHR_DEV_OSST is not set
 # CONFIG_BLK_DEV_SR is not set
-CONFIG_CHR_DEV_SG=m
+# CONFIG_CHR_DEV_SG is not set
 # CONFIG_CHR_DEV_SCH is not set
-
-#
-# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
-#
 CONFIG_SCSI_MULTI_LUN=y
 # CONFIG_SCSI_CONSTANTS is not set
 # CONFIG_SCSI_LOGGING is not set
@@ -655,34 +622,18 @@ CONFIG_SCSI_WAIT_SCAN=m
 CONFIG_SCSI_LOWLEVEL=y
 # CONFIG_ISCSI_TCP is not set
 # CONFIG_LIBFC is not set
+# CONFIG_LIBFCOE is not set
 # CONFIG_SCSI_DEBUG is not set
 # CONFIG_SCSI_DH is not set
+# CONFIG_SCSI_OSD_INITIATOR is not set
 # CONFIG_ATA is not set
-CONFIG_MD=y
-CONFIG_BLK_DEV_MD=m
-CONFIG_MD_LINEAR=m
-CONFIG_MD_RAID0=m
-CONFIG_MD_RAID1=m
-CONFIG_MD_RAID10=m
-CONFIG_MD_RAID456=m
-CONFIG_MD_RAID5_RESHAPE=y
-CONFIG_MD_MULTIPATH=m
-CONFIG_MD_FAULTY=m
-CONFIG_BLK_DEV_DM=m
-# CONFIG_DM_DEBUG is not set
-CONFIG_DM_CRYPT=m
-CONFIG_DM_SNAPSHOT=m
-CONFIG_DM_MIRROR=m
-CONFIG_DM_ZERO=m
-CONFIG_DM_MULTIPATH=m
-CONFIG_DM_DELAY=m
-# CONFIG_DM_UEVENT is not set
+# CONFIG_MD is not set
 CONFIG_NETDEVICES=y
-CONFIG_DUMMY=m
+# CONFIG_DUMMY is not set
 # CONFIG_BONDING is not set
 # CONFIG_MACVLAN is not set
 # CONFIG_EQUALIZER is not set
-CONFIG_TUN=m
+# CONFIG_TUN is not set
 # CONFIG_VETH is not set
 CONFIG_PHYLIB=y
 
@@ -695,7 +646,7 @@ CONFIG_PHYLIB=y
 # CONFIG_LXT_PHY is not set
 # CONFIG_CICADA_PHY is not set
 # CONFIG_VITESSE_PHY is not set
-CONFIG_SMSC_PHY=y
+# CONFIG_SMSC_PHY is not set
 # CONFIG_BROADCOM_PHY is not set
 # CONFIG_ICPLUS_PHY is not set
 # CONFIG_REALTEK_PHY is not set
@@ -710,8 +661,10 @@ CONFIG_MII=y
 CONFIG_SMC91X=y
 # CONFIG_DM9000 is not set
 # CONFIG_ENC28J60 is not set
-CONFIG_SMC911X=m
-CONFIG_SMSC911X=m
+# CONFIG_ETHOC is not set
+# CONFIG_SMC911X is not set
+# CONFIG_SMSC911X is not set
+# CONFIG_DNET is not set
 # CONFIG_IBM_NEW_EMAC_ZMII is not set
 # CONFIG_IBM_NEW_EMAC_RGMII is not set
 # CONFIG_IBM_NEW_EMAC_TAH is not set
@@ -720,33 +673,16 @@ CONFIG_SMSC911X=m
 # CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT is not set
 # CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
 # CONFIG_B44 is not set
-# CONFIG_NETDEV_1000 is not set
-# CONFIG_NETDEV_10000 is not set
+# CONFIG_KS8842 is not set
+# CONFIG_KS8851 is not set
+CONFIG_NETDEV_1000=y
+CONFIG_NETDEV_10000=y
 
 #
 # Wireless LAN
 #
 # CONFIG_WLAN_PRE80211 is not set
-CONFIG_WLAN_80211=y
-CONFIG_LIBERTAS=y
-CONFIG_LIBERTAS_USB=y
-CONFIG_LIBERTAS_SDIO=y
-CONFIG_LIBERTAS_DEBUG=y
-# CONFIG_LIBERTAS_THINFIRM is not set
-CONFIG_USB_ZD1201=m
-# CONFIG_USB_NET_RNDIS_WLAN is not set
-CONFIG_RTL8187=m
-# CONFIG_MAC80211_HWSIM is not set
-CONFIG_P54_COMMON=m
-CONFIG_P54_USB=m
-# CONFIG_IWLWIFI_LEDS is not set
-CONFIG_HOSTAP=m
-CONFIG_HOSTAP_FIRMWARE=y
-CONFIG_HOSTAP_FIRMWARE_NVRAM=y
-# CONFIG_B43 is not set
-# CONFIG_B43LEGACY is not set
-# CONFIG_ZD1211RW is not set
-# CONFIG_RT2X00 is not set
+# CONFIG_WLAN_80211 is not set
 
 #
 # Enable WiMAX (Networking options) to see the WiMAX drivers
@@ -755,41 +691,14 @@ CONFIG_HOSTAP_FIRMWARE_NVRAM=y
 #
 # USB Network Adapters
 #
-CONFIG_USB_CATC=m
-CONFIG_USB_KAWETH=m
-CONFIG_USB_PEGASUS=m
-CONFIG_USB_RTL8150=m
-CONFIG_USB_USBNET=y
-CONFIG_USB_NET_AX8817X=y
-CONFIG_USB_NET_CDCETHER=y
-CONFIG_USB_NET_DM9601=m
-# CONFIG_USB_NET_SMSC95XX is not set
-CONFIG_USB_NET_GL620A=m
-CONFIG_USB_NET_NET1080=m
-CONFIG_USB_NET_PLUSB=m
-CONFIG_USB_NET_MCS7830=m
-CONFIG_USB_NET_RNDIS_HOST=m
-CONFIG_USB_NET_CDC_SUBSET=m
-CONFIG_USB_ALI_M5632=y
-CONFIG_USB_AN2720=y
-CONFIG_USB_BELKIN=y
-CONFIG_USB_ARMLINUX=y
-CONFIG_USB_EPSON2888=y
-CONFIG_USB_KC2190=y
-CONFIG_USB_NET_ZAURUS=m
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RTL8150 is not set
+# CONFIG_USB_USBNET is not set
 # CONFIG_WAN is not set
-CONFIG_PPP=m
-# CONFIG_PPP_MULTILINK is not set
-# CONFIG_PPP_FILTER is not set
-CONFIG_PPP_ASYNC=m
-CONFIG_PPP_SYNC_TTY=m
-CONFIG_PPP_DEFLATE=m
-CONFIG_PPP_BSDCOMP=m
-CONFIG_PPP_MPPE=m
-CONFIG_PPPOE=m
-# CONFIG_PPPOL2TP is not set
+# CONFIG_PPP is not set
 # CONFIG_SLIP is not set
-CONFIG_SLHC=m
 # CONFIG_NETCONSOLE is not set
 # CONFIG_NETPOLL is not set
 # CONFIG_NET_POLL_CONTROLLER is not set
@@ -805,10 +714,7 @@ CONFIG_INPUT=y
 #
 # Userland interfaces
 #
-CONFIG_INPUT_MOUSEDEV=y
-CONFIG_INPUT_MOUSEDEV_PSAUX=y
-CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
-CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_MOUSEDEV is not set
 # CONFIG_INPUT_JOYDEV is not set
 CONFIG_INPUT_EVDEV=y
 # CONFIG_INPUT_EVBUG is not set
@@ -818,47 +724,54 @@ CONFIG_INPUT_EVDEV=y
 #
 CONFIG_INPUT_KEYBOARD=y
 # CONFIG_KEYBOARD_ATKBD is not set
-# CONFIG_KEYBOARD_SUNKBD is not set
 # CONFIG_KEYBOARD_LKKBD is not set
-# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_GPIO is not set
+# CONFIG_KEYBOARD_MATRIX is not set
+# CONFIG_KEYBOARD_LM8323 is not set
 # CONFIG_KEYBOARD_NEWTON is not set
 # CONFIG_KEYBOARD_STOWAWAY is not set
-# CONFIG_KEYBOARD_GPIO is not set
-CONFIG_INPUT_MOUSE=y
-CONFIG_MOUSE_PS2=y
-CONFIG_MOUSE_PS2_ALPS=y
-CONFIG_MOUSE_PS2_LOGIPS2PP=y
-CONFIG_MOUSE_PS2_SYNAPTICS=y
-CONFIG_MOUSE_PS2_TRACKPOINT=y
-# CONFIG_MOUSE_PS2_ELANTECH is not set
-# CONFIG_MOUSE_PS2_TOUCHKIT is not set
-# CONFIG_MOUSE_SERIAL is not set
-# CONFIG_MOUSE_APPLETOUCH is not set
-# CONFIG_MOUSE_BCM5974 is not set
-# CONFIG_MOUSE_VSXXXAA is not set
-# CONFIG_MOUSE_GPIO is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_INPUT_MOUSE is not set
 # CONFIG_INPUT_JOYSTICK is not set
 # CONFIG_INPUT_TABLET is not set
-# CONFIG_INPUT_TOUCHSCREEN is not set
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_ADS7846=y
+# CONFIG_TOUCHSCREEN_AD7877 is not set
+# CONFIG_TOUCHSCREEN_AD7879_I2C is not set
+# CONFIG_TOUCHSCREEN_AD7879_SPI is not set
+# CONFIG_TOUCHSCREEN_AD7879 is not set
+# CONFIG_TOUCHSCREEN_EETI is not set
+# CONFIG_TOUCHSCREEN_FUJITSU is not set
+# CONFIG_TOUCHSCREEN_GUNZE is not set
+# CONFIG_TOUCHSCREEN_ELO is not set
+# CONFIG_TOUCHSCREEN_WACOM_W8001 is not set
+# CONFIG_TOUCHSCREEN_MTOUCH is not set
+# CONFIG_TOUCHSCREEN_INEXIO is not set
+# CONFIG_TOUCHSCREEN_MK712 is not set
+# CONFIG_TOUCHSCREEN_PENMOUNT is not set
+# CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set
+# CONFIG_TOUCHSCREEN_TOUCHWIN is not set
+# CONFIG_TOUCHSCREEN_USB_COMPOSITE is not set
+# CONFIG_TOUCHSCREEN_TOUCHIT213 is not set
+# CONFIG_TOUCHSCREEN_TSC2007 is not set
+# CONFIG_TOUCHSCREEN_W90X900 is not set
 # CONFIG_INPUT_MISC is not set
 
 #
 # Hardware I/O ports
 #
-CONFIG_SERIO=y
-CONFIG_SERIO_SERPORT=y
-CONFIG_SERIO_LIBPS2=y
-# CONFIG_SERIO_RAW is not set
+# CONFIG_SERIO is not set
 # CONFIG_GAMEPORT is not set
 
 #
 # Character devices
 #
 CONFIG_VT=y
-CONFIG_CONSOLE_TRANSLATIONS=y
+# CONFIG_CONSOLE_TRANSLATIONS is not set
 CONFIG_VT_CONSOLE=y
 CONFIG_HW_CONSOLE=y
-CONFIG_VT_HW_CONSOLE_BINDING=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
 CONFIG_DEVKMEM=y
 # CONFIG_SERIAL_NONSTANDARD is not set
 
@@ -878,6 +791,7 @@ CONFIG_SERIAL_8250_RSA=y
 #
 # Non-8250 serial port support
 #
+# CONFIG_SERIAL_MAX3100 is not set
 CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
 CONFIG_UNIX98_PTYS=y
@@ -885,6 +799,7 @@ CONFIG_UNIX98_PTYS=y
 # CONFIG_LEGACY_PTYS is not set
 # CONFIG_IPMI_HANDLER is not set
 CONFIG_HW_RANDOM=y
+# CONFIG_HW_RANDOM_TIMERIOMEM is not set
 # CONFIG_R3964 is not set
 # CONFIG_RAW_DRIVER is not set
 # CONFIG_TCG_TPM is not set
@@ -900,6 +815,7 @@ CONFIG_I2C_HELPER_AUTO=y
 #
 # I2C system bus drivers (mostly embedded / system-on-chip)
 #
+# CONFIG_I2C_DESIGNWARE is not set
 # CONFIG_I2C_GPIO is not set
 # CONFIG_I2C_OCORES is not set
 CONFIG_I2C_OMAP=y
@@ -925,8 +841,6 @@ CONFIG_I2C_OMAP=y
 # CONFIG_SENSORS_PCF8574 is not set
 # CONFIG_PCF8575 is not set
 # CONFIG_SENSORS_PCA9539 is not set
-# CONFIG_SENSORS_PCF8591 is not set
-# CONFIG_SENSORS_MAX6875 is not set
 # CONFIG_SENSORS_TSL2550 is not set
 # CONFIG_I2C_DEBUG_CORE is not set
 # CONFIG_I2C_DEBUG_ALGO is not set
@@ -975,68 +889,8 @@ CONFIG_GPIO_TWL4030=y
 # CONFIG_GPIO_MAX7301 is not set
 # CONFIG_GPIO_MCP23S08 is not set
 # CONFIG_W1 is not set
-CONFIG_POWER_SUPPLY=m
-# CONFIG_POWER_SUPPLY_DEBUG is not set
-# CONFIG_PDA_POWER is not set
-# CONFIG_BATTERY_DS2760 is not set
-# CONFIG_BATTERY_BQ27x00 is not set
-CONFIG_HWMON=y
-# CONFIG_HWMON_VID is not set
-# CONFIG_SENSORS_AD7414 is not set
-# CONFIG_SENSORS_AD7418 is not set
-# CONFIG_SENSORS_ADCXX is not set
-# CONFIG_SENSORS_ADM1021 is not set
-# CONFIG_SENSORS_ADM1025 is not set
-# CONFIG_SENSORS_ADM1026 is not set
-# CONFIG_SENSORS_ADM1029 is not set
-# CONFIG_SENSORS_ADM1031 is not set
-# CONFIG_SENSORS_ADM9240 is not set
-# CONFIG_SENSORS_ADT7462 is not set
-# CONFIG_SENSORS_ADT7470 is not set
-# CONFIG_SENSORS_ADT7473 is not set
-# CONFIG_SENSORS_ADT7475 is not set
-# CONFIG_SENSORS_ATXP1 is not set
-# CONFIG_SENSORS_DS1621 is not set
-# CONFIG_SENSORS_F71805F is not set
-# CONFIG_SENSORS_F71882FG is not set
-# CONFIG_SENSORS_F75375S is not set
-# CONFIG_SENSORS_GL518SM is not set
-# CONFIG_SENSORS_GL520SM is not set
-# CONFIG_SENSORS_IT87 is not set
-# CONFIG_SENSORS_LM63 is not set
-# CONFIG_SENSORS_LM70 is not set
-# CONFIG_SENSORS_LM75 is not set
-# CONFIG_SENSORS_LM77 is not set
-# CONFIG_SENSORS_LM78 is not set
-# CONFIG_SENSORS_LM80 is not set
-# CONFIG_SENSORS_LM83 is not set
-# CONFIG_SENSORS_LM85 is not set
-# CONFIG_SENSORS_LM87 is not set
-# CONFIG_SENSORS_LM90 is not set
-# CONFIG_SENSORS_LM92 is not set
-# CONFIG_SENSORS_LM93 is not set
-# CONFIG_SENSORS_LTC4245 is not set
-# CONFIG_SENSORS_MAX1111 is not set
-# CONFIG_SENSORS_MAX1619 is not set
-# CONFIG_SENSORS_MAX6650 is not set
-# CONFIG_SENSORS_PC87360 is not set
-# CONFIG_SENSORS_PC87427 is not set
-# CONFIG_SENSORS_DME1737 is not set
-# CONFIG_SENSORS_SMSC47M1 is not set
-# CONFIG_SENSORS_SMSC47M192 is not set
-# CONFIG_SENSORS_SMSC47B397 is not set
-# CONFIG_SENSORS_ADS7828 is not set
-# CONFIG_SENSORS_THMC50 is not set
-# CONFIG_SENSORS_VT1211 is not set
-# CONFIG_SENSORS_W83781D is not set
-# CONFIG_SENSORS_W83791D is not set
-# CONFIG_SENSORS_W83792D is not set
-# CONFIG_SENSORS_W83793 is not set
-# CONFIG_SENSORS_W83L785TS is not set
-# CONFIG_SENSORS_W83L786NG is not set
-# CONFIG_SENSORS_W83627HF is not set
-# CONFIG_SENSORS_W83627EHF is not set
-# CONFIG_HWMON_DEBUG_CHIP is not set
+# CONFIG_POWER_SUPPLY is not set
+# CONFIG_HWMON is not set
 # CONFIG_THERMAL is not set
 # CONFIG_THERMAL_HWMON is not set
 CONFIG_WATCHDOG=y
@@ -1046,7 +900,8 @@ CONFIG_WATCHDOG_NOWAYOUT=y
 # Watchdog Device Drivers
 #
 # CONFIG_SOFT_WATCHDOG is not set
-# CONFIG_OMAP_WATCHDOG is not set
+CONFIG_OMAP_WATCHDOG=y
+CONFIG_TWL4030_WATCHDOG=y
 
 #
 # USB-based Watchdog Cards
@@ -1077,237 +932,9 @@ CONFIG_TWL4030_CORE=y
 # CONFIG_MFD_WM8400 is not set
 # CONFIG_MFD_WM8350_I2C is not set
 # CONFIG_MFD_PCF50633 is not set
-
-#
-# Multimedia devices
-#
-
-#
-# Multimedia core support
-#
-CONFIG_VIDEO_DEV=m
-CONFIG_VIDEO_V4L2_COMMON=m
-CONFIG_VIDEO_ALLOW_V4L1=y
-CONFIG_VIDEO_V4L1_COMPAT=y
-CONFIG_DVB_CORE=m
-CONFIG_VIDEO_MEDIA=m
-
-#
-# Multimedia drivers
-#
-CONFIG_MEDIA_ATTACH=y
-CONFIG_MEDIA_TUNER=m
-# CONFIG_MEDIA_TUNER_CUSTOMIZE is not set
-CONFIG_MEDIA_TUNER_SIMPLE=m
-CONFIG_MEDIA_TUNER_TDA8290=m
-CONFIG_MEDIA_TUNER_TDA827X=m
-CONFIG_MEDIA_TUNER_TDA18271=m
-CONFIG_MEDIA_TUNER_TDA9887=m
-CONFIG_MEDIA_TUNER_TEA5761=m
-CONFIG_MEDIA_TUNER_TEA5767=m
-CONFIG_MEDIA_TUNER_MT20XX=m
-CONFIG_MEDIA_TUNER_MT2060=m
-CONFIG_MEDIA_TUNER_MT2266=m
-CONFIG_MEDIA_TUNER_QT1010=m
-CONFIG_MEDIA_TUNER_XC2028=m
-CONFIG_MEDIA_TUNER_XC5000=m
-CONFIG_MEDIA_TUNER_MXL5005S=m
-CONFIG_VIDEO_V4L2=m
-CONFIG_VIDEO_V4L1=m
-CONFIG_VIDEO_TVEEPROM=m
-CONFIG_VIDEO_TUNER=m
-CONFIG_VIDEO_CAPTURE_DRIVERS=y
-# CONFIG_VIDEO_ADV_DEBUG is not set
-# CONFIG_VIDEO_FIXED_MINOR_RANGES is not set
-CONFIG_VIDEO_HELPER_CHIPS_AUTO=y
-CONFIG_VIDEO_MSP3400=m
-CONFIG_VIDEO_CS53L32A=m
-CONFIG_VIDEO_WM8775=m
-CONFIG_VIDEO_SAA711X=m
-CONFIG_VIDEO_CX25840=m
-CONFIG_VIDEO_CX2341X=m
-# CONFIG_VIDEO_VIVI is not set
-# CONFIG_VIDEO_CPIA is not set
-# CONFIG_VIDEO_CPIA2 is not set
-# CONFIG_VIDEO_SAA5246A is not set
-# CONFIG_VIDEO_SAA5249 is not set
-# CONFIG_VIDEO_AU0828 is not set
-# CONFIG_SOC_CAMERA is not set
-CONFIG_V4L_USB_DRIVERS=y
-CONFIG_USB_VIDEO_CLASS=m
-CONFIG_USB_VIDEO_CLASS_INPUT_EVDEV=y
-# CONFIG_USB_GSPCA is not set
-CONFIG_VIDEO_PVRUSB2=m
-CONFIG_VIDEO_PVRUSB2_SYSFS=y
-CONFIG_VIDEO_PVRUSB2_DVB=y
-# CONFIG_VIDEO_PVRUSB2_DEBUGIFC is not set
-# CONFIG_VIDEO_EM28XX is not set
-CONFIG_VIDEO_USBVISION=m
-CONFIG_VIDEO_USBVIDEO=m
-CONFIG_USB_VICAM=m
-CONFIG_USB_IBMCAM=m
-CONFIG_USB_KONICAWC=m
-CONFIG_USB_QUICKCAM_MESSENGER=m
-# CONFIG_USB_ET61X251 is not set
-CONFIG_VIDEO_OVCAMCHIP=m
-CONFIG_USB_W9968CF=m
-CONFIG_USB_OV511=m
-CONFIG_USB_SE401=m
-CONFIG_USB_SN9C102=m
-CONFIG_USB_STV680=m
-# CONFIG_USB_ZC0301 is not set
-CONFIG_USB_PWC=m
-# CONFIG_USB_PWC_DEBUG is not set
-CONFIG_USB_ZR364XX=m
-# CONFIG_USB_STKWEBCAM is not set
-# CONFIG_USB_S2255 is not set
-CONFIG_RADIO_ADAPTERS=y
-# CONFIG_USB_DSBR is not set
-# CONFIG_USB_SI470X is not set
-# CONFIG_USB_MR800 is not set
-# CONFIG_RADIO_TEA5764 is not set
-# CONFIG_DVB_DYNAMIC_MINORS is not set
-CONFIG_DVB_CAPTURE_DRIVERS=y
-# CONFIG_TTPCI_EEPROM is not set
-
-#
-# Supported USB Adapters
-#
-CONFIG_DVB_USB=m
-# CONFIG_DVB_USB_DEBUG is not set
-CONFIG_DVB_USB_A800=m
-CONFIG_DVB_USB_DIBUSB_MB=m
-# CONFIG_DVB_USB_DIBUSB_MB_FAULTY is not set
-CONFIG_DVB_USB_DIBUSB_MC=m
-CONFIG_DVB_USB_DIB0700=m
-CONFIG_DVB_USB_UMT_010=m
-CONFIG_DVB_USB_CXUSB=m
-CONFIG_DVB_USB_M920X=m
-CONFIG_DVB_USB_GL861=m
-CONFIG_DVB_USB_AU6610=m
-CONFIG_DVB_USB_DIGITV=m
-CONFIG_DVB_USB_VP7045=m
-CONFIG_DVB_USB_VP702X=m
-CONFIG_DVB_USB_GP8PSK=m
-CONFIG_DVB_USB_NOVA_T_USB2=m
-CONFIG_DVB_USB_TTUSB2=m
-CONFIG_DVB_USB_DTT200U=m
-CONFIG_DVB_USB_OPERA1=m
-CONFIG_DVB_USB_AF9005=m
-CONFIG_DVB_USB_AF9005_REMOTE=m
-# CONFIG_DVB_USB_DW2102 is not set
-# CONFIG_DVB_USB_CINERGY_T2 is not set
-# CONFIG_DVB_USB_ANYSEE is not set
-# CONFIG_DVB_USB_DTV5100 is not set
-# CONFIG_DVB_USB_AF9015 is not set
-# CONFIG_DVB_SIANO_SMS1XXX is not set
-
-#
-# Supported FlexCopII (B2C2) Adapters
-#
-# CONFIG_DVB_B2C2_FLEXCOP is not set
-
-#
-# Supported DVB Frontends
-#
-
-#
-# Customise DVB Frontends
-#
-# CONFIG_DVB_FE_CUSTOMISE is not set
-
-#
-# Multistandard (satellite) frontends
-#
-# CONFIG_DVB_STB0899 is not set
-# CONFIG_DVB_STB6100 is not set
-
-#
-# DVB-S (satellite) frontends
-#
-CONFIG_DVB_CX24110=m
-CONFIG_DVB_CX24123=m
-CONFIG_DVB_MT312=m
-CONFIG_DVB_S5H1420=m
-# CONFIG_DVB_STV0288 is not set
-# CONFIG_DVB_STB6000 is not set
-CONFIG_DVB_STV0299=m
-CONFIG_DVB_TDA8083=m
-CONFIG_DVB_TDA10086=m
-# CONFIG_DVB_TDA8261 is not set
-CONFIG_DVB_VES1X93=m
-CONFIG_DVB_TUNER_ITD1000=m
-# CONFIG_DVB_TUNER_CX24113 is not set
-CONFIG_DVB_TDA826X=m
-CONFIG_DVB_TUA6100=m
-# CONFIG_DVB_CX24116 is not set
-# CONFIG_DVB_SI21XX is not set
-
-#
-# DVB-T (terrestrial) frontends
-#
-CONFIG_DVB_SP8870=m
-CONFIG_DVB_SP887X=m
-CONFIG_DVB_CX22700=m
-CONFIG_DVB_CX22702=m
-# CONFIG_DVB_DRX397XD is not set
-CONFIG_DVB_L64781=m
-CONFIG_DVB_TDA1004X=m
-CONFIG_DVB_NXT6000=m
-CONFIG_DVB_MT352=m
-CONFIG_DVB_ZL10353=m
-CONFIG_DVB_DIB3000MB=m
-CONFIG_DVB_DIB3000MC=m
-CONFIG_DVB_DIB7000M=m
-CONFIG_DVB_DIB7000P=m
-CONFIG_DVB_TDA10048=m
-
-#
-# DVB-C (cable) frontends
-#
-CONFIG_DVB_VES1820=m
-CONFIG_DVB_TDA10021=m
-CONFIG_DVB_TDA10023=m
-CONFIG_DVB_STV0297=m
-
-#
-# ATSC (North American/Korean Terrestrial/Cable DTV) frontends
-#
-CONFIG_DVB_NXT200X=m
-# CONFIG_DVB_OR51211 is not set
-# CONFIG_DVB_OR51132 is not set
-CONFIG_DVB_BCM3510=m
-CONFIG_DVB_LGDT330X=m
-# CONFIG_DVB_LGDT3304 is not set
-CONFIG_DVB_S5H1409=m
-CONFIG_DVB_AU8522=m
-CONFIG_DVB_S5H1411=m
-
-#
-# ISDB-T (terrestrial) frontends
-#
-# CONFIG_DVB_S921 is not set
-
-#
-# Digital terrestrial only tuners/PLL
-#
-CONFIG_DVB_PLL=m
-CONFIG_DVB_TUNER_DIB0070=m
-
-#
-# SEC control devices for DVB-S
-#
-CONFIG_DVB_LNBP21=m
-# CONFIG_DVB_ISL6405 is not set
-CONFIG_DVB_ISL6421=m
-# CONFIG_DVB_LGS8GL5 is not set
-
-#
-# Tools to develop new frontends
-#
-# CONFIG_DVB_DUMMY_FE is not set
-# CONFIG_DVB_AF9013 is not set
-# CONFIG_DAB is not set
+# CONFIG_AB3100_CORE is not set
+# CONFIG_EZX_PCAP is not set
+# CONFIG_MEDIA_SUPPORT is not set
 
 #
 # Graphics support
@@ -1366,53 +993,10 @@ CONFIG_LOGO=y
 CONFIG_LOGO_LINUX_MONO=y
 CONFIG_LOGO_LINUX_VGA16=y
 CONFIG_LOGO_LINUX_CLUT224=y
-CONFIG_SOUND=y
-CONFIG_SOUND_OSS_CORE=y
-CONFIG_SND=y
-CONFIG_SND_TIMER=y
-CONFIG_SND_PCM=y
-CONFIG_SND_HWDEP=y
-CONFIG_SND_RAWMIDI=y
-CONFIG_SND_SEQUENCER=m
-# CONFIG_SND_SEQ_DUMMY is not set
-CONFIG_SND_OSSEMUL=y
-CONFIG_SND_MIXER_OSS=y
-CONFIG_SND_PCM_OSS=y
-CONFIG_SND_PCM_OSS_PLUGINS=y
-CONFIG_SND_SEQUENCER_OSS=y
-# CONFIG_SND_HRTIMER is not set
-# CONFIG_SND_DYNAMIC_MINORS is not set
-CONFIG_SND_SUPPORT_OLD_API=y
-CONFIG_SND_VERBOSE_PROCFS=y
-CONFIG_SND_VERBOSE_PRINTK=y
-CONFIG_SND_DEBUG=y
-# CONFIG_SND_DEBUG_VERBOSE is not set
-# CONFIG_SND_PCM_XRUN_DEBUG is not set
-CONFIG_SND_DRIVERS=y
-# CONFIG_SND_DUMMY is not set
-# CONFIG_SND_VIRMIDI is not set
-# CONFIG_SND_MTPAV is not set
-# CONFIG_SND_SERIAL_U16550 is not set
-# CONFIG_SND_MPU401 is not set
-CONFIG_SND_ARM=y
-CONFIG_SND_SPI=y
-CONFIG_SND_USB=y
-CONFIG_SND_USB_AUDIO=y
-CONFIG_SND_USB_CAIAQ=m
-CONFIG_SND_USB_CAIAQ_INPUT=y
-CONFIG_SND_SOC=y
-CONFIG_SND_OMAP_SOC=y
-CONFIG_SND_OMAP_SOC_MCBSP=y
-# CONFIG_SND_OMAP_SOC_OVERO is not set
-CONFIG_SND_OMAP_SOC_SDP3430=y
-# CONFIG_SND_OMAP_SOC_OMAP3_PANDORA is not set
-CONFIG_SND_SOC_I2C_AND_SPI=y
-# CONFIG_SND_SOC_ALL_CODECS is not set
-CONFIG_SND_SOC_TWL4030=y
-# CONFIG_SOUND_PRIME is not set
+# CONFIG_SOUND is not set
 CONFIG_HID_SUPPORT=y
 CONFIG_HID=y
-CONFIG_HID_DEBUG=y
+# CONFIG_HID_DEBUG is not set
 # CONFIG_HIDRAW is not set
 
 #
@@ -1425,35 +1009,35 @@ CONFIG_USB_HID=y
 #
 # Special HID drivers
 #
-CONFIG_HID_COMPAT=y
-CONFIG_HID_A4TECH=y
-CONFIG_HID_APPLE=y
-CONFIG_HID_BELKIN=y
-CONFIG_HID_CHERRY=y
-CONFIG_HID_CHICONY=y
-CONFIG_HID_CYPRESS=y
-CONFIG_HID_EZKEY=y
-CONFIG_HID_GYRATION=y
-CONFIG_HID_LOGITECH=y
-# CONFIG_LOGITECH_FF is not set
-# CONFIG_LOGIRUMBLEPAD2_FF is not set
-CONFIG_HID_MICROSOFT=y
-CONFIG_HID_MONTEREY=y
+# CONFIG_HID_A4TECH is not set
+# CONFIG_HID_APPLE is not set
+# CONFIG_HID_BELKIN is not set
+# CONFIG_HID_CHERRY is not set
+# CONFIG_HID_CHICONY is not set
+# CONFIG_HID_CYPRESS is not set
+# CONFIG_HID_DRAGONRISE is not set
+# CONFIG_HID_EZKEY is not set
+# CONFIG_HID_KYE is not set
+# CONFIG_HID_GYRATION is not set
+# CONFIG_HID_KENSINGTON is not set
+# CONFIG_HID_LOGITECH is not set
+# CONFIG_HID_MICROSOFT is not set
+# CONFIG_HID_MONTEREY is not set
 # CONFIG_HID_NTRIG is not set
-CONFIG_HID_PANTHERLORD=y
-# CONFIG_PANTHERLORD_FF is not set
-CONFIG_HID_PETALYNX=y
-CONFIG_HID_SAMSUNG=y
-CONFIG_HID_SONY=y
-CONFIG_HID_SUNPLUS=y
-# CONFIG_GREENASIA_FF is not set
+# CONFIG_HID_PANTHERLORD is not set
+# CONFIG_HID_PETALYNX is not set
+# CONFIG_HID_SAMSUNG is not set
+# CONFIG_HID_SONY is not set
+# CONFIG_HID_SUNPLUS is not set
+# CONFIG_HID_GREENASIA is not set
+# CONFIG_HID_SMARTJOYPLUS is not set
 # CONFIG_HID_TOPSEED is not set
-# CONFIG_THRUSTMASTER_FF is not set
-# CONFIG_ZEROPLUS_FF is not set
+# CONFIG_HID_THRUSTMASTER is not set
+# CONFIG_HID_ZEROPLUS is not set
 CONFIG_USB_SUPPORT=y
 CONFIG_USB_ARCH_HAS_HCD=y
 CONFIG_USB_ARCH_HAS_OHCI=y
-# CONFIG_USB_ARCH_HAS_EHCI is not set
+CONFIG_USB_ARCH_HAS_EHCI=y
 CONFIG_USB=y
 CONFIG_USB_DEBUG=y
 CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
@@ -1461,9 +1045,9 @@ CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
 #
 # Miscellaneous USB options
 #
-CONFIG_USB_DEVICEFS=y
-CONFIG_USB_DEVICE_CLASS=y
-CONFIG_USB_DYNAMIC_MINORS=y
+# CONFIG_USB_DEVICEFS is not set
+# CONFIG_USB_DEVICE_CLASS is not set
+# CONFIG_USB_DYNAMIC_MINORS is not set
 CONFIG_USB_SUSPEND=y
 CONFIG_USB_OTG=y
 # CONFIG_USB_OTG_WHITELIST is not set
@@ -1476,8 +1060,12 @@ CONFIG_USB_MON=y
 # USB Host Controller Drivers
 #
 # CONFIG_USB_C67X00_HCD is not set
+CONFIG_USB_EHCI_HCD=m
+# CONFIG_USB_EHCI_ROOT_HUB_TT is not set
+# CONFIG_USB_EHCI_TT_NEWSCHED is not set
 # CONFIG_USB_OXU210HP_HCD is not set
 # CONFIG_USB_ISP116X_HCD is not set
+# CONFIG_USB_ISP1760_HCD is not set
 # CONFIG_USB_OHCI_HCD is not set
 # CONFIG_USB_SL811_HCD is not set
 # CONFIG_USB_R8A66597_HCD is not set
@@ -1493,23 +1081,25 @@ CONFIG_USB_MUSB_SOC=y
 CONFIG_USB_MUSB_OTG=y
 CONFIG_USB_GADGET_MUSB_HDRC=y
 CONFIG_USB_MUSB_HDRC_HCD=y
-CONFIG_MUSB_PIO_ONLY=y
+# CONFIG_MUSB_PIO_ONLY is not set
+CONFIG_USB_INVENTRA_DMA=y
+# CONFIG_USB_TI_CPPI_DMA is not set
 # CONFIG_USB_MUSB_DEBUG is not set
 
 #
 # USB Device Class drivers
 #
 # CONFIG_USB_ACM is not set
-CONFIG_USB_PRINTER=y
-CONFIG_USB_WDM=y
+# CONFIG_USB_PRINTER is not set
+# CONFIG_USB_WDM is not set
 # CONFIG_USB_TMC is not set
 
 #
-# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may also be needed;
+# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may
 #
 
 #
-# see USB_STORAGE Help for more information
+# also be needed; see USB_STORAGE Help for more info
 #
 CONFIG_USB_STORAGE=y
 # CONFIG_USB_STORAGE_DEBUG is not set
@@ -1551,14 +1141,14 @@ CONFIG_USB_STORAGE=y
 # CONFIG_USB_LED is not set
 # CONFIG_USB_CYPRESS_CY7C63 is not set
 # CONFIG_USB_CYTHERM is not set
-# CONFIG_USB_PHIDGET is not set
 # CONFIG_USB_IDMOUSE is not set
 # CONFIG_USB_FTDI_ELAN is not set
 # CONFIG_USB_APPLEDISPLAY is not set
+# CONFIG_USB_SISUSBVGA is not set
 # CONFIG_USB_LD is not set
 # CONFIG_USB_TRANCEVIBRATOR is not set
 # CONFIG_USB_IOWARRIOR is not set
-# CONFIG_USB_TEST is not set
+CONFIG_USB_TEST=y
 # CONFIG_USB_ISIGHTFW is not set
 # CONFIG_USB_VST is not set
 CONFIG_USB_GADGET=y
@@ -1574,25 +1164,29 @@ CONFIG_USB_GADGET_SELECTED=y
 # CONFIG_USB_GADGET_OMAP is not set
 # CONFIG_USB_GADGET_PXA25X is not set
 # CONFIG_USB_GADGET_PXA27X is not set
-# CONFIG_USB_GADGET_S3C2410 is not set
+# CONFIG_USB_GADGET_S3C_HSOTG is not set
 # CONFIG_USB_GADGET_IMX is not set
+# CONFIG_USB_GADGET_S3C2410 is not set
 # CONFIG_USB_GADGET_M66592 is not set
 # CONFIG_USB_GADGET_AMD5536UDC is not set
 # CONFIG_USB_GADGET_FSL_QE is not set
 # CONFIG_USB_GADGET_CI13XXX is not set
 # CONFIG_USB_GADGET_NET2280 is not set
 # CONFIG_USB_GADGET_GOKU is not set
+# CONFIG_USB_GADGET_LANGWELL is not set
 # CONFIG_USB_GADGET_DUMMY_HCD is not set
 CONFIG_USB_GADGET_DUALSPEED=y
 # CONFIG_USB_ZERO is not set
-CONFIG_USB_ETH=y
+# CONFIG_USB_AUDIO is not set
+CONFIG_USB_ETH=m
 CONFIG_USB_ETH_RNDIS=y
-# CONFIG_USB_GADGETFS is not set
-# CONFIG_USB_FILE_STORAGE is not set
-# CONFIG_USB_G_SERIAL is not set
+CONFIG_USB_GADGETFS=m
+CONFIG_USB_FILE_STORAGE=m
+# CONFIG_USB_FILE_STORAGE_TEST is not set
+CONFIG_USB_G_SERIAL=m
 # CONFIG_USB_MIDI_GADGET is not set
 # CONFIG_USB_G_PRINTER is not set
-# CONFIG_USB_CDC_COMPOSITE is not set
+CONFIG_USB_CDC_COMPOSITE=m
 
 #
 # OTG and related infrastructure
@@ -1601,6 +1195,7 @@ CONFIG_USB_OTG_UTILS=y
 # CONFIG_USB_GPIO_VBUS is not set
 # CONFIG_ISP1301_OMAP is not set
 CONFIG_TWL4030_USB=y
+# CONFIG_NOP_USB_XCEIV is not set
 CONFIG_MMC=y
 # CONFIG_MMC_DEBUG is not set
 CONFIG_MMC_UNSAFE_RESUME=y
@@ -1617,7 +1212,6 @@ CONFIG_SDIO_UART=y
 # MMC/SD/SDIO Host Controller Drivers
 #
 # CONFIG_MMC_SDHCI is not set
-# CONFIG_MMC_OMAP is not set
 CONFIG_MMC_OMAP_HS=y
 # CONFIG_MMC_SPI is not set
 # CONFIG_MEMSTICK is not set
@@ -1628,9 +1222,16 @@ CONFIG_LEDS_CLASS=y
 #
 # LED drivers
 #
+# CONFIG_LEDS_OMAP_DEBUG is not set
+# CONFIG_LEDS_OMAP is not set
+# CONFIG_LEDS_OMAP_PWM is not set
 # CONFIG_LEDS_PCA9532 is not set
 CONFIG_LEDS_GPIO=y
+CONFIG_LEDS_GPIO_PLATFORM=y
+# CONFIG_LEDS_LP3944 is not set
 # CONFIG_LEDS_PCA955X is not set
+# CONFIG_LEDS_DAC124S085 is not set
+# CONFIG_LEDS_BD2802 is not set
 
 #
 # LED Triggers
@@ -1639,7 +1240,12 @@ CONFIG_LEDS_TRIGGERS=y
 CONFIG_LEDS_TRIGGER_TIMER=y
 CONFIG_LEDS_TRIGGER_HEARTBEAT=y
 # CONFIG_LEDS_TRIGGER_BACKLIGHT is not set
+# CONFIG_LEDS_TRIGGER_GPIO is not set
 # CONFIG_LEDS_TRIGGER_DEFAULT_ON is not set
+
+#
+# iptables trigger is under Netfilter config (LED target)
+#
 CONFIG_RTC_LIB=y
 CONFIG_RTC_CLASS=y
 CONFIG_RTC_HCTOSYS=y
@@ -1672,6 +1278,7 @@ CONFIG_RTC_DRV_TWL4030=y
 # CONFIG_RTC_DRV_S35390A is not set
 # CONFIG_RTC_DRV_FM3130 is not set
 # CONFIG_RTC_DRV_RX8581 is not set
+# CONFIG_RTC_DRV_RX8025 is not set
 
 #
 # SPI RTC drivers
@@ -1703,6 +1310,7 @@ CONFIG_RTC_DRV_TWL4030=y
 # on-CPU RTC drivers
 #
 # CONFIG_DMADEVICES is not set
+# CONFIG_AUXDISPLAY is not set
 CONFIG_REGULATOR=y
 # CONFIG_REGULATOR_DEBUG is not set
 # CONFIG_REGULATOR_FIXED_VOLTAGE is not set
@@ -1711,32 +1319,36 @@ CONFIG_REGULATOR=y
 # CONFIG_REGULATOR_BQ24022 is not set
 # CONFIG_REGULATOR_MAX1586 is not set
 CONFIG_REGULATOR_TWL4030=y
+# CONFIG_REGULATOR_LP3971 is not set
 # CONFIG_UIO is not set
 # CONFIG_STAGING is not set
 
 #
+# CBUS support
+#
+# CONFIG_CBUS is not set
+
+#
 # File systems
 #
 CONFIG_EXT2_FS=y
 # CONFIG_EXT2_FS_XATTR is not set
 # CONFIG_EXT2_FS_XIP is not set
 CONFIG_EXT3_FS=y
+# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
 # CONFIG_EXT3_FS_XATTR is not set
 # CONFIG_EXT4_FS is not set
 CONFIG_JBD=y
 # CONFIG_JBD_DEBUG is not set
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
-CONFIG_FS_POSIX_ACL=y
-CONFIG_FILE_LOCKING=y
-CONFIG_XFS_FS=m
-# CONFIG_XFS_QUOTA is not set
-# CONFIG_XFS_POSIX_ACL is not set
-# CONFIG_XFS_RT is not set
-# CONFIG_XFS_DEBUG is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
 # CONFIG_GFS2_FS is not set
 # CONFIG_OCFS2_FS is not set
 # CONFIG_BTRFS_FS is not set
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
 CONFIG_DNOTIFY=y
 CONFIG_INOTIFY=y
 CONFIG_INOTIFY_USER=y
@@ -1749,16 +1361,18 @@ CONFIG_QFMT_V2=y
 CONFIG_QUOTACTL=y
 # CONFIG_AUTOFS_FS is not set
 # CONFIG_AUTOFS4_FS is not set
-CONFIG_FUSE_FS=m
+# CONFIG_FUSE_FS is not set
+
+#
+# Caches
+#
+# CONFIG_FSCACHE is not set
 
 #
 # CD-ROM/DVD Filesystems
 #
-CONFIG_ISO9660_FS=m
-CONFIG_JOLIET=y
-CONFIG_ZISOFS=y
-CONFIG_UDF_FS=m
-CONFIG_UDF_NLS=y
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
 
 #
 # DOS/FAT/NT Filesystems
@@ -1793,15 +1407,13 @@ CONFIG_JFFS2_FS=y
 CONFIG_JFFS2_FS_DEBUG=0
 CONFIG_JFFS2_FS_WRITEBUFFER=y
 # CONFIG_JFFS2_FS_WBUF_VERIFY is not set
-CONFIG_JFFS2_SUMMARY=y
-CONFIG_JFFS2_FS_XATTR=y
-CONFIG_JFFS2_FS_POSIX_ACL=y
-CONFIG_JFFS2_FS_SECURITY=y
+# CONFIG_JFFS2_SUMMARY is not set
+# CONFIG_JFFS2_FS_XATTR is not set
 CONFIG_JFFS2_COMPRESSION_OPTIONS=y
 CONFIG_JFFS2_ZLIB=y
-CONFIG_JFFS2_LZO=y
+# CONFIG_JFFS2_LZO is not set
 CONFIG_JFFS2_RTIME=y
-CONFIG_JFFS2_RUBIN=y
+# CONFIG_JFFS2_RUBIN is not set
 # CONFIG_JFFS2_CMODE_NONE is not set
 CONFIG_JFFS2_CMODE_PRIORITY=y
 # CONFIG_JFFS2_CMODE_SIZE is not set
@@ -1816,20 +1428,20 @@ CONFIG_JFFS2_CMODE_PRIORITY=y
 # CONFIG_ROMFS_FS is not set
 # CONFIG_SYSV_FS is not set
 # CONFIG_UFS_FS is not set
+# CONFIG_NILFS2_FS is not set
 CONFIG_NETWORK_FILESYSTEMS=y
 CONFIG_NFS_FS=y
 CONFIG_NFS_V3=y
 # CONFIG_NFS_V3_ACL is not set
 CONFIG_NFS_V4=y
+# CONFIG_NFS_V4_1 is not set
 CONFIG_ROOT_NFS=y
 # CONFIG_NFSD is not set
 CONFIG_LOCKD=y
 CONFIG_LOCKD_V4=y
-CONFIG_EXPORTFS=m
 CONFIG_NFS_COMMON=y
 CONFIG_SUNRPC=y
 CONFIG_SUNRPC_GSS=y
-# CONFIG_SUNRPC_REGISTER_V4 is not set
 CONFIG_RPCSEC_GSS_KRB5=y
 # CONFIG_RPCSEC_GSS_SPKM3 is not set
 # CONFIG_SMB_FS is not set
@@ -1917,12 +1529,15 @@ CONFIG_DEBUG_KERNEL=y
 CONFIG_DETECT_SOFTLOCKUP=y
 # CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set
 CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0
+CONFIG_DETECT_HUNG_TASK=y
+# CONFIG_BOOTPARAM_HUNG_TASK_PANIC is not set
+CONFIG_BOOTPARAM_HUNG_TASK_PANIC_VALUE=0
 CONFIG_SCHED_DEBUG=y
-CONFIG_SCHEDSTATS=y
-CONFIG_TIMER_STATS=y
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_TIMER_STATS is not set
 # CONFIG_DEBUG_OBJECTS is not set
-# CONFIG_SLUB_DEBUG_ON is not set
-# CONFIG_SLUB_STATS is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_KMEMLEAK is not set
 # CONFIG_DEBUG_RT_MUTEXES is not set
 # CONFIG_RT_MUTEX_TESTER is not set
 # CONFIG_DEBUG_SPINLOCK is not set
@@ -1932,10 +1547,9 @@ CONFIG_DEBUG_MUTEXES=y
 # CONFIG_LOCK_STAT is not set
 # CONFIG_DEBUG_SPINLOCK_SLEEP is not set
 # CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
-CONFIG_STACKTRACE=y
 # CONFIG_DEBUG_KOBJECT is not set
 # CONFIG_DEBUG_BUGVERBOSE is not set
-# CONFIG_DEBUG_INFO is not set
+CONFIG_DEBUG_INFO=y
 # CONFIG_DEBUG_VM is not set
 # CONFIG_DEBUG_WRITECOUNT is not set
 # CONFIG_DEBUG_MEMORY_INIT is not set
@@ -1950,30 +1564,20 @@ CONFIG_FRAME_POINTER=y
 # CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
 # CONFIG_FAULT_INJECTION is not set
 # CONFIG_LATENCYTOP is not set
-CONFIG_NOP_TRACER=y
+# CONFIG_PAGE_POISONING is not set
 CONFIG_HAVE_FUNCTION_TRACER=y
-CONFIG_RING_BUFFER=y
-CONFIG_TRACING=y
-
-#
-# Tracers
-#
-# CONFIG_FUNCTION_TRACER is not set
-# CONFIG_IRQSOFF_TRACER is not set
-# CONFIG_SCHED_TRACER is not set
-# CONFIG_CONTEXT_SWITCH_TRACER is not set
-# CONFIG_BOOT_TRACER is not set
-# CONFIG_TRACE_BRANCH_PROFILING is not set
-# CONFIG_STACK_TRACER is not set
-# CONFIG_FTRACE_STARTUP_TEST is not set
-# CONFIG_DYNAMIC_PRINTK_DEBUG is not set
+CONFIG_TRACING_SUPPORT=y
+# CONFIG_FTRACE is not set
+# CONFIG_DYNAMIC_DEBUG is not set
 # CONFIG_SAMPLES is not set
 CONFIG_HAVE_ARCH_KGDB=y
 # CONFIG_KGDB is not set
+# CONFIG_ARM_UNWIND is not set
 # CONFIG_DEBUG_USER is not set
 # CONFIG_DEBUG_ERRORS is not set
 # CONFIG_DEBUG_STACK_USAGE is not set
-# CONFIG_DEBUG_LL is not set
+CONFIG_DEBUG_LL=y
+# CONFIG_DEBUG_ICEDCC is not set
 
 #
 # Security options
@@ -1982,10 +1586,6 @@ CONFIG_HAVE_ARCH_KGDB=y
 # CONFIG_SECURITY is not set
 # CONFIG_SECURITYFS is not set
 # CONFIG_SECURITY_FILE_CAPABILITIES is not set
-CONFIG_XOR_BLOCKS=m
-CONFIG_ASYNC_CORE=m
-CONFIG_ASYNC_MEMCPY=m
-CONFIG_ASYNC_XOR=m
 CONFIG_CRYPTO=y
 
 #
@@ -2000,13 +1600,15 @@ CONFIG_CRYPTO_BLKCIPHER2=y
 CONFIG_CRYPTO_HASH=y
 CONFIG_CRYPTO_HASH2=y
 CONFIG_CRYPTO_RNG2=y
+CONFIG_CRYPTO_PCOMP=y
 CONFIG_CRYPTO_MANAGER=y
 CONFIG_CRYPTO_MANAGER2=y
-CONFIG_CRYPTO_GF128MUL=m
-CONFIG_CRYPTO_NULL=m
-CONFIG_CRYPTO_CRYPTD=m
+# CONFIG_CRYPTO_GF128MUL is not set
+# CONFIG_CRYPTO_NULL is not set
+CONFIG_CRYPTO_WORKQUEUE=y
+# CONFIG_CRYPTO_CRYPTD is not set
 # CONFIG_CRYPTO_AUTHENC is not set
-CONFIG_CRYPTO_TEST=m
+# CONFIG_CRYPTO_TEST is not set
 
 #
 # Authenticated Encryption with Associated Data
@@ -2021,58 +1623,58 @@ CONFIG_CRYPTO_TEST=m
 CONFIG_CRYPTO_CBC=y
 # CONFIG_CRYPTO_CTR is not set
 # CONFIG_CRYPTO_CTS is not set
-CONFIG_CRYPTO_ECB=y
-CONFIG_CRYPTO_LRW=m
+CONFIG_CRYPTO_ECB=m
+# CONFIG_CRYPTO_LRW is not set
 CONFIG_CRYPTO_PCBC=m
 # CONFIG_CRYPTO_XTS is not set
 
 #
 # Hash modes
 #
-CONFIG_CRYPTO_HMAC=m
-CONFIG_CRYPTO_XCBC=m
+# CONFIG_CRYPTO_HMAC is not set
+# CONFIG_CRYPTO_XCBC is not set
 
 #
 # Digest
 #
 CONFIG_CRYPTO_CRC32C=y
-CONFIG_CRYPTO_MD4=m
+# CONFIG_CRYPTO_MD4 is not set
 CONFIG_CRYPTO_MD5=y
-CONFIG_CRYPTO_MICHAEL_MIC=y
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
 # CONFIG_CRYPTO_RMD128 is not set
 # CONFIG_CRYPTO_RMD160 is not set
 # CONFIG_CRYPTO_RMD256 is not set
 # CONFIG_CRYPTO_RMD320 is not set
-CONFIG_CRYPTO_SHA1=m
-CONFIG_CRYPTO_SHA256=m
-CONFIG_CRYPTO_SHA512=m
-CONFIG_CRYPTO_TGR192=m
-CONFIG_CRYPTO_WP512=m
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_WP512 is not set
 
 #
 # Ciphers
 #
-CONFIG_CRYPTO_AES=y
-CONFIG_CRYPTO_ANUBIS=m
-CONFIG_CRYPTO_ARC4=y
-CONFIG_CRYPTO_BLOWFISH=m
-CONFIG_CRYPTO_CAMELLIA=m
-CONFIG_CRYPTO_CAST5=m
-CONFIG_CRYPTO_CAST6=m
+# CONFIG_CRYPTO_AES is not set
+# CONFIG_CRYPTO_ANUBIS is not set
+# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_CAMELLIA is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
 CONFIG_CRYPTO_DES=y
-CONFIG_CRYPTO_FCRYPT=m
-CONFIG_CRYPTO_KHAZAD=m
+# CONFIG_CRYPTO_FCRYPT is not set
+# CONFIG_CRYPTO_KHAZAD is not set
 # CONFIG_CRYPTO_SALSA20 is not set
 # CONFIG_CRYPTO_SEED is not set
-CONFIG_CRYPTO_SERPENT=m
-CONFIG_CRYPTO_TEA=m
-CONFIG_CRYPTO_TWOFISH=m
-CONFIG_CRYPTO_TWOFISH_COMMON=m
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_TWOFISH is not set
 
 #
 # Compression
 #
-CONFIG_CRYPTO_DEFLATE=m
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_ZLIB is not set
 # CONFIG_CRYPTO_LZO is not set
 
 #
@@ -2080,6 +1682,7 @@ CONFIG_CRYPTO_DEFLATE=m
 #
 # CONFIG_CRYPTO_ANSI_CPRNG is not set
 CONFIG_CRYPTO_HW=y
+# CONFIG_BINARY_PRINTF is not set
 
 #
 # Library routines
@@ -2087,17 +1690,16 @@ CONFIG_CRYPTO_HW=y
 CONFIG_BITREVERSE=y
 CONFIG_GENERIC_FIND_LAST_BIT=y
 CONFIG_CRC_CCITT=y
-CONFIG_CRC16=m
-CONFIG_CRC_T10DIF=y
-CONFIG_CRC_ITU_T=y
+# CONFIG_CRC16 is not set
+# CONFIG_CRC_T10DIF is not set
+# CONFIG_CRC_ITU_T is not set
 CONFIG_CRC32=y
-CONFIG_CRC7=y
+# CONFIG_CRC7 is not set
 CONFIG_LIBCRC32C=y
 CONFIG_ZLIB_INFLATE=y
 CONFIG_ZLIB_DEFLATE=y
-CONFIG_LZO_COMPRESS=y
-CONFIG_LZO_DECOMPRESS=y
-CONFIG_PLIST=y
+CONFIG_DECOMPRESS_GZIP=y
 CONFIG_HAS_IOMEM=y
 CONFIG_HAS_IOPORT=y
 CONFIG_HAS_DMA=y
+CONFIG_NLATTR=y
diff --git a/arch/arm/configs/omap_3630sdp_defconfig b/arch/arm/configs/omap_3630sdp_defconfig
new file mode 100644 (file)
index 0000000..e836c8a
--- /dev/null
@@ -0,0 +1,1611 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.32-rc6
+# Thu Nov 12 12:21:37 2009
+#
+CONFIG_ARM=y
+CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+CONFIG_GENERIC_GPIO=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_ARCH_HAS_CPUFREQ=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
+CONFIG_VECTORS_BASE=0xffff0000
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+# CONFIG_POSIX_MQUEUE is not set
+CONFIG_BSD_PROCESS_ACCT=y
+# CONFIG_BSD_PROCESS_ACCT_V3 is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_AUDIT is not set
+
+#
+# RCU Subsystem
+#
+CONFIG_TREE_RCU=y
+# CONFIG_TREE_PREEMPT_RCU is not set
+# CONFIG_RCU_TRACE is not set
+CONFIG_RCU_FANOUT=32
+# CONFIG_RCU_FANOUT_EXACT is not set
+# CONFIG_TREE_RCU_TRACE is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_GROUP_SCHED=y
+CONFIG_FAIR_GROUP_SCHED=y
+# CONFIG_RT_GROUP_SCHED is not set
+CONFIG_USER_SCHED=y
+# CONFIG_CGROUP_SCHED is not set
+# CONFIG_CGROUPS is not set
+# CONFIG_SYSFS_DEPRECATED_V2 is not set
+# CONFIG_RELAY is not set
+# CONFIG_NAMESPACES is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_RD_GZIP=y
+# CONFIG_RD_BZIP2 is not set
+# CONFIG_RD_LZMA is not set
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+CONFIG_ANON_INODES=y
+CONFIG_EMBEDDED=y
+CONFIG_UID16=y
+# CONFIG_SYSCTL_SYSCALL is not set
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+CONFIG_KALLSYMS_EXTRA_PASS=y
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_AIO=y
+
+#
+# Kernel Performance Events And Counters
+#
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_COMPAT_BRK=y
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
+# CONFIG_PROFILING is not set
+CONFIG_HAVE_OPROFILE=y
+# CONFIG_KPROBES is not set
+CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_KRETPROBES=y
+CONFIG_HAVE_CLK=y
+
+#
+# GCOV-based kernel profiling
+#
+# CONFIG_SLOW_WORK is not set
+CONFIG_HAVE_GENERIC_DMA_COHERENT=y
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+# CONFIG_MODULE_FORCE_LOAD is not set
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+CONFIG_MODVERSIONS=y
+CONFIG_MODULE_SRCVERSION_ALL=y
+CONFIG_BLOCK=y
+CONFIG_LBDAF=y
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_BLK_DEV_INTEGRITY is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+CONFIG_DEFAULT_AS=y
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="anticipatory"
+CONFIG_FREEZER=y
+
+#
+# System Type
+#
+CONFIG_MMU=y
+# CONFIG_ARCH_AAEC2000 is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_REALVIEW is not set
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_AT91 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_GEMINI is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_EP93XX is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_MXC is not set
+# CONFIG_ARCH_STMP3XXX is not set
+# CONFIG_ARCH_NETX is not set
+# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_NOMADIK is not set
+# CONFIG_ARCH_IOP13XX is not set
+# CONFIG_ARCH_IOP32X is not set
+# CONFIG_ARCH_IOP33X is not set
+# CONFIG_ARCH_IXP23XX is not set
+# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_KIRKWOOD is not set
+# CONFIG_ARCH_LOKI is not set
+# CONFIG_ARCH_MV78XX0 is not set
+# CONFIG_ARCH_ORION5X is not set
+# CONFIG_ARCH_MMP is not set
+# CONFIG_ARCH_KS8695 is not set
+# CONFIG_ARCH_NS9XXX is not set
+# CONFIG_ARCH_W90X900 is not set
+# CONFIG_ARCH_PNX4008 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_MSM is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_S3C64XX is not set
+# CONFIG_ARCH_S5PC1XX is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_U300 is not set
+# CONFIG_ARCH_DAVINCI is not set
+CONFIG_ARCH_OMAP=y
+# CONFIG_ARCH_BCMRING is not set
+
+#
+# TI OMAP Implementations
+#
+CONFIG_ARCH_OMAP_OTG=y
+# CONFIG_ARCH_OMAP1 is not set
+# CONFIG_ARCH_OMAP2 is not set
+CONFIG_ARCH_OMAP3=y
+# CONFIG_ARCH_OMAP4 is not set
+
+#
+# OMAP Feature Selections
+#
+# CONFIG_OMAP_DEBUG_POWERDOMAIN is not set
+# CONFIG_OMAP_DEBUG_CLOCKDOMAIN is not set
+# CONFIG_OMAP_RESET_CLOCKS is not set
+CONFIG_OMAP_MUX=y
+CONFIG_OMAP_MUX_DEBUG=y
+CONFIG_OMAP_MUX_WARNINGS=y
+CONFIG_OMAP_MCBSP=y
+# CONFIG_OMAP_MBOX_FWK is not set
+# CONFIG_OMAP_MPU_TIMER is not set
+CONFIG_OMAP_32K_TIMER=y
+CONFIG_OMAP_32K_TIMER_HZ=128
+CONFIG_OMAP_DM_TIMER=y
+CONFIG_OMAP_LL_DEBUG_UART1=y
+# CONFIG_OMAP_LL_DEBUG_UART2 is not set
+# CONFIG_OMAP_LL_DEBUG_UART3 is not set
+# CONFIG_OMAP_LL_DEBUG_NONE is not set
+# CONFIG_OMAP_PM_NONE is not set
+CONFIG_OMAP_PM_NOOP=y
+CONFIG_ARCH_OMAP34XX=y
+CONFIG_ARCH_OMAP3430=y
+
+#
+# OMAP Board Type
+#
+# CONFIG_MACH_OMAP3_BEAGLE is not set
+# CONFIG_MACH_OMAP_LDP is not set
+# CONFIG_MACH_OVERO is not set
+# CONFIG_MACH_OMAP3EVM is not set
+# CONFIG_MACH_OMAP3_PANDORA is not set
+# CONFIG_MACH_OMAP_3430SDP is not set
+# CONFIG_MACH_NOKIA_RX51 is not set
+# CONFIG_MACH_OMAP_ZOOM2 is not set
+# CONFIG_MACH_CM_T35 is not set
+# CONFIG_MACH_OMAP_ZOOM3 is not set
+CONFIG_MACH_OMAP_3630SDP=y
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_32v6K=y
+CONFIG_CPU_V7=y
+CONFIG_CPU_32v7=y
+CONFIG_CPU_ABRT_EV7=y
+CONFIG_CPU_PABRT_V7=y
+CONFIG_CPU_CACHE_V7=y
+CONFIG_CPU_CACHE_VIPT=y
+CONFIG_CPU_COPY_V6=y
+CONFIG_CPU_TLB_V7=y
+CONFIG_CPU_HAS_ASID=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
+
+#
+# Processor Features
+#
+CONFIG_ARM_THUMB=y
+# CONFIG_ARM_THUMBEE is not set
+# CONFIG_CPU_ICACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_DISABLE is not set
+# CONFIG_CPU_BPREDICT_DISABLE is not set
+CONFIG_HAS_TLS_REG=y
+CONFIG_ARM_L1_CACHE_SHIFT=6
+# CONFIG_ARM_ERRATA_430973 is not set
+# CONFIG_ARM_ERRATA_458693 is not set
+# CONFIG_ARM_ERRATA_460075 is not set
+CONFIG_COMMON_CLKDEV=y
+
+#
+# Bus support
+#
+# CONFIG_PCI_SYSCALL is not set
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+CONFIG_TICK_ONESHOT=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+CONFIG_VMSPLIT_3G=y
+# CONFIG_VMSPLIT_2G is not set
+# CONFIG_VMSPLIT_1G is not set
+CONFIG_PAGE_OFFSET=0xC0000000
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+CONFIG_HZ=128
+# CONFIG_THUMB2_KERNEL is not set
+CONFIG_AEABI=y
+CONFIG_OABI_COMPAT=y
+# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set
+# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set
+# CONFIG_HIGHMEM is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+CONFIG_PAGEFLAGS_EXTENDED=y
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_PHYS_ADDR_T_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=0
+CONFIG_VIRT_TO_BUS=y
+CONFIG_HAVE_MLOCK=y
+CONFIG_HAVE_MLOCKED_PAGE_BIT=y
+# CONFIG_KSM is not set
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
+# CONFIG_LEDS is not set
+CONFIG_ALIGNMENT_TRAP=y
+# CONFIG_UACCESS_WITH_MEMCPY is not set
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="root=/dev/nfs nfsroot=192.168.0.1:/home/user/buildroot ip=192.168.0.2:192.168.0.1:192.168.0.1:255.255.255.0:tgt:eth0:off rw console=ttyS2,115200n8"
+# CONFIG_XIP_KERNEL is not set
+# CONFIG_KEXEC is not set
+
+#
+# CPU Power Management
+#
+# CONFIG_CPU_FREQ is not set
+# CONFIG_CPU_IDLE is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
+# CONFIG_FPE_FASTFPE is not set
+CONFIG_VFP=y
+CONFIG_VFPv3=y
+# CONFIG_NEON is not set
+
+#
+# Userspace binary formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_HAVE_AOUT=y
+# CONFIG_BINFMT_AOUT is not set
+CONFIG_BINFMT_MISC=y
+
+#
+# Power management options
+#
+CONFIG_PM=y
+CONFIG_PM_DEBUG=y
+CONFIG_PM_VERBOSE=y
+CONFIG_CAN_PM_TRACE=y
+CONFIG_PM_SLEEP=y
+CONFIG_SUSPEND=y
+# CONFIG_PM_TEST_SUSPEND is not set
+CONFIG_SUSPEND_FREEZER=y
+# CONFIG_APM_EMULATION is not set
+# CONFIG_PM_RUNTIME is not set
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+CONFIG_XFRM_USER=y
+# CONFIG_XFRM_SUB_POLICY is not set
+CONFIG_XFRM_MIGRATE=y
+# CONFIG_XFRM_STATISTICS is not set
+CONFIG_NET_KEY=y
+CONFIG_NET_KEY_MIGRATE=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+CONFIG_IP_PNP_RARP=y
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
+# CONFIG_INET_LRO is not set
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# CONFIG_RDS is not set
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_NET_DSA is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_PHONET is not set
+# CONFIG_IEEE802154 is not set
+# CONFIG_NET_SCHED is not set
+# CONFIG_DCB is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_CAN is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+# CONFIG_WIRELESS is not set
+# CONFIG_WIMAX is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+# CONFIG_DEVTMPFS is not set
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES is not set
+# CONFIG_SYS_HYPERVISOR is not set
+CONFIG_CONNECTOR=y
+CONFIG_PROC_EVENTS=y
+# CONFIG_MTD is not set
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_UB is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=16384
+# CONFIG_BLK_DEV_XIP is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+# CONFIG_MG_DISK is not set
+CONFIG_MISC_DEVICES=y
+# CONFIG_ICS932S401 is not set
+# CONFIG_ENCLOSURE_SERVICES is not set
+# CONFIG_ISL29003 is not set
+# CONFIG_C2PORT is not set
+
+#
+# EEPROM support
+#
+# CONFIG_EEPROM_AT24 is not set
+# CONFIG_EEPROM_AT25 is not set
+# CONFIG_EEPROM_LEGACY is not set
+# CONFIG_EEPROM_MAX6875 is not set
+# CONFIG_EEPROM_93CX6 is not set
+CONFIG_HAVE_IDE=y
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=y
+CONFIG_SCSI_DMA=y
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+# CONFIG_BLK_DEV_SR is not set
+# CONFIG_CHR_DEV_SG is not set
+# CONFIG_CHR_DEV_SCH is not set
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC is not set
+CONFIG_SCSI_WAIT_SCAN=m
+
+#
+# SCSI Transports
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+# CONFIG_SCSI_SRP_ATTRS is not set
+CONFIG_SCSI_LOWLEVEL=y
+# CONFIG_ISCSI_TCP is not set
+# CONFIG_LIBFC is not set
+# CONFIG_LIBFCOE is not set
+# CONFIG_SCSI_DEBUG is not set
+# CONFIG_SCSI_DH is not set
+# CONFIG_SCSI_OSD_INITIATOR is not set
+# CONFIG_ATA is not set
+# CONFIG_MD is not set
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_VETH is not set
+CONFIG_PHYLIB=y
+
+#
+# MII PHY device drivers
+#
+# CONFIG_MARVELL_PHY is not set
+# CONFIG_DAVICOM_PHY is not set
+# CONFIG_QSEMI_PHY is not set
+# CONFIG_LXT_PHY is not set
+# CONFIG_CICADA_PHY is not set
+# CONFIG_VITESSE_PHY is not set
+CONFIG_SMSC_PHY=y
+# CONFIG_BROADCOM_PHY is not set
+# CONFIG_ICPLUS_PHY is not set
+# CONFIG_REALTEK_PHY is not set
+# CONFIG_NATIONAL_PHY is not set
+# CONFIG_STE10XP is not set
+# CONFIG_LSI_ET1011C_PHY is not set
+# CONFIG_FIXED_PHY is not set
+# CONFIG_MDIO_BITBANG is not set
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_AX88796 is not set
+CONFIG_SMC91X=y
+# CONFIG_DM9000 is not set
+# CONFIG_ENC28J60 is not set
+# CONFIG_ETHOC is not set
+# CONFIG_SMC911X is not set
+# CONFIG_SMSC911X is not set
+# CONFIG_DNET is not set
+# CONFIG_IBM_NEW_EMAC_ZMII is not set
+# CONFIG_IBM_NEW_EMAC_RGMII is not set
+# CONFIG_IBM_NEW_EMAC_TAH is not set
+# CONFIG_IBM_NEW_EMAC_EMAC4 is not set
+# CONFIG_IBM_NEW_EMAC_NO_FLOW_CTRL is not set
+# CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT is not set
+# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
+# CONFIG_B44 is not set
+# CONFIG_KS8842 is not set
+# CONFIG_KS8851 is not set
+# CONFIG_KS8851_MLL is not set
+CONFIG_NETDEV_1000=y
+CONFIG_NETDEV_10000=y
+CONFIG_WLAN=y
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
+
+#
+# Enable WiMAX (Networking options) to see the WiMAX drivers
+#
+
+#
+# USB Network Adapters
+#
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RTL8150 is not set
+# CONFIG_USB_USBNET is not set
+# CONFIG_WAN is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_ISDN is not set
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
+
+#
+# Userland interfaces
+#
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_ADS7846=y
+# CONFIG_TOUCHSCREEN_AD7877 is not set
+# CONFIG_TOUCHSCREEN_AD7879_I2C is not set
+# CONFIG_TOUCHSCREEN_AD7879_SPI is not set
+# CONFIG_TOUCHSCREEN_AD7879 is not set
+# CONFIG_TOUCHSCREEN_EETI is not set
+# CONFIG_TOUCHSCREEN_FUJITSU is not set
+# CONFIG_TOUCHSCREEN_GUNZE is not set
+# CONFIG_TOUCHSCREEN_ELO is not set
+# CONFIG_TOUCHSCREEN_WACOM_W8001 is not set
+# CONFIG_TOUCHSCREEN_MCS5000 is not set
+# CONFIG_TOUCHSCREEN_MTOUCH is not set
+# CONFIG_TOUCHSCREEN_INEXIO is not set
+# CONFIG_TOUCHSCREEN_MK712 is not set
+# CONFIG_TOUCHSCREEN_PENMOUNT is not set
+# CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set
+# CONFIG_TOUCHSCREEN_TOUCHWIN is not set
+# CONFIG_TOUCHSCREEN_USB_COMPOSITE is not set
+# CONFIG_TOUCHSCREEN_TOUCHIT213 is not set
+# CONFIG_TOUCHSCREEN_TSC2007 is not set
+# CONFIG_TOUCHSCREEN_W90X900 is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_CONSOLE_TRANSLATIONS=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
+CONFIG_DEVKMEM=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=32
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+CONFIG_SERIAL_8250_EXTENDED=y
+CONFIG_SERIAL_8250_MANY_PORTS=y
+CONFIG_SERIAL_8250_SHARE_IRQ=y
+CONFIG_SERIAL_8250_DETECT_IRQ=y
+CONFIG_SERIAL_8250_RSA=y
+
+#
+# Non-8250 serial port support
+#
+# CONFIG_SERIAL_MAX3100 is not set
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_IPMI_HANDLER is not set
+CONFIG_HW_RANDOM=y
+# CONFIG_HW_RANDOM_TIMERIOMEM is not set
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+CONFIG_I2C=y
+CONFIG_I2C_BOARDINFO=y
+CONFIG_I2C_COMPAT=y
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_HELPER_AUTO=y
+
+#
+# I2C Hardware Bus support
+#
+
+#
+# I2C system bus drivers (mostly embedded / system-on-chip)
+#
+# CONFIG_I2C_DESIGNWARE is not set
+# CONFIG_I2C_GPIO is not set
+# CONFIG_I2C_OCORES is not set
+CONFIG_I2C_OMAP=y
+# CONFIG_I2C_SIMTEC is not set
+
+#
+# External I2C/SMBus adapter drivers
+#
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_TAOS_EVM is not set
+# CONFIG_I2C_TINY_USB is not set
+
+#
+# Other I2C/SMBus bus drivers
+#
+# CONFIG_I2C_PCA_PLATFORM is not set
+# CONFIG_I2C_STUB is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_DS1682 is not set
+# CONFIG_SENSORS_TSL2550 is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+CONFIG_SPI=y
+# CONFIG_SPI_DEBUG is not set
+CONFIG_SPI_MASTER=y
+
+#
+# SPI Master Controller Drivers
+#
+# CONFIG_SPI_BITBANG is not set
+# CONFIG_SPI_GPIO is not set
+CONFIG_SPI_OMAP24XX=y
+
+#
+# SPI Protocol Masters
+#
+# CONFIG_SPI_SPIDEV is not set
+# CONFIG_SPI_TLE62X0 is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
+CONFIG_ARCH_REQUIRE_GPIOLIB=y
+CONFIG_GPIOLIB=y
+# CONFIG_DEBUG_GPIO is not set
+# CONFIG_GPIO_SYSFS is not set
+
+#
+# Memory mapped GPIO expanders:
+#
+
+#
+# I2C GPIO expanders:
+#
+# CONFIG_GPIO_MAX732X is not set
+# CONFIG_GPIO_PCA953X is not set
+# CONFIG_GPIO_PCF857X is not set
+CONFIG_GPIO_TWL4030=y
+
+#
+# PCI GPIO expanders:
+#
+
+#
+# SPI GPIO expanders:
+#
+# CONFIG_GPIO_MAX7301 is not set
+# CONFIG_GPIO_MCP23S08 is not set
+# CONFIG_GPIO_MC33880 is not set
+
+#
+# AC97 GPIO expanders:
+#
+CONFIG_W1=y
+CONFIG_W1_CON=y
+
+#
+# 1-wire Bus Masters
+#
+# CONFIG_W1_MASTER_DS2490 is not set
+# CONFIG_W1_MASTER_DS2482 is not set
+# CONFIG_W1_MASTER_DS1WM is not set
+# CONFIG_W1_MASTER_GPIO is not set
+# CONFIG_HDQ_MASTER_OMAP is not set
+
+#
+# 1-wire Slaves
+#
+# CONFIG_W1_SLAVE_THERM is not set
+# CONFIG_W1_SLAVE_SMEM is not set
+# CONFIG_W1_SLAVE_DS2431 is not set
+# CONFIG_W1_SLAVE_DS2433 is not set
+# CONFIG_W1_SLAVE_DS2760 is not set
+# CONFIG_W1_SLAVE_BQ27000 is not set
+CONFIG_POWER_SUPPLY=y
+# CONFIG_POWER_SUPPLY_DEBUG is not set
+# CONFIG_PDA_POWER is not set
+# CONFIG_BATTERY_DS2760 is not set
+# CONFIG_BATTERY_DS2782 is not set
+# CONFIG_BATTERY_BQ27x00 is not set
+# CONFIG_BATTERY_MAX17040 is not set
+# CONFIG_HWMON is not set
+# CONFIG_THERMAL is not set
+CONFIG_WATCHDOG=y
+CONFIG_WATCHDOG_NOWAYOUT=y
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+# CONFIG_OMAP_WATCHDOG is not set
+# CONFIG_TWL4030_WATCHDOG is not set
+
+#
+# USB-based Watchdog Cards
+#
+# CONFIG_USBPCWATCHDOG is not set
+CONFIG_SSB_POSSIBLE=y
+
+#
+# Sonics Silicon Backplane
+#
+# CONFIG_SSB is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_CORE is not set
+# CONFIG_MFD_SM501 is not set
+# CONFIG_MFD_ASIC3 is not set
+# CONFIG_HTC_EGPIO is not set
+# CONFIG_HTC_PASIC3 is not set
+# CONFIG_TPS65010 is not set
+CONFIG_TWL4030_CORE=y
+# CONFIG_TWL4030_POWER is not set
+# CONFIG_MFD_TMIO is not set
+# CONFIG_MFD_T7L66XB is not set
+# CONFIG_MFD_TC6387XB is not set
+# CONFIG_MFD_TC6393XB is not set
+# CONFIG_PMIC_DA903X is not set
+# CONFIG_MFD_WM8400 is not set
+# CONFIG_MFD_WM831X is not set
+# CONFIG_MFD_WM8350_I2C is not set
+# CONFIG_MFD_PCF50633 is not set
+# CONFIG_MFD_MC13783 is not set
+# CONFIG_AB3100_CORE is not set
+# CONFIG_EZX_PCAP is not set
+CONFIG_REGULATOR=y
+# CONFIG_REGULATOR_DEBUG is not set
+# CONFIG_REGULATOR_FIXED_VOLTAGE is not set
+# CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set
+# CONFIG_REGULATOR_USERSPACE_CONSUMER is not set
+# CONFIG_REGULATOR_BQ24022 is not set
+# CONFIG_REGULATOR_MAX1586 is not set
+CONFIG_REGULATOR_TWL4030=y
+# CONFIG_REGULATOR_LP3971 is not set
+# CONFIG_REGULATOR_TPS65023 is not set
+# CONFIG_REGULATOR_TPS6507X is not set
+# CONFIG_MEDIA_SUPPORT is not set
+
+#
+# Graphics support
+#
+# CONFIG_VGASTATE is not set
+CONFIG_VIDEO_OUTPUT_CONTROL=m
+# CONFIG_FB is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_SOUND=y
+# CONFIG_SOUND_OSS_CORE is not set
+CONFIG_SND=y
+CONFIG_SND_TIMER=m
+CONFIG_SND_PCM=m
+# CONFIG_SND_SEQUENCER is not set
+# CONFIG_SND_MIXER_OSS is not set
+# CONFIG_SND_PCM_OSS is not set
+# CONFIG_SND_HRTIMER is not set
+# CONFIG_SND_DYNAMIC_MINORS is not set
+CONFIG_SND_SUPPORT_OLD_API=y
+CONFIG_SND_VERBOSE_PROCFS=y
+# CONFIG_SND_VERBOSE_PRINTK is not set
+# CONFIG_SND_DEBUG is not set
+# CONFIG_SND_RAWMIDI_SEQ is not set
+# CONFIG_SND_OPL3_LIB_SEQ is not set
+# CONFIG_SND_OPL4_LIB_SEQ is not set
+# CONFIG_SND_SBAWE_SEQ is not set
+# CONFIG_SND_EMU10K1_SEQ is not set
+CONFIG_SND_DRIVERS=y
+# CONFIG_SND_DUMMY is not set
+# CONFIG_SND_MTPAV is not set
+# CONFIG_SND_SERIAL_U16550 is not set
+# CONFIG_SND_MPU401 is not set
+CONFIG_SND_ARM=y
+CONFIG_SND_SPI=y
+CONFIG_SND_USB=y
+# CONFIG_SND_USB_AUDIO is not set
+# CONFIG_SND_USB_CAIAQ is not set
+# CONFIG_SND_SOC is not set
+# CONFIG_SOUND_PRIME is not set
+CONFIG_HID_SUPPORT=y
+CONFIG_HID=y
+# CONFIG_HIDRAW is not set
+
+#
+# USB Input Devices
+#
+CONFIG_USB_HID=y
+# CONFIG_HID_PID is not set
+# CONFIG_USB_HIDDEV is not set
+
+#
+# Special HID drivers
+#
+# CONFIG_HID_A4TECH is not set
+# CONFIG_HID_APPLE is not set
+# CONFIG_HID_BELKIN is not set
+# CONFIG_HID_CHERRY is not set
+# CONFIG_HID_CHICONY is not set
+# CONFIG_HID_CYPRESS is not set
+# CONFIG_HID_DRAGONRISE is not set
+# CONFIG_HID_EZKEY is not set
+# CONFIG_HID_KYE is not set
+# CONFIG_HID_GYRATION is not set
+# CONFIG_HID_TWINHAN is not set
+# CONFIG_HID_KENSINGTON is not set
+# CONFIG_HID_LOGITECH is not set
+# CONFIG_HID_MICROSOFT is not set
+# CONFIG_HID_MONTEREY is not set
+# CONFIG_HID_NTRIG is not set
+# CONFIG_HID_PANTHERLORD is not set
+# CONFIG_HID_PETALYNX is not set
+# CONFIG_HID_SAMSUNG is not set
+# CONFIG_HID_SONY is not set
+# CONFIG_HID_SUNPLUS is not set
+# CONFIG_HID_GREENASIA is not set
+# CONFIG_HID_SMARTJOYPLUS is not set
+# CONFIG_HID_TOPSEED is not set
+# CONFIG_HID_THRUSTMASTER is not set
+# CONFIG_HID_ZEROPLUS is not set
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+CONFIG_USB_ARCH_HAS_EHCI=y
+CONFIG_USB=y
+CONFIG_USB_DEBUG=y
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+# CONFIG_USB_DEVICE_CLASS is not set
+# CONFIG_USB_DYNAMIC_MINORS is not set
+CONFIG_USB_SUSPEND=y
+CONFIG_USB_OTG=y
+# CONFIG_USB_OTG_WHITELIST is not set
+# CONFIG_USB_OTG_BLACKLIST_HUB is not set
+CONFIG_USB_MON=y
+# CONFIG_USB_WUSB is not set
+# CONFIG_USB_WUSB_CBAF is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_C67X00_HCD is not set
+# CONFIG_USB_EHCI_HCD is not set
+# CONFIG_USB_OXU210HP_HCD is not set
+# CONFIG_USB_ISP116X_HCD is not set
+# CONFIG_USB_ISP1760_HCD is not set
+# CONFIG_USB_ISP1362_HCD is not set
+# CONFIG_USB_OHCI_HCD is not set
+# CONFIG_USB_SL811_HCD is not set
+# CONFIG_USB_R8A66597_HCD is not set
+# CONFIG_USB_HWA_HCD is not set
+CONFIG_USB_MUSB_HDRC=y
+CONFIG_USB_MUSB_SOC=y
+
+#
+# OMAP 343x high speed USB support
+#
+# CONFIG_USB_MUSB_HOST is not set
+# CONFIG_USB_MUSB_PERIPHERAL is not set
+CONFIG_USB_MUSB_OTG=y
+CONFIG_USB_GADGET_MUSB_HDRC=y
+CONFIG_USB_MUSB_HDRC_HCD=y
+# CONFIG_MUSB_PIO_ONLY is not set
+CONFIG_USB_INVENTRA_DMA=y
+# CONFIG_USB_TI_CPPI_DMA is not set
+CONFIG_USB_MUSB_DEBUG=y
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+# CONFIG_USB_WDM is not set
+# CONFIG_USB_TMC is not set
+
+#
+# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may
+#
+
+#
+# also be needed; see USB_STORAGE Help for more info
+#
+CONFIG_USB_STORAGE=y
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_ISD200 is not set
+# CONFIG_USB_STORAGE_USBAT is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_SDDR55 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_STORAGE_ALAUDA is not set
+# CONFIG_USB_STORAGE_ONETOUCH is not set
+# CONFIG_USB_STORAGE_KARMA is not set
+# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set
+# CONFIG_USB_LIBUSUAL is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+
+#
+# USB port drivers
+#
+# CONFIG_USB_SERIAL is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_ADUTUX is not set
+# CONFIG_USB_SEVSEG is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_BERRY_CHARGE is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYPRESS_CY7C63 is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_FTDI_ELAN is not set
+# CONFIG_USB_APPLEDISPLAY is not set
+# CONFIG_USB_SISUSBVGA is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
+# CONFIG_USB_IOWARRIOR is not set
+CONFIG_USB_TEST=m
+# CONFIG_USB_ISIGHTFW is not set
+# CONFIG_USB_VST is not set
+CONFIG_USB_GADGET=m
+CONFIG_USB_GADGET_DEBUG=y
+CONFIG_USB_GADGET_DEBUG_FILES=y
+CONFIG_USB_GADGET_VBUS_DRAW=2
+CONFIG_USB_GADGET_SELECTED=y
+# CONFIG_USB_GADGET_AT91 is not set
+# CONFIG_USB_GADGET_ATMEL_USBA is not set
+# CONFIG_USB_GADGET_FSL_USB2 is not set
+# CONFIG_USB_GADGET_LH7A40X is not set
+# CONFIG_USB_GADGET_OMAP is not set
+# CONFIG_USB_GADGET_PXA25X is not set
+# CONFIG_USB_GADGET_R8A66597 is not set
+# CONFIG_USB_GADGET_PXA27X is not set
+# CONFIG_USB_GADGET_S3C_HSOTG is not set
+# CONFIG_USB_GADGET_IMX is not set
+# CONFIG_USB_GADGET_S3C2410 is not set
+# CONFIG_USB_GADGET_M66592 is not set
+# CONFIG_USB_GADGET_AMD5536UDC is not set
+# CONFIG_USB_GADGET_FSL_QE is not set
+# CONFIG_USB_GADGET_CI13XXX is not set
+# CONFIG_USB_GADGET_NET2280 is not set
+# CONFIG_USB_GADGET_GOKU is not set
+# CONFIG_USB_GADGET_LANGWELL is not set
+# CONFIG_USB_GADGET_DUMMY_HCD is not set
+CONFIG_USB_GADGET_DUALSPEED=y
+CONFIG_USB_ZERO=m
+# CONFIG_USB_ZERO_HNPTEST is not set
+CONFIG_USB_AUDIO=m
+CONFIG_USB_ETH=m
+CONFIG_USB_ETH_RNDIS=y
+# CONFIG_USB_ETH_EEM is not set
+CONFIG_USB_GADGETFS=m
+CONFIG_USB_FILE_STORAGE=m
+# CONFIG_USB_FILE_STORAGE_TEST is not set
+CONFIG_USB_G_SERIAL=m
+# CONFIG_USB_MIDI_GADGET is not set
+# CONFIG_USB_G_PRINTER is not set
+CONFIG_USB_CDC_COMPOSITE=m
+
+#
+# OTG and related infrastructure
+#
+CONFIG_USB_OTG_UTILS=y
+# CONFIG_USB_GPIO_VBUS is not set
+# CONFIG_ISP1301_OMAP is not set
+CONFIG_TWL4030_USB=y
+# CONFIG_NOP_USB_XCEIV is not set
+CONFIG_MMC=y
+# CONFIG_MMC_DEBUG is not set
+# CONFIG_MMC_UNSAFE_RESUME is not set
+
+#
+# MMC/SD/SDIO Card Drivers
+#
+CONFIG_MMC_BLOCK=y
+CONFIG_MMC_BLOCK_BOUNCE=y
+# CONFIG_SDIO_UART is not set
+# CONFIG_MMC_TEST is not set
+
+#
+# MMC/SD/SDIO Host Controller Drivers
+#
+# CONFIG_MMC_SDHCI is not set
+# CONFIG_MMC_OMAP is not set
+CONFIG_MMC_OMAP_HS=y
+# CONFIG_MMC_AT91 is not set
+# CONFIG_MMC_ATMELMCI is not set
+# CONFIG_MMC_SPI is not set
+# CONFIG_MEMSTICK is not set
+# CONFIG_NEW_LEDS is not set
+# CONFIG_ACCESSIBILITY is not set
+CONFIG_RTC_LIB=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_HCTOSYS=y
+CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
+# CONFIG_RTC_DEBUG is not set
+
+#
+# RTC interfaces
+#
+CONFIG_RTC_INTF_SYSFS=y
+CONFIG_RTC_INTF_PROC=y
+CONFIG_RTC_INTF_DEV=y
+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+# CONFIG_RTC_DRV_TEST is not set
+
+#
+# I2C RTC drivers
+#
+# CONFIG_RTC_DRV_DS1307 is not set
+# CONFIG_RTC_DRV_DS1374 is not set
+# CONFIG_RTC_DRV_DS1672 is not set
+# CONFIG_RTC_DRV_MAX6900 is not set
+# CONFIG_RTC_DRV_RS5C372 is not set
+# CONFIG_RTC_DRV_ISL1208 is not set
+# CONFIG_RTC_DRV_X1205 is not set
+# CONFIG_RTC_DRV_PCF8563 is not set
+# CONFIG_RTC_DRV_PCF8583 is not set
+# CONFIG_RTC_DRV_M41T80 is not set
+# CONFIG_RTC_DRV_TWL4030 is not set
+# CONFIG_RTC_DRV_S35390A is not set
+# CONFIG_RTC_DRV_FM3130 is not set
+# CONFIG_RTC_DRV_RX8581 is not set
+# CONFIG_RTC_DRV_RX8025 is not set
+
+#
+# SPI RTC drivers
+#
+# CONFIG_RTC_DRV_M41T94 is not set
+# CONFIG_RTC_DRV_DS1305 is not set
+# CONFIG_RTC_DRV_DS1390 is not set
+# CONFIG_RTC_DRV_MAX6902 is not set
+# CONFIG_RTC_DRV_R9701 is not set
+# CONFIG_RTC_DRV_RS5C348 is not set
+# CONFIG_RTC_DRV_DS3234 is not set
+# CONFIG_RTC_DRV_PCF2123 is not set
+
+#
+# Platform RTC drivers
+#
+# CONFIG_RTC_DRV_CMOS is not set
+# CONFIG_RTC_DRV_DS1286 is not set
+# CONFIG_RTC_DRV_DS1511 is not set
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+# CONFIG_RTC_DRV_STK17TA8 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_M48T35 is not set
+# CONFIG_RTC_DRV_M48T59 is not set
+# CONFIG_RTC_DRV_BQ4802 is not set
+# CONFIG_RTC_DRV_V3020 is not set
+
+#
+# on-CPU RTC drivers
+#
+# CONFIG_DMADEVICES is not set
+# CONFIG_AUXDISPLAY is not set
+# CONFIG_UIO is not set
+
+#
+# TI VLYNQ
+#
+# CONFIG_STAGING is not set
+
+#
+# CBUS support
+#
+# CONFIG_CBUS is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
+# CONFIG_EXT3_FS_XATTR is not set
+# CONFIG_EXT4_FS is not set
+CONFIG_JBD=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+CONFIG_FS_POSIX_ACL=y
+# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_BTRFS_FS is not set
+# CONFIG_NILFS2_FS is not set
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
+CONFIG_DNOTIFY=y
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+CONFIG_QUOTA=y
+# CONFIG_QUOTA_NETLINK_INTERFACE is not set
+CONFIG_PRINT_QUOTA_WARNING=y
+CONFIG_QUOTA_TREE=y
+# CONFIG_QFMT_V1 is not set
+CONFIG_QFMT_V2=y
+CONFIG_QUOTACTL=y
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# Caches
+#
+# CONFIG_FSCACHE is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLB_PAGE is not set
+# CONFIG_CONFIGFS_FS is not set
+CONFIG_MISC_FILESYSTEMS=y
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_SQUASHFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_OMFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+CONFIG_NETWORK_FILESYSTEMS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+CONFIG_NFS_V3_ACL=y
+CONFIG_NFS_V4=y
+# CONFIG_NFS_V4_1 is not set
+CONFIG_ROOT_NFS=y
+# CONFIG_NFSD is not set
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_ACL_SUPPORT=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+CONFIG_SUNRPC_GSS=y
+CONFIG_RPCSEC_GSS_KRB5=y
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_KARMA_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+# CONFIG_SYSV68_PARTITION is not set
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+CONFIG_NLS_ISO8859_1=y
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+# CONFIG_DLM is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_WARN_DEPRECATED=y
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_FRAME_WARN=1024
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_STRIP_ASM_SYMS is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SHIRQ is not set
+CONFIG_DETECT_SOFTLOCKUP=y
+# CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set
+CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0
+CONFIG_DETECT_HUNG_TASK=y
+# CONFIG_BOOTPARAM_HUNG_TASK_PANIC is not set
+CONFIG_BOOTPARAM_HUNG_TASK_PANIC_VALUE=0
+CONFIG_SCHED_DEBUG=y
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_TIMER_STATS is not set
+# CONFIG_DEBUG_OBJECTS is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_KMEMLEAK is not set
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+CONFIG_DEBUG_MUTEXES=y
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_LOCK_STAT is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_DEBUG_KOBJECT is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+CONFIG_DEBUG_INFO=y
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_WRITECOUNT is not set
+# CONFIG_DEBUG_MEMORY_INIT is not set
+# CONFIG_DEBUG_LIST is not set
+# CONFIG_DEBUG_SG is not set
+# CONFIG_DEBUG_NOTIFIERS is not set
+# CONFIG_DEBUG_CREDENTIALS is not set
+# CONFIG_BOOT_PRINTK_DELAY is not set
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_RCU_CPU_STALL_DETECTOR is not set
+# CONFIG_BACKTRACE_SELF_TEST is not set
+# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
+# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
+# CONFIG_FAULT_INJECTION is not set
+# CONFIG_LATENCYTOP is not set
+# CONFIG_PAGE_POISONING is not set
+CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_TRACING_SUPPORT=y
+CONFIG_FTRACE=y
+# CONFIG_FUNCTION_TRACER is not set
+# CONFIG_IRQSOFF_TRACER is not set
+# CONFIG_SCHED_TRACER is not set
+# CONFIG_ENABLE_DEFAULT_TRACERS is not set
+# CONFIG_BOOT_TRACER is not set
+CONFIG_BRANCH_PROFILE_NONE=y
+# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set
+# CONFIG_PROFILE_ALL_BRANCHES is not set
+# CONFIG_STACK_TRACER is not set
+# CONFIG_KMEMTRACE is not set
+# CONFIG_WORKQUEUE_TRACER is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_SAMPLES is not set
+CONFIG_HAVE_ARCH_KGDB=y
+# CONFIG_KGDB is not set
+CONFIG_ARM_UNWIND=y
+# CONFIG_DEBUG_USER is not set
+# CONFIG_DEBUG_ERRORS is not set
+# CONFIG_DEBUG_STACK_USAGE is not set
+CONFIG_DEBUG_LL=y
+# CONFIG_DEBUG_ICEDCC is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+# CONFIG_SECURITYFS is not set
+# CONFIG_SECURITY_FILE_CAPABILITIES is not set
+CONFIG_CRYPTO=y
+
+#
+# Crypto core or helper
+#
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_ALGAPI2=y
+CONFIG_CRYPTO_AEAD2=y
+CONFIG_CRYPTO_BLKCIPHER=y
+CONFIG_CRYPTO_BLKCIPHER2=y
+CONFIG_CRYPTO_HASH=y
+CONFIG_CRYPTO_HASH2=y
+CONFIG_CRYPTO_RNG2=y
+CONFIG_CRYPTO_PCOMP=y
+CONFIG_CRYPTO_MANAGER=y
+CONFIG_CRYPTO_MANAGER2=y
+# CONFIG_CRYPTO_GF128MUL is not set
+# CONFIG_CRYPTO_NULL is not set
+CONFIG_CRYPTO_WORKQUEUE=y
+# CONFIG_CRYPTO_CRYPTD is not set
+# CONFIG_CRYPTO_AUTHENC is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Authenticated Encryption with Associated Data
+#
+# CONFIG_CRYPTO_CCM is not set
+# CONFIG_CRYPTO_GCM is not set
+# CONFIG_CRYPTO_SEQIV is not set
+
+#
+# Block modes
+#
+CONFIG_CRYPTO_CBC=y
+# CONFIG_CRYPTO_CTR is not set
+# CONFIG_CRYPTO_CTS is not set
+CONFIG_CRYPTO_ECB=m
+# CONFIG_CRYPTO_LRW is not set
+CONFIG_CRYPTO_PCBC=m
+# CONFIG_CRYPTO_XTS is not set
+
+#
+# Hash modes
+#
+# CONFIG_CRYPTO_HMAC is not set
+# CONFIG_CRYPTO_XCBC is not set
+# CONFIG_CRYPTO_VMAC is not set
+
+#
+# Digest
+#
+CONFIG_CRYPTO_CRC32C=y
+# CONFIG_CRYPTO_GHASH is not set
+# CONFIG_CRYPTO_MD4 is not set
+CONFIG_CRYPTO_MD5=y
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_RMD128 is not set
+# CONFIG_CRYPTO_RMD160 is not set
+# CONFIG_CRYPTO_RMD256 is not set
+# CONFIG_CRYPTO_RMD320 is not set
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_WP512 is not set
+
+#
+# Ciphers
+#
+# CONFIG_CRYPTO_AES is not set
+# CONFIG_CRYPTO_ANUBIS is not set
+# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_CAMELLIA is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+CONFIG_CRYPTO_DES=y
+# CONFIG_CRYPTO_FCRYPT is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_SALSA20 is not set
+# CONFIG_CRYPTO_SEED is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+
+#
+# Compression
+#
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_ZLIB is not set
+# CONFIG_CRYPTO_LZO is not set
+
+#
+# Random Number Generation
+#
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
+CONFIG_CRYPTO_HW=y
+# CONFIG_BINARY_PRINTF is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+CONFIG_GENERIC_FIND_LAST_BIT=y
+CONFIG_CRC_CCITT=y
+# CONFIG_CRC16 is not set
+CONFIG_CRC_T10DIF=y
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+CONFIG_LIBCRC32C=y
+CONFIG_ZLIB_INFLATE=y
+CONFIG_DECOMPRESS_GZIP=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
+CONFIG_NLATTR=y
index 23e43ea..a464ca3 100644 (file)
@@ -52,8 +52,8 @@ CONFIG_FAIR_GROUP_SCHED=y
 CONFIG_USER_SCHED=y
 # CONFIG_CGROUP_SCHED is not set
 # CONFIG_CGROUPS is not set
-CONFIG_SYSFS_DEPRECATED=y
-CONFIG_SYSFS_DEPRECATED_V2=y
+# CONFIG_SYSFS_DEPRECATED=y is not set
+# CONFIG_SYSFS_DEPRECATED_V2=y is not set
 # CONFIG_RELAY is not set
 # CONFIG_NAMESPACES is not set
 CONFIG_BLK_DEV_INITRD=y
index b9c4891..9139532 100644 (file)
@@ -49,8 +49,8 @@ CONFIG_FAIR_GROUP_SCHED=y
 # CONFIG_RT_GROUP_SCHED is not set
 CONFIG_USER_SCHED=y
 # CONFIG_CGROUP_SCHED is not set
-CONFIG_SYSFS_DEPRECATED=y
-CONFIG_SYSFS_DEPRECATED_V2=y
+# CONFIG_SYSFS_DEPRECATED=y is not set
+# CONFIG_SYSFS_DEPRECATED_V2=y is not set
 # CONFIG_RELAY is not set
 # CONFIG_NAMESPACES is not set
 CONFIG_BLK_DEV_INITRD=y
index f1739fa..eef9362 100644 (file)
@@ -59,8 +59,8 @@ CONFIG_FAIR_GROUP_SCHED=y
 CONFIG_USER_SCHED=y
 # CONFIG_CGROUP_SCHED is not set
 # CONFIG_CGROUPS is not set
-CONFIG_SYSFS_DEPRECATED=y
-CONFIG_SYSFS_DEPRECATED_V2=y
+# CONFIG_SYSFS_DEPRECATED=y is not set
+# CONFIG_SYSFS_DEPRECATED_V2=y is not set
 # CONFIG_RELAY is not set
 # CONFIG_NAMESPACES is not set
 CONFIG_BLK_DEV_INITRD=y
@@ -202,7 +202,8 @@ CONFIG_OMAP_32K_TIMER_HZ=128
 CONFIG_OMAP_DM_TIMER=y
 # CONFIG_OMAP_LL_DEBUG_UART1 is not set
 # CONFIG_OMAP_LL_DEBUG_UART2 is not set
-CONFIG_OMAP_LL_DEBUG_UART3=y
+# CONFIG_OMAP_LL_DEBUG_UART3 is not set
+CONFIG_OMAP_LL_DEBUG_NONE=y
 CONFIG_ARCH_OMAP34XX=y
 CONFIG_ARCH_OMAP3430=y
 
diff --git a/arch/arm/configs/omap_zoom3_defconfig b/arch/arm/configs/omap_zoom3_defconfig
new file mode 100644 (file)
index 0000000..f0e7d0f
--- /dev/null
@@ -0,0 +1,1610 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.32-rc6
+# Thu Nov 12 13:04:07 2009
+#
+CONFIG_ARM=y
+CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+CONFIG_GENERIC_GPIO=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_ARCH_HAS_CPUFREQ=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
+CONFIG_VECTORS_BASE=0xffff0000
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+# CONFIG_POSIX_MQUEUE is not set
+CONFIG_BSD_PROCESS_ACCT=y
+# CONFIG_BSD_PROCESS_ACCT_V3 is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_AUDIT is not set
+
+#
+# RCU Subsystem
+#
+CONFIG_TREE_RCU=y
+# CONFIG_TREE_PREEMPT_RCU is not set
+# CONFIG_RCU_TRACE is not set
+CONFIG_RCU_FANOUT=32
+# CONFIG_RCU_FANOUT_EXACT is not set
+# CONFIG_TREE_RCU_TRACE is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_GROUP_SCHED=y
+CONFIG_FAIR_GROUP_SCHED=y
+# CONFIG_RT_GROUP_SCHED is not set
+CONFIG_USER_SCHED=y
+# CONFIG_CGROUP_SCHED is not set
+# CONFIG_CGROUPS is not set
+# CONFIG_SYSFS_DEPRECATED_V2 is not set
+# CONFIG_RELAY is not set
+# CONFIG_NAMESPACES is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_RD_GZIP=y
+# CONFIG_RD_BZIP2 is not set
+# CONFIG_RD_LZMA is not set
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+CONFIG_ANON_INODES=y
+CONFIG_EMBEDDED=y
+CONFIG_UID16=y
+# CONFIG_SYSCTL_SYSCALL is not set
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+CONFIG_KALLSYMS_EXTRA_PASS=y
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_AIO=y
+
+#
+# Kernel Performance Events And Counters
+#
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_COMPAT_BRK=y
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
+# CONFIG_PROFILING is not set
+CONFIG_HAVE_OPROFILE=y
+# CONFIG_KPROBES is not set
+CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_KRETPROBES=y
+CONFIG_HAVE_CLK=y
+
+#
+# GCOV-based kernel profiling
+#
+# CONFIG_SLOW_WORK is not set
+CONFIG_HAVE_GENERIC_DMA_COHERENT=y
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+# CONFIG_MODULE_FORCE_LOAD is not set
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+CONFIG_MODVERSIONS=y
+CONFIG_MODULE_SRCVERSION_ALL=y
+CONFIG_BLOCK=y
+CONFIG_LBDAF=y
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_BLK_DEV_INTEGRITY is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+CONFIG_DEFAULT_AS=y
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="anticipatory"
+CONFIG_FREEZER=y
+
+#
+# System Type
+#
+CONFIG_MMU=y
+# CONFIG_ARCH_AAEC2000 is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_REALVIEW is not set
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_AT91 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_GEMINI is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_EP93XX is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_MXC is not set
+# CONFIG_ARCH_STMP3XXX is not set
+# CONFIG_ARCH_NETX is not set
+# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_NOMADIK is not set
+# CONFIG_ARCH_IOP13XX is not set
+# CONFIG_ARCH_IOP32X is not set
+# CONFIG_ARCH_IOP33X is not set
+# CONFIG_ARCH_IXP23XX is not set
+# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_KIRKWOOD is not set
+# CONFIG_ARCH_LOKI is not set
+# CONFIG_ARCH_MV78XX0 is not set
+# CONFIG_ARCH_ORION5X is not set
+# CONFIG_ARCH_MMP is not set
+# CONFIG_ARCH_KS8695 is not set
+# CONFIG_ARCH_NS9XXX is not set
+# CONFIG_ARCH_W90X900 is not set
+# CONFIG_ARCH_PNX4008 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_MSM is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_S3C64XX is not set
+# CONFIG_ARCH_S5PC1XX is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_U300 is not set
+# CONFIG_ARCH_DAVINCI is not set
+CONFIG_ARCH_OMAP=y
+# CONFIG_ARCH_BCMRING is not set
+
+#
+# TI OMAP Implementations
+#
+CONFIG_ARCH_OMAP_OTG=y
+# CONFIG_ARCH_OMAP1 is not set
+# CONFIG_ARCH_OMAP2 is not set
+CONFIG_ARCH_OMAP3=y
+# CONFIG_ARCH_OMAP4 is not set
+
+#
+# OMAP Feature Selections
+#
+# CONFIG_OMAP_DEBUG_POWERDOMAIN is not set
+# CONFIG_OMAP_DEBUG_CLOCKDOMAIN is not set
+# CONFIG_OMAP_RESET_CLOCKS is not set
+CONFIG_OMAP_MUX=y
+CONFIG_OMAP_MUX_DEBUG=y
+CONFIG_OMAP_MUX_WARNINGS=y
+CONFIG_OMAP_MCBSP=y
+# CONFIG_OMAP_MBOX_FWK is not set
+# CONFIG_OMAP_MPU_TIMER is not set
+CONFIG_OMAP_32K_TIMER=y
+CONFIG_OMAP_32K_TIMER_HZ=128
+CONFIG_OMAP_DM_TIMER=y
+# CONFIG_OMAP_LL_DEBUG_UART1 is not set
+# CONFIG_OMAP_LL_DEBUG_UART2 is not set
+# CONFIG_OMAP_LL_DEBUG_UART3 is not set
+CONFIG_OMAP_LL_DEBUG_NONE=y
+# CONFIG_OMAP_PM_NONE is not set
+CONFIG_OMAP_PM_NOOP=y
+CONFIG_ARCH_OMAP34XX=y
+CONFIG_ARCH_OMAP3430=y
+
+#
+# OMAP Board Type
+#
+# CONFIG_MACH_OMAP3_BEAGLE is not set
+# CONFIG_MACH_OMAP_LDP is not set
+# CONFIG_MACH_OVERO is not set
+# CONFIG_MACH_OMAP3EVM is not set
+# CONFIG_MACH_OMAP3_PANDORA is not set
+# CONFIG_MACH_OMAP_3430SDP is not set
+# CONFIG_MACH_NOKIA_RX51 is not set
+# CONFIG_MACH_OMAP_ZOOM2 is not set
+# CONFIG_MACH_CM_T35 is not set
+CONFIG_MACH_OMAP_ZOOM3=y
+# CONFIG_MACH_OMAP_3630SDP is not set
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_32v6K=y
+CONFIG_CPU_V7=y
+CONFIG_CPU_32v7=y
+CONFIG_CPU_ABRT_EV7=y
+CONFIG_CPU_PABRT_V7=y
+CONFIG_CPU_CACHE_V7=y
+CONFIG_CPU_CACHE_VIPT=y
+CONFIG_CPU_COPY_V6=y
+CONFIG_CPU_TLB_V7=y
+CONFIG_CPU_HAS_ASID=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
+
+#
+# Processor Features
+#
+CONFIG_ARM_THUMB=y
+# CONFIG_ARM_THUMBEE is not set
+# CONFIG_CPU_ICACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_DISABLE is not set
+# CONFIG_CPU_BPREDICT_DISABLE is not set
+CONFIG_HAS_TLS_REG=y
+CONFIG_ARM_L1_CACHE_SHIFT=6
+# CONFIG_ARM_ERRATA_430973 is not set
+# CONFIG_ARM_ERRATA_458693 is not set
+# CONFIG_ARM_ERRATA_460075 is not set
+CONFIG_COMMON_CLKDEV=y
+
+#
+# Bus support
+#
+# CONFIG_PCI_SYSCALL is not set
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+CONFIG_TICK_ONESHOT=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+CONFIG_VMSPLIT_3G=y
+# CONFIG_VMSPLIT_2G is not set
+# CONFIG_VMSPLIT_1G is not set
+CONFIG_PAGE_OFFSET=0xC0000000
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+CONFIG_HZ=128
+# CONFIG_THUMB2_KERNEL is not set
+CONFIG_AEABI=y
+CONFIG_OABI_COMPAT=y
+# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set
+# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set
+# CONFIG_HIGHMEM is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+CONFIG_PAGEFLAGS_EXTENDED=y
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_PHYS_ADDR_T_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=0
+CONFIG_VIRT_TO_BUS=y
+CONFIG_HAVE_MLOCK=y
+CONFIG_HAVE_MLOCKED_PAGE_BIT=y
+# CONFIG_KSM is not set
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
+# CONFIG_LEDS is not set
+CONFIG_ALIGNMENT_TRAP=y
+# CONFIG_UACCESS_WITH_MEMCPY is not set
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="root=/dev/nfs nfsroot=192.168.0.1:/home/user/buildroot ip=192.168.0.2:192.168.0.1:192.168.0.1:255.255.255.0:tgt:eth0:off rw console=ttyS2,115200n8"
+# CONFIG_XIP_KERNEL is not set
+# CONFIG_KEXEC is not set
+
+#
+# CPU Power Management
+#
+# CONFIG_CPU_FREQ is not set
+# CONFIG_CPU_IDLE is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
+# CONFIG_FPE_FASTFPE is not set
+CONFIG_VFP=y
+CONFIG_VFPv3=y
+# CONFIG_NEON is not set
+
+#
+# Userspace binary formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_HAVE_AOUT=y
+# CONFIG_BINFMT_AOUT is not set
+CONFIG_BINFMT_MISC=y
+
+#
+# Power management options
+#
+CONFIG_PM=y
+CONFIG_PM_DEBUG=y
+CONFIG_PM_VERBOSE=y
+CONFIG_CAN_PM_TRACE=y
+CONFIG_PM_SLEEP=y
+CONFIG_SUSPEND=y
+# CONFIG_PM_TEST_SUSPEND is not set
+CONFIG_SUSPEND_FREEZER=y
+# CONFIG_APM_EMULATION is not set
+# CONFIG_PM_RUNTIME is not set
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+CONFIG_XFRM_USER=y
+# CONFIG_XFRM_SUB_POLICY is not set
+CONFIG_XFRM_MIGRATE=y
+# CONFIG_XFRM_STATISTICS is not set
+CONFIG_NET_KEY=y
+CONFIG_NET_KEY_MIGRATE=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+CONFIG_IP_PNP_RARP=y
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
+# CONFIG_INET_LRO is not set
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# CONFIG_RDS is not set
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_NET_DSA is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_PHONET is not set
+# CONFIG_IEEE802154 is not set
+# CONFIG_NET_SCHED is not set
+# CONFIG_DCB is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_CAN is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+# CONFIG_WIRELESS is not set
+# CONFIG_WIMAX is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+# CONFIG_DEVTMPFS is not set
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES is not set
+# CONFIG_SYS_HYPERVISOR is not set
+CONFIG_CONNECTOR=y
+CONFIG_PROC_EVENTS=y
+# CONFIG_MTD is not set
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_UB is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=16384
+# CONFIG_BLK_DEV_XIP is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+# CONFIG_MG_DISK is not set
+CONFIG_MISC_DEVICES=y
+# CONFIG_ICS932S401 is not set
+# CONFIG_ENCLOSURE_SERVICES is not set
+# CONFIG_ISL29003 is not set
+# CONFIG_C2PORT is not set
+
+#
+# EEPROM support
+#
+# CONFIG_EEPROM_AT24 is not set
+# CONFIG_EEPROM_AT25 is not set
+# CONFIG_EEPROM_LEGACY is not set
+# CONFIG_EEPROM_MAX6875 is not set
+# CONFIG_EEPROM_93CX6 is not set
+CONFIG_HAVE_IDE=y
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=y
+CONFIG_SCSI_DMA=y
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+# CONFIG_BLK_DEV_SR is not set
+# CONFIG_CHR_DEV_SG is not set
+# CONFIG_CHR_DEV_SCH is not set
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC is not set
+CONFIG_SCSI_WAIT_SCAN=m
+
+#
+# SCSI Transports
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+# CONFIG_SCSI_SRP_ATTRS is not set
+CONFIG_SCSI_LOWLEVEL=y
+# CONFIG_ISCSI_TCP is not set
+# CONFIG_LIBFC is not set
+# CONFIG_LIBFCOE is not set
+# CONFIG_SCSI_DEBUG is not set
+# CONFIG_SCSI_DH is not set
+# CONFIG_SCSI_OSD_INITIATOR is not set
+# CONFIG_ATA is not set
+# CONFIG_MD is not set
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_VETH is not set
+CONFIG_PHYLIB=y
+
+#
+# MII PHY device drivers
+#
+# CONFIG_MARVELL_PHY is not set
+# CONFIG_DAVICOM_PHY is not set
+# CONFIG_QSEMI_PHY is not set
+# CONFIG_LXT_PHY is not set
+# CONFIG_CICADA_PHY is not set
+# CONFIG_VITESSE_PHY is not set
+CONFIG_SMSC_PHY=y
+# CONFIG_BROADCOM_PHY is not set
+# CONFIG_ICPLUS_PHY is not set
+# CONFIG_REALTEK_PHY is not set
+# CONFIG_NATIONAL_PHY is not set
+# CONFIG_STE10XP is not set
+# CONFIG_LSI_ET1011C_PHY is not set
+# CONFIG_FIXED_PHY is not set
+# CONFIG_MDIO_BITBANG is not set
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_AX88796 is not set
+# CONFIG_SMC91X is not set
+# CONFIG_DM9000 is not set
+# CONFIG_ENC28J60 is not set
+# CONFIG_ETHOC is not set
+# CONFIG_SMC911X is not set
+CONFIG_SMSC911X=y
+# CONFIG_DNET is not set
+# CONFIG_IBM_NEW_EMAC_ZMII is not set
+# CONFIG_IBM_NEW_EMAC_RGMII is not set
+# CONFIG_IBM_NEW_EMAC_TAH is not set
+# CONFIG_IBM_NEW_EMAC_EMAC4 is not set
+# CONFIG_IBM_NEW_EMAC_NO_FLOW_CTRL is not set
+# CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT is not set
+# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
+# CONFIG_B44 is not set
+# CONFIG_KS8842 is not set
+# CONFIG_KS8851 is not set
+# CONFIG_KS8851_MLL is not set
+CONFIG_NETDEV_1000=y
+CONFIG_NETDEV_10000=y
+CONFIG_WLAN=y
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
+
+#
+# Enable WiMAX (Networking options) to see the WiMAX drivers
+#
+
+#
+# USB Network Adapters
+#
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RTL8150 is not set
+# CONFIG_USB_USBNET is not set
+# CONFIG_WAN is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_ISDN is not set
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
+
+#
+# Userland interfaces
+#
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_ADS7846=y
+# CONFIG_TOUCHSCREEN_AD7877 is not set
+# CONFIG_TOUCHSCREEN_AD7879_I2C is not set
+# CONFIG_TOUCHSCREEN_AD7879_SPI is not set
+# CONFIG_TOUCHSCREEN_AD7879 is not set
+# CONFIG_TOUCHSCREEN_EETI is not set
+# CONFIG_TOUCHSCREEN_FUJITSU is not set
+# CONFIG_TOUCHSCREEN_GUNZE is not set
+# CONFIG_TOUCHSCREEN_ELO is not set
+# CONFIG_TOUCHSCREEN_WACOM_W8001 is not set
+# CONFIG_TOUCHSCREEN_MCS5000 is not set
+# CONFIG_TOUCHSCREEN_MTOUCH is not set
+# CONFIG_TOUCHSCREEN_INEXIO is not set
+# CONFIG_TOUCHSCREEN_MK712 is not set
+# CONFIG_TOUCHSCREEN_PENMOUNT is not set
+# CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set
+# CONFIG_TOUCHSCREEN_TOUCHWIN is not set
+# CONFIG_TOUCHSCREEN_USB_COMPOSITE is not set
+# CONFIG_TOUCHSCREEN_TOUCHIT213 is not set
+# CONFIG_TOUCHSCREEN_TSC2007 is not set
+# CONFIG_TOUCHSCREEN_W90X900 is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_CONSOLE_TRANSLATIONS=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
+CONFIG_DEVKMEM=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=32
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+CONFIG_SERIAL_8250_EXTENDED=y
+CONFIG_SERIAL_8250_MANY_PORTS=y
+CONFIG_SERIAL_8250_SHARE_IRQ=y
+CONFIG_SERIAL_8250_DETECT_IRQ=y
+CONFIG_SERIAL_8250_RSA=y
+
+#
+# Non-8250 serial port support
+#
+# CONFIG_SERIAL_MAX3100 is not set
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_IPMI_HANDLER is not set
+CONFIG_HW_RANDOM=y
+# CONFIG_HW_RANDOM_TIMERIOMEM is not set
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+CONFIG_I2C=y
+CONFIG_I2C_BOARDINFO=y
+CONFIG_I2C_COMPAT=y
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_HELPER_AUTO=y
+
+#
+# I2C Hardware Bus support
+#
+
+#
+# I2C system bus drivers (mostly embedded / system-on-chip)
+#
+# CONFIG_I2C_DESIGNWARE is not set
+# CONFIG_I2C_GPIO is not set
+# CONFIG_I2C_OCORES is not set
+CONFIG_I2C_OMAP=y
+# CONFIG_I2C_SIMTEC is not set
+
+#
+# External I2C/SMBus adapter drivers
+#
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_TAOS_EVM is not set
+# CONFIG_I2C_TINY_USB is not set
+
+#
+# Other I2C/SMBus bus drivers
+#
+# CONFIG_I2C_PCA_PLATFORM is not set
+# CONFIG_I2C_STUB is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_DS1682 is not set
+# CONFIG_SENSORS_TSL2550 is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+CONFIG_SPI=y
+# CONFIG_SPI_DEBUG is not set
+CONFIG_SPI_MASTER=y
+
+#
+# SPI Master Controller Drivers
+#
+# CONFIG_SPI_BITBANG is not set
+# CONFIG_SPI_GPIO is not set
+CONFIG_SPI_OMAP24XX=y
+
+#
+# SPI Protocol Masters
+#
+# CONFIG_SPI_SPIDEV is not set
+# CONFIG_SPI_TLE62X0 is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
+CONFIG_ARCH_REQUIRE_GPIOLIB=y
+CONFIG_GPIOLIB=y
+# CONFIG_DEBUG_GPIO is not set
+# CONFIG_GPIO_SYSFS is not set
+
+#
+# Memory mapped GPIO expanders:
+#
+
+#
+# I2C GPIO expanders:
+#
+# CONFIG_GPIO_MAX732X is not set
+# CONFIG_GPIO_PCA953X is not set
+# CONFIG_GPIO_PCF857X is not set
+CONFIG_GPIO_TWL4030=y
+
+#
+# PCI GPIO expanders:
+#
+
+#
+# SPI GPIO expanders:
+#
+# CONFIG_GPIO_MAX7301 is not set
+# CONFIG_GPIO_MCP23S08 is not set
+# CONFIG_GPIO_MC33880 is not set
+
+#
+# AC97 GPIO expanders:
+#
+CONFIG_W1=y
+CONFIG_W1_CON=y
+
+#
+# 1-wire Bus Masters
+#
+# CONFIG_W1_MASTER_DS2490 is not set
+# CONFIG_W1_MASTER_DS2482 is not set
+# CONFIG_W1_MASTER_DS1WM is not set
+# CONFIG_W1_MASTER_GPIO is not set
+# CONFIG_HDQ_MASTER_OMAP is not set
+
+#
+# 1-wire Slaves
+#
+# CONFIG_W1_SLAVE_THERM is not set
+# CONFIG_W1_SLAVE_SMEM is not set
+# CONFIG_W1_SLAVE_DS2431 is not set
+# CONFIG_W1_SLAVE_DS2433 is not set
+# CONFIG_W1_SLAVE_DS2760 is not set
+# CONFIG_W1_SLAVE_BQ27000 is not set
+CONFIG_POWER_SUPPLY=y
+# CONFIG_POWER_SUPPLY_DEBUG is not set
+# CONFIG_PDA_POWER is not set
+# CONFIG_BATTERY_DS2760 is not set
+# CONFIG_BATTERY_DS2782 is not set
+# CONFIG_BATTERY_BQ27x00 is not set
+# CONFIG_BATTERY_MAX17040 is not set
+# CONFIG_HWMON is not set
+# CONFIG_THERMAL is not set
+CONFIG_WATCHDOG=y
+CONFIG_WATCHDOG_NOWAYOUT=y
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+# CONFIG_OMAP_WATCHDOG is not set
+# CONFIG_TWL4030_WATCHDOG is not set
+
+#
+# USB-based Watchdog Cards
+#
+# CONFIG_USBPCWATCHDOG is not set
+CONFIG_SSB_POSSIBLE=y
+
+#
+# Sonics Silicon Backplane
+#
+# CONFIG_SSB is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_CORE is not set
+# CONFIG_MFD_SM501 is not set
+# CONFIG_MFD_ASIC3 is not set
+# CONFIG_HTC_EGPIO is not set
+# CONFIG_HTC_PASIC3 is not set
+# CONFIG_TPS65010 is not set
+CONFIG_TWL4030_CORE=y
+# CONFIG_TWL4030_POWER is not set
+# CONFIG_MFD_TMIO is not set
+# CONFIG_MFD_T7L66XB is not set
+# CONFIG_MFD_TC6387XB is not set
+# CONFIG_MFD_TC6393XB is not set
+# CONFIG_PMIC_DA903X is not set
+# CONFIG_MFD_WM8400 is not set
+# CONFIG_MFD_WM831X is not set
+# CONFIG_MFD_WM8350_I2C is not set
+# CONFIG_MFD_PCF50633 is not set
+# CONFIG_MFD_MC13783 is not set
+# CONFIG_AB3100_CORE is not set
+# CONFIG_EZX_PCAP is not set
+CONFIG_REGULATOR=y
+# CONFIG_REGULATOR_DEBUG is not set
+# CONFIG_REGULATOR_FIXED_VOLTAGE is not set
+# CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set
+# CONFIG_REGULATOR_USERSPACE_CONSUMER is not set
+# CONFIG_REGULATOR_BQ24022 is not set
+# CONFIG_REGULATOR_MAX1586 is not set
+CONFIG_REGULATOR_TWL4030=y
+# CONFIG_REGULATOR_LP3971 is not set
+# CONFIG_REGULATOR_TPS65023 is not set
+# CONFIG_REGULATOR_TPS6507X is not set
+# CONFIG_MEDIA_SUPPORT is not set
+
+#
+# Graphics support
+#
+# CONFIG_VGASTATE is not set
+CONFIG_VIDEO_OUTPUT_CONTROL=m
+# CONFIG_FB is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_SOUND=y
+# CONFIG_SOUND_OSS_CORE is not set
+CONFIG_SND=y
+CONFIG_SND_TIMER=m
+CONFIG_SND_PCM=m
+# CONFIG_SND_SEQUENCER is not set
+# CONFIG_SND_MIXER_OSS is not set
+# CONFIG_SND_PCM_OSS is not set
+# CONFIG_SND_HRTIMER is not set
+# CONFIG_SND_DYNAMIC_MINORS is not set
+CONFIG_SND_SUPPORT_OLD_API=y
+CONFIG_SND_VERBOSE_PROCFS=y
+# CONFIG_SND_VERBOSE_PRINTK is not set
+# CONFIG_SND_DEBUG is not set
+# CONFIG_SND_RAWMIDI_SEQ is not set
+# CONFIG_SND_OPL3_LIB_SEQ is not set
+# CONFIG_SND_OPL4_LIB_SEQ is not set
+# CONFIG_SND_SBAWE_SEQ is not set
+# CONFIG_SND_EMU10K1_SEQ is not set
+CONFIG_SND_DRIVERS=y
+# CONFIG_SND_DUMMY is not set
+# CONFIG_SND_MTPAV is not set
+# CONFIG_SND_SERIAL_U16550 is not set
+# CONFIG_SND_MPU401 is not set
+CONFIG_SND_ARM=y
+CONFIG_SND_SPI=y
+CONFIG_SND_USB=y
+# CONFIG_SND_USB_AUDIO is not set
+# CONFIG_SND_USB_CAIAQ is not set
+# CONFIG_SND_SOC is not set
+# CONFIG_SOUND_PRIME is not set
+CONFIG_HID_SUPPORT=y
+CONFIG_HID=y
+# CONFIG_HIDRAW is not set
+
+#
+# USB Input Devices
+#
+CONFIG_USB_HID=y
+# CONFIG_HID_PID is not set
+# CONFIG_USB_HIDDEV is not set
+
+#
+# Special HID drivers
+#
+# CONFIG_HID_A4TECH is not set
+# CONFIG_HID_APPLE is not set
+# CONFIG_HID_BELKIN is not set
+# CONFIG_HID_CHERRY is not set
+# CONFIG_HID_CHICONY is not set
+# CONFIG_HID_CYPRESS is not set
+# CONFIG_HID_DRAGONRISE is not set
+# CONFIG_HID_EZKEY is not set
+# CONFIG_HID_KYE is not set
+# CONFIG_HID_GYRATION is not set
+# CONFIG_HID_TWINHAN is not set
+# CONFIG_HID_KENSINGTON is not set
+# CONFIG_HID_LOGITECH is not set
+# CONFIG_HID_MICROSOFT is not set
+# CONFIG_HID_MONTEREY is not set
+# CONFIG_HID_NTRIG is not set
+# CONFIG_HID_PANTHERLORD is not set
+# CONFIG_HID_PETALYNX is not set
+# CONFIG_HID_SAMSUNG is not set
+# CONFIG_HID_SONY is not set
+# CONFIG_HID_SUNPLUS is not set
+# CONFIG_HID_GREENASIA is not set
+# CONFIG_HID_SMARTJOYPLUS is not set
+# CONFIG_HID_TOPSEED is not set
+# CONFIG_HID_THRUSTMASTER is not set
+# CONFIG_HID_ZEROPLUS is not set
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+CONFIG_USB_ARCH_HAS_EHCI=y
+CONFIG_USB=y
+CONFIG_USB_DEBUG=y
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+# CONFIG_USB_DEVICE_CLASS is not set
+# CONFIG_USB_DYNAMIC_MINORS is not set
+CONFIG_USB_SUSPEND=y
+CONFIG_USB_OTG=y
+# CONFIG_USB_OTG_WHITELIST is not set
+# CONFIG_USB_OTG_BLACKLIST_HUB is not set
+CONFIG_USB_MON=y
+# CONFIG_USB_WUSB is not set
+# CONFIG_USB_WUSB_CBAF is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_C67X00_HCD is not set
+# CONFIG_USB_EHCI_HCD is not set
+# CONFIG_USB_OXU210HP_HCD is not set
+# CONFIG_USB_ISP116X_HCD is not set
+# CONFIG_USB_ISP1760_HCD is not set
+# CONFIG_USB_ISP1362_HCD is not set
+# CONFIG_USB_OHCI_HCD is not set
+# CONFIG_USB_SL811_HCD is not set
+# CONFIG_USB_R8A66597_HCD is not set
+# CONFIG_USB_HWA_HCD is not set
+CONFIG_USB_MUSB_HDRC=y
+CONFIG_USB_MUSB_SOC=y
+
+#
+# OMAP 343x high speed USB support
+#
+# CONFIG_USB_MUSB_HOST is not set
+# CONFIG_USB_MUSB_PERIPHERAL is not set
+CONFIG_USB_MUSB_OTG=y
+CONFIG_USB_GADGET_MUSB_HDRC=y
+CONFIG_USB_MUSB_HDRC_HCD=y
+# CONFIG_MUSB_PIO_ONLY is not set
+CONFIG_USB_INVENTRA_DMA=y
+# CONFIG_USB_TI_CPPI_DMA is not set
+CONFIG_USB_MUSB_DEBUG=y
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+# CONFIG_USB_WDM is not set
+# CONFIG_USB_TMC is not set
+
+#
+# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may
+#
+
+#
+# also be needed; see USB_STORAGE Help for more info
+#
+CONFIG_USB_STORAGE=y
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_ISD200 is not set
+# CONFIG_USB_STORAGE_USBAT is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_SDDR55 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_STORAGE_ALAUDA is not set
+# CONFIG_USB_STORAGE_ONETOUCH is not set
+# CONFIG_USB_STORAGE_KARMA is not set
+# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set
+# CONFIG_USB_LIBUSUAL is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+
+#
+# USB port drivers
+#
+# CONFIG_USB_SERIAL is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_ADUTUX is not set
+# CONFIG_USB_SEVSEG is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_BERRY_CHARGE is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYPRESS_CY7C63 is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_FTDI_ELAN is not set
+# CONFIG_USB_APPLEDISPLAY is not set
+# CONFIG_USB_SISUSBVGA is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
+# CONFIG_USB_IOWARRIOR is not set
+CONFIG_USB_TEST=m
+# CONFIG_USB_ISIGHTFW is not set
+# CONFIG_USB_VST is not set
+CONFIG_USB_GADGET=m
+CONFIG_USB_GADGET_DEBUG=y
+CONFIG_USB_GADGET_DEBUG_FILES=y
+CONFIG_USB_GADGET_VBUS_DRAW=2
+CONFIG_USB_GADGET_SELECTED=y
+# CONFIG_USB_GADGET_AT91 is not set
+# CONFIG_USB_GADGET_ATMEL_USBA is not set
+# CONFIG_USB_GADGET_FSL_USB2 is not set
+# CONFIG_USB_GADGET_LH7A40X is not set
+# CONFIG_USB_GADGET_OMAP is not set
+# CONFIG_USB_GADGET_PXA25X is not set
+# CONFIG_USB_GADGET_R8A66597 is not set
+# CONFIG_USB_GADGET_PXA27X is not set
+# CONFIG_USB_GADGET_S3C_HSOTG is not set
+# CONFIG_USB_GADGET_IMX is not set
+# CONFIG_USB_GADGET_S3C2410 is not set
+# CONFIG_USB_GADGET_M66592 is not set
+# CONFIG_USB_GADGET_AMD5536UDC is not set
+# CONFIG_USB_GADGET_FSL_QE is not set
+# CONFIG_USB_GADGET_CI13XXX is not set
+# CONFIG_USB_GADGET_NET2280 is not set
+# CONFIG_USB_GADGET_GOKU is not set
+# CONFIG_USB_GADGET_LANGWELL is not set
+# CONFIG_USB_GADGET_DUMMY_HCD is not set
+CONFIG_USB_GADGET_DUALSPEED=y
+CONFIG_USB_ZERO=m
+# CONFIG_USB_ZERO_HNPTEST is not set
+CONFIG_USB_AUDIO=m
+CONFIG_USB_ETH=m
+CONFIG_USB_ETH_RNDIS=y
+# CONFIG_USB_ETH_EEM is not set
+CONFIG_USB_GADGETFS=m
+CONFIG_USB_FILE_STORAGE=m
+# CONFIG_USB_FILE_STORAGE_TEST is not set
+CONFIG_USB_G_SERIAL=m
+# CONFIG_USB_MIDI_GADGET is not set
+# CONFIG_USB_G_PRINTER is not set
+CONFIG_USB_CDC_COMPOSITE=m
+
+#
+# OTG and related infrastructure
+#
+CONFIG_USB_OTG_UTILS=y
+# CONFIG_USB_GPIO_VBUS is not set
+# CONFIG_ISP1301_OMAP is not set
+CONFIG_TWL4030_USB=y
+# CONFIG_NOP_USB_XCEIV is not set
+CONFIG_MMC=y
+# CONFIG_MMC_DEBUG is not set
+# CONFIG_MMC_UNSAFE_RESUME is not set
+
+#
+# MMC/SD/SDIO Card Drivers
+#
+CONFIG_MMC_BLOCK=y
+CONFIG_MMC_BLOCK_BOUNCE=y
+# CONFIG_SDIO_UART is not set
+# CONFIG_MMC_TEST is not set
+
+#
+# MMC/SD/SDIO Host Controller Drivers
+#
+# CONFIG_MMC_SDHCI is not set
+# CONFIG_MMC_OMAP is not set
+CONFIG_MMC_OMAP_HS=y
+# CONFIG_MMC_AT91 is not set
+# CONFIG_MMC_ATMELMCI is not set
+# CONFIG_MMC_SPI is not set
+# CONFIG_MEMSTICK is not set
+# CONFIG_NEW_LEDS is not set
+# CONFIG_ACCESSIBILITY is not set
+CONFIG_RTC_LIB=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_HCTOSYS=y
+CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
+# CONFIG_RTC_DEBUG is not set
+
+#
+# RTC interfaces
+#
+CONFIG_RTC_INTF_SYSFS=y
+CONFIG_RTC_INTF_PROC=y
+CONFIG_RTC_INTF_DEV=y
+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+# CONFIG_RTC_DRV_TEST is not set
+
+#
+# I2C RTC drivers
+#
+# CONFIG_RTC_DRV_DS1307 is not set
+# CONFIG_RTC_DRV_DS1374 is not set
+# CONFIG_RTC_DRV_DS1672 is not set
+# CONFIG_RTC_DRV_MAX6900 is not set
+# CONFIG_RTC_DRV_RS5C372 is not set
+# CONFIG_RTC_DRV_ISL1208 is not set
+# CONFIG_RTC_DRV_X1205 is not set
+# CONFIG_RTC_DRV_PCF8563 is not set
+# CONFIG_RTC_DRV_PCF8583 is not set
+# CONFIG_RTC_DRV_M41T80 is not set
+# CONFIG_RTC_DRV_TWL4030 is not set
+# CONFIG_RTC_DRV_S35390A is not set
+# CONFIG_RTC_DRV_FM3130 is not set
+# CONFIG_RTC_DRV_RX8581 is not set
+# CONFIG_RTC_DRV_RX8025 is not set
+
+#
+# SPI RTC drivers
+#
+# CONFIG_RTC_DRV_M41T94 is not set
+# CONFIG_RTC_DRV_DS1305 is not set
+# CONFIG_RTC_DRV_DS1390 is not set
+# CONFIG_RTC_DRV_MAX6902 is not set
+# CONFIG_RTC_DRV_R9701 is not set
+# CONFIG_RTC_DRV_RS5C348 is not set
+# CONFIG_RTC_DRV_DS3234 is not set
+# CONFIG_RTC_DRV_PCF2123 is not set
+
+#
+# Platform RTC drivers
+#
+# CONFIG_RTC_DRV_CMOS is not set
+# CONFIG_RTC_DRV_DS1286 is not set
+# CONFIG_RTC_DRV_DS1511 is not set
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+# CONFIG_RTC_DRV_STK17TA8 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_M48T35 is not set
+# CONFIG_RTC_DRV_M48T59 is not set
+# CONFIG_RTC_DRV_BQ4802 is not set
+# CONFIG_RTC_DRV_V3020 is not set
+
+#
+# on-CPU RTC drivers
+#
+# CONFIG_DMADEVICES is not set
+# CONFIG_AUXDISPLAY is not set
+# CONFIG_UIO is not set
+
+#
+# TI VLYNQ
+#
+# CONFIG_STAGING is not set
+
+#
+# CBUS support
+#
+# CONFIG_CBUS is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
+# CONFIG_EXT3_FS_XATTR is not set
+# CONFIG_EXT4_FS is not set
+CONFIG_JBD=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+CONFIG_FS_POSIX_ACL=y
+# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_BTRFS_FS is not set
+# CONFIG_NILFS2_FS is not set
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
+CONFIG_DNOTIFY=y
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+CONFIG_QUOTA=y
+# CONFIG_QUOTA_NETLINK_INTERFACE is not set
+CONFIG_PRINT_QUOTA_WARNING=y
+CONFIG_QUOTA_TREE=y
+# CONFIG_QFMT_V1 is not set
+CONFIG_QFMT_V2=y
+CONFIG_QUOTACTL=y
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# Caches
+#
+# CONFIG_FSCACHE is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLB_PAGE is not set
+# CONFIG_CONFIGFS_FS is not set
+CONFIG_MISC_FILESYSTEMS=y
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_SQUASHFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_OMFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+CONFIG_NETWORK_FILESYSTEMS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+CONFIG_NFS_V3_ACL=y
+CONFIG_NFS_V4=y
+# CONFIG_NFS_V4_1 is not set
+CONFIG_ROOT_NFS=y
+# CONFIG_NFSD is not set
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_ACL_SUPPORT=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+CONFIG_SUNRPC_GSS=y
+CONFIG_RPCSEC_GSS_KRB5=y
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_KARMA_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+# CONFIG_SYSV68_PARTITION is not set
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+CONFIG_NLS_ISO8859_1=y
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+# CONFIG_DLM is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_WARN_DEPRECATED=y
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_FRAME_WARN=1024
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_STRIP_ASM_SYMS is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SHIRQ is not set
+CONFIG_DETECT_SOFTLOCKUP=y
+# CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set
+CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0
+CONFIG_DETECT_HUNG_TASK=y
+# CONFIG_BOOTPARAM_HUNG_TASK_PANIC is not set
+CONFIG_BOOTPARAM_HUNG_TASK_PANIC_VALUE=0
+CONFIG_SCHED_DEBUG=y
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_TIMER_STATS is not set
+# CONFIG_DEBUG_OBJECTS is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_KMEMLEAK is not set
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+CONFIG_DEBUG_MUTEXES=y
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_LOCK_STAT is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_DEBUG_KOBJECT is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+CONFIG_DEBUG_INFO=y
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_WRITECOUNT is not set
+# CONFIG_DEBUG_MEMORY_INIT is not set
+# CONFIG_DEBUG_LIST is not set
+# CONFIG_DEBUG_SG is not set
+# CONFIG_DEBUG_NOTIFIERS is not set
+# CONFIG_DEBUG_CREDENTIALS is not set
+# CONFIG_BOOT_PRINTK_DELAY is not set
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_RCU_CPU_STALL_DETECTOR is not set
+# CONFIG_BACKTRACE_SELF_TEST is not set
+# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
+# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
+# CONFIG_FAULT_INJECTION is not set
+# CONFIG_LATENCYTOP is not set
+# CONFIG_PAGE_POISONING is not set
+CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_TRACING_SUPPORT=y
+CONFIG_FTRACE=y
+# CONFIG_FUNCTION_TRACER is not set
+# CONFIG_IRQSOFF_TRACER is not set
+# CONFIG_SCHED_TRACER is not set
+# CONFIG_ENABLE_DEFAULT_TRACERS is not set
+# CONFIG_BOOT_TRACER is not set
+CONFIG_BRANCH_PROFILE_NONE=y
+# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set
+# CONFIG_PROFILE_ALL_BRANCHES is not set
+# CONFIG_STACK_TRACER is not set
+# CONFIG_KMEMTRACE is not set
+# CONFIG_WORKQUEUE_TRACER is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_SAMPLES is not set
+CONFIG_HAVE_ARCH_KGDB=y
+# CONFIG_KGDB is not set
+CONFIG_ARM_UNWIND=y
+# CONFIG_DEBUG_USER is not set
+# CONFIG_DEBUG_ERRORS is not set
+# CONFIG_DEBUG_STACK_USAGE is not set
+# CONFIG_DEBUG_LL is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+# CONFIG_SECURITYFS is not set
+# CONFIG_SECURITY_FILE_CAPABILITIES is not set
+CONFIG_CRYPTO=y
+
+#
+# Crypto core or helper
+#
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_ALGAPI2=y
+CONFIG_CRYPTO_AEAD2=y
+CONFIG_CRYPTO_BLKCIPHER=y
+CONFIG_CRYPTO_BLKCIPHER2=y
+CONFIG_CRYPTO_HASH=y
+CONFIG_CRYPTO_HASH2=y
+CONFIG_CRYPTO_RNG2=y
+CONFIG_CRYPTO_PCOMP=y
+CONFIG_CRYPTO_MANAGER=y
+CONFIG_CRYPTO_MANAGER2=y
+# CONFIG_CRYPTO_GF128MUL is not set
+# CONFIG_CRYPTO_NULL is not set
+CONFIG_CRYPTO_WORKQUEUE=y
+# CONFIG_CRYPTO_CRYPTD is not set
+# CONFIG_CRYPTO_AUTHENC is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Authenticated Encryption with Associated Data
+#
+# CONFIG_CRYPTO_CCM is not set
+# CONFIG_CRYPTO_GCM is not set
+# CONFIG_CRYPTO_SEQIV is not set
+
+#
+# Block modes
+#
+CONFIG_CRYPTO_CBC=y
+# CONFIG_CRYPTO_CTR is not set
+# CONFIG_CRYPTO_CTS is not set
+CONFIG_CRYPTO_ECB=m
+# CONFIG_CRYPTO_LRW is not set
+CONFIG_CRYPTO_PCBC=m
+# CONFIG_CRYPTO_XTS is not set
+
+#
+# Hash modes
+#
+# CONFIG_CRYPTO_HMAC is not set
+# CONFIG_CRYPTO_XCBC is not set
+# CONFIG_CRYPTO_VMAC is not set
+
+#
+# Digest
+#
+CONFIG_CRYPTO_CRC32C=y
+# CONFIG_CRYPTO_GHASH is not set
+# CONFIG_CRYPTO_MD4 is not set
+CONFIG_CRYPTO_MD5=y
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_RMD128 is not set
+# CONFIG_CRYPTO_RMD160 is not set
+# CONFIG_CRYPTO_RMD256 is not set
+# CONFIG_CRYPTO_RMD320 is not set
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_WP512 is not set
+
+#
+# Ciphers
+#
+# CONFIG_CRYPTO_AES is not set
+# CONFIG_CRYPTO_ANUBIS is not set
+# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_CAMELLIA is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+CONFIG_CRYPTO_DES=y
+# CONFIG_CRYPTO_FCRYPT is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_SALSA20 is not set
+# CONFIG_CRYPTO_SEED is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+
+#
+# Compression
+#
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_ZLIB is not set
+# CONFIG_CRYPTO_LZO is not set
+
+#
+# Random Number Generation
+#
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
+CONFIG_CRYPTO_HW=y
+# CONFIG_BINARY_PRINTF is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+CONFIG_GENERIC_FIND_LAST_BIT=y
+CONFIG_CRC_CCITT=y
+# CONFIG_CRC16 is not set
+CONFIG_CRC_T10DIF=y
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+CONFIG_LIBCRC32C=y
+CONFIG_ZLIB_INFLATE=y
+CONFIG_DECOMPRESS_GZIP=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
+CONFIG_NLATTR=y
index a57f9e4..b3ea2c4 100644 (file)
@@ -54,8 +54,8 @@ CONFIG_FAIR_GROUP_SCHED=y
 # CONFIG_RT_GROUP_SCHED is not set
 CONFIG_USER_SCHED=y
 # CONFIG_CGROUP_SCHED is not set
-CONFIG_SYSFS_DEPRECATED=y
-CONFIG_SYSFS_DEPRECATED_V2=y
+# CONFIG_SYSFS_DEPRECATED=y is not set
+# CONFIG_SYSFS_DEPRECATED_V2=y is not set
 # CONFIG_RELAY is not set
 # CONFIG_NAMESPACES is not set
 CONFIG_BLK_DEV_INITRD=y
index e7e3133..1559734 100644 (file)
@@ -784,7 +784,7 @@ CONFIG_INPUT_KEYBOARD=y
 # CONFIG_KEYBOARD_XTKBD is not set
 # CONFIG_KEYBOARD_NEWTON is not set
 # CONFIG_KEYBOARD_STOWAWAY is not set
-# CONFIG_KEYBOARD_GPIO is not set
+CONFIG_KEYBOARD_GPIO=m
 # CONFIG_INPUT_MOUSE is not set
 # CONFIG_INPUT_JOYSTICK is not set
 # CONFIG_INPUT_TABLET is not set
diff --git a/arch/arm/configs/u8500_defconfig b/arch/arm/configs/u8500_defconfig
new file mode 100644 (file)
index 0000000..15fde22
--- /dev/null
@@ -0,0 +1,680 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.32-rc8
+# Mon Nov 30 11:11:29 2009
+#
+CONFIG_ARM=y
+CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_GENERIC_LOCKBREAK=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
+CONFIG_VECTORS_BASE=0xffff0000
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_LOCK_KERNEL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+# CONFIG_SWAP is not set
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+
+#
+# RCU Subsystem
+#
+CONFIG_TREE_RCU=y
+# CONFIG_TREE_PREEMPT_RCU is not set
+# CONFIG_RCU_TRACE is not set
+CONFIG_RCU_FANOUT=32
+# CONFIG_RCU_FANOUT_EXACT is not set
+# CONFIG_TREE_RCU_TRACE is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=17
+CONFIG_GROUP_SCHED=y
+CONFIG_FAIR_GROUP_SCHED=y
+CONFIG_RT_GROUP_SCHED=y
+CONFIG_USER_SCHED=y
+# CONFIG_CGROUP_SCHED is not set
+# CONFIG_CGROUPS is not set
+CONFIG_SYSFS_DEPRECATED=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+# CONFIG_RELAY is not set
+CONFIG_NAMESPACES=y
+# CONFIG_UTS_NS is not set
+# CONFIG_IPC_NS is not set
+# CONFIG_USER_NS is not set
+# CONFIG_PID_NS is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_RD_GZIP=y
+CONFIG_RD_BZIP2=y
+CONFIG_RD_LZMA=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+CONFIG_ANON_INODES=y
+# CONFIG_EMBEDDED is not set
+CONFIG_UID16=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+CONFIG_KALLSYMS_ALL=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_AIO=y
+
+#
+# Kernel Performance Events And Counters
+#
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_SLUB_DEBUG=y
+CONFIG_COMPAT_BRK=y
+# CONFIG_SLAB is not set
+CONFIG_SLUB=y
+# CONFIG_SLOB is not set
+# CONFIG_PROFILING is not set
+CONFIG_HAVE_OPROFILE=y
+# CONFIG_KPROBES is not set
+CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_KRETPROBES=y
+CONFIG_USE_GENERIC_SMP_HELPERS=y
+
+#
+# GCOV-based kernel profiling
+#
+# CONFIG_SLOW_WORK is not set
+CONFIG_HAVE_GENERIC_DMA_COHERENT=y
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+# CONFIG_MODULE_FORCE_LOAD is not set
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_STOP_MACHINE=y
+CONFIG_BLOCK=y
+# CONFIG_LBDAF is not set
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_BLK_DEV_INTEGRITY is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_DEFAULT_AS is not set
+# CONFIG_DEFAULT_DEADLINE is not set
+CONFIG_DEFAULT_CFQ=y
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="cfq"
+# CONFIG_FREEZER is not set
+
+#
+# System Type
+#
+CONFIG_MMU=y
+# CONFIG_ARCH_AAEC2000 is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_REALVIEW is not set
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_AT91 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_GEMINI is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_EP93XX is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_MXC is not set
+# CONFIG_ARCH_STMP3XXX is not set
+# CONFIG_ARCH_NETX is not set
+# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_NOMADIK is not set
+# CONFIG_ARCH_IOP13XX is not set
+# CONFIG_ARCH_IOP32X is not set
+# CONFIG_ARCH_IOP33X is not set
+# CONFIG_ARCH_IXP23XX is not set
+# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_KIRKWOOD is not set
+# CONFIG_ARCH_LOKI is not set
+# CONFIG_ARCH_MV78XX0 is not set
+# CONFIG_ARCH_ORION5X is not set
+# CONFIG_ARCH_MMP is not set
+# CONFIG_ARCH_KS8695 is not set
+# CONFIG_ARCH_NS9XXX is not set
+# CONFIG_ARCH_W90X900 is not set
+# CONFIG_ARCH_PNX4008 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_MSM is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_S3C64XX is not set
+# CONFIG_ARCH_S5PC1XX is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_U300 is not set
+# CONFIG_ARCH_DAVINCI is not set
+# CONFIG_ARCH_OMAP is not set
+# CONFIG_ARCH_BCMRING is not set
+CONFIG_ARCH_U8500=y
+CONFIG_PLAT_NOMADIK=y
+CONFIG_HAS_MTU=y
+
+#
+# ST-Ericsson platform type
+#
+
+#
+# ST-Ericsson Multicore Mobile Platforms
+#
+CONFIG_MACH_U8500_MOP=y
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_32v6K=y
+CONFIG_CPU_V7=y
+CONFIG_CPU_32v7=y
+CONFIG_CPU_ABRT_EV7=y
+CONFIG_CPU_PABRT_V7=y
+CONFIG_CPU_CACHE_V7=y
+CONFIG_CPU_CACHE_VIPT=y
+CONFIG_CPU_COPY_V6=y
+CONFIG_CPU_TLB_V7=y
+CONFIG_CPU_HAS_ASID=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
+
+#
+# Processor Features
+#
+CONFIG_ARM_THUMB=y
+# CONFIG_ARM_THUMBEE is not set
+# CONFIG_CPU_ICACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_DISABLE is not set
+# CONFIG_CPU_BPREDICT_DISABLE is not set
+CONFIG_HAS_TLS_REG=y
+CONFIG_ARM_L1_CACHE_SHIFT=5
+# CONFIG_ARM_ERRATA_430973 is not set
+# CONFIG_ARM_ERRATA_458693 is not set
+# CONFIG_ARM_ERRATA_460075 is not set
+CONFIG_ARM_GIC=y
+CONFIG_COMMON_CLKDEV=y
+
+#
+# Bus support
+#
+CONFIG_ARM_AMBA=y
+# CONFIG_PCI_SYSCALL is not set
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+# CONFIG_NO_HZ is not set
+# CONFIG_HIGH_RES_TIMERS is not set
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+CONFIG_SMP=y
+CONFIG_HAVE_ARM_SCU=y
+CONFIG_HAVE_ARM_TWD=y
+CONFIG_VMSPLIT_3G=y
+# CONFIG_VMSPLIT_2G is not set
+# CONFIG_VMSPLIT_1G is not set
+CONFIG_PAGE_OFFSET=0xC0000000
+CONFIG_NR_CPUS=2
+# CONFIG_HOTPLUG_CPU is not set
+CONFIG_LOCAL_TIMERS=y
+# CONFIG_PREEMPT_NONE is not set
+# CONFIG_PREEMPT_VOLUNTARY is not set
+CONFIG_PREEMPT=y
+CONFIG_HZ=100
+# CONFIG_THUMB2_KERNEL is not set
+CONFIG_AEABI=y
+CONFIG_OABI_COMPAT=y
+# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set
+# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set
+# CONFIG_HIGHMEM is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+CONFIG_PAGEFLAGS_EXTENDED=y
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_PHYS_ADDR_T_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=0
+CONFIG_VIRT_TO_BUS=y
+CONFIG_HAVE_MLOCK=y
+CONFIG_HAVE_MLOCKED_PAGE_BIT=y
+# CONFIG_KSM is not set
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
+CONFIG_ALIGNMENT_TRAP=y
+# CONFIG_UACCESS_WITH_MEMCPY is not set
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0
+CONFIG_ZBOOT_ROM_BSS=0
+CONFIG_CMDLINE="root=/dev/ram0 console=ttyAMA2,115200n8"
+# CONFIG_XIP_KERNEL is not set
+# CONFIG_KEXEC is not set
+
+#
+# CPU Power Management
+#
+# CONFIG_CPU_IDLE is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+# CONFIG_FPE_NWFPE is not set
+# CONFIG_FPE_FASTFPE is not set
+CONFIG_VFP=y
+CONFIG_VFPv3=y
+CONFIG_NEON=y
+
+#
+# Userspace binary formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_HAVE_AOUT=y
+# CONFIG_BINFMT_AOUT is not set
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Power management options
+#
+# CONFIG_PM is not set
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+# CONFIG_NET is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+# CONFIG_DEVTMPFS is not set
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=y
+CONFIG_FIRMWARE_IN_KERNEL=y
+CONFIG_EXTRA_FIRMWARE=""
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES is not set
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_MTD is not set
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_DEV_COW_COMMON is not set
+# CONFIG_BLK_DEV_LOOP is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=65536
+# CONFIG_BLK_DEV_XIP is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_MISC_DEVICES is not set
+CONFIG_HAVE_IDE=y
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+# CONFIG_SCSI is not set
+# CONFIG_SCSI_DMA is not set
+# CONFIG_SCSI_NETLINK is not set
+# CONFIG_ATA is not set
+# CONFIG_MD is not set
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_CONSOLE_TRANSLATIONS=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+CONFIG_VT_HW_CONSOLE_BINDING=y
+CONFIG_DEVKMEM=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+# CONFIG_SERIAL_AMBA_PL010 is not set
+CONFIG_SERIAL_AMBA_PL011=y
+CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
+# CONFIG_SERIAL_MAX3100 is not set
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_HW_RANDOM is not set
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+# CONFIG_I2C is not set
+CONFIG_SPI=y
+# CONFIG_SPI_DEBUG is not set
+CONFIG_SPI_MASTER=y
+
+#
+# SPI Master Controller Drivers
+#
+# CONFIG_SPI_BITBANG is not set
+CONFIG_SPI_PL022=y
+
+#
+# SPI Protocol Masters
+#
+# CONFIG_SPI_SPIDEV is not set
+# CONFIG_SPI_TLE62X0 is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+# CONFIG_HWMON is not set
+# CONFIG_THERMAL is not set
+# CONFIG_WATCHDOG is not set
+CONFIG_SSB_POSSIBLE=y
+
+#
+# Sonics Silicon Backplane
+#
+# CONFIG_SSB is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_CORE is not set
+# CONFIG_MFD_SM501 is not set
+# CONFIG_HTC_PASIC3 is not set
+# CONFIG_MFD_TMIO is not set
+# CONFIG_MFD_MC13783 is not set
+# CONFIG_EZX_PCAP is not set
+# CONFIG_REGULATOR is not set
+# CONFIG_MEDIA_SUPPORT is not set
+
+#
+# Graphics support
+#
+# CONFIG_VGASTATE is not set
+# CONFIG_VIDEO_OUTPUT_CONTROL is not set
+# CONFIG_FB is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+# CONFIG_SOUND is not set
+# CONFIG_HID_SUPPORT is not set
+# CONFIG_USB_SUPPORT is not set
+# CONFIG_MMC is not set
+# CONFIG_MEMSTICK is not set
+# CONFIG_NEW_LEDS is not set
+# CONFIG_ACCESSIBILITY is not set
+CONFIG_RTC_LIB=y
+# CONFIG_RTC_CLASS is not set
+# CONFIG_DMADEVICES is not set
+# CONFIG_AUXDISPLAY is not set
+# CONFIG_UIO is not set
+
+#
+# TI VLYNQ
+#
+# CONFIG_STAGING is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT2_FS_POSIX_ACL=y
+CONFIG_EXT2_FS_SECURITY=y
+# CONFIG_EXT2_FS_XIP is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_EXT4_FS is not set
+CONFIG_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+CONFIG_FS_POSIX_ACL=y
+# CONFIG_XFS_FS is not set
+# CONFIG_BTRFS_FS is not set
+# CONFIG_NILFS2_FS is not set
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
+CONFIG_DNOTIFY=y
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+CONFIG_GENERIC_ACL=y
+
+#
+# Caches
+#
+# CONFIG_FSCACHE is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+# CONFIG_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+CONFIG_TMPFS_POSIX_ACL=y
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_CONFIGFS_FS=m
+# CONFIG_MISC_FILESYSTEMS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_NLS is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_WARN_DEPRECATED=y
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_FRAME_WARN=1024
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_STRIP_ASM_SYMS is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SHIRQ is not set
+CONFIG_DETECT_SOFTLOCKUP=y
+# CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set
+CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0
+CONFIG_DETECT_HUNG_TASK=y
+# CONFIG_BOOTPARAM_HUNG_TASK_PANIC is not set
+CONFIG_BOOTPARAM_HUNG_TASK_PANIC_VALUE=0
+# CONFIG_SCHED_DEBUG is not set
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_TIMER_STATS is not set
+# CONFIG_DEBUG_OBJECTS is not set
+# CONFIG_SLUB_DEBUG_ON is not set
+# CONFIG_SLUB_STATS is not set
+# CONFIG_DEBUG_KMEMLEAK is not set
+# CONFIG_DEBUG_PREEMPT is not set
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_LOCK_STAT is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_DEBUG_KOBJECT is not set
+CONFIG_DEBUG_BUGVERBOSE=y
+CONFIG_DEBUG_INFO=y
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_WRITECOUNT is not set
+CONFIG_DEBUG_MEMORY_INIT=y
+# CONFIG_DEBUG_LIST is not set
+# CONFIG_DEBUG_SG is not set
+# CONFIG_DEBUG_NOTIFIERS is not set
+# CONFIG_DEBUG_CREDENTIALS is not set
+# CONFIG_BOOT_PRINTK_DELAY is not set
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_RCU_CPU_STALL_DETECTOR is not set
+# CONFIG_BACKTRACE_SELF_TEST is not set
+# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
+# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
+# CONFIG_FAULT_INJECTION is not set
+# CONFIG_SYSCTL_SYSCALL_CHECK is not set
+# CONFIG_PAGE_POISONING is not set
+CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_TRACING_SUPPORT=y
+# CONFIG_FTRACE is not set
+# CONFIG_SAMPLES is not set
+CONFIG_HAVE_ARCH_KGDB=y
+# CONFIG_KGDB is not set
+CONFIG_ARM_UNWIND=y
+CONFIG_DEBUG_USER=y
+CONFIG_DEBUG_ERRORS=y
+# CONFIG_DEBUG_STACK_USAGE is not set
+# CONFIG_DEBUG_LL is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+# CONFIG_SECURITYFS is not set
+# CONFIG_SECURITY_FILE_CAPABILITIES is not set
+# CONFIG_CRYPTO is not set
+# CONFIG_BINARY_PRINTF is not set
+
+#
+# Library routines
+#
+CONFIG_GENERIC_FIND_LAST_BIT=y
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+CONFIG_CRC_T10DIF=m
+# CONFIG_CRC_ITU_T is not set
+# CONFIG_CRC32 is not set
+# CONFIG_CRC7 is not set
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_DECOMPRESS_GZIP=y
+CONFIG_DECOMPRESS_BZIP2=y
+CONFIG_DECOMPRESS_LZMA=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
index 3d0cdd2..73eceb8 100644 (file)
@@ -331,15 +331,15 @@ static inline void outer_flush_range(unsigned long start, unsigned long end)
  * Convert calls to our calling convention.
  */
 #define flush_cache_all()              __cpuc_flush_kern_all()
-#ifndef CONFIG_CPU_CACHE_VIPT
-static inline void flush_cache_mm(struct mm_struct *mm)
+
+static inline void vivt_flush_cache_mm(struct mm_struct *mm)
 {
        if (cpumask_test_cpu(smp_processor_id(), mm_cpumask(mm)))
                __cpuc_flush_user_all();
 }
 
 static inline void
-flush_cache_range(struct vm_area_struct *vma, unsigned long start, unsigned long end)
+vivt_flush_cache_range(struct vm_area_struct *vma, unsigned long start, unsigned long end)
 {
        if (cpumask_test_cpu(smp_processor_id(), mm_cpumask(vma->vm_mm)))
                __cpuc_flush_user_range(start & PAGE_MASK, PAGE_ALIGN(end),
@@ -347,7 +347,7 @@ flush_cache_range(struct vm_area_struct *vma, unsigned long start, unsigned long
 }
 
 static inline void
-flush_cache_page(struct vm_area_struct *vma, unsigned long user_addr, unsigned long pfn)
+vivt_flush_cache_page(struct vm_area_struct *vma, unsigned long user_addr, unsigned long pfn)
 {
        if (cpumask_test_cpu(smp_processor_id(), mm_cpumask(vma->vm_mm))) {
                unsigned long addr = user_addr & PAGE_MASK;
@@ -356,7 +356,7 @@ flush_cache_page(struct vm_area_struct *vma, unsigned long user_addr, unsigned l
 }
 
 static inline void
-flush_ptrace_access(struct vm_area_struct *vma, struct page *page,
+vivt_flush_ptrace_access(struct vm_area_struct *vma, struct page *page,
                         unsigned long uaddr, void *kaddr,
                         unsigned long len, int write)
 {
@@ -365,6 +365,16 @@ flush_ptrace_access(struct vm_area_struct *vma, struct page *page,
                __cpuc_coherent_kern_range(addr, addr + len);
        }
 }
+
+#ifndef CONFIG_CPU_CACHE_VIPT
+#define flush_cache_mm(mm) \
+               vivt_flush_cache_mm(mm)
+#define flush_cache_range(vma,start,end) \
+               vivt_flush_cache_range(vma,start,end)
+#define flush_cache_page(vma,addr,pfn) \
+               vivt_flush_cache_page(vma,addr,pfn)
+#define flush_ptrace_access(vma,page,ua,ka,len,write) \
+               vivt_flush_ptrace_access(vma,page,ua,ka,len,write)
 #else
 extern void flush_cache_mm(struct mm_struct *mm);
 extern void flush_cache_range(struct vm_area_struct *vma, unsigned long start, unsigned long end);
@@ -408,10 +418,9 @@ extern void flush_ptrace_access(struct vm_area_struct *vma, struct page *page,
  * about to change to user space.  This is the same method as used on SPARC64.
  * See update_mmu_cache for the user space part.
  */
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 1
 extern void flush_dcache_page(struct page *);
 
-extern void __flush_dcache_page(struct address_space *mapping, struct page *page);
-
 static inline void __flush_icache_all(void)
 {
 #ifdef CONFIG_ARM_ERRATA_411920
index ff46dfa..a96300b 100644 (file)
  * must not be used by drivers.
  */
 #ifndef __arch_page_to_dma
-
-#if !defined(CONFIG_HIGHMEM)
 static inline dma_addr_t page_to_dma(struct device *dev, struct page *page)
 {
-       return (dma_addr_t)__virt_to_bus((unsigned long)page_address(page));
+       return (dma_addr_t)__pfn_to_bus(page_to_pfn(page));
 }
-#elif defined(__pfn_to_bus)
-static inline dma_addr_t page_to_dma(struct device *dev, struct page *page)
+
+static inline struct page *dma_to_page(struct device *dev, dma_addr_t addr)
 {
-       return (dma_addr_t)__pfn_to_bus(page_to_pfn(page));
+       return pfn_to_page(__bus_to_pfn(addr));
 }
-#else
-#error "this machine class needs to define __arch_page_to_dma to use HIGHMEM"
-#endif
 
 static inline void *dma_to_virt(struct device *dev, dma_addr_t addr)
 {
@@ -45,6 +40,11 @@ static inline dma_addr_t page_to_dma(struct device *dev, struct page *page)
        return __arch_page_to_dma(dev, page);
 }
 
+static inline struct page *dma_to_page(struct device *dev, dma_addr_t addr)
+{
+       return __arch_dma_to_page(dev, addr);
+}
+
 static inline void *dma_to_virt(struct device *dev, dma_addr_t addr)
 {
        return __arch_dma_to_virt(dev, addr);
@@ -257,9 +257,11 @@ extern int dma_needs_bounce(struct device*, dma_addr_t, size_t);
  */
 extern dma_addr_t dma_map_single(struct device *, void *, size_t,
                enum dma_data_direction);
+extern void dma_unmap_single(struct device *, dma_addr_t, size_t,
+               enum dma_data_direction);
 extern dma_addr_t dma_map_page(struct device *, struct page *,
                unsigned long, size_t, enum dma_data_direction);
-extern void dma_unmap_single(struct device *, dma_addr_t, size_t,
+extern void dma_unmap_page(struct device *, dma_addr_t, size_t,
                enum dma_data_direction);
 
 /*
@@ -352,7 +354,6 @@ static inline void dma_unmap_single(struct device *dev, dma_addr_t handle,
 {
        /* nothing to do */
 }
-#endif /* CONFIG_DMABOUNCE */
 
 /**
  * dma_unmap_page - unmap a buffer previously mapped through dma_map_page()
@@ -371,8 +372,9 @@ static inline void dma_unmap_single(struct device *dev, dma_addr_t handle,
 static inline void dma_unmap_page(struct device *dev, dma_addr_t handle,
                size_t size, enum dma_data_direction dir)
 {
-       dma_unmap_single(dev, handle, size, dir);
+       /* nothing to do */
 }
+#endif /* CONFIG_DMABOUNCE */
 
 /**
  * dma_sync_single_range_for_cpu
diff --git a/arch/arm/include/asm/hardware/cache-tauros2.h b/arch/arm/include/asm/hardware/cache-tauros2.h
new file mode 100644 (file)
index 0000000..538f17c
--- /dev/null
@@ -0,0 +1,11 @@
+/*
+ * arch/arm/include/asm/hardware/cache-tauros2.h
+ *
+ * Copyright (C) 2008 Marvell Semiconductor
+ *
+ * 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.
+ */
+
+extern void __init tauros2_init(void);
diff --git a/arch/arm/include/asm/hardware/coresight.h b/arch/arm/include/asm/hardware/coresight.h
new file mode 100644 (file)
index 0000000..f82b25d
--- /dev/null
@@ -0,0 +1,165 @@
+/*
+ * linux/arch/arm/include/asm/hardware/coresight.h
+ *
+ * CoreSight components' registers
+ *
+ * Copyright (C) 2009 Nokia Corporation.
+ * Alexander Shishkin
+ *
+ * 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_HARDWARE_CORESIGHT_H
+#define __ASM_HARDWARE_CORESIGHT_H
+
+#define TRACER_ACCESSED_BIT    0
+#define TRACER_RUNNING_BIT     1
+#define TRACER_CYCLE_ACC_BIT   2
+#define TRACER_ACCESSED                BIT(TRACER_ACCESSED_BIT)
+#define TRACER_RUNNING         BIT(TRACER_RUNNING_BIT)
+#define TRACER_CYCLE_ACC       BIT(TRACER_CYCLE_ACC_BIT)
+
+struct tracectx {
+       unsigned int    etb_bufsz;
+       void __iomem    *etb_regs;
+       void __iomem    *etm_regs;
+       unsigned long   flags;
+       int             ncmppairs;
+       int             etm_portsz;
+       struct device   *dev;
+       struct clk      *emu_clk;
+       struct mutex    mutex;
+};
+
+#define TRACER_TIMEOUT 10000
+
+#define etm_writel(t, v, x) \
+       (__raw_writel((v), (t)->etm_regs + (x)))
+#define etm_readl(t, x) (__raw_readl((t)->etm_regs + (x)))
+
+/* CoreSight Management Registers */
+#define CSMR_LOCKACCESS 0xfb0
+#define CSMR_LOCKSTATUS 0xfb4
+#define CSMR_AUTHSTATUS 0xfb8
+#define CSMR_DEVID     0xfc8
+#define CSMR_DEVTYPE   0xfcc
+/* CoreSight Component Registers */
+#define CSCR_CLASS     0xff4
+
+#define CSCR_PRSR      0x314
+
+#define UNLOCK_MAGIC   0xc5acce55
+
+/* ETM control register, "ETM Architecture", 3.3.1 */
+#define ETMR_CTRL              0
+#define ETMCTRL_POWERDOWN      1
+#define ETMCTRL_PROGRAM                (1 << 10)
+#define ETMCTRL_PORTSEL                (1 << 11)
+#define ETMCTRL_DO_CONTEXTID   (3 << 14)
+#define ETMCTRL_PORTMASK1      (7 << 4)
+#define ETMCTRL_PORTMASK2      (1 << 21)
+#define ETMCTRL_PORTMASK       (ETMCTRL_PORTMASK1 | ETMCTRL_PORTMASK2)
+#define ETMCTRL_PORTSIZE(x) ((((x) & 7) << 4) | (!!((x) & 8)) << 21)
+#define ETMCTRL_DO_CPRT                (1 << 1)
+#define ETMCTRL_DATAMASK       (3 << 2)
+#define ETMCTRL_DATA_DO_DATA   (1 << 2)
+#define ETMCTRL_DATA_DO_ADDR   (1 << 3)
+#define ETMCTRL_DATA_DO_BOTH   (ETMCTRL_DATA_DO_DATA | ETMCTRL_DATA_DO_ADDR)
+#define ETMCTRL_BRANCH_OUTPUT  (1 << 8)
+#define ETMCTRL_CYCLEACCURATE  (1 << 12)
+
+/* ETM configuration code register */
+#define ETMR_CONFCODE          (0x04)
+
+/* ETM trace start/stop resource control register */
+#define ETMR_TRACESSCTRL       (0x18)
+
+/* ETM trigger event register */
+#define ETMR_TRIGEVT           (0x08)
+
+/* address access type register bits, "ETM architecture",
+ * table 3-27 */
+/* - access type */
+#define ETMAAT_IFETCH          0
+#define ETMAAT_IEXEC           1
+#define ETMAAT_IEXECPASS       2
+#define ETMAAT_IEXECFAIL       3
+#define ETMAAT_DLOADSTORE      4
+#define ETMAAT_DLOAD           5
+#define ETMAAT_DSTORE          6
+/* - comparison access size */
+#define ETMAAT_JAVA            (0 << 3)
+#define ETMAAT_THUMB           (1 << 3)
+#define ETMAAT_ARM             (3 << 3)
+/* - data value comparison control */
+#define ETMAAT_NOVALCMP                (0 << 5)
+#define ETMAAT_VALMATCH                (1 << 5)
+#define ETMAAT_VALNOMATCH      (3 << 5)
+/* - exact match */
+#define ETMAAT_EXACTMATCH      (1 << 7)
+/* - context id comparator control */
+#define ETMAAT_IGNCONTEXTID    (0 << 8)
+#define ETMAAT_VALUE1          (1 << 8)
+#define ETMAAT_VALUE2          (2 << 8)
+#define ETMAAT_VALUE3          (3 << 8)
+/* - security level control */
+#define ETMAAT_IGNSECURITY     (0 << 10)
+#define ETMAAT_NSONLY          (1 << 10)
+#define ETMAAT_SONLY           (2 << 10)
+
+#define ETMR_COMP_VAL(x)       (0x40 + (x) * 4)
+#define ETMR_COMP_ACC_TYPE(x)  (0x80 + (x) * 4)
+
+/* ETM status register, "ETM Architecture", 3.3.2 */
+#define ETMR_STATUS            (0x10)
+#define ETMST_OVERFLOW         (1 << 0)
+#define ETMST_PROGBIT          (1 << 1)
+#define ETMST_STARTSTOP                (1 << 2)
+#define ETMST_TRIGGER          (1 << 3)
+
+#define etm_progbit(t)         (etm_readl((t), ETMR_STATUS) & ETMST_PROGBIT)
+#define etm_started(t)         (etm_readl((t), ETMR_STATUS) & ETMST_STARTSTOP)
+#define etm_triggered(t)       (etm_readl((t), ETMR_STATUS) & ETMST_TRIGGER)
+
+#define ETMR_TRACEENCTRL2      0x1c
+#define ETMR_TRACEENCTRL       0x24
+#define ETMTE_INCLEXCL         (1 << 24)
+#define ETMR_TRACEENEVT                0x20
+#define ETMCTRL_OPTS           (ETMCTRL_DO_CPRT | \
+                               ETMCTRL_DATA_DO_ADDR | \
+                               ETMCTRL_BRANCH_OUTPUT | \
+                               ETMCTRL_DO_CONTEXTID)
+
+/* ETB registers, "CoreSight Components TRM", 9.3 */
+#define ETBR_DEPTH             0x04
+#define ETBR_STATUS            0x0c
+#define ETBR_READMEM           0x10
+#define ETBR_READADDR          0x14
+#define ETBR_WRITEADDR         0x18
+#define ETBR_TRIGGERCOUNT      0x1c
+#define ETBR_CTRL              0x20
+#define ETBR_FORMATTERCTRL     0x304
+#define ETBFF_ENFTC            1
+#define ETBFF_ENFCONT          (1 << 1)
+#define ETBFF_FONFLIN          (1 << 4)
+#define ETBFF_MANUAL_FLUSH     (1 << 6)
+#define ETBFF_TRIGIN           (1 << 8)
+#define ETBFF_TRIGEVT          (1 << 9)
+#define ETBFF_TRIGFL           (1 << 10)
+
+#define etb_writel(t, v, x) \
+       (__raw_writel((v), (t)->etb_regs + (x)))
+#define etb_readl(t, x) (__raw_readl((t)->etb_regs + (x)))
+
+#define etm_lock(t) do { etm_writel((t), 0, CSMR_LOCKACCESS); } while (0)
+#define etm_unlock(t) \
+       do { etm_writel((t), UNLOCK_MAGIC, CSMR_LOCKACCESS); } while (0)
+
+#define etb_lock(t) do { etb_writel((t), 0, CSMR_LOCKACCESS); } while (0)
+#define etb_unlock(t) \
+       do { etb_writel((t), UNLOCK_MAGIC, CSMR_LOCKACCESS); } while (0)
+
+#endif /* __ASM_HARDWARE_CORESIGHT_H */
+
index 8d60ad2..5daea29 100644 (file)
@@ -234,7 +234,13 @@ extern int iop3xx_get_init_atu(void);
 void iop3xx_map_io(void);
 void iop_init_cp6_handler(void);
 void iop_init_time(unsigned long tickrate);
-unsigned long iop_gettimeoffset(void);
+
+static inline u32 read_tmr0(void)
+{
+       u32 val;
+       asm volatile("mrc p6, 0, %0, c0, c1, 0" : "=r" (val));
+       return val;
+}
 
 static inline void write_tmr0(u32 val)
 {
@@ -253,6 +259,11 @@ static inline u32 read_tcr0(void)
        return val;
 }
 
+static inline void write_tcr0(u32 val)
+{
+       asm volatile("mcr p6, 0, %0, c2, c1, 0" : : "r" (val));
+}
+
 static inline u32 read_tcr1(void)
 {
        u32 val;
@@ -260,6 +271,11 @@ static inline u32 read_tcr1(void)
        return val;
 }
 
+static inline void write_tcr1(u32 val)
+{
+       asm volatile("mcr p6, 0, %0, c3, c1, 0" : : "r" (val));
+}
+
 static inline void write_trr0(u32 val)
 {
        asm volatile("mcr p6, 0, %0, c4, c1, 0" : : "r" (val));
index cefedf0..5421d82 100644 (file)
  * private definitions which should NOT be used outside memory.h
  * files.  Use virt_to_phys/phys_to_virt/__pa/__va instead.
  */
+#ifndef __virt_to_phys
 #define __virt_to_phys(x)      ((x) - PAGE_OFFSET + PHYS_OFFSET)
 #define __phys_to_virt(x)      ((x) - PHYS_OFFSET + PAGE_OFFSET)
+#endif
 
 /*
  * Convert a physical address to a Page Frame Number and back
 #define        __phys_to_pfn(paddr)    ((paddr) >> PAGE_SHIFT)
 #define        __pfn_to_phys(pfn)      ((pfn) << PAGE_SHIFT)
 
+/*
+ * Convert a page to/from a physical address
+ */
+#define page_to_phys(page)     (__pfn_to_phys(page_to_pfn(page)))
+#define phys_to_page(phys)     (pfn_to_page(__phys_to_pfn(phys)))
+
 #ifndef __ASSEMBLY__
 
 /*
@@ -194,7 +202,8 @@ static inline void *phys_to_virt(unsigned long x)
 #ifndef __virt_to_bus
 #define __virt_to_bus  __virt_to_phys
 #define __bus_to_virt  __phys_to_virt
-#define __pfn_to_bus(x)        ((x) << PAGE_SHIFT)
+#define __pfn_to_bus(x)        __pfn_to_phys(x)
+#define __bus_to_pfn(x)        __phys_to_pfn(x)
 #endif
 
 static inline __deprecated unsigned long virt_to_bus(void *x)
@@ -293,11 +302,6 @@ static inline __deprecated void *bus_to_virt(unsigned long x)
 #endif /* !CONFIG_DISCONTIGMEM */
 
 /*
- * For BIO.  "will die".  Kill me when bio_to_phys() and bvec_to_phys() die.
- */
-#define page_to_phys(page)     (page_to_pfn(page) << PAGE_SHIFT)
-
-/*
  * Optional coherency support.  Currently used only by selected
  * Intel XSC3-based systems.
  */
index 201ccaa..1139768 100644 (file)
@@ -304,13 +304,23 @@ PTE_BIT_FUNC(mkyoung,   |= L_PTE_YOUNG);
 
 static inline pte_t pte_mkspecial(pte_t pte) { return pte; }
 
+#define __pgprot_modify(prot,mask,bits)                \
+       __pgprot((pgprot_val(prot) & ~(mask)) | (bits))
+
 /*
  * Mark the prot value as uncacheable and unbufferable.
  */
 #define pgprot_noncached(prot) \
-       __pgprot((pgprot_val(prot) & ~L_PTE_MT_MASK) | L_PTE_MT_UNCACHED)
+       __pgprot_modify(prot, L_PTE_MT_MASK, L_PTE_MT_UNCACHED)
 #define pgprot_writecombine(prot) \
-       __pgprot((pgprot_val(prot) & ~L_PTE_MT_MASK) | L_PTE_MT_BUFFERABLE)
+       __pgprot_modify(prot, L_PTE_MT_MASK, L_PTE_MT_BUFFERABLE)
+#if __LINUX_ARM_ARCH__ >= 7
+#define pgprot_dmacoherent(prot) \
+       __pgprot_modify(prot, L_PTE_MT_MASK|L_PTE_EXEC, L_PTE_MT_BUFFERABLE)
+#else
+#define pgprot_dmacoherent(prot) \
+       __pgprot_modify(prot, L_PTE_MT_MASK|L_PTE_EXEC, L_PTE_MT_UNCACHED)
+#endif
 
 #define pmd_none(pmd)          (!pmd_val(pmd))
 #define pmd_present(pmd)       (pmd_val(pmd))
index ca2bf2f..9997ad2 100644 (file)
 #  define __SWAB_64_THRU_32__
 #endif
 
+#if defined(__KERNEL__) && __LINUX_ARM_ARCH__ >= 6
+
+static inline __attribute_const__ __u16 __arch_swab16(__u16 x)
+{
+       __asm__ ("rev16 %0, %1" : "=r" (x) : "r" (x));
+       return x;
+}
+#define __arch_swab16 __arch_swab16
+
+static inline __attribute_const__ __u32 __arch_swab32(__u32 x)
+{
+       __asm__ ("rev %0, %1" : "=r" (x) : "r" (x));
+       return x;
+}
+#define __arch_swab32 __arch_swab32
+
+#else
+
 static inline __attribute_const__ __u32 __arch_swab32(__u32 x)
 {
        __u32 t;
@@ -48,3 +66,4 @@ static inline __attribute_const__ __u32 __arch_swab32(__u32 x)
 
 #endif
 
+#endif
index d65b2f5..058e7e9 100644 (file)
@@ -138,21 +138,26 @@ extern unsigned int user_debug;
 #define dmb() __asm__ __volatile__ ("" : : : "memory")
 #endif
 
-#ifndef CONFIG_SMP
+#if __LINUX_ARM_ARCH__ >= 7 || defined(CONFIG_SMP)
+#define mb()           dmb()
+#define rmb()          dmb()
+#define wmb()          dmb()
+#else
 #define mb()   do { if (arch_is_coherent()) dmb(); else barrier(); } while (0)
 #define rmb()  do { if (arch_is_coherent()) dmb(); else barrier(); } while (0)
 #define wmb()  do { if (arch_is_coherent()) dmb(); else barrier(); } while (0)
+#endif
+
+#ifndef CONFIG_SMP
 #define smp_mb()       barrier()
 #define smp_rmb()      barrier()
 #define smp_wmb()      barrier()
 #else
-#define mb()           dmb()
-#define rmb()          dmb()
-#define wmb()          dmb()
-#define smp_mb()       dmb()
-#define smp_rmb()      dmb()
-#define smp_wmb()      dmb()
+#define smp_mb()       mb()
+#define smp_rmb()      rmb()
+#define smp_wmb()      wmb()
 #endif
+
 #define read_barrier_depends()         do { } while(0)
 #define smp_read_barrier_depends()     do { } while(0)
 
index 79087dd..e7ccf7e 100644 (file)
@@ -17,6 +17,8 @@ obj-y         := compat.o elf.o entry-armv.o entry-common.o irq.o \
                   process.o ptrace.o return_address.o setup.o signal.o \
                   sys_arm.o stacktrace.o time.o traps.o
 
+obj-$(CONFIG_OC_ETM)           += etm.o
+
 obj-$(CONFIG_ISA_DMA_API)      += dma.o
 obj-$(CONFIG_ARCH_ACORN)       += ecard.o 
 obj-$(CONFIG_FIQ)              += fiq.o
diff --git a/arch/arm/kernel/etm.c b/arch/arm/kernel/etm.c
new file mode 100644 (file)
index 0000000..8277539
--- /dev/null
@@ -0,0 +1,641 @@
+/*
+ * linux/arch/arm/kernel/etm.c
+ *
+ * Driver for ARM's Embedded Trace Macrocell and Embedded Trace Buffer.
+ *
+ * Copyright (C) 2009 Nokia Corporation.
+ * Alexander Shishkin
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/io.h>
+#include <linux/sysrq.h>
+#include <linux/device.h>
+#include <linux/clk.h>
+#include <linux/amba/bus.h>
+#include <linux/fs.h>
+#include <linux/uaccess.h>
+#include <linux/miscdevice.h>
+#include <linux/vmalloc.h>
+#include <linux/mutex.h>
+#include <asm/hardware/coresight.h>
+#include <asm/sections.h>
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Alexander Shishkin");
+
+static struct tracectx tracer;
+
+static inline bool trace_isrunning(struct tracectx *t)
+{
+       return !!(t->flags & TRACER_RUNNING);
+}
+
+static int etm_setup_address_range(struct tracectx *t, int n,
+               unsigned long start, unsigned long end, int exclude, int data)
+{
+       u32 flags = ETMAAT_ARM | ETMAAT_IGNCONTEXTID | ETMAAT_NSONLY | \
+                   ETMAAT_NOVALCMP;
+
+       if (n < 1 || n > t->ncmppairs)
+               return -EINVAL;
+
+       /* comparators and ranges are numbered starting with 1 as opposed
+        * to bits in a word */
+       n--;
+
+       if (data)
+               flags |= ETMAAT_DLOADSTORE;
+       else
+               flags |= ETMAAT_IEXEC;
+
+       /* first comparator for the range */
+       etm_writel(t, flags, ETMR_COMP_ACC_TYPE(n * 2));
+       etm_writel(t, start, ETMR_COMP_VAL(n * 2));
+
+       /* second comparator is right next to it */
+       etm_writel(t, flags, ETMR_COMP_ACC_TYPE(n * 2 + 1));
+       etm_writel(t, end, ETMR_COMP_VAL(n * 2 + 1));
+
+       flags = exclude ? ETMTE_INCLEXCL : 0;
+       etm_writel(t, flags | (1 << n), ETMR_TRACEENCTRL);
+
+       return 0;
+}
+
+static int trace_start(struct tracectx *t)
+{
+       u32 v;
+       unsigned long timeout = TRACER_TIMEOUT;
+
+       etb_unlock(t);
+
+       etb_writel(t, 0, ETBR_FORMATTERCTRL);
+       etb_writel(t, 1, ETBR_CTRL);
+
+       etb_lock(t);
+
+       /* configure etm */
+       v = ETMCTRL_OPTS | ETMCTRL_PROGRAM | ETMCTRL_PORTSIZE(t->etm_portsz);
+
+       if (t->flags & TRACER_CYCLE_ACC)
+               v |= ETMCTRL_CYCLEACCURATE;
+
+       etm_unlock(t);
+
+       etm_writel(t, v, ETMR_CTRL);
+
+       while (!(etm_readl(t, ETMR_CTRL) & ETMCTRL_PROGRAM) && --timeout)
+               ;
+       if (!timeout) {
+               dev_dbg(t->dev, "Waiting for progbit to assert timed out\n");
+               etm_lock(t);
+               return -EFAULT;
+       }
+
+       etm_setup_address_range(t, 1, (unsigned long)_stext,
+                       (unsigned long)_etext, 0, 0);
+       etm_writel(t, 0, ETMR_TRACEENCTRL2);
+       etm_writel(t, 0, ETMR_TRACESSCTRL);
+       etm_writel(t, 0x6f, ETMR_TRACEENEVT);
+
+       v &= ~ETMCTRL_PROGRAM;
+       v |= ETMCTRL_PORTSEL;
+
+       etm_writel(t, v, ETMR_CTRL);
+
+       timeout = TRACER_TIMEOUT;
+       while (etm_readl(t, ETMR_CTRL) & ETMCTRL_PROGRAM && --timeout)
+               ;
+       if (!timeout) {
+               dev_dbg(t->dev, "Waiting for progbit to deassert timed out\n");
+               etm_lock(t);
+               return -EFAULT;
+       }
+
+       etm_lock(t);
+
+       t->flags |= TRACER_RUNNING;
+
+       return 0;
+}
+
+static int trace_stop(struct tracectx *t)
+{
+       unsigned long timeout = TRACER_TIMEOUT;
+
+       etm_unlock(t);
+
+       etm_writel(t, 0x440, ETMR_CTRL);
+       while (!(etm_readl(t, ETMR_CTRL) & ETMCTRL_PROGRAM) && --timeout)
+               ;
+       if (!timeout) {
+               dev_dbg(t->dev, "Waiting for progbit to assert timed out\n");
+               etm_lock(t);
+               return -EFAULT;
+       }
+
+       etm_lock(t);
+
+       etb_unlock(t);
+       etb_writel(t, ETBFF_MANUAL_FLUSH, ETBR_FORMATTERCTRL);
+
+       timeout = TRACER_TIMEOUT;
+       while (etb_readl(t, ETBR_FORMATTERCTRL) &
+                       ETBFF_MANUAL_FLUSH && --timeout)
+               ;
+       if (!timeout) {
+               dev_dbg(t->dev, "Waiting for formatter flush to commence "
+                               "timed out\n");
+               etb_lock(t);
+               return -EFAULT;
+       }
+
+       etb_writel(t, 0, ETBR_CTRL);
+
+       etb_lock(t);
+
+       t->flags &= ~TRACER_RUNNING;
+
+       return 0;
+}
+
+static int etb_getdatalen(struct tracectx *t)
+{
+       u32 v;
+       int rp, wp;
+
+       v = etb_readl(t, ETBR_STATUS);
+
+       if (v & 1)
+               return t->etb_bufsz;
+
+       rp = etb_readl(t, ETBR_READADDR);
+       wp = etb_readl(t, ETBR_WRITEADDR);
+
+       if (rp > wp) {
+               etb_writel(t, 0, ETBR_READADDR);
+               etb_writel(t, 0, ETBR_WRITEADDR);
+
+               return 0;
+       }
+
+       return wp - rp;
+}
+
+/* sysrq+v will always stop the running trace and leave it at that */
+static void etm_dump(void)
+{
+       struct tracectx *t = &tracer;
+       u32 first = 0;
+       int length;
+
+       if (!t->etb_regs) {
+               printk(KERN_INFO "No tracing hardware found\n");
+               return;
+       }
+
+       if (trace_isrunning(t))
+               trace_stop(t);
+
+       etb_unlock(t);
+
+       length = etb_getdatalen(t);
+
+       if (length == t->etb_bufsz)
+               first = etb_readl(t, ETBR_WRITEADDR);
+
+       etb_writel(t, first, ETBR_READADDR);
+
+       printk(KERN_INFO "Trace buffer contents length: %d\n", length);
+       printk(KERN_INFO "--- ETB buffer begin ---\n");
+       for (; length; length--)
+               printk("%08x", cpu_to_be32(etb_readl(t, ETBR_READMEM)));
+       printk(KERN_INFO "\n--- ETB buffer end ---\n");
+
+       /* deassert the overflow bit */
+       etb_writel(t, 1, ETBR_CTRL);
+       etb_writel(t, 0, ETBR_CTRL);
+
+       etb_writel(t, 0, ETBR_TRIGGERCOUNT);
+       etb_writel(t, 0, ETBR_READADDR);
+       etb_writel(t, 0, ETBR_WRITEADDR);
+
+       etb_lock(t);
+}
+
+static void sysrq_etm_dump(int key, struct tty_struct *tty)
+{
+       dev_dbg(tracer.dev, "Dumping ETB buffer\n");
+       etm_dump();
+}
+
+static struct sysrq_key_op sysrq_etm_op = {
+       .handler = sysrq_etm_dump,
+       .help_msg = "ETM buffer dump",
+       .action_msg = "etm",
+};
+
+static int etb_open(struct inode *inode, struct file *file)
+{
+       if (!tracer.etb_regs)
+               return -ENODEV;
+
+       file->private_data = &tracer;
+
+       return nonseekable_open(inode, file);
+}
+
+static ssize_t etb_read(struct file *file, char __user *data,
+               size_t len, loff_t *ppos)
+{
+       int total, i;
+       long length;
+       struct tracectx *t = file->private_data;
+       u32 first = 0;
+       u32 *buf;
+
+       mutex_lock(&t->mutex);
+
+       if (trace_isrunning(t)) {
+               length = 0;
+               goto out;
+       }
+
+       etb_unlock(t);
+
+       total = etb_getdatalen(t);
+       if (total == t->etb_bufsz)
+               first = etb_readl(t, ETBR_WRITEADDR);
+
+       etb_writel(t, first, ETBR_READADDR);
+
+       length = min(total * 4, (int)len);
+       buf = vmalloc(length);
+
+       dev_dbg(t->dev, "ETB buffer length: %d\n", total);
+       dev_dbg(t->dev, "ETB status reg: %x\n", etb_readl(t, ETBR_STATUS));
+       for (i = 0; i < length / 4; i++)
+               buf[i] = etb_readl(t, ETBR_READMEM);
+
+       /* the only way to deassert overflow bit in ETB status is this */
+       etb_writel(t, 1, ETBR_CTRL);
+       etb_writel(t, 0, ETBR_CTRL);
+
+       etb_writel(t, 0, ETBR_WRITEADDR);
+       etb_writel(t, 0, ETBR_READADDR);
+       etb_writel(t, 0, ETBR_TRIGGERCOUNT);
+
+       etb_lock(t);
+
+       length -= copy_to_user(data, buf, length);
+       vfree(buf);
+
+out:
+       mutex_unlock(&t->mutex);
+
+       return length;
+}
+
+static int etb_release(struct inode *inode, struct file *file)
+{
+       /* there's nothing to do here, actually */
+       return 0;
+}
+
+static const struct file_operations etb_fops = {
+       .owner = THIS_MODULE,
+       .read = etb_read,
+       .open = etb_open,
+       .release = etb_release,
+};
+
+static struct miscdevice etb_miscdev = {
+       .name = "tracebuf",
+       .minor = 0,
+       .fops = &etb_fops,
+};
+
+static int __init etb_probe(struct amba_device *dev, struct amba_id *id)
+{
+       struct tracectx *t = &tracer;
+       int ret = 0;
+
+       ret = amba_request_regions(dev, NULL);
+       if (ret)
+               goto out;
+
+       t->etb_regs = ioremap_nocache(dev->res.start, resource_size(&dev->res));
+       if (!t->etb_regs) {
+               ret = -ENOMEM;
+               goto out_release;
+       }
+
+       amba_set_drvdata(dev, t);
+
+       etb_miscdev.parent = &dev->dev;
+
+       ret = misc_register(&etb_miscdev);
+       if (ret)
+               goto out_unmap;
+
+       t->emu_clk = clk_get(&dev->dev, "emu_src_ck");
+       if (IS_ERR(t->emu_clk)) {
+               dev_dbg(&dev->dev, "Failed to obtain emu_src_ck.\n");
+               return -EFAULT;
+       }
+
+       clk_enable(t->emu_clk);
+
+       etb_unlock(t);
+       t->etb_bufsz = etb_readl(t, ETBR_DEPTH);
+       dev_dbg(&dev->dev, "Size: %x\n", t->etb_bufsz);
+
+       /* make sure trace capture is disabled */
+       etb_writel(t, 0, ETBR_CTRL);
+       etb_writel(t, 0x1000, ETBR_FORMATTERCTRL);
+       etb_lock(t);
+
+       dev_dbg(&dev->dev, "ETB AMBA driver initialized.\n");
+
+out:
+       return ret;
+
+out_unmap:
+       amba_set_drvdata(dev, NULL);
+       iounmap(t->etb_regs);
+
+out_release:
+       amba_release_regions(dev);
+
+       return ret;
+}
+
+static int etb_remove(struct amba_device *dev)
+{
+       struct tracectx *t = amba_get_drvdata(dev);
+
+       amba_set_drvdata(dev, NULL);
+
+       iounmap(t->etb_regs);
+       t->etb_regs = NULL;
+
+       clk_disable(t->emu_clk);
+       clk_put(t->emu_clk);
+
+       amba_release_regions(dev);
+
+       return 0;
+}
+
+static struct amba_id etb_ids[] = {
+       {
+               .id     = 0x0003b907,
+               .mask   = 0x0007ffff,
+       },
+       { 0, 0 },
+};
+
+static struct amba_driver etb_driver = {
+       .drv            = {
+               .name   = "etb",
+               .owner  = THIS_MODULE,
+       },
+       .probe          = etb_probe,
+       .remove         = etb_remove,
+       .id_table       = etb_ids,
+};
+
+/* use a sysfs file "trace_running" to start/stop tracing */
+static ssize_t trace_running_show(struct kobject *kobj,
+                                 struct kobj_attribute *attr,
+                                 char *buf)
+{
+       return sprintf(buf, "%x\n", trace_isrunning(&tracer));
+}
+
+static ssize_t trace_running_store(struct kobject *kobj,
+                                  struct kobj_attribute *attr,
+                                  const char *buf, size_t n)
+{
+       unsigned int value;
+       int ret;
+
+       if (sscanf(buf, "%u", &value) != 1)
+               return -EINVAL;
+
+       mutex_lock(&tracer.mutex);
+       ret = value ? trace_start(&tracer) : trace_stop(&tracer);
+       mutex_unlock(&tracer.mutex);
+
+       return ret ? : n;
+}
+
+static struct kobj_attribute trace_running_attr =
+       __ATTR(trace_running, 0644, trace_running_show, trace_running_store);
+
+static ssize_t trace_info_show(struct kobject *kobj,
+                                 struct kobj_attribute *attr,
+                                 char *buf)
+{
+       u32 etb_wa, etb_ra, etb_st, etb_fc, etm_ctrl, etm_st;
+       int datalen;
+
+       etb_unlock(&tracer);
+       datalen = etb_getdatalen(&tracer);
+       etb_wa = etb_readl(&tracer, ETBR_WRITEADDR);
+       etb_ra = etb_readl(&tracer, ETBR_READADDR);
+       etb_st = etb_readl(&tracer, ETBR_STATUS);
+       etb_fc = etb_readl(&tracer, ETBR_FORMATTERCTRL);
+       etb_lock(&tracer);
+
+       etm_unlock(&tracer);
+       etm_ctrl = etm_readl(&tracer, ETMR_CTRL);
+       etm_st = etm_readl(&tracer, ETMR_STATUS);
+       etm_lock(&tracer);
+
+       return sprintf(buf, "Trace buffer len: %d\nComparator pairs: %d\n"
+                       "ETBR_WRITEADDR:\t%08x\n"
+                       "ETBR_READADDR:\t%08x\n"
+                       "ETBR_STATUS:\t%08x\n"
+                       "ETBR_FORMATTERCTRL:\t%08x\n"
+                       "ETMR_CTRL:\t%08x\n"
+                       "ETMR_STATUS:\t%08x\n",
+                       datalen,
+                       tracer.ncmppairs,
+                       etb_wa,
+                       etb_ra,
+                       etb_st,
+                       etb_fc,
+                       etm_ctrl,
+                       etm_st
+                       );
+}
+
+static struct kobj_attribute trace_info_attr =
+       __ATTR(trace_info, 0444, trace_info_show, NULL);
+
+static ssize_t trace_mode_show(struct kobject *kobj,
+                                 struct kobj_attribute *attr,
+                                 char *buf)
+{
+       return sprintf(buf, "%d %d\n",
+                       !!(tracer.flags & TRACER_CYCLE_ACC),
+                       tracer.etm_portsz);
+}
+
+static ssize_t trace_mode_store(struct kobject *kobj,
+                                  struct kobj_attribute *attr,
+                                  const char *buf, size_t n)
+{
+       unsigned int cycacc, portsz;
+
+       if (sscanf(buf, "%u %u", &cycacc, &portsz) != 2)
+               return -EINVAL;
+
+       mutex_lock(&tracer.mutex);
+       if (cycacc)
+               tracer.flags |= TRACER_CYCLE_ACC;
+       else
+               tracer.flags &= ~TRACER_CYCLE_ACC;
+
+       tracer.etm_portsz = portsz & 0x0f;
+       mutex_unlock(&tracer.mutex);
+
+       return n;
+}
+
+static struct kobj_attribute trace_mode_attr =
+       __ATTR(trace_mode, 0644, trace_mode_show, trace_mode_store);
+
+static int __init etm_probe(struct amba_device *dev, struct amba_id *id)
+{
+       struct tracectx *t = &tracer;
+       int ret = 0;
+
+       if (t->etm_regs) {
+               dev_dbg(&dev->dev, "ETM already initialized\n");
+               ret = -EBUSY;
+               goto out;
+       }
+
+       ret = amba_request_regions(dev, NULL);
+       if (ret)
+               goto out;
+
+       t->etm_regs = ioremap_nocache(dev->res.start, resource_size(&dev->res));
+       if (!t->etm_regs) {
+               ret = -ENOMEM;
+               goto out_release;
+       }
+
+       amba_set_drvdata(dev, t);
+
+       mutex_init(&t->mutex);
+       t->dev = &dev->dev;
+       t->flags = TRACER_CYCLE_ACC;
+       t->etm_portsz = 1;
+
+       etm_unlock(t);
+       ret = etm_readl(t, CSCR_PRSR);
+
+       t->ncmppairs = etm_readl(t, ETMR_CONFCODE) & 0xf;
+       etm_writel(t, 0x440, ETMR_CTRL);
+       etm_lock(t);
+
+       ret = sysfs_create_file(&dev->dev.kobj,
+                       &trace_running_attr.attr);
+       if (ret)
+               goto out_unmap;
+
+       /* failing to create any of these two is not fatal */
+       ret = sysfs_create_file(&dev->dev.kobj, &trace_info_attr.attr);
+       if (ret)
+               dev_dbg(&dev->dev, "Failed to create trace_info in sysfs\n");
+
+       ret = sysfs_create_file(&dev->dev.kobj, &trace_mode_attr.attr);
+       if (ret)
+               dev_dbg(&dev->dev, "Failed to create trace_mode in sysfs\n");
+
+       dev_dbg(t->dev, "ETM AMBA driver initialized.\n");
+
+out:
+       return ret;
+
+out_unmap:
+       amba_set_drvdata(dev, NULL);
+       iounmap(t->etm_regs);
+
+out_release:
+       amba_release_regions(dev);
+
+       return ret;
+}
+
+static int etm_remove(struct amba_device *dev)
+{
+       struct tracectx *t = amba_get_drvdata(dev);
+
+       amba_set_drvdata(dev, NULL);
+
+       iounmap(t->etm_regs);
+       t->etm_regs = NULL;
+
+       amba_release_regions(dev);
+
+       sysfs_remove_file(&dev->dev.kobj, &trace_running_attr.attr);
+       sysfs_remove_file(&dev->dev.kobj, &trace_info_attr.attr);
+       sysfs_remove_file(&dev->dev.kobj, &trace_mode_attr.attr);
+
+       return 0;
+}
+
+static struct amba_id etm_ids[] = {
+       {
+               .id     = 0x0003b921,
+               .mask   = 0x0007ffff,
+       },
+       { 0, 0 },
+};
+
+static struct amba_driver etm_driver = {
+       .drv            = {
+               .name   = "etm",
+               .owner  = THIS_MODULE,
+       },
+       .probe          = etm_probe,
+       .remove         = etm_remove,
+       .id_table       = etm_ids,
+};
+
+static int __init etm_init(void)
+{
+       int retval;
+
+       retval = amba_driver_register(&etb_driver);
+       if (retval) {
+               printk(KERN_ERR "Failed to register etb\n");
+               return retval;
+       }
+
+       retval = amba_driver_register(&etm_driver);
+       if (retval) {
+               amba_driver_unregister(&etb_driver);
+               printk(KERN_ERR "Failed to probe etm\n");
+               return retval;
+       }
+
+       /* not being able to install this handler is not fatal */
+       (void)register_sysrq_key('v', &sysrq_etm_op);
+
+       return 0;
+}
+
+device_initcall(etm_init);
+
index e5dfc28..573b803 100644 (file)
@@ -32,7 +32,7 @@
  * numbers for r1.
  *
  */
-       .section ".text.head", "ax"
+       __HEAD
 ENTRY(stext)
        setmode PSR_F_BIT | PSR_I_BIT | SVC_MODE, r9 @ ensure svc mode
                                                @ and irqs disabled
index 38ccbe1..eb62bf9 100644 (file)
@@ -74,7 +74,7 @@
  * crap here - that's what the boot loader (or in extreme, well justified
  * circumstances, zImage) is for.
  */
-       .section ".text.head", "ax"
+       __HEAD
 ENTRY(stext)
        setmode PSR_F_BIT | PSR_I_BIT | SVC_MODE, r9 @ ensure svc mode
                                                @ and irqs disabled
index 8ac9b84..3464859 100644 (file)
@@ -22,47 +22,42 @@ static unsigned int isa_membase, isa_portbase, isa_portshift;
 
 static ctl_table ctl_isa_vars[4] = {
        {
-               .ctl_name       = BUS_ISA_MEM_BASE,
                .procname       = "membase",
                .data           = &isa_membase, 
                .maxlen         = sizeof(isa_membase),
                .mode           = 0444,
-               .proc_handler   = &proc_dointvec,
+               .proc_handler   = proc_dointvec,
        }, {
-               .ctl_name       = BUS_ISA_PORT_BASE,
                .procname       = "portbase",
                .data           = &isa_portbase, 
                .maxlen         = sizeof(isa_portbase),
                .mode           = 0444,
-               .proc_handler   = &proc_dointvec,
+               .proc_handler   = proc_dointvec,
        }, {
-               .ctl_name       = BUS_ISA_PORT_SHIFT,
                .procname       = "portshift",
                .data           = &isa_portshift, 
                .maxlen         = sizeof(isa_portshift),
                .mode           = 0444,
-               .proc_handler   = &proc_dointvec,
-       }, {0}
+               .proc_handler   = proc_dointvec,
+       }, {}
 };
 
 static struct ctl_table_header *isa_sysctl_header;
 
 static ctl_table ctl_isa[2] = {
        {
-               .ctl_name       = CTL_BUS_ISA,
                .procname       = "isa",
                .mode           = 0555,
                .child          = ctl_isa_vars,
-       }, {0}
+       }, {}
 };
 
 static ctl_table ctl_bus[2] = {
        {
-               .ctl_name       = CTL_BUS,
                .procname       = "bus",
                .mode           = 0555,
                .child          = ctl_isa,
-       }, {0}
+       }, {}
 };
 
 void __init
index aecf87d..71151bd 100644 (file)
@@ -24,13 +24,11 @@ SECTIONS
 #else
        . = PAGE_OFFSET + TEXT_OFFSET;
 #endif
-       .text.head : {
-               _stext = .;
-               _sinittext = .;
-               *(.text.head)
-       }
 
        .init : {                       /* Init code and data           */
+               _stext = .;
+               _sinittext = .;
+                       HEAD_TEXT
                        INIT_TEXT
                _einittext = .;
                __proc_info_begin = .;
@@ -42,43 +40,31 @@ SECTIONS
                __tagtable_begin = .;
                        *(.taglist.init)
                __tagtable_end = .;
-               . = ALIGN(16);
-               __setup_start = .;
-                       *(.init.setup)
-               __setup_end = .;
+
+               INIT_SETUP(16)
+
                __early_begin = .;
                        *(.early_param.init)
                __early_end = .;
-               __initcall_start = .;
-                       INITCALLS
-               __initcall_end = .;
-               __con_initcall_start = .;
-                       *(.con_initcall.init)
-               __con_initcall_end = .;
-               __security_initcall_start = .;
-                       *(.security_initcall.init)
-               __security_initcall_end = .;
-#ifdef CONFIG_BLK_DEV_INITRD
-               . = ALIGN(32);
-               __initramfs_start = .;
-                       usr/built-in.o(.init.ramfs)
-               __initramfs_end = .;
-#endif
-               . = ALIGN(PAGE_SIZE);
-               __per_cpu_load = .;
-               __per_cpu_start = .;
-                       *(.data.percpu.page_aligned)
-                       *(.data.percpu)
-                       *(.data.percpu.shared_aligned)
-               __per_cpu_end = .;
+
+               INIT_CALLS
+               CON_INITCALL
+               SECURITY_INITCALL
+               INIT_RAM_FS
+
 #ifndef CONFIG_XIP_KERNEL
                __init_begin = _stext;
                INIT_DATA
-               . = ALIGN(PAGE_SIZE);
-               __init_end = .;
 #endif
        }
 
+       PERCPU(PAGE_SIZE)
+
+#ifndef CONFIG_XIP_KERNEL
+       . = ALIGN(PAGE_SIZE);
+       __init_end = .;
+#endif
+
        /DISCARD/ : {                   /* Exit code and data           */
                EXIT_TEXT
                EXIT_DATA
@@ -157,7 +143,7 @@ SECTIONS
                 * first, the init task union, aligned
                 * to an 8192 byte boundary.
                 */
-               *(.data.init_task)
+               INIT_TASK_DATA(THREAD_SIZE)
 
 #ifdef CONFIG_XIP_KERNEL
                . = ALIGN(PAGE_SIZE);
@@ -167,17 +153,8 @@ SECTIONS
                __init_end = .;
 #endif
 
-               . = ALIGN(PAGE_SIZE);
-               __nosave_begin = .;
-               *(.data.nosave)
-               . = ALIGN(PAGE_SIZE);
-               __nosave_end = .;
-
-               /*
-                * then the cacheline aligned data
-                */
-               . = ALIGN(32);
-               *(.data.cacheline_aligned)
+               NOSAVE_DATA
+               CACHELINE_ALIGNED_DATA(32)
 
                /*
                 * The exception fixup table (might need resorting at runtime)
@@ -256,20 +233,10 @@ SECTIONS
        }
 #endif
 
-       .bss : {
-               __bss_start = .;        /* BSS                          */
-               *(.bss)
-               *(COMMON)
-               __bss_stop = .;
-               _end = .;
-       }
-                                       /* Stabs debugging sections.    */
-       .stab 0 : { *(.stab) }
-       .stabstr 0 : { *(.stabstr) }
-       .stab.excl 0 : { *(.stab.excl) }
-       .stab.exclstr 0 : { *(.stab.exclstr) }
-       .stab.index 0 : { *(.stab.index) }
-       .stab.indexstr 0 : { *(.stab.indexstr) }
+       BSS_SECTION(0, 0, 0)
+       _end = .;
+
+       STABS_DEBUG
        .comment 0 : { *(.comment) }
 }
 
index 2fd8843..0b2ee95 100644 (file)
@@ -1,5 +1,20 @@
 if ARCH_AT91
 
+config HAVE_AT91_DATAFLASH_CARD
+       bool
+
+config HAVE_NAND_ATMEL_BUSWIDTH_16
+       bool
+
+config HAVE_AT91_USART3
+       bool
+
+config HAVE_AT91_USART4
+       bool
+
+config HAVE_AT91_USART5
+       bool
+
 menu "Atmel AT91 System-on-Chip"
 
 choice
@@ -10,54 +25,69 @@ config ARCH_AT91RM9200
        select CPU_ARM920T
        select GENERIC_TIME
        select GENERIC_CLOCKEVENTS
+       select HAVE_AT91_USART3
 
 config ARCH_AT91SAM9260
        bool "AT91SAM9260 or AT91SAM9XE"
        select CPU_ARM926T
        select GENERIC_TIME
        select GENERIC_CLOCKEVENTS
+       select HAVE_AT91_USART3
+       select HAVE_AT91_USART4
+       select HAVE_AT91_USART5
 
 config ARCH_AT91SAM9261
        bool "AT91SAM9261"
        select CPU_ARM926T
        select GENERIC_TIME
        select GENERIC_CLOCKEVENTS
+       select HAVE_FB_ATMEL
 
 config ARCH_AT91SAM9G10
        bool "AT91SAM9G10"
        select CPU_ARM926T
        select GENERIC_TIME
        select GENERIC_CLOCKEVENTS
+       select HAVE_FB_ATMEL
 
 config ARCH_AT91SAM9263
        bool "AT91SAM9263"
        select CPU_ARM926T
        select GENERIC_TIME
        select GENERIC_CLOCKEVENTS
+       select HAVE_FB_ATMEL
 
 config ARCH_AT91SAM9RL
        bool "AT91SAM9RL"
        select CPU_ARM926T
        select GENERIC_TIME
        select GENERIC_CLOCKEVENTS
+       select HAVE_AT91_USART3
+       select HAVE_FB_ATMEL
 
 config ARCH_AT91SAM9G20
        bool "AT91SAM9G20"
        select CPU_ARM926T
        select GENERIC_TIME
        select GENERIC_CLOCKEVENTS
+       select HAVE_AT91_USART3
+       select HAVE_AT91_USART4
+       select HAVE_AT91_USART5
 
 config ARCH_AT91SAM9G45
        bool "AT91SAM9G45"
        select CPU_ARM926T
        select GENERIC_TIME
        select GENERIC_CLOCKEVENTS
+       select HAVE_AT91_USART3
+       select HAVE_FB_ATMEL
 
 config ARCH_AT91CAP9
        bool "AT91CAP9"
        select CPU_ARM926T
        select GENERIC_TIME
        select GENERIC_CLOCKEVENTS
+       select HAVE_FB_ATMEL
 
 config ARCH_AT91X40
        bool "AT91x40"
@@ -76,93 +106,88 @@ comment "AT91RM9200 Board Type"
 
 config MACH_ONEARM
        bool "Ajeco 1ARM Single Board Computer"
-       depends on ARCH_AT91RM9200
        help
          Select this if you are using Ajeco's 1ARM Single Board Computer.
          <http://www.ajeco.fi/products.htm>
 
 config ARCH_AT91RM9200DK
        bool "Atmel AT91RM9200-DK Development board"
-       depends on ARCH_AT91RM9200
+       select HAVE_AT91_DATAFLASH_CARD
        help
          Select this if you are using Atmel's AT91RM9200-DK Development board.
          (Discontinued)
 
 config MACH_AT91RM9200EK
        bool "Atmel AT91RM9200-EK Evaluation Kit"
-       depends on ARCH_AT91RM9200
+       select HAVE_AT91_DATAFLASH_CARD
        help
          Select this if you are using Atmel's AT91RM9200-EK Evaluation Kit.
          <http://www.atmel.com/dyn/products/tools_card.asp?tool_id=3507>
 
 config MACH_CSB337
        bool "Cogent CSB337"
-       depends on ARCH_AT91RM9200
        help
          Select this if you are using Cogent's CSB337 board.
          <http://www.cogcomp.com/csb_csb337.htm>
 
 config MACH_CSB637
        bool "Cogent CSB637"
-       depends on ARCH_AT91RM9200
        help
          Select this if you are using Cogent's CSB637 board.
          <http://www.cogcomp.com/csb_csb637.htm>
 
 config MACH_CARMEVA
        bool "Conitec ARM&EVA"
-       depends on ARCH_AT91RM9200
        help
          Select this if you are using Conitec's AT91RM9200-MCU-Module.
          <http://www.conitec.net/english/linuxboard.htm>
 
 config MACH_ATEB9200
        bool "Embest ATEB9200"
-       depends on ARCH_AT91RM9200
        help
          Select this if you are using Embest's ATEB9200 board.
          <http://www.embedinfo.com/english/product/ATEB9200.asp>
 
 config MACH_KB9200
        bool "KwikByte KB920x"
-       depends on ARCH_AT91RM9200
        help
          Select this if you are using KwikByte's KB920x board.
          <http://kwikbyte.com/KB9202_description_new.htm>
 
 config MACH_PICOTUX2XX
        bool "picotux 200"
-       depends on ARCH_AT91RM9200
        help
          Select this if you are using a picotux 200.
          <http://www.picotux.com/>
 
 config MACH_KAFA
        bool "Sperry-Sun KAFA board"
-       depends on ARCH_AT91RM9200
        help
          Select this if you are using Sperry-Sun's KAFA board.
 
 config MACH_ECBAT91
        bool "emQbit ECB_AT91 SBC"
-       depends on ARCH_AT91RM9200
+       select HAVE_AT91_DATAFLASH_CARD
        help
          Select this if you are using emQbit's ECB_AT91 board.
          <http://wiki.emqbit.com/free-ecb-at91>
 
 config MACH_YL9200
        bool "ucDragon YL-9200"
-       depends on ARCH_AT91RM9200
        help
          Select this if you are using the ucDragon YL-9200 board.
 
 config MACH_CPUAT91
        bool "Eukrea CPUAT91"
-       depends on ARCH_AT91RM9200
        help
          Select this if you are using the Eukrea Electromatique's
          CPUAT91 board <http://www.eukrea.com/>.
 
+config MACH_ECO920
+       bool "eco920"
+       help
+         Select this if you are using the eco920 board
+
 endif
 
 # ----------------------------------------------------------
@@ -173,7 +198,6 @@ comment "AT91SAM9260 Variants"
 
 config ARCH_AT91SAM9260_SAM9XE
        bool "AT91SAM9XE"
-       depends on ARCH_AT91SAM9260
        help
          Select this if you are using Atmel's AT91SAM9XE System-on-Chip.
          They are basically AT91SAM9260s with various sizes of embedded Flash.
@@ -182,28 +206,27 @@ comment "AT91SAM9260 / AT91SAM9XE Board Type"
 
 config MACH_AT91SAM9260EK
        bool "Atmel AT91SAM9260-EK / AT91SAM9XE Evaluation Kit"
-       depends on ARCH_AT91SAM9260
+       select HAVE_AT91_DATAFLASH_CARD
+       select HAVE_NAND_ATMEL_BUSWIDTH_16
        help
          Select this if you are using Atmel's AT91SAM9260-EK or AT91SAM9XE Evaluation Kit
          <http://www.atmel.com/dyn/products/tools_card.asp?tool_id=3933>
 
 config MACH_CAM60
        bool "KwikByte KB9260 (CAM60) board"
-       depends on ARCH_AT91SAM9260
        help
          Select this if you are using KwikByte's KB9260 (CAM60) board based on the Atmel AT91SAM9260.
          <http://www.kwikbyte.com/KB9260.html>
 
 config MACH_SAM9_L9260
        bool "Olimex SAM9-L9260 board"
-       depends on ARCH_AT91SAM9260
+       select HAVE_AT91_DATAFLASH_CARD
        help
          Select this if you are using Olimex's SAM9-L9260 board based on the Atmel AT91SAM9260.
          <http://www.olimex.com/dev/sam9-L9260.html>
 
 config MACH_AFEB9260
        bool "Custom afeb9260 board v1"
-       depends on ARCH_AT91SAM9260
        help
          Select this if you are using custom afeb9260 board based on
          open hardware design. Select this for revision 1 of the board.
@@ -212,21 +235,18 @@ config MACH_AFEB9260
 
 config MACH_USB_A9260
        bool "CALAO USB-A9260"
-       depends on ARCH_AT91SAM9260
        help
          Select this if you are using a Calao Systems USB-A9260.
          <http://www.calao-systems.com>
 
 config MACH_QIL_A9260
        bool "CALAO QIL-A9260 board"
-       depends on ARCH_AT91SAM9260
        help
          Select this if you are using a Calao Systems QIL-A9260 Board.
          <http://www.calao-systems.com>
 
 config MACH_CPU9260
        bool "Eukrea CPU9260 board"
-       depends on ARCH_AT91SAM9260
        help
          Select this if you are using a Eukrea Electromatique's
          CPU9260 Board <http://www.eukrea.com/>
@@ -241,7 +261,8 @@ comment "AT91SAM9261 Board Type"
 
 config MACH_AT91SAM9261EK
        bool "Atmel AT91SAM9261-EK Evaluation Kit"
-       depends on ARCH_AT91SAM9261
+       select HAVE_AT91_DATAFLASH_CARD
+       select HAVE_NAND_ATMEL_BUSWIDTH_16
        help
          Select this if you are using Atmel's AT91SAM9261-EK Evaluation Kit.
          <http://www.atmel.com/dyn/products/tools_card.asp?tool_id=3820>
@@ -256,7 +277,8 @@ comment "AT91SAM9G10 Board Type"
 
 config MACH_AT91SAM9G10EK
        bool "Atmel AT91SAM9G10-EK Evaluation Kit"
-       depends on ARCH_AT91SAM9G10
+       select HAVE_AT91_DATAFLASH_CARD
+       select HAVE_NAND_ATMEL_BUSWIDTH_16
        help
          Select this if you are using Atmel's AT91SAM9G10-EK Evaluation Kit.
          <http://www.atmel.com/dyn/products/tools_card.asp?tool_id=4588>
@@ -271,21 +293,21 @@ comment "AT91SAM9263 Board Type"
 
 config MACH_AT91SAM9263EK
        bool "Atmel AT91SAM9263-EK Evaluation Kit"
-       depends on ARCH_AT91SAM9263
+       select HAVE_AT91_DATAFLASH_CARD
+       select HAVE_NAND_ATMEL_BUSWIDTH_16
        help
          Select this if you are using Atmel's AT91SAM9263-EK Evaluation Kit.
          <http://www.atmel.com/dyn/products/tools_card.asp?tool_id=4057>
 
 config MACH_USB_A9263
        bool "CALAO USB-A9263"
-       depends on ARCH_AT91SAM9263
        help
          Select this if you are using a Calao Systems USB-A9263.
          <http://www.calao-systems.com>
 
 config MACH_NEOCORE926
        bool "Adeneo NEOCORE926"
-       depends on ARCH_AT91SAM9263
+       select HAVE_AT91_DATAFLASH_CARD
        help
          Select this if you are using the Adeneo Neocore 926 board.
 
@@ -299,7 +321,6 @@ comment "AT91SAM9RL Board Type"
 
 config MACH_AT91SAM9RLEK
        bool "Atmel AT91SAM9RL-EK Evaluation Kit"
-       depends on ARCH_AT91SAM9RL
        help
          Select this if you are using Atmel's AT91SAM9RL-EK Evaluation Kit.
 
@@ -313,14 +334,15 @@ comment "AT91SAM9G20 Board Type"
 
 config MACH_AT91SAM9G20EK
        bool "Atmel AT91SAM9G20-EK Evaluation Kit"
-       depends on ARCH_AT91SAM9G20
+       select HAVE_AT91_DATAFLASH_CARD
+       select HAVE_NAND_ATMEL_BUSWIDTH_16
        help
          Select this if you are using Atmel's AT91SAM9G20-EK Evaluation Kit
          that embeds only one SD/MMC slot.
 
 config MACH_AT91SAM9G20EK_2MMC
        bool "Atmel AT91SAM9G20-EK Evaluation Kit with 2 SD/MMC Slots"
-       depends on ARCH_AT91SAM9G20
+       select HAVE_NAND_ATMEL_BUSWIDTH_16
        help
          Select this if you are using an Atmel AT91SAM9G20-EK Evaluation Kit
          with 2 SD/MMC Slots. This is the case for AT91SAM9G20-EK rev. C and
@@ -328,7 +350,6 @@ config MACH_AT91SAM9G20EK_2MMC
 
 config MACH_CPU9G20
        bool "Eukrea CPU9G20 board"
-       depends on ARCH_AT91SAM9G20
        help
          Select this if you are using a Eukrea Electromatique's
          CPU9G20 Board <http://www.eukrea.com/>
@@ -343,7 +364,7 @@ comment "AT91SAM9G45 Board Type"
 
 config MACH_AT91SAM9G45EKES
        bool "Atmel AT91SAM9G45-EKES Evaluation Kit"
-       depends on ARCH_AT91SAM9G45
+       select HAVE_NAND_ATMEL_BUSWIDTH_16
        help
          Select this if you are using Atmel's AT91SAM9G45-EKES Evaluation Kit.
          "ES" at the end of the name means that this board is an
@@ -359,7 +380,8 @@ comment "AT91CAP9 Board Type"
 
 config MACH_AT91CAP9ADK
        bool "Atmel AT91CAP9A-DK Evaluation Kit"
-       depends on ARCH_AT91CAP9
+       select HAVE_AT91_DATAFLASH_CARD
+       select HAVE_NAND_ATMEL_BUSWIDTH_16
        help
          Select this if you are using Atmel's AT91CAP9A-DK Evaluation Kit.
          <http://www.atmel.com/dyn/products/tools_card.asp?tool_id=4138>
@@ -388,13 +410,13 @@ comment "AT91 Board Options"
 
 config MTD_AT91_DATAFLASH_CARD
        bool "Enable DataFlash Card support"
-       depends on (ARCH_AT91RM9200DK || MACH_AT91RM9200EK || MACH_AT91SAM9260EK || MACH_AT91SAM9261EK || MACH_AT91SAM9G10EK || MACH_AT91SAM9263EK || MACH_AT91SAM9G20EK || MACH_ECBAT91 || MACH_SAM9_L9260 || MACH_AT91CAP9ADK || MACH_NEOCORE926)
+       depends on HAVE_AT91_DATAFLASH_CARD
        help
          Enable support for the DataFlash card.
 
 config MTD_NAND_ATMEL_BUSWIDTH_16
        bool "Enable 16-bit data bus interface to NAND flash"
-       depends on (MACH_AT91SAM9260EK || MACH_AT91SAM9261EK || MACH_AT91SAM9G10EK || MACH_AT91SAM9263EK || MACH_AT91SAM9G20EK || MACH_AT91SAM9G20EK_2MMC || MACH_AT91SAM9G45EKES || MACH_AT91CAP9ADK)
+       depends on HAVE_NAND_ATMEL_BUSWIDTH_16
        help
          On AT91SAM926x boards both types of NAND flash can be present
          (8 and 16 bit data bus width).
@@ -456,15 +478,15 @@ config AT91_EARLY_USART2
 
 config AT91_EARLY_USART3
        bool "USART3"
-       depends on (ARCH_AT91RM9200 || ARCH_AT91SAM9RL || ARCH_AT91SAM9260 || ARCH_AT91SAM9G20 || ARCH_AT91SAM9G45)
+       depends on HAVE_AT91_USART3
 
 config AT91_EARLY_USART4
        bool "USART4"
-       depends on ARCH_AT91SAM9260 || ARCH_AT91SAM9G20
+       depends on HAVE_AT91_USART4
 
 config AT91_EARLY_USART5
        bool "USART5"
-       depends on ARCH_AT91SAM9260 || ARCH_AT91SAM9G20
+       depends on HAVE_AT91_USART5
 
 endchoice
 
index ada440a..709fbad 100644 (file)
@@ -35,6 +35,7 @@ obj-$(CONFIG_MACH_PICOTUX2XX) += board-picotux200.o
 obj-$(CONFIG_MACH_ECBAT91)     += board-ecbat91.o
 obj-$(CONFIG_MACH_YL9200)      += board-yl-9200.o
 obj-$(CONFIG_MACH_CPUAT91)     += board-cpuat91.o
+obj-$(CONFIG_MACH_ECO920)      += board-eco920.o
 
 # AT91SAM9260 board-specific support
 obj-$(CONFIG_MACH_AT91SAM9260EK) += board-sam9260ek.o
@@ -77,6 +78,7 @@ obj-y                         += leds.o
 # Power Management
 obj-$(CONFIG_PM)               += pm.o
 obj-$(CONFIG_AT91_SLOW_CLOCK)  += pm_slowclock.o
+obj-$(CONFIG_CPU_IDLE) += cpuidle.o
 
 ifeq ($(CONFIG_PM_DEBUG),y)
 CFLAGS_pm.o += -DDEBUG
index 332b784..a57af3e 100644 (file)
@@ -131,6 +131,62 @@ void __init at91_add_device_usbh_ohci(struct at91_usbh_data *data) {}
 
 
 /* --------------------------------------------------------------------
+ *  USB Host HS (EHCI)
+ *  Needs an OHCI host for low and full speed management
+ * -------------------------------------------------------------------- */
+
+#if defined(CONFIG_USB_EHCI_HCD) || defined(CONFIG_USB_EHCI_HCD_MODULE)
+static u64 ehci_dmamask = DMA_BIT_MASK(32);
+static struct at91_usbh_data usbh_ehci_data;
+
+static struct resource usbh_ehci_resources[] = {
+       [0] = {
+               .start  = AT91SAM9G45_EHCI_BASE,
+               .end    = AT91SAM9G45_EHCI_BASE + SZ_1M - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = AT91SAM9G45_ID_UHPHS,
+               .end    = AT91SAM9G45_ID_UHPHS,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device at91_usbh_ehci_device = {
+       .name           = "atmel-ehci",
+       .id             = -1,
+       .dev            = {
+                               .dma_mask               = &ehci_dmamask,
+                               .coherent_dma_mask      = DMA_BIT_MASK(32),
+                               .platform_data          = &usbh_ehci_data,
+       },
+       .resource       = usbh_ehci_resources,
+       .num_resources  = ARRAY_SIZE(usbh_ehci_resources),
+};
+
+void __init at91_add_device_usbh_ehci(struct at91_usbh_data *data)
+{
+       int i;
+
+       if (!data)
+               return;
+
+       /* Enable VBus control for UHP ports */
+       for (i = 0; i < data->ports; i++) {
+               if (data->vbus_pin[i])
+                       at91_set_gpio_output(data->vbus_pin[i], 0);
+       }
+
+       usbh_ehci_data = *data;
+       at91_clock_associate("uhphs_clk", &at91_usbh_ehci_device.dev, "ehci_clk");
+       platform_device_register(&at91_usbh_ehci_device);
+}
+#else
+void __init at91_add_device_usbh_ehci(struct at91_usbh_data *data) {}
+#endif
+
+
+/* --------------------------------------------------------------------
  *  USB HS Device (Gadget)
  * -------------------------------------------------------------------- */
 
diff --git a/arch/arm/mach-at91/board-eco920.c b/arch/arm/mach-at91/board-eco920.c
new file mode 100644 (file)
index 0000000..295a966
--- /dev/null
@@ -0,0 +1,158 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/mtd/physmap.h>
+#include <linux/gpio.h>
+
+#include <asm/mach-types.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+
+#include <mach/board.h>
+#include <mach/at91rm9200_mc.h>
+#include "generic.h"
+
+static void __init eco920_map_io(void)
+{
+       at91rm9200_initialize(18432000, AT91RM9200_PQFP);
+
+       /* Setup the LEDs */
+       at91_init_leds(AT91_PIN_PB0, AT91_PIN_PB1);
+
+       /* DBGU on ttyS0. (Rx & Tx only */
+       at91_register_uart(0, 0, 0);
+
+       /* set serial console to ttyS0 (ie, DBGU) */
+       at91_set_serial_console(0);
+}
+
+static void __init eco920_init_irq(void)
+{
+       at91rm9200_init_interrupts(NULL);
+}
+
+static struct at91_eth_data __initdata eco920_eth_data = {
+       .phy_irq_pin    = AT91_PIN_PC2,
+       .is_rmii        = 1,
+};
+
+static struct at91_usbh_data __initdata eco920_usbh_data = {
+       .ports          = 1,
+};
+
+static struct at91_udc_data __initdata eco920_udc_data = {
+       .vbus_pin       = AT91_PIN_PB12,
+       .pullup_pin     = AT91_PIN_PB13,
+};
+
+static struct at91_mmc_data __initdata eco920_mmc_data = {
+       .slot_b         = 0,
+       .wire4          = 0,
+};
+
+static struct physmap_flash_data eco920_flash_data = {
+       .width  = 2,
+};
+
+static struct resource eco920_flash_resource = {
+       .start          = 0x11000000,
+       .end            = 0x11ffffff,
+       .flags          = IORESOURCE_MEM,
+};
+
+static struct platform_device eco920_flash = {
+       .name           = "physmap-flash",
+       .id             = 0,
+       .dev            = {
+               .platform_data  = &eco920_flash_data,
+       },
+       .resource       = &eco920_flash_resource,
+       .num_resources  = 1,
+};
+
+static struct resource at91_beeper_resources[] = {
+       [0] = {
+               .start          = AT91RM9200_BASE_TC3,
+               .end            = AT91RM9200_BASE_TC3 + 0x39,
+               .flags          = IORESOURCE_MEM,
+       },
+};
+
+static struct platform_device at91_beeper = {
+       .name           = "at91_beeper",
+       .id             = 0,
+       .resource       = at91_beeper_resources,
+       .num_resources  = ARRAY_SIZE(at91_beeper_resources),
+};
+
+static struct spi_board_info eco920_spi_devices[] = {
+       {       /* CAN controller */
+               .modalias       = "tlv5638",
+               .chip_select    = 3,
+               .max_speed_hz   = 20 * 1000 * 1000,
+               .mode           = SPI_CPHA,
+       },
+};
+
+static void __init eco920_board_init(void)
+{
+       at91_add_device_serial();
+       at91_add_device_eth(&eco920_eth_data);
+       at91_add_device_usbh(&eco920_usbh_data);
+       at91_add_device_udc(&eco920_udc_data);
+
+       at91_add_device_mmc(0, &eco920_mmc_data);
+       platform_device_register(&eco920_flash);
+
+       at91_sys_write(AT91_SMC_CSR(7), AT91_SMC_RWHOLD_(1)
+                               | AT91_SMC_RWSETUP_(1)
+                               | AT91_SMC_DBW_8
+                               | AT91_SMC_WSEN
+                               | AT91_SMC_NWS_(15));
+
+       at91_set_A_periph(AT91_PIN_PC6, 1);
+
+       at91_set_gpio_input(AT91_PIN_PA23, 0);
+       at91_set_deglitch(AT91_PIN_PA23, 1);
+
+/* Initialization of the Static Memory Controller for Chip Select 3 */
+       at91_sys_write(AT91_SMC_CSR(3),
+               AT91_SMC_DBW_16  |      /* 16 bit */
+               AT91_SMC_WSEN    |
+               AT91_SMC_NWS_(5) |      /* wait states */
+               AT91_SMC_TDF_(1)        /* float time */
+       );
+
+       at91_clock_associate("tc3_clk", &at91_beeper.dev, "at91_beeper");
+       at91_set_B_periph(AT91_PIN_PB6, 0);
+       platform_device_register(&at91_beeper);
+
+       at91_add_device_spi(eco920_spi_devices, ARRAY_SIZE(eco920_spi_devices));
+}
+
+MACHINE_START(ECO920, "eco920")
+       /* Maintainer: Sascha Hauer */
+       .phys_io        = AT91_BASE_SYS,
+       .io_pg_offst    = (AT91_VA_BASE_SYS >> 18) & 0xfffc,
+       .boot_params    = AT91_SDRAM_BASE + 0x100,
+       .timer          = &at91rm9200_timer,
+       .map_io         = eco920_map_io,
+       .init_irq       = eco920_init_irq,
+       .init_machine   = eco920_board_init,
+MACHINE_END
index 64c3843..1cf4d86 100644 (file)
@@ -366,6 +366,7 @@ static void __init ek_board_init(void)
        at91_add_device_serial();
        /* USB HS Host */
        at91_add_device_usbh_ohci(&ek_usbh_hs_data);
+       at91_add_device_usbh_ehci(&ek_usbh_hs_data);
        /* USB HS Device */
        at91_add_device_usba(&ek_usba_udc_data);
        /* SPI */
diff --git a/arch/arm/mach-at91/cpuidle.c b/arch/arm/mach-at91/cpuidle.c
new file mode 100644 (file)
index 0000000..1cfeac1
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * based on arch/arm/mach-kirkwood/cpuidle.c
+ *
+ * CPU idle support for AT91 SoC
+ *
+ * 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.
+ *
+ * The cpu idle uses wait-for-interrupt and RAM self refresh in order
+ * to implement two idle states -
+ * #1 wait-for-interrupt
+ * #2 wait-for-interrupt and RAM self refresh
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/cpuidle.h>
+#include <asm/proc-fns.h>
+#include <linux/io.h>
+
+#include "pm.h"
+
+#define AT91_MAX_STATES        2
+
+static DEFINE_PER_CPU(struct cpuidle_device, at91_cpuidle_device);
+
+static struct cpuidle_driver at91_idle_driver = {
+       .name =         "at91_idle",
+       .owner =        THIS_MODULE,
+};
+
+/* Actual code that puts the SoC in different idle states */
+static int at91_enter_idle(struct cpuidle_device *dev,
+                              struct cpuidle_state *state)
+{
+       struct timeval before, after;
+       int idle_time;
+       u32 saved_lpr;
+
+       local_irq_disable();
+       do_gettimeofday(&before);
+       if (state == &dev->states[0])
+               /* Wait for interrupt state */
+               cpu_do_idle();
+       else if (state == &dev->states[1]) {
+               asm("b 1f; .align 5; 1:");
+               asm("mcr p15, 0, r0, c7, c10, 4");      /* drain write buffer */
+               saved_lpr = sdram_selfrefresh_enable();
+               cpu_do_idle();
+               sdram_selfrefresh_disable(saved_lpr);
+       }
+       do_gettimeofday(&after);
+       local_irq_enable();
+       idle_time = (after.tv_sec - before.tv_sec) * USEC_PER_SEC +
+                       (after.tv_usec - before.tv_usec);
+       return idle_time;
+}
+
+/* Initialize CPU idle by registering the idle states */
+static int at91_init_cpuidle(void)
+{
+       struct cpuidle_device *device;
+
+       cpuidle_register_driver(&at91_idle_driver);
+
+       device = &per_cpu(at91_cpuidle_device, smp_processor_id());
+       device->state_count = AT91_MAX_STATES;
+
+       /* Wait for interrupt state */
+       device->states[0].enter = at91_enter_idle;
+       device->states[0].exit_latency = 1;
+       device->states[0].target_residency = 10000;
+       device->states[0].flags = CPUIDLE_FLAG_TIME_VALID;
+       strcpy(device->states[0].name, "WFI");
+       strcpy(device->states[0].desc, "Wait for interrupt");
+
+       /* Wait for interrupt and RAM self refresh state */
+       device->states[1].enter = at91_enter_idle;
+       device->states[1].exit_latency = 10;
+       device->states[1].target_residency = 10000;
+       device->states[1].flags = CPUIDLE_FLAG_TIME_VALID;
+       strcpy(device->states[1].name, "RAM_SR");
+       strcpy(device->states[1].desc, "WFI and RAM Self Refresh");
+
+       if (cpuidle_register_device(device)) {
+               printk(KERN_ERR "at91_init_cpuidle: Failed registering\n");
+               return -EIO;
+       }
+       return 0;
+}
+
+device_initcall(at91_init_cpuidle);
index 2f4fced..2295d80 100644 (file)
@@ -98,6 +98,7 @@ struct at91_usbh_data {
 };
 extern void __init at91_add_device_usbh(struct at91_usbh_data *data);
 extern void __init at91_add_device_usbh_ohci(struct at91_usbh_data *data);
+extern void __init at91_add_device_usbh_ehci(struct at91_usbh_data *data);
 
  /* NAND / SmartMedia */
 struct atmel_nand_data {
index 4028724..6156689 100644 (file)
 #include <mach/cpu.h>
 
 #include "generic.h"
-
-#ifdef CONFIG_ARCH_AT91RM9200
-#include <mach/at91rm9200_mc.h>
-
-/*
- * The AT91RM9200 goes into self-refresh mode with this command, and will
- * terminate self-refresh automatically on the next SDRAM access.
- */
-#define sdram_selfrefresh_enable()     at91_sys_write(AT91_SDRAMC_SRR, 1)
-#define sdram_selfrefresh_disable()    do {} while (0)
-
-#elif defined(CONFIG_ARCH_AT91CAP9)
-#include <mach/at91cap9_ddrsdr.h>
-
-static u32 saved_lpr;
-
-static inline void sdram_selfrefresh_enable(void)
-{
-       u32 lpr;
-
-       saved_lpr = at91_sys_read(AT91_DDRSDRC_LPR);
-
-       lpr = saved_lpr & ~AT91_DDRSDRC_LPCB;
-       at91_sys_write(AT91_DDRSDRC_LPR, lpr | AT91_DDRSDRC_LPCB_SELF_REFRESH);
-}
-
-#define sdram_selfrefresh_disable()    at91_sys_write(AT91_DDRSDRC_LPR, saved_lpr)
-
-#else
-#include <mach/at91sam9_sdramc.h>
-
-#ifdef CONFIG_ARCH_AT91SAM9263
-/*
- * FIXME either or both the SDRAM controllers (EB0, EB1) might be in use;
- * handle those cases both here and in the Suspend-To-RAM support.
- */
-#define        AT91_SDRAMC     AT91_SDRAMC0
-#warning Assuming EB1 SDRAM controller is *NOT* used
-#endif
-
-static u32 saved_lpr;
-
-static inline void sdram_selfrefresh_enable(void)
-{
-       u32 lpr;
-
-       saved_lpr = at91_sys_read(AT91_SDRAMC_LPR);
-
-       lpr = saved_lpr & ~AT91_SDRAMC_LPCB;
-       at91_sys_write(AT91_SDRAMC_LPR, lpr | AT91_SDRAMC_LPCB_SELF_REFRESH);
-}
-
-#define sdram_selfrefresh_disable()    at91_sys_write(AT91_SDRAMC_LPR, saved_lpr)
-
-#endif
-
+#include "pm.h"
 
 /*
  * Show the reason for the previous system reset.
@@ -260,6 +205,7 @@ extern u32 at91_slow_clock_sz;
 
 static int at91_pm_enter(suspend_state_t state)
 {
+       u32 saved_lpr;
        at91_gpio_suspend();
        at91_irq_suspend();
 
@@ -315,9 +261,9 @@ static int at91_pm_enter(suspend_state_t state)
                         */
                        asm("b 1f; .align 5; 1:");
                        asm("mcr p15, 0, r0, c7, c10, 4");      /* drain write buffer */
-                       sdram_selfrefresh_enable();
+                       saved_lpr = sdram_selfrefresh_enable();
                        asm("mcr p15, 0, r0, c7, c0, 4");       /* wait for interrupt */
-                       sdram_selfrefresh_disable();
+                       sdram_selfrefresh_disable(saved_lpr);
                        break;
 
                case PM_SUSPEND_ON:
diff --git a/arch/arm/mach-at91/pm.h b/arch/arm/mach-at91/pm.h
new file mode 100644 (file)
index 0000000..08322c4
--- /dev/null
@@ -0,0 +1,67 @@
+#ifdef CONFIG_ARCH_AT91RM9200
+#include <mach/at91rm9200_mc.h>
+
+/*
+ * The AT91RM9200 goes into self-refresh mode with this command, and will
+ * terminate self-refresh automatically on the next SDRAM access.
+ *
+ * Self-refresh mode is exited as soon as a memory access is made, but we don't
+ * know for sure when that happens. However, we need to restore the low-power
+ * mode if it was enabled before going idle. Restoring low-power mode while
+ * still in self-refresh is "not recommended", but seems to work.
+ */
+
+static inline u32 sdram_selfrefresh_enable(void)
+{
+       u32 saved_lpr = at91_sys_read(AT91_SDRAMC_LPR);
+
+       at91_sys_write(AT91_SDRAMC_LPR, 0);
+       at91_sys_write(AT91_SDRAMC_SRR, 1);
+       return saved_lpr;
+}
+
+#define sdram_selfrefresh_disable(saved_lpr)   at91_sys_write(AT91_SDRAMC_LPR, saved_lpr)
+
+#elif defined(CONFIG_ARCH_AT91CAP9)
+#include <mach/at91cap9_ddrsdr.h>
+
+
+static inline u32 sdram_selfrefresh_enable(void)
+{
+       u32 saved_lpr, lpr;
+
+       saved_lpr = at91_sys_read(AT91_DDRSDRC_LPR);
+
+       lpr = saved_lpr & ~AT91_DDRSDRC_LPCB;
+       at91_sys_write(AT91_DDRSDRC_LPR, lpr | AT91_DDRSDRC_LPCB_SELF_REFRESH);
+       return saved_lpr;
+}
+
+#define sdram_selfrefresh_disable(saved_lpr)   at91_sys_write(AT91_DDRSDRC_LPR, saved_lpr)
+
+#else
+#include <mach/at91sam9_sdramc.h>
+
+#ifdef CONFIG_ARCH_AT91SAM9263
+/*
+ * FIXME either or both the SDRAM controllers (EB0, EB1) might be in use;
+ * handle those cases both here and in the Suspend-To-RAM support.
+ */
+#define        AT91_SDRAMC     AT91_SDRAMC0
+#warning Assuming EB1 SDRAM controller is *NOT* used
+#endif
+
+static inline u32 sdram_selfrefresh_enable(void)
+{
+       u32 saved_lpr, lpr;
+
+       saved_lpr = at91_sys_read(AT91_SDRAMC_LPR);
+
+       lpr = saved_lpr & ~AT91_SDRAMC_LPCB;
+       at91_sys_write(AT91_SDRAMC_LPR, lpr | AT91_SDRAMC_LPCB_SELF_REFRESH);
+       return saved_lpr;
+}
+
+#define sdram_selfrefresh_disable(saved_lpr)   at91_sys_write(AT91_SDRAMC_LPR, saved_lpr)
+
+#endif
index 0da693b..fbe6fa0 100644 (file)
@@ -47,10 +47,6 @@ HW_DECLARE_SPINLOCK(gpio)
     EXPORT_SYMBOL(bcmring_gpio_reg_lock);
 #endif
 
-/* FIXME: temporary solution */
-#define BCM_SYSCTL_REBOOT_WARM               1
-#define CTL_BCM_REBOOT                 112
-
 /* sysctl */
 int bcmring_arch_warm_reboot;  /* do a warm reboot on hard reset */
 
@@ -58,18 +54,16 @@ static struct ctl_table_header *bcmring_sysctl_header;
 
 static struct ctl_table bcmring_sysctl_warm_reboot[] = {
        {
-        .ctl_name = BCM_SYSCTL_REBOOT_WARM,
         .procname = "warm",
         .data = &bcmring_arch_warm_reboot,
         .maxlen = sizeof(int),
         .mode = 0644,
-        .proc_handler = &proc_dointvec},
+        .proc_handler = proc_dointvec},
        {}
 };
 
 static struct ctl_table bcmring_sysctl_reboot[] = {
        {
-        .ctl_name = CTL_BCM_REBOOT,
         .procname = "reboot",
         .mode = 0555,
         .child = bcmring_sysctl_warm_reboot},
index 4db0eff..dae5e9b 100644 (file)
 
 #define IO_SPACE_LIMIT 0xffffffff
 
-#define __io(a)         ((void __iomem *)HW_IO_PHYS_TO_VIRT(a))
-
-/* Do not enable mem_pci for a big endian arm architecture or unexpected byteswaps will */
-/* happen in readw/writew etc. */
-
-#define readb(c)        __raw_readb(c)
-#define readw(c)        __raw_readw(c)
-#define readl(c)        __raw_readl(c)
-#define readb_relaxed(addr) readb(addr)
-#define readw_relaxed(addr) readw(addr)
-#define readl_relaxed(addr) readl(addr)
-
-#define readsb(p, d, l)   __raw_readsb(p, d, l)
-#define readsw(p, d, l)   __raw_readsw(p, d, l)
-#define readsl(p, d, l)   __raw_readsl(p, d, l)
-
-#define writeb(v, c)     __raw_writeb(v, c)
-#define writew(v, c)     __raw_writew(v, c)
-#define writel(v, c)     __raw_writel(v, c)
-
-#define writesb(p, d, l)  __raw_writesb(p, d, l)
-#define writesw(p, d, l)  __raw_writesw(p, d, l)
-#define writesl(p, d, l)  __raw_writesl(p, d, l)
-
-#define memset_io(c, v, l)    _memset_io((c), (v), (l))
-#define memcpy_fromio(a, c, l)    _memcpy_fromio((a), (c), (l))
-#define memcpy_toio(c, a, l)  _memcpy_toio((c), (a), (l))
-
-#define eth_io_copy_and_sum(s, c, l, b) eth_copy_and_sum((s), (c), (l), (b))
+/*
+ * We don't actually have real ISA nor PCI buses, but there is so many
+ * drivers out there that might just work if we fake them...
+ */
+#define __io(a)                __typesafe_io(a)
+#define __mem_pci(a)   (a)
 
 #endif
index 18e4ce3..e07f70e 100644 (file)
@@ -51,6 +51,14 @@ struct snd_platform_data {
        u32 rx_dma_offset;
        enum dma_event_q eventq_no;     /* event queue number */
        unsigned int codec_fmt;
+       /*
+        * Allowing this is more efficient and eliminates left and right swaps
+        * caused by underruns, but will swap the left and right channels
+        * when compared to previous behavior.
+        */
+       unsigned enable_channel_combine:1;
+       unsigned sram_size_playback;
+       unsigned sram_size_capture;
 
        /* McASP specific fields */
        int tdm_slots;
diff --git a/arch/arm/mach-dove/Kconfig b/arch/arm/mach-dove/Kconfig
new file mode 100644 (file)
index 0000000..3b9a32a
--- /dev/null
@@ -0,0 +1,14 @@
+if ARCH_DOVE
+
+menu "Marvell Dove Implementations"
+
+config MACH_DOVE_DB
+       bool "Marvell DB-MV88AP510 Development Board"
+       select I2C_BOARDINFO
+       help
+         Say 'Y' here if you want your kernel to support the
+         Marvell DB-MV88AP510 Development Board.
+
+endmenu
+
+endif
diff --git a/arch/arm/mach-dove/Makefile b/arch/arm/mach-dove/Makefile
new file mode 100644 (file)
index 0000000..7ab3be5
--- /dev/null
@@ -0,0 +1,3 @@
+obj-y                          += common.o addr-map.o irq.o pcie.o
+
+obj-$(CONFIG_MACH_DOVE_DB)     += dove-db-setup.o
diff --git a/arch/arm/mach-dove/Makefile.boot b/arch/arm/mach-dove/Makefile.boot
new file mode 100644 (file)
index 0000000..67039c3
--- /dev/null
@@ -0,0 +1,3 @@
+   zreladdr-y  := 0x00008000
+params_phys-y  := 0x00000100
+initrd_phys-y  := 0x00800000
diff --git a/arch/arm/mach-dove/addr-map.c b/arch/arm/mach-dove/addr-map.c
new file mode 100644 (file)
index 0000000..00be4fc
--- /dev/null
@@ -0,0 +1,149 @@
+/*
+ * arch/arm/mach-dove/addr-map.c
+ *
+ * Address map functions for Marvell Dove 88AP510 SoC
+ *
+ * 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/kernel.h>
+#include <linux/init.h>
+#include <linux/mbus.h>
+#include <linux/io.h>
+#include <asm/mach/arch.h>
+#include <asm/setup.h>
+#include "common.h"
+
+/*
+ * Generic Address Decode Windows bit settings
+ */
+#define TARGET_DDR             0x0
+#define TARGET_BOOTROM         0x1
+#define TARGET_CESA            0x3
+#define TARGET_PCIE0           0x4
+#define TARGET_PCIE1           0x8
+#define TARGET_SCRATCHPAD      0xd
+
+#define ATTR_CESA              0x01
+#define ATTR_BOOTROM           0xfd
+#define ATTR_DEV_SPI0_ROM      0xfe
+#define ATTR_DEV_SPI1_ROM      0xfb
+#define ATTR_PCIE_IO           0xe0
+#define ATTR_PCIE_MEM          0xe8
+#define ATTR_SCRATCHPAD                0x0
+
+/*
+ * CPU Address Decode Windows registers
+ */
+#define WIN_CTRL(n)    (BRIDGE_VIRT_BASE + ((n) << 4) + 0x0)
+#define WIN_BASE(n)    (BRIDGE_VIRT_BASE + ((n) << 4) + 0x4)
+#define WIN_REMAP_LO(n)        (BRIDGE_VIRT_BASE + ((n) << 4) + 0x8)
+#define WIN_REMAP_HI(n)        (BRIDGE_VIRT_BASE + ((n) << 4) + 0xc)
+
+struct mbus_dram_target_info dove_mbus_dram_info;
+
+static inline void __iomem *ddr_map_sc(int i)
+{
+       return (void __iomem *)(DOVE_MC_VIRT_BASE + 0x100 + ((i) << 4));
+}
+
+static int cpu_win_can_remap(int win)
+{
+       if (win < 4)
+               return 1;
+
+       return 0;
+}
+
+static void __init setup_cpu_win(int win, u32 base, u32 size,
+                                u8 target, u8 attr, int remap)
+{
+       u32 ctrl;
+
+       base &= 0xffff0000;
+       ctrl = ((size - 1) & 0xffff0000) | (attr << 8) | (target << 4) | 1;
+
+       writel(base, WIN_BASE(win));
+       writel(ctrl, WIN_CTRL(win));
+       if (cpu_win_can_remap(win)) {
+               if (remap < 0)
+                       remap = base;
+               writel(remap & 0xffff0000, WIN_REMAP_LO(win));
+               writel(0, WIN_REMAP_HI(win));
+       }
+}
+
+void __init dove_setup_cpu_mbus(void)
+{
+       int i;
+       int cs;
+
+       /*
+        * First, disable and clear windows.
+        */
+       for (i = 0; i < 8; i++) {
+               writel(0, WIN_BASE(i));
+               writel(0, WIN_CTRL(i));
+               if (cpu_win_can_remap(i)) {
+                       writel(0, WIN_REMAP_LO(i));
+                       writel(0, WIN_REMAP_HI(i));
+               }
+       }
+
+       /*
+        * Setup windows for PCIe IO+MEM space.
+        */
+       setup_cpu_win(0, DOVE_PCIE0_IO_PHYS_BASE, DOVE_PCIE0_IO_SIZE,
+                     TARGET_PCIE0, ATTR_PCIE_IO, DOVE_PCIE0_IO_BUS_BASE);
+       setup_cpu_win(1, DOVE_PCIE1_IO_PHYS_BASE, DOVE_PCIE1_IO_SIZE,
+                     TARGET_PCIE1, ATTR_PCIE_IO, DOVE_PCIE1_IO_BUS_BASE);
+       setup_cpu_win(2, DOVE_PCIE0_MEM_PHYS_BASE, DOVE_PCIE0_MEM_SIZE,
+                     TARGET_PCIE0, ATTR_PCIE_MEM, -1);
+       setup_cpu_win(3, DOVE_PCIE1_MEM_PHYS_BASE, DOVE_PCIE1_MEM_SIZE,
+                     TARGET_PCIE1, ATTR_PCIE_MEM, -1);
+
+       /*
+        * Setup window for CESA engine.
+        */
+       setup_cpu_win(4, DOVE_CESA_PHYS_BASE, DOVE_CESA_SIZE,
+                     TARGET_CESA, ATTR_CESA, -1);
+
+       /*
+        * Setup the Window to the BootROM for Standby and Sleep Resume
+        */
+       setup_cpu_win(5, DOVE_BOOTROM_PHYS_BASE, DOVE_BOOTROM_SIZE,
+                     TARGET_BOOTROM, ATTR_BOOTROM, -1);
+
+       /*
+        * Setup the Window to the PMU Scratch Pad space
+        */
+       setup_cpu_win(6, DOVE_SCRATCHPAD_PHYS_BASE, DOVE_SCRATCHPAD_SIZE,
+                     TARGET_SCRATCHPAD, ATTR_SCRATCHPAD, -1);
+
+       /*
+        * Setup MBUS dram target info.
+        */
+       dove_mbus_dram_info.mbus_dram_target_id = TARGET_DDR;
+
+       for (i = 0, cs = 0; i < 2; i++) {
+               u32 map = readl(ddr_map_sc(i));
+
+               /*
+                * Chip select enabled?
+                */
+               if (map & 1) {
+                       struct mbus_dram_window *w;
+
+                       w = &dove_mbus_dram_info.cs[cs++];
+                       w->cs_index = i;
+                       w->mbus_attr = 0; /* CS address decoding done inside */
+                                         /* the DDR controller, no need to  */
+                                         /* provide attributes */
+                       w->base = map & 0xff800000;
+                       w->size = 0x100000 << (((map & 0x000f0000) >> 16) - 4);
+               }
+       }
+       dove_mbus_dram_info.num_cs = cs;
+}
diff --git a/arch/arm/mach-dove/common.c b/arch/arm/mach-dove/common.c
new file mode 100644 (file)
index 0000000..806972a
--- /dev/null
@@ -0,0 +1,781 @@
+/*
+ * arch/arm/mach-dove/common.c
+ *
+ * Core functions for Marvell Dove 88AP510 System On Chip
+ *
+ * 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/kernel.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/pci.h>
+#include <linux/serial_8250.h>
+#include <linux/clk.h>
+#include <linux/mbus.h>
+#include <linux/mv643xx_eth.h>
+#include <linux/mv643xx_i2c.h>
+#include <linux/ata_platform.h>
+#include <linux/spi/orion_spi.h>
+#include <linux/gpio.h>
+#include <asm/page.h>
+#include <asm/setup.h>
+#include <asm/timex.h>
+#include <asm/hardware/cache-tauros2.h>
+#include <asm/mach/map.h>
+#include <asm/mach/time.h>
+#include <asm/mach/pci.h>
+#include <mach/dove.h>
+#include <mach/bridge-regs.h>
+#include <asm/mach/arch.h>
+#include <linux/irq.h>
+#include <plat/mv_xor.h>
+#include <plat/ehci-orion.h>
+#include <plat/time.h>
+#include "common.h"
+
+/*****************************************************************************
+ * I/O Address Mapping
+ ****************************************************************************/
+static struct map_desc dove_io_desc[] __initdata = {
+       {
+               .virtual        = DOVE_SB_REGS_VIRT_BASE,
+               .pfn            = __phys_to_pfn(DOVE_SB_REGS_PHYS_BASE),
+               .length         = DOVE_SB_REGS_SIZE,
+               .type           = MT_DEVICE,
+       }, {
+               .virtual        = DOVE_NB_REGS_VIRT_BASE,
+               .pfn            = __phys_to_pfn(DOVE_NB_REGS_PHYS_BASE),
+               .length         = DOVE_NB_REGS_SIZE,
+               .type           = MT_DEVICE,
+       }, {
+               .virtual        = DOVE_PCIE0_IO_VIRT_BASE,
+               .pfn            = __phys_to_pfn(DOVE_PCIE0_IO_PHYS_BASE),
+               .length         = DOVE_PCIE0_IO_SIZE,
+               .type           = MT_DEVICE,
+       }, {
+               .virtual        = DOVE_PCIE1_IO_VIRT_BASE,
+               .pfn            = __phys_to_pfn(DOVE_PCIE1_IO_PHYS_BASE),
+               .length         = DOVE_PCIE1_IO_SIZE,
+               .type           = MT_DEVICE,
+       },
+};
+
+void __init dove_map_io(void)
+{
+       iotable_init(dove_io_desc, ARRAY_SIZE(dove_io_desc));
+}
+
+/*****************************************************************************
+ * EHCI
+ ****************************************************************************/
+static struct orion_ehci_data dove_ehci_data = {
+       .dram           = &dove_mbus_dram_info,
+       .phy_version    = EHCI_PHY_NA,
+};
+
+static u64 ehci_dmamask = DMA_BIT_MASK(32);
+
+/*****************************************************************************
+ * EHCI0
+ ****************************************************************************/
+static struct resource dove_ehci0_resources[] = {
+       {
+               .start  = DOVE_USB0_PHYS_BASE,
+               .end    = DOVE_USB0_PHYS_BASE + SZ_4K - 1,
+               .flags  = IORESOURCE_MEM,
+       }, {
+               .start  = IRQ_DOVE_USB0,
+               .end    = IRQ_DOVE_USB0,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device dove_ehci0 = {
+       .name           = "orion-ehci",
+       .id             = 0,
+       .dev            = {
+               .dma_mask               = &ehci_dmamask,
+               .coherent_dma_mask      = DMA_BIT_MASK(32),
+               .platform_data          = &dove_ehci_data,
+       },
+       .resource       = dove_ehci0_resources,
+       .num_resources  = ARRAY_SIZE(dove_ehci0_resources),
+};
+
+void __init dove_ehci0_init(void)
+{
+       platform_device_register(&dove_ehci0);
+}
+
+/*****************************************************************************
+ * EHCI1
+ ****************************************************************************/
+static struct resource dove_ehci1_resources[] = {
+       {
+               .start  = DOVE_USB1_PHYS_BASE,
+               .end    = DOVE_USB1_PHYS_BASE + SZ_4K - 1,
+               .flags  = IORESOURCE_MEM,
+       }, {
+               .start  = IRQ_DOVE_USB1,
+               .end    = IRQ_DOVE_USB1,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device dove_ehci1 = {
+       .name           = "orion-ehci",
+       .id             = 1,
+       .dev            = {
+               .dma_mask               = &ehci_dmamask,
+               .coherent_dma_mask      = DMA_BIT_MASK(32),
+               .platform_data          = &dove_ehci_data,
+       },
+       .resource       = dove_ehci1_resources,
+       .num_resources  = ARRAY_SIZE(dove_ehci1_resources),
+};
+
+void __init dove_ehci1_init(void)
+{
+       platform_device_register(&dove_ehci1);
+}
+
+/*****************************************************************************
+ * GE00
+ ****************************************************************************/
+struct mv643xx_eth_shared_platform_data dove_ge00_shared_data = {
+       .t_clk          = 0,
+       .dram           = &dove_mbus_dram_info,
+};
+
+static struct resource dove_ge00_shared_resources[] = {
+       {
+               .name   = "ge00 base",
+               .start  = DOVE_GE00_PHYS_BASE + 0x2000,
+               .end    = DOVE_GE00_PHYS_BASE + SZ_16K - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+};
+
+static struct platform_device dove_ge00_shared = {
+       .name           = MV643XX_ETH_SHARED_NAME,
+       .id             = 0,
+       .dev            = {
+               .platform_data  = &dove_ge00_shared_data,
+       },
+       .num_resources  = 1,
+       .resource       = dove_ge00_shared_resources,
+};
+
+static struct resource dove_ge00_resources[] = {
+       {
+               .name   = "ge00 irq",
+               .start  = IRQ_DOVE_GE00_SUM,
+               .end    = IRQ_DOVE_GE00_SUM,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device dove_ge00 = {
+       .name           = MV643XX_ETH_NAME,
+       .id             = 0,
+       .num_resources  = 1,
+       .resource       = dove_ge00_resources,
+       .dev            = {
+               .coherent_dma_mask      = 0xffffffff,
+       },
+};
+
+void __init dove_ge00_init(struct mv643xx_eth_platform_data *eth_data)
+{
+       eth_data->shared = &dove_ge00_shared;
+       dove_ge00.dev.platform_data = eth_data;
+
+       platform_device_register(&dove_ge00_shared);
+       platform_device_register(&dove_ge00);
+}
+
+/*****************************************************************************
+ * SoC RTC
+ ****************************************************************************/
+static struct resource dove_rtc_resource[] = {
+       {
+               .start  = DOVE_RTC_PHYS_BASE,
+               .end    = DOVE_RTC_PHYS_BASE + 32 - 1,
+               .flags  = IORESOURCE_MEM,
+       }, {
+               .start  = IRQ_DOVE_RTC,
+               .flags  = IORESOURCE_IRQ,
+       }
+};
+
+void __init dove_rtc_init(void)
+{
+       platform_device_register_simple("rtc-mv", -1, dove_rtc_resource, 2);
+}
+
+/*****************************************************************************
+ * SATA
+ ****************************************************************************/
+static struct resource dove_sata_resources[] = {
+       {
+               .name   = "sata base",
+               .start  = DOVE_SATA_PHYS_BASE,
+               .end    = DOVE_SATA_PHYS_BASE + 0x5000 - 1,
+               .flags  = IORESOURCE_MEM,
+       }, {
+               .name   = "sata irq",
+               .start  = IRQ_DOVE_SATA,
+               .end    = IRQ_DOVE_SATA,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device dove_sata = {
+       .name           = "sata_mv",
+       .id             = 0,
+       .dev            = {
+               .coherent_dma_mask      = DMA_BIT_MASK(32),
+       },
+       .num_resources  = ARRAY_SIZE(dove_sata_resources),
+       .resource       = dove_sata_resources,
+};
+
+void __init dove_sata_init(struct mv_sata_platform_data *sata_data)
+{
+       sata_data->dram = &dove_mbus_dram_info;
+       dove_sata.dev.platform_data = sata_data;
+       platform_device_register(&dove_sata);
+}
+
+/*****************************************************************************
+ * UART0
+ ****************************************************************************/
+static struct plat_serial8250_port dove_uart0_data[] = {
+       {
+               .mapbase        = DOVE_UART0_PHYS_BASE,
+               .membase        = (char *)DOVE_UART0_VIRT_BASE,
+               .irq            = IRQ_DOVE_UART_0,
+               .flags          = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF,
+               .iotype         = UPIO_MEM,
+               .regshift       = 2,
+               .uartclk        = 0,
+       }, {
+       },
+};
+
+static struct resource dove_uart0_resources[] = {
+       {
+               .start          = DOVE_UART0_PHYS_BASE,
+               .end            = DOVE_UART0_PHYS_BASE + SZ_256 - 1,
+               .flags          = IORESOURCE_MEM,
+       }, {
+               .start          = IRQ_DOVE_UART_0,
+               .end            = IRQ_DOVE_UART_0,
+               .flags          = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device dove_uart0 = {
+       .name                   = "serial8250",
+       .id                     = 0,
+       .dev                    = {
+               .platform_data  = dove_uart0_data,
+       },
+       .resource               = dove_uart0_resources,
+       .num_resources          = ARRAY_SIZE(dove_uart0_resources),
+};
+
+void __init dove_uart0_init(void)
+{
+       platform_device_register(&dove_uart0);
+}
+
+/*****************************************************************************
+ * UART1
+ ****************************************************************************/
+static struct plat_serial8250_port dove_uart1_data[] = {
+       {
+               .mapbase        = DOVE_UART1_PHYS_BASE,
+               .membase        = (char *)DOVE_UART1_VIRT_BASE,
+               .irq            = IRQ_DOVE_UART_1,
+               .flags          = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF,
+               .iotype         = UPIO_MEM,
+               .regshift       = 2,
+               .uartclk        = 0,
+       }, {
+       },
+};
+
+static struct resource dove_uart1_resources[] = {
+       {
+               .start          = DOVE_UART1_PHYS_BASE,
+               .end            = DOVE_UART1_PHYS_BASE + SZ_256 - 1,
+               .flags          = IORESOURCE_MEM,
+       }, {
+               .start          = IRQ_DOVE_UART_1,
+               .end            = IRQ_DOVE_UART_1,
+               .flags          = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device dove_uart1 = {
+       .name                   = "serial8250",
+       .id                     = 1,
+       .dev                    = {
+               .platform_data  = dove_uart1_data,
+       },
+       .resource               = dove_uart1_resources,
+       .num_resources          = ARRAY_SIZE(dove_uart1_resources),
+};
+
+void __init dove_uart1_init(void)
+{
+       platform_device_register(&dove_uart1);
+}
+
+/*****************************************************************************
+ * UART2
+ ****************************************************************************/
+static struct plat_serial8250_port dove_uart2_data[] = {
+       {
+               .mapbase        = DOVE_UART2_PHYS_BASE,
+               .membase        = (char *)DOVE_UART2_VIRT_BASE,
+               .irq            = IRQ_DOVE_UART_2,
+               .flags          = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF,
+               .iotype         = UPIO_MEM,
+               .regshift       = 2,
+               .uartclk        = 0,
+       }, {
+       },
+};
+
+static struct resource dove_uart2_resources[] = {
+       {
+               .start          = DOVE_UART2_PHYS_BASE,
+               .end            = DOVE_UART2_PHYS_BASE + SZ_256 - 1,
+               .flags          = IORESOURCE_MEM,
+       }, {
+               .start          = IRQ_DOVE_UART_2,
+               .end            = IRQ_DOVE_UART_2,
+               .flags          = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device dove_uart2 = {
+       .name                   = "serial8250",
+       .id                     = 2,
+       .dev                    = {
+               .platform_data  = dove_uart2_data,
+       },
+       .resource               = dove_uart2_resources,
+       .num_resources          = ARRAY_SIZE(dove_uart2_resources),
+};
+
+void __init dove_uart2_init(void)
+{
+       platform_device_register(&dove_uart2);
+}
+
+/*****************************************************************************
+ * UART3
+ ****************************************************************************/
+static struct plat_serial8250_port dove_uart3_data[] = {
+       {
+               .mapbase        = DOVE_UART3_PHYS_BASE,
+               .membase        = (char *)DOVE_UART3_VIRT_BASE,
+               .irq            = IRQ_DOVE_UART_3,
+               .flags          = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF,
+               .iotype         = UPIO_MEM,
+               .regshift       = 2,
+               .uartclk        = 0,
+       }, {
+       },
+};
+
+static struct resource dove_uart3_resources[] = {
+       {
+               .start          = DOVE_UART3_PHYS_BASE,
+               .end            = DOVE_UART3_PHYS_BASE + SZ_256 - 1,
+               .flags          = IORESOURCE_MEM,
+       }, {
+               .start          = IRQ_DOVE_UART_3,
+               .end            = IRQ_DOVE_UART_3,
+               .flags          = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device dove_uart3 = {
+       .name                   = "serial8250",
+       .id                     = 3,
+       .dev                    = {
+               .platform_data  = dove_uart3_data,
+       },
+       .resource               = dove_uart3_resources,
+       .num_resources          = ARRAY_SIZE(dove_uart3_resources),
+};
+
+void __init dove_uart3_init(void)
+{
+       platform_device_register(&dove_uart3);
+}
+
+/*****************************************************************************
+ * SPI0
+ ****************************************************************************/
+static struct orion_spi_info dove_spi0_data = {
+       .tclk           = 0,
+};
+
+static struct resource dove_spi0_resources[] = {
+       {
+               .start  = DOVE_SPI0_PHYS_BASE,
+               .end    = DOVE_SPI0_PHYS_BASE + SZ_512 - 1,
+               .flags  = IORESOURCE_MEM,
+       }, {
+               .start  = IRQ_DOVE_SPI0,
+               .end    = IRQ_DOVE_SPI0,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device dove_spi0 = {
+       .name           = "orion_spi",
+       .id             = 0,
+       .resource       = dove_spi0_resources,
+       .dev            = {
+               .platform_data  = &dove_spi0_data,
+       },
+       .num_resources  = ARRAY_SIZE(dove_spi0_resources),
+};
+
+void __init dove_spi0_init(void)
+{
+       platform_device_register(&dove_spi0);
+}
+
+/*****************************************************************************
+ * SPI1
+ ****************************************************************************/
+static struct orion_spi_info dove_spi1_data = {
+       .tclk           = 0,
+};
+
+static struct resource dove_spi1_resources[] = {
+       {
+               .start  = DOVE_SPI1_PHYS_BASE,
+               .end    = DOVE_SPI1_PHYS_BASE + SZ_512 - 1,
+               .flags  = IORESOURCE_MEM,
+       }, {
+               .start  = IRQ_DOVE_SPI1,
+               .end    = IRQ_DOVE_SPI1,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device dove_spi1 = {
+       .name           = "orion_spi",
+       .id             = 1,
+       .resource       = dove_spi1_resources,
+       .dev            = {
+               .platform_data  = &dove_spi1_data,
+       },
+       .num_resources  = ARRAY_SIZE(dove_spi1_resources),
+};
+
+void __init dove_spi1_init(void)
+{
+       platform_device_register(&dove_spi1);
+}
+
+/*****************************************************************************
+ * I2C
+ ****************************************************************************/
+static struct mv64xxx_i2c_pdata dove_i2c_data = {
+       .freq_m         = 10, /* assumes 166 MHz TCLK gets 94.3kHz */
+       .freq_n         = 3,
+       .timeout        = 1000, /* Default timeout of 1 second */
+};
+
+static struct resource dove_i2c_resources[] = {
+       {
+               .name   = "i2c base",
+               .start  = DOVE_I2C_PHYS_BASE,
+               .end    = DOVE_I2C_PHYS_BASE + 0x20 - 1,
+               .flags  = IORESOURCE_MEM,
+       }, {
+               .name   = "i2c irq",
+               .start  = IRQ_DOVE_I2C,
+               .end    = IRQ_DOVE_I2C,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device dove_i2c = {
+       .name           = MV64XXX_I2C_CTLR_NAME,
+       .id             = 0,
+       .num_resources  = ARRAY_SIZE(dove_i2c_resources),
+       .resource       = dove_i2c_resources,
+       .dev            = {
+               .platform_data = &dove_i2c_data,
+       },
+};
+
+void __init dove_i2c_init(void)
+{
+       platform_device_register(&dove_i2c);
+}
+
+/*****************************************************************************
+ * Time handling
+ ****************************************************************************/
+static int get_tclk(void)
+{
+       /* use DOVE_RESET_SAMPLE_HI/LO to detect tclk */
+       return 166666667;
+}
+
+static void dove_timer_init(void)
+{
+       orion_time_init(IRQ_DOVE_BRIDGE, get_tclk());
+}
+
+struct sys_timer dove_timer = {
+       .init = dove_timer_init,
+};
+
+/*****************************************************************************
+ * XOR
+ ****************************************************************************/
+static struct mv_xor_platform_shared_data dove_xor_shared_data = {
+       .dram           = &dove_mbus_dram_info,
+};
+
+/*****************************************************************************
+ * XOR 0
+ ****************************************************************************/
+static u64 dove_xor0_dmamask = DMA_BIT_MASK(32);
+
+static struct resource dove_xor0_shared_resources[] = {
+       {
+               .name   = "xor 0 low",
+               .start  = DOVE_XOR0_PHYS_BASE,
+               .end    = DOVE_XOR0_PHYS_BASE + 0xff,
+               .flags  = IORESOURCE_MEM,
+       }, {
+               .name   = "xor 0 high",
+               .start  = DOVE_XOR0_HIGH_PHYS_BASE,
+               .end    = DOVE_XOR0_HIGH_PHYS_BASE + 0xff,
+               .flags  = IORESOURCE_MEM,
+       },
+};
+
+static struct platform_device dove_xor0_shared = {
+       .name           = MV_XOR_SHARED_NAME,
+       .id             = 0,
+       .dev            = {
+               .platform_data = &dove_xor_shared_data,
+       },
+       .num_resources  = ARRAY_SIZE(dove_xor0_shared_resources),
+       .resource       = dove_xor0_shared_resources,
+};
+
+static struct resource dove_xor00_resources[] = {
+       [0] = {
+               .start  = IRQ_DOVE_XOR_00,
+               .end    = IRQ_DOVE_XOR_00,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct mv_xor_platform_data dove_xor00_data = {
+       .shared         = &dove_xor0_shared,
+       .hw_id          = 0,
+       .pool_size      = PAGE_SIZE,
+};
+
+static struct platform_device dove_xor00_channel = {
+       .name           = MV_XOR_NAME,
+       .id             = 0,
+       .num_resources  = ARRAY_SIZE(dove_xor00_resources),
+       .resource       = dove_xor00_resources,
+       .dev            = {
+               .dma_mask               = &dove_xor0_dmamask,
+               .coherent_dma_mask      = DMA_BIT_MASK(64),
+               .platform_data          = (void *)&dove_xor00_data,
+       },
+};
+
+static struct resource dove_xor01_resources[] = {
+       [0] = {
+               .start  = IRQ_DOVE_XOR_01,
+               .end    = IRQ_DOVE_XOR_01,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct mv_xor_platform_data dove_xor01_data = {
+       .shared         = &dove_xor0_shared,
+       .hw_id          = 1,
+       .pool_size      = PAGE_SIZE,
+};
+
+static struct platform_device dove_xor01_channel = {
+       .name           = MV_XOR_NAME,
+       .id             = 1,
+       .num_resources  = ARRAY_SIZE(dove_xor01_resources),
+       .resource       = dove_xor01_resources,
+       .dev            = {
+               .dma_mask               = &dove_xor0_dmamask,
+               .coherent_dma_mask      = DMA_BIT_MASK(64),
+               .platform_data          = (void *)&dove_xor01_data,
+       },
+};
+
+void __init dove_xor0_init(void)
+{
+       platform_device_register(&dove_xor0_shared);
+
+       /*
+        * two engines can't do memset simultaneously, this limitation
+        * satisfied by removing memset support from one of the engines.
+        */
+       dma_cap_set(DMA_MEMCPY, dove_xor00_data.cap_mask);
+       dma_cap_set(DMA_XOR, dove_xor00_data.cap_mask);
+       platform_device_register(&dove_xor00_channel);
+
+       dma_cap_set(DMA_MEMCPY, dove_xor01_data.cap_mask);
+       dma_cap_set(DMA_MEMSET, dove_xor01_data.cap_mask);
+       dma_cap_set(DMA_XOR, dove_xor01_data.cap_mask);
+       platform_device_register(&dove_xor01_channel);
+}
+
+/*****************************************************************************
+ * XOR 1
+ ****************************************************************************/
+static u64 dove_xor1_dmamask = DMA_BIT_MASK(32);
+
+static struct resource dove_xor1_shared_resources[] = {
+       {
+               .name   = "xor 0 low",
+               .start  = DOVE_XOR1_PHYS_BASE,
+               .end    = DOVE_XOR1_PHYS_BASE + 0xff,
+               .flags  = IORESOURCE_MEM,
+       }, {
+               .name   = "xor 0 high",
+               .start  = DOVE_XOR1_HIGH_PHYS_BASE,
+               .end    = DOVE_XOR1_HIGH_PHYS_BASE + 0xff,
+               .flags  = IORESOURCE_MEM,
+       },
+};
+
+static struct platform_device dove_xor1_shared = {
+       .name           = MV_XOR_SHARED_NAME,
+       .id             = 1,
+       .dev            = {
+               .platform_data = &dove_xor_shared_data,
+       },
+       .num_resources  = ARRAY_SIZE(dove_xor1_shared_resources),
+       .resource       = dove_xor1_shared_resources,
+};
+
+static struct resource dove_xor10_resources[] = {
+       [0] = {
+               .start  = IRQ_DOVE_XOR_10,
+               .end    = IRQ_DOVE_XOR_10,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct mv_xor_platform_data dove_xor10_data = {
+       .shared         = &dove_xor1_shared,
+       .hw_id          = 0,
+       .pool_size      = PAGE_SIZE,
+};
+
+static struct platform_device dove_xor10_channel = {
+       .name           = MV_XOR_NAME,
+       .id             = 2,
+       .num_resources  = ARRAY_SIZE(dove_xor10_resources),
+       .resource       = dove_xor10_resources,
+       .dev            = {
+               .dma_mask               = &dove_xor1_dmamask,
+               .coherent_dma_mask      = DMA_BIT_MASK(64),
+               .platform_data          = (void *)&dove_xor10_data,
+       },
+};
+
+static struct resource dove_xor11_resources[] = {
+       [0] = {
+               .start  = IRQ_DOVE_XOR_11,
+               .end    = IRQ_DOVE_XOR_11,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct mv_xor_platform_data dove_xor11_data = {
+       .shared         = &dove_xor1_shared,
+       .hw_id          = 1,
+       .pool_size      = PAGE_SIZE,
+};
+
+static struct platform_device dove_xor11_channel = {
+       .name           = MV_XOR_NAME,
+       .id             = 3,
+       .num_resources  = ARRAY_SIZE(dove_xor11_resources),
+       .resource       = dove_xor11_resources,
+       .dev            = {
+               .dma_mask               = &dove_xor1_dmamask,
+               .coherent_dma_mask      = DMA_BIT_MASK(64),
+               .platform_data          = (void *)&dove_xor11_data,
+       },
+};
+
+void __init dove_xor1_init(void)
+{
+       platform_device_register(&dove_xor1_shared);
+
+       /*
+        * two engines can't do memset simultaneously, this limitation
+        * satisfied by removing memset support from one of the engines.
+        */
+       dma_cap_set(DMA_MEMCPY, dove_xor10_data.cap_mask);
+       dma_cap_set(DMA_XOR, dove_xor10_data.cap_mask);
+       platform_device_register(&dove_xor10_channel);
+
+       dma_cap_set(DMA_MEMCPY, dove_xor11_data.cap_mask);
+       dma_cap_set(DMA_MEMSET, dove_xor11_data.cap_mask);
+       dma_cap_set(DMA_XOR, dove_xor11_data.cap_mask);
+       platform_device_register(&dove_xor11_channel);
+}
+
+void __init dove_init(void)
+{
+       int tclk;
+
+       tclk = get_tclk();
+
+       printk(KERN_INFO "Dove 88AP510 SoC, ");
+       printk(KERN_INFO "TCLK = %dMHz\n", (tclk + 499999) / 1000000);
+
+#ifdef CONFIG_CACHE_TAUROS2
+       tauros2_init();
+#endif
+       dove_setup_cpu_mbus();
+
+       dove_ge00_shared_data.t_clk = tclk;
+       dove_uart0_data[0].uartclk = tclk;
+       dove_uart1_data[0].uartclk = tclk;
+       dove_uart2_data[0].uartclk = tclk;
+       dove_uart3_data[0].uartclk = tclk;
+       dove_spi0_data.tclk = tclk;
+       dove_spi1_data.tclk = tclk;
+
+       /* internal devices that every board has */
+       dove_rtc_init();
+       dove_xor0_init();
+       dove_xor1_init();
+}
diff --git a/arch/arm/mach-dove/common.h b/arch/arm/mach-dove/common.h
new file mode 100644 (file)
index 0000000..b29e893
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * arch/arm/mach-dove/common.h
+ *
+ * Core functions for Marvell Dove 88AP510 System On Chip
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#ifndef __ARCH_DOVE_COMMON_H
+#define __ARCH_DOVE_COMMON_H
+
+struct mv643xx_eth_platform_data;
+struct mv_sata_platform_data;
+
+extern struct sys_timer dove_timer;
+extern struct mbus_dram_target_info dove_mbus_dram_info;
+
+/*
+ * Basic Dove init functions used early by machine-setup.
+ */
+void dove_map_io(void);
+void dove_init(void);
+void dove_init_irq(void);
+void dove_setup_cpu_mbus(void);
+void dove_ge00_init(struct mv643xx_eth_platform_data *eth_data);
+void dove_sata_init(struct mv_sata_platform_data *sata_data);
+void dove_pcie_init(int init_port0, int init_port1);
+void dove_ehci0_init(void);
+void dove_ehci1_init(void);
+void dove_uart0_init(void);
+void dove_uart1_init(void);
+void dove_uart2_init(void);
+void dove_uart3_init(void);
+void dove_spi0_init(void);
+void dove_spi1_init(void);
+void dove_i2c_init(void);
+
+#endif
diff --git a/arch/arm/mach-dove/dove-db-setup.c b/arch/arm/mach-dove/dove-db-setup.c
new file mode 100644 (file)
index 0000000..f2971b7
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * arch/arm/mach-dove/dove-db-setup.c
+ *
+ * Marvell DB-MV88AP510-BP Development Board Setup
+ *
+ * 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/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/irq.h>
+#include <linux/mtd/physmap.h>
+#include <linux/mtd/nand.h>
+#include <linux/timer.h>
+#include <linux/ata_platform.h>
+#include <linux/mv643xx_eth.h>
+#include <linux/i2c.h>
+#include <linux/pci.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/orion_spi.h>
+#include <linux/spi/flash.h>
+#include <linux/gpio.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <mach/dove.h>
+#include "common.h"
+
+static struct mv643xx_eth_platform_data dove_db_ge00_data = {
+       .phy_addr       = MV643XX_ETH_PHY_ADDR_DEFAULT,
+};
+
+static struct mv_sata_platform_data dove_db_sata_data = {
+       .n_ports        = 1,
+};
+
+/*****************************************************************************
+ * SPI Devices:
+ *     SPI0: 4M Flash ST-M25P32-VMF6P
+ ****************************************************************************/
+static const struct flash_platform_data dove_db_spi_flash_data = {
+       .type           = "m25p64",
+};
+
+static struct spi_board_info __initdata dove_db_spi_flash_info[] = {
+       {
+               .modalias       = "m25p80",
+               .platform_data  = &dove_db_spi_flash_data,
+               .irq            = -1,
+               .max_speed_hz   = 20000000,
+               .bus_num        = 0,
+               .chip_select    = 0,
+       },
+};
+
+/*****************************************************************************
+ * PCI
+ ****************************************************************************/
+static int __init dove_db_pci_init(void)
+{
+       if (machine_is_dove_db())
+               dove_pcie_init(1, 1);
+
+       return 0;
+}
+
+subsys_initcall(dove_db_pci_init);
+
+/*****************************************************************************
+ * Board Init
+ ****************************************************************************/
+static void __init dove_db_init(void)
+{
+       /*
+        * Basic Dove setup. Needs to be called early.
+        */
+       dove_init();
+
+       dove_ge00_init(&dove_db_ge00_data);
+       dove_ehci0_init();
+       dove_ehci1_init();
+       dove_sata_init(&dove_db_sata_data);
+       dove_spi0_init();
+       dove_spi1_init();
+       dove_uart0_init();
+       dove_uart1_init();
+       dove_i2c_init();
+       spi_register_board_info(dove_db_spi_flash_info,
+                               ARRAY_SIZE(dove_db_spi_flash_info));
+}
+
+MACHINE_START(DOVE_DB, "Marvell DB-MV88AP510-BP Development Board")
+       .phys_io        = DOVE_SB_REGS_PHYS_BASE,
+       .io_pg_offst    = ((DOVE_SB_REGS_VIRT_BASE) >> 18) & 0xfffc,
+       .boot_params    = 0x00000100,
+       .init_machine   = dove_db_init,
+       .map_io         = dove_map_io,
+       .init_irq       = dove_init_irq,
+       .timer          = &dove_timer,
+MACHINE_END
diff --git a/arch/arm/mach-dove/include/mach/bridge-regs.h b/arch/arm/mach-dove/include/mach/bridge-regs.h
new file mode 100644 (file)
index 0000000..214a4c3
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * arch/arm/mach-dove/include/mach/bridge-regs.h
+ *
+ * Mbus-L to Mbus Bridge Registers
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#ifndef __ASM_ARCH_BRIDGE_REGS_H
+#define __ASM_ARCH_BRIDGE_REGS_H
+
+#include <mach/dove.h>
+
+#define CPU_CONFIG             (BRIDGE_VIRT_BASE | 0x0000)
+
+#define CPU_CONTROL            (BRIDGE_VIRT_BASE | 0x0104)
+#define  CPU_CTRL_PCIE0_LINK   0x00000001
+#define  CPU_RESET             0x00000002
+#define  CPU_CTRL_PCIE1_LINK   0x00000008
+
+#define RSTOUTn_MASK           (BRIDGE_VIRT_BASE | 0x0108)
+#define  SOFT_RESET_OUT_EN     0x00000004
+
+#define SYSTEM_SOFT_RESET      (BRIDGE_VIRT_BASE | 0x010c)
+#define  SOFT_RESET            0x00000001
+
+#define BRIDGE_CAUSE           (BRIDGE_VIRT_BASE | 0x0110)
+#define BRIDGE_MASK            (BRIDGE_VIRT_BASE | 0x0114)
+#define  BRIDGE_INT_TIMER0     0x0002
+#define  BRIDGE_INT_TIMER1     0x0004
+#define  BRIDGE_INT_TIMER1_CLR (~0x0004)
+
+#define IRQ_VIRT_BASE          (BRIDGE_VIRT_BASE | 0x0200)
+#define IRQ_CAUSE_LOW_OFF      0x0000
+#define IRQ_MASK_LOW_OFF       0x0004
+#define FIQ_MASK_LOW_OFF       0x0008
+#define ENDPOINT_MASK_LOW_OFF  0x000c
+#define IRQ_CAUSE_HIGH_OFF     0x0010
+#define IRQ_MASK_HIGH_OFF      0x0014
+#define FIQ_MASK_HIGH_OFF      0x0018
+#define ENDPOINT_MASK_HIGH_OFF 0x001c
+#define PCIE_INTERRUPT_MASK_OFF        0x0020
+
+#define IRQ_MASK_LOW           (IRQ_VIRT_BASE + IRQ_MASK_LOW_OFF)
+#define FIQ_MASK_LOW           (IRQ_VIRT_BASE + FIQ_MASK_LOW_OFF)
+#define ENDPOINT_MASK_LOW      (IRQ_VIRT_BASE + ENDPOINT_MASK_LOW_OFF)
+#define IRQ_MASK_HIGH          (IRQ_VIRT_BASE + IRQ_MASK_HIGH_OFF)
+#define FIQ_MASK_HIGH          (IRQ_VIRT_BASE + FIQ_MASK_HIGH_OFF)
+#define ENDPOINT_MASK_HIGH     (IRQ_VIRT_BASE + ENDPOINT_MASK_HIGH_OFF)
+#define PCIE_INTERRUPT_MASK    (IRQ_VIRT_BASE + PCIE_INTERRUPT_MASK_OFF)
+
+#define POWER_MANAGEMENT       (BRIDGE_VIRT_BASE | 0x011c)
+
+#define TIMER_VIRT_BASE                (BRIDGE_VIRT_BASE | 0x0300)
+
+#endif
diff --git a/arch/arm/mach-dove/include/mach/debug-macro.S b/arch/arm/mach-dove/include/mach/debug-macro.S
new file mode 100644 (file)
index 0000000..9b89ec7
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ * arch/arm/mach-dove/include/mach/debug-macro.S
+ *
+ * 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 <mach/bridge-regs.h>
+
+       .macro  addruart,rx
+       mrc     p15, 0, \rx, c1, c0
+       tst     \rx, #1                                 @ MMU enabled?
+       ldreq   \rx, =DOVE_SB_REGS_PHYS_BASE
+       ldrne   \rx, =DOVE_SB_REGS_VIRT_BASE
+       orr     \rx, \rx, #0x00012000
+       .endm
+
+#define UART_SHIFT     2
+#include <asm/hardware/debug-8250.S>
diff --git a/arch/arm/mach-dove/include/mach/dove.h b/arch/arm/mach-dove/include/mach/dove.h
new file mode 100644 (file)
index 0000000..f6a0839
--- /dev/null
@@ -0,0 +1,180 @@
+/*
+ * arch/arm/mach-dove/include/mach/dove.h
+ *
+ * Generic definitions for Marvell Dove 88AP510 SoC
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#ifndef __ASM_ARCH_DOVE_H
+#define __ASM_ARCH_DOVE_H
+
+#include <mach/vmalloc.h>
+
+/*
+ * Marvell Dove address maps.
+ *
+ * phys                virt            size
+ * c8000000    fdb00000        1M      Cryptographic SRAM
+ * e0000000    @runtime        128M    PCIe-0 Memory space
+ * e8000000    @runtime        128M    PCIe-1 Memory space
+ * f1000000    fde00000        8M      on-chip south-bridge registers
+ * f1800000    fe600000        8M      on-chip north-bridge registers
+ * f2000000    fee00000        1M      PCIe-0 I/O space
+ * f2100000    fef00000        1M      PCIe-1 I/O space
+ */
+
+#define DOVE_CESA_PHYS_BASE            0xc8000000
+#define DOVE_CESA_VIRT_BASE            0xfdb00000
+#define DOVE_CESA_SIZE                 SZ_1M
+
+#define DOVE_PCIE0_MEM_PHYS_BASE       0xe0000000
+#define DOVE_PCIE0_MEM_SIZE            SZ_128M
+
+#define DOVE_PCIE1_MEM_PHYS_BASE       0xe8000000
+#define DOVE_PCIE1_MEM_SIZE            SZ_128M
+
+#define DOVE_BOOTROM_PHYS_BASE         0xf8000000
+#define DOVE_BOOTROM_SIZE              SZ_128M
+
+#define DOVE_SCRATCHPAD_PHYS_BASE      0xf0000000
+#define DOVE_SCRATCHPAD_VIRT_BASE      0xfdd00000
+#define DOVE_SCRATCHPAD_SIZE           SZ_1M
+
+#define DOVE_SB_REGS_PHYS_BASE         0xf1000000
+#define DOVE_SB_REGS_VIRT_BASE         0xfde00000
+#define DOVE_SB_REGS_SIZE              SZ_8M
+
+#define DOVE_NB_REGS_PHYS_BASE         0xf1800000
+#define DOVE_NB_REGS_VIRT_BASE         0xfe600000
+#define DOVE_NB_REGS_SIZE              SZ_8M
+
+#define DOVE_PCIE0_IO_PHYS_BASE                0xf2000000
+#define DOVE_PCIE0_IO_VIRT_BASE                0xfee00000
+#define DOVE_PCIE0_IO_BUS_BASE         0x00000000
+#define DOVE_PCIE0_IO_SIZE             SZ_1M
+
+#define DOVE_PCIE1_IO_PHYS_BASE                0xf2100000
+#define DOVE_PCIE1_IO_VIRT_BASE                0xfef00000
+#define DOVE_PCIE1_IO_BUS_BASE         0x00100000
+#define DOVE_PCIE1_IO_SIZE             SZ_1M
+
+/*
+ * Dove Core Registers Map
+ */
+
+/* SPI, I2C, UART */
+#define DOVE_I2C_PHYS_BASE     (DOVE_SB_REGS_PHYS_BASE | 0x11000)
+#define DOVE_UART0_PHYS_BASE   (DOVE_SB_REGS_PHYS_BASE | 0x12000)
+#define DOVE_UART0_VIRT_BASE   (DOVE_SB_REGS_VIRT_BASE | 0x12000)
+#define DOVE_UART1_PHYS_BASE   (DOVE_SB_REGS_PHYS_BASE | 0x12100)
+#define DOVE_UART1_VIRT_BASE   (DOVE_SB_REGS_VIRT_BASE | 0x12100)
+#define DOVE_UART2_PHYS_BASE   (DOVE_SB_REGS_PHYS_BASE | 0x12200)
+#define DOVE_UART2_VIRT_BASE   (DOVE_SB_REGS_VIRT_BASE | 0x12200)
+#define DOVE_UART3_PHYS_BASE   (DOVE_SB_REGS_PHYS_BASE | 0x12300)
+#define DOVE_UART3_VIRT_BASE   (DOVE_SB_REGS_VIRT_BASE | 0x12300)
+#define DOVE_SPI0_PHYS_BASE    (DOVE_SB_REGS_PHYS_BASE | 0x10600)
+#define DOVE_SPI1_PHYS_BASE    (DOVE_SB_REGS_PHYS_BASE | 0x14600)
+
+/* North-South Bridge */
+#define BRIDGE_VIRT_BASE       (DOVE_SB_REGS_VIRT_BASE | 0x20000)
+
+/* Cryptographic Engine */
+#define DOVE_CRYPT_PHYS_BASE   (DOVE_SB_REGS_PHYS_BASE | 0x30000)
+
+/* PCIe 0 */
+#define DOVE_PCIE0_VIRT_BASE   (DOVE_SB_REGS_VIRT_BASE | 0x40000)
+
+/* USB */
+#define DOVE_USB0_PHYS_BASE    (DOVE_SB_REGS_PHYS_BASE | 0x50000)
+#define DOVE_USB1_PHYS_BASE    (DOVE_SB_REGS_PHYS_BASE | 0x51000)
+
+/* XOR 0 Engine */
+#define DOVE_XOR0_PHYS_BASE    (DOVE_SB_REGS_PHYS_BASE | 0x60800)
+#define DOVE_XOR0_VIRT_BASE    (DOVE_SB_REGS_VIRT_BASE | 0x60800)
+#define DOVE_XOR0_HIGH_PHYS_BASE       (DOVE_SB_REGS_PHYS_BASE | 0x60A00)
+#define DOVE_XOR0_HIGH_VIRT_BASE       (DOVE_SB_REGS_VIRT_BASE | 0x60A00)
+
+/* XOR 1 Engine */
+#define DOVE_XOR1_PHYS_BASE    (DOVE_SB_REGS_PHYS_BASE | 0x60900)
+#define DOVE_XOR1_VIRT_BASE    (DOVE_SB_REGS_VIRT_BASE | 0x60900)
+#define DOVE_XOR1_HIGH_PHYS_BASE       (DOVE_SB_REGS_PHYS_BASE | 0x60B00)
+#define DOVE_XOR1_HIGH_VIRT_BASE       (DOVE_SB_REGS_VIRT_BASE | 0x60B00)
+
+/* Gigabit Ethernet */
+#define DOVE_GE00_PHYS_BASE    (DOVE_SB_REGS_PHYS_BASE | 0x70000)
+
+/* PCIe 1 */
+#define DOVE_PCIE1_VIRT_BASE   (DOVE_SB_REGS_VIRT_BASE | 0x80000)
+
+/* CAFE */
+#define DOVE_SDIO0_PHYS_BASE   (DOVE_SB_REGS_PHYS_BASE | 0x92000)
+#define DOVE_SDIO1_PHYS_BASE   (DOVE_SB_REGS_PHYS_BASE | 0x90000)
+#define DOVE_CAM_PHYS_BASE     (DOVE_SB_REGS_PHYS_BASE | 0x94000)
+#define DOVE_CAFE_WIN_PHYS_BASE        (DOVE_SB_REGS_PHYS_BASE | 0x98000)
+
+/* SATA */
+#define DOVE_SATA_PHYS_BASE    (DOVE_SB_REGS_PHYS_BASE | 0xa0000)
+
+/* I2S/SPDIF */
+#define DOVE_AUD0_PHYS_BASE    (DOVE_SB_REGS_PHYS_BASE | 0xb0000)
+#define DOVE_AUD1_PHYS_BASE    (DOVE_SB_REGS_PHYS_BASE | 0xb4000)
+
+/* NAND Flash Controller */
+#define DOVE_NFC_PHYS_BASE     (DOVE_SB_REGS_PHYS_BASE | 0xc0000)
+
+/* MPP, GPIO, Reset Sampling */
+#define DOVE_MPP_VIRT_BASE     (DOVE_SB_REGS_VIRT_BASE | 0xd0200)
+#define DOVE_PMU_MPP_GENERAL_CTRL (DOVE_MPP_VIRT_BASE + 0x10)
+#define DOVE_RESET_SAMPLE_LO   (DOVE_MPP_VIRT_BASE | 0x014)
+#define DOVE_RESET_SAMPLE_HI   (DOVE_MPP_VIRT_BASE | 0x018)
+#define DOVE_GPIO_VIRT_BASE    (DOVE_SB_REGS_VIRT_BASE | 0xd0400)
+#define DOVE_MPP_GENERAL_VIRT_BASE     (DOVE_SB_REGS_VIRT_BASE | 0xe803c)
+#define  DOVE_AU1_SPDIFO_GPIO_EN       (1 << 1)
+#define  DOVE_NAND_GPIO_EN             (1 << 0)
+#define DOVE_MPP_CTRL4_VIRT_BASE       (DOVE_GPIO_VIRT_BASE + 0x40)
+
+
+/* Power Management */
+#define DOVE_PMU_VIRT_BASE     (DOVE_SB_REGS_VIRT_BASE | 0xd0000)
+
+/* Real Time Clock */
+#define DOVE_RTC_PHYS_BASE     (DOVE_SB_REGS_PHYS_BASE | 0xd8500)
+
+/* AC97 */
+#define DOVE_AC97_PHYS_BASE    (DOVE_SB_REGS_PHYS_BASE | 0xe0000)
+#define DOVE_AC97_VIRT_BASE    (DOVE_SB_REGS_VIRT_BASE | 0xe0000)
+
+/* Peripheral DMA */
+#define DOVE_PDMA_PHYS_BASE    (DOVE_SB_REGS_PHYS_BASE | 0xe4000)
+#define DOVE_PDMA_VIRT_BASE    (DOVE_SB_REGS_VIRT_BASE | 0xe4000)
+
+#define DOVE_GLOBAL_CONFIG_1   (DOVE_SB_REGS_VIRT_BASE | 0xe802C)
+#define  DOVE_TWSI_ENABLE_OPTION1      (1 << 7)
+#define DOVE_GLOBAL_CONFIG_2   (DOVE_SB_REGS_VIRT_BASE | 0xe8030)
+#define  DOVE_TWSI_ENABLE_OPTION2      (1 << 20)
+#define  DOVE_TWSI_ENABLE_OPTION3      (1 << 21)
+#define  DOVE_TWSI_OPTION3_GPIO                (1 << 22)
+#define DOVE_SSP_PHYS_BASE     (DOVE_SB_REGS_PHYS_BASE | 0xec000)
+#define DOVE_SSP_CTRL_STATUS_1 (DOVE_SB_REGS_VIRT_BASE | 0xe8034)
+#define  DOVE_SSP_ON_AU1               (1 << 0)
+#define  DOVE_SSP_CLOCK_ENABLE         (1 << 1)
+#define  DOVE_SSP_BPB_CLOCK_SRC_SSP    (1 << 11)
+/* Memory Controller */
+#define DOVE_MC_VIRT_BASE      (DOVE_NB_REGS_VIRT_BASE | 0x00000)
+
+/* LCD Controller */
+#define DOVE_LCD_PHYS_BASE     (DOVE_NB_REGS_PHYS_BASE | 0x10000)
+#define DOVE_LCD1_PHYS_BASE    (DOVE_NB_REGS_PHYS_BASE | 0x20000)
+#define DOVE_LCD2_PHYS_BASE    (DOVE_NB_REGS_PHYS_BASE | 0x10000)
+#define DOVE_LCD_DCON_PHYS_BASE        (DOVE_NB_REGS_PHYS_BASE | 0x30000)
+
+/* Graphic Engine */
+#define DOVE_GPU_PHYS_BASE     (DOVE_NB_REGS_PHYS_BASE | 0x40000)
+
+/* Video Engine */
+#define DOVE_VPU_PHYS_BASE     (DOVE_NB_REGS_PHYS_BASE | 0x400000)
+
+#endif
diff --git a/arch/arm/mach-dove/include/mach/entry-macro.S b/arch/arm/mach-dove/include/mach/entry-macro.S
new file mode 100644 (file)
index 0000000..e84c78c
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * arch/arm/mach-dove/include/mach/entry-macro.S
+ *
+ * Low-level IRQ helper macros for Marvell Dove 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/bridge-regs.h>
+
+       .macro  disable_fiq
+       .endm
+
+       .macro  arch_ret_to_user, tmp1, tmp2
+       .endm
+
+       .macro  get_irqnr_preamble, base, tmp
+       ldr     \base, =IRQ_VIRT_BASE
+       .endm
+
+       .macro  get_irqnr_and_base, irqnr, irqstat, base, tmp
+       @ check low interrupts
+       ldr     \irqstat, [\base, #IRQ_CAUSE_LOW_OFF]
+       ldr     \tmp, [\base, #IRQ_MASK_LOW_OFF]
+       mov     \irqnr, #31
+       ands    \irqstat, \irqstat, \tmp
+
+       @ if no low interrupts set, check high interrupts
+       ldreq   \irqstat, [\base, #IRQ_CAUSE_HIGH_OFF]
+       ldreq   \tmp, [\base, #IRQ_MASK_HIGH_OFF]
+       moveq   \irqnr, #63
+       andeqs  \irqstat, \irqstat, \tmp
+
+       @ find first active interrupt source
+       clzne   \irqstat, \irqstat
+       subne   \irqnr, \irqnr, \irqstat
+       .endm
diff --git a/arch/arm/mach-dove/include/mach/gpio.h b/arch/arm/mach-dove/include/mach/gpio.h
new file mode 100644 (file)
index 0000000..0ee70ff
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * arch/arm/mach-dove/include/mach/gpio.h
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#ifndef __ASM_ARCH_GPIO_H
+#define __ASM_ARCH_GPIO_H
+
+#include <asm/errno.h>
+#include <mach/irqs.h>
+#include <plat/gpio.h>
+#include <asm-generic/gpio.h>          /* cansleep wrappers */
+
+#define GPIO_MAX       64
+
+#define GPIO_BASE_LO           (DOVE_GPIO_VIRT_BASE + 0x00)
+#define GPIO_BASE_HI           (DOVE_GPIO_VIRT_BASE + 0x20)
+
+#define GPIO_BASE(pin)         ((pin < 32) ? GPIO_BASE_LO : GPIO_BASE_HI)
+
+#define GPIO_OUT(pin)          (GPIO_BASE(pin) + 0x00)
+#define GPIO_IO_CONF(pin)      (GPIO_BASE(pin) + 0x04)
+#define GPIO_BLINK_EN(pin)     (GPIO_BASE(pin) + 0x08)
+#define GPIO_IN_POL(pin)       (GPIO_BASE(pin) + 0x0c)
+#define GPIO_DATA_IN(pin)      (GPIO_BASE(pin) + 0x10)
+#define GPIO_EDGE_CAUSE(pin)   (GPIO_BASE(pin) + 0x14)
+#define GPIO_EDGE_MASK(pin)    (GPIO_BASE(pin) + 0x18)
+#define GPIO_LEVEL_MASK(pin)   (GPIO_BASE(pin) + 0x1c)
+
+static inline int gpio_to_irq(int pin)
+{
+       if (pin < NR_GPIO_IRQS)
+               return pin + IRQ_DOVE_GPIO_START;
+
+       return -EINVAL;
+}
+
+static inline int irq_to_gpio(int irq)
+{
+       if (IRQ_DOVE_GPIO_START < irq && irq < NR_IRQS)
+               return irq - IRQ_DOVE_GPIO_START;
+
+       return -EINVAL;
+}
+
+#endif
diff --git a/arch/arm/mach-dove/include/mach/hardware.h b/arch/arm/mach-dove/include/mach/hardware.h
new file mode 100644 (file)
index 0000000..32b0826
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * arch/arm/mach-dove/include/mach/hardware.h
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#ifndef __ASM_ARCH_HARDWARE_H
+#define __ASM_ARCH_HARDWARE_H
+
+#include "dove.h"
+
+#define pcibios_assign_all_busses()    1
+
+#define PCIBIOS_MIN_IO                 0x1000
+#define PCIBIOS_MIN_MEM                        0x01000000
+#define PCIMEM_BASE                    DOVE_PCIE0_MEM_PHYS_BASE
+
+
+/* Macros below are required for compatibility with PXA AC'97 driver.  */
+#define __REG(x)       (*((volatile u32 *)((x) - DOVE_SB_REGS_PHYS_BASE + \
+                               DOVE_SB_REGS_VIRT_BASE)))
+#define __PREG(x)      (((u32)&(x)) - DOVE_SB_REGS_VIRT_BASE + \
+               DOVE_SB_REGS_PHYS_BASE)
+#endif
diff --git a/arch/arm/mach-dove/include/mach/io.h b/arch/arm/mach-dove/include/mach/io.h
new file mode 100644 (file)
index 0000000..3b3e472
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ * arch/arm/mach-dove/include/mach/io.h
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#ifndef __ASM_ARCH_IO_H
+#define __ASM_ARCH_IO_H
+
+#include "dove.h"
+
+#define IO_SPACE_LIMIT         0xffffffff
+
+#define __io(a)  ((void __iomem *)(((a) - DOVE_PCIE0_IO_PHYS_BASE) +\
+                                  DOVE_PCIE0_IO_VIRT_BASE))
+#define __mem_pci(a)           (a)
+
+#endif
diff --git a/arch/arm/mach-dove/include/mach/irqs.h b/arch/arm/mach-dove/include/mach/irqs.h
new file mode 100644 (file)
index 0000000..4668146
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+ * arch/arm/mach-dove/include/mach/irqs.h
+ *
+ * IRQ definitions for Marvell Dove 88AP510 SoC
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#ifndef __ASM_ARCH_IRQS_H
+#define __ASM_ARCH_IRQS_H
+
+/*
+ * Dove Low Interrupt Controller
+ */
+#define IRQ_DOVE_BRIDGE                0
+#define IRQ_DOVE_H2C           1
+#define IRQ_DOVE_C2H           2
+#define IRQ_DOVE_NAND          3
+#define IRQ_DOVE_PDMA          4
+#define IRQ_DOVE_SPI1          5
+#define IRQ_DOVE_SPI0          6
+#define IRQ_DOVE_UART_0                7
+#define IRQ_DOVE_UART_1                8
+#define IRQ_DOVE_UART_2                9
+#define IRQ_DOVE_UART_3                10
+#define IRQ_DOVE_I2C           11
+#define IRQ_DOVE_GPIO_0_7      12
+#define IRQ_DOVE_GPIO_8_15     13
+#define IRQ_DOVE_GPIO_16_23    14
+#define IRQ_DOVE_PCIE0_ERR     15
+#define IRQ_DOVE_PCIE0         16
+#define IRQ_DOVE_PCIE1_ERR     17
+#define IRQ_DOVE_PCIE1         18
+#define IRQ_DOVE_I2S0          19
+#define IRQ_DOVE_I2S0_ERR      20
+#define IRQ_DOVE_I2S1          21
+#define IRQ_DOVE_I2S1_ERR      22
+#define IRQ_DOVE_USB_ERR       23
+#define IRQ_DOVE_USB0          24
+#define IRQ_DOVE_USB1          25
+#define IRQ_DOVE_GE00_RX       26
+#define IRQ_DOVE_GE00_TX       27
+#define IRQ_DOVE_GE00_MISC     28
+#define IRQ_DOVE_GE00_SUM      29
+#define IRQ_DOVE_GE00_ERR      30
+#define IRQ_DOVE_CRYPTO                31
+
+/*
+ * Dove High Interrupt Controller
+ */
+#define IRQ_DOVE_AC97          32
+#define IRQ_DOVE_PMU           33
+#define IRQ_DOVE_CAM           34
+#define IRQ_DOVE_SDIO0         35
+#define IRQ_DOVE_SDIO1         36
+#define IRQ_DOVE_SDIO0_WAKEUP  37
+#define IRQ_DOVE_SDIO1_WAKEUP  38
+#define IRQ_DOVE_XOR_00                39
+#define IRQ_DOVE_XOR_01                40
+#define IRQ_DOVE_XOR0_ERR      41
+#define IRQ_DOVE_XOR_10                42
+#define IRQ_DOVE_XOR_11                43
+#define IRQ_DOVE_XOR1_ERR      44
+#define IRQ_DOVE_LCD_DCON      45
+#define IRQ_DOVE_LCD1          46
+#define IRQ_DOVE_LCD0          47
+#define IRQ_DOVE_GPU           48
+#define IRQ_DOVE_PERFORM_MNTR  49
+#define IRQ_DOVE_VPRO_DMA1     51
+#define IRQ_DOVE_SSP_TIMER     54
+#define IRQ_DOVE_SSP           55
+#define IRQ_DOVE_MC_L2_ERR     56
+#define IRQ_DOVE_CRYPTO_ERR    59
+#define IRQ_DOVE_GPIO_24_31    60
+#define IRQ_DOVE_HIGH_GPIO     61
+#define IRQ_DOVE_SATA          62
+
+/*
+ * DOVE General Purpose Pins
+ */
+#define IRQ_DOVE_GPIO_START    64
+#define NR_GPIO_IRQS           64
+
+/*
+ * PMU interrupts
+ */
+#define IRQ_DOVE_PMU_START     (IRQ_DOVE_GPIO_START + NR_GPIO_IRQS)
+#define NR_PMU_IRQS            7
+#define IRQ_DOVE_RTC           (IRQ_DOVE_PMU_START + 5)
+
+#define NR_IRQS                        (IRQ_DOVE_PMU_START + NR_PMU_IRQS)
+
+/* Required for compatability with PXA AC97 driver.    */
+#define IRQ_AC97               IRQ_DOVE_AC97
+/* Required for compatability with PXA DMA driver.     */
+#define IRQ_DMA                        IRQ_DOVE_PDMA
+/* Required for compatability with PXA NAND driver     */
+#define IRQ_NAND               IRQ_DOVE_NAND
+#endif
diff --git a/arch/arm/mach-dove/include/mach/memory.h b/arch/arm/mach-dove/include/mach/memory.h
new file mode 100644 (file)
index 0000000..d668720
--- /dev/null
@@ -0,0 +1,10 @@
+/*
+ * arch/arm/mach-dove/include/mach/memory.h
+ */
+
+#ifndef __ASM_ARCH_MEMORY_H
+#define __ASM_ARCH_MEMORY_H
+
+#define PHYS_OFFSET            UL(0x00000000)
+
+#endif
diff --git a/arch/arm/mach-dove/include/mach/pm.h b/arch/arm/mach-dove/include/mach/pm.h
new file mode 100644 (file)
index 0000000..3ad9f94
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * arch/arm/mach-dove/include/mach/pm.h
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#ifndef __ASM_ARCH_PM_H
+#define __ASM_ARCH_PM_H
+
+#include <asm/errno.h>
+#include <mach/irqs.h>
+
+#define CLOCK_GATING_CONTROL   (DOVE_PMU_VIRT_BASE + 0x38)
+#define  CLOCK_GATING_USB0_MASK                (1 << 0)
+#define  CLOCK_GATING_USB1_MASK                (1 << 1)
+#define  CLOCK_GATING_GBE_MASK         (1 << 2)
+#define  CLOCK_GATING_SATA_MASK                (1 << 3)
+#define  CLOCK_GATING_PCIE0_MASK       (1 << 4)
+#define  CLOCK_GATING_PCIE1_MASK       (1 << 5)
+#define  CLOCK_GATING_SDIO0_MASK       (1 << 8)
+#define  CLOCK_GATING_SDIO1_MASK       (1 << 9)
+#define  CLOCK_GATING_NAND_MASK                (1 << 10)
+#define  CLOCK_GATING_CAMERA_MASK      (1 << 11)
+#define  CLOCK_GATING_I2S0_MASK                (1 << 12)
+#define  CLOCK_GATING_I2S1_MASK                (1 << 13)
+#define  CLOCK_GATING_CRYPTO_MASK      (1 << 15)
+#define  CLOCK_GATING_AC97_MASK                (1 << 21)
+#define  CLOCK_GATING_PDMA_MASK                (1 << 22)
+#define  CLOCK_GATING_XOR0_MASK                (1 << 23)
+#define  CLOCK_GATING_XOR1_MASK                (1 << 24)
+#define  CLOCK_GATING_GIGA_PHY_MASK    (1 << 30)
+
+#define PMU_INTERRUPT_CAUSE    (DOVE_PMU_VIRT_BASE + 0x50)
+#define PMU_INTERRUPT_MASK     (DOVE_PMU_VIRT_BASE + 0x54)
+
+static inline int pmu_to_irq(int pin)
+{
+       if (pin < NR_PMU_IRQS)
+               return pin + IRQ_DOVE_PMU_START;
+
+       return -EINVAL;
+}
+
+static inline int irq_to_pmu(int irq)
+{
+       if (IRQ_DOVE_PMU_START < irq && irq < NR_IRQS)
+               return irq - IRQ_DOVE_PMU_START;
+
+       return -EINVAL;
+}
+
+#endif
diff --git a/arch/arm/mach-dove/include/mach/system.h b/arch/arm/mach-dove/include/mach/system.h
new file mode 100644 (file)
index 0000000..356afda
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * arch/arm/mach-dove/include/mach/system.h
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#ifndef __ASM_ARCH_SYSTEM_H
+#define __ASM_ARCH_SYSTEM_H
+
+#include <mach/bridge-regs.h>
+
+static inline void arch_idle(void)
+{
+       cpu_do_idle();
+}
+
+static inline void arch_reset(char mode, const char *cmd)
+{
+       /*
+        * Enable soft reset to assert RSTOUTn.
+        */
+       writel(SOFT_RESET_OUT_EN, RSTOUTn_MASK);
+
+       /*
+        * Assert soft reset.
+        */
+       writel(SOFT_RESET, SYSTEM_SOFT_RESET);
+
+       while (1)
+               ;
+}
+
+
+#endif
diff --git a/arch/arm/mach-dove/include/mach/timex.h b/arch/arm/mach-dove/include/mach/timex.h
new file mode 100644 (file)
index 0000000..251d538
--- /dev/null
@@ -0,0 +1,9 @@
+/*
+ * arch/arm/mach-dove/include/mach/timex.h
+ *
+ * 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.
+ */
+
+#define CLOCK_TICK_RATE                (100 * HZ)
diff --git a/arch/arm/mach-dove/include/mach/uncompress.h b/arch/arm/mach-dove/include/mach/uncompress.h
new file mode 100644 (file)
index 0000000..2c5cdd7
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * arch/arm/mach-dove/include/mach/uncompress.h
+ *
+ * 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/dove.h>
+
+#define UART_THR ((volatile unsigned char *)(DOVE_UART0_PHYS_BASE + 0x0))
+#define UART_LSR ((volatile unsigned char *)(DOVE_UART0_PHYS_BASE + 0x14))
+
+#define LSR_THRE       0x20
+
+static void putc(const char c)
+{
+       int i;
+
+       for (i = 0; i < 0x1000; i++) {
+               /* Transmit fifo not full? */
+               if (*UART_LSR & LSR_THRE)
+                       break;
+       }
+
+       *UART_THR = c;
+}
+
+static void flush(void)
+{
+}
+
+/*
+ * nothing to do
+ */
+#define arch_decomp_setup()
+#define arch_decomp_wdog()
diff --git a/arch/arm/mach-dove/include/mach/vmalloc.h b/arch/arm/mach-dove/include/mach/vmalloc.h
new file mode 100644 (file)
index 0000000..8b2c974
--- /dev/null
@@ -0,0 +1,5 @@
+/*
+ * arch/arm/mach-dove/include/mach/vmalloc.h
+ */
+
+#define VMALLOC_END    0xfd800000
diff --git a/arch/arm/mach-dove/irq.c b/arch/arm/mach-dove/irq.c
new file mode 100644 (file)
index 0000000..61bfcb3
--- /dev/null
@@ -0,0 +1,133 @@
+/*
+ * arch/arm/mach-dove/irq.c
+ *
+ * Dove IRQ handling.
+ *
+ * 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/kernel.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/gpio.h>
+#include <linux/io.h>
+#include <asm/mach/arch.h>
+#include <plat/irq.h>
+#include <asm/mach/irq.h>
+#include <mach/pm.h>
+#include <mach/bridge-regs.h>
+#include "common.h"
+
+static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
+{
+       int irqoff;
+       BUG_ON(irq < IRQ_DOVE_GPIO_0_7 || irq > IRQ_DOVE_HIGH_GPIO);
+
+       irqoff = irq <= IRQ_DOVE_GPIO_16_23 ? irq - IRQ_DOVE_GPIO_0_7 :
+               3 + irq - IRQ_DOVE_GPIO_24_31;
+
+       orion_gpio_irq_handler(irqoff << 3);
+       if (irq == IRQ_DOVE_HIGH_GPIO) {
+               orion_gpio_irq_handler(40);
+               orion_gpio_irq_handler(48);
+               orion_gpio_irq_handler(56);
+       }
+}
+
+static void pmu_irq_mask(unsigned int irq)
+{
+       int pin = irq_to_pmu(irq);
+       u32 u;
+
+       u = readl(PMU_INTERRUPT_MASK);
+       u &= ~(1 << (pin & 31));
+       writel(u, PMU_INTERRUPT_MASK);
+}
+
+static void pmu_irq_unmask(unsigned int irq)
+{
+       int pin = irq_to_pmu(irq);
+       u32 u;
+
+       u = readl(PMU_INTERRUPT_MASK);
+       u |= 1 << (pin & 31);
+       writel(u, PMU_INTERRUPT_MASK);
+}
+
+static void pmu_irq_ack(unsigned int irq)
+{
+       int pin = irq_to_pmu(irq);
+       u32 u;
+
+       u = ~(1 << (pin & 31));
+       writel(u, PMU_INTERRUPT_CAUSE);
+}
+
+static struct irq_chip pmu_irq_chip = {
+       .name           = "pmu_irq",
+       .mask           = pmu_irq_mask,
+       .unmask         = pmu_irq_unmask,
+       .ack            = pmu_irq_ack,
+};
+
+static void pmu_irq_handler(unsigned int irq, struct irq_desc *desc)
+{
+       unsigned long cause = readl(PMU_INTERRUPT_CAUSE);
+
+       cause &= readl(PMU_INTERRUPT_MASK);
+       if (cause == 0) {
+               do_bad_IRQ(irq, desc);
+               return;
+       }
+
+       for (irq = 0; irq < NR_PMU_IRQS; irq++) {
+               if (!(cause & (1 << irq)))
+                       continue;
+               irq = pmu_to_irq(irq);
+               desc = irq_desc + irq;
+               desc_handle_irq(irq, desc);
+       }
+}
+
+void __init dove_init_irq(void)
+{
+       int i;
+
+       orion_irq_init(0, (void __iomem *)(IRQ_VIRT_BASE + IRQ_MASK_LOW_OFF));
+       orion_irq_init(32, (void __iomem *)(IRQ_VIRT_BASE + IRQ_MASK_HIGH_OFF));
+
+       /*
+        * Mask and clear GPIO IRQ interrupts.
+        */
+       writel(0, GPIO_LEVEL_MASK(0));
+       writel(0, GPIO_EDGE_MASK(0));
+       writel(0, GPIO_EDGE_CAUSE(0));
+
+       /*
+        * Mask and clear PMU interrupts
+        */
+       writel(0, PMU_INTERRUPT_MASK);
+       writel(0, PMU_INTERRUPT_CAUSE);
+
+       for (i = IRQ_DOVE_GPIO_START; i < IRQ_DOVE_PMU_START; i++) {
+               set_irq_chip(i, &orion_gpio_irq_chip);
+               set_irq_handler(i, handle_level_irq);
+               irq_desc[i].status |= IRQ_LEVEL;
+               set_irq_flags(i, IRQF_VALID);
+       }
+       set_irq_chained_handler(IRQ_DOVE_GPIO_0_7, gpio_irq_handler);
+       set_irq_chained_handler(IRQ_DOVE_GPIO_8_15, gpio_irq_handler);
+       set_irq_chained_handler(IRQ_DOVE_GPIO_16_23, gpio_irq_handler);
+       set_irq_chained_handler(IRQ_DOVE_GPIO_24_31, gpio_irq_handler);
+       set_irq_chained_handler(IRQ_DOVE_HIGH_GPIO, gpio_irq_handler);
+
+       for (i = IRQ_DOVE_PMU_START; i < NR_IRQS; i++) {
+               set_irq_chip(i, &pmu_irq_chip);
+               set_irq_handler(i, handle_level_irq);
+               irq_desc[i].status |= IRQ_LEVEL;
+               set_irq_flags(i, IRQF_VALID);
+       }
+       set_irq_chained_handler(IRQ_DOVE_PMU, pmu_irq_handler);
+}
diff --git a/arch/arm/mach-dove/pcie.c b/arch/arm/mach-dove/pcie.c
new file mode 100644 (file)
index 0000000..502d1ca
--- /dev/null
@@ -0,0 +1,238 @@
+/*
+ * arch/arm/mach-dove/pcie.c
+ *
+ * PCIe functions for Marvell Dove 88AP510 SoC
+ *
+ * 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/kernel.h>
+#include <linux/pci.h>
+#include <linux/mbus.h>
+#include <asm/mach/pci.h>
+#include <asm/mach/arch.h>
+#include <asm/setup.h>
+#include <asm/delay.h>
+#include <plat/pcie.h>
+#include <mach/irqs.h>
+#include <mach/bridge-regs.h>
+#include "common.h"
+
+struct pcie_port {
+       u8                      index;
+       u8                      root_bus_nr;
+       void __iomem            *base;
+       spinlock_t              conf_lock;
+       char                    io_space_name[16];
+       char                    mem_space_name[16];
+       struct resource         res[2];
+};
+
+static struct pcie_port pcie_port[2];
+static int num_pcie_ports;
+
+
+static int __init dove_pcie_setup(int nr, struct pci_sys_data *sys)
+{
+       struct pcie_port *pp;
+
+       if (nr >= num_pcie_ports)
+               return 0;
+
+       pp = &pcie_port[nr];
+       pp->root_bus_nr = sys->busnr;
+
+       /*
+        * Generic PCIe unit setup.
+        */
+       orion_pcie_set_local_bus_nr(pp->base, sys->busnr);
+
+       orion_pcie_setup(pp->base, &dove_mbus_dram_info);
+
+       /*
+        * IORESOURCE_IO
+        */
+       snprintf(pp->io_space_name, sizeof(pp->io_space_name),
+                "PCIe %d I/O", pp->index);
+       pp->io_space_name[sizeof(pp->io_space_name) - 1] = 0;
+       pp->res[0].name = pp->io_space_name;
+       if (pp->index == 0) {
+               pp->res[0].start = DOVE_PCIE0_IO_PHYS_BASE;
+               pp->res[0].end = pp->res[0].start + DOVE_PCIE0_IO_SIZE - 1;
+       } else {
+               pp->res[0].start = DOVE_PCIE1_IO_PHYS_BASE;
+               pp->res[0].end = pp->res[0].start + DOVE_PCIE1_IO_SIZE - 1;
+       }
+       pp->res[0].flags = IORESOURCE_IO;
+       if (request_resource(&ioport_resource, &pp->res[0]))
+               panic("Request PCIe IO resource failed\n");
+       sys->resource[0] = &pp->res[0];
+
+       /*
+        * IORESOURCE_MEM
+        */
+       snprintf(pp->mem_space_name, sizeof(pp->mem_space_name),
+                "PCIe %d MEM", pp->index);
+       pp->mem_space_name[sizeof(pp->mem_space_name) - 1] = 0;
+       pp->res[1].name = pp->mem_space_name;
+       if (pp->index == 0) {
+               pp->res[1].start = DOVE_PCIE0_MEM_PHYS_BASE;
+               pp->res[1].end = pp->res[1].start + DOVE_PCIE0_MEM_SIZE - 1;
+       } else {
+               pp->res[1].start = DOVE_PCIE1_MEM_PHYS_BASE;
+               pp->res[1].end = pp->res[1].start + DOVE_PCIE1_MEM_SIZE - 1;
+       }
+       pp->res[1].flags = IORESOURCE_MEM;
+       if (request_resource(&iomem_resource, &pp->res[1]))
+               panic("Request PCIe Memory resource failed\n");
+       sys->resource[1] = &pp->res[1];
+
+       sys->resource[2] = NULL;
+
+       return 1;
+}
+
+static struct pcie_port *bus_to_port(int bus)
+{
+       int i;
+
+       for (i = num_pcie_ports - 1; i >= 0; i--) {
+               int rbus = pcie_port[i].root_bus_nr;
+               if (rbus != -1 && rbus <= bus)
+                       break;
+       }
+
+       return i >= 0 ? pcie_port + i : NULL;
+}
+
+static int pcie_valid_config(struct pcie_port *pp, int bus, int dev)
+{
+       /*
+        * Don't go out when trying to access nonexisting devices
+        * on the local bus.
+        */
+       if (bus == pp->root_bus_nr && dev > 1)
+               return 0;
+
+       return 1;
+}
+
+static int pcie_rd_conf(struct pci_bus *bus, u32 devfn, int where,
+                       int size, u32 *val)
+{
+       struct pcie_port *pp = bus_to_port(bus->number);
+       unsigned long flags;
+       int ret;
+
+       if (pcie_valid_config(pp, bus->number, PCI_SLOT(devfn)) == 0) {
+               *val = 0xffffffff;
+               return PCIBIOS_DEVICE_NOT_FOUND;
+       }
+
+       spin_lock_irqsave(&pp->conf_lock, flags);
+       ret = orion_pcie_rd_conf(pp->base, bus, devfn, where, size, val);
+       spin_unlock_irqrestore(&pp->conf_lock, flags);
+
+       return ret;
+}
+
+static int pcie_wr_conf(struct pci_bus *bus, u32 devfn,
+                       int where, int size, u32 val)
+{
+       struct pcie_port *pp = bus_to_port(bus->number);
+       unsigned long flags;
+       int ret;
+
+       if (pcie_valid_config(pp, bus->number, PCI_SLOT(devfn)) == 0)
+               return PCIBIOS_DEVICE_NOT_FOUND;
+
+       spin_lock_irqsave(&pp->conf_lock, flags);
+       ret = orion_pcie_wr_conf(pp->base, bus, devfn, where, size, val);
+       spin_unlock_irqrestore(&pp->conf_lock, flags);
+
+       return ret;
+}
+
+static struct pci_ops pcie_ops = {
+       .read = pcie_rd_conf,
+       .write = pcie_wr_conf,
+};
+
+static void __devinit rc_pci_fixup(struct pci_dev *dev)
+{
+       /*
+        * Prevent enumeration of root complex.
+        */
+       if (dev->bus->parent == NULL && dev->devfn == 0) {
+               int i;
+
+               for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
+                       dev->resource[i].start = 0;
+                       dev->resource[i].end   = 0;
+                       dev->resource[i].flags = 0;
+               }
+       }
+}
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_MARVELL, PCI_ANY_ID, rc_pci_fixup);
+
+static struct pci_bus __init *
+dove_pcie_scan_bus(int nr, struct pci_sys_data *sys)
+{
+       struct pci_bus *bus;
+
+       if (nr < num_pcie_ports) {
+               bus = pci_scan_bus(sys->busnr, &pcie_ops, sys);
+       } else {
+               bus = NULL;
+               BUG();
+       }
+
+       return bus;
+}
+
+static int __init dove_pcie_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+{
+       struct pcie_port *pp = bus_to_port(dev->bus->number);
+
+       return pp->index ? IRQ_DOVE_PCIE1 : IRQ_DOVE_PCIE0;
+}
+
+static struct hw_pci dove_pci __initdata = {
+       .nr_controllers = 2,
+       .swizzle        = pci_std_swizzle,
+       .setup          = dove_pcie_setup,
+       .scan           = dove_pcie_scan_bus,
+       .map_irq        = dove_pcie_map_irq,
+};
+
+static void __init add_pcie_port(int index, unsigned long base)
+{
+       printk(KERN_INFO "Dove PCIe port %d: ", index);
+
+       if (orion_pcie_link_up((void __iomem *)base)) {
+               struct pcie_port *pp = &pcie_port[num_pcie_ports++];
+
+               printk(KERN_INFO "link up\n");
+
+               pp->index = index;
+               pp->root_bus_nr = -1;
+               pp->base = (void __iomem *)base;
+               spin_lock_init(&pp->conf_lock);
+               memset(pp->res, 0, sizeof(pp->res));
+       } else {
+               printk(KERN_INFO "link down, ignoring\n");
+       }
+}
+
+void __init dove_pcie_init(int init_port0, int init_port1)
+{
+       if (init_port0)
+               add_pcie_port(0, DOVE_PCIE0_VIRT_BASE);
+
+       if (init_port1)
+               add_pcie_port(1, DOVE_PCIE1_VIRT_BASE);
+
+       pci_common_init(&dove_pci);
+}
index b4357c3..1f0d665 100644 (file)
@@ -31,6 +31,7 @@
 
 #include <mach/hardware.h>
 #include <mach/fb.h>
+#include <mach/ep93xx_keypad.h>
 
 #include <asm/mach/map.h>
 #include <asm/mach/time.h>
@@ -728,6 +729,82 @@ void __init ep93xx_register_fb(struct ep93xxfb_mach_info *data)
        platform_device_register(&ep93xx_fb_device);
 }
 
+
+/*************************************************************************
+ * EP93xx matrix keypad peripheral handling
+ *************************************************************************/
+static struct resource ep93xx_keypad_resource[] = {
+       {
+               .start  = EP93XX_KEY_MATRIX_PHYS_BASE,
+               .end    = EP93XX_KEY_MATRIX_PHYS_BASE + 0x0c - 1,
+               .flags  = IORESOURCE_MEM,
+       }, {
+               .start  = IRQ_EP93XX_KEY,
+               .end    = IRQ_EP93XX_KEY,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device ep93xx_keypad_device = {
+       .name                   = "ep93xx-keypad",
+       .id                     = -1,
+       .num_resources          = ARRAY_SIZE(ep93xx_keypad_resource),
+       .resource               = ep93xx_keypad_resource,
+};
+
+void __init ep93xx_register_keypad(struct ep93xx_keypad_platform_data *data)
+{
+       ep93xx_keypad_device.dev.platform_data = data;
+       platform_device_register(&ep93xx_keypad_device);
+}
+
+int ep93xx_keypad_acquire_gpio(struct platform_device *pdev)
+{
+       int err;
+       int i;
+
+       for (i = 0; i < 8; i++) {
+               err = gpio_request(EP93XX_GPIO_LINE_C(i), dev_name(&pdev->dev));
+               if (err)
+                       goto fail_gpio_c;
+               err = gpio_request(EP93XX_GPIO_LINE_D(i), dev_name(&pdev->dev));
+               if (err)
+                       goto fail_gpio_d;
+       }
+
+       /* Enable the keypad controller; GPIO ports C and D used for keypad */
+       ep93xx_devcfg_clear_bits(EP93XX_SYSCON_DEVCFG_KEYS |
+                                EP93XX_SYSCON_DEVCFG_GONK);
+
+       return 0;
+
+fail_gpio_d:
+       gpio_free(EP93XX_GPIO_LINE_C(i));
+fail_gpio_c:
+       for ( ; i >= 0; --i) {
+               gpio_free(EP93XX_GPIO_LINE_C(i));
+               gpio_free(EP93XX_GPIO_LINE_D(i));
+       }
+       return err;
+}
+EXPORT_SYMBOL(ep93xx_keypad_acquire_gpio);
+
+void ep93xx_keypad_release_gpio(struct platform_device *pdev)
+{
+       int i;
+
+       for (i = 0; i < 8; i++) {
+               gpio_free(EP93XX_GPIO_LINE_C(i));
+               gpio_free(EP93XX_GPIO_LINE_D(i));
+       }
+
+       /* Disable the keypad controller; GPIO ports C and D used for GPIO */
+       ep93xx_devcfg_set_bits(EP93XX_SYSCON_DEVCFG_KEYS |
+                              EP93XX_SYSCON_DEVCFG_GONK);
+}
+EXPORT_SYMBOL(ep93xx_keypad_release_gpio);
+
+
 extern void ep93xx_gpio_init(void);
 
 void __init ep93xx_init_devices(void)
index 04b37a8..50cb991 100644 (file)
@@ -1,3 +1,7 @@
+/*
+ * arch/arm/mach-ep93xx/include/mach/clkdev.h
+ */
+
 #ifndef __ASM_MACH_CLKDEV_H
 #define __ASM_MACH_CLKDEV_H
 
index ef6bd9d..3a5961d 100644 (file)
@@ -1,3 +1,7 @@
+/*
+ * arch/arm/mach-ep93xx/include/mach/dma.h
+ */
+
 #ifndef __ASM_ARCH_DMA_H
 #define __ASM_ARCH_DMA_H
 
index b1f937e..d55194a 100644 (file)
 #define EP93XX_UART3_PHYS_BASE         EP93XX_APB_PHYS(0x000e0000)
 #define EP93XX_UART3_BASE              EP93XX_APB_IOMEM(0x000e0000)
 
+#define EP93XX_KEY_MATRIX_PHYS_BASE    EP93XX_APB_PHYS(0x000f0000)
 #define EP93XX_KEY_MATRIX_BASE         EP93XX_APB_IOMEM(0x000f0000)
 
 #define EP93XX_ADC_BASE                        EP93XX_APB_IOMEM(0x00100000)
index 349fa7c..5a3ce02 100644 (file)
@@ -1,6 +1,7 @@
 /*
  * arch/arm/mach-ep93xx/include/mach/hardware.h
  */
+
 #ifndef __ASM_ARCH_HARDWARE_H
 #define __ASM_ARCH_HARDWARE_H
 
index cebcc1c..594b77f 100644 (file)
@@ -1,6 +1,7 @@
 /*
  * arch/arm/mach-ep93xx/include/mach/io.h
  */
+
 #ifndef __ASM_MACH_IO_H
 #define __ASM_MACH_IO_H
 
index 469fd96..c6dc14d 100644 (file)
@@ -8,6 +8,7 @@ struct i2c_gpio_platform_data;
 struct i2c_board_info;
 struct platform_device;
 struct ep93xxfb_mach_info;
+struct ep93xx_keypad_platform_data;
 
 struct ep93xx_eth_data
 {
@@ -39,6 +40,9 @@ void ep93xx_register_fb(struct ep93xxfb_mach_info *data);
 void ep93xx_register_pwm(int pwm0, int pwm1);
 int ep93xx_pwm_acquire_gpio(struct platform_device *pdev);
 void ep93xx_pwm_release_gpio(struct platform_device *pdev);
+void ep93xx_register_keypad(struct ep93xx_keypad_platform_data *data);
+int ep93xx_keypad_acquire_gpio(struct platform_device *pdev);
+void ep93xx_keypad_release_gpio(struct platform_device *pdev);
 
 void ep93xx_init_devices(void);
 extern struct sys_timer ep93xx_timer;
index 42ae29b..25b1da9 100644 (file)
@@ -64,6 +64,8 @@ static inline unsigned long __lbus_to_virt(dma_addr_t x)
                (dma_addr_t)page_to_phys(page);                         \
        })
 
+#define __arch_dma_to_page(dev, addr)  phys_to_page(addr)
+
 #endif /* CONFIG_ARCH_IOP13XX */
 #endif /* !ASSEMBLY */
 
index d6d5252..f1c00d6 100644 (file)
@@ -20,7 +20,6 @@
 #define IOP13XX_CORE_FREQ_1200         (5 << 16)
 
 void iop_init_time(unsigned long tickrate);
-unsigned long iop_gettimeoffset(void);
 
 static inline unsigned long iop13xx_core_freq(void)
 {
@@ -66,6 +65,13 @@ static inline unsigned long iop13xx_xsi_bus_ratio(void)
        return 2;
 }
 
+static inline u32 read_tmr0(void)
+{
+       u32 val;
+       asm volatile("mrc p6, 0, %0, c0, c9, 0" : "=r" (val));
+       return val;
+}
+
 static inline void write_tmr0(u32 val)
 {
        asm volatile("mcr p6, 0, %0, c0, c9, 0" : : "r" (val));
@@ -83,6 +89,11 @@ static inline u32 read_tcr0(void)
        return val;
 }
 
+static inline void write_tcr0(u32 val)
+{
+       asm volatile("mcr p6, 0, %0, c2, c9, 0" : : "r" (val));
+}
+
 static inline u32 read_tcr1(void)
 {
        u32 val;
@@ -90,6 +101,11 @@ static inline u32 read_tcr1(void)
        return val;
 }
 
+static inline void write_tcr1(u32 val)
+{
+       asm volatile("mcr p6, 0, %0, c3, c9, 0" : : "r" (val));
+}
+
 static inline void write_trr0(u32 val)
 {
        asm volatile("mcr p6, 0, %0, c4, c9, 0" : : "r" (val));
index 5051c03..f91f315 100644 (file)
@@ -87,7 +87,6 @@ static void __init iq81340mc_timer_init(void)
 
 static struct sys_timer iq81340mc_timer = {
        .init       = iq81340mc_timer_init,
-       .offset     = iop_gettimeoffset,
 };
 
 MACHINE_START(IQ81340MC, "Intel IQ81340MC")
index bc44307..ddb7a34 100644 (file)
@@ -89,7 +89,6 @@ static void __init iq81340sc_timer_init(void)
 
 static struct sys_timer iq81340sc_timer = {
        .init       = iq81340sc_timer_init,
-       .offset     = iop_gettimeoffset,
 };
 
 MACHINE_START(IQ81340SC, "Intel IQ81340SC")
index 3ad4696..2bef9b6 100644 (file)
@@ -42,7 +42,6 @@ static void __init em7210_timer_init(void)
 
 static struct sys_timer em7210_timer = {
        .init           = em7210_timer_init,
-       .offset         = iop_gettimeoffset,
 };
 
 /*
index a9c2dfd..93370a4 100644 (file)
@@ -47,7 +47,6 @@ static void __init glantank_timer_init(void)
 
 static struct sys_timer glantank_timer = {
        .init           = glantank_timer_init,
-       .offset         = iop_gettimeoffset,
 };
 
 
index dd1cd99..a7a08dd 100644 (file)
@@ -78,7 +78,6 @@ static void __init iq31244_timer_init(void)
 
 static struct sys_timer iq31244_timer = {
        .init           = iq31244_timer_init,
-       .offset         = iop_gettimeoffset,
 };
 
 
index fbe2779..0200f80 100644 (file)
@@ -46,7 +46,6 @@ static void __init iq80321_timer_init(void)
 
 static struct sys_timer iq80321_timer = {
        .init           = iq80321_timer_init,
-       .offset         = iop_gettimeoffset,
 };
 
 
index d2e4278..2a5c637 100644 (file)
@@ -53,7 +53,6 @@ static void __init n2100_timer_init(void)
 
 static struct sys_timer n2100_timer = {
        .init           = n2100_timer_init,
-       .offset         = iop_gettimeoffset,
 };
 
 
index d51e10c..394e95a 100644 (file)
@@ -48,7 +48,6 @@ static void __init iq80331_timer_init(void)
 
 static struct sys_timer iq80331_timer = {
        .init           = iq80331_timer_init,
-       .offset         = iop_gettimeoffset,
 };
 
 
index 92fb44c..a40badf 100644 (file)
@@ -48,7 +48,6 @@ static void __init iq80332_timer_init(void)
 
 static struct sys_timer iq80332_timer = {
        .init           = iq80332_timer_init,
-       .offset         = iop_gettimeoffset,
 };
 
 
index 0aca451..8bf09ae 100644 (file)
@@ -33,10 +33,18 @@ config MACH_SHEEVAPLUG
          Marvell SheevaPlug Reference Board.
 
 config MACH_TS219
-       bool "QNAP TS-119 and TS-219 Turbo NAS"
+       bool "QNAP TS-110, TS-119, TS-210, TS-219 and TS-219P Turbo NAS"
        help
          Say 'Y' here if you want your kernel to support the
-         QNAP TS-119 and TS-219 Turbo NAS devices.
+         QNAP TS-110, TS-119, TS-210, TS-219 and TS-219P Turbo NAS
+         devices.
+
+config MACH_TS41X
+       bool "QNAP TS-410, TS-410U, TS-419P and TS-419U Turbo NAS"
+       help
+         Say 'Y' here if you want your kernel to support the
+         QNAP TS-410, TS-410U, TS-419P and TS-419U Turbo NAS
+         devices.
 
 config MACH_OPENRD_BASE
        bool "Marvell OpenRD Base Board"
index 80ab0ec..9f2f67b 100644 (file)
@@ -5,7 +5,8 @@ obj-$(CONFIG_MACH_RD88F6192_NAS)        += rd88f6192-nas-setup.o
 obj-$(CONFIG_MACH_RD88F6281)           += rd88f6281-setup.o
 obj-$(CONFIG_MACH_MV88F6281GTW_GE)     += mv88f6281gtw_ge-setup.o
 obj-$(CONFIG_MACH_SHEEVAPLUG)          += sheevaplug-setup.o
-obj-$(CONFIG_MACH_TS219)               += ts219-setup.o
+obj-$(CONFIG_MACH_TS219)               += ts219-setup.o tsx1x-common.o
+obj-$(CONFIG_MACH_TS41X)               += ts41x-setup.o tsx1x-common.o
 obj-$(CONFIG_MACH_OPENRD_BASE)         += openrd_base-setup.o
 
 obj-$(CONFIG_CPU_IDLE)                 += cpuidle.o
index ec1a64f..2830f0f 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- * QNAP TS-119/TS-219 Turbo NAS Board Setup
+ * QNAP TS-11x/TS-21x Turbo NAS Board Setup
  *
  * Copyright (C) 2009  Martin Michlmayr <tbm@cyrius.com>
  * Copyright (C) 2008  Byron Bradley <byron.bbradley@gmail.com>
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/platform_device.h>
-#include <linux/mtd/physmap.h>
-#include <linux/spi/flash.h>
-#include <linux/spi/spi.h>
-#include <linux/spi/orion_spi.h>
 #include <linux/i2c.h>
 #include <linux/mv643xx_eth.h>
 #include <linux/ata_platform.h>
 #include <linux/gpio_keys.h>
 #include <linux/input.h>
-#include <linux/timex.h>
-#include <linux/serial_reg.h>
-#include <linux/pci.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <mach/kirkwood.h>
 #include "common.h"
 #include "mpp.h"
-
-/****************************************************************************
- * 16 MiB NOR flash. The struct mtd_partition is not in the same order as the
- *     partitions on the device because we want to keep compatability with
- *     the QNAP firmware.
- * Layout as used by QNAP:
- *  0x00000000-0x00080000 : "U-Boot"
- *  0x00200000-0x00400000 : "Kernel"
- *  0x00400000-0x00d00000 : "RootFS"
- *  0x00d00000-0x01000000 : "RootFS2"
- *  0x00080000-0x000c0000 : "U-Boot Config"
- *  0x000c0000-0x00200000 : "NAS Config"
- *
- * We'll use "RootFS1" instead of "RootFS" to stay compatible with the layout
- * used by the QNAP TS-109/TS-209.
- *
- ***************************************************************************/
-
-static struct mtd_partition qnap_ts219_partitions[] = {
-       {
-               .name           = "U-Boot",
-               .size           = 0x00080000,
-               .offset         = 0,
-               .mask_flags     = MTD_WRITEABLE,
-       }, {
-               .name           = "Kernel",
-               .size           = 0x00200000,
-               .offset         = 0x00200000,
-       }, {
-               .name           = "RootFS1",
-               .size           = 0x00900000,
-               .offset         = 0x00400000,
-       }, {
-               .name           = "RootFS2",
-               .size           = 0x00300000,
-               .offset         = 0x00d00000,
-       }, {
-               .name           = "U-Boot Config",
-               .size           = 0x00040000,
-               .offset         = 0x00080000,
-       }, {
-               .name           = "NAS Config",
-               .size           = 0x00140000,
-               .offset         = 0x000c0000,
-       },
-};
-
-static const struct flash_platform_data qnap_ts219_flash = {
-       .type           = "m25p128",
-       .name           = "spi_flash",
-       .parts          = qnap_ts219_partitions,
-       .nr_parts       = ARRAY_SIZE(qnap_ts219_partitions),
-};
-
-static struct spi_board_info __initdata qnap_ts219_spi_slave_info[] = {
-       {
-               .modalias       = "m25p80",
-               .platform_data  = &qnap_ts219_flash,
-               .irq            = -1,
-               .max_speed_hz   = 20000000,
-               .bus_num        = 0,
-               .chip_select    = 0,
-       },
-};
+#include "tsx1x-common.h"
 
 static struct i2c_board_info __initdata qnap_ts219_i2c_rtc = {
        I2C_BOARD_INFO("s35390a", 0x30),
@@ -152,36 +82,10 @@ static unsigned int qnap_ts219_mpp_config[] __initdata = {
        MPP14_UART1_RXD,        /* PIC controller */
        MPP15_GPIO,             /* USB Copy button */
        MPP16_GPIO,             /* Reset button */
+       MPP36_GPIO,             /* RAM: 0: 256 MB, 1: 512 MB */
        0
 };
 
-
-/*****************************************************************************
- * QNAP TS-x19 specific power off method via UART1-attached PIC
- ****************************************************************************/
-
-#define UART1_REG(x)   (UART1_VIRT_BASE + ((UART_##x) << 2))
-
-void qnap_ts219_power_off(void)
-{
-       /* 19200 baud divisor */
-       const unsigned divisor = ((kirkwood_tclk + (8 * 19200)) / (16 * 19200));
-
-       pr_info("%s: triggering power-off...\n", __func__);
-
-       /* hijack UART1 and reset into sane state (19200,8n1) */
-       writel(0x83, UART1_REG(LCR));
-       writel(divisor & 0xff, UART1_REG(DLL));
-       writel((divisor >> 8) & 0xff, UART1_REG(DLM));
-       writel(0x03, UART1_REG(LCR));
-       writel(0x00, UART1_REG(IER));
-       writel(0x00, UART1_REG(FCR));
-       writel(0x00, UART1_REG(MCR));
-
-       /* send the power-off command 'A' to PIC */
-       writel('A', UART1_REG(TX));
-}
-
 static void __init qnap_ts219_init(void)
 {
        /*
@@ -192,9 +96,7 @@ static void __init qnap_ts219_init(void)
 
        kirkwood_uart0_init();
        kirkwood_uart1_init(); /* A PIC controller is connected here. */
-       spi_register_board_info(qnap_ts219_spi_slave_info,
-                               ARRAY_SIZE(qnap_ts219_spi_slave_info));
-       kirkwood_spi_init();
+       qnap_tsx1x_register_flash();
        kirkwood_i2c_init();
        i2c_register_board_info(0, &qnap_ts219_i2c_rtc, 1);
        kirkwood_ge00_init(&qnap_ts219_ge00_data);
@@ -202,7 +104,7 @@ static void __init qnap_ts219_init(void)
        kirkwood_ehci_init();
        platform_device_register(&qnap_ts219_button_device);
 
-       pm_power_off = qnap_ts219_power_off;
+       pm_power_off = qnap_tsx1x_power_off;
 
 }
 
diff --git a/arch/arm/mach-kirkwood/ts41x-setup.c b/arch/arm/mach-kirkwood/ts41x-setup.c
new file mode 100644 (file)
index 0000000..de49c2d
--- /dev/null
@@ -0,0 +1,154 @@
+/*
+ *
+ * QNAP TS-410, TS-410U, TS-419P and TS-419U Turbo NAS Board Setup
+ *
+ * Copyright (C) 2009  Martin Michlmayr <tbm@cyrius.com>
+ * Copyright (C) 2008  Byron Bradley <byron.bbradley@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/i2c.h>
+#include <linux/mv643xx_eth.h>
+#include <linux/ata_platform.h>
+#include <linux/gpio_keys.h>
+#include <linux/input.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <mach/kirkwood.h>
+#include "common.h"
+#include "mpp.h"
+#include "tsx1x-common.h"
+
+static struct i2c_board_info __initdata qnap_ts41x_i2c_rtc = {
+       I2C_BOARD_INFO("s35390a", 0x30),
+};
+
+static struct mv643xx_eth_platform_data qnap_ts41x_ge00_data = {
+       .phy_addr       = MV643XX_ETH_PHY_ADDR(8),
+};
+
+static struct mv643xx_eth_platform_data qnap_ts41x_ge01_data = {
+       .phy_addr       = MV643XX_ETH_PHY_ADDR(0),
+};
+
+static struct mv_sata_platform_data qnap_ts41x_sata_data = {
+       .n_ports        = 2,
+};
+
+static struct gpio_keys_button qnap_ts41x_buttons[] = {
+       {
+               .code           = KEY_COPY,
+               .gpio           = 43,
+               .desc           = "USB Copy",
+               .active_low     = 1,
+       },
+       {
+               .code           = KEY_RESTART,
+               .gpio           = 37,
+               .desc           = "Reset",
+               .active_low     = 1,
+       },
+};
+
+static struct gpio_keys_platform_data qnap_ts41x_button_data = {
+       .buttons        = qnap_ts41x_buttons,
+       .nbuttons       = ARRAY_SIZE(qnap_ts41x_buttons),
+};
+
+static struct platform_device qnap_ts41x_button_device = {
+       .name           = "gpio-keys",
+       .id             = -1,
+       .num_resources  = 0,
+       .dev            = {
+               .platform_data  = &qnap_ts41x_button_data,
+       }
+};
+
+static unsigned int qnap_ts41x_mpp_config[] __initdata = {
+       MPP0_SPI_SCn,
+       MPP1_SPI_MOSI,
+       MPP2_SPI_SCK,
+       MPP3_SPI_MISO,
+       MPP6_SYSRST_OUTn,
+       MPP7_PEX_RST_OUTn,
+       MPP8_TW_SDA,
+       MPP9_TW_SCK,
+       MPP10_UART0_TXD,
+       MPP11_UART0_RXD,
+       MPP13_UART1_TXD,        /* PIC controller */
+       MPP14_UART1_RXD,        /* PIC controller */
+       MPP15_SATA0_ACTn,
+       MPP16_SATA1_ACTn,
+       MPP20_GE1_0,
+       MPP21_GE1_1,
+       MPP22_GE1_2,
+       MPP23_GE1_3,
+       MPP24_GE1_4,
+       MPP25_GE1_5,
+       MPP26_GE1_6,
+       MPP27_GE1_7,
+       MPP30_GE1_10,
+       MPP31_GE1_11,
+       MPP32_GE1_12,
+       MPP33_GE1_13,
+       MPP36_GPIO,             /* RAM: 0: 256 MB, 1: 512 MB */
+       MPP37_GPIO,             /* Reset button */
+       MPP43_GPIO,             /* USB Copy button */
+       MPP44_GPIO,             /* Board ID: 0: TS-419U, 1: TS-419 */
+       MPP45_GPIO,             /* JP1: 0: console, 1: LCD */
+       MPP46_GPIO,             /* External SATA HDD1 error indicator */
+       MPP47_GPIO,             /* External SATA HDD2 error indicator */
+       MPP48_GPIO,             /* External SATA HDD3 error indicator */
+       MPP49_GPIO,             /* External SATA HDD4 error indicator */
+       0
+};
+
+static void __init qnap_ts41x_init(void)
+{
+       /*
+        * Basic setup. Needs to be called early.
+        */
+       kirkwood_init();
+       kirkwood_mpp_conf(qnap_ts41x_mpp_config);
+
+       kirkwood_uart0_init();
+       kirkwood_uart1_init(); /* A PIC controller is connected here. */
+       qnap_tsx1x_register_flash();
+       kirkwood_i2c_init();
+       i2c_register_board_info(0, &qnap_ts41x_i2c_rtc, 1);
+       kirkwood_ge00_init(&qnap_ts41x_ge00_data);
+       kirkwood_ge01_init(&qnap_ts41x_ge01_data);
+       kirkwood_sata_init(&qnap_ts41x_sata_data);
+       kirkwood_ehci_init();
+       platform_device_register(&qnap_ts41x_button_device);
+
+       pm_power_off = qnap_tsx1x_power_off;
+
+}
+
+static int __init ts41x_pci_init(void)
+{
+       if (machine_is_ts41x())
+               kirkwood_pcie_init();
+
+   return 0;
+}
+subsys_initcall(ts41x_pci_init);
+
+MACHINE_START(TS41X, "QNAP TS-41x")
+       /* Maintainer: Martin Michlmayr <tbm@cyrius.com> */
+       .phys_io        = KIRKWOOD_REGS_PHYS_BASE,
+       .io_pg_offst    = ((KIRKWOOD_REGS_VIRT_BASE) >> 18) & 0xfffc,
+       .boot_params    = 0x00000100,
+       .init_machine   = qnap_ts41x_init,
+       .map_io         = kirkwood_map_io,
+       .init_irq       = kirkwood_init_irq,
+       .timer          = &kirkwood_timer,
+MACHINE_END
diff --git a/arch/arm/mach-kirkwood/tsx1x-common.c b/arch/arm/mach-kirkwood/tsx1x-common.c
new file mode 100644 (file)
index 0000000..7221c20
--- /dev/null
@@ -0,0 +1,113 @@
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/platform_device.h>
+#include <linux/mtd/physmap.h>
+#include <linux/spi/flash.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/orion_spi.h>
+#include <linux/serial_reg.h>
+#include <mach/kirkwood.h>
+#include "common.h"
+
+/*
+ * QNAP TS-x1x Boards flash
+ */
+
+/****************************************************************************
+ * 16 MiB NOR flash. The struct mtd_partition is not in the same order as the
+ *     partitions on the device because we want to keep compatability with
+ *     the QNAP firmware.
+ * Layout as used by QNAP:
+ *  0x00000000-0x00080000 : "U-Boot"
+ *  0x00200000-0x00400000 : "Kernel"
+ *  0x00400000-0x00d00000 : "RootFS"
+ *  0x00d00000-0x01000000 : "RootFS2"
+ *  0x00080000-0x000c0000 : "U-Boot Config"
+ *  0x000c0000-0x00200000 : "NAS Config"
+ *
+ * We'll use "RootFS1" instead of "RootFS" to stay compatible with the layout
+ * used by the QNAP TS-109/TS-209.
+ *
+ ***************************************************************************/
+
+struct mtd_partition qnap_tsx1x_partitions[] = {
+       {
+               .name           = "U-Boot",
+               .size           = 0x00080000,
+               .offset         = 0,
+               .mask_flags     = MTD_WRITEABLE,
+       }, {
+               .name           = "Kernel",
+               .size           = 0x00200000,
+               .offset         = 0x00200000,
+       }, {
+               .name           = "RootFS1",
+               .size           = 0x00900000,
+               .offset         = 0x00400000,
+       }, {
+               .name           = "RootFS2",
+               .size           = 0x00300000,
+               .offset         = 0x00d00000,
+       }, {
+               .name           = "U-Boot Config",
+               .size           = 0x00040000,
+               .offset         = 0x00080000,
+       }, {
+               .name           = "NAS Config",
+               .size           = 0x00140000,
+               .offset         = 0x000c0000,
+       },
+};
+
+const struct flash_platform_data qnap_tsx1x_flash = {
+       .type           = "m25p128",
+       .name           = "spi_flash",
+       .parts          = qnap_tsx1x_partitions,
+       .nr_parts       = ARRAY_SIZE(qnap_tsx1x_partitions),
+};
+
+struct spi_board_info __initdata qnap_tsx1x_spi_slave_info[] = {
+       {
+               .modalias       = "m25p80",
+               .platform_data  = &qnap_tsx1x_flash,
+               .irq            = -1,
+               .max_speed_hz   = 20000000,
+               .bus_num        = 0,
+               .chip_select    = 0,
+       },
+};
+
+void qnap_tsx1x_register_flash(void)
+{
+       spi_register_board_info(qnap_tsx1x_spi_slave_info,
+                               ARRAY_SIZE(qnap_tsx1x_spi_slave_info));
+       kirkwood_spi_init();
+}
+
+
+/*****************************************************************************
+ * QNAP TS-x1x specific power off method via UART1-attached PIC
+ ****************************************************************************/
+
+#define UART1_REG(x)   (UART1_VIRT_BASE + ((UART_##x) << 2))
+
+void qnap_tsx1x_power_off(void)
+{
+       /* 19200 baud divisor */
+       const unsigned divisor = ((kirkwood_tclk + (8 * 19200)) / (16 * 19200));
+
+       pr_info("%s: triggering power-off...\n", __func__);
+
+       /* hijack UART1 and reset into sane state (19200,8n1) */
+       writel(0x83, UART1_REG(LCR));
+       writel(divisor & 0xff, UART1_REG(DLL));
+       writel((divisor >> 8) & 0xff, UART1_REG(DLM));
+       writel(0x03, UART1_REG(LCR));
+       writel(0x00, UART1_REG(IER));
+       writel(0x00, UART1_REG(FCR));
+       writel(0x00, UART1_REG(MCR));
+
+       /* send the power-off command 'A' to PIC */
+       writel('A', UART1_REG(TX));
+}
+
diff --git a/arch/arm/mach-kirkwood/tsx1x-common.h b/arch/arm/mach-kirkwood/tsx1x-common.h
new file mode 100644 (file)
index 0000000..9a59296
--- /dev/null
@@ -0,0 +1,7 @@
+#ifndef __ARCH_KIRKWOOD_TSX1X_COMMON_H
+#define __ARCH_KIRKWOOD_TSX1X_COMMON_H
+
+extern void qnap_tsx1x_register_flash(void);
+extern void qnap_tsx1x_power_off(void);
+
+#endif
index 76e5308..ffa19aa 100644 (file)
@@ -41,6 +41,13 @@ extern struct bus_type platform_bus_type;
                __dma = __dma - PHYS_OFFSET + KS8695_PCIMEM_PA; \
           __dma; })
 
+#define __arch_dma_to_page(dev, x)     \
+       ({ dma_addr_t __dma = x;                                \
+          if (!is_lbus_device(dev))                            \
+               __dma += PHYS_OFFSET - KS8695_PCIMEM_PA;        \
+          phys_to_page(__dma);                                 \
+       })
+
 #endif
 
 #endif
index 4562452..a2d307e 100644 (file)
@@ -13,6 +13,9 @@
 #include <linux/kernel.h>
 #include <linux/platform_device.h>
 #include <linux/smc91x.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/nand.h>
 
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
@@ -85,12 +88,48 @@ static struct platform_device smc91x_device = {
        .resource       = smc91x_resources,
 };
 
+static struct mtd_partition aspenite_nand_partitions[] = {
+       {
+               .name           = "bootloader",
+               .offset         = 0,
+               .size           = SZ_1M,
+               .mask_flags     = MTD_WRITEABLE,
+       }, {
+               .name           = "reserved",
+               .offset         = MTDPART_OFS_APPEND,
+               .size           = SZ_128K,
+               .mask_flags     = MTD_WRITEABLE,
+       }, {
+               .name           = "reserved",
+               .offset         = MTDPART_OFS_APPEND,
+               .size           = SZ_8M,
+               .mask_flags     = MTD_WRITEABLE,
+       }, {
+               .name           = "kernel",
+               .offset         = MTDPART_OFS_APPEND,
+               .size           = (SZ_2M + SZ_1M),
+               .mask_flags     = 0,
+       }, {
+               .name           = "filesystem",
+               .offset         = MTDPART_OFS_APPEND,
+               .size           = SZ_48M,
+               .mask_flags     = 0,
+       }
+};
+
+static struct pxa3xx_nand_platform_data aspenite_nand_info = {
+       .enable_arbiter = 1,
+       .parts          = aspenite_nand_partitions,
+       .nr_parts       = ARRAY_SIZE(aspenite_nand_partitions),
+};
+
 static void __init common_init(void)
 {
        mfp_config(ARRAY_AND_SIZE(common_pin_config));
 
        /* on-chip devices */
        pxa168_add_uart(1);
+       pxa168_add_nand(&aspenite_nand_info);
 
        /* off-chip devices */
        platform_device_register(&smc91x_device);
index 2d9cc5a..2a46ed5 100644 (file)
@@ -34,6 +34,21 @@ struct clkops apbc_clk_ops = {
        .disable        = apbc_clk_disable,
 };
 
+static void apmu_clk_enable(struct clk *clk)
+{
+       __raw_writel(clk->enable_val, clk->clk_rst);
+}
+
+static void apmu_clk_disable(struct clk *clk)
+{
+       __raw_writel(0, clk->clk_rst);
+}
+
+struct clkops apmu_clk_ops = {
+       .enable         = apmu_clk_enable,
+       .disable        = apmu_clk_disable,
+};
+
 static DEFINE_SPINLOCK(clocks_lock);
 
 int clk_enable(struct clk *clk)
index ed967e7..eefffbe 100644 (file)
@@ -25,6 +25,7 @@ struct clk {
 };
 
 extern struct clkops apbc_clk_ops;
+extern struct clkops apmu_clk_ops;
 
 #define APBC_CLK(_name, _reg, _fnclksel, _rate)                        \
 struct clk clk_##_name = {                                     \
index 16295cf..d68871b 100644 (file)
@@ -31,7 +31,9 @@
 #define IRQ_PXA168_DDR_INT             26
 #define IRQ_PXA168_UART1               27
 #define IRQ_PXA168_UART2               28
+#define IRQ_PXA168_UART3               29
 #define IRQ_PXA168_WDT                 35
+#define IRQ_PXA168_MAIN_PMU            36
 #define IRQ_PXA168_FRQ_CHANGE          38
 #define IRQ_PXA168_SDH1                        39
 #define IRQ_PXA168_SDH2                        40
@@ -46,7 +48,7 @@
 #define IRQ_PXA168_USB2                        51
 #define IRQ_PXA168_AC97                        57
 #define IRQ_PXA168_TWSI1               58
-#define IRQ_PXA168_PMU                 60
+#define IRQ_PXA168_AP_PMU              60
 #define IRQ_PXA168_SM_INT              63
 
 /*
index 6bf1f0e..3ad612c 100644 (file)
@@ -4,6 +4,7 @@
 #include <linux/i2c.h>
 #include <mach/devices.h>
 #include <plat/i2c.h>
+#include <plat/pxa3xx_nand.h>
 
 extern struct pxa_device_desc pxa168_device_uart1;
 extern struct pxa_device_desc pxa168_device_uart2;
@@ -13,6 +14,7 @@ extern struct pxa_device_desc pxa168_device_pwm1;
 extern struct pxa_device_desc pxa168_device_pwm2;
 extern struct pxa_device_desc pxa168_device_pwm3;
 extern struct pxa_device_desc pxa168_device_pwm4;
+extern struct pxa_device_desc pxa168_device_nand;
 
 static inline int pxa168_add_uart(int id)
 {
@@ -64,4 +66,9 @@ static inline int pxa168_add_pwm(int id)
 
        return pxa_register_device(d, NULL, 0);
 }
+
+static inline int pxa168_add_nand(struct pxa3xx_nand_platform_data *info)
+{
+       return pxa_register_device(&pxa168_device_nand, info, sizeof(*info));
+}
 #endif /* __ASM_MACH_PXA168_H */
index 6ae1ed7..4f0b4ec 100644 (file)
@@ -4,6 +4,7 @@
 #include <linux/i2c.h>
 #include <mach/devices.h>
 #include <plat/i2c.h>
+#include <plat/pxa3xx_nand.h>
 
 extern struct pxa_device_desc pxa910_device_uart1;
 extern struct pxa_device_desc pxa910_device_uart2;
@@ -13,6 +14,7 @@ extern struct pxa_device_desc pxa910_device_pwm1;
 extern struct pxa_device_desc pxa910_device_pwm2;
 extern struct pxa_device_desc pxa910_device_pwm3;
 extern struct pxa_device_desc pxa910_device_pwm4;
+extern struct pxa_device_desc pxa910_device_nand;
 
 static inline int pxa910_add_uart(int id)
 {
@@ -64,4 +66,9 @@ static inline int pxa910_add_pwm(int id)
 
        return pxa_register_device(d, NULL, 0);
 }
+
+static inline int pxa910_add_nand(struct pxa3xx_nand_platform_data *info)
+{
+       return pxa_register_device(&pxa910_device_nand, info, sizeof(*info));
+}
 #endif /* __ASM_MACH_PXA910_H */
index 71b1ae3..37dbdde 100644 (file)
@@ -19,6 +19,7 @@
 #include <mach/addr-map.h>
 #include <mach/cputype.h>
 #include <mach/regs-apbc.h>
+#include <mach/regs-apmu.h>
 #include <mach/irqs.h>
 #include <mach/gpio.h>
 #include <mach/dma.h>
@@ -72,6 +73,8 @@ static APBC_CLK(pwm2, PXA168_PWM2, 1, 13000000);
 static APBC_CLK(pwm3, PXA168_PWM3, 1, 13000000);
 static APBC_CLK(pwm4, PXA168_PWM4, 1, 13000000);
 
+static APMU_CLK(nand, NAND, 0x01db, 208000000);
+
 /* device and clock bindings */
 static struct clk_lookup pxa168_clkregs[] = {
        INIT_CLKREG(&clk_uart1, "pxa2xx-uart.0", NULL),
@@ -82,6 +85,7 @@ static struct clk_lookup pxa168_clkregs[] = {
        INIT_CLKREG(&clk_pwm2, "pxa168-pwm.1", NULL),
        INIT_CLKREG(&clk_pwm3, "pxa168-pwm.2", NULL),
        INIT_CLKREG(&clk_pwm4, "pxa168-pwm.3", NULL),
+       INIT_CLKREG(&clk_nand, "pxa3xx-nand", NULL),
 };
 
 static int __init pxa168_init(void)
@@ -127,3 +131,4 @@ PXA168_DEVICE(pwm1, "pxa168-pwm", 0, NONE, 0xd401a000, 0x10);
 PXA168_DEVICE(pwm2, "pxa168-pwm", 1, NONE, 0xd401a400, 0x10);
 PXA168_DEVICE(pwm3, "pxa168-pwm", 2, NONE, 0xd401a800, 0x10);
 PXA168_DEVICE(pwm4, "pxa168-pwm", 3, NONE, 0xd401ac00, 0x10);
+PXA168_DEVICE(nand, "pxa3xx-nand", -1, NAND, 0xd4283000, 0x80, 97, 99);
index 5882ca6..d404950 100644 (file)
@@ -110,6 +110,8 @@ static APBC_CLK(pwm2, PXA910_PWM2, 1, 13000000);
 static APBC_CLK(pwm3, PXA910_PWM3, 1, 13000000);
 static APBC_CLK(pwm4, PXA910_PWM4, 1, 13000000);
 
+static APMU_CLK(nand, NAND, 0x01db, 208000000);
+
 /* device and clock bindings */
 static struct clk_lookup pxa910_clkregs[] = {
        INIT_CLKREG(&clk_uart1, "pxa2xx-uart.0", NULL),
@@ -120,6 +122,7 @@ static struct clk_lookup pxa910_clkregs[] = {
        INIT_CLKREG(&clk_pwm2, "pxa910-pwm.1", NULL),
        INIT_CLKREG(&clk_pwm3, "pxa910-pwm.2", NULL),
        INIT_CLKREG(&clk_pwm4, "pxa910-pwm.3", NULL),
+       INIT_CLKREG(&clk_nand, "pxa3xx-nand", NULL),
 };
 
 static int __init pxa910_init(void)
@@ -174,3 +177,4 @@ PXA910_DEVICE(pwm1, "pxa910-pwm", 0, NONE, 0xd401a000, 0x10);
 PXA910_DEVICE(pwm2, "pxa910-pwm", 1, NONE, 0xd401a400, 0x10);
 PXA910_DEVICE(pwm3, "pxa910-pwm", 2, NONE, 0xd401a800, 0x10);
 PXA910_DEVICE(pwm4, "pxa910-pwm", 3, NONE, 0xd401ac00, 0x10);
+PXA910_DEVICE(nand, "pxa3xx-nand", -1, NAND, 0xd4283000, 0x80, 97, 99);
index 08cfef6..8f49b2b 100644 (file)
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/platform_device.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/onenand.h>
 
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
+#include <asm/mach/flash.h>
 #include <mach/addr-map.h>
 #include <mach/mfp-pxa910.h>
 #include <mach/pxa910.h>
@@ -26,6 +30,86 @@ static unsigned long ttc_dkb_pin_config[] __initdata = {
        /* UART2 */
        GPIO47_UART2_RXD,
        GPIO48_UART2_TXD,
+
+       /* DFI */
+       DF_IO0_ND_IO0,
+       DF_IO1_ND_IO1,
+       DF_IO2_ND_IO2,
+       DF_IO3_ND_IO3,
+       DF_IO4_ND_IO4,
+       DF_IO5_ND_IO5,
+       DF_IO6_ND_IO6,
+       DF_IO7_ND_IO7,
+       DF_IO8_ND_IO8,
+       DF_IO9_ND_IO9,
+       DF_IO10_ND_IO10,
+       DF_IO11_ND_IO11,
+       DF_IO12_ND_IO12,
+       DF_IO13_ND_IO13,
+       DF_IO14_ND_IO14,
+       DF_IO15_ND_IO15,
+       DF_nCS0_SM_nCS2_nCS0,
+       DF_ALE_SM_WEn_ND_ALE,
+       DF_CLE_SM_OEn_ND_CLE,
+       DF_WEn_DF_WEn,
+       DF_REn_DF_REn,
+       DF_RDY0_DF_RDY0,
+};
+
+static struct mtd_partition ttc_dkb_onenand_partitions[] = {
+       {
+               .name           = "bootloader",
+               .offset         = 0,
+               .size           = SZ_1M,
+               .mask_flags     = MTD_WRITEABLE,
+       }, {
+               .name           = "reserved",
+               .offset         = MTDPART_OFS_APPEND,
+               .size           = SZ_128K,
+               .mask_flags     = MTD_WRITEABLE,
+       }, {
+               .name           = "reserved",
+               .offset         = MTDPART_OFS_APPEND,
+               .size           = SZ_8M,
+               .mask_flags     = MTD_WRITEABLE,
+       }, {
+               .name           = "kernel",
+               .offset         = MTDPART_OFS_APPEND,
+               .size           = (SZ_2M + SZ_1M),
+               .mask_flags     = 0,
+       }, {
+               .name           = "filesystem",
+               .offset         = MTDPART_OFS_APPEND,
+               .size           = SZ_48M,
+               .mask_flags     = 0,
+       }
+};
+
+static struct onenand_platform_data ttc_dkb_onenand_info = {
+       .parts          = ttc_dkb_onenand_partitions,
+       .nr_parts       = ARRAY_SIZE(ttc_dkb_onenand_partitions),
+};
+
+static struct resource ttc_dkb_resource_onenand[] = {
+       [0] = {
+               .start  = SMC_CS0_PHYS_BASE,
+               .end    = SMC_CS0_PHYS_BASE + SZ_1M,
+               .flags  = IORESOURCE_MEM,
+       },
+};
+
+static struct platform_device ttc_dkb_device_onenand = {
+       .name           = "onenand-flash",
+       .id             = -1,
+       .resource       = ttc_dkb_resource_onenand,
+       .num_resources  = ARRAY_SIZE(ttc_dkb_resource_onenand),
+       .dev            = {
+               .platform_data  = &ttc_dkb_onenand_info,
+       },
+};
+
+static struct platform_device *ttc_dkb_devices[] = {
+       &ttc_dkb_device_onenand,
 };
 
 static void __init ttc_dkb_init(void)
@@ -34,6 +118,9 @@ static void __init ttc_dkb_init(void)
 
        /* on-chip devices */
        pxa910_add_uart(1);
+
+       /* off-chip devices */
+       platform_add_devices(ARRAY_AND_SIZE(ttc_dkb_devices));
 }
 
 MACHINE_START(TTC_DKB, "PXA910-based TTC_DKB Development Platform")
index c8a2eac..b96c6a3 100644 (file)
@@ -6,11 +6,13 @@ choice
 
 config MACH_MX21
        bool "i.MX21 support"
+       select ARCH_MXC_AUDMUX_V1
        help
          This enables support for Freescale's MX2 based i.MX21 processor.
 
 config MACH_MX27
        bool "i.MX27 support"
+       select ARCH_MXC_AUDMUX_V1
        help
          This enables support for Freescale's MX2 based i.MX27 processor.
 
@@ -102,4 +104,11 @@ config MACH_PCA100
          Include support for phyCARD-s (aka pca100) platform. This
          includes specific configurations for the module and its peripherals.
 
+config MACH_MXT_TD60
+       bool "Maxtrack i-MXT TD60"
+       depends on MACH_MX27
+       help
+         Include support for i-MXT (aka td60) platform. This
+         includes specific configurations for the module and its peripherals.
+
 endif
index 19560f0..52aca0a 100644 (file)
@@ -20,4 +20,5 @@ obj-$(CONFIG_MACH_MX27LITE) += mx27lite.o
 obj-$(CONFIG_MACH_EUKREA_CPUIMX27) += eukrea_cpuimx27.o
 obj-$(CONFIG_MACH_EUKREA_MBIMX27_BASEBOARD) += eukrea_mbimx27-baseboard.o
 obj-$(CONFIG_MACH_PCA100) += pca100.o
+obj-$(CONFIG_MACH_MXT_TD60) += mxt_td60.o
 
index eede798..91901b5 100644 (file)
@@ -1000,7 +1000,7 @@ int __init mx21_clocks_init(unsigned long lref, unsigned long href)
        clk_enable(&per_clk[0]);
        clk_enable(&gpio_clk);
 
-#ifdef CONFIG_DEBUG_LL_CONSOLE
+#if defined(CONFIG_DEBUG_LL) && !defined(CONFIG_DEBUG_ICEDCC)
        clk_enable(&uart_clk[0]);
 #endif
 
index ff5e332..b010bf9 100644 (file)
@@ -651,8 +651,8 @@ static struct clk_lookup lookups[] = {
        _REGISTER_CLOCK("mxc-ehci.1", "usb_ahb", usb_clk1)
        _REGISTER_CLOCK("mxc-ehci.2", "usb", usb_clk)
        _REGISTER_CLOCK("mxc-ehci.2", "usb_ahb", usb_clk1)
-       _REGISTER_CLOCK(NULL, "ssi1", ssi1_clk)
-       _REGISTER_CLOCK(NULL, "ssi2", ssi2_clk)
+       _REGISTER_CLOCK("imx-ssi.0", NULL, ssi1_clk)
+       _REGISTER_CLOCK("imx-ssi.1", NULL, ssi2_clk)
        _REGISTER_CLOCK("mxc_nand.0", NULL, nfc_clk)
        _REGISTER_CLOCK(NULL, "vpu", vpu_clk)
        _REGISTER_CLOCK(NULL, "dma", dma_clk)
@@ -751,7 +751,7 @@ int __init mx27_clocks_init(unsigned long fref)
        clk_enable(&emi_clk);
        clk_enable(&iim_clk);
 
-#ifdef CONFIG_DEBUG_LL_CONSOLE
+#if defined(CONFIG_DEBUG_LL) && !defined(CONFIG_DEBUG_ICEDCC)
        clk_enable(&uart1_clk);
 #endif
 
index 50199af..3d398ce 100644 (file)
@@ -530,6 +530,84 @@ struct platform_device mxc_usbh2 = {
 };
 #endif
 
+static struct resource imx_ssi_resources0[] = {
+       {
+               .start  = SSI1_BASE_ADDR,
+               .end    = SSI1_BASE_ADDR + 0x6F,
+               .flags  = IORESOURCE_MEM,
+       }, {
+               .start  = MXC_INT_SSI1,
+               .end    = MXC_INT_SSI1,
+               .flags  = IORESOURCE_IRQ,
+       }, {
+               .name   = "tx0",
+               .start  = DMA_REQ_SSI1_TX0,
+               .end    = DMA_REQ_SSI1_TX0,
+               .flags  = IORESOURCE_DMA,
+       }, {
+               .name   = "rx0",
+               .start  = DMA_REQ_SSI1_RX0,
+               .end    = DMA_REQ_SSI1_RX0,
+               .flags  = IORESOURCE_DMA,
+       }, {
+               .name   = "tx1",
+               .start  = DMA_REQ_SSI1_TX1,
+               .end    = DMA_REQ_SSI1_TX1,
+               .flags  = IORESOURCE_DMA,
+       }, {
+               .name   = "rx1",
+               .start  = DMA_REQ_SSI1_RX1,
+               .end    = DMA_REQ_SSI1_RX1,
+               .flags  = IORESOURCE_DMA,
+       },
+};
+
+static struct resource imx_ssi_resources1[] = {
+       {
+               .start  = SSI2_BASE_ADDR,
+               .end    = SSI2_BASE_ADDR + 0x6F,
+               .flags  = IORESOURCE_MEM,
+       }, {
+               .start  = MXC_INT_SSI2,
+               .end    = MXC_INT_SSI2,
+               .flags  = IORESOURCE_IRQ,
+       }, {
+               .name   = "tx0",
+               .start  = DMA_REQ_SSI2_TX0,
+               .end    = DMA_REQ_SSI2_TX0,
+               .flags  = IORESOURCE_DMA,
+       }, {
+               .name   = "rx0",
+               .start  = DMA_REQ_SSI2_RX0,
+               .end    = DMA_REQ_SSI2_RX0,
+               .flags  = IORESOURCE_DMA,
+       }, {
+               .name   = "tx1",
+               .start  = DMA_REQ_SSI2_TX1,
+               .end    = DMA_REQ_SSI2_TX1,
+               .flags  = IORESOURCE_DMA,
+       }, {
+               .name   = "rx1",
+               .start  = DMA_REQ_SSI2_RX1,
+               .end    = DMA_REQ_SSI2_RX1,
+               .flags  = IORESOURCE_DMA,
+       },
+};
+
+struct platform_device imx_ssi_device0 = {
+       .name = "imx-ssi",
+       .id = 0,
+       .num_resources = ARRAY_SIZE(imx_ssi_resources0),
+       .resource = imx_ssi_resources0,
+};
+
+struct platform_device imx_ssi_device1 = {
+       .name = "imx-ssi",
+       .id = 1,
+       .num_resources = ARRAY_SIZE(imx_ssi_resources1),
+       .resource = imx_ssi_resources1,
+};
+
 /* GPIO port description */
 static struct mxc_gpio_port imx_gpio_ports[] = {
        {
index d315406..97306aa 100644 (file)
@@ -26,4 +26,5 @@ extern struct platform_device mxc_usbh2;
 extern struct platform_device mxc_spi_device0;
 extern struct platform_device mxc_spi_device1;
 extern struct platform_device mxc_spi_device2;
-
+extern struct platform_device imx_ssi_device0;
+extern struct platform_device imx_ssi_device1;
diff --git a/arch/arm/mach-mx2/mxt_td60.c b/arch/arm/mach-mx2/mxt_td60.c
new file mode 100644 (file)
index 0000000..03dbbdc
--- /dev/null
@@ -0,0 +1,319 @@
+/*
+ *  Copyright (C) 2000 Deep Blue Solutions Ltd
+ *  Copyright (C) 2002 Shane Nay (shane@minirl.com)
+ *  Copyright 2006-2007 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/platform_device.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/physmap.h>
+#include <linux/i2c.h>
+#include <linux/irq.h>
+#include <mach/common.h>
+#include <mach/hardware.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/time.h>
+#include <asm/mach/map.h>
+#include <linux/gpio.h>
+#include <mach/imx-uart.h>
+#include <mach/iomux.h>
+#include <mach/mxc_nand.h>
+#include <mach/i2c.h>
+#include <linux/i2c/pca953x.h>
+#include <mach/imxfb.h>
+#include <mach/mmc.h>
+
+#include "devices.h"
+
+static unsigned int mxt_td60_pins[] __initdata = {
+       /* UART0 */
+       PE12_PF_UART1_TXD,
+       PE13_PF_UART1_RXD,
+       PE14_PF_UART1_CTS,
+       PE15_PF_UART1_RTS,
+       /* UART1 */
+       PE3_PF_UART2_CTS,
+       PE4_PF_UART2_RTS,
+       PE6_PF_UART2_TXD,
+       PE7_PF_UART2_RXD,
+       /* UART2 */
+       PE8_PF_UART3_TXD,
+       PE9_PF_UART3_RXD,
+       PE10_PF_UART3_CTS,
+       PE11_PF_UART3_RTS,
+       /* UART3 */
+       PB26_AF_UART4_RTS,
+       PB28_AF_UART4_TXD,
+       PB29_AF_UART4_CTS,
+       PB31_AF_UART4_RXD,
+       /* UART4 */
+       PB18_AF_UART5_TXD,
+       PB19_AF_UART5_RXD,
+       PB20_AF_UART5_CTS,
+       PB21_AF_UART5_RTS,
+       /* UART5 */
+       PB10_AF_UART6_TXD,
+       PB12_AF_UART6_CTS,
+       PB11_AF_UART6_RXD,
+       PB13_AF_UART6_RTS,
+       /* FEC */
+       PD0_AIN_FEC_TXD0,
+       PD1_AIN_FEC_TXD1,
+       PD2_AIN_FEC_TXD2,
+       PD3_AIN_FEC_TXD3,
+       PD4_AOUT_FEC_RX_ER,
+       PD5_AOUT_FEC_RXD1,
+       PD6_AOUT_FEC_RXD2,
+       PD7_AOUT_FEC_RXD3,
+       PD8_AF_FEC_MDIO,
+       PD9_AIN_FEC_MDC,
+       PD10_AOUT_FEC_CRS,
+       PD11_AOUT_FEC_TX_CLK,
+       PD12_AOUT_FEC_RXD0,
+       PD13_AOUT_FEC_RX_DV,
+       PD14_AOUT_FEC_RX_CLK,
+       PD15_AOUT_FEC_COL,
+       PD16_AIN_FEC_TX_ER,
+       PF23_AIN_FEC_TX_EN,
+       /* I2C1 */
+       PD17_PF_I2C_DATA,
+       PD18_PF_I2C_CLK,
+       /* I2C2 */
+       PC5_PF_I2C2_SDA,
+       PC6_PF_I2C2_SCL,
+       /* FB */
+       PA5_PF_LSCLK,
+       PA6_PF_LD0,
+       PA7_PF_LD1,
+       PA8_PF_LD2,
+       PA9_PF_LD3,
+       PA10_PF_LD4,
+       PA11_PF_LD5,
+       PA12_PF_LD6,
+       PA13_PF_LD7,
+       PA14_PF_LD8,
+       PA15_PF_LD9,
+       PA16_PF_LD10,
+       PA17_PF_LD11,
+       PA18_PF_LD12,
+       PA19_PF_LD13,
+       PA20_PF_LD14,
+       PA21_PF_LD15,
+       PA22_PF_LD16,
+       PA23_PF_LD17,
+       PA25_PF_CLS,
+       PA27_PF_SPL_SPR,
+       PA28_PF_HSYNC,
+       PA29_PF_VSYNC,
+       PA30_PF_CONTRAST,
+       PA31_PF_OE_ACD,
+       /* OWIRE */
+       PE16_AF_OWIRE,
+       /* SDHC1*/
+       PE18_PF_SD1_D0,
+       PE19_PF_SD1_D1,
+       PE20_PF_SD1_D2,
+       PE21_PF_SD1_D3,
+       PE22_PF_SD1_CMD,
+       PE23_PF_SD1_CLK,
+       PF8_AF_ATA_IORDY,
+       /* SDHC2*/
+       PB4_PF_SD2_D0,
+       PB5_PF_SD2_D1,
+       PB6_PF_SD2_D2,
+       PB7_PF_SD2_D3,
+       PB8_PF_SD2_CMD,
+       PB9_PF_SD2_CLK,
+};
+
+static struct mxc_nand_platform_data mxt_td60_nand_board_info = {
+       .width = 1,
+       .hw_ecc = 1,
+};
+
+static struct imxi2c_platform_data mxt_td60_i2c_data = {
+       .bitrate = 100000,
+};
+
+/* PCA9557 */
+static int mxt_td60_pca9557_setup(struct i2c_client *client,
+                               unsigned gpio_base, unsigned ngpio,
+                               void *context)
+{
+       static int mxt_td60_gpio_value[] = {
+               -1, -1, -1, -1, -1, -1, -1, 1
+       };
+       int n;
+
+       for (n = 0; n < ARRAY_SIZE(mxt_td60_gpio_value); ++n) {
+               gpio_request(gpio_base + n, "MXT_TD60 GPIO Exp");
+               if (mxt_td60_gpio_value[n] < 0)
+                       gpio_direction_input(gpio_base + n);
+               else
+                       gpio_direction_output(gpio_base + n,
+                                               mxt_td60_gpio_value[n]);
+               gpio_export(gpio_base + n, 0);
+       }
+
+       return 0;
+}
+
+static struct pca953x_platform_data mxt_td60_pca9557_pdata = {
+       .gpio_base      = 240, /* place PCA9557 after all MX27 gpio pins */
+       .invert         = 0, /* Do not invert */
+       .setup          = mxt_td60_pca9557_setup,
+};
+
+static struct i2c_board_info mxt_td60_i2c_devices[] = {
+       {
+               I2C_BOARD_INFO("pca9557", 0x18),
+               .platform_data = &mxt_td60_pca9557_pdata,
+       },
+};
+
+static struct imxi2c_platform_data mxt_td60_i2c2_data = {
+       .bitrate = 100000,
+};
+
+static struct i2c_board_info mxt_td60_i2c2_devices[] = {
+};
+
+static struct imx_fb_videomode mxt_td60_modes[] = {
+       {
+               .mode = {
+                       .name           = "Chimei LW700AT9003",
+                       .refresh        = 60,
+                       .xres           = 800,
+                       .yres           = 480,
+                       .pixclock       = 30303,
+                       .hsync_len      = 64,
+                       .left_margin    = 0x67,
+                       .right_margin   = 0x68,
+                       .vsync_len      = 16,
+                       .upper_margin   = 0x0f,
+                       .lower_margin   = 0x0f,
+               },
+               .bpp            = 16,
+               .pcr            = 0xFA208B83,
+       },
+};
+
+static struct imx_fb_platform_data mxt_td60_fb_data = {
+       .mode = mxt_td60_modes,
+       .num_modes = ARRAY_SIZE(mxt_td60_modes),
+
+       /*
+        * - HSYNC active high
+        * - VSYNC active high
+        * - clk notenabled while idle
+        * - clock inverted
+        * - data not inverted
+        * - data enable low active
+        * - enable sharp mode
+        */
+       .pwmr           = 0x00A903FF,
+       .lscr1          = 0x00120300,
+       .dmacr          = 0x00020010,
+};
+
+static int mxt_td60_sdhc1_init(struct device *dev, irq_handler_t detect_irq,
+                               void *data)
+{
+       return request_irq(IRQ_GPIOF(8), detect_irq, IRQF_TRIGGER_FALLING,
+                               "sdhc1-card-detect", data);
+}
+
+static void mxt_td60_sdhc1_exit(struct device *dev, void *data)
+{
+       free_irq(IRQ_GPIOF(8), data);
+}
+
+static struct imxmmc_platform_data sdhc1_pdata = {
+       .init = mxt_td60_sdhc1_init,
+       .exit = mxt_td60_sdhc1_exit,
+};
+
+static struct platform_device *platform_devices[] __initdata = {
+       &mxc_fec_device,
+};
+
+static struct imxuart_platform_data uart_pdata[] = {
+       {
+               .flags = IMXUART_HAVE_RTSCTS,
+       }, {
+               .flags = IMXUART_HAVE_RTSCTS,
+       }, {
+               .flags = IMXUART_HAVE_RTSCTS,
+       }, {
+               .flags = IMXUART_HAVE_RTSCTS,
+       }, {
+               .flags = IMXUART_HAVE_RTSCTS,
+       }, {
+               .flags = IMXUART_HAVE_RTSCTS,
+       },
+};
+
+static void __init mxt_td60_board_init(void)
+{
+       mxc_gpio_setup_multiple_pins(mxt_td60_pins, ARRAY_SIZE(mxt_td60_pins),
+                       "MXT_TD60");
+
+       mxc_register_device(&mxc_uart_device0, &uart_pdata[0]);
+       mxc_register_device(&mxc_uart_device1, &uart_pdata[1]);
+       mxc_register_device(&mxc_uart_device2, &uart_pdata[2]);
+       mxc_register_device(&mxc_uart_device3, &uart_pdata[3]);
+       mxc_register_device(&mxc_uart_device4, &uart_pdata[4]);
+       mxc_register_device(&mxc_uart_device5, &uart_pdata[5]);
+       mxc_register_device(&mxc_nand_device, &mxt_td60_nand_board_info);
+
+       i2c_register_board_info(0, mxt_td60_i2c_devices,
+                               ARRAY_SIZE(mxt_td60_i2c_devices));
+
+       i2c_register_board_info(1, mxt_td60_i2c2_devices,
+                               ARRAY_SIZE(mxt_td60_i2c2_devices));
+
+       mxc_register_device(&mxc_i2c_device0, &mxt_td60_i2c_data);
+       mxc_register_device(&mxc_i2c_device1, &mxt_td60_i2c2_data);
+       mxc_register_device(&mxc_fb_device, &mxt_td60_fb_data);
+       mxc_register_device(&mxc_sdhc_device0, &sdhc1_pdata);
+
+       platform_add_devices(platform_devices, ARRAY_SIZE(platform_devices));
+}
+
+static void __init mxt_td60_timer_init(void)
+{
+       mx27_clocks_init(26000000);
+}
+
+static struct sys_timer mxt_td60_timer = {
+       .init   = mxt_td60_timer_init,
+};
+
+MACHINE_START(MXT_TD60, "Maxtrack i-MXT TD60")
+       /* maintainer: Maxtrack Industrial */
+       .phys_io        = AIPI_BASE_ADDR,
+       .io_pg_offst    = ((AIPI_BASE_ADDR_VIRT) >> 18) & 0xfffc,
+       .boot_params    = PHYS_OFFSET + 0x100,
+       .map_io         = mx27_map_io,
+       .init_irq       = mx27_init_irq,
+       .init_machine   = mxt_td60_board_init,
+       .timer          = &mxt_td60_timer,
+MACHINE_END
+
index fe5b165..aea3d34 100644 (file)
@@ -237,7 +237,7 @@ MACHINE_START(PCA100, "phyCARD-i.MX27")
        .io_pg_offst    = ((AIPI_BASE_ADDR_VIRT) >> 18) & 0xfffc,
        .boot_params    = PHYS_OFFSET + 0x100,
        .map_io         = mx27_map_io,
-       .init_irq       = mxc_init_irq,
+       .init_irq       = mx27_init_irq,
        .init_machine   = pca100_init,
        .timer          = &pca100_timer,
 MACHINE_END
index 851f245..ea8ed10 100644 (file)
@@ -2,11 +2,13 @@ if ARCH_MX3
 
 config ARCH_MX31
        select ARCH_HAS_RNGA
+       select ARCH_MXC_AUDMUX_V2
        bool
 
 config ARCH_MX35
        bool
        select ARCH_MXC_IOMUX_V3
+       select ARCH_MXC_AUDMUX_V2
 
 comment "MX3 platforms:"
 
@@ -61,6 +63,7 @@ config MACH_MX31_3DS
 config MACH_MX31MOBOARD
        bool "Support mx31moboard platforms (EPFL Mobots group)"
        select ARCH_MX31
+       select MXC_ULPI
        help
          Include support for mx31moboard platform. This includes specific
          configurations for the board and its peripherals.
@@ -100,4 +103,12 @@ config MACH_MX35_3DS
        help
          Include support for MX35PDK platform. This includes specific
          configurations for the board and its peripherals.
+
+config MACH_KZM_ARM11_01
+       bool "Support KZM-ARM11-01(Kyoto Microcomputer)"
+       select ARCH_MX31
+       help
+         Include support for KZM-ARM11-01. This includes specific
+         configurations for the board and its peripherals.
+
 endif
index 6b97754..93c7b29 100644 (file)
@@ -4,12 +4,12 @@
 
 # Object file lists.
 
-obj-y                          := mm.o devices.o
+obj-y                          := mm.o devices.o cpu.o
 obj-$(CONFIG_ARCH_MX31)                += clock.o iomux.o
 obj-$(CONFIG_ARCH_MX35)                += clock-imx35.o
 obj-$(CONFIG_MACH_MX31ADS)     += mx31ads.o
 obj-$(CONFIG_MACH_MX31LILLY)   += mx31lilly.o mx31lilly-db.o
-obj-$(CONFIG_MACH_MX31LITE)    += mx31lite.o
+obj-$(CONFIG_MACH_MX31LITE)    += mx31lite.o mx31lite-db.o
 obj-$(CONFIG_MACH_PCM037)      += pcm037.o
 obj-$(CONFIG_MACH_PCM037_EET)  += pcm037_eet.o
 obj-$(CONFIG_MACH_MX31_3DS)    += mx31pdk.o
@@ -19,3 +19,4 @@ obj-$(CONFIG_MACH_QONG)               += qong.o
 obj-$(CONFIG_MACH_PCM043)      += pcm043.o
 obj-$(CONFIG_MACH_ARMADILLO5X0) += armadillo5x0.o
 obj-$(CONFIG_MACH_MX35_3DS)    += mx35pdk.o
+obj-$(CONFIG_MACH_KZM_ARM11_01)        += kzmarm11.o
index 776c0ee..54aab40 100644 (file)
@@ -33,6 +33,9 @@
 #include <linux/irq.h>
 #include <linux/mtd/physmap.h>
 #include <linux/io.h>
+#include <linux/input.h>
+#include <linux/gpio_keys.h>
+#include <linux/i2c.h>
 
 #include <mach/hardware.h>
 #include <asm/mach-types.h>
@@ -97,6 +100,47 @@ static int armadillo5x0_pins[] = {
        MX31_PIN_FPSHIFT__FPSHIFT,
        MX31_PIN_DRDY0__DRDY0,
        IOMUX_MODE(MX31_PIN_LCS1, IOMUX_CONFIG_GPIO), /*ADV7125_PSAVE*/
+       /* I2C2 */
+       MX31_PIN_CSPI2_MOSI__SCL,
+       MX31_PIN_CSPI2_MISO__SDA,
+};
+
+/* RTC over I2C*/
+#define ARMADILLO5X0_RTC_GPIO  IOMUX_TO_GPIO(MX31_PIN_SRXD4)
+
+static struct i2c_board_info armadillo5x0_i2c_rtc = {
+       I2C_BOARD_INFO("s35390a", 0x30),
+};
+
+/* GPIO BUTTONS */
+static struct gpio_keys_button armadillo5x0_buttons[] = {
+       {
+               .code           = KEY_ENTER, /*28*/
+               .gpio           = IOMUX_TO_GPIO(MX31_PIN_SCLK0),
+               .active_low     = 1,
+               .desc           = "menu",
+               .wakeup         = 1,
+       }, {
+               .code           = KEY_BACK, /*158*/
+               .gpio           = IOMUX_TO_GPIO(MX31_PIN_SRST0),
+               .active_low     = 1,
+               .desc           = "back",
+               .wakeup         = 1,
+       }
+};
+
+static struct gpio_keys_platform_data armadillo5x0_button_data = {
+       .buttons        = armadillo5x0_buttons,
+       .nbuttons       = ARRAY_SIZE(armadillo5x0_buttons),
+};
+
+static struct platform_device armadillo5x0_button_device = {
+       .name           = "gpio-keys",
+       .id             = -1,
+       .num_resources  = 0,
+       .dev            = {
+               .platform_data  = &armadillo5x0_button_data,
+       }
 };
 
 /*
@@ -278,7 +322,7 @@ static struct resource armadillo5x0_smc911x_resources[] = {
 };
 
 static struct smsc911x_platform_config smsc911x_info = {
-       .flags          = SMSC911X_USE_32BIT,
+       .flags          = SMSC911X_USE_16BIT,
        .irq_polarity   = SMSC911X_IRQ_POLARITY_ACTIVE_LOW,
        .irq_type       = SMSC911X_IRQ_TYPE_PUSH_PULL,
 };
@@ -300,6 +344,8 @@ static struct imxuart_platform_data uart_pdata = {
 
 static struct platform_device *devices[] __initdata = {
        &armadillo5x0_smc911x_device,
+       &mxc_i2c_device1,
+       &armadillo5x0_button_device,
 };
 
 /*
@@ -335,6 +381,18 @@ static void __init armadillo5x0_init(void)
 
        /* set NAND page size to 2k if not configured via boot mode pins */
        __raw_writel(__raw_readl(MXC_CCM_RCSR) | (1 << 30), MXC_CCM_RCSR);
+
+       /* RTC */
+       /* Get RTC IRQ and register the chip */
+       if (gpio_request(ARMADILLO5X0_RTC_GPIO, "rtc") == 0) {
+               if (gpio_direction_input(ARMADILLO5X0_RTC_GPIO) == 0)
+                       armadillo5x0_i2c_rtc.irq = gpio_to_irq(ARMADILLO5X0_RTC_GPIO);
+               else
+                       gpio_free(ARMADILLO5X0_RTC_GPIO);
+       }
+       if (armadillo5x0_i2c_rtc.irq == 0)
+               pr_warning("armadillo5x0_init: failed to get RTC IRQ\n");
+       i2c_register_board_info(1, &armadillo5x0_i2c_rtc, 1);
 }
 
 static void __init armadillo5x0_timer_init(void)
index c595260..7584b4c 100644 (file)
@@ -335,7 +335,7 @@ static void clk_cgr_disable(struct clk *clk)
 
 DEFINE_CLOCK(asrc_clk,   0, CCM_CGR0,  0, NULL, NULL);
 DEFINE_CLOCK(ata_clk,    0, CCM_CGR0,  2, get_rate_ipg, NULL);
-DEFINE_CLOCK(audmux_clk, 0, CCM_CGR0,  4, NULL, NULL);
+/* DEFINE_CLOCK(audmux_clk, 0, CCM_CGR0,  4, NULL, NULL); */
 DEFINE_CLOCK(can1_clk,   0, CCM_CGR0,  6, get_rate_ipg, NULL);
 DEFINE_CLOCK(can2_clk,   1, CCM_CGR0,  8, get_rate_ipg, NULL);
 DEFINE_CLOCK(cspi1_clk,  0, CCM_CGR0, 10, get_rate_ipg, NULL);
@@ -381,12 +381,43 @@ DEFINE_CLOCK(uart3_clk,  2, CCM_CGR2, 20, get_rate_uart, NULL);
 DEFINE_CLOCK(usbotg_clk, 0, CCM_CGR2, 22, get_rate_otg, NULL);
 DEFINE_CLOCK(wdog_clk,   0, CCM_CGR2, 24, NULL, NULL);
 DEFINE_CLOCK(max_clk,    0, CCM_CGR2, 26, NULL, NULL);
-DEFINE_CLOCK(admux_clk,  0, CCM_CGR2, 30, NULL, NULL);
+DEFINE_CLOCK(audmux_clk, 0, CCM_CGR2, 30, NULL, NULL);
 
 DEFINE_CLOCK(csi_clk,    0, CCM_CGR3,  0, get_rate_csi, NULL);
 DEFINE_CLOCK(iim_clk,    0, CCM_CGR3,  2, NULL, NULL);
 DEFINE_CLOCK(gpu2d_clk,  0, CCM_CGR3,  4, NULL, NULL);
 
+DEFINE_CLOCK(usbahb_clk, 0, 0,         0, get_rate_ahb, NULL);
+
+static int clk_dummy_enable(struct clk *clk)
+{
+       return 0;
+}
+
+static void clk_dummy_disable(struct clk *clk)
+{
+}
+
+static unsigned long get_rate_nfc(struct clk *clk)
+{
+       unsigned long div1;
+
+       div1 = (__raw_readl(CCM_BASE + CCM_PDR4) >> 28) + 1;
+
+       return get_rate_ahb(NULL) / div1;
+}
+
+/* NAND Controller: It seems it can't be disabled */
+static struct clk nfc_clk = {
+       .id             = 0,
+       .enable_reg     = 0,
+       .enable_shift   = 0,
+       .get_rate       = get_rate_nfc,
+       .set_rate       = NULL, /* set_rate_nfc, */
+       .enable         = clk_dummy_enable,
+       .disable        = clk_dummy_disable
+};
+
 #define _REGISTER_CLOCK(d, n, c)       \
        {                               \
                .dev_id = d,            \
@@ -397,7 +428,6 @@ DEFINE_CLOCK(gpu2d_clk,  0, CCM_CGR3,  4, NULL, NULL);
 static struct clk_lookup lookups[] = {
        _REGISTER_CLOCK(NULL, "asrc", asrc_clk)
        _REGISTER_CLOCK(NULL, "ata", ata_clk)
-       _REGISTER_CLOCK(NULL, "audmux", audmux_clk)
        _REGISTER_CLOCK(NULL, "can", can1_clk)
        _REGISTER_CLOCK(NULL, "can", can2_clk)
        _REGISTER_CLOCK("spi_imx.0", NULL, cspi1_clk)
@@ -434,8 +464,8 @@ static struct clk_lookup lookups[] = {
        _REGISTER_CLOCK(NULL, "sdma", sdma_clk)
        _REGISTER_CLOCK(NULL, "spba", spba_clk)
        _REGISTER_CLOCK(NULL, "spdif", spdif_clk)
-       _REGISTER_CLOCK(NULL, "ssi", ssi1_clk)
-       _REGISTER_CLOCK(NULL, "ssi", ssi2_clk)
+       _REGISTER_CLOCK("imx-ssi.0", NULL, ssi1_clk)
+       _REGISTER_CLOCK("imx-ssi.1", NULL, ssi2_clk)
        _REGISTER_CLOCK("imx-uart.0", NULL, uart1_clk)
        _REGISTER_CLOCK("imx-uart.1", NULL, uart2_clk)
        _REGISTER_CLOCK("imx-uart.2", NULL, uart3_clk)
@@ -443,12 +473,14 @@ static struct clk_lookup lookups[] = {
        _REGISTER_CLOCK("mxc-ehci.1", "usb", usbotg_clk)
        _REGISTER_CLOCK("mxc-ehci.2", "usb", usbotg_clk)
        _REGISTER_CLOCK("fsl-usb2-udc", "usb", usbotg_clk)
+       _REGISTER_CLOCK("fsl-usb2-udc", "usb_ahb", usbahb_clk)
        _REGISTER_CLOCK("imx-wdt.0", NULL, wdog_clk)
        _REGISTER_CLOCK(NULL, "max", max_clk)
-       _REGISTER_CLOCK(NULL, "admux", admux_clk)
+       _REGISTER_CLOCK(NULL, "audmux", audmux_clk)
        _REGISTER_CLOCK(NULL, "csi", csi_clk)
        _REGISTER_CLOCK(NULL, "iim", iim_clk)
        _REGISTER_CLOCK(NULL, "gpu2d", gpu2d_clk)
+       _REGISTER_CLOCK("mxc_nand.0", NULL, nfc_clk)
 };
 
 int __init mx35_clocks_init()
@@ -456,7 +488,7 @@ int __init mx35_clocks_init()
        int i;
        unsigned int ll = 0;
 
-#ifdef CONFIG_DEBUG_LL_CONSOLE
+#if defined(CONFIG_DEBUG_LL) && !defined(CONFIG_DEBUG_ICEDCC)
        ll = (3 << 16);
 #endif
 
index b2a3bcf..27a318a 100644 (file)
@@ -558,8 +558,8 @@ static struct clk_lookup lookups[] = {
        _REGISTER_CLOCK("mxc_w1.0", NULL, owire_clk)
        _REGISTER_CLOCK("mxc-mmc.0", NULL, sdhc1_clk)
        _REGISTER_CLOCK("mxc-mmc.1", NULL, sdhc2_clk)
-       _REGISTER_CLOCK(NULL, "ssi", ssi1_clk)
-       _REGISTER_CLOCK(NULL, "ssi", ssi2_clk)
+       _REGISTER_CLOCK("imx-ssi.0", NULL, ssi1_clk)
+       _REGISTER_CLOCK("imx-ssi.1", NULL, ssi2_clk)
        _REGISTER_CLOCK(NULL, "firi", firi_clk)
        _REGISTER_CLOCK(NULL, "ata", ata_clk)
        _REGISTER_CLOCK(NULL, "rtic", rtic_clk)
@@ -616,6 +616,8 @@ int __init mx31_clocks_init(unsigned long fref)
 
        clk_enable(&serial_pll_clk);
 
+       mx31_read_cpu_rev();
+
        if (mx31_revision() >= CHIP_REV_2_0) {
                reg = __raw_readl(MXC_CCM_PMCR1);
                /* No PLL restart on DVFS switch; enable auto EMI handshake */
diff --git a/arch/arm/mach-mx3/cpu.c b/arch/arm/mach-mx3/cpu.c
new file mode 100644 (file)
index 0000000..db82880
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * MX3 CPU type detection
+ *
+ * Copyright (c) 2009 Daniel Mack <daniel@caiaq.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/io.h>
+#include <mach/hardware.h>
+#include <mach/iim.h>
+
+unsigned int mx31_cpu_rev;
+EXPORT_SYMBOL(mx31_cpu_rev);
+
+struct mx3_cpu_type {
+       u8 srev;
+       const char *name;
+       const char *v;
+       unsigned int rev;
+};
+
+static struct mx3_cpu_type mx31_cpu_type[] __initdata = {
+       { .srev = 0x00, .name = "i.MX31(L)", .v = "1.0",  .rev = CHIP_REV_1_0   },
+       { .srev = 0x10, .name = "i.MX31",    .v = "1.1",  .rev = CHIP_REV_1_1   },
+       { .srev = 0x11, .name = "i.MX31L",   .v = "1.1",  .rev = CHIP_REV_1_1   },
+       { .srev = 0x12, .name = "i.MX31",    .v = "1.15", .rev = CHIP_REV_1_1   },
+       { .srev = 0x13, .name = "i.MX31L",   .v = "1.15", .rev = CHIP_REV_1_1   },
+       { .srev = 0x14, .name = "i.MX31",    .v = "1.2",  .rev = CHIP_REV_1_2   },
+       { .srev = 0x15, .name = "i.MX31L",   .v = "1.2",  .rev = CHIP_REV_1_2   },
+       { .srev = 0x28, .name = "i.MX31",    .v = "2.0",  .rev = CHIP_REV_2_0   },
+       { .srev = 0x29, .name = "i.MX31L",   .v = "2.0",  .rev = CHIP_REV_2_0   },
+};
+
+void __init mx31_read_cpu_rev(void)
+{
+       u32 i, srev;
+
+       /* read SREV register from IIM module */
+       srev = __raw_readl(IO_ADDRESS(IIM_BASE_ADDR) + MXC_IIMSREV);
+
+       for (i = 0; i < ARRAY_SIZE(mx31_cpu_type); i++)
+               if (srev == mx31_cpu_type[i].srev) {
+                       printk(KERN_INFO
+                               "CPU identified as %s, silicon rev %s\n",
+                               mx31_cpu_type[i].name, mx31_cpu_type[i].v);
+
+                       mx31_cpu_rev = mx31_cpu_type[i].rev;
+                       return;
+               }
+
+       printk(KERN_WARNING "Unknown CPU identifier. srev = %02x\n", srev);
+}
index e6abe18..6adb586 100644 (file)
@@ -537,6 +537,44 @@ struct platform_device mxc_fec_device = {
 };
 #endif
 
+static struct resource imx_ssi_resources0[] = {
+       {
+               .start  = SSI1_BASE_ADDR,
+               .end    = SSI1_BASE_ADDR + 0xfff,
+               .flags  = IORESOURCE_MEM,
+       }, {
+               .start  = MX31_INT_SSI1,
+               .end    = MX31_INT_SSI1,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct resource imx_ssi_resources1[] = {
+       {
+               .start  = SSI2_BASE_ADDR,
+               .end    = SSI2_BASE_ADDR + 0xfff,
+               .flags  = IORESOURCE_MEM
+       }, {
+               .start  = MX31_INT_SSI2,
+               .end    = MX31_INT_SSI2,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+struct platform_device imx_ssi_device0 = {
+       .name = "imx-ssi",
+       .id = 0,
+       .num_resources = ARRAY_SIZE(imx_ssi_resources0),
+       .resource = imx_ssi_resources0,
+};
+
+struct platform_device imx_ssi_device1 = {
+       .name = "imx-ssi",
+       .id = 1,
+       .num_resources = ARRAY_SIZE(imx_ssi_resources1),
+       .resource = imx_ssi_resources1,
+};
+
 static int mx3_devices_init(void)
 {
        if (cpu_is_mx31()) {
@@ -546,7 +584,7 @@ static int mx3_devices_init(void)
        }
        if (cpu_is_mx35()) {
                mxc_nand_resources[0].start = MX35_NFC_BASE_ADDR;
-               mxc_nand_resources[0].end = MX35_NFC_BASE_ADDR + 0xfff;
+               mxc_nand_resources[0].end = MX35_NFC_BASE_ADDR + 0x1fff;
                otg_resources[0].start = MX35_OTG_BASE_ADDR;
                otg_resources[0].end = MX35_OTG_BASE_ADDR + 0x1ff;
                otg_resources[1].start = MXC_INT_USBOTG;
@@ -555,6 +593,10 @@ static int mx3_devices_init(void)
                mxc_usbh1_resources[0].end = MX35_OTG_BASE_ADDR + 0x5ff;
                mxc_usbh1_resources[1].start = MXC_INT_USBHS;
                mxc_usbh1_resources[1].end = MXC_INT_USBHS;
+               imx_ssi_resources0[1].start = MX35_INT_SSI1;
+               imx_ssi_resources0[1].end = MX35_INT_SSI1;
+               imx_ssi_resources1[1].start = MX35_INT_SSI2;
+               imx_ssi_resources1[1].end = MX35_INT_SSI2;
        }
 
        return 0;
index ab87419..42cf175 100644 (file)
@@ -23,4 +23,6 @@ extern struct platform_device mxc_rnga_device;
 extern struct platform_device mxc_spi_device0;
 extern struct platform_device mxc_spi_device1;
 extern struct platform_device mxc_spi_device2;
+extern struct platform_device imx_ssi_device0;
+extern struct platform_device imx_ssi_device1;
 
diff --git a/arch/arm/mach-mx3/kzmarm11.c b/arch/arm/mach-mx3/kzmarm11.c
new file mode 100644 (file)
index 0000000..6fa99ce
--- /dev/null
@@ -0,0 +1,268 @@
+/*
+ * KZM-ARM11-01 support
+ *  Copyright (C) 2009  Yoichi Yuasa <yuasa@linux-mips.org>
+ *
+ * based on code for MX31ADS,
+ *  Copyright (C) 2000 Deep Blue Solutions Ltd
+ *  Copyright (C) 2002 Shane Nay (shane@minirl.com)
+ *  Copyright 2005-2007 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/gpio.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/serial_8250.h>
+#include <linux/smsc911x.h>
+#include <linux/types.h>
+
+#include <asm/irq.h>
+#include <asm/mach-types.h>
+#include <asm/setup.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/irq.h>
+#include <asm/mach/map.h>
+#include <asm/mach/time.h>
+
+#include <mach/board-kzmarm11.h>
+#include <mach/clock.h>
+#include <mach/common.h>
+#include <mach/imx-uart.h>
+#include <mach/iomux-mx3.h>
+#include <mach/memory.h>
+
+#include "devices.h"
+
+#if defined(CONFIG_SERIAL_8250) || defined(CONFIG_SERIAL_8250_MODULE)
+/*
+ * KZM-ARM11-01 has an external UART on FPGA
+ */
+static struct plat_serial8250_port serial_platform_data[] = {
+       {
+               .membase        = IO_ADDRESS(KZM_ARM11_16550),
+               .mapbase        = KZM_ARM11_16550,
+               .irq            = IOMUX_TO_IRQ(MX31_PIN_GPIO1_1),
+               .irqflags       = IRQ_TYPE_EDGE_RISING,
+               .uartclk        = 14745600,
+               .regshift       = 0,
+               .iotype         = UPIO_MEM,
+               .flags          = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST |
+                                 UPF_BUGGY_UART,
+       },
+       {},
+};
+
+static struct resource serial8250_resources[] = {
+       {
+               .start  = KZM_ARM11_16550,
+               .end    = KZM_ARM11_16550 + 0x10,
+               .flags  = IORESOURCE_MEM,
+       },
+       {
+               .start  = IOMUX_TO_IRQ(MX31_PIN_GPIO1_1),
+               .end    = IOMUX_TO_IRQ(MX31_PIN_GPIO1_1),
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device serial_device = {
+       .name           = "serial8250",
+       .id             = PLAT8250_DEV_PLATFORM,
+       .dev            = {
+                               .platform_data = serial_platform_data,
+                         },
+       .num_resources  = ARRAY_SIZE(serial8250_resources),
+       .resource       = serial8250_resources,
+};
+
+static int __init kzm_init_ext_uart(void)
+{
+       u8 tmp;
+
+       /*
+        * GPIO 1-1: external UART interrupt line
+        */
+       mxc_iomux_mode(IOMUX_MODE(MX31_PIN_GPIO1_1, IOMUX_CONFIG_GPIO));
+       gpio_request(IOMUX_TO_GPIO(MX31_PIN_GPIO1_1), "ext-uart-int");
+       gpio_direction_input(IOMUX_TO_GPIO(MX31_PIN_GPIO1_1));
+
+       /*
+        * Unmask UART interrupt
+        */
+       tmp = __raw_readb(IO_ADDRESS(KZM_ARM11_CTL1));
+       tmp |= 0x2;
+       __raw_writeb(tmp, IO_ADDRESS(KZM_ARM11_CTL1));
+
+       return platform_device_register(&serial_device);
+}
+#else
+static inline int kzm_init_ext_uart(void)
+{
+       return 0;
+}
+#endif
+
+/*
+ * SMSC LAN9118
+ */
+#if defined(CONFIG_SMSC911X) || defined(CONFIG_SMSC911X_MODULE)
+static struct smsc911x_platform_config kzm_smsc9118_config = {
+       .phy_interface  = PHY_INTERFACE_MODE_MII,
+       .irq_polarity   = SMSC911X_IRQ_POLARITY_ACTIVE_HIGH,
+       .irq_type       = SMSC911X_IRQ_TYPE_PUSH_PULL,
+       .flags          = SMSC911X_USE_32BIT | SMSC911X_SAVE_MAC_ADDRESS,
+};
+
+static struct resource kzm_smsc9118_resources[] = {
+       {
+               .start  = CS5_BASE_ADDR,
+               .end    = CS5_BASE_ADDR + SZ_128K - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       {
+               .start  = IOMUX_TO_IRQ(MX31_PIN_GPIO1_2),
+               .end    = IOMUX_TO_IRQ(MX31_PIN_GPIO1_2),
+               .flags  = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE,
+       },
+};
+
+static struct platform_device kzm_smsc9118_device = {
+       .name           = "smsc911x",
+       .id             = -1,
+       .num_resources  = ARRAY_SIZE(kzm_smsc9118_resources),
+       .resource       = kzm_smsc9118_resources,
+       .dev            = {
+                               .platform_data = &kzm_smsc9118_config,
+                         },
+};
+
+static int __init kzm_init_smsc9118(void)
+{
+       /*
+        * GPIO 1-2: SMSC9118 interrupt line
+        */
+       mxc_iomux_mode(IOMUX_MODE(MX31_PIN_GPIO1_2, IOMUX_CONFIG_GPIO));
+       gpio_request(IOMUX_TO_GPIO(MX31_PIN_GPIO1_2), "smsc9118-int");
+       gpio_direction_input(IOMUX_TO_GPIO(MX31_PIN_GPIO1_2));
+
+       return platform_device_register(&kzm_smsc9118_device);
+}
+#else
+static inline int kzm_init_smsc9118(void)
+{
+       return 0;
+}
+#endif
+
+#if defined(CONFIG_SERIAL_IMX) || defined(CONFIG_SERIAL_IMX_MODULE)
+static struct imxuart_platform_data uart_pdata = {
+       .flags = IMXUART_HAVE_RTSCTS,
+};
+
+static void __init kzm_init_imx_uart(void)
+{
+       mxc_register_device(&mxc_uart_device0, &uart_pdata);
+
+       mxc_register_device(&mxc_uart_device1, &uart_pdata);
+}
+#else
+static inline void kzm_init_imx_uart(void)
+{
+}
+#endif
+
+static int kzm_pins[] __initdata = {
+       MX31_PIN_CTS1__CTS1,
+       MX31_PIN_RTS1__RTS1,
+       MX31_PIN_TXD1__TXD1,
+       MX31_PIN_RXD1__RXD1,
+       MX31_PIN_DCD_DCE1__DCD_DCE1,
+       MX31_PIN_RI_DCE1__RI_DCE1,
+       MX31_PIN_DSR_DCE1__DSR_DCE1,
+       MX31_PIN_DTR_DCE1__DTR_DCE1,
+       MX31_PIN_CTS2__CTS2,
+       MX31_PIN_RTS2__RTS2,
+       MX31_PIN_TXD2__TXD2,
+       MX31_PIN_RXD2__RXD2,
+       MX31_PIN_DCD_DTE1__DCD_DTE2,
+       MX31_PIN_RI_DTE1__RI_DTE2,
+       MX31_PIN_DSR_DTE1__DSR_DTE2,
+       MX31_PIN_DTR_DTE1__DTR_DTE2,
+};
+
+/*
+ * Board specific initialization.
+ */
+static void __init kzm_board_init(void)
+{
+       mxc_iomux_setup_multiple_pins(kzm_pins,
+                                     ARRAY_SIZE(kzm_pins), "kzm");
+       kzm_init_ext_uart();
+       kzm_init_smsc9118();
+       kzm_init_imx_uart();
+
+       pr_info("Clock input source is 26MHz\n");
+}
+
+/*
+ * This structure defines static mappings for the kzm-arm11-01 board.
+ */
+static struct map_desc kzm_io_desc[] __initdata = {
+       {
+               .virtual        = CS4_BASE_ADDR_VIRT,
+               .pfn            = __phys_to_pfn(CS4_BASE_ADDR),
+               .length         = CS4_SIZE,
+               .type           = MT_DEVICE
+       },
+       {
+               .virtual        = CS5_BASE_ADDR_VIRT,
+               .pfn            = __phys_to_pfn(CS5_BASE_ADDR),
+               .length         = CS5_SIZE,
+               .type           = MT_DEVICE
+       },
+};
+
+/*
+ * Set up static virtual mappings.
+ */
+static void __init kzm_map_io(void)
+{
+       mx31_map_io();
+       iotable_init(kzm_io_desc, ARRAY_SIZE(kzm_io_desc));
+}
+
+static void __init kzm_timer_init(void)
+{
+       mx31_clocks_init(26000000);
+}
+
+static struct sys_timer kzm_timer = {
+       .init   = kzm_timer_init,
+};
+
+/*
+ * The following uses standard kernel macros define in arch.h in order to
+ * initialize __mach_desc_KZM_ARM11_01 data structure.
+ */
+MACHINE_START(KZM_ARM11_01, "Kyoto Microcomputer Co., Ltd. KZM-ARM11-01")
+       .phys_io        = AIPS1_BASE_ADDR,
+       .io_pg_offst    = ((AIPS1_BASE_ADDR_VIRT) >> 18) & 0xfffc,
+       .boot_params    = PHYS_OFFSET + 0x100,
+       .map_io         = kzm_map_io,
+       .init_irq       = mx31_init_irq,
+       .init_machine   = kzm_board_init,
+       .timer          = &kzm_timer,
+MACHINE_END
index 3b3a78f..7aebd74 100644 (file)
@@ -109,6 +109,9 @@ static int mxc_mmc1_get_ro(struct device *dev)
 
 static int gpio_det, gpio_wp;
 
+#define MMC_PAD_CFG (PAD_CTL_DRV_MAX | PAD_CTL_SRE_FAST | PAD_CTL_HYS_CMOS | \
+                       PAD_CTL_ODE_CMOS | PAD_CTL_100K_PU)
+
 static int mxc_mmc1_init(struct device *dev,
                         irq_handler_t detect_irq, void *data)
 {
@@ -117,6 +120,13 @@ static int mxc_mmc1_init(struct device *dev,
        gpio_det = IOMUX_TO_GPIO(MX31_PIN_GPIO1_1);
        gpio_wp = IOMUX_TO_GPIO(MX31_PIN_LCS0);
 
+       mxc_iomux_set_pad(MX31_PIN_SD1_DATA0, MMC_PAD_CFG);
+       mxc_iomux_set_pad(MX31_PIN_SD1_DATA1, MMC_PAD_CFG);
+       mxc_iomux_set_pad(MX31_PIN_SD1_DATA2, MMC_PAD_CFG);
+       mxc_iomux_set_pad(MX31_PIN_SD1_DATA3, MMC_PAD_CFG);
+       mxc_iomux_set_pad(MX31_PIN_SD1_CLK, MMC_PAD_CFG);
+       mxc_iomux_set_pad(MX31_PIN_SD1_CMD, MMC_PAD_CFG);
+
        ret = gpio_request(gpio_det, "MMC detect");
        if (ret)
                return ret;
index 4230251..9ce029f 100644 (file)
@@ -31,6 +31,8 @@
 #include <linux/interrupt.h>
 #include <linux/smsc911x.h>
 #include <linux/mtd/physmap.h>
+#include <linux/spi/spi.h>
+#include <linux/mfd/mc13783.h>
 
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
@@ -41,6 +43,7 @@
 #include <mach/common.h>
 #include <mach/iomux-mx3.h>
 #include <mach/board-mx31lilly.h>
+#include <mach/spi.h>
 
 #include "devices.h"
 
@@ -108,7 +111,36 @@ static struct platform_device physmap_flash_device = {
 static struct platform_device *devices[] __initdata = {
        &smsc91x_device,
        &physmap_flash_device,
-       &mxc_i2c_device1,
+};
+
+/* SPI */
+
+static int spi_internal_chipselect[] = {
+       MXC_SPI_CS(0),
+       MXC_SPI_CS(1),
+       MXC_SPI_CS(2),
+};
+
+static struct spi_imx_master spi0_pdata = {
+       .chipselect = spi_internal_chipselect,
+       .num_chipselect = ARRAY_SIZE(spi_internal_chipselect),
+};
+
+static struct spi_imx_master spi1_pdata = {
+       .chipselect = spi_internal_chipselect,
+       .num_chipselect = ARRAY_SIZE(spi_internal_chipselect),
+};
+
+static struct mc13783_platform_data mc13783_pdata __initdata = {
+       .flags = MC13783_USE_RTC | MC13783_USE_TOUCHSCREEN,
+};
+
+static struct spi_board_info mc13783_dev __initdata = {
+       .modalias       = "mc13783",
+       .max_speed_hz   = 1000000,
+       .bus_num        = 1,
+       .chip_select    = 0,
+       .platform_data  = &mc13783_pdata,
 };
 
 static int mx31lilly_baseboard;
@@ -128,8 +160,27 @@ static void __init mx31lilly_board_init(void)
        }
 
        mxc_iomux_alloc_pin(MX31_PIN_CS4__CS4, "Ethernet CS");
-       mxc_iomux_alloc_pin(MX31_PIN_CSPI2_MOSI__SCL, "I2C SCL");
-       mxc_iomux_alloc_pin(MX31_PIN_CSPI2_MISO__SDA, "I2C SDA");
+
+       /* SPI */
+       mxc_iomux_alloc_pin(MX31_PIN_CSPI1_SCLK__SCLK, "SPI1_CLK");
+       mxc_iomux_alloc_pin(MX31_PIN_CSPI1_MOSI__MOSI, "SPI1_TX");
+       mxc_iomux_alloc_pin(MX31_PIN_CSPI1_MISO__MISO, "SPI1_RX");
+       mxc_iomux_alloc_pin(MX31_PIN_CSPI1_SPI_RDY__SPI_RDY, "SPI1_RDY");
+       mxc_iomux_alloc_pin(MX31_PIN_CSPI1_SS0__SS0, "SPI1_SS0");
+       mxc_iomux_alloc_pin(MX31_PIN_CSPI1_SS1__SS1, "SPI1_SS1");
+       mxc_iomux_alloc_pin(MX31_PIN_CSPI1_SS2__SS2, "SPI1_SS2");
+
+       mxc_iomux_alloc_pin(MX31_PIN_CSPI2_SCLK__SCLK, "SPI2_CLK");
+       mxc_iomux_alloc_pin(MX31_PIN_CSPI2_MOSI__MOSI, "SPI2_TX");
+       mxc_iomux_alloc_pin(MX31_PIN_CSPI2_MISO__MISO, "SPI2_RX");
+       mxc_iomux_alloc_pin(MX31_PIN_CSPI2_SPI_RDY__SPI_RDY, "SPI2_RDY");
+       mxc_iomux_alloc_pin(MX31_PIN_CSPI2_SS0__SS0, "SPI2_SS0");
+       mxc_iomux_alloc_pin(MX31_PIN_CSPI2_SS1__SS1, "SPI2_SS1");
+       mxc_iomux_alloc_pin(MX31_PIN_CSPI2_SS2__SS2, "SPI2_SS2");
+
+       mxc_register_device(&mxc_spi_device0, &spi0_pdata);
+       mxc_register_device(&mxc_spi_device1, &spi1_pdata);
+       spi_register_board_info(&mc13783_dev, 1);
 
        platform_add_devices(devices, ARRAY_SIZE(devices));
 }
diff --git a/arch/arm/mach-mx3/mx31lite-db.c b/arch/arm/mach-mx3/mx31lite-db.c
new file mode 100644 (file)
index 0000000..694611d
--- /dev/null
@@ -0,0 +1,198 @@
+/*
+ *  LogicPD i.MX31 SOM-LV development board support
+ *
+ *    Copyright (c) 2009 Daniel Mack <daniel@caiaq.de>
+ *
+ *  based on code for other MX31 boards,
+ *
+ *    Copyright 2005-2007 Freescale Semiconductor
+ *    Copyright (c) 2009 Alberto Panizzo <maramaopercheseimorto@gmail.com>
+ *    Copyright (C) 2009 Valentin Longchamp, EPFL Mobots group
+ *
+ * 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/types.h>
+#include <linux/init.h>
+#include <linux/gpio.h>
+#include <linux/platform_device.h>
+#include <linux/leds.h>
+#include <linux/platform_device.h>
+
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+
+#include <mach/hardware.h>
+#include <mach/common.h>
+#include <mach/imx-uart.h>
+#include <mach/iomux-mx3.h>
+#include <mach/board-mx31lite.h>
+#include <mach/mmc.h>
+#include <mach/spi.h>
+
+#include "devices.h"
+
+/*
+ * This file contains board-specific initialization routines for the
+ * LogicPD i.MX31 SOM-LV development board, aka 'LiteKit'.
+ * If you design an own baseboard for the module, use this file as base
+ * for support code.
+ */
+
+static unsigned int litekit_db_board_pins[] __initdata = {
+       /* UART1 */
+       MX31_PIN_CTS1__CTS1,
+       MX31_PIN_RTS1__RTS1,
+       MX31_PIN_TXD1__TXD1,
+       MX31_PIN_RXD1__RXD1,
+       /* SPI 0 */
+       MX31_PIN_CSPI1_SCLK__SCLK,
+       MX31_PIN_CSPI1_MOSI__MOSI,
+       MX31_PIN_CSPI1_MISO__MISO,
+       MX31_PIN_CSPI1_SPI_RDY__SPI_RDY,
+       MX31_PIN_CSPI1_SS0__SS0,
+       MX31_PIN_CSPI1_SS1__SS1,
+       MX31_PIN_CSPI1_SS2__SS2,
+};
+
+/* UART */
+static struct imxuart_platform_data uart_pdata __initdata = {
+       .flags = IMXUART_HAVE_RTSCTS,
+};
+
+/* MMC */
+
+static int gpio_det, gpio_wp;
+
+#define MMC_PAD_CFG (PAD_CTL_DRV_MAX | PAD_CTL_SRE_FAST | PAD_CTL_HYS_CMOS | \
+                       PAD_CTL_ODE_CMOS | PAD_CTL_100K_PU)
+
+static int mxc_mmc1_get_ro(struct device *dev)
+{
+       return gpio_get_value(IOMUX_TO_GPIO(MX31_PIN_LCS0));
+}
+
+static int mxc_mmc1_init(struct device *dev,
+                        irq_handler_t detect_irq, void *data)
+{
+       int ret;
+
+       gpio_det = IOMUX_TO_GPIO(MX31_PIN_DCD_DCE1);
+       gpio_wp = IOMUX_TO_GPIO(MX31_PIN_GPIO1_6);
+
+       mxc_iomux_set_pad(MX31_PIN_SD1_DATA0, MMC_PAD_CFG);
+       mxc_iomux_set_pad(MX31_PIN_SD1_DATA1, MMC_PAD_CFG);
+       mxc_iomux_set_pad(MX31_PIN_SD1_DATA2, MMC_PAD_CFG);
+       mxc_iomux_set_pad(MX31_PIN_SD1_DATA3, MMC_PAD_CFG);
+       mxc_iomux_set_pad(MX31_PIN_SD1_CLK, MMC_PAD_CFG);
+       mxc_iomux_set_pad(MX31_PIN_SD1_CMD, MMC_PAD_CFG);
+
+       ret = gpio_request(gpio_det, "MMC detect");
+       if (ret)
+               return ret;
+
+       ret = gpio_request(gpio_wp, "MMC w/p");
+       if (ret)
+               goto exit_free_det;
+
+       gpio_direction_input(gpio_det);
+       gpio_direction_input(gpio_wp);
+
+       ret = request_irq(IOMUX_TO_IRQ(MX31_PIN_DCD_DCE1), detect_irq,
+                         IRQF_DISABLED | IRQF_TRIGGER_FALLING,
+                         "MMC detect", data);
+       if (ret)
+               goto exit_free_wp;
+
+       return 0;
+
+exit_free_wp:
+       gpio_free(gpio_wp);
+
+exit_free_det:
+       gpio_free(gpio_det);
+
+       return ret;
+}
+
+static void mxc_mmc1_exit(struct device *dev, void *data)
+{
+       gpio_free(gpio_det);
+       gpio_free(gpio_wp);
+       free_irq(IOMUX_TO_IRQ(MX31_PIN_GPIO1_1), data);
+}
+
+static struct imxmmc_platform_data mmc_pdata = {
+       .get_ro  = mxc_mmc1_get_ro,
+       .init      = mxc_mmc1_init,
+       .exit      = mxc_mmc1_exit,
+};
+
+/* SPI */
+
+static int spi_internal_chipselect[] = {
+       MXC_SPI_CS(0),
+       MXC_SPI_CS(1),
+       MXC_SPI_CS(2),
+};
+
+static struct spi_imx_master spi0_pdata = {
+       .chipselect     = spi_internal_chipselect,
+       .num_chipselect = ARRAY_SIZE(spi_internal_chipselect),
+};
+
+/* GPIO LEDs */
+
+static struct gpio_led litekit_leds[] = {
+       {
+               .name           = "GPIO0",
+               .gpio           = IOMUX_TO_GPIO(MX31_PIN_COMPARE),
+               .active_low     = 1,
+               .default_state  = LEDS_GPIO_DEFSTATE_OFF,
+       },
+       {
+               .name           = "GPIO1",
+               .gpio           = IOMUX_TO_GPIO(MX31_PIN_CAPTURE),
+               .active_low     = 1,
+               .default_state  = LEDS_GPIO_DEFSTATE_OFF,
+       }
+};
+
+static struct gpio_led_platform_data litekit_led_platform_data = {
+       .leds           = litekit_leds,
+       .num_leds       = ARRAY_SIZE(litekit_leds),
+};
+
+static struct platform_device litekit_led_device = {
+       .name   = "leds-gpio",
+       .id     = -1,
+       .dev    = {
+               .platform_data = &litekit_led_platform_data,
+       },
+};
+
+void __init mx31lite_db_init(void)
+{
+       mxc_iomux_setup_multiple_pins(litekit_db_board_pins,
+                                       ARRAY_SIZE(litekit_db_board_pins),
+                                       "development board pins");
+       mxc_register_device(&mxc_uart_device0, &uart_pdata);
+       mxc_register_device(&mxcsdhc_device0, &mmc_pdata);
+       mxc_register_device(&mxc_spi_device0, &spi0_pdata);
+       platform_device_register(&litekit_led_device);
+}
+
index a8d57de..def6b67 100644 (file)
@@ -2,6 +2,7 @@
  *  Copyright (C) 2000 Deep Blue Solutions Ltd
  *  Copyright (C) 2002 Shane Nay (shane@minirl.com)
  *  Copyright 2005-2007 Freescale Semiconductor, Inc. All Rights Reserved.
+ *  Copyright (C) 2009 Daniel Mack <daniel@caiaq.de>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
 #include <linux/platform_device.h>
 #include <linux/gpio.h>
 #include <linux/smsc911x.h>
+#include <linux/mfd/mc13783.h>
+#include <linux/spi/spi.h>
+#include <linux/usb/otg.h>
+#include <linux/usb/ulpi.h>
+#include <linux/mtd/physmap.h>
 
-#include <mach/hardware.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/time.h>
 #include <asm/mach/map.h>
-#include <mach/common.h>
 #include <asm/page.h>
 #include <asm/setup.h>
+
+#include <mach/hardware.h>
+#include <mach/common.h>
 #include <mach/board-mx31lite.h>
 #include <mach/imx-uart.h>
 #include <mach/iomux-mx3.h>
 #include <mach/irqs.h>
 #include <mach/mxc_nand.h>
+#include <mach/spi.h>
+#include <mach/mxc_ehci.h>
+#include <mach/ulpi.h>
+
 #include "devices.h"
 
 /*
- * This file contains the board-specific initialization routines.
+ * This file contains the module-specific initialization routines.
  */
 
 static unsigned int mx31lite_pins[] = {
-       /* UART1 */
-       MX31_PIN_CTS1__CTS1,
-       MX31_PIN_RTS1__RTS1,
-       MX31_PIN_TXD1__TXD1,
-       MX31_PIN_RXD1__RXD1,
        /* LAN9117 IRQ pin */
        IOMUX_MODE(MX31_PIN_SFS6, IOMUX_CONFIG_GPIO),
-};
-
-static struct imxuart_platform_data uart_pdata = {
-       .flags = IMXUART_HAVE_RTSCTS,
+       /* SPI 1 */
+       MX31_PIN_CSPI2_SCLK__SCLK,
+       MX31_PIN_CSPI2_MOSI__MOSI,
+       MX31_PIN_CSPI2_MISO__MISO,
+       MX31_PIN_CSPI2_SPI_RDY__SPI_RDY,
+       MX31_PIN_CSPI2_SS0__SS0,
+       MX31_PIN_CSPI2_SS1__SS1,
+       MX31_PIN_CSPI2_SS2__SS2,
 };
 
 static struct mxc_nand_platform_data mx31lite_nand_board_info = {
@@ -93,6 +103,111 @@ static struct platform_device smsc911x_device = {
 };
 
 /*
+ * SPI
+ *
+ * The MC13783 is the only hard-wired SPI device on the module.
+ */
+
+static int spi_internal_chipselect[] = {
+       MXC_SPI_CS(0),
+};
+
+static struct spi_imx_master spi1_pdata = {
+       .chipselect     = spi_internal_chipselect,
+       .num_chipselect = ARRAY_SIZE(spi_internal_chipselect),
+};
+
+static struct mc13783_platform_data mc13783_pdata __initdata = {
+       .flags  = MC13783_USE_RTC |
+                 MC13783_USE_REGULATOR,
+};
+
+static struct spi_board_info mc13783_spi_dev __initdata = {
+       .modalias       = "mc13783",
+       .max_speed_hz   = 1000000,
+       .bus_num        = 1,
+       .chip_select    = 0,
+       .platform_data  = &mc13783_pdata,
+       .irq            = IOMUX_TO_IRQ(MX31_PIN_GPIO1_3),
+};
+
+/*
+ * USB
+ */
+
+#define USB_PAD_CFG (PAD_CTL_DRV_MAX | PAD_CTL_SRE_FAST | PAD_CTL_HYS_CMOS | \
+                       PAD_CTL_ODE_CMOS | PAD_CTL_100K_PU)
+
+static int usbh2_init(struct platform_device *pdev)
+{
+       int pins[] = {
+               MX31_PIN_USBH2_DATA0__USBH2_DATA0,
+               MX31_PIN_USBH2_DATA1__USBH2_DATA1,
+               MX31_PIN_USBH2_CLK__USBH2_CLK,
+               MX31_PIN_USBH2_DIR__USBH2_DIR,
+               MX31_PIN_USBH2_NXT__USBH2_NXT,
+               MX31_PIN_USBH2_STP__USBH2_STP,
+       };
+
+       mxc_iomux_setup_multiple_pins(pins, ARRAY_SIZE(pins), "USB H2");
+
+       mxc_iomux_set_pad(MX31_PIN_USBH2_CLK, USB_PAD_CFG);
+       mxc_iomux_set_pad(MX31_PIN_USBH2_DIR, USB_PAD_CFG);
+       mxc_iomux_set_pad(MX31_PIN_USBH2_NXT, USB_PAD_CFG);
+       mxc_iomux_set_pad(MX31_PIN_USBH2_STP, USB_PAD_CFG);
+       mxc_iomux_set_pad(MX31_PIN_USBH2_DATA0, USB_PAD_CFG);
+       mxc_iomux_set_pad(MX31_PIN_USBH2_DATA1, USB_PAD_CFG);
+       mxc_iomux_set_pad(MX31_PIN_SRXD6, USB_PAD_CFG);
+       mxc_iomux_set_pad(MX31_PIN_STXD6, USB_PAD_CFG);
+       mxc_iomux_set_pad(MX31_PIN_SFS3, USB_PAD_CFG);
+       mxc_iomux_set_pad(MX31_PIN_SCK3, USB_PAD_CFG);
+       mxc_iomux_set_pad(MX31_PIN_SRXD3, USB_PAD_CFG);
+       mxc_iomux_set_pad(MX31_PIN_STXD3, USB_PAD_CFG);
+
+       mxc_iomux_set_gpr(MUX_PGP_UH2, true);
+
+       /* chip select */
+       mxc_iomux_alloc_pin(IOMUX_MODE(MX31_PIN_DTR_DCE1, IOMUX_CONFIG_GPIO),
+                               "USBH2_CS");
+       gpio_request(IOMUX_TO_GPIO(MX31_PIN_DTR_DCE1), "USBH2 CS");
+       gpio_direction_output(IOMUX_TO_GPIO(MX31_PIN_DTR_DCE1), 0);
+
+       return 0;
+}
+
+static struct mxc_usbh_platform_data usbh2_pdata = {
+       .init   = usbh2_init,
+       .portsc = MXC_EHCI_MODE_ULPI | MXC_EHCI_UTMI_8BIT,
+       .flags  = MXC_EHCI_POWER_PINS_ENABLED,
+};
+
+/*
+ * NOR flash
+ */
+
+static struct physmap_flash_data nor_flash_data = {
+       .width  = 2,
+};
+
+static struct resource nor_flash_resource = {
+       .start  = 0xa0000000,
+       .end    = 0xa1ffffff,
+       .flags  = IORESOURCE_MEM,
+};
+
+static struct platform_device physmap_flash_device = {
+       .name   = "physmap-flash",
+       .id     = 0,
+       .dev    = {
+               .platform_data  = &nor_flash_data,
+       },
+       .resource = &nor_flash_resource,
+       .num_resources = 1,
+};
+
+
+
+/*
  * This structure defines the MX31 memory map.
  */
 static struct map_desc mx31lite_io_desc[] __initdata = {
@@ -118,19 +233,40 @@ void __init mx31lite_map_io(void)
        iotable_init(mx31lite_io_desc, ARRAY_SIZE(mx31lite_io_desc));
 }
 
-/*
- * Board specific initialization.
- */
+static int mx31lite_baseboard;
+core_param(mx31lite_baseboard, mx31lite_baseboard, int, 0444);
+
 static void __init mxc_board_init(void)
 {
        int ret;
 
+       switch (mx31lite_baseboard) {
+       case MX31LITE_NOBOARD:
+               break;
+       case MX31LITE_DB:
+               mx31lite_db_init();
+               break;
+       default:
+               printk(KERN_ERR "Illegal mx31lite_baseboard type %d\n",
+                               mx31lite_baseboard);
+       }
+
        mxc_iomux_setup_multiple_pins(mx31lite_pins, ARRAY_SIZE(mx31lite_pins),
                                      "mx31lite");
 
-       mxc_register_device(&mxc_uart_device0, &uart_pdata);
+       /* NOR and NAND flash */
+       platform_device_register(&physmap_flash_device);
        mxc_register_device(&mxc_nand_device, &mx31lite_nand_board_info);
 
+       mxc_register_device(&mxc_spi_device1, &spi1_pdata);
+       spi_register_board_info(&mc13783_spi_dev, 1);
+
+       /* USB */
+       usbh2_pdata.otg = otg_ulpi_create(&mxc_ulpi_access_ops,
+                               USB_OTG_DRV_VBUS | USB_OTG_DRV_VBUS_EXT);
+
+       mxc_register_device(&mxc_usbh2, &usbh2_pdata);
+
        /* SMSC9117 IRQ pin */
        ret = gpio_request(IOMUX_TO_GPIO(MX31_PIN_SFS6), "sms9117-irq");
        if (ret)
@@ -150,12 +286,7 @@ struct sys_timer mx31lite_timer = {
        .init   = mx31lite_timer_init,
 };
 
-/*
- * The following uses standard kernel macros defined in arch.h in order to
- * initialize __mach_desc_MX31LITE data structure.
- */
-
-MACHINE_START(MX31LITE, "LogicPD MX31 LITEKIT")
+MACHINE_START(MX31LITE, "LogicPD i.MX31 SOM")
        /* Maintainer: Freescale Semiconductor, Inc. */
        .phys_io        = AIPS1_BASE_ADDR,
        .io_pg_offst    = ((AIPS1_BASE_ADDR_VIRT) >> 18) & 0xfffc,
index 5592cdb..8fc624f 100644 (file)
 #include <linux/platform_device.h>
 #include <linux/types.h>
 
+#include <linux/usb/otg.h>
+
 #include <mach/common.h>
 #include <mach/imx-uart.h>
 #include <mach/iomux-mx3.h>
 #include <mach/hardware.h>
 #include <mach/mmc.h>
+#include <mach/mxc_ehci.h>
+#include <mach/ulpi.h>
 
 #include "devices.h"
 
@@ -39,6 +43,12 @@ static unsigned int devboard_pins[] = {
        MX31_PIN_PC_READY__SD2_DATA1, MX31_PIN_PC_WAIT_B__SD2_DATA0,
        MX31_PIN_PC_CD2_B__SD2_CLK, MX31_PIN_PC_CD1_B__SD2_CMD,
        MX31_PIN_ATA_DIOR__GPIO3_28, MX31_PIN_ATA_DIOW__GPIO3_29,
+       /* USB H1 */
+       MX31_PIN_CSPI1_MISO__USBH1_RXDP, MX31_PIN_CSPI1_MOSI__USBH1_RXDM,
+       MX31_PIN_CSPI1_SS0__USBH1_TXDM, MX31_PIN_CSPI1_SS1__USBH1_TXDP,
+       MX31_PIN_CSPI1_SS2__USBH1_RCV, MX31_PIN_CSPI1_SCLK__USBH1_OEB,
+       MX31_PIN_CSPI1_SPI_RDY__USBH1_FS, MX31_PIN_SFS6__USBH1_SUSPEND,
+       MX31_PIN_NFRE_B__GPIO1_11, MX31_PIN_NFALE__GPIO1_12,
 };
 
 static struct imxuart_platform_data uart_pdata = {
@@ -98,6 +108,80 @@ static struct imxmmc_platform_data sdhc2_pdata = {
        .exit   = devboard_sdhc2_exit,
 };
 
+#define USB_PAD_CFG (PAD_CTL_DRV_MAX | PAD_CTL_SRE_FAST | PAD_CTL_HYS_CMOS | \
+                       PAD_CTL_ODE_CMOS | PAD_CTL_100K_PU)
+
+static int devboard_usbh1_hw_init(struct platform_device *pdev)
+{
+       mxc_iomux_set_gpr(MUX_PGP_USB_SUSPEND, true);
+
+       mxc_iomux_set_pad(MX31_PIN_CSPI1_MISO, USB_PAD_CFG);
+       mxc_iomux_set_pad(MX31_PIN_CSPI1_MOSI, USB_PAD_CFG);
+       mxc_iomux_set_pad(MX31_PIN_CSPI1_SS0, USB_PAD_CFG);
+       mxc_iomux_set_pad(MX31_PIN_CSPI1_SS1, USB_PAD_CFG);
+       mxc_iomux_set_pad(MX31_PIN_CSPI1_SS2, USB_PAD_CFG);
+       mxc_iomux_set_pad(MX31_PIN_CSPI1_SCLK, USB_PAD_CFG);
+       mxc_iomux_set_pad(MX31_PIN_CSPI1_SPI_RDY, USB_PAD_CFG);
+       mxc_iomux_set_pad(MX31_PIN_SFS6, USB_PAD_CFG);
+
+       return 0;
+}
+
+#define USBH1_VBUSEN_B IOMUX_TO_GPIO(MX31_PIN_NFRE_B)
+#define USBH1_MODE     IOMUX_TO_GPIO(MX31_PIN_NFALE)
+
+static int devboard_isp1105_init(struct otg_transceiver *otg)
+{
+       int ret = gpio_request(USBH1_MODE, "usbh1-mode");
+       if (ret)
+               return ret;
+       /* single ended */
+       gpio_direction_output(USBH1_MODE, 0);
+
+       ret = gpio_request(USBH1_VBUSEN_B, "usbh1-vbusen");
+       if (ret) {
+               gpio_free(USBH1_MODE);
+               return ret;
+       }
+       gpio_direction_output(USBH1_VBUSEN_B, 1);
+
+       return 0;
+}
+
+
+static int devboard_isp1105_set_vbus(struct otg_transceiver *otg, bool on)
+{
+       if (on)
+               gpio_set_value(USBH1_VBUSEN_B, 0);
+       else
+               gpio_set_value(USBH1_VBUSEN_B, 1);
+
+       return 0;
+}
+
+static struct mxc_usbh_platform_data usbh1_pdata = {
+       .init   = devboard_usbh1_hw_init,
+       .portsc = MXC_EHCI_MODE_UTMI | MXC_EHCI_SERIAL,
+       .flags  = MXC_EHCI_POWER_PINS_ENABLED | MXC_EHCI_INTERFACE_SINGLE_UNI,
+};
+
+static int __init devboard_usbh1_init(void)
+{
+       struct otg_transceiver *otg;
+
+       otg = kzalloc(sizeof(*otg), GFP_KERNEL);
+       if (!otg)
+               return -ENOMEM;
+
+       otg->label      = "ISP1105";
+       otg->init       = devboard_isp1105_init;
+       otg->set_vbus   = devboard_isp1105_set_vbus;
+
+       usbh1_pdata.otg = otg;
+
+       return mxc_register_device(&mx31_usbh1, &usbh1_pdata);
+}
+
 /*
  * system init for baseboard usage. Will be called by mx31moboard init.
  */
@@ -111,4 +195,6 @@ void __init mx31moboard_devboard_init(void)
        mxc_register_device(&mxc_uart_device1, &uart_pdata);
 
        mxc_register_device(&mxcsdhc_device1, &sdhc2_pdata);
+
+       devboard_usbh1_init();
 }
index 2bfaffb..85184a3 100644 (file)
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
+#include <linux/delay.h>
 #include <linux/gpio.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
+#include <linux/i2c.h>
+#include <linux/spi/spi.h>
 #include <linux/platform_device.h>
 #include <linux/types.h>
 
+#include <linux/usb/otg.h>
+
 #include <mach/common.h>
 #include <mach/hardware.h>
 #include <mach/imx-uart.h>
 #include <mach/iomux-mx3.h>
 #include <mach/mmc.h>
+#include <mach/mxc_ehci.h>
+#include <mach/ulpi.h>
+
+#include <media/soc_camera.h>
 
 #include "devices.h"
 
@@ -37,7 +46,6 @@ static unsigned int marxbot_pins[] = {
        MX31_PIN_PC_CD2_B__SD2_CLK, MX31_PIN_PC_CD1_B__SD2_CMD,
        MX31_PIN_ATA_DIOR__GPIO3_28, MX31_PIN_ATA_DIOW__GPIO3_29,
        /* CSI */
-       MX31_PIN_CSI_D4__CSI_D4, MX31_PIN_CSI_D5__CSI_D5,
        MX31_PIN_CSI_D6__CSI_D6, MX31_PIN_CSI_D7__CSI_D7,
        MX31_PIN_CSI_D8__CSI_D8, MX31_PIN_CSI_D9__CSI_D9,
        MX31_PIN_CSI_D10__CSI_D10, MX31_PIN_CSI_D11__CSI_D11,
@@ -45,10 +53,19 @@ static unsigned int marxbot_pins[] = {
        MX31_PIN_CSI_D14__CSI_D14, MX31_PIN_CSI_D15__CSI_D15,
        MX31_PIN_CSI_HSYNC__CSI_HSYNC, MX31_PIN_CSI_MCLK__CSI_MCLK,
        MX31_PIN_CSI_PIXCLK__CSI_PIXCLK, MX31_PIN_CSI_VSYNC__CSI_VSYNC,
+       MX31_PIN_CSI_D4__GPIO3_4, MX31_PIN_CSI_D5__GPIO3_5,
        MX31_PIN_GPIO3_0__GPIO3_0, MX31_PIN_GPIO3_1__GPIO3_1,
        MX31_PIN_TXD2__GPIO1_28,
        /* dsPIC resets */
        MX31_PIN_STXD5__GPIO1_21, MX31_PIN_SRXD5__GPIO1_22,
+       /*battery detection */
+       MX31_PIN_LCS0__GPIO3_23,
+       /* USB H1 */
+       MX31_PIN_CSPI1_MISO__USBH1_RXDP, MX31_PIN_CSPI1_MOSI__USBH1_RXDM,
+       MX31_PIN_CSPI1_SS0__USBH1_TXDM, MX31_PIN_CSPI1_SS1__USBH1_TXDP,
+       MX31_PIN_CSPI1_SS2__USBH1_RCV, MX31_PIN_CSPI1_SCLK__USBH1_OEB,
+       MX31_PIN_CSPI1_SPI_RDY__USBH1_FS, MX31_PIN_SFS6__USBH1_SUSPEND,
+       MX31_PIN_NFRE_B__GPIO1_11, MX31_PIN_NFALE__GPIO1_12,
 };
 
 #define SDHC2_CD IOMUX_TO_GPIO(MX31_PIN_ATA_DIOR)
@@ -120,6 +137,166 @@ static void dspics_resets_init(void)
        }
 }
 
+static struct spi_board_info marxbot_spi_board_info[] __initdata = {
+       {
+               .modalias = "spidev",
+               .max_speed_hz = 300000,
+               .bus_num = 1,
+               .chip_select = 1, /* according spi1_cs[] ! */
+       },
+};
+
+#define TURRETCAM_POWER        IOMUX_TO_GPIO(MX31_PIN_GPIO3_1)
+#define BASECAM_POWER  IOMUX_TO_GPIO(MX31_PIN_CSI_D5)
+#define TURRETCAM_RST_B        IOMUX_TO_GPIO(MX31_PIN_GPIO3_0)
+#define BASECAM_RST_B  IOMUX_TO_GPIO(MX31_PIN_CSI_D4)
+#define CAM_CHOICE     IOMUX_TO_GPIO(MX31_PIN_TXD2)
+
+static int marxbot_basecam_power(struct device *dev, int on)
+{
+       gpio_set_value(BASECAM_POWER, !on);
+       return 0;
+}
+
+static int marxbot_basecam_reset(struct device *dev)
+{
+       gpio_set_value(BASECAM_RST_B, 0);
+       udelay(100);
+       gpio_set_value(BASECAM_RST_B, 1);
+       return 0;
+}
+
+static struct i2c_board_info marxbot_i2c_devices[] = {
+       {
+               I2C_BOARD_INFO("mt9t031", 0x5d),
+       },
+};
+
+static struct soc_camera_link base_iclink = {
+       .bus_id         = 0,            /* Must match with the camera ID */
+       .power          = marxbot_basecam_power,
+       .reset          = marxbot_basecam_reset,
+       .board_info     = &marxbot_i2c_devices[0],
+       .i2c_adapter_id = 0,
+       .module_name    = "mt9t031",
+};
+
+static struct platform_device marxbot_camera[] = {
+       {
+               .name   = "soc-camera-pdrv",
+               .id     = 0,
+               .dev    = {
+                       .platform_data = &base_iclink,
+               },
+       },
+};
+
+static struct platform_device *marxbot_cameras[] __initdata = {
+       &marxbot_camera[0],
+};
+
+static int __init marxbot_cam_init(void)
+{
+       int ret = gpio_request(CAM_CHOICE, "cam-choice");
+       if (ret)
+               return ret;
+       gpio_direction_output(CAM_CHOICE, 1);
+
+       ret = gpio_request(BASECAM_RST_B, "basecam-reset");
+       if (ret)
+               return ret;
+       gpio_direction_output(BASECAM_RST_B, 1);
+       ret = gpio_request(BASECAM_POWER, "basecam-standby");
+       if (ret)
+               return ret;
+       gpio_direction_output(BASECAM_POWER, 0);
+
+       ret = gpio_request(TURRETCAM_RST_B, "turretcam-reset");
+       if (ret)
+               return ret;
+       gpio_direction_output(TURRETCAM_RST_B, 1);
+       ret = gpio_request(TURRETCAM_POWER, "turretcam-standby");
+       if (ret)
+               return ret;
+       gpio_direction_output(TURRETCAM_POWER, 0);
+
+       return 0;
+}
+
+#define USB_PAD_CFG (PAD_CTL_DRV_MAX | PAD_CTL_SRE_FAST | PAD_CTL_HYS_CMOS | \
+                       PAD_CTL_ODE_CMOS | PAD_CTL_100K_PU)
+
+static int marxbot_usbh1_hw_init(struct platform_device *pdev)
+{
+       mxc_iomux_set_gpr(MUX_PGP_USB_SUSPEND, true);
+
+       mxc_iomux_set_pad(MX31_PIN_CSPI1_MISO, USB_PAD_CFG);
+       mxc_iomux_set_pad(MX31_PIN_CSPI1_MOSI, USB_PAD_CFG);
+       mxc_iomux_set_pad(MX31_PIN_CSPI1_SS0, USB_PAD_CFG);
+       mxc_iomux_set_pad(MX31_PIN_CSPI1_SS1, USB_PAD_CFG);
+       mxc_iomux_set_pad(MX31_PIN_CSPI1_SS2, USB_PAD_CFG);
+       mxc_iomux_set_pad(MX31_PIN_CSPI1_SCLK, USB_PAD_CFG);
+       mxc_iomux_set_pad(MX31_PIN_CSPI1_SPI_RDY, USB_PAD_CFG);
+       mxc_iomux_set_pad(MX31_PIN_SFS6, USB_PAD_CFG);
+
+       return 0;
+}
+
+#define USBH1_VBUSEN_B IOMUX_TO_GPIO(MX31_PIN_NFRE_B)
+#define USBH1_MODE     IOMUX_TO_GPIO(MX31_PIN_NFALE)
+
+static int marxbot_isp1105_init(struct otg_transceiver *otg)
+{
+       int ret = gpio_request(USBH1_MODE, "usbh1-mode");
+       if (ret)
+               return ret;
+       /* single ended */
+       gpio_direction_output(USBH1_MODE, 0);
+
+       ret = gpio_request(USBH1_VBUSEN_B, "usbh1-vbusen");
+       if (ret) {
+               gpio_free(USBH1_MODE);
+               return ret;
+       }
+       gpio_direction_output(USBH1_VBUSEN_B, 1);
+
+       return 0;
+}
+
+
+static int marxbot_isp1105_set_vbus(struct otg_transceiver *otg, bool on)
+{
+       if (on)
+               gpio_set_value(USBH1_VBUSEN_B, 0);
+       else
+               gpio_set_value(USBH1_VBUSEN_B, 1);
+
+       return 0;
+}
+
+static struct mxc_usbh_platform_data usbh1_pdata = {
+       .init   = marxbot_usbh1_hw_init,
+       .portsc = MXC_EHCI_MODE_UTMI | MXC_EHCI_SERIAL,
+       .flags  = MXC_EHCI_POWER_PINS_ENABLED | MXC_EHCI_INTERFACE_SINGLE_UNI,
+};
+
+static int __init marxbot_usbh1_init(void)
+{
+       struct otg_transceiver *otg;
+
+       otg = kzalloc(sizeof(*otg), GFP_KERNEL);
+       if (!otg)
+               return -ENOMEM;
+
+       otg->label      = "ISP1105";
+       otg->init       = marxbot_isp1105_init;
+       otg->set_vbus   = marxbot_isp1105_set_vbus;
+
+       usbh1_pdata.otg = otg;
+
+       return mxc_register_device(&mx31_usbh1, &usbh1_pdata);
+}
+
 /*
  * system init for baseboard usage. Will be called by mx31moboard init.
  */
@@ -133,4 +310,17 @@ void __init mx31moboard_marxbot_init(void)
        dspics_resets_init();
 
        mxc_register_device(&mxcsdhc_device1, &sdhc2_pdata);
+
+       spi_register_board_info(marxbot_spi_board_info,
+               ARRAY_SIZE(marxbot_spi_board_info));
+
+       marxbot_cam_init();
+       platform_add_devices(marxbot_cameras, ARRAY_SIZE(marxbot_cameras));
+
+       /* battery present pin */
+       gpio_request(IOMUX_TO_GPIO(MX31_PIN_LCS0), "bat-present");
+       gpio_direction_input(IOMUX_TO_GPIO(MX31_PIN_LCS0));
+       gpio_export(IOMUX_TO_GPIO(MX31_PIN_LCS0), false);
+
+       marxbot_usbh1_init();
 }
index 9243de5..b705291 100644 (file)
@@ -17,6 +17,7 @@
  */
 
 #include <linux/delay.h>
+#include <linux/dma-mapping.h>
 #include <linux/fsl_devices.h>
 #include <linux/gpio.h>
 #include <linux/init.h>
 #include <linux/mtd/physmap.h>
 #include <linux/mtd/partitions.h>
 #include <linux/platform_device.h>
+#include <linux/regulator/machine.h>
+#include <linux/mfd/mc13783.h>
+#include <linux/spi/spi.h>
 #include <linux/types.h>
 
+#include <linux/usb/otg.h>
+#include <linux/usb/ulpi.h>
+
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/time.h>
 #include <mach/hardware.h>
 #include <mach/imx-uart.h>
 #include <mach/iomux-mx3.h>
+#include <mach/ipu.h>
 #include <mach/i2c.h>
 #include <mach/mmc.h>
-#include <mach/mx31.h>
+#include <mach/mxc_ehci.h>
+#include <mach/mx3_camera.h>
+#include <mach/spi.h>
+#include <mach/ulpi.h>
 
 #include "devices.h"
 
 static unsigned int moboard_pins[] = {
        /* UART0 */
-       MX31_PIN_CTS1__CTS1, MX31_PIN_RTS1__RTS1,
        MX31_PIN_TXD1__TXD1, MX31_PIN_RXD1__RXD1,
+       MX31_PIN_CTS1__GPIO2_7,
        /* UART4 */
        MX31_PIN_PC_RST__CTS5, MX31_PIN_PC_VS2__RTS5,
        MX31_PIN_PC_BVD2__TXD5, MX31_PIN_PC_BVD1__RXD5,
@@ -73,12 +84,31 @@ static unsigned int moboard_pins[] = {
        MX31_PIN_USBOTG_CLK__USBOTG_CLK, MX31_PIN_USBOTG_DIR__USBOTG_DIR,
        MX31_PIN_USBOTG_NXT__USBOTG_NXT, MX31_PIN_USBOTG_STP__USBOTG_STP,
        MX31_PIN_USB_OC__GPIO1_30,
+       /* USB H2 */
+       MX31_PIN_USBH2_DATA0__USBH2_DATA0,
+       MX31_PIN_USBH2_DATA1__USBH2_DATA1,
+       MX31_PIN_STXD3__USBH2_DATA2, MX31_PIN_SRXD3__USBH2_DATA3,
+       MX31_PIN_SCK3__USBH2_DATA4, MX31_PIN_SFS3__USBH2_DATA5,
+       MX31_PIN_STXD6__USBH2_DATA6, MX31_PIN_SRXD6__USBH2_DATA7,
+       MX31_PIN_USBH2_CLK__USBH2_CLK, MX31_PIN_USBH2_DIR__USBH2_DIR,
+       MX31_PIN_USBH2_NXT__USBH2_NXT, MX31_PIN_USBH2_STP__USBH2_STP,
+       MX31_PIN_SCK6__GPIO1_25,
        /* LEDs */
        MX31_PIN_SVEN0__GPIO2_0, MX31_PIN_STX0__GPIO2_1,
        MX31_PIN_SRX0__GPIO2_2, MX31_PIN_SIMPD0__GPIO2_3,
        /* SEL */
        MX31_PIN_DTR_DCE1__GPIO2_8, MX31_PIN_DSR_DCE1__GPIO2_9,
        MX31_PIN_RI_DCE1__GPIO2_10, MX31_PIN_DCD_DCE1__GPIO2_11,
+       /* SPI1 */
+       MX31_PIN_CSPI2_MOSI__MOSI, MX31_PIN_CSPI2_MISO__MISO,
+       MX31_PIN_CSPI2_SCLK__SCLK, MX31_PIN_CSPI2_SPI_RDY__SPI_RDY,
+       MX31_PIN_CSPI2_SS0__SS0, MX31_PIN_CSPI2_SS2__SS2,
+       /* Atlas IRQ */
+       MX31_PIN_GPIO1_3__GPIO1_3,
+       /* SPI2 */
+       MX31_PIN_CSPI3_MOSI__MOSI, MX31_PIN_CSPI3_MISO__MISO,
+       MX31_PIN_CSPI3_SCLK__SCLK, MX31_PIN_CSPI3_SPI_RDY__SPI_RDY,
+       MX31_PIN_CSPI2_SS1__CSPI3_SS1,
 };
 
 static struct physmap_flash_data mx31moboard_flash_data = {
@@ -101,7 +131,18 @@ static struct platform_device mx31moboard_flash = {
        .num_resources = 1,
 };
 
-static struct imxuart_platform_data uart_pdata = {
+static int moboard_uart0_init(struct platform_device *pdev)
+{
+       gpio_request(IOMUX_TO_GPIO(MX31_PIN_CTS1), "uart0-cts-hack");
+       gpio_direction_output(IOMUX_TO_GPIO(MX31_PIN_CTS1), 0);
+       return 0;
+}
+
+static struct imxuart_platform_data uart0_pdata = {
+       .init = moboard_uart0_init,
+};
+
+static struct imxuart_platform_data uart4_pdata = {
        .flags = IMXUART_HAVE_RTSCTS,
 };
 
@@ -113,6 +154,103 @@ static struct imxi2c_platform_data moboard_i2c1_pdata = {
        .bitrate = 100000,
 };
 
+static int moboard_spi1_cs[] = {
+       MXC_SPI_CS(0),
+       MXC_SPI_CS(2),
+};
+
+static struct spi_imx_master moboard_spi1_master = {
+       .chipselect     = moboard_spi1_cs,
+       .num_chipselect = ARRAY_SIZE(moboard_spi1_cs),
+};
+
+static struct regulator_consumer_supply sdhc_consumers[] = {
+       {
+               .dev    = &mxcsdhc_device0.dev,
+               .supply = "sdhc0_vcc",
+       },
+       {
+               .dev    = &mxcsdhc_device1.dev,
+               .supply = "sdhc1_vcc",
+       },
+};
+
+static struct regulator_init_data sdhc_vreg_data = {
+       .constraints = {
+               .min_uV = 2700000,
+               .max_uV = 3000000,
+               .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE |
+                       REGULATOR_CHANGE_MODE | REGULATOR_CHANGE_STATUS,
+               .valid_modes_mask = REGULATOR_MODE_NORMAL |
+                       REGULATOR_MODE_FAST,
+               .always_on = 0,
+               .boot_on = 1,
+       },
+       .num_consumer_supplies = ARRAY_SIZE(sdhc_consumers),
+       .consumer_supplies = sdhc_consumers,
+};
+
+static struct regulator_consumer_supply cam_consumers[] = {
+       {
+               .dev    = &mx3_camera.dev,
+               .supply = "cam_vcc",
+       },
+};
+
+static struct regulator_init_data cam_vreg_data = {
+       .constraints = {
+               .min_uV = 2700000,
+               .max_uV = 3000000,
+               .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE |
+                       REGULATOR_CHANGE_MODE | REGULATOR_CHANGE_STATUS,
+               .valid_modes_mask = REGULATOR_MODE_NORMAL |
+                       REGULATOR_MODE_FAST,
+               .always_on = 0,
+               .boot_on = 1,
+       },
+       .num_consumer_supplies = ARRAY_SIZE(cam_consumers),
+       .consumer_supplies = cam_consumers,
+};
+
+static struct mc13783_regulator_init_data moboard_regulators[] = {
+       {
+               .id = MC13783_REGU_VMMC1,
+               .init_data = &sdhc_vreg_data,
+       },
+       {
+               .id = MC13783_REGU_VCAM,
+               .init_data = &cam_vreg_data,
+       },
+};
+
+static struct mc13783_platform_data moboard_pmic = {
+       .regulators = moboard_regulators,
+       .num_regulators = ARRAY_SIZE(moboard_regulators),
+       .flags = MC13783_USE_REGULATOR | MC13783_USE_RTC |
+               MC13783_USE_ADC,
+};
+
+static struct spi_board_info moboard_spi_board_info[] __initdata = {
+       {
+               .modalias = "mc13783",
+               .irq = IOMUX_TO_IRQ(MX31_PIN_GPIO1_3),
+               .max_speed_hz = 300000,
+               .bus_num = 1,
+               .chip_select = 0,
+               .platform_data = &moboard_pmic,
+               .mode = SPI_CS_HIGH,
+       },
+};
+
+static int moboard_spi2_cs[] = {
+       MXC_SPI_CS(1),
+};
+
+static struct spi_imx_master moboard_spi2_master = {
+       .chipselect     = moboard_spi2_cs,
+       .num_chipselect = ARRAY_SIZE(moboard_spi2_cs),
+};
+
 #define SDHC1_CD IOMUX_TO_GPIO(MX31_PIN_ATA_CS0)
 #define SDHC1_WP IOMUX_TO_GPIO(MX31_PIN_ATA_CS1)
 
@@ -208,6 +346,56 @@ static struct fsl_usb2_platform_data usb_pdata = {
        .phy_mode       = FSL_USB2_PHY_ULPI,
 };
 
+#define USBH2_EN_B IOMUX_TO_GPIO(MX31_PIN_SCK6)
+
+static int moboard_usbh2_hw_init(struct platform_device *pdev)
+{
+       int ret = gpio_request(USBH2_EN_B, "usbh2-en");
+       if (ret)
+               return ret;
+
+       mxc_iomux_set_gpr(MUX_PGP_UH2, true);
+
+       mxc_iomux_set_pad(MX31_PIN_USBH2_CLK, USB_PAD_CFG);
+       mxc_iomux_set_pad(MX31_PIN_USBH2_DIR, USB_PAD_CFG);
+       mxc_iomux_set_pad(MX31_PIN_USBH2_NXT, USB_PAD_CFG);
+       mxc_iomux_set_pad(MX31_PIN_USBH2_STP, USB_PAD_CFG);
+       mxc_iomux_set_pad(MX31_PIN_USBH2_DATA0, USB_PAD_CFG);
+       mxc_iomux_set_pad(MX31_PIN_USBH2_DATA1, USB_PAD_CFG);
+       mxc_iomux_set_pad(MX31_PIN_SRXD6, USB_PAD_CFG);
+       mxc_iomux_set_pad(MX31_PIN_STXD6, USB_PAD_CFG);
+       mxc_iomux_set_pad(MX31_PIN_SFS3, USB_PAD_CFG);
+       mxc_iomux_set_pad(MX31_PIN_SCK3, USB_PAD_CFG);
+       mxc_iomux_set_pad(MX31_PIN_SRXD3, USB_PAD_CFG);
+       mxc_iomux_set_pad(MX31_PIN_STXD3, USB_PAD_CFG);
+
+       gpio_direction_output(USBH2_EN_B, 0);
+
+       return 0;
+}
+
+static int moboard_usbh2_hw_exit(struct platform_device *pdev)
+{
+       gpio_free(USBH2_EN_B);
+       return 0;
+}
+
+static struct mxc_usbh_platform_data usbh2_pdata = {
+       .init   = moboard_usbh2_hw_init,
+       .exit   = moboard_usbh2_hw_exit,
+       .portsc = MXC_EHCI_MODE_ULPI | MXC_EHCI_UTMI_8BIT,
+       .flags  = MXC_EHCI_POWER_PINS_ENABLED,
+};
+
+static int __init moboard_usbh2_init(void)
+{
+       usbh2_pdata.otg = otg_ulpi_create(&mxc_ulpi_access_ops,
+                       USB_OTG_DRV_VBUS | USB_OTG_DRV_VBUS_EXT);
+
+       return mxc_register_device(&mx31_usbh2, &usbh2_pdata);
+}
+
+
 static struct gpio_led mx31moboard_leds[] = {
        {
                .name   = "coreboard-led-0:red:running",
@@ -266,11 +454,48 @@ static void mx31moboard_init_sel_gpios(void)
        }
 }
 
+static struct ipu_platform_data mx3_ipu_data = {
+       .irq_base = MXC_IPU_IRQ_START,
+};
+
 static struct platform_device *devices[] __initdata = {
        &mx31moboard_flash,
        &mx31moboard_leds_device,
 };
 
+static struct mx3_camera_pdata camera_pdata = {
+       .dma_dev        = &mx3_ipu.dev,
+       .flags          = MX3_CAMERA_DATAWIDTH_8 | MX3_CAMERA_DATAWIDTH_10,
+       .mclk_10khz     = 4800,
+};
+
+#define CAMERA_BUF_SIZE        (4*1024*1024)
+
+static int __init mx31moboard_cam_alloc_dma(const size_t buf_size)
+{
+       dma_addr_t dma_handle;
+       void *buf;
+       int dma;
+
+       if (buf_size < 2 * 1024 * 1024)
+               return -EINVAL;
+
+       buf = dma_alloc_coherent(NULL, buf_size, &dma_handle, GFP_KERNEL);
+       if (!buf) {
+               pr_err("%s: cannot allocate camera buffer-memory\n", __func__);
+               return -ENOMEM;
+       }
+
+       memset(buf, 0, buf_size);
+
+       dma = dma_declare_coherent_memory(&mx3_camera.dev,
+                                       dma_handle, dma_handle, buf_size,
+                                       DMA_MEMORY_MAP | DMA_MEMORY_EXCLUSIVE);
+
+       /* The way we call dma_declare_coherent_memory only a malloc can fail */
+       return dma & DMA_MEMORY_MAP ? 0 : -ENOMEM;
+}
+
 static int mx31moboard_baseboard;
 core_param(mx31moboard_baseboard, mx31moboard_baseboard, int, 0444);
 
@@ -284,20 +509,34 @@ static void __init mxc_board_init(void)
 
        platform_add_devices(devices, ARRAY_SIZE(devices));
 
-       mxc_register_device(&mxc_uart_device0, &uart_pdata);
-       mxc_register_device(&mxc_uart_device4, &uart_pdata);
+       mxc_register_device(&mxc_uart_device0, &uart0_pdata);
+
+       mxc_register_device(&mxc_uart_device4, &uart4_pdata);
 
        mx31moboard_init_sel_gpios();
 
        mxc_register_device(&mxc_i2c_device0, &moboard_i2c0_pdata);
        mxc_register_device(&mxc_i2c_device1, &moboard_i2c1_pdata);
 
+       mxc_register_device(&mxc_spi_device1, &moboard_spi1_master);
+       mxc_register_device(&mxc_spi_device2, &moboard_spi2_master);
+
+       gpio_request(IOMUX_TO_GPIO(MX31_PIN_GPIO1_3), "pmic-irq");
+       gpio_direction_input(IOMUX_TO_GPIO(MX31_PIN_GPIO1_3));
+       spi_register_board_info(moboard_spi_board_info,
+               ARRAY_SIZE(moboard_spi_board_info));
+
        mxc_register_device(&mxcsdhc_device0, &sdhc1_pdata);
 
+       mxc_register_device(&mx3_ipu, &mx3_ipu_data);
+       if (!mx31moboard_cam_alloc_dma(CAMERA_BUF_SIZE))
+               mxc_register_device(&mx3_camera, &camera_pdata);
+
        usb_xcvr_reset();
 
        moboard_usbotg_init();
        mxc_register_device(&mxc_otg_udc_device, &usb_pdata);
+       moboard_usbh2_init();
 
        switch (mx31moboard_baseboard) {
        case MX31NOBOARD:
index 6ff186e..0bbc65e 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/platform_device.h>
 #include <linux/memory.h>
 #include <linux/gpio.h>
+#include <linux/fsl_devices.h>
 
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
@@ -69,6 +70,15 @@ static struct pad_desc mx35pdk_pads[] = {
        MX35_PAD_FEC_TDATA2__FEC_TDATA_2,
        MX35_PAD_FEC_RDATA3__FEC_RDATA_3,
        MX35_PAD_FEC_TDATA3__FEC_TDATA_3,
+       /* USBOTG */
+       MX35_PAD_USBOTG_PWR__USB_TOP_USBOTG_PWR,
+       MX35_PAD_USBOTG_OC__USB_TOP_USBOTG_OC,
+};
+
+/* OTG config */
+static struct fsl_usb2_platform_data usb_pdata = {
+       .operating_mode = FSL_USB2_DR_DEVICE,
+       .phy_mode       = FSL_USB2_PHY_UTMI_WIDE,
 };
 
 /*
@@ -81,6 +91,8 @@ static void __init mxc_board_init(void)
        platform_add_devices(devices, ARRAY_SIZE(devices));
 
        mxc_register_device(&mxc_uart_device0, &uart_pdata);
+
+       mxc_register_device(&mxc_otg_udc_device, &usb_pdata);
 }
 
 static void __init mx35pdk_timer_init(void)
index e18a224..e3aa829 100644 (file)
@@ -43,6 +43,7 @@
 #include <mach/iomux-mx35.h>
 #include <mach/ipu.h>
 #include <mach/mx3fb.h>
+#include <mach/mxc_nand.h>
 
 #include "devices.h"
 
@@ -206,6 +207,11 @@ static struct pad_desc pcm043_pads[] = {
        MX35_PAD_ATA_CS0__GPIO2_6,
 };
 
+static struct mxc_nand_platform_data pcm037_nand_board_info = {
+       .width = 1,
+       .hw_ecc = 1,
+};
+
 /*
  * Board specific initialization.
  */
@@ -216,6 +222,7 @@ static void __init mxc_board_init(void)
        platform_add_devices(devices, ARRAY_SIZE(devices));
 
        mxc_register_device(&mxc_uart_device0, &uart_pdata);
+       mxc_register_device(&mxc_nand_device, &pcm037_nand_board_info);
 
        mxc_register_device(&mxc_uart_device1, &uart_pdata);
 
index 2a02b49..3c5e0f5 100644 (file)
@@ -5,13 +5,13 @@ menu "Nomadik boards"
 config MACH_NOMADIK_8815NHK
        bool "ST 8815 Nomadik Hardware Kit (evaluation board)"
        select NOMADIK_8815
+       select HAS_MTU
 
 endmenu
 
 config NOMADIK_8815
        bool
 
-
 config I2C_BITBANG_8815NHK
        tristate "Driver for bit-bang busses found on the 8815 NHK"
        depends on I2C && MACH_NOMADIK_8815NHK
index 4120409..36f67fb 100644 (file)
@@ -7,7 +7,7 @@
 
 # Object file lists.
 
-obj-y                  += clock.o timer.o gpio.o
+obj-y                  += clock.o gpio.o
 
 # Cpu revision
 obj-$(CONFIG_NOMADIK_8815) += cpu-8815.o
index 6bfd537..1163944 100644 (file)
 #include <asm/mach/arch.h>
 #include <asm/mach/irq.h>
 #include <asm/mach/flash.h>
+
+#include <plat/mtu.h>
+
 #include <mach/setup.h>
 #include <mach/nand.h>
 #include <mach/fsmc.h>
 #include "clock.h"
 
+/* Initial value for SRC control register: all timers use MXTAL/8 source */
+#define SRC_CR_INIT_MASK       0x00007fff
+#define SRC_CR_INIT_VAL                0x2aaa8000
+
 /* These adresses span 16MB, so use three individual pages */
 static struct resource nhk8815_nand_resources[] = {
        {
@@ -239,6 +246,26 @@ static struct platform_device *nhk8815_platform_devices[] __initdata = {
        /* will add more devices */
 };
 
+static void __init nomadik_timer_init(void)
+{
+       u32 src_cr;
+
+       /* Configure timer sources in "system reset controller" ctrl reg */
+       src_cr = readl(io_p2v(NOMADIK_SRC_BASE));
+       src_cr &= SRC_CR_INIT_MASK;
+       src_cr |= SRC_CR_INIT_VAL;
+       writel(src_cr, io_p2v(NOMADIK_SRC_BASE));
+
+       /* Save global pointer to mtu, used by platform timer code */
+       mtu_base = io_p2v(NOMADIK_MTU0_BASE);
+
+       nmdk_timer_init();
+}
+
+static struct sys_timer nomadik_timer = {
+       .init   = nomadik_timer_init,
+};
+
 static void __init nhk8815_platform_init(void)
 {
        int i;
index a4e468c..b7897ed 100644 (file)
@@ -15,7 +15,7 @@
 extern void cpu8815_map_io(void);
 extern void cpu8815_platform_init(void);
 extern void cpu8815_init_irq(void);
-extern struct sys_timer nomadik_timer;
+extern void nmdk_timer_init(void);
 
 #endif /* NOMADIK_8815 */
 
index 55ecc01..27f4897 100644 (file)
@@ -11,6 +11,7 @@ config ARCH_OMAP850
        depends on ARCH_OMAP1
        bool "OMAP850 Based System"
        select CPU_ARM926T
+       select ARCH_OMAP_OTG
 
 config ARCH_OMAP15XX
        depends on ARCH_OMAP1
@@ -56,6 +57,12 @@ config MACH_OMAP_HTCWIZARD
        help
          HTC Wizard smartphone support (AKA QTEK 9100, ...)
 
+config MACH_HERALD
+       bool "HTC Herald"
+       depends on ARCH_OMAP850
+       help
+         HTC Herald smartphone support (AKA T-Mobile Wing, ...)
+
 config MACH_OMAP_OSK
        bool "TI OSK Support"
        depends on ARCH_OMAP1 && ARCH_OMAP16XX
index 6867cd3..87e539a 100644 (file)
@@ -34,6 +34,7 @@ obj-$(CONFIG_MACH_OMAP_PALMTT)                += board-palmtt.o
 obj-$(CONFIG_MACH_NOKIA770)            += board-nokia770.o
 obj-$(CONFIG_MACH_AMS_DELTA)           += board-ams-delta.o
 obj-$(CONFIG_MACH_SX1)                 += board-sx1.o board-sx1-mmc.o
+obj-$(CONFIG_MACH_HERALD)              += board-htcherald.o
 
 ifeq ($(CONFIG_ARCH_OMAP15XX),y)
 # Innovator-1510 FPGA
index 8ad5cc3..7fc11c3 100644 (file)
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
 
-#include <mach/board-ams-delta.h>
+#include <plat/board-ams-delta.h>
 #include <mach/gpio.h>
-#include <mach/keypad.h>
-#include <mach/mux.h>
-#include <mach/usb.h>
-#include <mach/board.h>
-#include <mach/common.h>
+#include <plat/keypad.h>
+#include <plat/mux.h>
+#include <plat/usb.h>
+#include <plat/board.h>
+#include <plat/common.h>
 
 static u8 ams_delta_latch1_reg;
 static u16 ams_delta_latch2_reg;
index a7ead1b..f4b72c1 100644 (file)
 #include <asm/mach/flash.h>
 #include <asm/mach/map.h>
 
-#include <mach/tc.h>
+#include <plat/tc.h>
 #include <mach/gpio.h>
-#include <mach/mux.h>
-#include <mach/fpga.h>
-#include <mach/nand.h>
-#include <mach/keypad.h>
-#include <mach/common.h>
-#include <mach/board.h>
+#include <plat/mux.h>
+#include <plat/fpga.h>
+#include <plat/nand.h>
+#include <plat/keypad.h>
+#include <plat/common.h>
+#include <plat/board.h>
 
 /* fsample is pretty close to p2-sample */
 
@@ -107,7 +107,7 @@ static struct resource smc91x_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = INT_730_MPU_EXT_NIRQ,
+               .start  = INT_7XX_MPU_EXT_NIRQ,
                .end    = 0,
                .flags  = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE,
        },
@@ -196,8 +196,8 @@ static struct platform_device smc91x_device = {
 
 static struct resource kp_resources[] = {
        [0] = {
-               .start  = INT_730_MPUIO_KEYPAD,
-               .end    = INT_730_MPUIO_KEYPAD,
+               .start  = INT_7XX_MPUIO_KEYPAD,
+               .end    = INT_7XX_MPUIO_KEYPAD,
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -309,7 +309,7 @@ static void __init omap_fsample_map_io(void)
        /*
         * Hold GSM Reset until needed
         */
-       omap_writew(omap_readw(OMAP730_DSP_M_CTL) & ~1, OMAP730_DSP_M_CTL);
+       omap_writew(omap_readw(OMAP7XX_DSP_M_CTL) & ~1, OMAP7XX_DSP_M_CTL);
 
        /*
         * UARTs -> done automagically by 8250 driver
@@ -320,21 +320,21 @@ static void __init omap_fsample_map_io(void)
         */
 
        /* Flash: CS0 timings setup */
-       omap_writel(0x0000fff3, OMAP730_FLASH_CFG_0);
-       omap_writel(0x00000088, OMAP730_FLASH_ACFG_0);
+       omap_writel(0x0000fff3, OMAP7XX_FLASH_CFG_0);
+       omap_writel(0x00000088, OMAP7XX_FLASH_ACFG_0);
 
        /*
         * Ethernet support through the debug board
         * CS1 timings setup
         */
-       omap_writel(0x0000fff3, OMAP730_FLASH_CFG_1);
-       omap_writel(0x00000000, OMAP730_FLASH_ACFG_1);
+       omap_writel(0x0000fff3, OMAP7XX_FLASH_CFG_1);
+       omap_writel(0x00000000, OMAP7XX_FLASH_ACFG_1);
 
        /*
         * Configure MPU_EXT_NIRQ IO in IO_CONF9 register,
         * It is used as the Ethernet controller interrupt
         */
-       omap_writel(omap_readl(OMAP730_IO_CONF_9) & 0x1FFFFFFF, OMAP730_IO_CONF_9);
+       omap_writel(omap_readl(OMAP7XX_IO_CONF_9) & 0x1FFFFFFF, OMAP7XX_IO_CONF_9);
 }
 
 MACHINE_START(OMAP_FSAMPLE, "OMAP730 F-Sample")
index 6c8a41f..e1195a3 100644 (file)
 #include <asm/mach/map.h>
 
 #include <mach/gpio.h>
-#include <mach/mux.h>
-#include <mach/usb.h>
-#include <mach/board.h>
-#include <mach/common.h>
+#include <plat/mux.h>
+#include <plat/usb.h>
+#include <plat/board.h>
+#include <plat/common.h>
 
 static void __init omap_generic_init_irq(void)
 {
index 46098f5..b30c499 100644 (file)
@@ -16,7 +16,7 @@
 
 #include <linux/i2c/tps65010.h>
 
-#include <mach/mmc.h>
+#include <plat/mmc.h>
 #include <mach/gpio.h>
 
 #include "board-h2.h"
index aab8603..89ba8ec 100644 (file)
 #include <asm/mach/flash.h>
 #include <asm/mach/map.h>
 
-#include <mach/mux.h>
-#include <mach/dma.h>
-#include <mach/tc.h>
-#include <mach/nand.h>
-#include <mach/irda.h>
-#include <mach/usb.h>
-#include <mach/keypad.h>
-#include <mach/common.h>
+#include <plat/mux.h>
+#include <plat/dma.h>
+#include <plat/tc.h>
+#include <plat/nand.h>
+#include <plat/irda.h>
+#include <plat/usb.h>
+#include <plat/keypad.h>
+#include <plat/common.h>
 
 #include "board-h2.h"
 
index 5e8877c..54b0f06 100644 (file)
@@ -16,7 +16,7 @@
 
 #include <linux/i2c/tps65010.h>
 
-#include <mach/mmc.h>
+#include <plat/mmc.h>
 #include <mach/gpio.h>
 
 #include "board-h3.h"
index 89586b8..f5cc0a7 100644 (file)
 #include <asm/mach/map.h>
 
 #include <mach/irqs.h>
-#include <mach/mux.h>
-#include <mach/tc.h>
-#include <mach/nand.h>
-#include <mach/usb.h>
-#include <mach/keypad.h>
-#include <mach/dma.h>
-#include <mach/common.h>
+#include <plat/mux.h>
+#include <plat/tc.h>
+#include <plat/nand.h>
+#include <plat/usb.h>
+#include <plat/keypad.h>
+#include <plat/dma.h>
+#include <plat/common.h>
 
 #include "board-h3.h"
 
diff --git a/arch/arm/mach-omap1/board-htcherald.c b/arch/arm/mach-omap1/board-htcherald.c
new file mode 100644 (file)
index 0000000..5f28a5c
--- /dev/null
@@ -0,0 +1,247 @@
+/*
+ * HTC Herald board configuration
+ * Copyright (C) 2009 Cory Maccarrone <darkstar6262@gmail.com>
+ * Copyright (C) 2009 Wing Linux
+ *
+ * Based on the board-htcwizard.c file from the linwizard project:
+ * Copyright (C) 2006 Unai Uribarri
+ * Copyright (C) 2008 linwizard.sourceforge.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 program is distributed in the hope that it will be useful, but
+ * WITHOUT  ANY  WARRANTY;  without   even  the  implied  warranty  of
+ * MERCHANTABILITY or  FITNESS FOR A PARTICULAR PURPOSE.   See the GNU
+ * General Public License for more details.
+ *
+ * You should have  received a copy of the  GNU General Public License
+ * along  with  this program;  if  not,  write  to the  Free  Software
+ * Foundation,  Inc.,  51 Franklin  Street,  Fifth  Floor, Boston,  MA
+ * 02110-1301, USA.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/input.h>
+#include <linux/bootmem.h>
+#include <linux/io.h>
+#include <linux/gpio.h>
+
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+
+#include <plat/omap7xx.h>
+#include <plat/common.h>
+#include <plat/board.h>
+#include <plat/keypad.h>
+
+#include <mach/irqs.h>
+
+#include <linux/delay.h>
+
+/* LCD register definition */
+#define       OMAP_LCDC_CONTROL               (0xfffec000 + 0x00)
+#define       OMAP_LCDC_STATUS                (0xfffec000 + 0x10)
+#define       OMAP_DMA_LCD_CCR                (0xfffee300 + 0xc2)
+#define       OMAP_DMA_LCD_CTRL               (0xfffee300 + 0xc4)
+#define       OMAP_LCDC_CTRL_LCD_EN           (1 << 0)
+#define       OMAP_LCDC_STAT_DONE             (1 << 0)
+
+static struct omap_lcd_config htcherald_lcd_config __initdata = {
+       .ctrl_name      = "internal",
+};
+
+static struct omap_board_config_kernel htcherald_config[] __initdata = {
+       { OMAP_TAG_LCD, &htcherald_lcd_config },
+};
+
+/* Keyboard definition */
+
+static int htc_herald_keymap[] = {
+       KEY(0, 0, KEY_RECORD), /* Mail button */
+       KEY(0, 1, KEY_CAMERA), /* Camera */
+       KEY(0, 2, KEY_PHONE), /* Send key */
+       KEY(0, 3, KEY_VOLUMEUP), /* Volume up */
+       KEY(0, 4, KEY_F2),  /* Right bar (landscape) */
+       KEY(0, 5, KEY_MAIL), /* Win key (portrait) */
+       KEY(0, 6, KEY_DIRECTORY), /* Right bar (protrait) */
+       KEY(1, 0, KEY_LEFTCTRL), /* Windows key */
+       KEY(1, 1, KEY_COMMA),
+       KEY(1, 2, KEY_M),
+       KEY(1, 3, KEY_K),
+       KEY(1, 4, KEY_SLASH), /* OK key */
+       KEY(1, 5, KEY_I),
+       KEY(1, 6, KEY_U),
+       KEY(2, 0, KEY_LEFTALT),
+       KEY(2, 1, KEY_TAB),
+       KEY(2, 2, KEY_N),
+       KEY(2, 3, KEY_J),
+       KEY(2, 4, KEY_ENTER),
+       KEY(2, 5, KEY_H),
+       KEY(2, 6, KEY_Y),
+       KEY(3, 0, KEY_SPACE),
+       KEY(3, 1, KEY_L),
+       KEY(3, 2, KEY_B),
+       KEY(3, 3, KEY_V),
+       KEY(3, 4, KEY_BACKSPACE),
+       KEY(3, 5, KEY_G),
+       KEY(3, 6, KEY_T),
+       KEY(4, 0, KEY_CAPSLOCK), /* Shift */
+       KEY(4, 1, KEY_C),
+       KEY(4, 2, KEY_F),
+       KEY(4, 3, KEY_R),
+       KEY(4, 4, KEY_O),
+       KEY(4, 5, KEY_E),
+       KEY(4, 6, KEY_D),
+       KEY(5, 0, KEY_X),
+       KEY(5, 1, KEY_Z),
+       KEY(5, 2, KEY_S),
+       KEY(5, 3, KEY_W),
+       KEY(5, 4, KEY_P),
+       KEY(5, 5, KEY_Q),
+       KEY(5, 6, KEY_A),
+       KEY(6, 0, KEY_CONNECT), /* Voice button */
+       KEY(6, 2, KEY_CANCEL), /* End key */
+       KEY(6, 3, KEY_VOLUMEDOWN), /* Volume down */
+       KEY(6, 4, KEY_F1), /* Left bar (landscape) */
+       KEY(6, 5, KEY_WWW), /* OK button (portrait) */
+       KEY(6, 6, KEY_CALENDAR), /* Left bar (portrait) */
+       0
+};
+
+struct omap_kp_platform_data htcherald_kp_data = {
+       .rows   = 7,
+       .cols   = 7,
+       .delay = 20,
+       .rep = 1,
+       .keymap = htc_herald_keymap,
+};
+
+static struct resource kp_resources[] = {
+       [0] = {
+               .start  = INT_7XX_MPUIO_KEYPAD,
+               .end    = INT_7XX_MPUIO_KEYPAD,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device kp_device = {
+       .name           = "omap-keypad",
+       .id             = -1,
+       .dev            = {
+               .platform_data = &htcherald_kp_data,
+       },
+       .num_resources  = ARRAY_SIZE(kp_resources),
+       .resource       = kp_resources,
+};
+
+/* LCD Device resources */
+static struct platform_device lcd_device = {
+       .name           = "lcd_htcherald",
+       .id             = -1,
+};
+
+static struct platform_device *devices[] __initdata = {
+       &kp_device,
+       &lcd_device,
+};
+
+/*
+ * Init functions from here on
+ */
+
+static void __init htcherald_lcd_init(void)
+{
+       u32 reg;
+       unsigned int tries = 200;
+
+       /* disable controller if active */
+       reg = omap_readl(OMAP_LCDC_CONTROL);
+       if (reg & OMAP_LCDC_CTRL_LCD_EN) {
+               reg &= ~OMAP_LCDC_CTRL_LCD_EN;
+               omap_writel(reg, OMAP_LCDC_CONTROL);
+
+               /* wait for end of frame */
+               while (!(omap_readl(OMAP_LCDC_STATUS) & OMAP_LCDC_STAT_DONE)) {
+                       tries--;
+                       if (!tries)
+                               break;
+               }
+               if (!tries)
+                       printk(KERN_WARNING "Timeout waiting for end of frame "
+                              "-- LCD may not be available\n");
+
+               /* turn off DMA */
+               reg = omap_readw(OMAP_DMA_LCD_CCR);
+               reg &= ~(1 << 7);
+               omap_writew(reg, OMAP_DMA_LCD_CCR);
+
+               reg = omap_readw(OMAP_DMA_LCD_CTRL);
+               reg &= ~(1 << 8);
+               omap_writew(reg, OMAP_DMA_LCD_CTRL);
+       }
+}
+
+static void __init htcherald_map_io(void)
+{
+       omap1_map_common_io();
+
+       /*
+        * The LCD panel must be disabled and DMA turned off here, as doing
+        * it later causes the LCD never to reinitialize.
+        */
+       htcherald_lcd_init();
+
+       printk(KERN_INFO "htcherald_map_io done.\n");
+}
+
+static void __init htcherald_disable_watchdog(void)
+{
+       /* Disable watchdog if running */
+       if (omap_readl(OMAP_WDT_TIMER_MODE) & 0x8000) {
+               /*
+                * disable a potentially running watchdog timer before
+                * it kills us.
+                */
+               printk(KERN_WARNING "OMAP850 Watchdog seems to be activated, disabling it for now.\n");
+               omap_writel(0xF5, OMAP_WDT_TIMER_MODE);
+               omap_writel(0xA0, OMAP_WDT_TIMER_MODE);
+       }
+}
+
+static void __init htcherald_init(void)
+{
+       printk(KERN_INFO "HTC Herald init.\n");
+
+       omap_gpio_init();
+
+       omap_board_config = htcherald_config;
+       omap_board_config_size = ARRAY_SIZE(htcherald_config);
+       platform_add_devices(devices, ARRAY_SIZE(devices));
+
+       htcherald_disable_watchdog();
+}
+
+static void __init htcherald_init_irq(void)
+{
+       printk(KERN_INFO "htcherald_init_irq.\n");
+       omap1_init_common_hw();
+       omap_init_irq();
+}
+
+MACHINE_START(HERALD, "HTC Herald")
+       /* Maintainer: Cory Maccarrone <darkstar6262@gmail.com> */
+       /* Maintainer: wing-linux.sourceforge.net */
+       .phys_io        = 0xfff00000,
+       .io_pg_offst    = ((0xfef00000) >> 18) & 0xfffc,
+       .boot_params    = 0x10000100,
+       .map_io         = htcherald_map_io,
+       .init_irq       = htcherald_init_irq,
+       .init_machine   = htcherald_init,
+       .timer          = &omap_timer,
+MACHINE_END
index cd6c395..cf0fdb9 100644 (file)
 #include <asm/mach/flash.h>
 #include <asm/mach/map.h>
 
-#include <mach/mux.h>
-#include <mach/fpga.h>
+#include <plat/mux.h>
+#include <plat/fpga.h>
 #include <mach/gpio.h>
-#include <mach/tc.h>
-#include <mach/usb.h>
-#include <mach/keypad.h>
-#include <mach/common.h>
-#include <mach/mmc.h>
+#include <plat/tc.h>
+#include <plat/usb.h>
+#include <plat/keypad.h>
+#include <plat/common.h>
+#include <plat/mmc.h>
 
 /* At OMAP1610 Innovator the Ethernet is directly connected to CS1 */
 #define INNOVATOR1610_ETHR_START       0x04000300
index ed2a48a..5a275ba 100644 (file)
 #include <asm/mach/map.h>
 
 #include <mach/gpio.h>
-#include <mach/mux.h>
-#include <mach/usb.h>
-#include <mach/board.h>
-#include <mach/keypad.h>
-#include <mach/common.h>
-#include <mach/dsp_common.h>
-#include <mach/omapfb.h>
-#include <mach/hwa742.h>
-#include <mach/lcd_mipid.h>
-#include <mach/mmc.h>
-#include <mach/clock.h>
+#include <plat/mux.h>
+#include <plat/usb.h>
+#include <plat/board.h>
+#include <plat/keypad.h>
+#include <plat/common.h>
+#include <plat/dsp_common.h>
+#include <plat/omapfb.h>
+#include <plat/hwa742.h>
+#include <plat/lcd_mipid.h>
+#include <plat/mmc.h>
+#include <plat/clock.h>
 
 #define ADS7846_PENDOWN_GPIO   15
 
index ed891b8..50c92c1 100644 (file)
 #include <asm/mach/map.h>
 #include <asm/mach/flash.h>
 
-#include <mach/usb.h>
-#include <mach/mux.h>
-#include <mach/tc.h>
-#include <mach/common.h>
+#include <plat/usb.h>
+#include <plat/mux.h>
+#include <plat/tc.h>
+#include <plat/common.h>
 
 /* At OMAP5912 OSK the Ethernet is directly connected to CS1 */
 #define OMAP_OSK_ETHR_START            0x04800300
@@ -312,7 +312,7 @@ static struct omap_board_config_kernel osk_config[] __initdata = {
 #include <linux/spi/spi.h>
 #include <linux/spi/ads7846.h>
 
-#include <mach/keypad.h>
+#include <plat/keypad.h>
 
 static struct at24_platform_data at24c04 = {
        .byte_len       = SZ_4K / 8,
index 4de2584..9fe8872 100644 (file)
 #include <asm/mach/flash.h>
 
 #include <mach/gpio.h>
-#include <mach/mux.h>
-#include <mach/usb.h>
-#include <mach/tc.h>
-#include <mach/dma.h>
-#include <mach/board.h>
-#include <mach/irda.h>
-#include <mach/keypad.h>
-#include <mach/common.h>
+#include <plat/mux.h>
+#include <plat/usb.h>
+#include <plat/tc.h>
+#include <plat/dma.h>
+#include <plat/board.h>
+#include <plat/irda.h>
+#include <plat/keypad.h>
+#include <plat/common.h>
 
 #define PALMTE_USBDETECT_GPIO  0
 #define PALMTE_USB_OR_DC_GPIO  1
index d972cf9..af068e3 100644 (file)
 #include <asm/mach/map.h>
 #include <asm/mach/flash.h>
 
-#include <mach/led.h>
+#include <plat/led.h>
 #include <mach/gpio.h>
-#include <mach/mux.h>
-#include <mach/usb.h>
-#include <mach/dma.h>
-#include <mach/tc.h>
-#include <mach/board.h>
-#include <mach/irda.h>
-#include <mach/keypad.h>
-#include <mach/common.h>
+#include <plat/mux.h>
+#include <plat/usb.h>
+#include <plat/dma.h>
+#include <plat/tc.h>
+#include <plat/board.h>
+#include <plat/irda.h>
+#include <plat/keypad.h>
+#include <plat/common.h>
 
 #include <linux/spi/spi.h>
 #include <linux/spi/ads7846.h>
index 986bd4d..c7a3b6f 100644 (file)
 #include <asm/mach/flash.h>
 
 #include <mach/gpio.h>
-#include <mach/mux.h>
-#include <mach/usb.h>
-#include <mach/dma.h>
-#include <mach/tc.h>
-#include <mach/board.h>
-#include <mach/irda.h>
-#include <mach/keypad.h>
-#include <mach/common.h>
-#include <mach/omap-alsa.h>
+#include <plat/mux.h>
+#include <plat/usb.h>
+#include <plat/dma.h>
+#include <plat/tc.h>
+#include <plat/board.h>
+#include <plat/irda.h>
+#include <plat/keypad.h>
+#include <plat/common.h>
+#include <plat/omap-alsa.h>
 
 #include <linux/spi/spi.h>
 #include <linux/spi/ads7846.h>
index 8340669..ca7df1e 100644 (file)
 #include <asm/mach/flash.h>
 #include <asm/mach/map.h>
 
-#include <mach/tc.h>
+#include <plat/tc.h>
 #include <mach/gpio.h>
-#include <mach/mux.h>
-#include <mach/fpga.h>
-#include <mach/nand.h>
-#include <mach/keypad.h>
-#include <mach/common.h>
-#include <mach/board.h>
+#include <plat/mux.h>
+#include <plat/fpga.h>
+#include <plat/nand.h>
+#include <plat/keypad.h>
+#include <plat/common.h>
+#include <plat/board.h>
 
 static int p2_keymap[] = {
        KEY(0,0,KEY_UP),
@@ -74,7 +74,7 @@ static struct resource smc91x_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = INT_730_MPU_EXT_NIRQ,
+               .start  = INT_7XX_MPU_EXT_NIRQ,
                .end    = 0,
                .flags  = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE,
        },
@@ -163,8 +163,8 @@ static struct platform_device smc91x_device = {
 
 static struct resource kp_resources[] = {
        [0] = {
-               .start  = INT_730_MPUIO_KEYPAD,
-               .end    = INT_730_MPUIO_KEYPAD,
+               .start  = INT_7XX_MPUIO_KEYPAD,
+               .end    = INT_7XX_MPUIO_KEYPAD,
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -270,7 +270,7 @@ static void __init omap_perseus2_map_io(void)
        /*
         * Hold GSM Reset until needed
         */
-       omap_writew(omap_readw(OMAP730_DSP_M_CTL) & ~1, OMAP730_DSP_M_CTL);
+       omap_writew(omap_readw(OMAP7XX_DSP_M_CTL) & ~1, OMAP7XX_DSP_M_CTL);
 
        /*
         * UARTs -> done automagically by 8250 driver
@@ -281,21 +281,21 @@ static void __init omap_perseus2_map_io(void)
         */
 
        /* Flash: CS0 timings setup */
-       omap_writel(0x0000fff3, OMAP730_FLASH_CFG_0);
-       omap_writel(0x00000088, OMAP730_FLASH_ACFG_0);
+       omap_writel(0x0000fff3, OMAP7XX_FLASH_CFG_0);
+       omap_writel(0x00000088, OMAP7XX_FLASH_ACFG_0);
 
        /*
         * Ethernet support through the debug board
         * CS1 timings setup
         */
-       omap_writel(0x0000fff3, OMAP730_FLASH_CFG_1);
-       omap_writel(0x00000000, OMAP730_FLASH_ACFG_1);
+       omap_writel(0x0000fff3, OMAP7XX_FLASH_CFG_1);
+       omap_writel(0x00000000, OMAP7XX_FLASH_ACFG_1);
 
        /*
         * Configure MPU_EXT_NIRQ IO in IO_CONF9 register,
         * It is used as the Ethernet controller interrupt
         */
-       omap_writel(omap_readl(OMAP730_IO_CONF_9) & 0x1FFFFFFF, OMAP730_IO_CONF_9);
+       omap_writel(omap_readl(OMAP7XX_IO_CONF_9) & 0x1FFFFFFF, OMAP7XX_IO_CONF_9);
 }
 
 MACHINE_START(OMAP_PERSEUS2, "OMAP730 Perseus2")
index 58a46e4..5b33ae8 100644 (file)
@@ -15,9 +15,9 @@
 #include <linux/platform_device.h>
 
 #include <mach/hardware.h>
-#include <mach/mmc.h>
+#include <plat/mmc.h>
 #include <mach/gpio.h>
-#include <mach/board-sx1.h>
+#include <plat/board-sx1.h>
 
 #if defined(CONFIG_MMC_OMAP) || defined(CONFIG_MMC_OMAP_MODULE)
 
index 056ae64..7a97fac 100644 (file)
 #include <asm/mach/map.h>
 
 #include <mach/gpio.h>
-#include <mach/mux.h>
-#include <mach/dma.h>
-#include <mach/irda.h>
-#include <mach/usb.h>
-#include <mach/tc.h>
-#include <mach/board.h>
-#include <mach/common.h>
-#include <mach/keypad.h>
-#include <mach/board-sx1.h>
+#include <plat/mux.h>
+#include <plat/dma.h>
+#include <plat/irda.h>
+#include <plat/usb.h>
+#include <plat/tc.h>
+#include <plat/board.h>
+#include <plat/common.h>
+#include <plat/keypad.h>
+#include <plat/board-sx1.h>
 
 /* Write to I2C device */
 int sx1_i2c_write_byte(u8 devaddr, u8 regoffset, u8 value)
index 07b0752..35c75c1 100644 (file)
 #include <asm/mach/flash.h>
 #include <asm/mach/map.h>
 
-#include <mach/common.h>
+#include <plat/common.h>
 #include <mach/gpio.h>
-#include <mach/mux.h>
-#include <mach/tc.h>
-#include <mach/usb.h>
+#include <plat/mux.h>
+#include <plat/tc.h>
+#include <plat/usb.h>
 
 static struct plat_serial8250_port voiceblue_ports[] = {
        {
index 436eed2..42cbe20 100644 (file)
 #include <asm/mach-types.h>
 #include <asm/clkdev.h>
 
-#include <mach/cpu.h>
-#include <mach/usb.h>
-#include <mach/clock.h>
-#include <mach/sram.h>
+#include <plat/cpu.h>
+#include <plat/usb.h>
+#include <plat/clock.h>
+#include <plat/sram.h>
 
 static const struct clkops clkops_generic;
 static const struct clkops clkops_uart;
@@ -69,13 +69,13 @@ struct omap_clk {
        }
 
 #define CK_310 (1 << 0)
-#define CK_730 (1 << 1)
+#define CK_7XX (1 << 1)
 #define CK_1510        (1 << 2)
 #define CK_16XX        (1 << 3)
 
 static struct omap_clk omap_clks[] = {
        /* non-ULPD clocks */
-       CLK(NULL,       "ck_ref",       &ck_ref,        CK_16XX | CK_1510 | CK_310),
+       CLK(NULL,       "ck_ref",       &ck_ref,        CK_16XX | CK_1510 | CK_310 | CK_7XX),
        CLK(NULL,       "ck_dpll1",     &ck_dpll1,      CK_16XX | CK_1510 | CK_310),
        /* CK_GEN1 clocks */
        CLK(NULL,       "ck_dpll1out",  &ck_dpll1out.clk, CK_16XX),
@@ -83,7 +83,7 @@ static struct omap_clk omap_clks[] = {
        CLK(NULL,       "arm_ck",       &arm_ck,        CK_16XX | CK_1510 | CK_310),
        CLK(NULL,       "armper_ck",    &armper_ck.clk, CK_16XX | CK_1510 | CK_310),
        CLK(NULL,       "arm_gpio_ck",  &arm_gpio_ck,   CK_1510 | CK_310),
-       CLK(NULL,       "armxor_ck",    &armxor_ck.clk, CK_16XX | CK_1510 | CK_310),
+       CLK(NULL,       "armxor_ck",    &armxor_ck.clk, CK_16XX | CK_1510 | CK_310 | CK_7XX),
        CLK(NULL,       "armtim_ck",    &armtim_ck.clk, CK_16XX | CK_1510 | CK_310),
        CLK("omap_wdt", "fck",          &armwdt_ck.clk, CK_16XX | CK_1510 | CK_310),
        CLK("omap_wdt", "ick",          &armper_ck.clk, CK_16XX),
@@ -97,9 +97,9 @@ static struct omap_clk omap_clks[] = {
        CLK(NULL,       "dspxor_ck",    &dspxor_ck,     CK_16XX | CK_1510 | CK_310),
        CLK(NULL,       "dsptim_ck",    &dsptim_ck,     CK_16XX | CK_1510 | CK_310),
        /* CK_GEN3 clocks */
-       CLK(NULL,       "tc_ck",        &tc_ck.clk,     CK_16XX | CK_1510 | CK_310 | CK_730),
+       CLK(NULL,       "tc_ck",        &tc_ck.clk,     CK_16XX | CK_1510 | CK_310 | CK_7XX),
        CLK(NULL,       "tipb_ck",      &tipb_ck,       CK_1510 | CK_310),
-       CLK(NULL,       "l3_ocpi_ck",   &l3_ocpi_ck,    CK_16XX),
+       CLK(NULL,       "l3_ocpi_ck",   &l3_ocpi_ck,    CK_16XX | CK_7XX),
        CLK(NULL,       "tc1_ck",       &tc1_ck,        CK_16XX),
        CLK(NULL,       "tc2_ck",       &tc2_ck,        CK_16XX),
        CLK(NULL,       "dma_ck",       &dma_ck,        CK_16XX | CK_1510 | CK_310),
@@ -108,7 +108,7 @@ static struct omap_clk omap_clks[] = {
        CLK(NULL,       "lb_ck",        &lb_ck.clk,     CK_1510 | CK_310),
        CLK(NULL,       "rhea1_ck",     &rhea1_ck,      CK_16XX),
        CLK(NULL,       "rhea2_ck",     &rhea2_ck,      CK_16XX),
-       CLK(NULL,       "lcd_ck",       &lcd_ck_16xx,   CK_16XX | CK_730),
+       CLK(NULL,       "lcd_ck",       &lcd_ck_16xx,   CK_16XX | CK_7XX),
        CLK(NULL,       "lcd_ck",       &lcd_ck_1510.clk, CK_1510 | CK_310),
        /* ULPD clocks */
        CLK(NULL,       "uart1_ck",     &uart1_1510,    CK_1510 | CK_310),
@@ -120,12 +120,14 @@ static struct omap_clk omap_clks[] = {
        CLK(NULL,       "usb_hhc_ck",   &usb_hhc_ck1510, CK_1510 | CK_310),
        CLK(NULL,       "usb_hhc_ck",   &usb_hhc_ck16xx, CK_16XX),
        CLK(NULL,       "usb_dc_ck",    &usb_dc_ck,     CK_16XX),
+       CLK(NULL,       "usb_dc_ck",    &usb_dc_ck7xx,  CK_7XX),
        CLK(NULL,       "mclk",         &mclk_1510,     CK_1510 | CK_310),
        CLK(NULL,       "mclk",         &mclk_16xx,     CK_16XX),
        CLK(NULL,       "bclk",         &bclk_1510,     CK_1510 | CK_310),
        CLK(NULL,       "bclk",         &bclk_16xx,     CK_16XX),
        CLK("mmci-omap.0", "fck",       &mmc1_ck,       CK_16XX | CK_1510 | CK_310),
-       CLK("mmci-omap.0", "ick",       &armper_ck.clk, CK_16XX | CK_1510 | CK_310),
+       CLK("mmci-omap.0", "fck",       &mmc3_ck,       CK_7XX),
+       CLK("mmci-omap.0", "ick",       &armper_ck.clk, CK_16XX | CK_1510 | CK_310 | CK_7XX),
        CLK("mmci-omap.1", "fck",       &mmc2_ck,       CK_16XX),
        CLK("mmci-omap.1", "ick",       &armper_ck.clk, CK_16XX),
        /* Virtual clocks */
@@ -398,7 +400,7 @@ static int omap1_select_table_rate(struct clk * clk, unsigned long rate)
         * Reprogramming the DPLL is tricky, it must be done from SRAM.
         * (on 730, bit 13 must always be 1)
         */
-       if (cpu_is_omap730())
+       if (cpu_is_omap7xx())
                omap_sram_reprogram_clock(ptr->dpllctl_val, ptr->ckctl_val | 0x2000);
        else
                omap_sram_reprogram_clock(ptr->dpllctl_val, ptr->ckctl_val);
@@ -783,8 +785,8 @@ int __init omap1_clk_init(void)
                cpu_mask |= CK_16XX;
        if (cpu_is_omap1510())
                cpu_mask |= CK_1510;
-       if (cpu_is_omap730())
-               cpu_mask |= CK_730;
+       if (cpu_is_omap7xx())
+               cpu_mask |= CK_7XX;
        if (cpu_is_omap310())
                cpu_mask |= CK_310;
 
@@ -800,7 +802,7 @@ int __init omap1_clk_init(void)
                        crystal_type = info->system_clock_type;
        }
 
-#if defined(CONFIG_ARCH_OMAP730)
+#if defined(CONFIG_ARCH_OMAP730) || defined(CONFIG_ARCH_OMAP850)
        ck_ref.rate = 13000000;
 #elif defined(CONFIG_ARCH_OMAP16XX)
        if (crystal_type == 2)
@@ -847,7 +849,7 @@ int __init omap1_clk_init(void)
                printk(KERN_ERR "System frequencies not set. Check your config.\n");
                /* Guess sane values (60MHz) */
                omap_writew(0x2290, DPLL_CTL);
-               omap_writew(cpu_is_omap730() ? 0x3005 : 0x1005, ARM_CKCTL);
+               omap_writew(cpu_is_omap7xx() ? 0x3005 : 0x1005, ARM_CKCTL);
                ck_dpll1.rate = 60000000;
        }
 #endif
@@ -862,7 +864,7 @@ int __init omap1_clk_init(void)
 
 #if defined(CONFIG_MACH_OMAP_PERSEUS2) || defined(CONFIG_MACH_OMAP_FSAMPLE)
        /* Select slicer output as OMAP input clock */
-       omap_writew(omap_readw(OMAP730_PCC_UPLD_CTRL) & ~0x1, OMAP730_PCC_UPLD_CTRL);
+       omap_writew(omap_readw(OMAP7XX_PCC_UPLD_CTRL) & ~0x1, OMAP7XX_PCC_UPLD_CTRL);
 #endif
 
        /* Amstrad Delta wants BCLK high when inactive */
@@ -873,7 +875,7 @@ int __init omap1_clk_init(void)
 
        /* Turn off DSP and ARM_TIMXO. Make sure ARM_INTHCK is not divided */
        /* (on 730, bit 13 must not be cleared) */
-       if (cpu_is_omap730())
+       if (cpu_is_omap7xx())
                omap_writew(omap_readw(ARM_CKCTL) & 0x2fff, ARM_CKCTL);
        else
                omap_writew(omap_readw(ARM_CKCTL) & 0x0fff, ARM_CKCTL);
index 17f8742..29ffa97 100644 (file)
@@ -574,6 +574,16 @@ static struct clk usb_dc_ck = {
        .enable_bit     = 4,
 };
 
+static struct clk usb_dc_ck7xx = {
+       .name           = "usb_dc_ck",
+       .ops            = &clkops_generic,
+       /* Direct from ULPD, no parent */
+       .rate           = 48000000,
+       .flags          = RATE_FIXED,
+       .enable_reg     = OMAP1_IO_ADDRESS(SOFT_REQ_REG),
+       .enable_bit     = 8,
+};
+
 static struct clk mclk_1510 = {
        .name           = "mclk",
        .ops            = &clkops_generic,
@@ -637,6 +647,18 @@ static struct clk mmc2_ck = {
        .enable_bit     = 20,
 };
 
+static struct clk mmc3_ck = {
+       .name           = "mmc_ck",
+       .id             = 2,
+       .ops            = &clkops_generic,
+       /* Functional clock is direct from ULPD, interface clock is ARMPER */
+       .parent         = &armper_ck.clk,
+       .rate           = 48000000,
+       .flags          = RATE_FIXED | ENABLE_REG_32BIT | CLOCK_NO_IDLE_PARENT,
+       .enable_reg     = OMAP1_IO_ADDRESS(SOFT_REQ_REG),
+       .enable_bit     = 12,
+};
+
 static struct clk virtual_ck_mpu = {
        .name           = "mpu",
        .ops            = &clkops_null,
index 0680843..23ded2d 100644 (file)
 #include <mach/hardware.h>
 #include <asm/mach/map.h>
 
-#include <mach/tc.h>
-#include <mach/board.h>
-#include <mach/mux.h>
+#include <plat/tc.h>
+#include <plat/board.h>
+#include <plat/mux.h>
 #include <mach/gpio.h>
-#include <mach/mmc.h>
+#include <plat/mmc.h>
 
 /*-------------------------------------------------------------------------*/
 
@@ -108,15 +108,22 @@ static inline void omap1_mmc_mux(struct omap_mmc_platform_data *mmc_controller,
                        int controller_nr)
 {
        if (controller_nr == 0) {
-               omap_cfg_reg(MMC_CMD);
-               omap_cfg_reg(MMC_CLK);
-               omap_cfg_reg(MMC_DAT0);
+               if (cpu_is_omap7xx()) {
+                       omap_cfg_reg(MMC_7XX_CMD);
+                       omap_cfg_reg(MMC_7XX_CLK);
+                       omap_cfg_reg(MMC_7XX_DAT0);
+               } else {
+                       omap_cfg_reg(MMC_CMD);
+                       omap_cfg_reg(MMC_CLK);
+                       omap_cfg_reg(MMC_DAT0);
+               }
+
                if (cpu_is_omap1710()) {
                        omap_cfg_reg(M15_1710_MMC_CLKI);
                        omap_cfg_reg(P19_1710_MMC_CMDDIR);
                        omap_cfg_reg(P20_1710_MMC_DATDIR0);
                }
-               if (mmc_controller->slots[0].wires == 4) {
+               if (mmc_controller->slots[0].wires == 4 && !cpu_is_omap7xx()) {
                        omap_cfg_reg(MMC_DAT1);
                        /* NOTE: DAT2 can be on W10 (here) or M15 */
                        if (!mmc_controller->slots[0].nomux)
index 4f2b8a7..5cfce16 100644 (file)
@@ -27,7 +27,7 @@
 #include <asm/irq.h>
 #include <asm/mach/irq.h>
 
-#include <mach/fpga.h>
+#include <plat/fpga.h>
 #include <mach/gpio.h>
 
 static void fpga_mask_irq(unsigned int irq)
index e5dcdf7..a0e3560 100644 (file)
@@ -15,7 +15,7 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/io.h>
-#include <mach/cpu.h>
+#include <plat/cpu.h>
 
 #define OMAP_DIE_ID_0          0xfffe1800
 #define OMAP_DIE_ID_1          0xfffe1804
diff --git a/arch/arm/mach-omap1/include/mach/clkdev.h b/arch/arm/mach-omap1/include/mach/clkdev.h
new file mode 100644 (file)
index 0000000..ea8640e
--- /dev/null
@@ -0,0 +1,5 @@
+/*
+ * arch/arm/mach-omap1/include/mach/clkdev.h
+ */
+
+#include <plat/clkdev.h>
diff --git a/arch/arm/mach-omap1/include/mach/debug-macro.S b/arch/arm/mach-omap1/include/mach/debug-macro.S
new file mode 100644 (file)
index 0000000..aedb746
--- /dev/null
@@ -0,0 +1,45 @@
+/* arch/arm/mach-omap1/include/mach/debug-macro.S
+ *
+ * Debugging macro include header
+ *
+ *  Copyright (C) 1994-1999 Russell King
+ *  Moved from linux/arch/arm/kernel/debug.S by Ben Dooks
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+*/
+
+               .macro  addruart,rx
+               mrc     p15, 0, \rx, c1, c0
+               tst     \rx, #1                 @ MMU enabled?
+               moveq   \rx, #0xff000000        @ physical base address
+               movne   \rx, #0xfe000000        @ virtual base
+               orr     \rx, \rx, #0x00fb0000
+#ifdef CONFIG_OMAP_LL_DEBUG_UART3
+               orr     \rx, \rx, #0x00009000   @ UART 3
+#endif
+#if defined(CONFIG_OMAP_LL_DEBUG_UART2) || defined(CONFIG_OMAP_LL_DEBUG_UART3)
+               orr     \rx, \rx, #0x00000800   @ UART 2 & 3
+#endif
+               .endm
+
+               .macro  senduart,rd,rx
+               strb    \rd, [\rx]
+               .endm
+
+               .macro  busyuart,rd,rx
+1001:          ldrb    \rd, [\rx, #(0x5 << 2)] @ OMAP-1510 and friends
+               and     \rd, \rd, #0x60
+               teq     \rd, #0x60
+               beq     1002f
+               ldrb    \rd, [\rx, #(0x5 << 0)] @ OMAP-730 only
+               and     \rd, \rd, #0x60
+               teq     \rd, #0x60
+               bne     1001b
+1002:
+               .endm
+
+               .macro  waituart,rd,rx
+               .endm
diff --git a/arch/arm/mach-omap1/include/mach/entry-macro.S b/arch/arm/mach-omap1/include/mach/entry-macro.S
new file mode 100644 (file)
index 0000000..df9060e
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * arch/arm/mach-omap1/include/mach/entry-macro.S
+ *
+ * Low-level IRQ helper macros for OMAP-based platforms
+ *
+ * Copyright (C) 2009 Texas Instruments
+ *
+ * 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/io.h>
+#include <mach/irqs.h>
+#include <asm/hardware/gic.h>
+
+#if (defined(CONFIG_ARCH_OMAP730)||defined(CONFIG_ARCH_OMAP850)) && \
+       (defined(CONFIG_ARCH_OMAP15XX) || defined(CONFIG_ARCH_OMAP16XX))
+#error "FIXME: OMAP7XX doesn't support multiple-OMAP"
+#elif defined(CONFIG_ARCH_OMAP730) || defined(CONFIG_ARCH_OMAP850)
+#define INT_IH2_IRQ            INT_7XX_IH2_IRQ
+#elif defined(CONFIG_ARCH_OMAP15XX)
+#define INT_IH2_IRQ            INT_1510_IH2_IRQ
+#elif defined(CONFIG_ARCH_OMAP16XX)
+#define INT_IH2_IRQ            INT_1610_IH2_IRQ
+#else
+#warning "IH2 IRQ defaulted"
+#define INT_IH2_IRQ            INT_1510_IH2_IRQ
+#endif
+
+               .macro  disable_fiq
+               .endm
+
+               .macro  get_irqnr_preamble, base, tmp
+               .endm
+
+               .macro  arch_ret_to_user, tmp1, tmp2
+               .endm
+
+               .macro  get_irqnr_and_base, irqnr, irqstat, base, tmp
+               ldr     \base, =OMAP1_IO_ADDRESS(OMAP_IH1_BASE)
+               ldr     \irqnr, [\base, #IRQ_ITR_REG_OFFSET]
+               ldr     \tmp, [\base, #IRQ_MIR_REG_OFFSET]
+               mov     \irqstat, #0xffffffff
+               bic     \tmp, \irqstat, \tmp
+               tst     \irqnr, \tmp
+               beq     1510f
+
+               ldr     \irqnr, [\base, #IRQ_SIR_FIQ_REG_OFFSET]
+               cmp     \irqnr, #0
+               ldreq   \irqnr, [\base, #IRQ_SIR_IRQ_REG_OFFSET]
+               cmpeq   \irqnr, #INT_IH2_IRQ
+               ldreq   \base, =OMAP1_IO_ADDRESS(OMAP_IH2_BASE)
+               ldreq   \irqnr, [\base, #IRQ_SIR_IRQ_REG_OFFSET]
+               addeqs  \irqnr, \irqnr, #32
+1510:
+               .endm
+
diff --git a/arch/arm/mach-omap1/include/mach/gpio.h b/arch/arm/mach-omap1/include/mach/gpio.h
new file mode 100644 (file)
index 0000000..e737706
--- /dev/null
@@ -0,0 +1,5 @@
+/*
+ * arch/arm/mach-omap1/include/mach/gpio.h
+ */
+
+#include <plat/gpio.h>
diff --git a/arch/arm/mach-omap1/include/mach/hardware.h b/arch/arm/mach-omap1/include/mach/hardware.h
new file mode 100644 (file)
index 0000000..a3f6287
--- /dev/null
@@ -0,0 +1,5 @@
+/*
+ * arch/arm/mach-omap1/include/mach/hardware.h
+ */
+
+#include <plat/hardware.h>
diff --git a/arch/arm/mach-omap1/include/mach/io.h b/arch/arm/mach-omap1/include/mach/io.h
new file mode 100644 (file)
index 0000000..57bdf74
--- /dev/null
@@ -0,0 +1,5 @@
+/*
+ * arch/arm/mach-omap1/include/mach/io.h
+ */
+
+#include <plat/io.h>
diff --git a/arch/arm/mach-omap1/include/mach/irqs.h b/arch/arm/mach-omap1/include/mach/irqs.h
new file mode 100644 (file)
index 0000000..9292fdc
--- /dev/null
@@ -0,0 +1,5 @@
+/*
+ * arch/arm/mach-omap1/include/mach/irqs.h
+ */
+
+#include <plat/irqs.h>
diff --git a/arch/arm/mach-omap1/include/mach/memory.h b/arch/arm/mach-omap1/include/mach/memory.h
new file mode 100644 (file)
index 0000000..e9b600c
--- /dev/null
@@ -0,0 +1,5 @@
+/*
+ * arch/arm/mach-omap1/include/mach/memory.h
+ */
+
+#include <plat/memory.h>
diff --git a/arch/arm/mach-omap1/include/mach/smp.h b/arch/arm/mach-omap1/include/mach/smp.h
new file mode 100644 (file)
index 0000000..80a371c
--- /dev/null
@@ -0,0 +1,5 @@
+/*
+ * arch/arm/mach-omap1/include/mach/smp.h
+ */
+
+#include <plat/smp.h>
diff --git a/arch/arm/mach-omap1/include/mach/system.h b/arch/arm/mach-omap1/include/mach/system.h
new file mode 100644 (file)
index 0000000..a6c1b3a
--- /dev/null
@@ -0,0 +1,5 @@
+/*
+ * arch/arm/mach-omap1/include/mach/system.h
+ */
+
+#include <plat/system.h>
diff --git a/arch/arm/mach-omap1/include/mach/timex.h b/arch/arm/mach-omap1/include/mach/timex.h
new file mode 100644 (file)
index 0000000..4793790
--- /dev/null
@@ -0,0 +1,5 @@
+/*
+ * arch/arm/mach-omap1/include/mach/timex.h
+ */
+
+#include <plat/timex.h>
diff --git a/arch/arm/mach-omap1/include/mach/uncompress.h b/arch/arm/mach-omap1/include/mach/uncompress.h
new file mode 100644 (file)
index 0000000..0ff22dc
--- /dev/null
@@ -0,0 +1,5 @@
+/*
+ * arch/arm/mach-omap1/include/mach/uncompress.h
+ */
+
+#include <plat/uncompress.h>
diff --git a/arch/arm/mach-omap1/include/mach/vmalloc.h b/arch/arm/mach-omap1/include/mach/vmalloc.h
new file mode 100644 (file)
index 0000000..1b2af14
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ *  arch/arm/mach-omap1/include/mach/vmalloc.h
+ *
+ *  Copyright (C) 2000 Russell King.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#define VMALLOC_END    (PAGE_OFFSET + 0x18000000)
index 7030f92..2a6d68a 100644 (file)
@@ -15,8 +15,8 @@
 
 #include <asm/tlb.h>
 #include <asm/mach/map.h>
-#include <mach/mux.h>
-#include <mach/tc.h>
+#include <plat/mux.h>
+#include <plat/tc.h>
 
 extern int omap1_clk_init(void);
 extern void omap_check_revision(void);
@@ -36,33 +36,17 @@ static struct map_desc omap_io_desc[] __initdata = {
        }
 };
 
-#ifdef CONFIG_ARCH_OMAP730
-static struct map_desc omap730_io_desc[] __initdata = {
+#if defined (CONFIG_ARCH_OMAP730) || defined (CONFIG_ARCH_OMAP850)
+static struct map_desc omap7xx_io_desc[] __initdata = {
        {
-               .virtual        = OMAP730_DSP_BASE,
-               .pfn            = __phys_to_pfn(OMAP730_DSP_START),
-               .length         = OMAP730_DSP_SIZE,
+               .virtual        = OMAP7XX_DSP_BASE,
+               .pfn            = __phys_to_pfn(OMAP7XX_DSP_START),
+               .length         = OMAP7XX_DSP_SIZE,
                .type           = MT_DEVICE
        }, {
-               .virtual        = OMAP730_DSPREG_BASE,
-               .pfn            = __phys_to_pfn(OMAP730_DSPREG_START),
-               .length         = OMAP730_DSPREG_SIZE,
-               .type           = MT_DEVICE
-       }
-};
-#endif
-
-#ifdef CONFIG_ARCH_OMAP850
-static struct map_desc omap850_io_desc[] __initdata = {
-       {
-               .virtual        = OMAP850_DSP_BASE,
-               .pfn            = __phys_to_pfn(OMAP850_DSP_START),
-               .length         = OMAP850_DSP_SIZE,
-               .type           = MT_DEVICE
-       }, {
-               .virtual        = OMAP850_DSPREG_BASE,
-               .pfn            = __phys_to_pfn(OMAP850_DSPREG_START),
-               .length         = OMAP850_DSPREG_SIZE,
+               .virtual        = OMAP7XX_DSPREG_BASE,
+               .pfn            = __phys_to_pfn(OMAP7XX_DSPREG_START),
+               .length         = OMAP7XX_DSPREG_SIZE,
                .type           = MT_DEVICE
        }
 };
@@ -120,18 +104,11 @@ void __init omap1_map_common_io(void)
         */
        omap_check_revision();
 
-#ifdef CONFIG_ARCH_OMAP730
-       if (cpu_is_omap730()) {
-               iotable_init(omap730_io_desc, ARRAY_SIZE(omap730_io_desc));
-       }
-#endif
-
-#ifdef CONFIG_ARCH_OMAP850
-       if (cpu_is_omap850()) {
-               iotable_init(omap850_io_desc, ARRAY_SIZE(omap850_io_desc));
+#if defined (CONFIG_ARCH_OMAP730) || defined (CONFIG_ARCH_OMAP850)
+       if (cpu_is_omap7xx()) {
+               iotable_init(omap7xx_io_desc, ARRAY_SIZE(omap7xx_io_desc));
        }
 #endif
-
 #ifdef CONFIG_ARCH_OMAP15XX
        if (cpu_is_omap15xx()) {
                iotable_init(omap1510_io_desc, ARRAY_SIZE(omap1510_io_desc));
index de03c84..db913c3 100644 (file)
@@ -46,7 +46,7 @@
 #include <asm/irq.h>
 #include <asm/mach/irq.h>
 #include <mach/gpio.h>
-#include <mach/cpu.h>
+#include <plat/cpu.h>
 
 #define IRQ_BANK(irq) ((irq) >> 5)
 #define IRQ_BIT(irq)  ((irq) & 0x1f)
@@ -137,16 +137,8 @@ static void omap_irq_set_cfg(int irq, int fiq, int priority, int trigger)
        irq_bank_writel(val, bank, offset);
 }
 
-#ifdef CONFIG_ARCH_OMAP730
-static struct omap_irq_bank omap730_irq_banks[] = {
-       { .base_reg = OMAP_IH1_BASE,            .trigger_map = 0xb3f8e22f },
-       { .base_reg = OMAP_IH2_BASE,            .trigger_map = 0xfdb9c1f2 },
-       { .base_reg = OMAP_IH2_BASE + 0x100,    .trigger_map = 0x800040f3 },
-};
-#endif
-
-#ifdef CONFIG_ARCH_OMAP850
-static struct omap_irq_bank omap850_irq_banks[] = {
+#if defined (CONFIG_ARCH_OMAP730) || defined (CONFIG_ARCH_OMAP850)
+static struct omap_irq_bank omap7xx_irq_banks[] = {
        { .base_reg = OMAP_IH1_BASE,            .trigger_map = 0xb3f8e22f },
        { .base_reg = OMAP_IH2_BASE,            .trigger_map = 0xfdb9c1f2 },
        { .base_reg = OMAP_IH2_BASE + 0x100,    .trigger_map = 0x800040f3 },
@@ -186,16 +178,10 @@ void __init omap_init_irq(void)
 {
        int i, j;
 
-#ifdef CONFIG_ARCH_OMAP730
-       if (cpu_is_omap730()) {
-               irq_banks = omap730_irq_banks;
-               irq_bank_count = ARRAY_SIZE(omap730_irq_banks);
-       }
-#endif
-#ifdef CONFIG_ARCH_OMAP850
-       if (cpu_is_omap850()) {
-               irq_banks = omap850_irq_banks;
-               irq_bank_count = ARRAY_SIZE(omap850_irq_banks);
+#if defined(CONFIG_ARCH_OMAP730) || defined(CONFIG_ARCH_OMAP850)
+       if (cpu_is_omap7xx()) {
+               irq_banks = omap7xx_irq_banks;
+               irq_bank_count = ARRAY_SIZE(omap7xx_irq_banks);
        }
 #endif
 #ifdef CONFIG_ARCH_OMAP15XX
@@ -247,10 +233,8 @@ void __init omap_init_irq(void)
 
        /* Unmask level 2 handler */
 
-       if (cpu_is_omap730())
-               omap_unmask_irq(INT_730_IH2_IRQ);
-       else if (cpu_is_omap850())
-               omap_unmask_irq(INT_850_IH2_IRQ);
+       if (cpu_is_omap7xx())
+               omap_unmask_irq(INT_7XX_IH2_IRQ);
        else if (cpu_is_omap15xx())
                omap_unmask_irq(INT_1510_IH2_IRQ);
        else if (cpu_is_omap16xx())
index 17c9d0e..b4f9be5 100644 (file)
@@ -19,7 +19,7 @@
 #include <asm/system.h>
 #include <asm/mach-types.h>
 
-#include <mach/fpga.h>
+#include <plat/fpga.h>
 #include <mach/gpio.h>
 
 #include "leds.h"
index 8cbf256..277f356 100644 (file)
@@ -10,7 +10,7 @@
 #include <asm/mach-types.h>
 
 #include <mach/gpio.h>
-#include <mach/mux.h>
+#include <plat/mux.h>
 
 #include "leds.h"
 
index 6810b4a..caf889a 100644 (file)
@@ -14,7 +14,7 @@
 #include <linux/interrupt.h>
 #include <linux/platform_device.h>
 #include <linux/io.h>
-#include <mach/mailbox.h>
+#include <plat/mailbox.h>
 #include <mach/irqs.h>
 
 #define MAILBOX_ARM2DSP1               0x00
index 505d98c..6bddce1 100644 (file)
 #include <linux/platform_device.h>
 
 #include <mach/irqs.h>
-#include <mach/dma.h>
-#include <mach/mux.h>
-#include <mach/cpu.h>
-#include <mach/mcbsp.h>
-#include <mach/dsp_common.h>
+#include <plat/dma.h>
+#include <plat/mux.h>
+#include <plat/cpu.h>
+#include <plat/mcbsp.h>
+#include <plat/dsp_common.h>
 
 #define DPS_RSTCT2_PER_EN      (1 << 0)
 #define DSP_RSTCT2_WD_PER_EN   (1 << 1)
@@ -79,29 +79,29 @@ static struct omap_mcbsp_ops omap1_mcbsp_ops = {
        .free           = omap1_mcbsp_free,
 };
 
-#ifdef CONFIG_ARCH_OMAP730
-static struct omap_mcbsp_platform_data omap730_mcbsp_pdata[] = {
+#if defined(CONFIG_ARCH_OMAP730) || defined(CONFIG_ARCH_OMAP850)
+static struct omap_mcbsp_platform_data omap7xx_mcbsp_pdata[] = {
        {
-               .phys_base      = OMAP730_MCBSP1_BASE,
+               .phys_base      = OMAP7XX_MCBSP1_BASE,
                .dma_rx_sync    = OMAP_DMA_MCBSP1_RX,
                .dma_tx_sync    = OMAP_DMA_MCBSP1_TX,
-               .rx_irq         = INT_730_McBSP1RX,
-               .tx_irq         = INT_730_McBSP1TX,
+               .rx_irq         = INT_7XX_McBSP1RX,
+               .tx_irq         = INT_7XX_McBSP1TX,
                .ops            = &omap1_mcbsp_ops,
        },
        {
-               .phys_base      = OMAP730_MCBSP2_BASE,
+               .phys_base      = OMAP7XX_MCBSP2_BASE,
                .dma_rx_sync    = OMAP_DMA_MCBSP3_RX,
                .dma_tx_sync    = OMAP_DMA_MCBSP3_TX,
-               .rx_irq         = INT_730_McBSP2RX,
-               .tx_irq         = INT_730_McBSP2TX,
+               .rx_irq         = INT_7XX_McBSP2RX,
+               .tx_irq         = INT_7XX_McBSP2TX,
                .ops            = &omap1_mcbsp_ops,
        },
 };
-#define OMAP730_MCBSP_PDATA_SZ         ARRAY_SIZE(omap730_mcbsp_pdata)
+#define OMAP7XX_MCBSP_PDATA_SZ         ARRAY_SIZE(omap7xx_mcbsp_pdata)
 #else
-#define omap730_mcbsp_pdata            NULL
-#define OMAP730_MCBSP_PDATA_SZ         0
+#define omap7xx_mcbsp_pdata            NULL
+#define OMAP7XX_MCBSP_PDATA_SZ         0
 #endif
 
 #ifdef CONFIG_ARCH_OMAP15XX
@@ -172,8 +172,8 @@ static struct omap_mcbsp_platform_data omap16xx_mcbsp_pdata[] = {
 
 int __init omap1_mcbsp_init(void)
 {
-       if (cpu_is_omap730())
-               omap_mcbsp_count = OMAP730_MCBSP_PDATA_SZ;
+       if (cpu_is_omap7xx())
+               omap_mcbsp_count = OMAP7XX_MCBSP_PDATA_SZ;
        if (cpu_is_omap15xx())
                omap_mcbsp_count = OMAP15XX_MCBSP_PDATA_SZ;
        if (cpu_is_omap16xx())
@@ -184,9 +184,9 @@ int __init omap1_mcbsp_init(void)
        if (!mcbsp_ptr)
                return -ENOMEM;
 
-       if (cpu_is_omap730())
-               omap_mcbsp_register_board_cfg(omap730_mcbsp_pdata,
-                                               OMAP730_MCBSP_PDATA_SZ);
+       if (cpu_is_omap7xx())
+               omap_mcbsp_register_board_cfg(omap7xx_mcbsp_pdata,
+                                               OMAP7XX_MCBSP_PDATA_SZ);
 
        if (cpu_is_omap15xx())
                omap_mcbsp_register_board_cfg(omap15xx_mcbsp_pdata,
index 721e0d9..785371e 100644 (file)
 
 #include <asm/system.h>
 
-#include <mach/mux.h>
+#include <plat/mux.h>
 
 #ifdef CONFIG_OMAP_MUX
 
 static struct omap_mux_cfg arch_mux_cfg;
 
-#ifdef CONFIG_ARCH_OMAP730
-static struct pin_config __initdata_or_module omap730_pins[] = {
-MUX_CFG_730("E2_730_KBR0",        12,   21,    0,   20,   1, 0)
-MUX_CFG_730("J7_730_KBR1",        12,   25,    0,   24,   1, 0)
-MUX_CFG_730("E1_730_KBR2",        12,   29,    0,   28,   1, 0)
-MUX_CFG_730("F3_730_KBR3",        13,    1,    0,    0,   1, 0)
-MUX_CFG_730("D2_730_KBR4",        13,    5,    0,    4,   1, 0)
-MUX_CFG_730("C2_730_KBC0",        13,    9,    0,    8,   1, 0)
-MUX_CFG_730("D3_730_KBC1",        13,   13,    0,   12,   1, 0)
-MUX_CFG_730("E4_730_KBC2",        13,   17,    0,   16,   1, 0)
-MUX_CFG_730("F4_730_KBC3",        13,   21,    0,   20,   1, 0)
-MUX_CFG_730("E3_730_KBC4",        13,   25,    0,   24,   1, 0)
-
-MUX_CFG_730("AA17_730_USB_DM",     2,   21,    0,   20,   0, 0)
-MUX_CFG_730("W16_730_USB_PU_EN",   2,   25,    0,   24,   0, 0)
-MUX_CFG_730("W17_730_USB_VBUSI",   2,   29,    0,   28,   0, 0)
+#if defined(CONFIG_ARCH_OMAP730) || defined(CONFIG_ARCH_OMAP850)
+static struct pin_config __initdata_or_module omap7xx_pins[] = {
+MUX_CFG_7XX("E2_7XX_KBR0",        12,   21,    0,   20,   1, 0)
+MUX_CFG_7XX("J7_7XX_KBR1",        12,   25,    0,   24,   1, 0)
+MUX_CFG_7XX("E1_7XX_KBR2",        12,   29,    0,   28,   1, 0)
+MUX_CFG_7XX("F3_7XX_KBR3",        13,    1,    0,    0,   1, 0)
+MUX_CFG_7XX("D2_7XX_KBR4",        13,    5,    0,    4,   1, 0)
+MUX_CFG_7XX("C2_7XX_KBC0",        13,    9,    0,    8,   1, 0)
+MUX_CFG_7XX("D3_7XX_KBC1",        13,   13,    0,   12,   1, 0)
+MUX_CFG_7XX("E4_7XX_KBC2",        13,   17,    0,   16,   1, 0)
+MUX_CFG_7XX("F4_7XX_KBC3",        13,   21,    0,   20,   1, 0)
+MUX_CFG_7XX("E3_7XX_KBC4",        13,   25,    0,   24,   1, 0)
+
+MUX_CFG_7XX("AA17_7XX_USB_DM",     2,   21,    0,   20,   0, 0)
+MUX_CFG_7XX("W16_7XX_USB_PU_EN",   2,   25,    0,   24,   0, 0)
+MUX_CFG_7XX("W17_7XX_USB_VBUSI",   2,   29,    0,   28,   0, 0)
+
+/* MMC Pins */
+MUX_CFG_7XX("MMC_7XX_CMD",         2,    9,    0,    8,   1, 0)
+MUX_CFG_7XX("MMC_7XX_CLK",         2,   13,    0,   12,   1, 0)
+MUX_CFG_7XX("MMC_7XX_DAT0",        2,   17,    0,   16,   1, 0)
 };
-#define OMAP730_PINS_SZ                ARRAY_SIZE(omap730_pins)
+#define OMAP7XX_PINS_SZ                ARRAY_SIZE(omap7xx_pins)
 #else
-#define omap730_pins           NULL
-#define OMAP730_PINS_SZ                0
-#endif /* CONFIG_ARCH_OMAP730 */
-
-#ifdef CONFIG_ARCH_OMAP850
-struct pin_config __initdata_or_module omap850_pins[] = {
-MUX_CFG_850("E2_850_KBR0",        12,   21,    0,   20,   1, 0)
-MUX_CFG_850("J7_850_KBR1",        12,   25,    0,   24,   1, 0)
-MUX_CFG_850("E1_850_KBR2",        12,   29,    0,   28,   1, 0)
-MUX_CFG_850("F3_850_KBR3",        13,    1,    0,    0,   1, 0)
-MUX_CFG_850("D2_850_KBR4",        13,    5,    0,    4,   1, 0)
-MUX_CFG_850("C2_850_KBC0",        13,    9,    0,    8,   1, 0)
-MUX_CFG_850("D3_850_KBC1",        13,   13,    0,   12,   1, 0)
-MUX_CFG_850("E4_850_KBC2",        13,   17,    0,   16,   1, 0)
-MUX_CFG_850("F4_850_KBC3",        13,   21,    0,   20,   1, 0)
-MUX_CFG_850("E3_850_KBC4",        13,   25,    0,   24,   1, 0)
-
-MUX_CFG_850("AA17_850_USB_DM",     2,   21,    0,   20,   0, 0)
-MUX_CFG_850("W16_850_USB_PU_EN",   2,   25,    0,   24,   0, 0)
-MUX_CFG_850("W17_850_USB_VBUSI",   2,   29,    0,   28,   0, 0)
-};
-#endif
+#define omap7xx_pins           NULL
+#define OMAP7XX_PINS_SZ                0
+#endif /* CONFIG_ARCH_OMAP730 || CONFIG_ARCH_OMAP850 */
 
 #if defined(CONFIG_ARCH_OMAP15XX) || defined(CONFIG_ARCH_OMAP16XX)
 static struct pin_config __initdata_or_module omap1xxx_pins[] = {
@@ -438,11 +424,6 @@ int __init_or_module omap1_cfg_reg(const struct pin_config *cfg)
                        printk("      %s (0x%08x) = 0x%08x -> 0x%08x\n",
                               cfg->pull_name, cfg->pull_reg, pull_orig, pull);
        }
-
-#ifdef CONFIG_ARCH_OMAP850
-       omap_mux_register(omap850_pins, ARRAY_SIZE(omap850_pins));
-#endif
-
 #endif
 
 #ifdef CONFIG_OMAP_MUX_ERRORS
@@ -454,9 +435,9 @@ int __init_or_module omap1_cfg_reg(const struct pin_config *cfg)
 
 int __init omap1_mux_init(void)
 {
-       if (cpu_is_omap730()) {
-               arch_mux_cfg.pins       = omap730_pins;
-               arch_mux_cfg.size       = OMAP730_PINS_SZ;
+       if (cpu_is_omap7xx()) {
+               arch_mux_cfg.pins       = omap7xx_pins;
+               arch_mux_cfg.size       = OMAP7XX_PINS_SZ;
                arch_mux_cfg.cfg_reg    = omap1_cfg_reg;
        }
 
index 5218943..b1d3f9f 100644 (file)
 #include <asm/mach/time.h>
 #include <asm/mach/irq.h>
 
-#include <mach/cpu.h>
+#include <plat/cpu.h>
 #include <mach/irqs.h>
-#include <mach/clock.h>
-#include <mach/sram.h>
-#include <mach/tc.h>
-#include <mach/mux.h>
-#include <mach/dma.h>
-#include <mach/dmtimer.h>
+#include <plat/clock.h>
+#include <plat/sram.h>
+#include <plat/tc.h>
+#include <plat/mux.h>
+#include <plat/dma.h>
+#include <plat/dmtimer.h>
 
 #include "pm.h"
 
 static unsigned int arm_sleep_save[ARM_SLEEP_SAVE_SIZE];
 static unsigned short dsp_sleep_save[DSP_SLEEP_SAVE_SIZE];
 static unsigned short ulpd_sleep_save[ULPD_SLEEP_SAVE_SIZE];
-static unsigned int mpui730_sleep_save[MPUI730_SLEEP_SAVE_SIZE];
+static unsigned int mpui7xx_sleep_save[MPUI7XX_SLEEP_SAVE_SIZE];
 static unsigned int mpui1510_sleep_save[MPUI1510_SLEEP_SAVE_SIZE];
 static unsigned int mpui1610_sleep_save[MPUI1610_SLEEP_SAVE_SIZE];
 
@@ -183,9 +183,9 @@ static void omap_pm_wakeup_setup(void)
         * drivers must still separately call omap_set_gpio_wakeup() to
         * wake up to a GPIO interrupt.
         */
-       if (cpu_is_omap730())
-               level1_wake = OMAP_IRQ_BIT(INT_730_GPIO_BANK1) |
-                       OMAP_IRQ_BIT(INT_730_IH2_IRQ);
+       if (cpu_is_omap7xx())
+               level1_wake = OMAP_IRQ_BIT(INT_7XX_GPIO_BANK1) |
+                       OMAP_IRQ_BIT(INT_7XX_IH2_IRQ);
        else if (cpu_is_omap15xx())
                level1_wake = OMAP_IRQ_BIT(INT_GPIO_BANK1) |
                        OMAP_IRQ_BIT(INT_1510_IH2_IRQ);
@@ -195,10 +195,10 @@ static void omap_pm_wakeup_setup(void)
 
        omap_writel(~level1_wake, OMAP_IH1_MIR);
 
-       if (cpu_is_omap730()) {
+       if (cpu_is_omap7xx()) {
                omap_writel(~level2_wake, OMAP_IH2_0_MIR);
-               omap_writel(~(OMAP_IRQ_BIT(INT_730_WAKE_UP_REQ) |
-                               OMAP_IRQ_BIT(INT_730_MPUIO_KEYPAD)),
+               omap_writel(~(OMAP_IRQ_BIT(INT_7XX_WAKE_UP_REQ) |
+                               OMAP_IRQ_BIT(INT_7XX_MPUIO_KEYPAD)),
                                OMAP_IH2_1_MIR);
        } else if (cpu_is_omap15xx()) {
                level2_wake |= OMAP_IRQ_BIT(INT_KEYBOARD);
@@ -253,15 +253,15 @@ void omap1_pm_suspend(void)
         * Save interrupt, MPUI, ARM and UPLD control registers.
         */
 
-       if (cpu_is_omap730()) {
-               MPUI730_SAVE(OMAP_IH1_MIR);
-               MPUI730_SAVE(OMAP_IH2_0_MIR);
-               MPUI730_SAVE(OMAP_IH2_1_MIR);
-               MPUI730_SAVE(MPUI_CTRL);
-               MPUI730_SAVE(MPUI_DSP_BOOT_CONFIG);
-               MPUI730_SAVE(MPUI_DSP_API_CONFIG);
-               MPUI730_SAVE(EMIFS_CONFIG);
-               MPUI730_SAVE(EMIFF_SDRAM_CONFIG);
+       if (cpu_is_omap7xx()) {
+               MPUI7XX_SAVE(OMAP_IH1_MIR);
+               MPUI7XX_SAVE(OMAP_IH2_0_MIR);
+               MPUI7XX_SAVE(OMAP_IH2_1_MIR);
+               MPUI7XX_SAVE(MPUI_CTRL);
+               MPUI7XX_SAVE(MPUI_DSP_BOOT_CONFIG);
+               MPUI7XX_SAVE(MPUI_DSP_API_CONFIG);
+               MPUI7XX_SAVE(EMIFS_CONFIG);
+               MPUI7XX_SAVE(EMIFF_SDRAM_CONFIG);
 
        } else if (cpu_is_omap15xx()) {
                MPUI1510_SAVE(OMAP_IH1_MIR);
@@ -306,7 +306,7 @@ void omap1_pm_suspend(void)
        omap_writew(omap_readw(ARM_RSTCT1) & ~(1 << DSP_EN), ARM_RSTCT1);
 
                /* shut down dsp_ck */
-       if (!cpu_is_omap730())
+       if (!cpu_is_omap7xx())
                omap_writew(omap_readw(ARM_CKCTL) & ~(1 << EN_DSPCK), ARM_CKCTL);
 
        /* temporarily enabling api_ck to access DSP registers */
@@ -383,12 +383,12 @@ void omap1_pm_suspend(void)
        ULPD_RESTORE(ULPD_CLOCK_CTRL);
        ULPD_RESTORE(ULPD_STATUS_REQ);
 
-       if (cpu_is_omap730()) {
-               MPUI730_RESTORE(EMIFS_CONFIG);
-               MPUI730_RESTORE(EMIFF_SDRAM_CONFIG);
-               MPUI730_RESTORE(OMAP_IH1_MIR);
-               MPUI730_RESTORE(OMAP_IH2_0_MIR);
-               MPUI730_RESTORE(OMAP_IH2_1_MIR);
+       if (cpu_is_omap7xx()) {
+               MPUI7XX_RESTORE(EMIFS_CONFIG);
+               MPUI7XX_RESTORE(EMIFF_SDRAM_CONFIG);
+               MPUI7XX_RESTORE(OMAP_IH1_MIR);
+               MPUI7XX_RESTORE(OMAP_IH2_0_MIR);
+               MPUI7XX_RESTORE(OMAP_IH2_1_MIR);
        } else if (cpu_is_omap15xx()) {
                MPUI1510_RESTORE(MPUI_CTRL);
                MPUI1510_RESTORE(MPUI_DSP_BOOT_CONFIG);
@@ -461,13 +461,13 @@ static int omap_pm_read_proc(
        ULPD_SAVE(ULPD_DPLL_CTRL);
        ULPD_SAVE(ULPD_POWER_CTRL);
 
-       if (cpu_is_omap730()) {
-               MPUI730_SAVE(MPUI_CTRL);
-               MPUI730_SAVE(MPUI_DSP_STATUS);
-               MPUI730_SAVE(MPUI_DSP_BOOT_CONFIG);
-               MPUI730_SAVE(MPUI_DSP_API_CONFIG);
-               MPUI730_SAVE(EMIFF_SDRAM_CONFIG);
-               MPUI730_SAVE(EMIFS_CONFIG);
+       if (cpu_is_omap7xx()) {
+               MPUI7XX_SAVE(MPUI_CTRL);
+               MPUI7XX_SAVE(MPUI_DSP_STATUS);
+               MPUI7XX_SAVE(MPUI_DSP_BOOT_CONFIG);
+               MPUI7XX_SAVE(MPUI_DSP_API_CONFIG);
+               MPUI7XX_SAVE(EMIFF_SDRAM_CONFIG);
+               MPUI7XX_SAVE(EMIFS_CONFIG);
        } else if (cpu_is_omap15xx()) {
                MPUI1510_SAVE(MPUI_CTRL);
                MPUI1510_SAVE(MPUI_DSP_STATUS);
@@ -517,20 +517,20 @@ static int omap_pm_read_proc(
                   ULPD_SHOW(ULPD_STATUS_REQ),
                   ULPD_SHOW(ULPD_POWER_CTRL));
 
-               if (cpu_is_omap730()) {
+               if (cpu_is_omap7xx()) {
                        my_buffer_offset += sprintf(my_base + my_buffer_offset,
-                          "MPUI730_CTRL_REG         0x%-8x \n"
-                          "MPUI730_DSP_STATUS_REG:      0x%-8x \n"
-                          "MPUI730_DSP_BOOT_CONFIG_REG: 0x%-8x \n"
-                          "MPUI730_DSP_API_CONFIG_REG:  0x%-8x \n"
-                          "MPUI730_SDRAM_CONFIG_REG:    0x%-8x \n"
-                          "MPUI730_EMIFS_CONFIG_REG:    0x%-8x \n",
-                          MPUI730_SHOW(MPUI_CTRL),
-                          MPUI730_SHOW(MPUI_DSP_STATUS),
-                          MPUI730_SHOW(MPUI_DSP_BOOT_CONFIG),
-                          MPUI730_SHOW(MPUI_DSP_API_CONFIG),
-                          MPUI730_SHOW(EMIFF_SDRAM_CONFIG),
-                          MPUI730_SHOW(EMIFS_CONFIG));
+                          "MPUI7XX_CTRL_REG         0x%-8x \n"
+                          "MPUI7XX_DSP_STATUS_REG:      0x%-8x \n"
+                          "MPUI7XX_DSP_BOOT_CONFIG_REG: 0x%-8x \n"
+                          "MPUI7XX_DSP_API_CONFIG_REG:  0x%-8x \n"
+                          "MPUI7XX_SDRAM_CONFIG_REG:    0x%-8x \n"
+                          "MPUI7XX_EMIFS_CONFIG_REG:    0x%-8x \n",
+                          MPUI7XX_SHOW(MPUI_CTRL),
+                          MPUI7XX_SHOW(MPUI_DSP_STATUS),
+                          MPUI7XX_SHOW(MPUI_DSP_BOOT_CONFIG),
+                          MPUI7XX_SHOW(MPUI_DSP_API_CONFIG),
+                          MPUI7XX_SHOW(EMIFF_SDRAM_CONFIG),
+                          MPUI7XX_SHOW(EMIFS_CONFIG));
                } else if (cpu_is_omap15xx()) {
                        my_buffer_offset += sprintf(my_base + my_buffer_offset,
                           "MPUI1510_CTRL_REG             0x%-8x \n"
@@ -668,9 +668,9 @@ static int __init omap_pm_init(void)
         * These routines need to be in SRAM as that's the only
         * memory the MPU can see when it wakes up.
         */
-       if (cpu_is_omap730()) {
-               omap_sram_suspend = omap_sram_push(omap730_cpu_suspend,
-                                                  omap730_cpu_suspend_sz);
+       if (cpu_is_omap7xx()) {
+               omap_sram_suspend = omap_sram_push(omap7xx_cpu_suspend,
+                                                  omap7xx_cpu_suspend_sz);
        } else if (cpu_is_omap15xx()) {
                omap_sram_suspend = omap_sram_push(omap1510_cpu_suspend,
                                                   omap1510_cpu_suspend_sz);
@@ -686,8 +686,8 @@ static int __init omap_pm_init(void)
 
        pm_idle = omap1_pm_idle;
 
-       if (cpu_is_omap730())
-               setup_irq(INT_730_WAKE_UP_REQ, &omap_wakeup_irq);
+       if (cpu_is_omap7xx())
+               setup_irq(INT_7XX_WAKE_UP_REQ, &omap_wakeup_irq);
        else if (cpu_is_omap16xx())
                setup_irq(INT_1610_WAKE_UP_REQ, &omap_wakeup_irq);
 
@@ -700,8 +700,8 @@ static int __init omap_pm_init(void)
        omap_writew(ULPD_POWER_CTRL_REG_VAL, ULPD_POWER_CTRL);
 
        /* Configure IDLECT3 */
-       if (cpu_is_omap730())
-               omap_writel(OMAP730_IDLECT3_VAL, OMAP730_IDLECT3);
+       if (cpu_is_omap7xx())
+               omap_writel(OMAP7XX_IDLECT3_VAL, OMAP7XX_IDLECT3);
        else if (cpu_is_omap16xx())
                omap_writel(OMAP1610_IDLECT3_VAL, OMAP1610_IDLECT3);
 
index c4f05bd..56a6479 100644 (file)
 #define OMAP1610_IDLECT3               0xfffece24
 #define OMAP1610_IDLE_LOOP_REQUEST     0x0400
 
-#define OMAP730_IDLECT1_SLEEP_VAL      0x16c7
-#define OMAP730_IDLECT2_SLEEP_VAL      0x09c7
-#define OMAP730_IDLECT3_VAL            0x3f
-#define OMAP730_IDLECT3                0xfffece24
-#define OMAP730_IDLE_LOOP_REQUEST      0x0C00
+#define OMAP7XX_IDLECT1_SLEEP_VAL      0x16c7
+#define OMAP7XX_IDLECT2_SLEEP_VAL      0x09c7
+#define OMAP7XX_IDLECT3_VAL            0x3f
+#define OMAP7XX_IDLECT3                0xfffece24
+#define OMAP7XX_IDLE_LOOP_REQUEST      0x0C00
 
 #if     !defined(CONFIG_ARCH_OMAP730) && \
+       !defined(CONFIG_ARCH_OMAP850) && \
        !defined(CONFIG_ARCH_OMAP15XX) && \
        !defined(CONFIG_ARCH_OMAP16XX)
 #warning "Power management for this processor not implemented yet"
@@ -122,17 +123,17 @@ extern void allow_idle_sleep(void);
 extern void omap1_pm_idle(void);
 extern void omap1_pm_suspend(void);
 
-extern void omap730_cpu_suspend(unsigned short, unsigned short);
+extern void omap7xx_cpu_suspend(unsigned short, unsigned short);
 extern void omap1510_cpu_suspend(unsigned short, unsigned short);
 extern void omap1610_cpu_suspend(unsigned short, unsigned short);
-extern void omap730_idle_loop_suspend(void);
+extern void omap7xx_idle_loop_suspend(void);
 extern void omap1510_idle_loop_suspend(void);
 extern void omap1610_idle_loop_suspend(void);
 
-extern unsigned int omap730_cpu_suspend_sz;
+extern unsigned int omap7xx_cpu_suspend_sz;
 extern unsigned int omap1510_cpu_suspend_sz;
 extern unsigned int omap1610_cpu_suspend_sz;
-extern unsigned int omap730_idle_loop_suspend_sz;
+extern unsigned int omap7xx_idle_loop_suspend_sz;
 extern unsigned int omap1510_idle_loop_suspend_sz;
 extern unsigned int omap1610_idle_loop_suspend_sz;
 
@@ -155,9 +156,9 @@ extern void omap_serial_wake_trigger(int enable);
 #define ULPD_RESTORE(x) omap_writew((ulpd_sleep_save[ULPD_SLEEP_SAVE_##x]), (x))
 #define ULPD_SHOW(x) ulpd_sleep_save[ULPD_SLEEP_SAVE_##x]
 
-#define MPUI730_SAVE(x) mpui730_sleep_save[MPUI730_SLEEP_SAVE_##x] = omap_readl(x)
-#define MPUI730_RESTORE(x) omap_writel((mpui730_sleep_save[MPUI730_SLEEP_SAVE_##x]), (x))
-#define MPUI730_SHOW(x) mpui730_sleep_save[MPUI730_SLEEP_SAVE_##x]
+#define MPUI7XX_SAVE(x) mpui7xx_sleep_save[MPUI7XX_SLEEP_SAVE_##x] = omap_readl(x)
+#define MPUI7XX_RESTORE(x) omap_writel((mpui7xx_sleep_save[MPUI7XX_SLEEP_SAVE_##x]), (x))
+#define MPUI7XX_SHOW(x) mpui7xx_sleep_save[MPUI7XX_SLEEP_SAVE_##x]
 
 #define MPUI1510_SAVE(x) mpui1510_sleep_save[MPUI1510_SLEEP_SAVE_##x] = omap_readl(x)
 #define MPUI1510_RESTORE(x) omap_writel((mpui1510_sleep_save[MPUI1510_SLEEP_SAVE_##x]), (x))
@@ -232,24 +233,24 @@ enum mpui1510_save_state {
 #endif
 };
 
-enum mpui730_save_state {
-       MPUI730_SLEEP_SAVE_START = 0,
+enum mpui7xx_save_state {
+       MPUI7XX_SLEEP_SAVE_START = 0,
        /*
         * MPUI registers 32 bits
         */
-       MPUI730_SLEEP_SAVE_MPUI_CTRL,
-       MPUI730_SLEEP_SAVE_MPUI_DSP_BOOT_CONFIG,
-       MPUI730_SLEEP_SAVE_MPUI_DSP_API_CONFIG,
-       MPUI730_SLEEP_SAVE_MPUI_DSP_STATUS,
-       MPUI730_SLEEP_SAVE_EMIFF_SDRAM_CONFIG,
-       MPUI730_SLEEP_SAVE_EMIFS_CONFIG,
-       MPUI730_SLEEP_SAVE_OMAP_IH1_MIR,
-       MPUI730_SLEEP_SAVE_OMAP_IH2_0_MIR,
-       MPUI730_SLEEP_SAVE_OMAP_IH2_1_MIR,
-#if defined(CONFIG_ARCH_OMAP730)
-       MPUI730_SLEEP_SAVE_SIZE
+       MPUI7XX_SLEEP_SAVE_MPUI_CTRL,
+       MPUI7XX_SLEEP_SAVE_MPUI_DSP_BOOT_CONFIG,
+       MPUI7XX_SLEEP_SAVE_MPUI_DSP_API_CONFIG,
+       MPUI7XX_SLEEP_SAVE_MPUI_DSP_STATUS,
+       MPUI7XX_SLEEP_SAVE_EMIFF_SDRAM_CONFIG,
+       MPUI7XX_SLEEP_SAVE_EMIFS_CONFIG,
+       MPUI7XX_SLEEP_SAVE_OMAP_IH1_MIR,
+       MPUI7XX_SLEEP_SAVE_OMAP_IH2_0_MIR,
+       MPUI7XX_SLEEP_SAVE_OMAP_IH2_1_MIR,
+#if defined(CONFIG_ARCH_OMAP730) || defined(CONFIG_ARCH_OMAP850)
+       MPUI7XX_SLEEP_SAVE_SIZE
 #else
-       MPUI730_SLEEP_SAVE_SIZE = 0
+       MPUI7XX_SLEEP_SAVE_SIZE = 0
 #endif
 };
 
index d23979b..6e5207c 100644 (file)
 
 #include <asm/mach-types.h>
 
-#include <mach/board.h>
-#include <mach/mux.h>
+#include <plat/board.h>
+#include <plat/mux.h>
 #include <mach/gpio.h>
-#include <mach/fpga.h>
+#include <plat/fpga.h>
 
 static struct clk * uart1_ck;
 static struct clk * uart2_ck;
@@ -64,7 +64,6 @@ static void __init omap_serial_reset(struct plat_serial8250_port *p)
 
 static struct plat_serial8250_port serial_platform_data[] = {
        {
-               .membase        = OMAP1_IO_ADDRESS(OMAP_UART1_BASE),
                .mapbase        = OMAP_UART1_BASE,
                .irq            = INT_UART1,
                .flags          = UPF_BOOT_AUTOCONF,
@@ -73,7 +72,6 @@ static struct plat_serial8250_port serial_platform_data[] = {
                .uartclk        = OMAP16XX_BASE_BAUD * 16,
        },
        {
-               .membase        = OMAP1_IO_ADDRESS(OMAP_UART2_BASE),
                .mapbase        = OMAP_UART2_BASE,
                .irq            = INT_UART2,
                .flags          = UPF_BOOT_AUTOCONF,
@@ -82,7 +80,6 @@ static struct plat_serial8250_port serial_platform_data[] = {
                .uartclk        = OMAP16XX_BASE_BAUD * 16,
        },
        {
-               .membase        = OMAP1_IO_ADDRESS(OMAP_UART3_BASE),
                .mapbase        = OMAP_UART3_BASE,
                .irq            = INT_UART3,
                .flags          = UPF_BOOT_AUTOCONF,
@@ -110,18 +107,11 @@ void __init omap_serial_init(void)
 {
        int i;
 
-       if (cpu_is_omap730()) {
+       if (cpu_is_omap7xx()) {
                serial_platform_data[0].regshift = 0;
                serial_platform_data[1].regshift = 0;
-               serial_platform_data[0].irq = INT_730_UART_MODEM_1;
-               serial_platform_data[1].irq = INT_730_UART_MODEM_IRDA_2;
-       }
-
-       if (cpu_is_omap850()) {
-               serial_platform_data[0].regshift = 0;
-               serial_platform_data[1].regshift = 0;
-               serial_platform_data[0].irq = INT_850_UART_MODEM_1;
-               serial_platform_data[1].irq = INT_850_UART_MODEM_IRDA_2;
+               serial_platform_data[0].irq = INT_7XX_UART_MODEM_1;
+               serial_platform_data[1].irq = INT_7XX_UART_MODEM_IRDA_2;
        }
 
        if (cpu_is_omap15xx()) {
@@ -130,7 +120,15 @@ void __init omap_serial_init(void)
                serial_platform_data[2].uartclk = OMAP1510_BASE_BAUD * 16;
        }
 
-       for (i = 0; i < OMAP_MAX_NR_PORTS; i++) {
+       for (i = 0; i < ARRAY_SIZE(serial_platform_data) - 1; i++) {
+
+               /* Static mapping, never released */
+               serial_platform_data[i].membase =
+                       ioremap(serial_platform_data[i].mapbase, SZ_2K);
+               if (!serial_platform_data[i].membase) {
+                       printk(KERN_ERR "Could not ioremap uart%i\n", i);
+                       continue;
+               }
                switch (i) {
                case 0:
                        uart1_ck = clk_get(NULL, "uart1_ck");
index 22e8568..ef771ce 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * linux/arch/arm/mach-omap1/sleep.S
  *
- * Low-level OMAP730/1510/1610 sleep/wakeUp support
+ * Low-level OMAP7XX/1510/1610 sleep/wakeUp support
  *
  * Initial SA1110 code:
  * Copyright (c) 2001 Cliff Brake <cbrake@accelent.com>
@@ -57,8 +57,8 @@
  *
  */
 
-#if defined(CONFIG_ARCH_OMAP730)
-ENTRY(omap730_cpu_suspend)
+#if defined(CONFIG_ARCH_OMAP730) || defined(CONFIG_ARCH_OMAP850)
+ENTRY(omap7xx_cpu_suspend)
 
        @ save registers on stack
        stmfd   sp!, {r0 - r12, lr}
@@ -91,13 +91,13 @@ ENTRY(omap730_cpu_suspend)
 
        @ turn off clock domains
        @ do not disable PERCK (0x04)
-       mov     r5, #OMAP730_IDLECT2_SLEEP_VAL & 0xff
-       orr     r5, r5, #OMAP730_IDLECT2_SLEEP_VAL & 0xff00
+       mov     r5, #OMAP7XX_IDLECT2_SLEEP_VAL & 0xff
+       orr     r5, r5, #OMAP7XX_IDLECT2_SLEEP_VAL & 0xff00
        strh    r5, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]
 
        @ request ARM idle
-       mov     r3, #OMAP730_IDLECT1_SLEEP_VAL & 0xff
-       orr     r3, r3, #OMAP730_IDLECT1_SLEEP_VAL & 0xff00
+       mov     r3, #OMAP7XX_IDLECT1_SLEEP_VAL & 0xff
+       orr     r3, r3, #OMAP7XX_IDLECT1_SLEEP_VAL & 0xff00
        strh    r3, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff]
 
        @ disable instruction cache
@@ -113,7 +113,7 @@ ENTRY(omap730_cpu_suspend)
        mov     r2, #0
        mcr     p15, 0, r2, c7, c0, 4           @ wait for interrupt
 /*
- * omap730_cpu_suspend()'s resume point.
+ * omap7xx_cpu_suspend()'s resume point.
  *
  * It will just start executing here, so we'll restore stuff from the
  * stack.
@@ -132,9 +132,9 @@ ENTRY(omap730_cpu_suspend)
        @ restore regs and return
        ldmfd   sp!, {r0 - r12, pc}
 
-ENTRY(omap730_cpu_suspend_sz)
-       .word   . - omap730_cpu_suspend
-#endif /* CONFIG_ARCH_OMAP730 */
+ENTRY(omap7xx_cpu_suspend_sz)
+       .word   . - omap7xx_cpu_suspend
+#endif /* CONFIG_ARCH_OMAP730 || CONFIG_ARCH_OMAP850 */
 
 #ifdef CONFIG_ARCH_OMAP15XX
 ENTRY(omap1510_cpu_suspend)
index fd3f739..9ad1185 100644 (file)
@@ -52,7 +52,7 @@
 #include <asm/irq.h>
 #include <asm/mach/irq.h>
 #include <asm/mach/time.h>
-#include <mach/dmtimer.h>
+#include <plat/dmtimer.h>
 
 struct sys_timer omap_timer;
 
index aad194f..7309aab 100644 (file)
@@ -65,6 +65,10 @@ config MACH_OMAP3EVM
        bool "OMAP 3530 EVM board"
        depends on ARCH_OMAP3 && ARCH_OMAP34XX
 
+config MACH_OMAP3517EVM
+       bool "OMAP3517/ AM3517 EVM board"
+       depends on ARCH_OMAP3 && ARCH_OMAP34XX
+
 config MACH_OMAP3_PANDORA
        bool "OMAP3 Pandora"
        depends on ARCH_OMAP3 && ARCH_OMAP34XX
@@ -97,6 +101,30 @@ config MACH_OMAP_ZOOM2
        bool "OMAP3 Zoom2 board"
        depends on ARCH_OMAP3 && ARCH_OMAP34XX
 
+config MACH_OMAP_ZOOM3
+       bool "OMAP3630 Zoom3 board"
+       depends on ARCH_OMAP3 && ARCH_OMAP34XX
+
+config MACH_CM_T35
+       bool "CompuLab CM-T35 module"
+       depends on ARCH_OMAP3 && ARCH_OMAP34XX
+
+config MACH_IGEP0020
+       bool "IGEP0020"
+       depends on ARCH_OMAP3 && ARCH_OMAP34XX
+
+config MACH_OMAP_3630SDP
+       bool "OMAP3630 SDP board"
+       depends on ARCH_OMAP3 && ARCH_OMAP34XX
+
 config MACH_OMAP_4430SDP
        bool "OMAP 4430 SDP board"
        depends on ARCH_OMAP4
+
+config OMAP3_EMU
+       bool "OMAP3 debugging peripherals"
+       depends on ARCH_OMAP3
+       select OC_ETM
+       help
+         Say Y here to enable debugging hardware of omap3
+
index 8cb1677..32548a4 100644 (file)
@@ -31,7 +31,7 @@ obj-$(CONFIG_ARCH_OMAP2)              += sdrc2xxx.o
 ifeq ($(CONFIG_PM),y)
 obj-$(CONFIG_ARCH_OMAP2)               += pm24xx.o
 obj-$(CONFIG_ARCH_OMAP24XX)            += sleep24xx.o
-obj-$(CONFIG_ARCH_OMAP3)               += pm34xx.o sleep34xx.o
+obj-$(CONFIG_ARCH_OMAP3)               += pm34xx.o sleep34xx.o cpuidle34xx.o
 obj-$(CONFIG_PM_DEBUG)                 += pm-debug.o
 endif
 
@@ -44,6 +44,12 @@ obj-$(CONFIG_ARCH_OMAP4)             += cm4xxx.o
 obj-$(CONFIG_ARCH_OMAP2)               += clock24xx.o
 obj-$(CONFIG_ARCH_OMAP3)               += clock34xx.o
 
+# EMU peripherals
+obj-$(CONFIG_OMAP3_EMU)                += emu.o
+
+obj-$(CONFIG_OMAP_MBOX_FWK)            += mailbox_mach.o
+mailbox_mach-objs                      := mailbox.o
+
 iommu-y                                        += iommu2.o
 iommu-$(CONFIG_ARCH_OMAP3)             += omap3-iommu.o
 
@@ -69,17 +75,33 @@ obj-$(CONFIG_MACH_OMAP_3430SDP)             += board-3430sdp.o \
                                           mmc-twl4030.o
 obj-$(CONFIG_MACH_NOKIA_N8X0)          += board-n8x0.o
 obj-$(CONFIG_MACH_NOKIA_RX51)          += board-rx51.o \
+                                          board-rx51-sdram.o \
                                           board-rx51-peripherals.o \
                                           mmc-twl4030.o
 obj-$(CONFIG_MACH_OMAP_ZOOM2)          += board-zoom2.o \
+                                          board-zoom-peripherals.o \
+                                          mmc-twl4030.o \
+                                          board-zoom-debugboard.o
+obj-$(CONFIG_MACH_OMAP_ZOOM3)          += board-zoom3.o \
+                                          board-zoom-peripherals.o \
                                           mmc-twl4030.o \
                                           board-zoom-debugboard.o
+obj-$(CONFIG_MACH_OMAP_3630SDP)                += board-3630sdp.o \
+                                          board-zoom-peripherals.o \
+                                          mmc-twl4030.o
+obj-$(CONFIG_MACH_CM_T35)              += board-cm-t35.o \
+                                          mmc-twl4030.o
+obj-$(CONFIG_MACH_IGEP0020)            += board-igep0020.o \
+                                          mmc-twl4030.o
 
 obj-$(CONFIG_MACH_OMAP_4430SDP)                += board-4430sdp.o
 
+obj-$(CONFIG_MACH_OMAP3517EVM)     += board-am3517evm.o
+
 # Platform specific device init code
 obj-y                                  += usb-musb.o
 obj-$(CONFIG_MACH_OMAP2_TUSB6010)      += usb-tusb6010.o
+obj-y                                  += usb-ehci.o
 
 onenand-$(CONFIG_MTD_ONENAND_OMAP2)    := gpmc-onenand.o
 obj-y                                  += $(onenand-m) $(onenand-y)
index 42217b3..db9374b 100644 (file)
 #include <asm/mach/flash.h>
 
 #include <mach/gpio.h>
-#include <mach/mux.h>
-#include <mach/board.h>
-#include <mach/common.h>
-#include <mach/gpmc.h>
-#include <mach/usb.h>
-#include <mach/gpmc-smc91x.h>
+#include <plat/mux.h>
+#include <plat/board.h>
+#include <plat/common.h>
+#include <plat/gpmc.h>
+#include <plat/usb.h>
+#include <plat/gpmc-smc91x.h>
 
 #include "mmc-twl4030.h"
 
@@ -221,7 +221,7 @@ static void __init omap_2430sdp_map_io(void)
 MACHINE_START(OMAP_2430SDP, "OMAP2430 sdp2430 board")
        /* Maintainer: Syed Khasim - Texas Instruments Inc */
        .phys_io        = 0x48000000,
-       .io_pg_offst    = ((0xd8000000) >> 18) & 0xfffc,
+       .io_pg_offst    = ((0xfa000000) >> 18) & 0xfffc,
        .boot_params    = 0x80000100,
        .map_io         = omap_2430sdp_map_io,
        .init_irq       = omap_2430sdp_init_irq,
index 0acb556..491364e 100644 (file)
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
 
-#include <mach/mcspi.h>
-#include <mach/mux.h>
-#include <mach/board.h>
-#include <mach/usb.h>
-#include <mach/common.h>
-#include <mach/dma.h>
-#include <mach/gpmc.h>
+#include <plat/mcspi.h>
+#include <plat/mux.h>
+#include <plat/board.h>
+#include <plat/usb.h>
+#include <plat/common.h>
+#include <plat/dma.h>
+#include <plat/gpmc.h>
 
-#include <mach/control.h>
-#include <mach/gpmc-smc91x.h>
+#include <plat/control.h>
+#include <plat/gpmc-smc91x.h>
 
 #include "sdram-qimonda-hyb18m512160af-6.h"
 #include "mmc-twl4030.h"
@@ -410,6 +410,15 @@ static struct regulator_init_data sdp3430_vpll2 = {
        .consumer_supplies      = &sdp3430_vdvi_supply,
 };
 
+static struct twl4030_codec_audio_data sdp3430_audio = {
+       .audio_mclk = 26000000,
+};
+
+static struct twl4030_codec_data sdp3430_codec = {
+       .audio_mclk = 26000000,
+       .audio = &sdp3430_audio,
+};
+
 static struct twl4030_platform_data sdp3430_twldata = {
        .irq_base       = TWL4030_IRQ_BASE,
        .irq_end        = TWL4030_IRQ_END,
@@ -420,6 +429,7 @@ static struct twl4030_platform_data sdp3430_twldata = {
        .madc           = &sdp3430_madc_data,
        .keypad         = &sdp3430_kp_data,
        .usb            = &sdp3430_usb_data,
+       .codec          = &sdp3430_codec,
 
        .vaux1          = &sdp3430_vaux1,
        .vaux2          = &sdp3430_vaux2,
@@ -484,6 +494,18 @@ static void enable_board_wakeup_source(void)
        omap_cfg_reg(AF26_34XX_SYS_NIRQ); /* T2 interrupt line (keypad) */
 }
 
+static struct ehci_hcd_omap_platform_data ehci_pdata __initconst = {
+
+       .port_mode[0] = EHCI_HCD_OMAP_MODE_PHY,
+       .port_mode[1] = EHCI_HCD_OMAP_MODE_PHY,
+       .port_mode[2] = EHCI_HCD_OMAP_MODE_UNKNOWN,
+
+       .phy_reset  = true,
+       .reset_gpio_port[0]  = 57,
+       .reset_gpio_port[1]  = 61,
+       .reset_gpio_port[2]  = -EINVAL
+};
+
 static void __init omap_3430sdp_init(void)
 {
        omap3430_i2c_init();
@@ -500,6 +522,7 @@ static void __init omap_3430sdp_init(void)
        usb_musb_init();
        board_smc91x_init();
        enable_board_wakeup_source();
+       usb_ehci_init(&ehci_pdata);
 }
 
 static void __init omap_3430sdp_map_io(void)
@@ -511,7 +534,7 @@ static void __init omap_3430sdp_map_io(void)
 MACHINE_START(OMAP_3430SDP, "OMAP3430 3430SDP board")
        /* Maintainer: Syed Khasim - Texas Instruments Inc */
        .phys_io        = 0x48000000,
-       .io_pg_offst    = ((0xd8000000) >> 18) & 0xfffc,
+       .io_pg_offst    = ((0xfa000000) >> 18) & 0xfffc,
        .boot_params    = 0x80000100,
        .map_io         = omap_3430sdp_map_io,
        .init_irq       = omap_3430sdp_init_irq,
diff --git a/arch/arm/mach-omap2/board-3630sdp.c b/arch/arm/mach-omap2/board-3630sdp.c
new file mode 100755 (executable)
index 0000000..348b70b
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2009 Texas Instruments Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/input.h>
+#include <linux/gpio.h>
+
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+
+#include <plat/common.h>
+#include <plat/board.h>
+#include <plat/gpmc-smc91x.h>
+#include <plat/mux.h>
+#include <plat/usb.h>
+
+#include <mach/board-zoom.h>
+
+#include "sdram-hynix-h8mbx00u0mer-0em.h"
+
+#if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE)
+
+static struct omap_smc91x_platform_data board_smc91x_data = {
+       .cs             = 3,
+       .flags          = GPMC_MUX_ADD_DATA | IORESOURCE_IRQ_LOWLEVEL,
+};
+
+static void __init board_smc91x_init(void)
+{
+       board_smc91x_data.gpio_irq = 158;
+       gpmc_smc91x_init(&board_smc91x_data);
+}
+
+#else
+
+static inline void board_smc91x_init(void)
+{
+}
+
+#endif /* defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE) */
+
+static void enable_board_wakeup_source(void)
+{
+       omap_cfg_reg(AF26_34XX_SYS_NIRQ); /* T2 interrupt line (keypad) */
+}
+
+static struct ehci_hcd_omap_platform_data ehci_pdata __initconst = {
+
+       .port_mode[0] = EHCI_HCD_OMAP_MODE_PHY,
+       .port_mode[1] = EHCI_HCD_OMAP_MODE_PHY,
+       .port_mode[2] = EHCI_HCD_OMAP_MODE_UNKNOWN,
+
+       .phy_reset  = true,
+       .reset_gpio_port[0]  = 126,
+       .reset_gpio_port[1]  = 61,
+       .reset_gpio_port[2]  = -EINVAL
+};
+
+static void __init omap_sdp_map_io(void)
+{
+       omap2_set_globals_343x();
+       omap2_map_common_io();
+}
+
+static struct omap_board_config_kernel sdp_config[] __initdata = {
+};
+
+static void __init omap_sdp_init_irq(void)
+{
+       omap_board_config = sdp_config;
+       omap_board_config_size = ARRAY_SIZE(sdp_config);
+       omap2_init_common_hw(h8mbx00u0mer0em_sdrc_params,
+                       h8mbx00u0mer0em_sdrc_params);
+       omap_init_irq();
+       omap_gpio_init();
+}
+
+static void __init omap_sdp_init(void)
+{
+       zoom_peripherals_init();
+       board_smc91x_init();
+       enable_board_wakeup_source();
+       usb_ehci_init(&ehci_pdata);
+}
+
+MACHINE_START(OMAP_3630SDP, "OMAP 3630SDP board")
+       .phys_io        = 0x48000000,
+       .io_pg_offst    = ((0xfa000000) >> 18) & 0xfffc,
+       .boot_params    = 0x80000100,
+       .map_io         = omap_sdp_map_io,
+       .init_irq       = omap_sdp_init_irq,
+       .init_machine   = omap_sdp_init,
+       .timer          = &omap_timer,
+MACHINE_END
index 609a5a4..0c6be6b 100644 (file)
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
 
-#include <mach/board.h>
-#include <mach/common.h>
-#include <mach/control.h>
-#include <mach/timer-gp.h>
+#include <plat/board.h>
+#include <plat/common.h>
+#include <plat/control.h>
+#include <plat/timer-gp.h>
 #include <asm/hardware/gic.h>
 
 static struct platform_device sdp4430_lcd_device = {
@@ -52,8 +52,17 @@ static struct omap_board_config_kernel sdp4430_config[] __initdata = {
 
 static void __init gic_init_irq(void)
 {
-       gic_dist_init(0, OMAP2_IO_ADDRESS(OMAP44XX_GIC_DIST_BASE), 29);
-       gic_cpu_init(0, OMAP2_IO_ADDRESS(OMAP44XX_GIC_CPU_BASE));
+       void __iomem *base;
+
+       /* Static mapping, never released */
+       base = ioremap(OMAP44XX_GIC_DIST_BASE, SZ_4K);
+       BUG_ON(!base);
+       gic_dist_init(0, base, 29);
+
+       /* Static mapping, never released */
+       gic_cpu_base_addr = ioremap(OMAP44XX_GIC_CPU_BASE, SZ_512);
+       BUG_ON(!gic_cpu_base_addr);
+       gic_cpu_init(0, gic_cpu_base_addr);
 }
 
 static void __init omap_4430sdp_init_irq(void)
@@ -84,7 +93,7 @@ static void __init omap_4430sdp_map_io(void)
 MACHINE_START(OMAP_4430SDP, "OMAP4430 4430SDP board")
        /* Maintainer: Santosh Shilimkar - Texas Instruments Inc */
        .phys_io        = 0x48000000,
-       .io_pg_offst    = ((0xd8000000) >> 18) & 0xfffc,
+       .io_pg_offst    = ((0xfa000000) >> 18) & 0xfffc,
        .boot_params    = 0x80000100,
        .map_io         = omap_4430sdp_map_io,
        .init_irq       = omap_4430sdp_init_irq,
diff --git a/arch/arm/mach-omap2/board-am3517evm.c b/arch/arm/mach-omap2/board-am3517evm.c
new file mode 100644 (file)
index 0000000..415a13d
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * linux/arch/arm/mach-omap2/board-am3517evm.c
+ *
+ * Copyright (C) 2009 Texas Instruments Incorporated
+ * Author: Ranjith Lohithakshan <ranjithl@ti.com>
+ *
+ * Based on mach-omap2/board-omap3evm.c
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as  published by the
+ * Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any kind,
+ * whether express or implied; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+
+#include <mach/hardware.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+
+#include <plat/board.h>
+#include <plat/common.h>
+#include <plat/usb.h>
+
+/*
+ * Board initialization
+ */
+static struct omap_board_config_kernel am3517_evm_config[] __initdata = {
+};
+
+static struct platform_device *am3517_evm_devices[] __initdata = {
+};
+
+static void __init am3517_evm_init_irq(void)
+{
+       omap_board_config = am3517_evm_config;
+       omap_board_config_size = ARRAY_SIZE(am3517_evm_config);
+
+       omap2_init_common_hw(NULL, NULL);
+       omap_init_irq();
+       omap_gpio_init();
+}
+
+static struct ehci_hcd_omap_platform_data ehci_pdata __initdata = {
+       .port_mode[0] = EHCI_HCD_OMAP_MODE_PHY,
+       .port_mode[1] = EHCI_HCD_OMAP_MODE_PHY,
+       .port_mode[2] = EHCI_HCD_OMAP_MODE_UNKNOWN,
+
+       .phy_reset  = true,
+       .reset_gpio_port[0]  = 57,
+       .reset_gpio_port[1]  = -EINVAL,
+       .reset_gpio_port[2]  = -EINVAL
+};
+
+static void __init am3517_evm_init(void)
+{
+       platform_add_devices(am3517_evm_devices,
+                               ARRAY_SIZE(am3517_evm_devices));
+
+       omap_serial_init();
+       usb_ehci_init(&ehci_pdata);
+}
+
+static void __init am3517_evm_map_io(void)
+{
+       omap2_set_globals_343x();
+       omap2_map_common_io();
+}
+
+MACHINE_START(OMAP3517EVM, "OMAP3517/AM3517 EVM")
+       .phys_io        = 0x48000000,
+       .io_pg_offst    = ((0xd8000000) >> 18) & 0xfffc,
+       .boot_params    = 0x80000100,
+       .map_io         = am3517_evm_map_io,
+       .init_irq       = am3517_evm_init_irq,
+       .init_machine   = am3517_evm_init,
+       .timer          = &omap_timer,
+MACHINE_END
index a113228..8a2ce77 100644 (file)
 #include <asm/mach/flash.h>
 
 #include <mach/gpio.h>
-#include <mach/led.h>
-#include <mach/mux.h>
-#include <mach/usb.h>
-#include <mach/board.h>
-#include <mach/common.h>
-#include <mach/gpmc.h>
-#include <mach/control.h>
+#include <plat/led.h>
+#include <plat/mux.h>
+#include <plat/usb.h>
+#include <plat/board.h>
+#include <plat/common.h>
+#include <plat/gpmc.h>
+#include <plat/control.h>
 
 /* LED & Switch macros */
 #define LED0_GPIO13            13
@@ -333,7 +333,7 @@ static void __init omap_apollon_map_io(void)
 MACHINE_START(OMAP_APOLLON, "OMAP24xx Apollon")
        /* Maintainer: Kyungmin Park <kyungmin.park@samsung.com> */
        .phys_io        = 0x48000000,
-       .io_pg_offst    = ((0xd8000000) >> 18) & 0xfffc,
+       .io_pg_offst    = ((0xfa000000) >> 18) & 0xfffc,
        .boot_params    = 0x80000100,
        .map_io         = omap_apollon_map_io,
        .init_irq       = omap_apollon_init_irq,
diff --git a/arch/arm/mach-omap2/board-cm-t35.c b/arch/arm/mach-omap2/board-cm-t35.c
new file mode 100644 (file)
index 0000000..22c4529
--- /dev/null
@@ -0,0 +1,507 @@
+/*
+ * board-cm-t35.c (CompuLab CM-T35 module)
+ *
+ * Copyright (C) 2009 CompuLab, Ltd.
+ * Author: Mike Rapoport <mike@compulab.co.il>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/input.h>
+#include <linux/input/matrix_keypad.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+
+#include <linux/i2c/at24.h>
+#include <linux/i2c/twl4030.h>
+#include <linux/regulator/machine.h>
+
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+
+#include <plat/board.h>
+#include <plat/common.h>
+#include <plat/mux.h>
+#include <plat/nand.h>
+#include <plat/gpmc.h>
+#include <plat/usb.h>
+
+#include <mach/hardware.h>
+
+#include "sdram-micron-mt46h32m32lf-6.h"
+#include "mmc-twl4030.h"
+
+#define CM_T35_GPIO_PENDOWN    57
+
+#define CM_T35_SMSC911X_CS     5
+#define CM_T35_SMSC911X_GPIO   163
+#define SB_T35_SMSC911X_CS     4
+#define SB_T35_SMSC911X_GPIO   65
+
+#define NAND_BLOCK_SIZE                SZ_128K
+#define GPMC_CS0_BASE          0x60
+#define GPMC_CS0_BASE_ADDR     (OMAP34XX_GPMC_VIRT + GPMC_CS0_BASE)
+
+#if defined(CONFIG_SMSC911X) || defined(CONFIG_SMSC911X_MODULE)
+#include <linux/smsc911x.h>
+
+static struct smsc911x_platform_config cm_t35_smsc911x_config = {
+       .irq_polarity   = SMSC911X_IRQ_POLARITY_ACTIVE_LOW,
+       .irq_type       = SMSC911X_IRQ_TYPE_OPEN_DRAIN,
+       .flags          = SMSC911X_USE_32BIT | SMSC911X_SAVE_MAC_ADDRESS,
+       .phy_interface  = PHY_INTERFACE_MODE_MII,
+};
+
+static struct resource cm_t35_smsc911x_resources[] = {
+       {
+               .flags  = IORESOURCE_MEM,
+       },
+       {
+               .start  = OMAP_GPIO_IRQ(CM_T35_SMSC911X_GPIO),
+               .end    = OMAP_GPIO_IRQ(CM_T35_SMSC911X_GPIO),
+               .flags  = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWLEVEL,
+       },
+};
+
+static struct platform_device cm_t35_smsc911x_device = {
+       .name           = "smsc911x",
+       .id             = 0,
+       .num_resources  = ARRAY_SIZE(cm_t35_smsc911x_resources),
+       .resource       = cm_t35_smsc911x_resources,
+       .dev            = {
+               .platform_data = &cm_t35_smsc911x_config,
+       },
+};
+
+static struct resource sb_t35_smsc911x_resources[] = {
+       {
+               .flags  = IORESOURCE_MEM,
+       },
+       {
+               .start  = OMAP_GPIO_IRQ(SB_T35_SMSC911X_GPIO),
+               .end    = OMAP_GPIO_IRQ(SB_T35_SMSC911X_GPIO),
+               .flags  = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWLEVEL,
+       },
+};
+
+static struct platform_device sb_t35_smsc911x_device = {
+       .name           = "smsc911x",
+       .id             = 1,
+       .num_resources  = ARRAY_SIZE(sb_t35_smsc911x_resources),
+       .resource       = sb_t35_smsc911x_resources,
+       .dev            = {
+               .platform_data = &cm_t35_smsc911x_config,
+       },
+};
+
+static void __init cm_t35_init_smsc911x(struct platform_device *dev,
+                                       int cs, int irq_gpio)
+{
+       unsigned long cs_mem_base;
+
+       if (gpmc_cs_request(cs, SZ_16M, &cs_mem_base) < 0) {
+               pr_err("CM-T35: Failed request for GPMC mem for smsc911x\n");
+               return;
+       }
+
+       dev->resource[0].start = cs_mem_base + 0x0;
+       dev->resource[0].end   = cs_mem_base + 0xff;
+
+       if ((gpio_request(irq_gpio, "ETH IRQ") == 0) &&
+           (gpio_direction_input(irq_gpio) == 0)) {
+               gpio_export(irq_gpio, 0);
+       } else {
+               pr_err("CM-T35: could not obtain gpio for SMSC911X IRQ\n");
+               return;
+       }
+
+       platform_device_register(dev);
+}
+
+static void __init cm_t35_init_ethernet(void)
+{
+       cm_t35_init_smsc911x(&cm_t35_smsc911x_device,
+                            CM_T35_SMSC911X_CS, CM_T35_SMSC911X_GPIO);
+       cm_t35_init_smsc911x(&sb_t35_smsc911x_device,
+                            SB_T35_SMSC911X_CS, SB_T35_SMSC911X_GPIO);
+}
+#else
+static inline void __init cm_t35_init_ethernet(void) { return; }
+#endif
+
+#if defined(CONFIG_LEDS_GPIO) || defined(CONFIG_LEDS_GPIO_MODULE)
+#include <linux/leds.h>
+
+static struct gpio_led cm_t35_leds[] = {
+       [0] = {
+               .gpio                   = 186,
+               .name                   = "cm-t35:green",
+               .default_trigger        = "heartbeat",
+               .active_low             = 0,
+       },
+};
+
+static struct gpio_led_platform_data cm_t35_led_pdata = {
+       .num_leds       = ARRAY_SIZE(cm_t35_leds),
+       .leds           = cm_t35_leds,
+};
+
+static struct platform_device cm_t35_led_device = {
+       .name           = "leds-gpio",
+       .id             = -1,
+       .dev            = {
+               .platform_data  = &cm_t35_led_pdata,
+       },
+};
+
+static void __init cm_t35_init_led(void)
+{
+       platform_device_register(&cm_t35_led_device);
+}
+#else
+static inline void cm_t35_init_led(void) {}
+#endif
+
+#if defined(CONFIG_MTD_NAND_OMAP2) || defined(CONFIG_MTD_NAND_OMAP2_MODULE)
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/partitions.h>
+
+static struct mtd_partition cm_t35_nand_partitions[] = {
+       {
+               .name           = "xloader",
+               .offset         = 0,                    /* Offset = 0x00000 */
+               .size           = 4 * NAND_BLOCK_SIZE,
+               .mask_flags     = MTD_WRITEABLE
+       },
+       {
+               .name           = "uboot",
+               .offset         = MTDPART_OFS_APPEND,   /* Offset = 0x80000 */
+               .size           = 15 * NAND_BLOCK_SIZE,
+       },
+       {
+               .name           = "uboot environment",
+               .offset         = MTDPART_OFS_APPEND,   /* Offset = 0x260000 */
+               .size           = 2 * NAND_BLOCK_SIZE,
+       },
+       {
+               .name           = "linux",
+               .offset         = MTDPART_OFS_APPEND,   /* Offset = 0x280000 */
+               .size           = 32 * NAND_BLOCK_SIZE,
+       },
+       {
+               .name           = "rootfs",
+               .offset         = MTDPART_OFS_APPEND,   /* Offset = 0x680000 */
+               .size           = MTDPART_SIZ_FULL,
+       },
+};
+
+static struct omap_nand_platform_data cm_t35_nand_data = {
+       .parts                  = cm_t35_nand_partitions,
+       .nr_parts               = ARRAY_SIZE(cm_t35_nand_partitions),
+       .dma_channel            = -1,   /* disable DMA in OMAP NAND driver */
+       .cs                     = 0,
+       .gpmc_cs_baseaddr       = (void __iomem *)GPMC_CS0_BASE_ADDR,
+       .gpmc_baseaddr          = (void __iomem *)OMAP34XX_GPMC_VIRT,
+
+};
+
+static struct resource cm_t35_nand_resource = {
+       .flags          = IORESOURCE_MEM,
+};
+
+static struct platform_device cm_t35_nand_device = {
+       .name           = "omap2-nand",
+       .id             = -1,
+       .num_resources  = 1,
+       .resource       = &cm_t35_nand_resource,
+       .dev            = {
+               .platform_data  = &cm_t35_nand_data,
+       },
+};
+
+static void __init cm_t35_init_nand(void)
+{
+       if (platform_device_register(&cm_t35_nand_device) < 0)
+               pr_err("CM-T35: Unable to register NAND device\n");
+}
+#else
+static inline void cm_t35_init_nand(void) {}
+#endif
+
+#if defined(CONFIG_TOUCHSCREEN_ADS7846) || \
+       defined(CONFIG_TOUCHSCREEN_ADS7846_MODULE)
+#include <linux/spi/spi.h>
+#include <linux/spi/ads7846.h>
+
+#include <plat/mcspi.h>
+
+static struct omap2_mcspi_device_config ads7846_mcspi_config = {
+       .turbo_mode     = 0,
+       .single_channel = 1,    /* 0: slave, 1: master */
+};
+
+static int ads7846_get_pendown_state(void)
+{
+       return !gpio_get_value(CM_T35_GPIO_PENDOWN);
+}
+
+static struct ads7846_platform_data ads7846_config = {
+       .x_max                  = 0x0fff,
+       .y_max                  = 0x0fff,
+       .x_plate_ohms           = 180,
+       .pressure_max           = 255,
+       .debounce_max           = 10,
+       .debounce_tol           = 3,
+       .debounce_rep           = 1,
+       .get_pendown_state      = ads7846_get_pendown_state,
+       .keep_vref_on           = 1,
+};
+
+static struct spi_board_info cm_t35_spi_board_info[] __initdata = {
+       {
+               .modalias               = "ads7846",
+               .bus_num                = 1,
+               .chip_select            = 0,
+               .max_speed_hz           = 1500000,
+               .controller_data        = &ads7846_mcspi_config,
+               .irq                    = OMAP_GPIO_IRQ(CM_T35_GPIO_PENDOWN),
+               .platform_data          = &ads7846_config,
+       },
+};
+
+static void __init cm_t35_init_ads7846(void)
+{
+       if ((gpio_request(CM_T35_GPIO_PENDOWN, "ADS7846_PENDOWN") == 0) &&
+           (gpio_direction_input(CM_T35_GPIO_PENDOWN) == 0)) {
+               gpio_export(CM_T35_GPIO_PENDOWN, 0);
+       } else {
+               pr_err("CM-T35: could not obtain gpio for ADS7846_PENDOWN\n");
+               return;
+       }
+
+       spi_register_board_info(cm_t35_spi_board_info,
+                               ARRAY_SIZE(cm_t35_spi_board_info));
+}
+#else
+static inline void cm_t35_init_ads7846(void) {}
+#endif
+
+static struct regulator_consumer_supply cm_t35_vmmc1_supply = {
+       .supply                 = "vmmc",
+};
+
+static struct regulator_consumer_supply cm_t35_vsim_supply = {
+       .supply                 = "vmmc_aux",
+};
+
+/* VMMC1 for MMC1 pins CMD, CLK, DAT0..DAT3 (20 mA, plus card == max 220 mA) */
+static struct regulator_init_data cm_t35_vmmc1 = {
+       .constraints = {
+               .min_uV                 = 1850000,
+               .max_uV                 = 3150000,
+               .valid_modes_mask       = REGULATOR_MODE_NORMAL
+                                       | REGULATOR_MODE_STANDBY,
+               .valid_ops_mask         = REGULATOR_CHANGE_VOLTAGE
+                                       | REGULATOR_CHANGE_MODE
+                                       | REGULATOR_CHANGE_STATUS,
+       },
+       .num_consumer_supplies  = 1,
+       .consumer_supplies      = &cm_t35_vmmc1_supply,
+};
+
+/* VSIM for MMC1 pins DAT4..DAT7 (2 mA, plus card == max 50 mA) */
+static struct regulator_init_data cm_t35_vsim = {
+       .constraints = {
+               .min_uV                 = 1800000,
+               .max_uV                 = 3000000,
+               .valid_modes_mask       = REGULATOR_MODE_NORMAL
+                                       | REGULATOR_MODE_STANDBY,
+               .valid_ops_mask         = REGULATOR_CHANGE_VOLTAGE
+                                       | REGULATOR_CHANGE_MODE
+                                       | REGULATOR_CHANGE_STATUS,
+       },
+       .num_consumer_supplies  = 1,
+       .consumer_supplies      = &cm_t35_vsim_supply,
+};
+
+static struct twl4030_usb_data cm_t35_usb_data = {
+       .usb_mode       = T2_USB_MODE_ULPI,
+};
+
+static int cm_t35_keymap[] = {
+       KEY(0, 0, KEY_A),       KEY(0, 1, KEY_B),       KEY(0, 2, KEY_LEFT),
+       KEY(1, 0, KEY_UP),      KEY(1, 1, KEY_ENTER),   KEY(1, 2, KEY_DOWN),
+       KEY(2, 0, KEY_RIGHT),   KEY(2, 1, KEY_C),       KEY(2, 2, KEY_D),
+};
+
+static struct matrix_keymap_data cm_t35_keymap_data = {
+       .keymap                 = cm_t35_keymap,
+       .keymap_size            = ARRAY_SIZE(cm_t35_keymap),
+};
+
+static struct twl4030_keypad_data cm_t35_kp_data = {
+       .keymap_data    = &cm_t35_keymap_data,
+       .rows           = 3,
+       .cols           = 3,
+       .rep            = 1,
+};
+
+static struct twl4030_hsmmc_info mmc[] = {
+       {
+               .mmc            = 1,
+               .wires          = 4,
+               .gpio_cd        = -EINVAL,
+               .gpio_wp        = -EINVAL,
+
+       },
+       {
+               .mmc            = 2,
+               .wires          = 4,
+               .transceiver    = 1,
+               .gpio_cd        = -EINVAL,
+               .gpio_wp        = -EINVAL,
+               .ocr_mask       = 0x00100000,   /* 3.3V */
+       },
+       {}      /* Terminator */
+};
+
+static struct ehci_hcd_omap_platform_data ehci_pdata = {
+       .port_mode[0] = EHCI_HCD_OMAP_MODE_PHY,
+       .port_mode[1] = EHCI_HCD_OMAP_MODE_PHY,
+       .port_mode[2] = EHCI_HCD_OMAP_MODE_UNKNOWN,
+
+       .phy_reset  = true,
+       .reset_gpio_port[0]  = -EINVAL,
+       .reset_gpio_port[1]  = -EINVAL,
+       .reset_gpio_port[2]  = -EINVAL
+};
+
+static int cm_t35_twl_gpio_setup(struct device *dev, unsigned gpio,
+                                unsigned ngpio)
+{
+       int wlan_rst = gpio + 2;
+
+       if ((gpio_request(wlan_rst, "WLAN RST") == 0) &&
+           (gpio_direction_output(wlan_rst, 1) == 0)) {
+               gpio_export(wlan_rst, 0);
+
+               udelay(10);
+               gpio_set_value(wlan_rst, 0);
+               udelay(10);
+               gpio_set_value(wlan_rst, 1);
+       } else {
+               pr_err("CM-T35: could not obtain gpio for WiFi reset\n");
+       }
+
+       /* gpio + 0 is "mmc0_cd" (input/IRQ) */
+       mmc[0].gpio_cd = gpio + 0;
+       twl4030_mmc_init(mmc);
+
+       /* link regulators to MMC adapters */
+       cm_t35_vmmc1_supply.dev = mmc[0].dev;
+       cm_t35_vsim_supply.dev = mmc[0].dev;
+
+       /* setup USB with proper PHY reset GPIOs */
+       ehci_pdata.reset_gpio_port[0] = gpio + 6;
+       ehci_pdata.reset_gpio_port[1] = gpio + 7;
+
+       usb_ehci_init(&ehci_pdata);
+
+       return 0;
+}
+
+static struct twl4030_gpio_platform_data cm_t35_gpio_data = {
+       .gpio_base      = OMAP_MAX_GPIO_LINES,
+       .irq_base       = TWL4030_GPIO_IRQ_BASE,
+       .irq_end        = TWL4030_GPIO_IRQ_END,
+       .setup          = cm_t35_twl_gpio_setup,
+};
+
+static struct twl4030_platform_data cm_t35_twldata = {
+       .irq_base       = TWL4030_IRQ_BASE,
+       .irq_end        = TWL4030_IRQ_END,
+
+       /* platform_data for children goes here */
+       .keypad         = &cm_t35_kp_data,
+       .usb            = &cm_t35_usb_data,
+       .gpio           = &cm_t35_gpio_data,
+       .vmmc1          = &cm_t35_vmmc1,
+       .vsim           = &cm_t35_vsim,
+};
+
+static struct i2c_board_info __initdata cm_t35_i2c_boardinfo[] = {
+       {
+               I2C_BOARD_INFO("tps65930", 0x48),
+               .flags          = I2C_CLIENT_WAKE,
+               .irq            = INT_34XX_SYS_NIRQ,
+               .platform_data  = &cm_t35_twldata,
+       },
+};
+
+static void __init cm_t35_init_i2c(void)
+{
+       omap_register_i2c_bus(1, 2600, cm_t35_i2c_boardinfo,
+                             ARRAY_SIZE(cm_t35_i2c_boardinfo));
+}
+
+static struct omap_board_config_kernel cm_t35_config[] __initdata = {
+};
+
+static void __init cm_t35_init_irq(void)
+{
+       omap_board_config = cm_t35_config;
+       omap_board_config_size = ARRAY_SIZE(cm_t35_config);
+
+       omap2_init_common_hw(mt46h32m32lf6_sdrc_params,
+                            mt46h32m32lf6_sdrc_params);
+       omap_init_irq();
+       omap_gpio_init();
+}
+
+static void __init cm_t35_map_io(void)
+{
+       omap2_set_globals_343x();
+       omap2_map_common_io();
+}
+
+static void __init cm_t35_init(void)
+{
+       omap_serial_init();
+       cm_t35_init_i2c();
+       cm_t35_init_nand();
+       cm_t35_init_ads7846();
+       cm_t35_init_ethernet();
+       cm_t35_init_led();
+
+       usb_musb_init();
+
+       omap_cfg_reg(AF26_34XX_SYS_NIRQ);
+}
+
+MACHINE_START(CM_T35, "Compulab CM-T35")
+       .phys_io        = 0x48000000,
+       .io_pg_offst    = ((0xd8000000) >> 18) & 0xfffc,
+       .boot_params    = 0x80000100,
+       .map_io         = cm_t35_map_io,
+       .init_irq       = cm_t35_init_irq,
+       .init_machine   = cm_t35_init,
+       .timer          = &omap_timer,
+MACHINE_END
index 2e09a1c..7e6e6ca 100644 (file)
 #include <asm/mach/map.h>
 
 #include <mach/gpio.h>
-#include <mach/mux.h>
-#include <mach/usb.h>
-#include <mach/board.h>
-#include <mach/common.h>
+#include <plat/mux.h>
+#include <plat/usb.h>
+#include <plat/board.h>
+#include <plat/common.h>
 
 static struct omap_board_config_kernel generic_config[] = {
 };
@@ -56,7 +56,7 @@ static void __init omap_generic_map_io(void)
 MACHINE_START(OMAP_GENERIC, "Generic OMAP24xx")
        /* Maintainer: Paul Mundt <paul.mundt@nokia.com> */
        .phys_io        = 0x48000000,
-       .io_pg_offst    = ((0xd8000000) >> 18) & 0xfffc,
+       .io_pg_offst    = ((0xfa000000) >> 18) & 0xfffc,
        .boot_params    = 0x80000100,
        .map_io         = omap_generic_map_io,
        .init_irq       = omap_generic_init_irq,
index eaa02d0..cfb7f12 100644 (file)
 #include <asm/mach/map.h>
 #include <asm/mach/flash.h>
 
-#include <mach/control.h>
+#include <plat/control.h>
 #include <mach/gpio.h>
-#include <mach/mux.h>
-#include <mach/usb.h>
-#include <mach/board.h>
-#include <mach/common.h>
-#include <mach/keypad.h>
-#include <mach/menelaus.h>
-#include <mach/dma.h>
-#include <mach/gpmc.h>
+#include <plat/mux.h>
+#include <plat/usb.h>
+#include <plat/board.h>
+#include <plat/common.h>
+#include <plat/keypad.h>
+#include <plat/menelaus.h>
+#include <plat/dma.h>
+#include <plat/gpmc.h>
 
 #define H4_FLASH_CS    0
 #define H4_SMC91X_CS   1
@@ -376,7 +376,7 @@ static void __init omap_h4_map_io(void)
 MACHINE_START(OMAP_H4, "OMAP2420 H4 board")
        /* Maintainer: Paul Mundt <paul.mundt@nokia.com> */
        .phys_io        = 0x48000000,
-       .io_pg_offst    = ((0xd8000000) >> 18) & 0xfffc,
+       .io_pg_offst    = ((0xfa000000) >> 18) & 0xfffc,
        .boot_params    = 0x80000100,
        .map_io         = omap_h4_map_io,
        .init_irq       = omap_h4_init_irq,
diff --git a/arch/arm/mach-omap2/board-igep0020.c b/arch/arm/mach-omap2/board-igep0020.c
new file mode 100644 (file)
index 0000000..fa62e80
--- /dev/null
@@ -0,0 +1,251 @@
+/*
+ * Copyright (C) 2009 Integration Software and Electronic Engineering.
+ *
+ * Modified from mach-omap2/board-generic.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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/gpio.h>
+#include <linux/interrupt.h>
+
+#include <linux/regulator/machine.h>
+#include <linux/i2c/twl4030.h>
+
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+
+#include <plat/board.h>
+#include <plat/common.h>
+#include <plat/gpmc.h>
+#include <plat/mux.h>
+#include <plat/usb.h>
+
+#include "mmc-twl4030.h"
+
+#define IGEP2_SMSC911X_CS       5
+#define IGEP2_SMSC911X_GPIO     176
+#define IGEP2_GPIO_USBH_NRESET  24
+#define IGEP2_GPIO_LED0_RED    26
+#define IGEP2_GPIO_LED0_GREEN  27
+#define IGEP2_GPIO_LED1_RED    28
+
+#if defined(CONFIG_SMSC911X) || defined(CONFIG_SMSC911X_MODULE)
+
+#include <linux/smsc911x.h>
+
+static struct smsc911x_platform_config igep2_smsc911x_config = {
+       .irq_polarity   = SMSC911X_IRQ_POLARITY_ACTIVE_LOW,
+       .irq_type       = SMSC911X_IRQ_TYPE_OPEN_DRAIN,
+       .flags          = SMSC911X_USE_32BIT | SMSC911X_SAVE_MAC_ADDRESS  ,
+       .phy_interface  = PHY_INTERFACE_MODE_MII,
+};
+
+static struct resource igep2_smsc911x_resources[] = {
+       {
+               .flags  = IORESOURCE_MEM,
+       },
+       {
+               .start  = OMAP_GPIO_IRQ(IGEP2_SMSC911X_GPIO),
+               .end    = OMAP_GPIO_IRQ(IGEP2_SMSC911X_GPIO),
+               .flags  = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWLEVEL,
+       },
+};
+
+static struct platform_device igep2_smsc911x_device = {
+       .name           = "smsc911x",
+       .id             = 0,
+       .num_resources  = ARRAY_SIZE(igep2_smsc911x_resources),
+       .resource       = igep2_smsc911x_resources,
+       .dev            = {
+               .platform_data = &igep2_smsc911x_config,
+       },
+};
+
+static inline void __init igep2_init_smsc911x(void)
+{
+       unsigned long cs_mem_base;
+
+       if (gpmc_cs_request(IGEP2_SMSC911X_CS, SZ_16M, &cs_mem_base) < 0) {
+               pr_err("IGEP v2: Failed request for GPMC mem for smsc911x\n");
+               gpmc_cs_free(IGEP2_SMSC911X_CS);
+               return;
+       }
+
+       igep2_smsc911x_resources[0].start = cs_mem_base + 0x0;
+       igep2_smsc911x_resources[0].end   = cs_mem_base + 0xff;
+
+       if ((gpio_request(IGEP2_SMSC911X_GPIO, "SMSC911X IRQ") == 0) &&
+           (gpio_direction_input(IGEP2_SMSC911X_GPIO) == 0)) {
+               gpio_export(IGEP2_SMSC911X_GPIO, 0);
+       } else {
+               pr_err("IGEP v2: Could not obtain gpio for for SMSC911X IRQ\n");
+               return;
+       }
+
+       platform_device_register(&igep2_smsc911x_device);
+}
+
+#else
+static inline void __init igep2_init_smsc911x(void) { }
+#endif
+
+static struct omap_board_config_kernel igep2_config[] __initdata = {
+};
+
+static struct regulator_consumer_supply igep2_vmmc1_supply = {
+       .supply         = "vmmc",
+};
+
+/* VMMC1 for OMAP VDD_MMC1 (i/o) and MMC1 card */
+static struct regulator_init_data igep2_vmmc1 = {
+       .constraints = {
+               .min_uV                 = 1850000,
+               .max_uV                 = 3150000,
+               .valid_modes_mask       = REGULATOR_MODE_NORMAL
+                                       | REGULATOR_MODE_STANDBY,
+               .valid_ops_mask         = REGULATOR_CHANGE_VOLTAGE
+                                       | REGULATOR_CHANGE_MODE
+                                       | REGULATOR_CHANGE_STATUS,
+       },
+       .num_consumer_supplies  = 1,
+       .consumer_supplies      = &igep2_vmmc1_supply,
+};
+
+static struct twl4030_hsmmc_info mmc[] = {
+       {
+               .mmc            = 1,
+               .wires          = 4,
+               .gpio_cd        = -EINVAL,
+               .gpio_wp        = -EINVAL,
+       },
+       {
+               .mmc            = 2,
+               .wires          = 4,
+               .gpio_cd        = -EINVAL,
+               .gpio_wp        = -EINVAL,
+       },
+       {}      /* Terminator */
+};
+
+static int igep2_twl_gpio_setup(struct device *dev,
+               unsigned gpio, unsigned ngpio)
+{
+       /* gpio + 0 is "mmc0_cd" (input/IRQ) */
+       mmc[0].gpio_cd = gpio + 0;
+       twl4030_mmc_init(mmc);
+
+       /* link regulators to MMC adapters ... we "know" the
+        * regulators will be set up only *after* we return.
+       */
+       igep2_vmmc1_supply.dev = mmc[0].dev;
+
+       return 0;
+};
+
+static struct twl4030_gpio_platform_data igep2_gpio_data = {
+       .gpio_base      = OMAP_MAX_GPIO_LINES,
+       .irq_base       = TWL4030_GPIO_IRQ_BASE,
+       .irq_end        = TWL4030_GPIO_IRQ_END,
+       .use_leds       = false,
+       .setup          = igep2_twl_gpio_setup,
+};
+
+static struct twl4030_usb_data igep2_usb_data = {
+       .usb_mode       = T2_USB_MODE_ULPI,
+};
+
+static void __init igep2_init_irq(void)
+{
+       omap_board_config = igep2_config;
+       omap_board_config_size = ARRAY_SIZE(igep2_config);
+       omap2_init_common_hw(NULL, NULL);
+       omap_init_irq();
+       omap_gpio_init();
+}
+
+static struct twl4030_platform_data igep2_twldata = {
+       .irq_base       = TWL4030_IRQ_BASE,
+       .irq_end        = TWL4030_IRQ_END,
+
+       /* platform_data for children goes here */
+       .usb            = &igep2_usb_data,
+       .gpio           = &igep2_gpio_data,
+       .vmmc1          = &igep2_vmmc1,
+
+};
+
+static struct i2c_board_info __initdata igep2_i2c_boardinfo[] = {
+       {
+               I2C_BOARD_INFO("twl4030", 0x48),
+               .flags          = I2C_CLIENT_WAKE,
+               .irq            = INT_34XX_SYS_NIRQ,
+               .platform_data  = &igep2_twldata,
+       },
+};
+
+static int __init igep2_i2c_init(void)
+{
+       omap_register_i2c_bus(1, 2600, igep2_i2c_boardinfo,
+                       ARRAY_SIZE(igep2_i2c_boardinfo));
+       /* Bus 3 is attached to the DVI port where devices like the pico DLP
+        * projector don't work reliably with 400kHz */
+       omap_register_i2c_bus(3, 100, NULL, 0);
+       return 0;
+}
+
+static void __init igep2_init(void)
+{
+       igep2_i2c_init();
+       omap_serial_init();
+       usb_musb_init();
+
+       igep2_init_smsc911x();
+
+       /* GPIO userspace leds */
+       if ((gpio_request(IGEP2_GPIO_LED0_RED, "GPIO_LED0_RED") == 0) &&
+           (gpio_direction_output(IGEP2_GPIO_LED0_RED, 1) == 0)) {
+               gpio_export(IGEP2_GPIO_LED0_RED, 0);
+               gpio_set_value(IGEP2_GPIO_LED0_RED, 0);
+       } else
+               pr_warning("IGEP v2: Could not obtain gpio GPIO_LED0_RED\n");
+
+       if ((gpio_request(IGEP2_GPIO_LED0_GREEN, "GPIO_LED0_GREEN") == 0) &&
+           (gpio_direction_output(IGEP2_GPIO_LED0_GREEN, 1) == 0)) {
+               gpio_export(IGEP2_GPIO_LED0_GREEN, 0);
+               gpio_set_value(IGEP2_GPIO_LED0_GREEN, 0);
+       } else
+               pr_warning("IGEP v2: Could not obtain gpio GPIO_LED0_GREEN\n");
+
+       if ((gpio_request(IGEP2_GPIO_LED1_RED, "GPIO_LED1_RED") == 0) &&
+           (gpio_direction_output(IGEP2_GPIO_LED1_RED, 1) == 0)) {
+               gpio_export(IGEP2_GPIO_LED1_RED, 0);
+               gpio_set_value(IGEP2_GPIO_LED1_RED, 0);
+       } else
+               pr_warning("IGEP v2: Could not obtain gpio GPIO_LED1_RED\n");
+}
+
+static void __init igep2_map_io(void)
+{
+       omap2_set_globals_343x();
+       omap2_map_common_io();
+}
+
+MACHINE_START(IGEP0020, "IGEP v2 board")
+       .phys_io        = 0x48000000,
+       .io_pg_offst    = ((0xfa000000) >> 18) & 0xfffc,
+       .boot_params    = 0x80000100,
+       .map_io         = igep2_map_io,
+       .init_irq       = igep2_init_irq,
+       .init_machine   = igep2_init,
+       .timer          = &omap_timer,
+MACHINE_END
index d57ec2f..c062238 100644 (file)
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
 
-#include <mach/mcspi.h>
+#include <plat/mcspi.h>
 #include <mach/gpio.h>
-#include <mach/board.h>
-#include <mach/common.h>
-#include <mach/gpmc.h>
+#include <plat/board.h>
+#include <plat/common.h>
+#include <plat/gpmc.h>
 
 #include <asm/delay.h>
-#include <mach/control.h>
-#include <mach/usb.h>
+#include <plat/control.h>
+#include <plat/usb.h>
 
 #include "mmc-twl4030.h"
 
@@ -399,7 +399,7 @@ static void __init omap_ldp_map_io(void)
 
 MACHINE_START(OMAP_LDP, "OMAP LDP board")
        .phys_io        = 0x48000000,
-       .io_pg_offst    = ((0xd8000000) >> 18) & 0xfffc,
+       .io_pg_offst    = ((0xfa000000) >> 18) & 0xfffc,
        .boot_params    = 0x80000100,
        .map_io         = omap_ldp_map_io,
        .init_irq       = omap_ldp_init_irq,
index 8341632..764ab1e 100644 (file)
 #include <asm/mach/arch.h>
 #include <asm/mach-types.h>
 
-#include <mach/board.h>
-#include <mach/common.h>
+#include <plat/board.h>
+#include <plat/common.h>
 #include <mach/irqs.h>
-#include <mach/mcspi.h>
-#include <mach/onenand.h>
-#include <mach/serial.h>
+#include <plat/mcspi.h>
+#include <plat/onenand.h>
+#include <plat/serial.h>
 
 static struct omap2_mcspi_device_config p54spi_mcspi_config = {
        .turbo_mode     = 0,
@@ -121,7 +121,7 @@ static void __init n8x0_init_machine(void)
 
 MACHINE_START(NOKIA_N800, "Nokia N800")
        .phys_io        = 0x48000000,
-       .io_pg_offst    = ((0xd8000000) >> 18) & 0xfffc,
+       .io_pg_offst    = ((0xfa000000) >> 18) & 0xfffc,
        .boot_params    = 0x80000100,
        .map_io         = n8x0_map_io,
        .init_irq       = n8x0_init_irq,
@@ -131,7 +131,7 @@ MACHINE_END
 
 MACHINE_START(NOKIA_N810, "Nokia N810")
        .phys_io        = 0x48000000,
-       .io_pg_offst    = ((0xd8000000) >> 18) & 0xfffc,
+       .io_pg_offst    = ((0xfa000000) >> 18) & 0xfffc,
        .boot_params    = 0x80000100,
        .map_io         = n8x0_map_io,
        .init_irq       = n8x0_init_irq,
@@ -141,7 +141,7 @@ MACHINE_END
 
 MACHINE_START(NOKIA_N810_WIMAX, "Nokia N810 WiMAX")
        .phys_io        = 0x48000000,
-       .io_pg_offst    = ((0xd8000000) >> 18) & 0xfffc,
+       .io_pg_offst    = ((0xfa000000) >> 18) & 0xfffc,
        .boot_params    = 0x80000100,
        .map_io         = n8x0_map_io,
        .init_irq       = n8x0_init_irq,
index 08b0816..41480bd 100644 (file)
 #include <asm/mach/map.h>
 #include <asm/mach/flash.h>
 
-#include <mach/board.h>
-#include <mach/common.h>
-#include <mach/gpmc.h>
-#include <mach/nand.h>
-#include <mach/mux.h>
-#include <mach/usb.h>
-#include <mach/timer-gp.h>
+#include <plat/board.h>
+#include <plat/common.h>
+#include <plat/gpmc.h>
+#include <plat/nand.h>
+#include <plat/mux.h>
+#include <plat/usb.h>
+#include <plat/timer-gp.h>
 
 #include "mmc-twl4030.h"
 
@@ -254,6 +254,15 @@ static struct twl4030_usb_data beagle_usb_data = {
        .usb_mode       = T2_USB_MODE_ULPI,
 };
 
+static struct twl4030_codec_audio_data beagle_audio_data = {
+       .audio_mclk = 26000000,
+};
+
+static struct twl4030_codec_data beagle_codec_data = {
+       .audio_mclk = 26000000,
+       .audio = &beagle_audio_data,
+};
+
 static struct twl4030_platform_data beagle_twldata = {
        .irq_base       = TWL4030_IRQ_BASE,
        .irq_end        = TWL4030_IRQ_END,
@@ -261,6 +270,7 @@ static struct twl4030_platform_data beagle_twldata = {
        /* platform_data for children goes here */
        .usb            = &beagle_usb_data,
        .gpio           = &beagle_gpio_data,
+       .codec          = &beagle_codec_data,
        .vmmc1          = &beagle_vmmc1,
        .vsim           = &beagle_vsim,
        .vdac           = &beagle_vdac,
@@ -400,6 +410,18 @@ static void __init omap3beagle_flash_init(void)
        }
 }
 
+static struct ehci_hcd_omap_platform_data ehci_pdata __initconst = {
+
+       .port_mode[0] = EHCI_HCD_OMAP_MODE_PHY,
+       .port_mode[1] = EHCI_HCD_OMAP_MODE_PHY,
+       .port_mode[2] = EHCI_HCD_OMAP_MODE_UNKNOWN,
+
+       .phy_reset  = true,
+       .reset_gpio_port[0]  = -EINVAL,
+       .reset_gpio_port[1]  = 147,
+       .reset_gpio_port[2]  = -EINVAL
+};
+
 static void __init omap3_beagle_init(void)
 {
        omap3_beagle_i2c_init();
@@ -413,6 +435,7 @@ static void __init omap3_beagle_init(void)
        gpio_direction_output(170, true);
 
        usb_musb_init();
+       usb_ehci_init(&ehci_pdata);
        omap3beagle_flash_init();
 
        /* Ensure SDRC pins are mux'd for self-refresh */
@@ -429,7 +452,7 @@ static void __init omap3_beagle_map_io(void)
 MACHINE_START(OMAP3_BEAGLE, "OMAP3 Beagle Board")
        /* Maintainer: Syed Mohammed Khasim - http://beagleboard.org */
        .phys_io        = 0x48000000,
-       .io_pg_offst    = ((0xd8000000) >> 18) & 0xfffc,
+       .io_pg_offst    = ((0xfa000000) >> 18) & 0xfffc,
        .boot_params    = 0x80000100,
        .map_io         = omap3_beagle_map_io,
        .init_irq       = omap3_beagle_init_irq,
index 4c4d7f8..5efc2e9 100644 (file)
 #include <linux/input.h>
 #include <linux/input/matrix_keypad.h>
 #include <linux/leds.h>
+#include <linux/interrupt.h>
 
 #include <linux/spi/spi.h>
 #include <linux/spi/ads7846.h>
 #include <linux/i2c/twl4030.h>
 #include <linux/usb/otg.h>
+#include <linux/smsc911x.h>
+
+#include <linux/regulator/machine.h>
 
 #include <mach/hardware.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
 
-#include <mach/board.h>
-#include <mach/mux.h>
-#include <mach/usb.h>
-#include <mach/common.h>
-#include <mach/mcspi.h>
+#include <plat/board.h>
+#include <plat/mux.h>
+#include <plat/usb.h>
+#include <plat/common.h>
+#include <plat/mcspi.h>
 
 #include "sdram-micron-mt46h32m32lf-6.h"
 #include "mmc-twl4030.h"
 
 #define OMAP3_EVM_TS_GPIO      175
+#define OMAP3_EVM_EHCI_VBUS    22
+#define OMAP3_EVM_EHCI_SELECT  61
 
 #define OMAP3EVM_ETHR_START    0x2c000000
 #define OMAP3EVM_ETHR_SIZE     1024
+#define OMAP3EVM_ETHR_ID_REV   0x50
 #define OMAP3EVM_ETHR_GPIO_IRQ 176
-#define OMAP3EVM_SMC911X_CS    5
+#define OMAP3EVM_SMSC911X_CS   5
+
+static u8 omap3_evm_version;
+
+u8 get_omap3_evm_rev(void)
+{
+       return omap3_evm_version;
+}
+EXPORT_SYMBOL(get_omap3_evm_rev);
+
+static void __init omap3_evm_get_revision(void)
+{
+       void __iomem *ioaddr;
+       unsigned int smsc_id;
+
+       /* Ethernet PHY ID is stored at ID_REV register */
+       ioaddr = ioremap_nocache(OMAP3EVM_ETHR_START, SZ_1K);
+       if (!ioaddr)
+               return;
+       smsc_id = readl(ioaddr + OMAP3EVM_ETHR_ID_REV) & 0xFFFF0000;
+       iounmap(ioaddr);
+
+       switch (smsc_id) {
+       /*SMSC9115 chipset*/
+       case 0x01150000:
+               omap3_evm_version = OMAP3EVM_BOARD_GEN_1;
+               break;
+       /*SMSC 9220 chipset*/
+       case 0x92200000:
+       default:
+               omap3_evm_version = OMAP3EVM_BOARD_GEN_2;
+       }
+}
 
-static struct resource omap3evm_smc911x_resources[] = {
+#if defined(CONFIG_SMSC911X) || defined(CONFIG_SMSC911X_MODULE)
+static struct resource omap3evm_smsc911x_resources[] = {
        [0] =   {
                .start  = OMAP3EVM_ETHR_START,
                .end    = (OMAP3EVM_ETHR_START + OMAP3EVM_ETHR_SIZE - 1),
@@ -58,24 +98,34 @@ static struct resource omap3evm_smc911x_resources[] = {
        [1] =   {
                .start  = OMAP_GPIO_IRQ(OMAP3EVM_ETHR_GPIO_IRQ),
                .end    = OMAP_GPIO_IRQ(OMAP3EVM_ETHR_GPIO_IRQ),
-               .flags  = IORESOURCE_IRQ,
+               .flags  = (IORESOURCE_IRQ | IRQF_TRIGGER_LOW),
        },
 };
 
-static struct platform_device omap3evm_smc911x_device = {
-       .name           = "smc911x",
+static struct smsc911x_platform_config smsc911x_config = {
+       .phy_interface  = PHY_INTERFACE_MODE_MII,
+       .irq_polarity   = SMSC911X_IRQ_POLARITY_ACTIVE_LOW,
+       .irq_type       = SMSC911X_IRQ_TYPE_OPEN_DRAIN,
+       .flags          = (SMSC911X_USE_32BIT | SMSC911X_SAVE_MAC_ADDRESS),
+};
+
+static struct platform_device omap3evm_smsc911x_device = {
+       .name           = "smsc911x",
        .id             = -1,
-       .num_resources  = ARRAY_SIZE(omap3evm_smc911x_resources),
-       .resource       = &omap3evm_smc911x_resources[0],
+       .num_resources  = ARRAY_SIZE(omap3evm_smsc911x_resources),
+       .resource       = &omap3evm_smsc911x_resources[0],
+       .dev            = {
+               .platform_data = &smsc911x_config,
+       },
 };
 
-static inline void __init omap3evm_init_smc911x(void)
+static inline void __init omap3evm_init_smsc911x(void)
 {
        int eth_cs;
        struct clk *l3ck;
        unsigned int rate;
 
-       eth_cs = OMAP3EVM_SMC911X_CS;
+       eth_cs = OMAP3EVM_SMSC911X_CS;
 
        l3ck = clk_get(NULL, "l3_ck");
        if (IS_ERR(l3ck))
@@ -83,15 +133,58 @@ static inline void __init omap3evm_init_smc911x(void)
        else
                rate = clk_get_rate(l3ck);
 
-       if (gpio_request(OMAP3EVM_ETHR_GPIO_IRQ, "SMC911x irq") < 0) {
-               printk(KERN_ERR "Failed to request GPIO%d for smc911x IRQ\n",
+       if (gpio_request(OMAP3EVM_ETHR_GPIO_IRQ, "SMSC911x irq") < 0) {
+               printk(KERN_ERR "Failed to request GPIO%d for smsc911x IRQ\n",
                        OMAP3EVM_ETHR_GPIO_IRQ);
                return;
        }
 
        gpio_direction_input(OMAP3EVM_ETHR_GPIO_IRQ);
+       platform_device_register(&omap3evm_smsc911x_device);
 }
 
+#else
+static inline void __init omap3evm_init_smsc911x(void) { return; }
+#endif
+
+static struct regulator_consumer_supply omap3evm_vmmc1_supply = {
+       .supply                 = "vmmc",
+};
+
+static struct regulator_consumer_supply omap3evm_vsim_supply = {
+       .supply                 = "vmmc_aux",
+};
+
+/* VMMC1 for MMC1 pins CMD, CLK, DAT0..DAT3 (20 mA, plus card == max 220 mA) */
+static struct regulator_init_data omap3evm_vmmc1 = {
+       .constraints = {
+               .min_uV                 = 1850000,
+               .max_uV                 = 3150000,
+               .valid_modes_mask       = REGULATOR_MODE_NORMAL
+                                       | REGULATOR_MODE_STANDBY,
+               .valid_ops_mask         = REGULATOR_CHANGE_VOLTAGE
+                                       | REGULATOR_CHANGE_MODE
+                                       | REGULATOR_CHANGE_STATUS,
+       },
+       .num_consumer_supplies  = 1,
+       .consumer_supplies      = &omap3evm_vmmc1_supply,
+};
+
+/* VSIM for MMC1 pins DAT4..DAT7 (2 mA, plus card == max 50 mA) */
+static struct regulator_init_data omap3evm_vsim = {
+       .constraints = {
+               .min_uV                 = 1800000,
+               .max_uV                 = 3000000,
+               .valid_modes_mask       = REGULATOR_MODE_NORMAL
+                                       | REGULATOR_MODE_STANDBY,
+               .valid_ops_mask         = REGULATOR_CHANGE_VOLTAGE
+                                       | REGULATOR_CHANGE_MODE
+                                       | REGULATOR_CHANGE_STATUS,
+       },
+       .num_consumer_supplies  = 1,
+       .consumer_supplies      = &omap3evm_vsim_supply,
+};
+
 static struct twl4030_hsmmc_info mmc[] = {
        {
                .mmc            = 1,
@@ -134,6 +227,10 @@ static int omap3evm_twl_gpio_setup(struct device *dev,
        mmc[0].gpio_cd = gpio + 0;
        twl4030_mmc_init(mmc);
 
+       /* link regulators to MMC adapters */
+       omap3evm_vmmc1_supply.dev = mmc[0].dev;
+       omap3evm_vsim_supply.dev = mmc[0].dev;
+
        /*
         * Most GPIOs are for USB OTG.  Some are mostly sent to
         * the P2 connector; notably LEDA for the LCD backlight.
@@ -194,6 +291,15 @@ static struct twl4030_madc_platform_data omap3evm_madc_data = {
        .irq_line       = 1,
 };
 
+static struct twl4030_codec_audio_data omap3evm_audio_data = {
+       .audio_mclk = 26000000,
+};
+
+static struct twl4030_codec_data omap3evm_codec_data = {
+       .audio_mclk = 26000000,
+       .audio = &omap3evm_audio_data,
+};
+
 static struct twl4030_platform_data omap3evm_twldata = {
        .irq_base       = TWL4030_IRQ_BASE,
        .irq_end        = TWL4030_IRQ_END,
@@ -203,6 +309,7 @@ static struct twl4030_platform_data omap3evm_twldata = {
        .madc           = &omap3evm_madc_data,
        .usb            = &omap3evm_usb_data,
        .gpio           = &omap3evm_gpio_data,
+       .codec          = &omap3evm_codec_data,
 };
 
 static struct i2c_board_info __initdata omap3evm_i2c_boardinfo[] = {
@@ -216,6 +323,13 @@ static struct i2c_board_info __initdata omap3evm_i2c_boardinfo[] = {
 
 static int __init omap3_evm_i2c_init(void)
 {
+       /*
+        * REVISIT: These entries can be set in omap3evm_twl_data
+        * after a merge with MFD tree
+        */
+       omap3evm_twldata.vmmc1 = &omap3evm_vmmc1;
+       omap3evm_twldata.vsim = &omap3evm_vsim;
+
        omap_register_i2c_bus(1, 2600, omap3evm_i2c_boardinfo,
                        ARRAY_SIZE(omap3evm_i2c_boardinfo));
        omap_register_i2c_bus(2, 400, NULL, 0);
@@ -289,16 +403,29 @@ static void __init omap3_evm_init_irq(void)
        omap2_init_common_hw(mt46h32m32lf6_sdrc_params, NULL);
        omap_init_irq();
        omap_gpio_init();
-       omap3evm_init_smc911x();
 }
 
 static struct platform_device *omap3_evm_devices[] __initdata = {
        &omap3_evm_lcd_device,
-       &omap3evm_smc911x_device,
+};
+
+static struct ehci_hcd_omap_platform_data ehci_pdata __initconst = {
+
+       .port_mode[0] = EHCI_HCD_OMAP_MODE_UNKNOWN,
+       .port_mode[1] = EHCI_HCD_OMAP_MODE_PHY,
+       .port_mode[2] = EHCI_HCD_OMAP_MODE_UNKNOWN,
+
+       .phy_reset  = true,
+       /* PHY reset GPIO will be runtime programmed based on EVM version */
+       .reset_gpio_port[0]  = -EINVAL,
+       .reset_gpio_port[1]  = -EINVAL,
+       .reset_gpio_port[2]  = -EINVAL
 };
 
 static void __init omap3_evm_init(void)
 {
+       omap3_evm_get_revision();
+
        omap3_evm_i2c_init();
 
        platform_add_devices(omap3_evm_devices, ARRAY_SIZE(omap3_evm_devices));
@@ -311,8 +438,32 @@ static void __init omap3_evm_init(void)
        /* OMAP3EVM uses ISP1504 phy and so register nop transceiver */
        usb_nop_xceiv_register();
 #endif
+       if (get_omap3_evm_rev() >= OMAP3EVM_BOARD_GEN_2) {
+               /* enable EHCI VBUS using GPIO22 */
+               omap_cfg_reg(AF9_34XX_GPIO22);
+               gpio_request(OMAP3_EVM_EHCI_VBUS, "enable EHCI VBUS");
+               gpio_direction_output(OMAP3_EVM_EHCI_VBUS, 0);
+               gpio_set_value(OMAP3_EVM_EHCI_VBUS, 1);
+
+               /* Select EHCI port on main board */
+               omap_cfg_reg(U3_34XX_GPIO61);
+               gpio_request(OMAP3_EVM_EHCI_SELECT, "select EHCI port");
+               gpio_direction_output(OMAP3_EVM_EHCI_SELECT, 0);
+               gpio_set_value(OMAP3_EVM_EHCI_SELECT, 0);
+
+               /* setup EHCI phy reset config */
+               omap_cfg_reg(AH14_34XX_GPIO21);
+               ehci_pdata.reset_gpio_port[1] = 21;
+
+       } else {
+               /* setup EHCI phy reset on MDC */
+               omap_cfg_reg(AF4_34XX_GPIO135_OUT);
+               ehci_pdata.reset_gpio_port[1] = 135;
+       }
        usb_musb_init();
+       usb_ehci_init(&ehci_pdata);
        ads7846_dev_init();
+       omap3evm_init_smsc911x();
 }
 
 static void __init omap3_evm_map_io(void)
@@ -324,7 +475,7 @@ static void __init omap3_evm_map_io(void)
 MACHINE_START(OMAP3EVM, "OMAP3 EVM")
        /* Maintainer: Syed Mohammed Khasim - Texas Instruments */
        .phys_io        = 0x48000000,
-       .io_pg_offst    = ((0xd8000000) >> 18) & 0xfffc,
+       .io_pg_offst    = ((0xfa000000) >> 18) & 0xfffc,
        .boot_params    = 0x80000100,
        .map_io         = omap3_evm_map_io,
        .init_irq       = omap3_evm_init_irq,
index 7519edb..2db5ba5 100644 (file)
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
 
-#include <mach/board.h>
-#include <mach/common.h>
+#include <plat/board.h>
+#include <plat/common.h>
 #include <mach/gpio.h>
 #include <mach/hardware.h>
-#include <mach/mcspi.h>
-#include <mach/usb.h>
-#include <mach/mux.h>
+#include <plat/mcspi.h>
+#include <plat/usb.h>
+#include <plat/mux.h>
 
 #include "sdram-micron-mt46h32m32lf-6.h"
 #include "mmc-twl4030.h"
@@ -281,11 +281,21 @@ static struct twl4030_usb_data omap3pandora_usb_data = {
        .usb_mode       = T2_USB_MODE_ULPI,
 };
 
+static struct twl4030_codec_audio_data omap3pandora_audio_data = {
+       .audio_mclk = 26000000,
+};
+
+static struct twl4030_codec_data omap3pandora_codec_data = {
+       .audio_mclk = 26000000,
+       .audio = &omap3pandora_audio_data,
+};
+
 static struct twl4030_platform_data omap3pandora_twldata = {
        .irq_base       = TWL4030_IRQ_BASE,
        .irq_end        = TWL4030_IRQ_END,
        .gpio           = &omap3pandora_gpio_data,
        .usb            = &omap3pandora_usb_data,
+       .codec          = &omap3pandora_codec_data,
        .vmmc1          = &pandora_vmmc1,
        .vmmc2          = &pandora_vmmc2,
        .keypad         = &pandora_kp_data,
@@ -387,6 +397,18 @@ static struct platform_device *omap3pandora_devices[] __initdata = {
        &pandora_keys_gpio,
 };
 
+static struct ehci_hcd_omap_platform_data ehci_pdata __initconst = {
+
+       .port_mode[0] = EHCI_HCD_OMAP_MODE_PHY,
+       .port_mode[1] = EHCI_HCD_OMAP_MODE_UNKNOWN,
+       .port_mode[2] = EHCI_HCD_OMAP_MODE_UNKNOWN,
+
+       .phy_reset  = true,
+       .reset_gpio_port[0]  = 16,
+       .reset_gpio_port[1]  = -EINVAL,
+       .reset_gpio_port[2]  = -EINVAL
+};
+
 static void __init omap3pandora_init(void)
 {
        omap3pandora_i2c_init();
@@ -396,6 +418,7 @@ static void __init omap3pandora_init(void)
        spi_register_board_info(omap3pandora_spi_board_info,
                        ARRAY_SIZE(omap3pandora_spi_board_info));
        omap3pandora_ads7846_init();
+       usb_ehci_init(&ehci_pdata);
        pandora_keys_gpio_init();
        usb_musb_init();
 
@@ -412,7 +435,7 @@ static void __init omap3pandora_map_io(void)
 
 MACHINE_START(OMAP3_PANDORA, "Pandora Handheld Console")
        .phys_io        = 0x48000000,
-       .io_pg_offst    = ((0xd8000000) >> 18) & 0xfffc,
+       .io_pg_offst    = ((0xfa000000) >> 18) & 0xfffc,
        .boot_params    = 0x80000100,
        .map_io         = omap3pandora_map_io,
        .init_irq       = omap3pandora_init_irq,
index 9917d2f..52dfd51 100644 (file)
 #include <asm/mach/flash.h>
 #include <asm/mach/map.h>
 
-#include <mach/board.h>
-#include <mach/common.h>
+#include <plat/board.h>
+#include <plat/common.h>
 #include <mach/gpio.h>
-#include <mach/gpmc.h>
+#include <plat/gpmc.h>
 #include <mach/hardware.h>
-#include <mach/nand.h>
-#include <mach/mux.h>
-#include <mach/usb.h>
+#include <plat/nand.h>
+#include <plat/mux.h>
+#include <plat/usb.h>
 
 #include "sdram-micron-mt46h32m32lf-6.h"
 #include "mmc-twl4030.h"
@@ -67,7 +67,7 @@
 #if defined(CONFIG_TOUCHSCREEN_ADS7846) || \
        defined(CONFIG_TOUCHSCREEN_ADS7846_MODULE)
 
-#include <mach/mcspi.h>
+#include <plat/mcspi.h>
 #include <linux/spi/spi.h>
 #include <linux/spi/ads7846.h>
 
@@ -329,6 +329,15 @@ static struct regulator_init_data overo_vmmc1 = {
        .consumer_supplies      = &overo_vmmc1_supply,
 };
 
+static struct twl4030_codec_audio_data overo_audio_data = {
+       .audio_mclk = 26000000,
+};
+
+static struct twl4030_codec_data overo_codec_data = {
+       .audio_mclk = 26000000,
+       .audio = &overo_audio_data,
+};
+
 /* mmc2 (WLAN) and Bluetooth don't use twl4030 regulators */
 
 static struct twl4030_platform_data overo_twldata = {
@@ -336,6 +345,7 @@ static struct twl4030_platform_data overo_twldata = {
        .irq_end        = TWL4030_IRQ_END,
        .gpio           = &overo_gpio_data,
        .usb            = &overo_usb_data,
+       .codec          = &overo_codec_data,
        .vmmc1          = &overo_vmmc1,
 };
 
@@ -384,6 +394,18 @@ static struct platform_device *overo_devices[] __initdata = {
        &overo_lcd_device,
 };
 
+static struct ehci_hcd_omap_platform_data ehci_pdata __initconst = {
+       .port_mode[0] = EHCI_HCD_OMAP_MODE_UNKNOWN,
+       .port_mode[1] = EHCI_HCD_OMAP_MODE_PHY,
+       .port_mode[2] = EHCI_HCD_OMAP_MODE_UNKNOWN,
+
+       .phy_reset  = true,
+       .reset_gpio_port[0]  = -EINVAL,
+       .reset_gpio_port[1]  = OVERO_GPIO_USBH_NRESET,
+       .reset_gpio_port[2]  = -EINVAL
+};
+
+
 static void __init overo_init(void)
 {
        overo_i2c_init();
@@ -391,6 +413,7 @@ static void __init overo_init(void)
        omap_serial_init();
        overo_flash_init();
        usb_musb_init();
+       usb_ehci_init(&ehci_pdata);
        overo_ads7846_init();
        overo_init_smsc911x();
 
@@ -433,14 +456,6 @@ static void __init overo_init(void)
        else
                printk(KERN_ERR "could not obtain gpio for "
                                        "OVERO_GPIO_USBH_CPEN\n");
-
-       if ((gpio_request(OVERO_GPIO_USBH_NRESET,
-                         "OVERO_GPIO_USBH_NRESET") == 0) &&
-           (gpio_direction_output(OVERO_GPIO_USBH_NRESET, 1) == 0))
-               gpio_export(OVERO_GPIO_USBH_NRESET, 0);
-       else
-               printk(KERN_ERR "could not obtain gpio for "
-                                       "OVERO_GPIO_USBH_NRESET\n");
 }
 
 static void __init overo_map_io(void)
@@ -451,7 +466,7 @@ static void __init overo_map_io(void)
 
 MACHINE_START(OVERO, "Gumstix Overo")
        .phys_io        = 0x48000000,
-       .io_pg_offst    = ((0xd8000000) >> 18) & 0xfffc,
+       .io_pg_offst    = ((0xfa000000) >> 18) & 0xfffc,
        .boot_params    = 0x80000100,
        .map_io         = overo_map_io,
        .init_irq       = overo_init_irq,
index e34d96a..15ce651 100644 (file)
 #include <linux/input.h>
 #include <linux/input/matrix_keypad.h>
 #include <linux/spi/spi.h>
+#include <linux/spi/wl12xx.h>
 #include <linux/i2c.h>
 #include <linux/i2c/twl4030.h>
 #include <linux/clk.h>
 #include <linux/delay.h>
 #include <linux/regulator/machine.h>
 #include <linux/gpio.h>
+#include <linux/gpio_keys.h>
 #include <linux/mmc/host.h>
 
-#include <mach/mcspi.h>
-#include <mach/mux.h>
-#include <mach/board.h>
-#include <mach/common.h>
-#include <mach/dma.h>
-#include <mach/gpmc.h>
-#include <mach/onenand.h>
-#include <mach/gpmc-smc91x.h>
+#include <plat/mcspi.h>
+#include <plat/mux.h>
+#include <plat/board.h>
+#include <plat/common.h>
+#include <plat/dma.h>
+#include <plat/gpmc.h>
+#include <plat/onenand.h>
+#include <plat/gpmc-smc91x.h>
 
 #include "mmc-twl4030.h"
 
 #define SYSTEM_REV_B_USES_VAUX3        0x1699
 #define SYSTEM_REV_S_USES_VAUX3 0x8
 
+#define RX51_WL1251_POWER_GPIO         87
+#define RX51_WL1251_IRQ_GPIO           42
+
+/* list all spi devices here */
+enum {
+       RX51_SPI_WL1251,
+};
+
+static struct wl12xx_platform_data wl1251_pdata;
+
+static struct omap2_mcspi_device_config wl1251_mcspi_config = {
+       .turbo_mode     = 0,
+       .single_channel = 1,
+};
+
+static struct spi_board_info rx51_peripherals_spi_board_info[] __initdata = {
+       [RX51_SPI_WL1251] = {
+               .modalias               = "wl1251",
+               .bus_num                = 4,
+               .chip_select            = 0,
+               .max_speed_hz           = 48000000,
+               .mode                   = SPI_MODE_2,
+               .controller_data        = &wl1251_mcspi_config,
+               .platform_data          = &wl1251_pdata,
+       },
+};
+
+#if defined(CONFIG_KEYBOARD_GPIO) || defined(CONFIG_KEYBOARD_GPIO_MODULE)
+
+#define RX51_GPIO_CAMERA_LENS_COVER    110
+#define RX51_GPIO_CAMERA_FOCUS         68
+#define RX51_GPIO_CAMERA_CAPTURE       69
+#define RX51_GPIO_KEYPAD_SLIDE         71
+#define RX51_GPIO_LOCK_BUTTON          113
+#define RX51_GPIO_PROXIMITY            89
+
+#define RX51_GPIO_DEBOUNCE_TIMEOUT     10
+
+static struct gpio_keys_button rx51_gpio_keys[] = {
+       {
+               .desc                   = "Camera Lens Cover",
+               .type                   = EV_SW,
+               .code                   = SW_CAMERA_LENS_COVER,
+               .gpio                   = RX51_GPIO_CAMERA_LENS_COVER,
+               .active_low             = 1,
+               .debounce_interval      = RX51_GPIO_DEBOUNCE_TIMEOUT,
+       }, {
+               .desc                   = "Camera Focus",
+               .type                   = EV_KEY,
+               .code                   = KEY_CAMERA_FOCUS,
+               .gpio                   = RX51_GPIO_CAMERA_FOCUS,
+               .active_low             = 1,
+               .debounce_interval      = RX51_GPIO_DEBOUNCE_TIMEOUT,
+       }, {
+               .desc                   = "Camera Capture",
+               .type                   = EV_KEY,
+               .code                   = KEY_CAMERA,
+               .gpio                   = RX51_GPIO_CAMERA_CAPTURE,
+               .active_low             = 1,
+               .debounce_interval      = RX51_GPIO_DEBOUNCE_TIMEOUT,
+       }, {
+               .desc                   = "Lock Button",
+               .type                   = EV_KEY,
+               .code                   = KEY_SCREENLOCK,
+               .gpio                   = RX51_GPIO_LOCK_BUTTON,
+               .active_low             = 1,
+               .debounce_interval      = RX51_GPIO_DEBOUNCE_TIMEOUT,
+       }, {
+               .desc                   = "Keypad Slide",
+               .type                   = EV_SW,
+               .code                   = SW_KEYPAD_SLIDE,
+               .gpio                   = RX51_GPIO_KEYPAD_SLIDE,
+               .active_low             = 1,
+               .debounce_interval      = RX51_GPIO_DEBOUNCE_TIMEOUT,
+       }, {
+               .desc                   = "Proximity Sensor",
+               .type                   = EV_SW,
+               .code                   = SW_FRONT_PROXIMITY,
+               .gpio                   = RX51_GPIO_PROXIMITY,
+               .active_low             = 0,
+               .debounce_interval      = RX51_GPIO_DEBOUNCE_TIMEOUT,
+       }
+};
+
+static struct gpio_keys_platform_data rx51_gpio_keys_data = {
+       .buttons        = rx51_gpio_keys,
+       .nbuttons       = ARRAY_SIZE(rx51_gpio_keys),
+};
+
+static struct platform_device rx51_gpio_keys_device = {
+       .name   = "gpio-keys",
+       .id     = -1,
+       .dev    = {
+               .platform_data  = &rx51_gpio_keys_data,
+       },
+};
+
+static void __init rx51_add_gpio_keys(void)
+{
+       platform_device_register(&rx51_gpio_keys_device);
+}
+#else
+static void __init rx51_add_gpio_keys(void)
+{
+}
+#endif /* CONFIG_KEYBOARD_GPIO || CONFIG_KEYBOARD_GPIO_MODULE */
+
 static int board_keymap[] = {
        KEY(0, 0, KEY_Q),
        KEY(0, 1, KEY_O),
@@ -536,10 +645,64 @@ static inline void board_smc91x_init(void)
 
 #endif
 
+static void rx51_wl1251_set_power(bool enable)
+{
+       gpio_set_value(RX51_WL1251_POWER_GPIO, enable);
+}
+
+static void __init rx51_init_wl1251(void)
+{
+       int irq, ret;
+
+       ret = gpio_request(RX51_WL1251_POWER_GPIO, "wl1251 power");
+       if (ret < 0)
+               goto error;
+
+       ret = gpio_direction_output(RX51_WL1251_POWER_GPIO, 0);
+       if (ret < 0)
+               goto err_power;
+
+       ret = gpio_request(RX51_WL1251_IRQ_GPIO, "wl1251 irq");
+       if (ret < 0)
+               goto err_power;
+
+       ret = gpio_direction_input(RX51_WL1251_IRQ_GPIO);
+       if (ret < 0)
+               goto err_irq;
+
+       irq = gpio_to_irq(RX51_WL1251_IRQ_GPIO);
+       if (irq < 0)
+               goto err_irq;
+
+       wl1251_pdata.set_power = rx51_wl1251_set_power;
+       rx51_peripherals_spi_board_info[RX51_SPI_WL1251].irq = irq;
+
+       return;
+
+err_irq:
+       gpio_free(RX51_WL1251_IRQ_GPIO);
+
+err_power:
+       gpio_free(RX51_WL1251_POWER_GPIO);
+
+error:
+       printk(KERN_ERR "wl1251 board initialisation failed\n");
+       wl1251_pdata.set_power = NULL;
+
+       /*
+        * Now rx51_peripherals_spi_board_info[1].irq is zero and
+        * set_power is null, and wl1251_probe() will fail.
+        */
+}
+
 void __init rx51_peripherals_init(void)
 {
        rx51_i2c_init();
        board_onenand_init();
        board_smc91x_init();
+       rx51_add_gpio_keys();
+       rx51_init_wl1251();
+       spi_register_board_info(rx51_peripherals_spi_board_info,
+                               ARRAY_SIZE(rx51_peripherals_spi_board_info));
 }
 
diff --git a/arch/arm/mach-omap2/board-rx51-sdram.c b/arch/arm/mach-omap2/board-rx51-sdram.c
new file mode 100644 (file)
index 0000000..f392844
--- /dev/null
@@ -0,0 +1,221 @@
+/*
+ * SDRC register values for RX51
+ *
+ * Copyright (C) 2008 Nokia Corporation
+ *
+ * Lauri Leukkunen <lauri.leukkunen@nokia.com>
+ *
+ * Original code by Juha Yrjola <juha.yrjola@solidboot.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/kernel.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/io.h>
+
+#include <plat/io.h>
+#include <plat/common.h>
+#include <plat/clock.h>
+#include <plat/sdrc.h>
+
+
+/* In picoseconds, except for tREF (ns), tXP, tCKE, tWTR (clks) */
+struct sdram_timings {
+       u32 casl;
+       u32 tDAL;
+       u32 tDPL;
+       u32 tRRD;
+       u32 tRCD;
+       u32 tRP;
+       u32 tRAS;
+       u32 tRC;
+       u32 tRFC;
+       u32 tXSR;
+
+       u32 tREF; /* in ns */
+
+       u32 tXP;
+       u32 tCKE;
+       u32 tWTR;
+};
+
+struct omap_sdrc_params rx51_sdrc_params[4];
+
+static const struct sdram_timings rx51_timings[] = {
+       {
+               .casl = 3,
+               .tDAL = 33000,
+               .tDPL = 15000,
+               .tRRD = 12000,
+               .tRCD = 22500,
+               .tRP = 18000,
+               .tRAS = 42000,
+               .tRC = 66000,
+               .tRFC = 138000,
+               .tXSR = 200000,
+
+               .tREF = 7800,
+
+               .tXP = 2,
+               .tCKE = 2,
+               .tWTR = 2
+       },
+};
+
+static unsigned long sdrc_get_fclk_period(long rate)
+{
+       /* In picoseconds */
+       return 1000000000 / rate;
+}
+
+static unsigned int sdrc_ps_to_ticks(unsigned int time_ps, long rate)
+{
+       unsigned long tick_ps;
+
+       /* Calculate in picosecs to yield more exact results */
+       tick_ps = sdrc_get_fclk_period(rate);
+
+       return (time_ps + tick_ps - 1) / tick_ps;
+}
+#undef DEBUG
+#ifdef DEBUG
+static int set_sdrc_timing_regval(u32 *regval, int st_bit, int end_bit,
+                               int ticks, long rate, const char *name)
+#else
+static int set_sdrc_timing_regval(u32 *regval, int st_bit, int end_bit,
+                              int ticks)
+#endif
+{
+       int mask, nr_bits;
+
+       nr_bits = end_bit - st_bit + 1;
+       if (ticks >= 1 << nr_bits)
+               return -1;
+       mask = (1 << nr_bits) - 1;
+       *regval &= ~(mask << st_bit);
+       *regval |= ticks << st_bit;
+#ifdef DEBUG
+       printk(KERN_INFO "SDRC %s: %i ticks %i ns\n", name, ticks,
+                       (unsigned int)sdrc_get_fclk_period(rate) * ticks /
+                       1000);
+#endif
+
+       return 0;
+}
+
+#ifdef DEBUG
+#define SDRC_SET_ONE(reg, st, end, field, rate) \
+       if (set_sdrc_timing_regval((reg), (st), (end), \
+                       rx51_timings->field, (rate), #field) < 0) \
+               err = -1;
+#else
+#define SDRC_SET_ONE(reg, st, end, field, rate) \
+       if (set_sdrc_timing_regval((reg), (st), (end), \
+                       rx51_timings->field) < 0) \
+               err = -1;
+#endif
+
+#ifdef DEBUG
+static int set_sdrc_timing_regval_ps(u32 *regval, int st_bit, int end_bit,
+                               int time, long rate, const char *name)
+#else
+static int set_sdrc_timing_regval_ps(u32 *regval, int st_bit, int end_bit,
+                               int time, long rate)
+#endif
+{
+       int ticks, ret;
+       ret = 0;
+
+       if (time == 0)
+               ticks = 0;
+       else
+               ticks = sdrc_ps_to_ticks(time, rate);
+
+#ifdef DEBUG
+       ret = set_sdrc_timing_regval(regval, st_bit, end_bit, ticks,
+                                    rate, name);
+#else
+       ret = set_sdrc_timing_regval(regval, st_bit, end_bit, ticks);
+#endif
+
+       return ret;
+}
+
+#ifdef DEBUG
+#define SDRC_SET_ONE_PS(reg, st, end, field, rate) \
+       if (set_sdrc_timing_regval_ps((reg), (st), (end), \
+                       rx51_timings->field, \
+                       (rate), #field) < 0) \
+               err = -1;
+
+#else
+#define SDRC_SET_ONE_PS(reg, st, end, field, rate) \
+       if (set_sdrc_timing_regval_ps((reg), (st), (end), \
+                       rx51_timings->field, (rate)) < 0) \
+               err = -1;
+#endif
+
+static int sdrc_timings(int id, long rate)
+{
+       u32 ticks_per_ms;
+       u32 rfr, l;
+       u32 actim_ctrla = 0, actim_ctrlb = 0;
+       u32 rfr_ctrl;
+       int err = 0;
+       long l3_rate = rate / 1000;
+
+       SDRC_SET_ONE_PS(&actim_ctrla,  0,  4, tDAL, l3_rate);
+       SDRC_SET_ONE_PS(&actim_ctrla,  6,  8, tDPL, l3_rate);
+       SDRC_SET_ONE_PS(&actim_ctrla,  9, 11, tRRD, l3_rate);
+       SDRC_SET_ONE_PS(&actim_ctrla, 12, 14, tRCD, l3_rate);
+       SDRC_SET_ONE_PS(&actim_ctrla, 15, 17, tRP, l3_rate);
+       SDRC_SET_ONE_PS(&actim_ctrla, 18, 21, tRAS, l3_rate);
+       SDRC_SET_ONE_PS(&actim_ctrla, 22, 26, tRC, l3_rate);
+       SDRC_SET_ONE_PS(&actim_ctrla, 27, 31, tRFC, l3_rate);
+
+       SDRC_SET_ONE_PS(&actim_ctrlb,  0,  7, tXSR, l3_rate);
+
+       SDRC_SET_ONE(&actim_ctrlb,  8, 10, tXP, l3_rate);
+       SDRC_SET_ONE(&actim_ctrlb, 12, 14, tCKE, l3_rate);
+       SDRC_SET_ONE(&actim_ctrlb, 16, 17, tWTR, l3_rate);
+
+       ticks_per_ms = l3_rate;
+       rfr = rx51_timings[0].tREF * ticks_per_ms / 1000000;
+       if (rfr > 65535 + 50)
+               rfr = 65535;
+       else
+               rfr -= 50;
+
+#ifdef DEBUG
+       printk(KERN_INFO "SDRC tREF: %i ticks\n", rfr);
+#endif
+
+       l = rfr << 8;
+       rfr_ctrl = l | 0x1; /* autorefresh, reload counter with 1xARCV */
+
+       rx51_sdrc_params[id].rate = rate;
+       rx51_sdrc_params[id].actim_ctrla = actim_ctrla;
+       rx51_sdrc_params[id].actim_ctrlb = actim_ctrlb;
+       rx51_sdrc_params[id].rfr_ctrl = rfr_ctrl;
+       rx51_sdrc_params[id].mr = 0x32;
+
+       rx51_sdrc_params[id + 1].rate = 0;
+
+       return err;
+}
+
+struct omap_sdrc_params *rx51_get_sdram_timings(void)
+{
+       int err;
+
+       err = sdrc_timings(0, 41500000);
+       err |= sdrc_timings(1, 83000000);
+       err |= sdrc_timings(2, 166000000);
+
+       return &rx51_sdrc_params[0];
+}
+
index 78869a9..1bb1de2 100644 (file)
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
 
-#include <mach/mcspi.h>
-#include <mach/mux.h>
-#include <mach/board.h>
-#include <mach/common.h>
-#include <mach/dma.h>
-#include <mach/gpmc.h>
-#include <mach/usb.h>
+#include <plat/mcspi.h>
+#include <plat/mux.h>
+#include <plat/board.h>
+#include <plat/common.h>
+#include <plat/dma.h>
+#include <plat/gpmc.h>
+#include <plat/usb.h>
+
+struct omap_sdrc_params *rx51_get_sdram_timings(void);
 
 static struct omap_lcd_config rx51_lcd_config = {
        .ctrl_name      = "internal",
@@ -55,9 +57,12 @@ static struct omap_board_config_kernel rx51_config[] = {
 
 static void __init rx51_init_irq(void)
 {
+       struct omap_sdrc_params *sdrc_params;
+
        omap_board_config = rx51_config;
        omap_board_config_size = ARRAY_SIZE(rx51_config);
-       omap2_init_common_hw(NULL, NULL);
+       sdrc_params = rx51_get_sdram_timings();
+       omap2_init_common_hw(sdrc_params, sdrc_params);
        omap_init_irq();
        omap_gpio_init();
 }
@@ -84,7 +89,7 @@ static void __init rx51_map_io(void)
 MACHINE_START(NOKIA_RX51, "Nokia RX-51 board")
        /* Maintainer: Lauri Leukkunen <lauri.leukkunen@nokia.com> */
        .phys_io        = 0x48000000,
-       .io_pg_offst    = ((0xd8000000) >> 18) & 0xfffc,
+       .io_pg_offst    = ((0xfa000000) >> 18) & 0xfffc,
        .boot_params    = 0x80000100,
        .map_io         = rx51_map_io,
        .init_irq       = rx51_init_irq,
index 1f13e2a..bb4018b 100644 (file)
 #include <linux/smsc911x.h>
 #include <linux/interrupt.h>
 
-#include <mach/gpmc.h>
+#include <plat/gpmc.h>
 
-#define ZOOM2_SMSC911X_CS      7
-#define ZOOM2_SMSC911X_GPIO    158
-#define ZOOM2_QUADUART_CS      3
-#define ZOOM2_QUADUART_GPIO    102
+#define ZOOM_SMSC911X_CS       7
+#define ZOOM_SMSC911X_GPIO     158
+#define ZOOM_QUADUART_CS       3
+#define ZOOM_QUADUART_GPIO     102
 #define QUART_CLK              1843200
 #define DEBUG_BASE             0x08000000
-#define ZOOM2_ETHR_START       DEBUG_BASE
+#define ZOOM_ETHR_START        DEBUG_BASE
 
-static struct resource zoom2_smsc911x_resources[] = {
+static struct resource zoom_smsc911x_resources[] = {
        [0] = {
-               .start  = ZOOM2_ETHR_START,
-               .end    = ZOOM2_ETHR_START + SZ_4K,
+               .start  = ZOOM_ETHR_START,
+               .end    = ZOOM_ETHR_START + SZ_4K,
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
@@ -35,42 +35,42 @@ static struct resource zoom2_smsc911x_resources[] = {
        },
 };
 
-static struct smsc911x_platform_config zoom2_smsc911x_config = {
+static struct smsc911x_platform_config zoom_smsc911x_config = {
        .irq_polarity   = SMSC911X_IRQ_POLARITY_ACTIVE_LOW,
        .irq_type       = SMSC911X_IRQ_TYPE_OPEN_DRAIN,
        .flags          = SMSC911X_USE_32BIT,
        .phy_interface  = PHY_INTERFACE_MODE_MII,
 };
 
-static struct platform_device zoom2_smsc911x_device = {
+static struct platform_device zoom_smsc911x_device = {
        .name           = "smsc911x",
        .id             = -1,
-       .num_resources  = ARRAY_SIZE(zoom2_smsc911x_resources),
-       .resource       = zoom2_smsc911x_resources,
+       .num_resources  = ARRAY_SIZE(zoom_smsc911x_resources),
+       .resource       = zoom_smsc911x_resources,
        .dev            = {
-               .platform_data = &zoom2_smsc911x_config,
+               .platform_data = &zoom_smsc911x_config,
        },
 };
 
-static inline void __init zoom2_init_smsc911x(void)
+static inline void __init zoom_init_smsc911x(void)
 {
        int eth_cs;
        unsigned long cs_mem_base;
        int eth_gpio = 0;
 
-       eth_cs = ZOOM2_SMSC911X_CS;
+       eth_cs = ZOOM_SMSC911X_CS;
 
        if (gpmc_cs_request(eth_cs, SZ_16M, &cs_mem_base) < 0) {
                printk(KERN_ERR "Failed to request GPMC mem for smsc911x\n");
                return;
        }
 
-       zoom2_smsc911x_resources[0].start = cs_mem_base + 0x0;
-       zoom2_smsc911x_resources[0].end   = cs_mem_base + 0xff;
+       zoom_smsc911x_resources[0].start = cs_mem_base + 0x0;
+       zoom_smsc911x_resources[0].end   = cs_mem_base + 0xff;
 
-       eth_gpio = ZOOM2_SMSC911X_GPIO;
+       eth_gpio = ZOOM_SMSC911X_GPIO;
 
-       zoom2_smsc911x_resources[1].start = OMAP_GPIO_IRQ(eth_gpio);
+       zoom_smsc911x_resources[1].start = OMAP_GPIO_IRQ(eth_gpio);
 
        if (gpio_request(eth_gpio, "smsc911x irq") < 0) {
                printk(KERN_ERR "Failed to request GPIO%d for smsc911x IRQ\n",
@@ -94,7 +94,7 @@ static struct plat_serial8250_port serial_platform_data[] = {
        }
 };
 
-static struct platform_device zoom2_debugboard_serial_device = {
+static struct platform_device zoom_debugboard_serial_device = {
        .name                   = "serial8250",
        .id                     = 3,
        .dev                    = {
@@ -102,13 +102,13 @@ static struct platform_device zoom2_debugboard_serial_device = {
        },
 };
 
-static inline void __init zoom2_init_quaduart(void)
+static inline void __init zoom_init_quaduart(void)
 {
        int quart_cs;
        unsigned long cs_mem_base;
        int quart_gpio = 0;
 
-       quart_cs = ZOOM2_QUADUART_CS;
+       quart_cs = ZOOM_QUADUART_CS;
 
        if (gpmc_cs_request(quart_cs, SZ_1M, &cs_mem_base) < 0) {
                printk(KERN_ERR "Failed to request GPMC mem"
@@ -116,7 +116,7 @@ static inline void __init zoom2_init_quaduart(void)
                return;
        }
 
-       quart_gpio = ZOOM2_QUADUART_GPIO;
+       quart_gpio = ZOOM_QUADUART_GPIO;
 
        if (gpio_request(quart_gpio, "TL16CP754C GPIO") < 0) {
                printk(KERN_ERR "Failed to request GPIO%d for TL16CP754C\n",
@@ -126,15 +126,15 @@ static inline void __init zoom2_init_quaduart(void)
        gpio_direction_input(quart_gpio);
 }
 
-static inline int omap_zoom2_debugboard_detect(void)
+static inline int omap_zoom_debugboard_detect(void)
 {
        int debug_board_detect = 0;
        int ret = 1;
 
-       debug_board_detect = ZOOM2_SMSC911X_GPIO;
+       debug_board_detect = ZOOM_SMSC911X_GPIO;
 
-       if (gpio_request(debug_board_detect, "Zoom2 debug board detect") < 0) {
-               printk(KERN_ERR "Failed to request GPIO%d for Zoom2 debug"
+       if (gpio_request(debug_board_detect, "Zoom debug board detect") < 0) {
+               printk(KERN_ERR "Failed to request GPIO%d for Zoom debug"
                "board detect\n", debug_board_detect);
                return 0;
        }
@@ -147,17 +147,17 @@ static inline int omap_zoom2_debugboard_detect(void)
        return ret;
 }
 
-static struct platform_device *zoom2_devices[] __initdata = {
-       &zoom2_smsc911x_device,
-       &zoom2_debugboard_serial_device,
+static struct platform_device *zoom_devices[] __initdata = {
+       &zoom_smsc911x_device,
+       &zoom_debugboard_serial_device,
 };
 
-int __init omap_zoom2_debugboard_init(void)
+int __init zoom_debugboard_init(void)
 {
-       if (!omap_zoom2_debugboard_detect())
+       if (!omap_zoom_debugboard_detect())
                return 0;
 
-       zoom2_init_smsc911x();
-       zoom2_init_quaduart();
-       return platform_add_devices(zoom2_devices, ARRAY_SIZE(zoom2_devices));
+       zoom_init_smsc911x();
+       zoom_init_quaduart();
+       return platform_add_devices(zoom_devices, ARRAY_SIZE(zoom_devices));
 }
diff --git a/arch/arm/mach-omap2/board-zoom-peripherals.c b/arch/arm/mach-omap2/board-zoom-peripherals.c
new file mode 100755 (executable)
index 0000000..f14baa3
--- /dev/null
@@ -0,0 +1,267 @@
+/*
+ * Copyright (C) 2009 Texas Instruments Inc.
+ *
+ * Modified from mach-omap2/board-zoom2.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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/input.h>
+#include <linux/input/matrix_keypad.h>
+#include <linux/gpio.h>
+#include <linux/i2c/twl4030.h>
+#include <linux/regulator/machine.h>
+
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+
+#include <plat/common.h>
+#include <plat/usb.h>
+
+#include "mmc-twl4030.h"
+
+/* Zoom2 has Qwerty keyboard*/
+static int board_keymap[] = {
+       KEY(0, 0, KEY_E),
+       KEY(0, 1, KEY_R),
+       KEY(0, 2, KEY_T),
+       KEY(0, 3, KEY_HOME),
+       KEY(0, 6, KEY_I),
+       KEY(0, 7, KEY_LEFTSHIFT),
+       KEY(1, 0, KEY_D),
+       KEY(1, 1, KEY_F),
+       KEY(1, 2, KEY_G),
+       KEY(1, 3, KEY_SEND),
+       KEY(1, 6, KEY_K),
+       KEY(1, 7, KEY_ENTER),
+       KEY(2, 0, KEY_X),
+       KEY(2, 1, KEY_C),
+       KEY(2, 2, KEY_V),
+       KEY(2, 3, KEY_END),
+       KEY(2, 6, KEY_DOT),
+       KEY(2, 7, KEY_CAPSLOCK),
+       KEY(3, 0, KEY_Z),
+       KEY(3, 1, KEY_KPPLUS),
+       KEY(3, 2, KEY_B),
+       KEY(3, 3, KEY_F1),
+       KEY(3, 6, KEY_O),
+       KEY(3, 7, KEY_SPACE),
+       KEY(4, 0, KEY_W),
+       KEY(4, 1, KEY_Y),
+       KEY(4, 2, KEY_U),
+       KEY(4, 3, KEY_F2),
+       KEY(4, 4, KEY_VOLUMEUP),
+       KEY(4, 6, KEY_L),
+       KEY(4, 7, KEY_LEFT),
+       KEY(5, 0, KEY_S),
+       KEY(5, 1, KEY_H),
+       KEY(5, 2, KEY_J),
+       KEY(5, 3, KEY_F3),
+       KEY(5, 5, KEY_VOLUMEDOWN),
+       KEY(5, 6, KEY_M),
+       KEY(5, 7, KEY_ENTER),
+       KEY(6, 0, KEY_Q),
+       KEY(6, 1, KEY_A),
+       KEY(6, 2, KEY_N),
+       KEY(6, 3, KEY_BACKSPACE),
+       KEY(6, 6, KEY_P),
+       KEY(6, 7, KEY_SELECT),
+       KEY(7, 0, KEY_PROG1),   /*MACRO 1 <User defined> */
+       KEY(7, 1, KEY_PROG2),   /*MACRO 2 <User defined> */
+       KEY(7, 2, KEY_PROG3),   /*MACRO 3 <User defined> */
+       KEY(7, 3, KEY_PROG4),   /*MACRO 4 <User defined> */
+       KEY(7, 5, KEY_RIGHT),
+       KEY(7, 6, KEY_UP),
+       KEY(7, 7, KEY_DOWN)
+};
+
+static struct matrix_keymap_data board_map_data = {
+       .keymap                 = board_keymap,
+       .keymap_size            = ARRAY_SIZE(board_keymap),
+};
+
+static struct twl4030_keypad_data zoom_kp_twl4030_data = {
+       .keymap_data    = &board_map_data,
+       .rows           = 8,
+       .cols           = 8,
+       .rep            = 1,
+};
+
+static struct regulator_consumer_supply zoom_vmmc1_supply = {
+       .supply         = "vmmc",
+};
+
+static struct regulator_consumer_supply zoom_vsim_supply = {
+       .supply         = "vmmc_aux",
+};
+
+static struct regulator_consumer_supply zoom_vmmc2_supply = {
+       .supply         = "vmmc",
+};
+
+/* VMMC1 for OMAP VDD_MMC1 (i/o) and MMC1 card */
+static struct regulator_init_data zoom_vmmc1 = {
+       .constraints = {
+               .min_uV                 = 1850000,
+               .max_uV                 = 3150000,
+               .valid_modes_mask       = REGULATOR_MODE_NORMAL
+                                       | REGULATOR_MODE_STANDBY,
+               .valid_ops_mask         = REGULATOR_CHANGE_VOLTAGE
+                                       | REGULATOR_CHANGE_MODE
+                                       | REGULATOR_CHANGE_STATUS,
+       },
+       .num_consumer_supplies  = 1,
+       .consumer_supplies      = &zoom_vmmc1_supply,
+};
+
+/* VMMC2 for MMC2 card */
+static struct regulator_init_data zoom_vmmc2 = {
+       .constraints = {
+               .min_uV                 = 1850000,
+               .max_uV                 = 1850000,
+               .apply_uV               = true,
+               .valid_modes_mask       = REGULATOR_MODE_NORMAL
+                                       | REGULATOR_MODE_STANDBY,
+               .valid_ops_mask         = REGULATOR_CHANGE_MODE
+                                       | REGULATOR_CHANGE_STATUS,
+       },
+       .num_consumer_supplies  = 1,
+       .consumer_supplies      = &zoom_vmmc2_supply,
+};
+
+/* VSIM for OMAP VDD_MMC1A (i/o for DAT4..DAT7) */
+static struct regulator_init_data zoom_vsim = {
+       .constraints = {
+               .min_uV                 = 1800000,
+               .max_uV                 = 3000000,
+               .valid_modes_mask       = REGULATOR_MODE_NORMAL
+                                       | REGULATOR_MODE_STANDBY,
+               .valid_ops_mask         = REGULATOR_CHANGE_VOLTAGE
+                                       | REGULATOR_CHANGE_MODE
+                                       | REGULATOR_CHANGE_STATUS,
+       },
+       .num_consumer_supplies  = 1,
+       .consumer_supplies      = &zoom_vsim_supply,
+};
+
+static struct twl4030_hsmmc_info mmc[] __initdata = {
+       {
+               .mmc            = 1,
+               .wires          = 4,
+               .gpio_wp        = -EINVAL,
+       },
+       {
+               .mmc            = 2,
+               .wires          = 4,
+               .gpio_wp        = -EINVAL,
+       },
+       {}      /* Terminator */
+};
+
+static int zoom_twl_gpio_setup(struct device *dev,
+               unsigned gpio, unsigned ngpio)
+{
+       /* gpio + 0 is "mmc0_cd" (input/IRQ),
+        * gpio + 1 is "mmc1_cd" (input/IRQ)
+        */
+       mmc[0].gpio_cd = gpio + 0;
+       mmc[1].gpio_cd = gpio + 1;
+       twl4030_mmc_init(mmc);
+
+       /* link regulators to MMC adapters ... we "know" the
+        * regulators will be set up only *after* we return.
+       */
+       zoom_vmmc1_supply.dev = mmc[0].dev;
+       zoom_vsim_supply.dev = mmc[0].dev;
+       zoom_vmmc2_supply.dev = mmc[1].dev;
+
+       return 0;
+}
+
+
+static int zoom_batt_table[] = {
+/* 0 C*/
+30800, 29500, 28300, 27100,
+26000, 24900, 23900, 22900, 22000, 21100, 20300, 19400, 18700, 17900,
+17200, 16500, 15900, 15300, 14700, 14100, 13600, 13100, 12600, 12100,
+11600, 11200, 10800, 10400, 10000, 9630,  9280,  8950,  8620,  8310,
+8020,  7730,  7460,  7200,  6950,  6710,  6470,  6250,  6040,  5830,
+5640,  5450,  5260,  5090,  4920,  4760,  4600,  4450,  4310,  4170,
+4040,  3910,  3790,  3670,  3550
+};
+
+static struct twl4030_bci_platform_data zoom_bci_data = {
+       .battery_tmp_tbl        = zoom_batt_table,
+       .tblsize                = ARRAY_SIZE(zoom_batt_table),
+};
+
+static struct twl4030_usb_data zoom_usb_data = {
+       .usb_mode       = T2_USB_MODE_ULPI,
+};
+
+static struct twl4030_gpio_platform_data zoom_gpio_data = {
+       .gpio_base      = OMAP_MAX_GPIO_LINES,
+       .irq_base       = TWL4030_GPIO_IRQ_BASE,
+       .irq_end        = TWL4030_GPIO_IRQ_END,
+       .setup          = zoom_twl_gpio_setup,
+};
+
+static struct twl4030_madc_platform_data zoom_madc_data = {
+       .irq_line       = 1,
+};
+
+static struct twl4030_codec_audio_data zoom_audio_data = {
+       .audio_mclk = 26000000,
+};
+
+static struct twl4030_codec_data zoom_codec_data = {
+       .audio_mclk = 26000000,
+       .audio = &zoom_audio_data,
+};
+
+static struct twl4030_platform_data zoom_twldata = {
+       .irq_base       = TWL4030_IRQ_BASE,
+       .irq_end        = TWL4030_IRQ_END,
+
+       /* platform_data for children goes here */
+       .bci            = &zoom_bci_data,
+       .madc           = &zoom_madc_data,
+       .usb            = &zoom_usb_data,
+       .gpio           = &zoom_gpio_data,
+       .keypad         = &zoom_kp_twl4030_data,
+       .codec          = &zoom_codec_data,
+       .vmmc2          = &zoom_vmmc2,
+       .vsim           = &zoom_vsim,
+
+};
+
+static struct i2c_board_info __initdata zoom_i2c_boardinfo[] = {
+       {
+               I2C_BOARD_INFO("twl5030", 0x48),
+               .flags          = I2C_CLIENT_WAKE,
+               .irq            = INT_34XX_SYS_NIRQ,
+               .platform_data  = &zoom_twldata,
+       },
+};
+
+static int __init omap_i2c_init(void)
+{
+       omap_register_i2c_bus(1, 2400, zoom_i2c_boardinfo,
+                       ARRAY_SIZE(zoom_i2c_boardinfo));
+       omap_register_i2c_bus(2, 400, NULL, 0);
+       omap_register_i2c_bus(3, 400, NULL, 0);
+       return 0;
+}
+
+void __init zoom_peripherals_init(void)
+{
+       omap_i2c_init();
+       omap_serial_init();
+       usb_musb_init();
+}
index 51e0b3b..d94d047 100644 (file)
 #include <linux/init.h>
 #include <linux/platform_device.h>
 #include <linux/input.h>
-#include <linux/input/matrix_keypad.h>
 #include <linux/gpio.h>
-#include <linux/i2c/twl4030.h>
-#include <linux/regulator/machine.h>
 
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 
-#include <mach/common.h>
-#include <mach/usb.h>
+#include <plat/common.h>
+#include <plat/board.h>
 
-#include "mmc-twl4030.h"
-#include "sdram-micron-mt46h32m32lf-6.h"
-
-/* Zoom2 has Qwerty keyboard*/
-static int board_keymap[] = {
-       KEY(0, 0, KEY_E),
-       KEY(0, 1, KEY_R),
-       KEY(0, 2, KEY_T),
-       KEY(0, 3, KEY_HOME),
-       KEY(0, 6, KEY_I),
-       KEY(0, 7, KEY_LEFTSHIFT),
-       KEY(1, 0, KEY_D),
-       KEY(1, 1, KEY_F),
-       KEY(1, 2, KEY_G),
-       KEY(1, 3, KEY_SEND),
-       KEY(1, 6, KEY_K),
-       KEY(1, 7, KEY_ENTER),
-       KEY(2, 0, KEY_X),
-       KEY(2, 1, KEY_C),
-       KEY(2, 2, KEY_V),
-       KEY(2, 3, KEY_END),
-       KEY(2, 6, KEY_DOT),
-       KEY(2, 7, KEY_CAPSLOCK),
-       KEY(3, 0, KEY_Z),
-       KEY(3, 1, KEY_KPPLUS),
-       KEY(3, 2, KEY_B),
-       KEY(3, 3, KEY_F1),
-       KEY(3, 6, KEY_O),
-       KEY(3, 7, KEY_SPACE),
-       KEY(4, 0, KEY_W),
-       KEY(4, 1, KEY_Y),
-       KEY(4, 2, KEY_U),
-       KEY(4, 3, KEY_F2),
-       KEY(4, 4, KEY_VOLUMEUP),
-       KEY(4, 6, KEY_L),
-       KEY(4, 7, KEY_LEFT),
-       KEY(5, 0, KEY_S),
-       KEY(5, 1, KEY_H),
-       KEY(5, 2, KEY_J),
-       KEY(5, 3, KEY_F3),
-       KEY(5, 5, KEY_VOLUMEDOWN),
-       KEY(5, 6, KEY_M),
-       KEY(5, 7, KEY_ENTER),
-       KEY(6, 0, KEY_Q),
-       KEY(6, 1, KEY_A),
-       KEY(6, 2, KEY_N),
-       KEY(6, 3, KEY_BACKSPACE),
-       KEY(6, 6, KEY_P),
-       KEY(6, 7, KEY_SELECT),
-       KEY(7, 0, KEY_PROG1),   /*MACRO 1 <User defined> */
-       KEY(7, 1, KEY_PROG2),   /*MACRO 2 <User defined> */
-       KEY(7, 2, KEY_PROG3),   /*MACRO 3 <User defined> */
-       KEY(7, 3, KEY_PROG4),   /*MACRO 4 <User defined> */
-       KEY(7, 5, KEY_RIGHT),
-       KEY(7, 6, KEY_UP),
-       KEY(7, 7, KEY_DOWN)
-};
-
-static struct matrix_keymap_data board_map_data = {
-       .keymap                 = board_keymap,
-       .keymap_size            = ARRAY_SIZE(board_keymap),
-};
-
-static struct twl4030_keypad_data zoom2_kp_twl4030_data = {
-       .keymap_data    = &board_map_data,
-       .rows           = 8,
-       .cols           = 8,
-       .rep            = 1,
-};
-
-static struct omap_board_config_kernel zoom2_config[] __initdata = {
-};
-
-static struct regulator_consumer_supply zoom2_vmmc1_supply = {
-       .supply         = "vmmc",
-};
-
-static struct regulator_consumer_supply zoom2_vsim_supply = {
-       .supply         = "vmmc_aux",
-};
-
-static struct regulator_consumer_supply zoom2_vmmc2_supply = {
-       .supply         = "vmmc",
-};
-
-/* VMMC1 for OMAP VDD_MMC1 (i/o) and MMC1 card */
-static struct regulator_init_data zoom2_vmmc1 = {
-       .constraints = {
-               .min_uV                 = 1850000,
-               .max_uV                 = 3150000,
-               .valid_modes_mask       = REGULATOR_MODE_NORMAL
-                                       | REGULATOR_MODE_STANDBY,
-               .valid_ops_mask         = REGULATOR_CHANGE_VOLTAGE
-                                       | REGULATOR_CHANGE_MODE
-                                       | REGULATOR_CHANGE_STATUS,
-       },
-       .num_consumer_supplies  = 1,
-       .consumer_supplies      = &zoom2_vmmc1_supply,
-};
-
-/* VMMC2 for MMC2 card */
-static struct regulator_init_data zoom2_vmmc2 = {
-       .constraints = {
-               .min_uV                 = 1850000,
-               .max_uV                 = 1850000,
-               .apply_uV               = true,
-               .valid_modes_mask       = REGULATOR_MODE_NORMAL
-                                       | REGULATOR_MODE_STANDBY,
-               .valid_ops_mask         = REGULATOR_CHANGE_MODE
-                                       | REGULATOR_CHANGE_STATUS,
-       },
-       .num_consumer_supplies  = 1,
-       .consumer_supplies      = &zoom2_vmmc2_supply,
-};
-
-/* VSIM for OMAP VDD_MMC1A (i/o for DAT4..DAT7) */
-static struct regulator_init_data zoom2_vsim = {
-       .constraints = {
-               .min_uV                 = 1800000,
-               .max_uV                 = 3000000,
-               .valid_modes_mask       = REGULATOR_MODE_NORMAL
-                                       | REGULATOR_MODE_STANDBY,
-               .valid_ops_mask         = REGULATOR_CHANGE_VOLTAGE
-                                       | REGULATOR_CHANGE_MODE
-                                       | REGULATOR_CHANGE_STATUS,
-       },
-       .num_consumer_supplies  = 1,
-       .consumer_supplies      = &zoom2_vsim_supply,
-};
-
-static struct twl4030_hsmmc_info mmc[] __initdata = {
-       {
-               .mmc            = 1,
-               .wires          = 4,
-               .gpio_wp        = -EINVAL,
-       },
-       {
-               .mmc            = 2,
-               .wires          = 4,
-               .gpio_wp        = -EINVAL,
-       },
-       {}      /* Terminator */
-};
+#include <mach/board-zoom.h>
 
-static int zoom2_twl_gpio_setup(struct device *dev,
-               unsigned gpio, unsigned ngpio)
-{
-       /* gpio + 0 is "mmc0_cd" (input/IRQ),
-        * gpio + 1 is "mmc1_cd" (input/IRQ)
-        */
-       mmc[0].gpio_cd = gpio + 0;
-       mmc[1].gpio_cd = gpio + 1;
-       twl4030_mmc_init(mmc);
-
-       /* link regulators to MMC adapters ... we "know" the
-        * regulators will be set up only *after* we return.
-       */
-       zoom2_vmmc1_supply.dev = mmc[0].dev;
-       zoom2_vsim_supply.dev = mmc[0].dev;
-       zoom2_vmmc2_supply.dev = mmc[1].dev;
-
-       return 0;
-}
-
-
-static int zoom2_batt_table[] = {
-/* 0 C*/
-30800, 29500, 28300, 27100,
-26000, 24900, 23900, 22900, 22000, 21100, 20300, 19400, 18700, 17900,
-17200, 16500, 15900, 15300, 14700, 14100, 13600, 13100, 12600, 12100,
-11600, 11200, 10800, 10400, 10000, 9630,  9280,  8950,  8620,  8310,
-8020,  7730,  7460,  7200,  6950,  6710,  6470,  6250,  6040,  5830,
-5640,  5450,  5260,  5090,  4920,  4760,  4600,  4450,  4310,  4170,
-4040,  3910,  3790,  3670,  3550
-};
-
-static struct twl4030_bci_platform_data zoom2_bci_data = {
-       .battery_tmp_tbl        = zoom2_batt_table,
-       .tblsize                = ARRAY_SIZE(zoom2_batt_table),
-};
-
-static struct twl4030_usb_data zoom2_usb_data = {
-       .usb_mode       = T2_USB_MODE_ULPI,
-};
+#include "sdram-micron-mt46h32m32lf-6.h"
 
 static void __init omap_zoom2_init_irq(void)
 {
-       omap_board_config = zoom2_config;
-       omap_board_config_size = ARRAY_SIZE(zoom2_config);
        omap2_init_common_hw(mt46h32m32lf6_sdrc_params,
                                 mt46h32m32lf6_sdrc_params);
        omap_init_irq();
        omap_gpio_init();
 }
 
-static struct twl4030_gpio_platform_data zoom2_gpio_data = {
-       .gpio_base      = OMAP_MAX_GPIO_LINES,
-       .irq_base       = TWL4030_GPIO_IRQ_BASE,
-       .irq_end        = TWL4030_GPIO_IRQ_END,
-       .setup          = zoom2_twl_gpio_setup,
-};
+/* REVISIT: These audio entries can be removed once MFD code is merged */
+#if 0
 
 static struct twl4030_madc_platform_data zoom2_madc_data = {
        .irq_line       = 1,
 };
 
+static struct twl4030_codec_audio_data zoom2_audio_data = {
+       .audio_mclk = 26000000,
+};
+
+static struct twl4030_codec_data zoom2_codec_data = {
+       .audio_mclk = 26000000,
+       .audio = &zoom2_audio_data,
+};
+
 static struct twl4030_platform_data zoom2_twldata = {
        .irq_base       = TWL4030_IRQ_BASE,
        .irq_end        = TWL4030_IRQ_END,
@@ -240,38 +59,19 @@ static struct twl4030_platform_data zoom2_twldata = {
        .usb            = &zoom2_usb_data,
        .gpio           = &zoom2_gpio_data,
        .keypad         = &zoom2_kp_twl4030_data,
+       .codec          = &zoom2_codec_data,
        .vmmc1          = &zoom2_vmmc1,
        .vmmc2          = &zoom2_vmmc2,
        .vsim           = &zoom2_vsim,
 
 };
 
-static struct i2c_board_info __initdata zoom2_i2c_boardinfo[] = {
-       {
-               I2C_BOARD_INFO("twl4030", 0x48),
-               .flags          = I2C_CLIENT_WAKE,
-               .irq            = INT_34XX_SYS_NIRQ,
-               .platform_data  = &zoom2_twldata,
-       },
-};
-
-static int __init omap_i2c_init(void)
-{
-       omap_register_i2c_bus(1, 2600, zoom2_i2c_boardinfo,
-                       ARRAY_SIZE(zoom2_i2c_boardinfo));
-       omap_register_i2c_bus(2, 400, NULL, 0);
-       omap_register_i2c_bus(3, 400, NULL, 0);
-       return 0;
-}
-
-extern int __init omap_zoom2_debugboard_init(void);
+#endif
 
 static void __init omap_zoom2_init(void)
 {
-       omap_i2c_init();
-       omap_serial_init();
-       omap_zoom2_debugboard_init();
-       usb_musb_init();
+       zoom_peripherals_init();
+       zoom_debugboard_init();
 }
 
 static void __init omap_zoom2_map_io(void)
@@ -282,7 +82,7 @@ static void __init omap_zoom2_map_io(void)
 
 MACHINE_START(OMAP_ZOOM2, "OMAP Zoom2 board")
        .phys_io        = 0x48000000,
-       .io_pg_offst    = ((0xd8000000) >> 18) & 0xfffc,
+       .io_pg_offst    = ((0xfa000000) >> 18) & 0xfffc,
        .boot_params    = 0x80000100,
        .map_io         = omap_zoom2_map_io,
        .init_irq       = omap_zoom2_init_irq,
diff --git a/arch/arm/mach-omap2/board-zoom3.c b/arch/arm/mach-omap2/board-zoom3.c
new file mode 100644 (file)
index 0000000..8d965a6
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2009 Texas Instruments Inc.
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/input.h>
+#include <linux/gpio.h>
+
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+
+#include <mach/board-zoom.h>
+
+#include <plat/common.h>
+#include <plat/board.h>
+
+#include "sdram-hynix-h8mbx00u0mer-0em.h"
+
+static void __init omap_zoom_map_io(void)
+{
+       omap2_set_globals_343x();
+       omap2_map_common_io();
+}
+
+static struct omap_board_config_kernel zoom_config[] __initdata = {
+};
+
+static void __init omap_zoom_init_irq(void)
+{
+       omap_board_config = zoom_config;
+       omap_board_config_size = ARRAY_SIZE(zoom_config);
+       omap2_init_common_hw(h8mbx00u0mer0em_sdrc_params,
+                       h8mbx00u0mer0em_sdrc_params);
+       omap_init_irq();
+       omap_gpio_init();
+}
+
+static void __init omap_zoom_init(void)
+{
+       zoom_peripherals_init();
+       zoom_debugboard_init();
+}
+
+MACHINE_START(OMAP_ZOOM3, "OMAP Zoom3 board")
+       .phys_io        = 0x48000000,
+       .io_pg_offst    = ((0xfa000000) >> 18) & 0xfffc,
+       .boot_params    = 0x80000100,
+       .map_io         = omap_zoom_map_io,
+       .init_irq       = omap_zoom_init_irq,
+       .init_machine   = omap_zoom_init,
+       .timer          = &omap_timer,
+MACHINE_END
index f2a92d6..4716206 100644 (file)
 #include <linux/io.h>
 #include <linux/bitops.h>
 
-#include <mach/clock.h>
-#include <mach/clockdomain.h>
-#include <mach/cpu.h>
-#include <mach/prcm.h>
+#include <plat/clock.h>
+#include <plat/clockdomain.h>
+#include <plat/cpu.h>
+#include <plat/prcm.h>
 #include <asm/div64.h>
 
-#include <mach/sdrc.h>
+#include <plat/sdrc.h>
 #include "sdrc.h"
 #include "clock.h"
 #include "prm.h"
index 9ae7540..43b6bed 100644 (file)
@@ -16,7 +16,7 @@
 #ifndef __ARCH_ARM_MACH_OMAP2_CLOCK_H
 #define __ARCH_ARM_MACH_OMAP2_CLOCK_H
 
-#include <mach/clock.h>
+#include <plat/clock.h>
 
 /* The maximum error between a target DPLL rate and the rounded rate in Hz */
 #define DEFAULT_DPLL_RATE_TOLERANCE    50000
index e2dbedd..e70e7e0 100644 (file)
 #include <linux/cpufreq.h>
 #include <linux/bitops.h>
 
-#include <mach/clock.h>
-#include <mach/sram.h>
-#include <mach/prcm.h>
+#include <plat/clock.h>
+#include <plat/sram.h>
+#include <plat/prcm.h>
 #include <asm/div64.h>
 #include <asm/clkdev.h>
 
-#include <mach/sdrc.h>
+#include <plat/sdrc.h>
 #include "clock.h"
 #include "prm.h"
 #include "prm-regbits-24xx.h"
index 7c5c00d..9f2feaf 100644 (file)
 #include <linux/limits.h>
 #include <linux/bitops.h>
 
-#include <mach/cpu.h>
-#include <mach/clock.h>
-#include <mach/sram.h>
+#include <plat/cpu.h>
+#include <plat/clock.h>
+#include <plat/sram.h>
 #include <asm/div64.h>
 #include <asm/clkdev.h>
 
-#include <mach/sdrc.h>
+#include <plat/sdrc.h>
 #include "clock.h"
 #include "prm.h"
 #include "prm-regbits-34xx.h"
@@ -119,7 +119,7 @@ static struct omap_clk omap34xx_clks[] = {
        CLK(NULL,       "dpll3_m2x2_ck", &dpll3_m2x2_ck, CK_343X),
        CLK(NULL,       "dpll3_m3_ck",  &dpll3_m3_ck,   CK_343X),
        CLK(NULL,       "dpll3_m3x2_ck", &dpll3_m3x2_ck, CK_343X),
-       CLK(NULL,       "emu_core_alwon_ck", &emu_core_alwon_ck, CK_343X),
+       CLK("etb",      "emu_core_alwon_ck", &emu_core_alwon_ck, CK_343X),
        CLK(NULL,       "dpll4_ck",     &dpll4_ck,      CK_343X),
        CLK(NULL,       "dpll4_x2_ck",  &dpll4_x2_ck,   CK_343X),
        CLK(NULL,       "omap_96m_alwon_fck", &omap_96m_alwon_fck, CK_343X),
@@ -138,7 +138,7 @@ static struct omap_clk omap34xx_clks[] = {
        CLK(NULL,       "dpll4_m5x2_ck", &dpll4_m5x2_ck, CK_343X),
        CLK(NULL,       "dpll4_m6_ck",  &dpll4_m6_ck,   CK_343X),
        CLK(NULL,       "dpll4_m6x2_ck", &dpll4_m6x2_ck, CK_343X),
-       CLK(NULL,       "emu_per_alwon_ck", &emu_per_alwon_ck, CK_343X),
+       CLK("etb",      "emu_per_alwon_ck", &emu_per_alwon_ck, CK_343X),
        CLK(NULL,       "dpll5_ck",     &dpll5_ck,      CK_3430ES2),
        CLK(NULL,       "dpll5_m2_ck",  &dpll5_m2_ck,   CK_3430ES2),
        CLK(NULL,       "clkout2_src_ck", &clkout2_src_ck, CK_343X),
@@ -147,7 +147,7 @@ static struct omap_clk omap34xx_clks[] = {
        CLK(NULL,       "dpll1_fck",    &dpll1_fck,     CK_343X),
        CLK(NULL,       "mpu_ck",       &mpu_ck,        CK_343X),
        CLK(NULL,       "arm_fck",      &arm_fck,       CK_343X),
-       CLK(NULL,       "emu_mpu_alwon_ck", &emu_mpu_alwon_ck, CK_343X),
+       CLK("etb",      "emu_mpu_alwon_ck", &emu_mpu_alwon_ck, CK_343X),
        CLK(NULL,       "dpll2_fck",    &dpll2_fck,     CK_343X),
        CLK(NULL,       "iva2_ck",      &iva2_ck,       CK_343X),
        CLK(NULL,       "l3_ick",       &l3_ick,        CK_343X),
@@ -302,7 +302,7 @@ static struct omap_clk omap34xx_clks[] = {
        CLK("omap-mcbsp.2", "fck",      &mcbsp2_fck,    CK_343X),
        CLK("omap-mcbsp.3", "fck",      &mcbsp3_fck,    CK_343X),
        CLK("omap-mcbsp.4", "fck",      &mcbsp4_fck,    CK_343X),
-       CLK(NULL,       "emu_src_ck",   &emu_src_ck,    CK_343X),
+       CLK("etb",      "emu_src_ck",   &emu_src_ck,    CK_343X),
        CLK(NULL,       "pclk_fck",     &pclk_fck,      CK_343X),
        CLK(NULL,       "pclkx2_fck",   &pclkx2_fck,    CK_343X),
        CLK(NULL,       "atclk_fck",    &atclk_fck,     CK_343X),
index 9565c05..8fe1bcb 100644 (file)
@@ -19,7 +19,7 @@
 #ifndef __ARCH_ARM_MACH_OMAP2_CLOCK34XX_H
 #define __ARCH_ARM_MACH_OMAP2_CLOCK34XX_H
 
-#include <mach/control.h>
+#include <plat/control.h>
 
 #include "clock.h"
 #include "cm.h"
index 58aff84..fcd8232 100644 (file)
 
 #include <linux/bitops.h>
 
-#include <mach/clock.h>
+#include <plat/clock.h>
 
 #include "prm.h"
 #include "prm-regbits-24xx.h"
 #include "cm.h"
 
-#include <mach/powerdomain.h>
-#include <mach/clockdomain.h>
+#include <plat/powerdomain.h>
+#include <plat/clockdomain.h>
 
 /* clkdm_list contains all registered struct clockdomains */
 static LIST_HEAD(clkdm_list);
index fe319ae..c4ee076 100644 (file)
@@ -10,7 +10,7 @@
 #ifndef __ARCH_ARM_MACH_OMAP2_CLOCKDOMAINS_H
 #define __ARCH_ARM_MACH_OMAP2_CLOCKDOMAINS_H
 
-#include <mach/clockdomain.h>
+#include <plat/clockdomain.h>
 
 /*
  * OMAP2/3-common clockdomains
index cfd0b72..a2fcfcc 100644 (file)
 #include "prcm-common.h"
 
 #define OMAP2420_CM_REGADDR(module, reg)                               \
-                       OMAP2_IO_ADDRESS(OMAP2420_CM_BASE + (module) + (reg))
+                       OMAP2_L4_IO_ADDRESS(OMAP2420_CM_BASE + (module) + (reg))
 #define OMAP2430_CM_REGADDR(module, reg)                               \
-                       OMAP2_IO_ADDRESS(OMAP2430_CM_BASE + (module) + (reg))
+                       OMAP2_L4_IO_ADDRESS(OMAP2430_CM_BASE + (module) + (reg))
 #define OMAP34XX_CM_REGADDR(module, reg)                               \
-                       OMAP2_IO_ADDRESS(OMAP3430_CM_BASE + (module) + (reg))
+                       OMAP2_L4_IO_ADDRESS(OMAP3430_CM_BASE + (module) + (reg))
 
 /*
  * Architecture-specific global CM registers
index 5f3aad9..cdd1f35 100644 (file)
 #include <linux/kernel.h>
 #include <linux/io.h>
 
-#include <mach/common.h>
-#include <mach/control.h>
+#include <plat/common.h>
+#include <plat/control.h>
+#include <plat/sdrc.h>
+#include "cm-regbits-34xx.h"
+#include "prm-regbits-34xx.h"
+#include "cm.h"
+#include "prm.h"
+#include "sdrc.h"
 
 static void __iomem *omap2_ctrl_base;
 
+#if defined(CONFIG_ARCH_OMAP3) && defined(CONFIG_PM)
+struct omap3_scratchpad {
+       u32 boot_config_ptr;
+       u32 public_restore_ptr;
+       u32 secure_ram_restore_ptr;
+       u32 sdrc_module_semaphore;
+       u32 prcm_block_offset;
+       u32 sdrc_block_offset;
+};
+
+struct omap3_scratchpad_prcm_block {
+       u32 prm_clksrc_ctrl;
+       u32 prm_clksel;
+       u32 cm_clksel_core;
+       u32 cm_clksel_wkup;
+       u32 cm_clken_pll;
+       u32 cm_autoidle_pll;
+       u32 cm_clksel1_pll;
+       u32 cm_clksel2_pll;
+       u32 cm_clksel3_pll;
+       u32 cm_clken_pll_mpu;
+       u32 cm_autoidle_pll_mpu;
+       u32 cm_clksel1_pll_mpu;
+       u32 cm_clksel2_pll_mpu;
+       u32 prcm_block_size;
+};
+
+struct omap3_scratchpad_sdrc_block {
+       u16 sysconfig;
+       u16 cs_cfg;
+       u16 sharing;
+       u16 err_type;
+       u32 dll_a_ctrl;
+       u32 dll_b_ctrl;
+       u32 power;
+       u32 cs_0;
+       u32 mcfg_0;
+       u16 mr_0;
+       u16 emr_1_0;
+       u16 emr_2_0;
+       u16 emr_3_0;
+       u32 actim_ctrla_0;
+       u32 actim_ctrlb_0;
+       u32 rfr_ctrl_0;
+       u32 cs_1;
+       u32 mcfg_1;
+       u16 mr_1;
+       u16 emr_1_1;
+       u16 emr_2_1;
+       u16 emr_3_1;
+       u32 actim_ctrla_1;
+       u32 actim_ctrlb_1;
+       u32 rfr_ctrl_1;
+       u16 dcdl_1_ctrl;
+       u16 dcdl_2_ctrl;
+       u32 flags;
+       u32 block_size;
+};
+
+void *omap3_secure_ram_storage;
+
+/*
+ * This is used to store ARM registers in SDRAM before attempting
+ * an MPU OFF. The save and restore happens from the SRAM sleep code.
+ * The address is stored in scratchpad, so that it can be used
+ * during the restore path.
+ */
+u32 omap3_arm_context[128];
+
+struct omap3_control_regs {
+       u32 sysconfig;
+       u32 devconf0;
+       u32 mem_dftrw0;
+       u32 mem_dftrw1;
+       u32 msuspendmux_0;
+       u32 msuspendmux_1;
+       u32 msuspendmux_2;
+       u32 msuspendmux_3;
+       u32 msuspendmux_4;
+       u32 msuspendmux_5;
+       u32 sec_ctrl;
+       u32 devconf1;
+       u32 csirxfe;
+       u32 iva2_bootaddr;
+       u32 iva2_bootmod;
+       u32 debobs_0;
+       u32 debobs_1;
+       u32 debobs_2;
+       u32 debobs_3;
+       u32 debobs_4;
+       u32 debobs_5;
+       u32 debobs_6;
+       u32 debobs_7;
+       u32 debobs_8;
+       u32 prog_io0;
+       u32 prog_io1;
+       u32 dss_dpll_spreading;
+       u32 core_dpll_spreading;
+       u32 per_dpll_spreading;
+       u32 usbhost_dpll_spreading;
+       u32 pbias_lite;
+       u32 temp_sensor;
+       u32 sramldo4;
+       u32 sramldo5;
+       u32 csi;
+};
+
+static struct omap3_control_regs control_context;
+#endif /* CONFIG_ARCH_OMAP3 && CONFIG_PM */
+
 #define OMAP_CTRL_REGADDR(reg)         (omap2_ctrl_base + (reg))
 
 void __init omap2_set_globals_control(struct omap_globals *omap2_globals)
@@ -62,3 +178,268 @@ void omap_ctrl_writel(u32 val, u16 offset)
        __raw_writel(val, OMAP_CTRL_REGADDR(offset));
 }
 
+#if defined(CONFIG_ARCH_OMAP3) && defined(CONFIG_PM)
+/*
+ * Clears the scratchpad contents in case of cold boot-
+ * called during bootup
+ */
+void omap3_clear_scratchpad_contents(void)
+{
+       u32 max_offset = OMAP343X_SCRATCHPAD_ROM_OFFSET;
+       u32 *v_addr;
+       u32 offset = 0;
+       v_addr = OMAP2_L4_IO_ADDRESS(OMAP343X_SCRATCHPAD_ROM);
+       if (prm_read_mod_reg(OMAP3430_GR_MOD, OMAP3_PRM_RSTST_OFFSET) &
+               OMAP3430_GLOBAL_COLD_RST) {
+               for ( ; offset <= max_offset; offset += 0x4)
+                       __raw_writel(0x0, (v_addr + offset));
+               prm_set_mod_reg_bits(OMAP3430_GLOBAL_COLD_RST, OMAP3430_GR_MOD,
+                       OMAP3_PRM_RSTST_OFFSET);
+       }
+}
+
+/* Populate the scratchpad structure with restore structure */
+void omap3_save_scratchpad_contents(void)
+{
+       void * __iomem scratchpad_address;
+       u32 arm_context_addr;
+       struct omap3_scratchpad scratchpad_contents;
+       struct omap3_scratchpad_prcm_block prcm_block_contents;
+       struct omap3_scratchpad_sdrc_block sdrc_block_contents;
+
+       /* Populate the Scratchpad contents */
+       scratchpad_contents.boot_config_ptr = 0x0;
+       if (omap_rev() != OMAP3430_REV_ES3_0 &&
+                                       omap_rev() != OMAP3430_REV_ES3_1)
+               scratchpad_contents.public_restore_ptr =
+                       virt_to_phys(get_restore_pointer());
+       else
+               scratchpad_contents.public_restore_ptr =
+                       virt_to_phys(get_es3_restore_pointer());
+       if (omap_type() == OMAP2_DEVICE_TYPE_GP)
+               scratchpad_contents.secure_ram_restore_ptr = 0x0;
+       else
+               scratchpad_contents.secure_ram_restore_ptr =
+                       (u32) __pa(omap3_secure_ram_storage);
+       scratchpad_contents.sdrc_module_semaphore = 0x0;
+       scratchpad_contents.prcm_block_offset = 0x2C;
+       scratchpad_contents.sdrc_block_offset = 0x64;
+
+       /* Populate the PRCM block contents */
+       prcm_block_contents.prm_clksrc_ctrl = prm_read_mod_reg(OMAP3430_GR_MOD,
+                       OMAP3_PRM_CLKSRC_CTRL_OFFSET);
+       prcm_block_contents.prm_clksel = prm_read_mod_reg(OMAP3430_CCR_MOD,
+                       OMAP3_PRM_CLKSEL_OFFSET);
+       prcm_block_contents.cm_clksel_core =
+                       cm_read_mod_reg(CORE_MOD, CM_CLKSEL);
+       prcm_block_contents.cm_clksel_wkup =
+                       cm_read_mod_reg(WKUP_MOD, CM_CLKSEL);
+       prcm_block_contents.cm_clken_pll =
+                       cm_read_mod_reg(PLL_MOD, CM_CLKEN);
+       prcm_block_contents.cm_autoidle_pll =
+                       cm_read_mod_reg(PLL_MOD, OMAP3430_CM_AUTOIDLE_PLL);
+       prcm_block_contents.cm_clksel1_pll =
+                       cm_read_mod_reg(PLL_MOD, OMAP3430_CM_CLKSEL1_PLL);
+       prcm_block_contents.cm_clksel2_pll =
+                       cm_read_mod_reg(PLL_MOD, OMAP3430_CM_CLKSEL2_PLL);
+       prcm_block_contents.cm_clksel3_pll =
+                       cm_read_mod_reg(PLL_MOD, OMAP3430_CM_CLKSEL3);
+       prcm_block_contents.cm_clken_pll_mpu =
+                       cm_read_mod_reg(MPU_MOD, OMAP3430_CM_CLKEN_PLL);
+       prcm_block_contents.cm_autoidle_pll_mpu =
+                       cm_read_mod_reg(MPU_MOD, OMAP3430_CM_AUTOIDLE_PLL);
+       prcm_block_contents.cm_clksel1_pll_mpu =
+                       cm_read_mod_reg(MPU_MOD, OMAP3430_CM_CLKSEL1_PLL);
+       prcm_block_contents.cm_clksel2_pll_mpu =
+                       cm_read_mod_reg(MPU_MOD, OMAP3430_CM_CLKSEL2_PLL);
+       prcm_block_contents.prcm_block_size = 0x0;
+
+       /* Populate the SDRC block contents */
+       sdrc_block_contents.sysconfig =
+                       (sdrc_read_reg(SDRC_SYSCONFIG) & 0xFFFF);
+       sdrc_block_contents.cs_cfg =
+                       (sdrc_read_reg(SDRC_CS_CFG) & 0xFFFF);
+       sdrc_block_contents.sharing =
+                       (sdrc_read_reg(SDRC_SHARING) & 0xFFFF);
+       sdrc_block_contents.err_type =
+                       (sdrc_read_reg(SDRC_ERR_TYPE) & 0xFFFF);
+       sdrc_block_contents.dll_a_ctrl = sdrc_read_reg(SDRC_DLLA_CTRL);
+       sdrc_block_contents.dll_b_ctrl = 0x0;
+       /*
+        * Due to a OMAP3 errata (1.142), on EMU/HS devices SRDC should
+        * be programed to issue automatic self refresh on timeout
+        * of AUTO_CNT = 1 prior to any transition to OFF mode.
+        */
+       if ((omap_type() != OMAP2_DEVICE_TYPE_GP)
+                       && (omap_rev() >= OMAP3430_REV_ES3_0))
+               sdrc_block_contents.power = (sdrc_read_reg(SDRC_POWER) &
+                               ~(SDRC_POWER_AUTOCOUNT_MASK|
+                               SDRC_POWER_CLKCTRL_MASK)) |
+                               (1 << SDRC_POWER_AUTOCOUNT_SHIFT) |
+                               SDRC_SELF_REFRESH_ON_AUTOCOUNT;
+       else
+               sdrc_block_contents.power = sdrc_read_reg(SDRC_POWER);
+
+       sdrc_block_contents.cs_0 = 0x0;
+       sdrc_block_contents.mcfg_0 = sdrc_read_reg(SDRC_MCFG_0);
+       sdrc_block_contents.mr_0 = (sdrc_read_reg(SDRC_MR_0) & 0xFFFF);
+       sdrc_block_contents.emr_1_0 = 0x0;
+       sdrc_block_contents.emr_2_0 = 0x0;
+       sdrc_block_contents.emr_3_0 = 0x0;
+       sdrc_block_contents.actim_ctrla_0 =
+                       sdrc_read_reg(SDRC_ACTIM_CTRL_A_0);
+       sdrc_block_contents.actim_ctrlb_0 =
+                       sdrc_read_reg(SDRC_ACTIM_CTRL_B_0);
+       sdrc_block_contents.rfr_ctrl_0 =
+                       sdrc_read_reg(SDRC_RFR_CTRL_0);
+       sdrc_block_contents.cs_1 = 0x0;
+       sdrc_block_contents.mcfg_1 = sdrc_read_reg(SDRC_MCFG_1);
+       sdrc_block_contents.mr_1 = sdrc_read_reg(SDRC_MR_1) & 0xFFFF;
+       sdrc_block_contents.emr_1_1 = 0x0;
+       sdrc_block_contents.emr_2_1 = 0x0;
+       sdrc_block_contents.emr_3_1 = 0x0;
+       sdrc_block_contents.actim_ctrla_1 =
+                       sdrc_read_reg(SDRC_ACTIM_CTRL_A_1);
+       sdrc_block_contents.actim_ctrlb_1 =
+                       sdrc_read_reg(SDRC_ACTIM_CTRL_B_1);
+       sdrc_block_contents.rfr_ctrl_1 =
+                       sdrc_read_reg(SDRC_RFR_CTRL_1);
+       sdrc_block_contents.dcdl_1_ctrl = 0x0;
+       sdrc_block_contents.dcdl_2_ctrl = 0x0;
+       sdrc_block_contents.flags = 0x0;
+       sdrc_block_contents.block_size = 0x0;
+
+       arm_context_addr = virt_to_phys(omap3_arm_context);
+
+       /* Copy all the contents to the scratchpad location */
+       scratchpad_address = OMAP2_L4_IO_ADDRESS(OMAP343X_SCRATCHPAD);
+       memcpy_toio(scratchpad_address, &scratchpad_contents,
+                sizeof(scratchpad_contents));
+       /* Scratchpad contents being 32 bits, a divide by 4 done here */
+       memcpy_toio(scratchpad_address +
+               scratchpad_contents.prcm_block_offset,
+               &prcm_block_contents, sizeof(prcm_block_contents));
+       memcpy_toio(scratchpad_address +
+               scratchpad_contents.sdrc_block_offset,
+               &sdrc_block_contents, sizeof(sdrc_block_contents));
+       /*
+        * Copies the address of the location in SDRAM where ARM
+        * registers get saved during a MPU OFF transition.
+        */
+       memcpy_toio(scratchpad_address +
+               scratchpad_contents.sdrc_block_offset +
+               sizeof(sdrc_block_contents), &arm_context_addr, 4);
+}
+
+void omap3_control_save_context(void)
+{
+       control_context.sysconfig = omap_ctrl_readl(OMAP2_CONTROL_SYSCONFIG);
+       control_context.devconf0 = omap_ctrl_readl(OMAP2_CONTROL_DEVCONF0);
+       control_context.mem_dftrw0 =
+                       omap_ctrl_readl(OMAP343X_CONTROL_MEM_DFTRW0);
+       control_context.mem_dftrw1 =
+                       omap_ctrl_readl(OMAP343X_CONTROL_MEM_DFTRW1);
+       control_context.msuspendmux_0 =
+                       omap_ctrl_readl(OMAP2_CONTROL_MSUSPENDMUX_0);
+       control_context.msuspendmux_1 =
+                       omap_ctrl_readl(OMAP2_CONTROL_MSUSPENDMUX_1);
+       control_context.msuspendmux_2 =
+                       omap_ctrl_readl(OMAP2_CONTROL_MSUSPENDMUX_2);
+       control_context.msuspendmux_3 =
+                       omap_ctrl_readl(OMAP2_CONTROL_MSUSPENDMUX_3);
+       control_context.msuspendmux_4 =
+                       omap_ctrl_readl(OMAP2_CONTROL_MSUSPENDMUX_4);
+       control_context.msuspendmux_5 =
+                       omap_ctrl_readl(OMAP2_CONTROL_MSUSPENDMUX_5);
+       control_context.sec_ctrl = omap_ctrl_readl(OMAP2_CONTROL_SEC_CTRL);
+       control_context.devconf1 = omap_ctrl_readl(OMAP343X_CONTROL_DEVCONF1);
+       control_context.csirxfe = omap_ctrl_readl(OMAP343X_CONTROL_CSIRXFE);
+       control_context.iva2_bootaddr =
+                       omap_ctrl_readl(OMAP343X_CONTROL_IVA2_BOOTADDR);
+       control_context.iva2_bootmod =
+                       omap_ctrl_readl(OMAP343X_CONTROL_IVA2_BOOTMOD);
+       control_context.debobs_0 = omap_ctrl_readl(OMAP343X_CONTROL_DEBOBS(0));
+       control_context.debobs_1 = omap_ctrl_readl(OMAP343X_CONTROL_DEBOBS(1));
+       control_context.debobs_2 = omap_ctrl_readl(OMAP343X_CONTROL_DEBOBS(2));
+       control_context.debobs_3 = omap_ctrl_readl(OMAP343X_CONTROL_DEBOBS(3));
+       control_context.debobs_4 = omap_ctrl_readl(OMAP343X_CONTROL_DEBOBS(4));
+       control_context.debobs_5 = omap_ctrl_readl(OMAP343X_CONTROL_DEBOBS(5));
+       control_context.debobs_6 = omap_ctrl_readl(OMAP343X_CONTROL_DEBOBS(6));
+       control_context.debobs_7 = omap_ctrl_readl(OMAP343X_CONTROL_DEBOBS(7));
+       control_context.debobs_8 = omap_ctrl_readl(OMAP343X_CONTROL_DEBOBS(8));
+       control_context.prog_io0 = omap_ctrl_readl(OMAP343X_CONTROL_PROG_IO0);
+       control_context.prog_io1 = omap_ctrl_readl(OMAP343X_CONTROL_PROG_IO1);
+       control_context.dss_dpll_spreading =
+                       omap_ctrl_readl(OMAP343X_CONTROL_DSS_DPLL_SPREADING);
+       control_context.core_dpll_spreading =
+                       omap_ctrl_readl(OMAP343X_CONTROL_CORE_DPLL_SPREADING);
+       control_context.per_dpll_spreading =
+                       omap_ctrl_readl(OMAP343X_CONTROL_PER_DPLL_SPREADING);
+       control_context.usbhost_dpll_spreading =
+               omap_ctrl_readl(OMAP343X_CONTROL_USBHOST_DPLL_SPREADING);
+       control_context.pbias_lite =
+                       omap_ctrl_readl(OMAP343X_CONTROL_PBIAS_LITE);
+       control_context.temp_sensor =
+                       omap_ctrl_readl(OMAP343X_CONTROL_TEMP_SENSOR);
+       control_context.sramldo4 = omap_ctrl_readl(OMAP343X_CONTROL_SRAMLDO4);
+       control_context.sramldo5 = omap_ctrl_readl(OMAP343X_CONTROL_SRAMLDO5);
+       control_context.csi = omap_ctrl_readl(OMAP343X_CONTROL_CSI);
+       return;
+}
+
+void omap3_control_restore_context(void)
+{
+       omap_ctrl_writel(control_context.sysconfig, OMAP2_CONTROL_SYSCONFIG);
+       omap_ctrl_writel(control_context.devconf0, OMAP2_CONTROL_DEVCONF0);
+       omap_ctrl_writel(control_context.mem_dftrw0,
+                                       OMAP343X_CONTROL_MEM_DFTRW0);
+       omap_ctrl_writel(control_context.mem_dftrw1,
+                                       OMAP343X_CONTROL_MEM_DFTRW1);
+       omap_ctrl_writel(control_context.msuspendmux_0,
+                                       OMAP2_CONTROL_MSUSPENDMUX_0);
+       omap_ctrl_writel(control_context.msuspendmux_1,
+                                       OMAP2_CONTROL_MSUSPENDMUX_1);
+       omap_ctrl_writel(control_context.msuspendmux_2,
+                                       OMAP2_CONTROL_MSUSPENDMUX_2);
+       omap_ctrl_writel(control_context.msuspendmux_3,
+                                       OMAP2_CONTROL_MSUSPENDMUX_3);
+       omap_ctrl_writel(control_context.msuspendmux_4,
+                                       OMAP2_CONTROL_MSUSPENDMUX_4);
+       omap_ctrl_writel(control_context.msuspendmux_5,
+                                       OMAP2_CONTROL_MSUSPENDMUX_5);
+       omap_ctrl_writel(control_context.sec_ctrl, OMAP2_CONTROL_SEC_CTRL);
+       omap_ctrl_writel(control_context.devconf1, OMAP343X_CONTROL_DEVCONF1);
+       omap_ctrl_writel(control_context.csirxfe, OMAP343X_CONTROL_CSIRXFE);
+       omap_ctrl_writel(control_context.iva2_bootaddr,
+                                       OMAP343X_CONTROL_IVA2_BOOTADDR);
+       omap_ctrl_writel(control_context.iva2_bootmod,
+                                       OMAP343X_CONTROL_IVA2_BOOTMOD);
+       omap_ctrl_writel(control_context.debobs_0, OMAP343X_CONTROL_DEBOBS(0));
+       omap_ctrl_writel(control_context.debobs_1, OMAP343X_CONTROL_DEBOBS(1));
+       omap_ctrl_writel(control_context.debobs_2, OMAP343X_CONTROL_DEBOBS(2));
+       omap_ctrl_writel(control_context.debobs_3, OMAP343X_CONTROL_DEBOBS(3));
+       omap_ctrl_writel(control_context.debobs_4, OMAP343X_CONTROL_DEBOBS(4));
+       omap_ctrl_writel(control_context.debobs_5, OMAP343X_CONTROL_DEBOBS(5));
+       omap_ctrl_writel(control_context.debobs_6, OMAP343X_CONTROL_DEBOBS(6));
+       omap_ctrl_writel(control_context.debobs_7, OMAP343X_CONTROL_DEBOBS(7));
+       omap_ctrl_writel(control_context.debobs_8, OMAP343X_CONTROL_DEBOBS(8));
+       omap_ctrl_writel(control_context.prog_io0, OMAP343X_CONTROL_PROG_IO0);
+       omap_ctrl_writel(control_context.prog_io1, OMAP343X_CONTROL_PROG_IO1);
+       omap_ctrl_writel(control_context.dss_dpll_spreading,
+                                       OMAP343X_CONTROL_DSS_DPLL_SPREADING);
+       omap_ctrl_writel(control_context.core_dpll_spreading,
+                                       OMAP343X_CONTROL_CORE_DPLL_SPREADING);
+       omap_ctrl_writel(control_context.per_dpll_spreading,
+                                       OMAP343X_CONTROL_PER_DPLL_SPREADING);
+       omap_ctrl_writel(control_context.usbhost_dpll_spreading,
+                               OMAP343X_CONTROL_USBHOST_DPLL_SPREADING);
+       omap_ctrl_writel(control_context.pbias_lite,
+                                       OMAP343X_CONTROL_PBIAS_LITE);
+       omap_ctrl_writel(control_context.temp_sensor,
+                                       OMAP343X_CONTROL_TEMP_SENSOR);
+       omap_ctrl_writel(control_context.sramldo4, OMAP343X_CONTROL_SRAMLDO4);
+       omap_ctrl_writel(control_context.sramldo5, OMAP343X_CONTROL_SRAMLDO5);
+       omap_ctrl_writel(control_context.csi, OMAP343X_CONTROL_CSI);
+       return;
+}
+#endif /* CONFIG_ARCH_OMAP3 && CONFIG_PM */
diff --git a/arch/arm/mach-omap2/cpuidle34xx.c b/arch/arm/mach-omap2/cpuidle34xx.c
new file mode 100644 (file)
index 0000000..a26d6a0
--- /dev/null
@@ -0,0 +1,318 @@
+/*
+ * linux/arch/arm/mach-omap2/cpuidle34xx.c
+ *
+ * OMAP3 CPU IDLE Routines
+ *
+ * Copyright (C) 2008 Texas Instruments, Inc.
+ * Rajendra Nayak <rnayak@ti.com>
+ *
+ * Copyright (C) 2007 Texas Instruments, Inc.
+ * Karthik Dasu <karthik-dp@ti.com>
+ *
+ * Copyright (C) 2006 Nokia Corporation
+ * Tony Lindgren <tony@atomide.com>
+ *
+ * Copyright (C) 2005 Texas Instruments, Inc.
+ * Richard Woodruff <r-woodruff2@ti.com>
+ *
+ * Based on pm.c for omap2
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/sched.h>
+#include <linux/cpuidle.h>
+
+#include <plat/prcm.h>
+#include <plat/irqs.h>
+#include <plat/powerdomain.h>
+#include <plat/clockdomain.h>
+#include <plat/control.h>
+#include <plat/serial.h>
+
+#include "pm.h"
+
+#ifdef CONFIG_CPU_IDLE
+
+#define OMAP3_MAX_STATES 7
+#define OMAP3_STATE_C1 0 /* C1 - MPU WFI + Core active */
+#define OMAP3_STATE_C2 1 /* C2 - MPU WFI + Core inactive */
+#define OMAP3_STATE_C3 2 /* C3 - MPU CSWR + Core inactive */
+#define OMAP3_STATE_C4 3 /* C4 - MPU OFF + Core iactive */
+#define OMAP3_STATE_C5 4 /* C5 - MPU RET + Core RET */
+#define OMAP3_STATE_C6 5 /* C6 - MPU OFF + Core RET */
+#define OMAP3_STATE_C7 6 /* C7 - MPU OFF + Core OFF */
+
+struct omap3_processor_cx {
+       u8 valid;
+       u8 type;
+       u32 sleep_latency;
+       u32 wakeup_latency;
+       u32 mpu_state;
+       u32 core_state;
+       u32 threshold;
+       u32 flags;
+};
+
+struct omap3_processor_cx omap3_power_states[OMAP3_MAX_STATES];
+struct omap3_processor_cx current_cx_state;
+struct powerdomain *mpu_pd, *core_pd;
+
+static int omap3_idle_bm_check(void)
+{
+       if (!omap3_can_sleep())
+               return 1;
+       return 0;
+}
+
+static int _cpuidle_allow_idle(struct powerdomain *pwrdm,
+                               struct clockdomain *clkdm)
+{
+       omap2_clkdm_allow_idle(clkdm);
+       return 0;
+}
+
+static int _cpuidle_deny_idle(struct powerdomain *pwrdm,
+                               struct clockdomain *clkdm)
+{
+       omap2_clkdm_deny_idle(clkdm);
+       return 0;
+}
+
+/**
+ * omap3_enter_idle - Programs OMAP3 to enter the specified state
+ * @dev: cpuidle device
+ * @state: The target state to be programmed
+ *
+ * Called from the CPUidle framework to program the device to the
+ * specified target state selected by the governor.
+ */
+static int omap3_enter_idle(struct cpuidle_device *dev,
+                       struct cpuidle_state *state)
+{
+       struct omap3_processor_cx *cx = cpuidle_get_statedata(state);
+       struct timespec ts_preidle, ts_postidle, ts_idle;
+       u32 mpu_state = cx->mpu_state, core_state = cx->core_state;
+
+       current_cx_state = *cx;
+
+       /* Used to keep track of the total time in idle */
+       getnstimeofday(&ts_preidle);
+
+       local_irq_disable();
+       local_fiq_disable();
+
+       if (!enable_off_mode) {
+               if (mpu_state < PWRDM_POWER_RET)
+                       mpu_state = PWRDM_POWER_RET;
+               if (core_state < PWRDM_POWER_RET)
+                       core_state = PWRDM_POWER_RET;
+       }
+
+       pwrdm_set_next_pwrst(mpu_pd, mpu_state);
+       pwrdm_set_next_pwrst(core_pd, core_state);
+
+       if (omap_irq_pending() || need_resched())
+               goto return_sleep_time;
+
+       if (cx->type == OMAP3_STATE_C1) {
+               pwrdm_for_each_clkdm(mpu_pd, _cpuidle_deny_idle);
+               pwrdm_for_each_clkdm(core_pd, _cpuidle_deny_idle);
+       }
+
+       /* Execute ARM wfi */
+       omap_sram_idle();
+
+       if (cx->type == OMAP3_STATE_C1) {
+               pwrdm_for_each_clkdm(mpu_pd, _cpuidle_allow_idle);
+               pwrdm_for_each_clkdm(core_pd, _cpuidle_allow_idle);
+       }
+
+return_sleep_time:
+       getnstimeofday(&ts_postidle);
+       ts_idle = timespec_sub(ts_postidle, ts_preidle);
+
+       local_irq_enable();
+       local_fiq_enable();
+
+       return (u32)timespec_to_ns(&ts_idle)/1000;
+}
+
+/**
+ * omap3_enter_idle_bm - Checks for any bus activity
+ * @dev: cpuidle device
+ * @state: The target state to be programmed
+ *
+ * Used for C states with CPUIDLE_FLAG_CHECK_BM flag set. This
+ * function checks for any pending activity and then programs the
+ * device to the specified or a safer state.
+ */
+static int omap3_enter_idle_bm(struct cpuidle_device *dev,
+                              struct cpuidle_state *state)
+{
+       struct cpuidle_state *new_state = state;
+
+       if ((state->flags & CPUIDLE_FLAG_CHECK_BM) && omap3_idle_bm_check()) {
+               BUG_ON(!dev->safe_state);
+               new_state = dev->safe_state;
+       }
+
+       dev->last_state = new_state;
+       return omap3_enter_idle(dev, new_state);
+}
+
+DEFINE_PER_CPU(struct cpuidle_device, omap3_idle_dev);
+
+/* omap3_init_power_states - Initialises the OMAP3 specific C states.
+ *
+ * Below is the desciption of each C state.
+ *     C1 . MPU WFI + Core active
+ *     C2 . MPU WFI + Core inactive
+ *     C3 . MPU CSWR + Core inactive
+ *     C4 . MPU OFF + Core inactive
+ *     C5 . MPU CSWR + Core CSWR
+ *     C6 . MPU OFF + Core CSWR
+ *     C7 . MPU OFF + Core OFF
+ */
+void omap_init_power_states(void)
+{
+       /* C1 . MPU WFI + Core active */
+       omap3_power_states[OMAP3_STATE_C1].valid = 1;
+       omap3_power_states[OMAP3_STATE_C1].type = OMAP3_STATE_C1;
+       omap3_power_states[OMAP3_STATE_C1].sleep_latency = 2;
+       omap3_power_states[OMAP3_STATE_C1].wakeup_latency = 2;
+       omap3_power_states[OMAP3_STATE_C1].threshold = 5;
+       omap3_power_states[OMAP3_STATE_C1].mpu_state = PWRDM_POWER_ON;
+       omap3_power_states[OMAP3_STATE_C1].core_state = PWRDM_POWER_ON;
+       omap3_power_states[OMAP3_STATE_C1].flags = CPUIDLE_FLAG_TIME_VALID;
+
+       /* C2 . MPU WFI + Core inactive */
+       omap3_power_states[OMAP3_STATE_C2].valid = 1;
+       omap3_power_states[OMAP3_STATE_C2].type = OMAP3_STATE_C2;
+       omap3_power_states[OMAP3_STATE_C2].sleep_latency = 10;
+       omap3_power_states[OMAP3_STATE_C2].wakeup_latency = 10;
+       omap3_power_states[OMAP3_STATE_C2].threshold = 30;
+       omap3_power_states[OMAP3_STATE_C2].mpu_state = PWRDM_POWER_ON;
+       omap3_power_states[OMAP3_STATE_C2].core_state = PWRDM_POWER_ON;
+       omap3_power_states[OMAP3_STATE_C2].flags = CPUIDLE_FLAG_TIME_VALID;
+
+       /* C3 . MPU CSWR + Core inactive */
+       omap3_power_states[OMAP3_STATE_C3].valid = 1;
+       omap3_power_states[OMAP3_STATE_C3].type = OMAP3_STATE_C3;
+       omap3_power_states[OMAP3_STATE_C3].sleep_latency = 50;
+       omap3_power_states[OMAP3_STATE_C3].wakeup_latency = 50;
+       omap3_power_states[OMAP3_STATE_C3].threshold = 300;
+       omap3_power_states[OMAP3_STATE_C3].mpu_state = PWRDM_POWER_RET;
+       omap3_power_states[OMAP3_STATE_C3].core_state = PWRDM_POWER_ON;
+       omap3_power_states[OMAP3_STATE_C3].flags = CPUIDLE_FLAG_TIME_VALID |
+                               CPUIDLE_FLAG_CHECK_BM;
+
+       /* C4 . MPU OFF + Core inactive */
+       omap3_power_states[OMAP3_STATE_C4].valid = 1;
+       omap3_power_states[OMAP3_STATE_C4].type = OMAP3_STATE_C4;
+       omap3_power_states[OMAP3_STATE_C4].sleep_latency = 1500;
+       omap3_power_states[OMAP3_STATE_C4].wakeup_latency = 1800;
+       omap3_power_states[OMAP3_STATE_C4].threshold = 4000;
+       omap3_power_states[OMAP3_STATE_C4].mpu_state = PWRDM_POWER_OFF;
+       omap3_power_states[OMAP3_STATE_C4].core_state = PWRDM_POWER_ON;
+       omap3_power_states[OMAP3_STATE_C4].flags = CPUIDLE_FLAG_TIME_VALID |
+                               CPUIDLE_FLAG_CHECK_BM;
+
+       /* C5 . MPU CSWR + Core CSWR*/
+       omap3_power_states[OMAP3_STATE_C5].valid = 1;
+       omap3_power_states[OMAP3_STATE_C5].type = OMAP3_STATE_C5;
+       omap3_power_states[OMAP3_STATE_C5].sleep_latency = 2500;
+       omap3_power_states[OMAP3_STATE_C5].wakeup_latency = 7500;
+       omap3_power_states[OMAP3_STATE_C5].threshold = 12000;
+       omap3_power_states[OMAP3_STATE_C5].mpu_state = PWRDM_POWER_RET;
+       omap3_power_states[OMAP3_STATE_C5].core_state = PWRDM_POWER_RET;
+       omap3_power_states[OMAP3_STATE_C5].flags = CPUIDLE_FLAG_TIME_VALID |
+                               CPUIDLE_FLAG_CHECK_BM;
+
+       /* C6 . MPU OFF + Core CSWR */
+       omap3_power_states[OMAP3_STATE_C6].valid = 1;
+       omap3_power_states[OMAP3_STATE_C6].type = OMAP3_STATE_C6;
+       omap3_power_states[OMAP3_STATE_C6].sleep_latency = 3000;
+       omap3_power_states[OMAP3_STATE_C6].wakeup_latency = 8500;
+       omap3_power_states[OMAP3_STATE_C6].threshold = 15000;
+       omap3_power_states[OMAP3_STATE_C6].mpu_state = PWRDM_POWER_OFF;
+       omap3_power_states[OMAP3_STATE_C6].core_state = PWRDM_POWER_RET;
+       omap3_power_states[OMAP3_STATE_C6].flags = CPUIDLE_FLAG_TIME_VALID |
+                               CPUIDLE_FLAG_CHECK_BM;
+
+       /* C7 . MPU OFF + Core OFF */
+       omap3_power_states[OMAP3_STATE_C7].valid = 1;
+       omap3_power_states[OMAP3_STATE_C7].type = OMAP3_STATE_C7;
+       omap3_power_states[OMAP3_STATE_C7].sleep_latency = 10000;
+       omap3_power_states[OMAP3_STATE_C7].wakeup_latency = 30000;
+       omap3_power_states[OMAP3_STATE_C7].threshold = 300000;
+       omap3_power_states[OMAP3_STATE_C7].mpu_state = PWRDM_POWER_OFF;
+       omap3_power_states[OMAP3_STATE_C7].core_state = PWRDM_POWER_OFF;
+       omap3_power_states[OMAP3_STATE_C7].flags = CPUIDLE_FLAG_TIME_VALID |
+                               CPUIDLE_FLAG_CHECK_BM;
+}
+
+struct cpuidle_driver omap3_idle_driver = {
+       .name =         "omap3_idle",
+       .owner =        THIS_MODULE,
+};
+
+/**
+ * omap3_idle_init - Init routine for OMAP3 idle
+ *
+ * Registers the OMAP3 specific cpuidle driver with the cpuidle
+ * framework with the valid set of states.
+ */
+int __init omap3_idle_init(void)
+{
+       int i, count = 0;
+       struct omap3_processor_cx *cx;
+       struct cpuidle_state *state;
+       struct cpuidle_device *dev;
+
+       mpu_pd = pwrdm_lookup("mpu_pwrdm");
+       core_pd = pwrdm_lookup("core_pwrdm");
+
+       omap_init_power_states();
+       cpuidle_register_driver(&omap3_idle_driver);
+
+       dev = &per_cpu(omap3_idle_dev, smp_processor_id());
+
+       for (i = OMAP3_STATE_C1; i < OMAP3_MAX_STATES; i++) {
+               cx = &omap3_power_states[i];
+               state = &dev->states[count];
+
+               if (!cx->valid)
+                       continue;
+               cpuidle_set_statedata(state, cx);
+               state->exit_latency = cx->sleep_latency + cx->wakeup_latency;
+               state->target_residency = cx->threshold;
+               state->flags = cx->flags;
+               state->enter = (state->flags & CPUIDLE_FLAG_CHECK_BM) ?
+                       omap3_enter_idle_bm : omap3_enter_idle;
+               if (cx->type == OMAP3_STATE_C1)
+                       dev->safe_state = state;
+               sprintf(state->name, "C%d", count+1);
+               count++;
+       }
+
+       if (!count)
+               return -EINVAL;
+       dev->state_count = count;
+
+       if (cpuidle_register_device(dev)) {
+               printk(KERN_ERR "%s: CPUidle register device failed\n",
+                      __func__);
+               return -EIO;
+       }
+
+       return 0;
+}
+#else
+int __init omap3_idle_init(void)
+{
+       return 0;
+}
+#endif /* CONFIG_CPU_IDLE */
index faf7a1e..733d3dc 100644 (file)
 #include <asm/mach-types.h>
 #include <asm/mach/map.h>
 
-#include <mach/control.h>
-#include <mach/tc.h>
-#include <mach/board.h>
-#include <mach/mux.h>
+#include <plat/control.h>
+#include <plat/tc.h>
+#include <plat/board.h>
+#include <plat/mux.h>
 #include <mach/gpio.h>
-#include <mach/mmc.h>
+#include <plat/mmc.h>
 
 #if defined(CONFIG_VIDEO_OMAP2) || defined(CONFIG_VIDEO_OMAP2_MODULE)
 
@@ -136,9 +136,10 @@ static inline void omap_init_camera(void)
 
 #if defined(CONFIG_OMAP_MBOX_FWK) || defined(CONFIG_OMAP_MBOX_FWK_MODULE)
 
-#define MBOX_REG_SIZE  0x120
+#define MBOX_REG_SIZE   0x120
 
-static struct resource omap2_mbox_resources[] = {
+#ifdef CONFIG_ARCH_OMAP2
+static struct resource omap_mbox_resources[] = {
        {
                .start          = OMAP24XX_MAILBOX_BASE,
                .end            = OMAP24XX_MAILBOX_BASE + MBOX_REG_SIZE - 1,
@@ -153,8 +154,10 @@ static struct resource omap2_mbox_resources[] = {
                .flags          = IORESOURCE_IRQ,
        },
 };
+#endif
 
-static struct resource omap3_mbox_resources[] = {
+#ifdef CONFIG_ARCH_OMAP3
+static struct resource omap_mbox_resources[] = {
        {
                .start          = OMAP34XX_MAILBOX_BASE,
                .end            = OMAP34XX_MAILBOX_BASE + MBOX_REG_SIZE - 1,
@@ -165,6 +168,24 @@ static struct resource omap3_mbox_resources[] = {
                .flags          = IORESOURCE_IRQ,
        },
 };
+#endif
+
+#ifdef CONFIG_ARCH_OMAP4
+
+#define OMAP4_MBOX_REG_SIZE    0x130
+static struct resource omap_mbox_resources[] = {
+       {
+               .start          = OMAP44XX_MAILBOX_BASE,
+               .end            = OMAP44XX_MAILBOX_BASE +
+                                       OMAP4_MBOX_REG_SIZE - 1,
+               .flags          = IORESOURCE_MEM,
+       },
+       {
+               .start          = INT_44XX_MAIL_U0_MPU,
+               .flags          = IORESOURCE_IRQ,
+       },
+};
+#endif
 
 static struct platform_device mbox_device = {
        .name           = "omap2-mailbox",
@@ -173,12 +194,9 @@ static struct platform_device mbox_device = {
 
 static inline void omap_init_mbox(void)
 {
-       if (cpu_is_omap2420()) {
-               mbox_device.num_resources = ARRAY_SIZE(omap2_mbox_resources);
-               mbox_device.resource = omap2_mbox_resources;
-       } else if (cpu_is_omap3430()) {
-               mbox_device.num_resources = ARRAY_SIZE(omap3_mbox_resources);
-               mbox_device.resource = omap3_mbox_resources;
+       if (cpu_is_omap2420() || cpu_is_omap3430() || cpu_is_omap44xx()) {
+               mbox_device.num_resources = ARRAY_SIZE(omap_mbox_resources);
+               mbox_device.resource = omap_mbox_resources;
        } else {
                pr_err("%s: platform not supported\n", __func__);
                return;
@@ -250,7 +268,7 @@ static inline void omap_init_sti(void) {}
 
 #if defined(CONFIG_SPI_OMAP24XX) || defined(CONFIG_SPI_OMAP24XX_MODULE)
 
-#include <mach/mcspi.h>
+#include <plat/mcspi.h>
 
 #define OMAP2_MCSPI1_BASE              0x48098000
 #define OMAP2_MCSPI2_BASE              0x4809a000
@@ -575,7 +593,7 @@ static inline void omap2_mmc_mux(struct omap_mmc_platform_data *mmc_controller,
                }
        }
 
-       if (cpu_is_omap3430()) {
+       if (cpu_is_omap34xx()) {
                if (controller_nr == 0) {
                        omap_cfg_reg(N28_3430_MMC1_CLK);
                        omap_cfg_reg(M27_3430_MMC1_CMD);
@@ -609,6 +627,12 @@ static inline void omap2_mmc_mux(struct omap_mmc_platform_data *mmc_controller,
                                omap_cfg_reg(AG4_3430_MMC2_DAT2);
                                omap_cfg_reg(AF4_3430_MMC2_DAT3);
                        }
+                       if (mmc_controller->slots[0].wires == 8) {
+                               omap_cfg_reg(AE4_3430_MMC2_DAT4);
+                               omap_cfg_reg(AH3_3430_MMC2_DAT5);
+                               omap_cfg_reg(AF3_3430_MMC2_DAT6);
+                               omap_cfg_reg(AE3_3430_MMC2_DAT7);
+                       }
                }
 
                /*
diff --git a/arch/arm/mach-omap2/emu.c b/arch/arm/mach-omap2/emu.c
new file mode 100644 (file)
index 0000000..ec0d984
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * emu.c
+ *
+ * ETM and ETB CoreSight components' resources as found in OMAP3xxx.
+ *
+ * Copyright (C) 2009 Nokia Corporation.
+ * Alexander Shishkin
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/amba/bus.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Alexander Shishkin");
+
+/* Cortex CoreSight components within omap3xxx EMU */
+#define ETM_BASE       (L4_EMU_34XX_PHYS + 0x10000)
+#define DBG_BASE       (L4_EMU_34XX_PHYS + 0x11000)
+#define ETB_BASE       (L4_EMU_34XX_PHYS + 0x1b000)
+#define DAPCTL         (L4_EMU_34XX_PHYS + 0x1d000)
+
+static struct amba_device omap3_etb_device = {
+       .dev            = {
+               .init_name = "etb",
+       },
+       .res            = {
+               .start  = ETB_BASE,
+               .end    = ETB_BASE + SZ_4K - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       .periphid       = 0x000bb907,
+};
+
+static struct amba_device omap3_etm_device = {
+       .dev            = {
+               .init_name = "etm",
+       },
+       .res            = {
+               .start  = ETM_BASE,
+               .end    = ETM_BASE + SZ_4K - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       .periphid       = 0x102bb921,
+};
+
+static int __init emu_init(void)
+{
+       amba_device_register(&omap3_etb_device, &iomem_resource);
+       amba_device_register(&omap3_etm_device, &iomem_resource);
+
+       return 0;
+}
+
+subsys_initcall(emu_init);
+
index 54fec53..7bb6922 100644 (file)
@@ -17,9 +17,9 @@
 
 #include <asm/mach/flash.h>
 
-#include <mach/onenand.h>
-#include <mach/board.h>
-#include <mach/gpmc.h>
+#include <plat/onenand.h>
+#include <plat/board.h>
+#include <plat/gpmc.h>
 
 static struct omap_onenand_platform_data *gpmc_onenand_data;
 
index df99d31..6083e21 100644 (file)
@@ -17,9 +17,9 @@
 #include <linux/io.h>
 #include <linux/smc91x.h>
 
-#include <mach/board.h>
-#include <mach/gpmc.h>
-#include <mach/gpmc-smc91x.h>
+#include <plat/board.h>
+#include <plat/gpmc.h>
+#include <plat/gpmc-smc91x.h>
 
 static struct omap_smc91x_platform_data *gpmc_cfg;
 
index f3c992e..e86f5ca 100644 (file)
@@ -24,9 +24,9 @@
 #include <linux/module.h>
 
 #include <asm/mach-types.h>
-#include <mach/gpmc.h>
+#include <plat/gpmc.h>
 
-#include <mach/sdrc.h>
+#include <plat/sdrc.h>
 
 /* GPMC register offsets */
 #define GPMC_REVISION          0x00
 #define ENABLE_PREFETCH                (0x1 << 7)
 #define DMA_MPU_MODE           2
 
+/* Structure to save gpmc cs context */
+struct gpmc_cs_config {
+       u32 config1;
+       u32 config2;
+       u32 config3;
+       u32 config4;
+       u32 config5;
+       u32 config6;
+       u32 config7;
+       int is_valid;
+};
+
+/*
+ * Structure to save/restore gpmc context
+ * to support core off on OMAP3
+ */
+struct omap3_gpmc_regs {
+       u32 sysconfig;
+       u32 irqenable;
+       u32 timeout_ctrl;
+       u32 config;
+       u32 prefetch_config1;
+       u32 prefetch_config2;
+       u32 prefetch_control;
+       struct gpmc_cs_config cs_context[GPMC_CS_NUM];
+};
+
 static struct resource gpmc_mem_root;
 static struct resource gpmc_cs_mem[GPMC_CS_NUM];
 static DEFINE_SPINLOCK(gpmc_mem_lock);
@@ -261,7 +288,7 @@ static void gpmc_cs_enable_mem(int cs, u32 base, u32 size)
        l = (base >> GPMC_CHUNK_SHIFT) & 0x3f;
        l &= ~(0x0f << 8);
        l |= ((mask >> GPMC_CHUNK_SHIFT) & 0x0f) << 8;
-       l |= 1 << 6;            /* CSVALID */
+       l |= GPMC_CONFIG7_CSVALID;
        gpmc_cs_write_reg(cs, GPMC_CS_CONFIG7, l);
 }
 
@@ -270,7 +297,7 @@ static void gpmc_cs_disable_mem(int cs)
        u32 l;
 
        l = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG7);
-       l &= ~(1 << 6);         /* CSVALID */
+       l &= ~GPMC_CONFIG7_CSVALID;
        gpmc_cs_write_reg(cs, GPMC_CS_CONFIG7, l);
 }
 
@@ -290,7 +317,7 @@ static int gpmc_cs_mem_enabled(int cs)
        u32 l;
 
        l = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG7);
-       return l & (1 << 6);
+       return l & GPMC_CONFIG7_CSVALID;
 }
 
 int gpmc_cs_set_reserved(int cs, int reserved)
@@ -516,3 +543,68 @@ void __init gpmc_init(void)
        gpmc_write_reg(GPMC_SYSCONFIG, l);
        gpmc_mem_init();
 }
+
+#ifdef CONFIG_ARCH_OMAP3
+static struct omap3_gpmc_regs gpmc_context;
+
+void omap3_gpmc_save_context()
+{
+       int i;
+       gpmc_context.sysconfig = gpmc_read_reg(GPMC_SYSCONFIG);
+       gpmc_context.irqenable = gpmc_read_reg(GPMC_IRQENABLE);
+       gpmc_context.timeout_ctrl = gpmc_read_reg(GPMC_TIMEOUT_CONTROL);
+       gpmc_context.config = gpmc_read_reg(GPMC_CONFIG);
+       gpmc_context.prefetch_config1 = gpmc_read_reg(GPMC_PREFETCH_CONFIG1);
+       gpmc_context.prefetch_config2 = gpmc_read_reg(GPMC_PREFETCH_CONFIG2);
+       gpmc_context.prefetch_control = gpmc_read_reg(GPMC_PREFETCH_CONTROL);
+       for (i = 0; i < GPMC_CS_NUM; i++) {
+               gpmc_context.cs_context[i].is_valid = gpmc_cs_mem_enabled(i);
+               if (gpmc_context.cs_context[i].is_valid) {
+                       gpmc_context.cs_context[i].config1 =
+                               gpmc_cs_read_reg(i, GPMC_CS_CONFIG1);
+                       gpmc_context.cs_context[i].config2 =
+                               gpmc_cs_read_reg(i, GPMC_CS_CONFIG2);
+                       gpmc_context.cs_context[i].config3 =
+                               gpmc_cs_read_reg(i, GPMC_CS_CONFIG3);
+                       gpmc_context.cs_context[i].config4 =
+                               gpmc_cs_read_reg(i, GPMC_CS_CONFIG4);
+                       gpmc_context.cs_context[i].config5 =
+                               gpmc_cs_read_reg(i, GPMC_CS_CONFIG5);
+                       gpmc_context.cs_context[i].config6 =
+                               gpmc_cs_read_reg(i, GPMC_CS_CONFIG6);
+                       gpmc_context.cs_context[i].config7 =
+                               gpmc_cs_read_reg(i, GPMC_CS_CONFIG7);
+               }
+       }
+}
+
+void omap3_gpmc_restore_context()
+{
+       int i;
+       gpmc_write_reg(GPMC_SYSCONFIG, gpmc_context.sysconfig);
+       gpmc_write_reg(GPMC_IRQENABLE, gpmc_context.irqenable);
+       gpmc_write_reg(GPMC_TIMEOUT_CONTROL, gpmc_context.timeout_ctrl);
+       gpmc_write_reg(GPMC_CONFIG, gpmc_context.config);
+       gpmc_write_reg(GPMC_PREFETCH_CONFIG1, gpmc_context.prefetch_config1);
+       gpmc_write_reg(GPMC_PREFETCH_CONFIG2, gpmc_context.prefetch_config2);
+       gpmc_write_reg(GPMC_PREFETCH_CONTROL, gpmc_context.prefetch_control);
+       for (i = 0; i < GPMC_CS_NUM; i++) {
+               if (gpmc_context.cs_context[i].is_valid) {
+                       gpmc_cs_write_reg(i, GPMC_CS_CONFIG1,
+                               gpmc_context.cs_context[i].config1);
+                       gpmc_cs_write_reg(i, GPMC_CS_CONFIG2,
+                               gpmc_context.cs_context[i].config2);
+                       gpmc_cs_write_reg(i, GPMC_CS_CONFIG3,
+                               gpmc_context.cs_context[i].config3);
+                       gpmc_cs_write_reg(i, GPMC_CS_CONFIG4,
+                               gpmc_context.cs_context[i].config4);
+                       gpmc_cs_write_reg(i, GPMC_CS_CONFIG5,
+                               gpmc_context.cs_context[i].config5);
+                       gpmc_cs_write_reg(i, GPMC_CS_CONFIG6,
+                               gpmc_context.cs_context[i].config6);
+                       gpmc_cs_write_reg(i, GPMC_CS_CONFIG7,
+                               gpmc_context.cs_context[i].config7);
+               }
+       }
+}
+#endif /* CONFIG_ARCH_OMAP3 */
index a98201c..f48a4b2 100644 (file)
 
 #include <asm/cputype.h>
 
-#include <mach/common.h>
-#include <mach/control.h>
-#include <mach/cpu.h>
+#include <plat/common.h>
+#include <plat/control.h>
+#include <plat/cpu.h>
 
 static struct omap_chip_id omap_chip;
 static unsigned int omap_revision;
 
+u32 omap3_features;
 
 unsigned int omap_rev(void)
 {
@@ -52,11 +53,11 @@ int omap_type(void)
 {
        u32 val = 0;
 
-       if (cpu_is_omap24xx())
+       if (cpu_is_omap24xx()) {
                val = omap_ctrl_readl(OMAP24XX_CONTROL_STATUS);
-       else if (cpu_is_omap34xx())
+       } else if (cpu_is_omap34xx()) {
                val = omap_ctrl_readl(OMAP343X_CONTROL_STATUS);
-       else {
+       else {
                pr_err("Cannot detect omap type!\n");
                goto out;
        }
@@ -155,12 +156,37 @@ void __init omap24xx_check_revision(void)
        pr_info("\n");
 }
 
-void __init omap34xx_check_revision(void)
+#define OMAP3_CHECK_FEATURE(status,feat)                               \
+       if (((status & OMAP3_ ##feat## _MASK)                           \
+               >> OMAP3_ ##feat## _SHIFT) != FEAT_ ##feat## _NONE) {   \
+               omap3_features |= OMAP3_HAS_ ##feat;                    \
+       }
+
+void __init omap3_check_features(void)
+{
+       u32 status;
+
+       omap3_features = 0;
+
+       status = omap_ctrl_readl(OMAP3_CONTROL_OMAP_STATUS);
+
+       OMAP3_CHECK_FEATURE(status, L2CACHE);
+       OMAP3_CHECK_FEATURE(status, IVA);
+       OMAP3_CHECK_FEATURE(status, SGX);
+       OMAP3_CHECK_FEATURE(status, NEON);
+       OMAP3_CHECK_FEATURE(status, ISP);
+
+       /*
+        * TODO: Get additional info (where applicable)
+        *       e.g. Size of L2 cache.
+        */
+}
+
+void __init omap3_check_revision(void)
 {
        u32 cpuid, idcode;
        u16 hawkeye;
        u8 rev;
-       char *rev_name = "ES1.0";
 
        /*
         * We cannot access revision registers on ES1.0.
@@ -170,7 +196,7 @@ void __init omap34xx_check_revision(void)
        cpuid = read_cpuid(CPUID_ID);
        if ((((cpuid >> 4) & 0xfff) == 0xc08) && ((cpuid & 0xf) == 0x0)) {
                omap_revision = OMAP3430_REV_ES1_0;
-               goto out;
+               return;
        }
 
        /*
@@ -183,33 +209,115 @@ void __init omap34xx_check_revision(void)
        hawkeye = (idcode >> 12) & 0xffff;
        rev = (idcode >> 28) & 0xff;
 
-       if (hawkeye == 0xb7ae) {
+       switch (hawkeye) {
+       case 0xb7ae:
+               /* Handle 34xx/35xx devices */
                switch (rev) {
-               case 0:
+               case 0: /* Take care of early samples */
+               case 1:
                        omap_revision = OMAP3430_REV_ES2_0;
-                       rev_name = "ES2.0";
                        break;
                case 2:
                        omap_revision = OMAP3430_REV_ES2_1;
-                       rev_name = "ES2.1";
                        break;
                case 3:
                        omap_revision = OMAP3430_REV_ES3_0;
-                       rev_name = "ES3.0";
                        break;
                case 4:
-                       omap_revision = OMAP3430_REV_ES3_1;
-                       rev_name = "ES3.1";
-                       break;
+               /* FALLTHROUGH */
                default:
                        /* Use the latest known revision as default */
                        omap_revision = OMAP3430_REV_ES3_1;
-                       rev_name = "Unknown revision\n";
                }
+               break;
+       case 0xb868:
+               /* Handle OMAP35xx/AM35xx devices
+                *
+                * Set the device to be OMAP3505 here. Actual device
+                * is identified later based on the features.
+                */
+               omap_revision = OMAP3505_REV(rev);
+               break;
+       case 0xb891:
+       /* FALLTHROUGH */
+       default:
+               /* Unknown default to latest silicon rev as default*/
+               omap_revision = OMAP3630_REV_ES1_0;
        }
+}
 
-out:
-       pr_info("OMAP%04x %s\n", omap_rev() >> 16, rev_name);
+#define OMAP3_SHOW_FEATURE(feat)               \
+       if (omap3_has_ ##feat())                \
+               printk(#feat" ");
+
+void __init omap3_cpuinfo(void)
+{
+       u8 rev = GET_OMAP_REVISION();
+       char cpu_name[16], cpu_rev[16];
+
+       /* OMAP3430 and OMAP3530 are assumed to be same.
+        *
+        * OMAP3525, OMAP3515 and OMAP3503 can be detected only based
+        * on available features. Upon detection, update the CPU id
+        * and CPU class bits.
+        */
+       if (cpu_is_omap3630()) {
+               strcpy(cpu_name, "OMAP3630");
+       } else if (cpu_is_omap3505()) {
+               /*
+                * AM35xx devices
+                */
+               if (omap3_has_sgx()) {
+                       omap_revision = OMAP3517_REV(rev);
+                       strcpy(cpu_name, "AM3517");
+               } else {
+                       /* Already set in omap3_check_revision() */
+                       strcpy(cpu_name, "AM3505");
+               }
+       } else if (omap3_has_iva() && omap3_has_sgx()) {
+               /* OMAP3430, OMAP3525, OMAP3515, OMAP3503 devices */
+               strcpy(cpu_name, "OMAP3430/3530");
+       } else if (omap3_has_sgx()) {
+               omap_revision = OMAP3525_REV(rev);
+               strcpy(cpu_name, "OMAP3525");
+       } else if (omap3_has_iva()) {
+               omap_revision = OMAP3515_REV(rev);
+               strcpy(cpu_name, "OMAP3515");
+       } else {
+               omap_revision = OMAP3503_REV(rev);
+               strcpy(cpu_name, "OMAP3503");
+       }
+
+       switch (rev) {
+       case OMAP_REVBITS_00:
+               strcpy(cpu_rev, "1.0");
+               break;
+       case OMAP_REVBITS_10:
+               strcpy(cpu_rev, "2.0");
+               break;
+       case OMAP_REVBITS_20:
+               strcpy(cpu_rev, "2.1");
+               break;
+       case OMAP_REVBITS_30:
+               strcpy(cpu_rev, "3.0");
+               break;
+       case OMAP_REVBITS_40:
+       /* FALLTHROUGH */
+       default:
+               /* Use the latest known revision as default */
+               strcpy(cpu_rev, "3.1");
+       }
+
+       /* Print verbose information */
+       pr_info("%s ES%s (", cpu_name, cpu_rev);
+
+       OMAP3_SHOW_FEATURE(l2cache);
+       OMAP3_SHOW_FEATURE(iva);
+       OMAP3_SHOW_FEATURE(sgx);
+       OMAP3_SHOW_FEATURE(neon);
+       OMAP3_SHOW_FEATURE(isp);
+
+       printk(")\n");
 }
 
 /*
@@ -221,15 +329,18 @@ void __init omap2_check_revision(void)
         * At this point we have an idea about the processor revision set
         * earlier with omap2_set_globals_tap().
         */
-       if (cpu_is_omap24xx())
+       if (cpu_is_omap24xx()) {
                omap24xx_check_revision();
-       else if (cpu_is_omap34xx())
-               omap34xx_check_revision();
-       else if (cpu_is_omap44xx()) {
+       } else if (cpu_is_omap34xx()) {
+               omap3_check_revision();
+               omap3_check_features();
+               omap3_cpuinfo();
+       } else if (cpu_is_omap44xx()) {
                printk(KERN_INFO "FIXME: CPU revision = OMAP4430\n");
                return;
-       } else
+       } else {
                pr_err("OMAP revision unknown, please fix!\n");
+       }
 
        /*
         * OK, now we know the exact revision. Initialize omap_chip bits
@@ -241,6 +352,8 @@ void __init omap2_check_revision(void)
        } else if (cpu_is_omap242x()) {
                /* Currently only supports 2420ES2.1.1 and 2420-all */
                omap_chip.oc |= CHIP_IS_OMAP2420;
+       } else if (cpu_is_omap3505() || cpu_is_omap3517()) {
+               omap_chip.oc = CHIP_IS_OMAP3430 | CHIP_IS_OMAP3430ES3_1;
        } else if (cpu_is_omap343x()) {
                omap_chip.oc = CHIP_IS_OMAP3430;
                if (omap_rev() == OMAP3430_REV_ES1_0)
@@ -252,6 +365,8 @@ void __init omap2_check_revision(void)
                        omap_chip.oc |= CHIP_IS_OMAP3430ES3_0;
                else if (omap_rev() == OMAP3430_REV_ES3_1)
                        omap_chip.oc |= CHIP_IS_OMAP3430ES3_1;
+               else if (omap_rev() == OMAP3630_REV_ES1_0)
+                       omap_chip.oc |= CHIP_IS_OMAP3630ES1;
        } else {
                pr_err("Uninitialized omap_chip, please fix!\n");
        }
diff --git a/arch/arm/mach-omap2/include/mach/board-zoom.h b/arch/arm/mach-omap2/include/mach/board-zoom.h
new file mode 100644 (file)
index 0000000..c93b29e
--- /dev/null
@@ -0,0 +1,5 @@
+/*
+ * Defines for zoom boards
+ */
+extern int __init zoom_debugboard_init(void);
+extern void __init zoom_peripherals_init(void);
diff --git a/arch/arm/mach-omap2/include/mach/clkdev.h b/arch/arm/mach-omap2/include/mach/clkdev.h
new file mode 100644 (file)
index 0000000..53b0274
--- /dev/null
@@ -0,0 +1,5 @@
+/*
+ * arch/arm/mach-omap2/include/mach/clkdev.h
+ */
+
+#include <plat/clkdev.h>
@@ -1,4 +1,4 @@
-/* arch/arm/plat-omap/include/mach/debug-macro.S
+/* arch/arm/mach-omap2/include/mach/debug-macro.S
  *
  * Debugging macro include header
  *
                .macro  addruart,rx
                mrc     p15, 0, \rx, c1, c0
                tst     \rx, #1                 @ MMU enabled?
-#ifdef CONFIG_ARCH_OMAP1
-               moveq   \rx, #0xff000000        @ physical base address
-               movne   \rx, #0xfe000000        @ virtual base
-               orr     \rx, \rx, #0x00fb0000
-#ifdef CONFIG_OMAP_LL_DEBUG_UART3
-               orr     \rx, \rx, #0x00009000   @ UART 3
-#endif
-#if defined(CONFIG_OMAP_LL_DEBUG_UART2) || defined(CONFIG_OMAP_LL_DEBUG_UART3)
-               orr     \rx, \rx, #0x00000800   @ UART 2 & 3
-#endif
-
-#elif  CONFIG_ARCH_OMAP2
+#ifdef  CONFIG_ARCH_OMAP2
                moveq   \rx, #0x48000000        @ physical base address
-               movne   \rx, #0xd8000000        @ virtual base
+               movne   \rx, #0xfa000000        @ virtual base
                orr     \rx, \rx, #0x0006a000
 #ifdef CONFIG_OMAP_LL_DEBUG_UART2
                add     \rx, \rx, #0x00002000   @ UART 2
@@ -38,7 +27,7 @@
 
 #elif defined(CONFIG_ARCH_OMAP3) || defined(CONFIG_ARCH_OMAP4)
                moveq   \rx, #0x48000000        @ physical base address
-               movne   \rx, #0xd8000000        @ virtual base
+               movne   \rx, #0xfa000000        @ virtual base
                orr     \rx, \rx, #0x0006a000
 #ifdef CONFIG_OMAP_LL_DEBUG_UART2
                add     \rx, \rx, #0x00002000   @ UART 2
 #include <mach/irqs.h>
 #include <asm/hardware/gic.h>
 
-#if defined(CONFIG_ARCH_OMAP1)
-
-#if defined(CONFIG_ARCH_OMAP730) && \
-       (defined(CONFIG_ARCH_OMAP15XX) || defined(CONFIG_ARCH_OMAP16XX))
-#error "FIXME: OMAP730 doesn't support multiple-OMAP"
-#elif defined(CONFIG_ARCH_OMAP730)
-#define INT_IH2_IRQ            INT_730_IH2_IRQ
-#elif defined(CONFIG_ARCH_OMAP15XX)
-#define INT_IH2_IRQ            INT_1510_IH2_IRQ
-#elif defined(CONFIG_ARCH_OMAP16XX)
-#define INT_IH2_IRQ            INT_1610_IH2_IRQ
-#else
-#warning "IH2 IRQ defaulted"
-#define INT_IH2_IRQ            INT_1510_IH2_IRQ
-#endif
-
-               .macro  disable_fiq
-               .endm
-
-               .macro  get_irqnr_preamble, base, tmp
-               .endm
-
-               .macro  arch_ret_to_user, tmp1, tmp2
-               .endm
-
-               .macro  get_irqnr_and_base, irqnr, irqstat, base, tmp
-               ldr     \base, =OMAP1_IO_ADDRESS(OMAP_IH1_BASE)
-               ldr     \irqnr, [\base, #IRQ_ITR_REG_OFFSET]
-               ldr     \tmp, [\base, #IRQ_MIR_REG_OFFSET]
-               mov     \irqstat, #0xffffffff
-               bic     \tmp, \irqstat, \tmp
-               tst     \irqnr, \tmp
-               beq     1510f
-
-               ldr     \irqnr, [\base, #IRQ_SIR_FIQ_REG_OFFSET]
-               cmp     \irqnr, #0
-               ldreq   \irqnr, [\base, #IRQ_SIR_IRQ_REG_OFFSET]
-               cmpeq   \irqnr, #INT_IH2_IRQ
-               ldreq   \base, =OMAP1_IO_ADDRESS(OMAP_IH2_BASE)
-               ldreq   \irqnr, [\base, #IRQ_SIR_IRQ_REG_OFFSET]
-               addeqs  \irqnr, \irqnr, #32
-1510:
-               .endm
-
-#endif
-#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX) || \
-                       defined(CONFIG_ARCH_OMAP4)
-
-#include <mach/omap24xx.h>
-#include <mach/omap34xx.h>
+#include <plat/omap24xx.h>
+#include <plat/omap34xx.h>
 
 /* REVISIT: This should be set dynamically if CONFIG_MULTI_OMAP2 is selected */
 #if defined(CONFIG_ARCH_OMAP2420) || defined(CONFIG_ARCH_OMAP2430)
-#define OMAP2_VA_IC_BASE               OMAP2_IO_ADDRESS(OMAP24XX_IC_BASE)
+#define OMAP2_VA_IC_BASE               OMAP2_L4_IO_ADDRESS(OMAP24XX_IC_BASE)
 #elif defined(CONFIG_ARCH_OMAP34XX)
-#define OMAP2_VA_IC_BASE               OMAP2_IO_ADDRESS(OMAP34XX_IC_BASE)
+#define OMAP2_VA_IC_BASE               OMAP2_L4_IO_ADDRESS(OMAP34XX_IC_BASE)
 #endif
 #if defined(CONFIG_ARCH_OMAP4)
-#include <mach/omap44xx.h>
+#include <plat/omap44xx.h>
 #endif
 #define INTCPS_SIR_IRQ_OFFSET  0x0040          /* Active interrupt offset */
 #define        ACTIVEIRQ_MASK          0x7f            /* Active interrupt bits */
 
                .endm
 #else
+#define OMAP44XX_VA_GIC_CPU_BASE       OMAP2_L4_IO_ADDRESS(OMAP44XX_GIC_CPU_BASE)
+
                /*
                 * The interrupt numbering scheme is defined in the
                 * interrupt controller spec.  To wit:
 
                .macro  irq_prio_table
                .endm
-
-#endif
diff --git a/arch/arm/mach-omap2/include/mach/gpio.h b/arch/arm/mach-omap2/include/mach/gpio.h
new file mode 100644 (file)
index 0000000..be4d290
--- /dev/null
@@ -0,0 +1,5 @@
+/*
+ * arch/arm/mach-omap2/include/mach/gpio.h
+ */
+
+#include <plat/gpio.h>
diff --git a/arch/arm/mach-omap2/include/mach/hardware.h b/arch/arm/mach-omap2/include/mach/hardware.h
new file mode 100644 (file)
index 0000000..78edf9d
--- /dev/null
@@ -0,0 +1,5 @@
+/*
+ * arch/arm/mach-omap2/include/mach/hardware.h
+ */
+
+#include <plat/hardware.h>
diff --git a/arch/arm/mach-omap2/include/mach/io.h b/arch/arm/mach-omap2/include/mach/io.h
new file mode 100644 (file)
index 0000000..fd78f31
--- /dev/null
@@ -0,0 +1,5 @@
+/*
+ * arch/arm/mach-omap2/include/mach/io.h
+ */
+
+#include <plat/io.h>
diff --git a/arch/arm/mach-omap2/include/mach/irqs.h b/arch/arm/mach-omap2/include/mach/irqs.h
new file mode 100644 (file)
index 0000000..44dab77
--- /dev/null
@@ -0,0 +1,5 @@
+/*
+ * arch/arm/mach-omap2/include/mach/irqs.h
+ */
+
+#include <plat/irqs.h>
diff --git a/arch/arm/mach-omap2/include/mach/memory.h b/arch/arm/mach-omap2/include/mach/memory.h
new file mode 100644 (file)
index 0000000..ca6d32a
--- /dev/null
@@ -0,0 +1,5 @@
+/*
+ * arch/arm/mach-omap2/include/mach/memory.h
+ */
+
+#include <plat/memory.h>
diff --git a/arch/arm/mach-omap2/include/mach/smp.h b/arch/arm/mach-omap2/include/mach/smp.h
new file mode 100644 (file)
index 0000000..323675f
--- /dev/null
@@ -0,0 +1,5 @@
+/*
+ * arch/arm/mach-omap2/include/mach/smp.h
+ */
+
+#include <plat/smp.h>
diff --git a/arch/arm/mach-omap2/include/mach/system.h b/arch/arm/mach-omap2/include/mach/system.h
new file mode 100644 (file)
index 0000000..d488721
--- /dev/null
@@ -0,0 +1,5 @@
+/*
+ * arch/arm/mach-omap2/include/mach/system.h
+ */
+
+#include <plat/system.h>
diff --git a/arch/arm/mach-omap2/include/mach/timex.h b/arch/arm/mach-omap2/include/mach/timex.h
new file mode 100644 (file)
index 0000000..de9f8fc
--- /dev/null
@@ -0,0 +1,5 @@
+/*
+ * arch/arm/mach-omap2/include/mach/timex.h
+ */
+
+#include <plat/timex.h>
diff --git a/arch/arm/mach-omap2/include/mach/uncompress.h b/arch/arm/mach-omap2/include/mach/uncompress.h
new file mode 100644 (file)
index 0000000..78e0557
--- /dev/null
@@ -0,0 +1,5 @@
+/*
+ * arch/arm/mach-omap2/include/mach/uncompress.h
+ */
+
+#include <plat/uncompress.h>
similarity index 94%
rename from arch/arm/plat-omap/include/mach/vmalloc.h
rename to arch/arm/mach-omap2/include/mach/vmalloc.h
index b97dfaf..9ce9b6e 100644 (file)
@@ -17,5 +17,4 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  */
-#define VMALLOC_END      (PAGE_OFFSET + 0x18000000)
-
+#define VMALLOC_END      (PAGE_OFFSET + 0x38000000)
index 56be87d..59d28b2 100644 (file)
 
 #include <asm/mach/map.h>
 
-#include <mach/mux.h>
-#include <mach/omapfb.h>
-#include <mach/sram.h>
-#include <mach/sdrc.h>
-#include <mach/gpmc.h>
-#include <mach/serial.h>
+#include <plat/mux.h>
+#include <plat/omapfb.h>
+#include <plat/sram.h>
+#include <plat/sdrc.h>
+#include <plat/gpmc.h>
+#include <plat/serial.h>
 
 #ifndef CONFIG_ARCH_OMAP4      /* FIXME: Remove this once clkdev is ready */
 #include "clock.h"
 
-#include <mach/omap-pm.h>
-#include <mach/powerdomain.h>
+#include <plat/omap-pm.h>
+#include <plat/powerdomain.h>
 #include "powerdomains.h"
 
-#include <mach/clockdomain.h>
+#include <plat/clockdomain.h>
 #include "clockdomains.h"
 #endif
-#include <mach/omap_hwmod.h>
+#include <plat/omap_hwmod.h>
 #include "omap_hwmod_2420.h"
 #include "omap_hwmod_2430.h"
 #include "omap_hwmod_34xx.h"
@@ -203,6 +203,24 @@ static struct map_desc omap44xx_io_desc[] __initdata = {
                .type           = MT_DEVICE,
        },
        {
+               .virtual        = OMAP44XX_EMIF1_VIRT,
+               .pfn            = __phys_to_pfn(OMAP44XX_EMIF1_PHYS),
+               .length         = OMAP44XX_EMIF1_SIZE,
+               .type           = MT_DEVICE,
+       },
+       {
+               .virtual        = OMAP44XX_EMIF2_VIRT,
+               .pfn            = __phys_to_pfn(OMAP44XX_EMIF2_PHYS),
+               .length         = OMAP44XX_EMIF2_SIZE,
+               .type           = MT_DEVICE,
+       },
+       {
+               .virtual        = OMAP44XX_DMM_VIRT,
+               .pfn            = __phys_to_pfn(OMAP44XX_DMM_PHYS),
+               .length         = OMAP44XX_DMM_SIZE,
+               .type           = MT_DEVICE,
+       },
+       {
                .virtual        = L4_PER_44XX_VIRT,
                .pfn            = __phys_to_pfn(L4_PER_44XX_PHYS),
                .length         = L4_PER_44XX_SIZE,
index 4a0e1cd..6f4b7cc 100644 (file)
@@ -17,7 +17,7 @@
 #include <linux/module.h>
 #include <linux/stringify.h>
 
-#include <mach/iommu.h>
+#include <plat/iommu.h>
 
 /*
  * omap2 architecture specific register bit definitions
index b828638..e9bc782 100644 (file)
 #define INTC_SYSSTATUS         0x0014
 #define INTC_SIR               0x0040
 #define INTC_CONTROL           0x0048
+#define INTC_PROTECTION                0x004C
+#define INTC_IDLE              0x0050
+#define INTC_THRESHOLD         0x0068
+#define INTC_MIR0              0x0084
 #define INTC_MIR_CLEAR0                0x0088
 #define INTC_MIR_SET0          0x008c
 #define INTC_PENDING_IRQ0      0x0098
@@ -48,6 +52,18 @@ static struct omap_irq_bank {
        },
 };
 
+/* Structure to save interrupt controller context */
+struct omap3_intc_regs {
+       u32 sysconfig;
+       u32 protection;
+       u32 idle;
+       u32 threshold;
+       u32 ilr[INTCPS_NR_IRQS];
+       u32 mir[INTCPS_NR_MIR_REGS];
+};
+
+static struct omap3_intc_regs intc_context[ARRAY_SIZE(irq_banks)];
+
 /* INTC bank register get/set */
 
 static void intc_bank_write_reg(u32 val, struct omap_irq_bank *bank, u16 reg)
@@ -178,12 +194,20 @@ void __init omap_init_irq(void)
        int i;
 
        for (i = 0; i < ARRAY_SIZE(irq_banks); i++) {
+               unsigned long base;
                struct omap_irq_bank *bank = irq_banks + i;
 
                if (cpu_is_omap24xx())
-                       bank->base_reg = OMAP2_IO_ADDRESS(OMAP24XX_IC_BASE);
+                       base = OMAP24XX_IC_BASE;
                else if (cpu_is_omap34xx())
-                       bank->base_reg = OMAP2_IO_ADDRESS(OMAP34XX_IC_BASE);
+                       base = OMAP34XX_IC_BASE;
+
+               /* Static mapping, never released */
+               bank->base_reg = ioremap(base, SZ_4K);
+               if (!bank->base_reg) {
+                       printk(KERN_ERR "Could not ioremap irq bank%i\n", i);
+                       continue;
+               }
 
                omap_irq_bank_init_one(bank);
 
@@ -201,3 +225,53 @@ void __init omap_init_irq(void)
        }
 }
 
+#ifdef CONFIG_ARCH_OMAP3
+void omap_intc_save_context(void)
+{
+       int ind = 0, i = 0;
+       for (ind = 0; ind < ARRAY_SIZE(irq_banks); ind++) {
+               struct omap_irq_bank *bank = irq_banks + ind;
+               intc_context[ind].sysconfig =
+                       intc_bank_read_reg(bank, INTC_SYSCONFIG);
+               intc_context[ind].protection =
+                       intc_bank_read_reg(bank, INTC_PROTECTION);
+               intc_context[ind].idle =
+                       intc_bank_read_reg(bank, INTC_IDLE);
+               intc_context[ind].threshold =
+                       intc_bank_read_reg(bank, INTC_THRESHOLD);
+               for (i = 0; i < INTCPS_NR_IRQS; i++)
+                       intc_context[ind].ilr[i] =
+                               intc_bank_read_reg(bank, (0x100 + 0x4*i));
+               for (i = 0; i < INTCPS_NR_MIR_REGS; i++)
+                       intc_context[ind].mir[i] =
+                               intc_bank_read_reg(&irq_banks[0], INTC_MIR0 +
+                               (0x20 * i));
+       }
+}
+
+void omap_intc_restore_context(void)
+{
+       int ind = 0, i = 0;
+
+       for (ind = 0; ind < ARRAY_SIZE(irq_banks); ind++) {
+               struct omap_irq_bank *bank = irq_banks + ind;
+               intc_bank_write_reg(intc_context[ind].sysconfig,
+                                       bank, INTC_SYSCONFIG);
+               intc_bank_write_reg(intc_context[ind].sysconfig,
+                                       bank, INTC_SYSCONFIG);
+               intc_bank_write_reg(intc_context[ind].protection,
+                                       bank, INTC_PROTECTION);
+               intc_bank_write_reg(intc_context[ind].idle,
+                                       bank, INTC_IDLE);
+               intc_bank_write_reg(intc_context[ind].threshold,
+                                       bank, INTC_THRESHOLD);
+               for (i = 0; i < INTCPS_NR_IRQS; i++)
+                       intc_bank_write_reg(intc_context[ind].ilr[i],
+                               bank, (0x100 + 0x4*i));
+               for (i = 0; i < INTCPS_NR_MIR_REGS; i++)
+                       intc_bank_write_reg(intc_context[ind].mir[i],
+                                &irq_banks[0], INTC_MIR0 + (0x20 * i));
+       }
+       /* MIRs are saved and restore with other PRCM registers */
+}
+#endif /* CONFIG_ARCH_OMAP3 */
index ef57b38..281ab63 100644 (file)
 #include <linux/err.h>
 #include <linux/platform_device.h>
 #include <linux/io.h>
-#include <mach/mailbox.h>
+#include <plat/mailbox.h>
 #include <mach/irqs.h>
 
+#define DRV_NAME "omap2-mailbox"
+
 #define MAILBOX_REVISION               0x000
 #define MAILBOX_SYSCONFIG              0x010
 #define MAILBOX_SYSSTATUS              0x014
 #define MAILBOX_IRQSTATUS(u)           (0x100 + 8 * (u))
 #define MAILBOX_IRQENABLE(u)           (0x104 + 8 * (u))
 
-#define MAILBOX_IRQ_NEWMSG(u)          (1 << (2 * (u)))
-#define MAILBOX_IRQ_NOTFULL(u)         (1 << (2 * (u) + 1))
+#define OMAP4_MAILBOX_IRQSTATUS(u)     (0x104 + 10 * (u))
+#define OMAP4_MAILBOX_IRQENABLE(u)     (0x108 + 10 * (u))
+#define OMAP4_MAILBOX_IRQENABLE_CLR(u) (0x10c + 10 * (u))
+
+#define MAILBOX_IRQ_NEWMSG(m)          (1 << (2 * (m)))
+#define MAILBOX_IRQ_NOTFULL(m)         (1 << (2 * (m) + 1))
 
 /* SYSCONFIG: register bit definition */
 #define AUTOIDLE       (1 << 0)
 #define RESETDONE      (1 << 0)
 
 #define MBOX_REG_SIZE                  0x120
+
+#define OMAP4_MBOX_REG_SIZE            0x130
+
 #define MBOX_NR_REGS                   (MBOX_REG_SIZE / sizeof(u32))
+#define OMAP4_MBOX_NR_REGS             (OMAP4_MBOX_REG_SIZE / sizeof(u32))
 
 static void __iomem *mbox_base;
 
@@ -56,7 +66,8 @@ struct omap_mbox2_priv {
        unsigned long irqstatus;
        u32 newmsg_bit;
        u32 notfull_bit;
-       u32 ctx[MBOX_NR_REGS];
+       u32 ctx[OMAP4_MBOX_NR_REGS];
+       unsigned long irqdisable;
 };
 
 static struct clk *mbox_ick_handle;
@@ -82,8 +93,9 @@ static int omap2_mbox_startup(struct omap_mbox *mbox)
 
        mbox_ick_handle = clk_get(NULL, "mailboxes_ick");
        if (IS_ERR(mbox_ick_handle)) {
-               pr_err("Can't get mailboxes_ick\n");
-               return -ENODEV;
+               printk(KERN_ERR "Could not get mailboxes_ick: %d\n",
+                       PTR_ERR(mbox_ick_handle));
+               return PTR_ERR(mbox_ick_handle);
        }
        clk_enable(mbox_ick_handle);
 
@@ -115,6 +127,7 @@ static void omap2_mbox_shutdown(struct omap_mbox *mbox)
 {
        clk_disable(mbox_ick_handle);
        clk_put(mbox_ick_handle);
+       mbox_ick_handle = NULL;
 }
 
 /* Mailbox FIFO handle functions */
@@ -143,7 +156,7 @@ static int omap2_mbox_fifo_full(struct omap_mbox *mbox)
 {
        struct omap_mbox2_fifo *fifo =
                &((struct omap_mbox2_priv *)mbox->priv)->tx_fifo;
-       return (mbox_read_reg(fifo->fifo_stat));
+       return mbox_read_reg(fifo->fifo_stat);
 }
 
 /* Mailbox IRQ handle functions */
@@ -163,10 +176,9 @@ static void omap2_mbox_disable_irq(struct omap_mbox *mbox,
 {
        struct omap_mbox2_priv *p = (struct omap_mbox2_priv *)mbox->priv;
        u32 l, bit = (irq == IRQ_TX) ? p->notfull_bit : p->newmsg_bit;
-
-       l = mbox_read_reg(p->irqenable);
+       l = mbox_read_reg(p->irqdisable);
        l &= ~bit;
-       mbox_write_reg(l, p->irqenable);
+       mbox_write_reg(l, p->irqdisable);
 }
 
 static void omap2_mbox_ack_irq(struct omap_mbox *mbox,
@@ -189,15 +201,19 @@ static int omap2_mbox_is_irq(struct omap_mbox *mbox,
        u32 enable = mbox_read_reg(p->irqenable);
        u32 status = mbox_read_reg(p->irqstatus);
 
-       return (enable & status & bit);
+       return (int)(enable & status & bit);
 }
 
 static void omap2_mbox_save_ctx(struct omap_mbox *mbox)
 {
        int i;
        struct omap_mbox2_priv *p = mbox->priv;
-
-       for (i = 0; i < MBOX_NR_REGS; i++) {
+       int nr_regs;
+       if (cpu_is_omap44xx())
+               nr_regs = OMAP4_MBOX_NR_REGS;
+       else
+               nr_regs = MBOX_NR_REGS;
+       for (i = 0; i < nr_regs; i++) {
                p->ctx[i] = mbox_read_reg(i * sizeof(u32));
 
                dev_dbg(mbox->dev, "%s: [%02x] %08x\n", __func__,
@@ -209,8 +225,12 @@ static void omap2_mbox_restore_ctx(struct omap_mbox *mbox)
 {
        int i;
        struct omap_mbox2_priv *p = mbox->priv;
-
-       for (i = 0; i < MBOX_NR_REGS; i++) {
+       int nr_regs;
+       if (cpu_is_omap44xx())
+               nr_regs = OMAP4_MBOX_NR_REGS;
+       else
+               nr_regs = MBOX_NR_REGS;
+       for (i = 0; i < nr_regs; i++) {
                mbox_write_reg(p->ctx[i], i * sizeof(u32));
 
                dev_dbg(mbox->dev, "%s: [%02x] %08x\n", __func__,
@@ -242,7 +262,6 @@ static struct omap_mbox_ops omap2_mbox_ops = {
  */
 
 /* FIXME: the following structs should be filled automatically by the user id */
-
 /* DSP */
 static struct omap_mbox2_priv omap2_mbox_dsp_priv = {
        .tx_fifo = {
@@ -257,8 +276,36 @@ static struct omap_mbox2_priv omap2_mbox_dsp_priv = {
        .irqstatus      = MAILBOX_IRQSTATUS(0),
        .notfull_bit    = MAILBOX_IRQ_NOTFULL(0),
        .newmsg_bit     = MAILBOX_IRQ_NEWMSG(1),
+       .irqdisable     = MAILBOX_IRQENABLE(0),
+};
+
+
+
+/* OMAP4 specific data structure. Use the cpu_is_omap4xxx()
+to use this*/
+static struct omap_mbox2_priv omap2_mbox_1_priv = {
+       .tx_fifo = {
+               .msg            = MAILBOX_MESSAGE(0),
+               .fifo_stat      = MAILBOX_FIFOSTATUS(0),
+       },
+       .rx_fifo = {
+               .msg            = MAILBOX_MESSAGE(1),
+               .msg_stat       = MAILBOX_MSGSTATUS(1),
+       },
+       .irqenable      = OMAP4_MAILBOX_IRQENABLE(0),
+       .irqstatus      = OMAP4_MAILBOX_IRQSTATUS(0),
+       .notfull_bit    = MAILBOX_IRQ_NOTFULL(0),
+       .newmsg_bit     = MAILBOX_IRQ_NEWMSG(1),
+       .irqdisable     = OMAP4_MAILBOX_IRQENABLE_CLR(0),
 };
 
+struct omap_mbox mbox_1_info = {
+       .name   = "mailbox-1",
+       .ops    = &omap2_mbox_ops,
+       .priv   = &omap2_mbox_1_priv,
+};
+EXPORT_SYMBOL(mbox_1_info);
+
 struct omap_mbox mbox_dsp_info = {
        .name   = "dsp",
        .ops    = &omap2_mbox_ops,
@@ -266,6 +313,30 @@ struct omap_mbox mbox_dsp_info = {
 };
 EXPORT_SYMBOL(mbox_dsp_info);
 
+static struct omap_mbox2_priv omap2_mbox_2_priv = {
+       .tx_fifo = {
+               .msg            = MAILBOX_MESSAGE(3),
+               .fifo_stat      = MAILBOX_FIFOSTATUS(3),
+       },
+       .rx_fifo = {
+               .msg            = MAILBOX_MESSAGE(2),
+               .msg_stat       = MAILBOX_MSGSTATUS(2),
+       },
+       .irqenable      = OMAP4_MAILBOX_IRQENABLE(0),
+       .irqstatus      = OMAP4_MAILBOX_IRQSTATUS(0),
+       .notfull_bit    = MAILBOX_IRQ_NOTFULL(3),
+       .newmsg_bit     = MAILBOX_IRQ_NEWMSG(2),
+       .irqdisable     = OMAP4_MAILBOX_IRQENABLE_CLR(0),
+};
+
+struct omap_mbox mbox_2_info = {
+       .name   = "mailbox-2",
+       .ops    = &omap2_mbox_ops,
+       .priv   = &omap2_mbox_2_priv,
+};
+EXPORT_SYMBOL(mbox_2_info);
+
+
 #if defined(CONFIG_ARCH_OMAP2420) /* IVA */
 static struct omap_mbox2_priv omap2_mbox_iva_priv = {
        .tx_fifo = {
@@ -280,6 +351,7 @@ static struct omap_mbox2_priv omap2_mbox_iva_priv = {
        .irqstatus      = MAILBOX_IRQSTATUS(3),
        .notfull_bit    = MAILBOX_IRQ_NOTFULL(2),
        .newmsg_bit     = MAILBOX_IRQ_NEWMSG(3),
+       .irqdisable     = MAILBOX_IRQENABLE(3),
 };
 
 static struct omap_mbox mbox_iva_info = {
@@ -305,17 +377,31 @@ static int __devinit omap2_mbox_probe(struct platform_device *pdev)
                return -ENOMEM;
 
        /* DSP or IVA2 IRQ */
-       ret = platform_get_irq(pdev, 0);
-       if (ret < 0) {
+       res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+
+       if (unlikely(!res)) {
                dev_err(&pdev->dev, "invalid irq resource\n");
+               ret = -ENODEV;
                goto err_dsp;
        }
-       mbox_dsp_info.irq = ret;
-
-       ret = omap_mbox_register(&pdev->dev, &mbox_dsp_info);
+       if (cpu_is_omap44xx()) {
+               mbox_1_info.irq = res->start;
+               ret = omap_mbox_register(&pdev->dev, &mbox_1_info);
+       } else {
+               mbox_dsp_info.irq = res->start;
+               ret = omap_mbox_register(&pdev->dev, &mbox_dsp_info);
+       }
        if (ret)
                goto err_dsp;
 
+       if (cpu_is_omap44xx()) {
+               mbox_2_info.irq = res->start;
+               ret = omap_mbox_register(&pdev->dev, &mbox_2_info);
+               if (ret) {
+                       omap_mbox_unregister(&mbox_1_info);
+                       goto err_dsp;
+               }
+       }
 #if defined(CONFIG_ARCH_OMAP2420) /* IVA */
        if (cpu_is_omap2420()) {
                /* IVA IRQ */
@@ -335,6 +421,7 @@ static int __devinit omap2_mbox_probe(struct platform_device *pdev)
 
 err_iva1:
        omap_mbox_unregister(&mbox_dsp_info);
+
 err_dsp:
        iounmap(mbox_base);
        return ret;
@@ -345,7 +432,12 @@ static int __devexit omap2_mbox_remove(struct platform_device *pdev)
 #if defined(CONFIG_ARCH_OMAP2420)
        omap_mbox_unregister(&mbox_iva_info);
 #endif
-       omap_mbox_unregister(&mbox_dsp_info);
+
+       if (cpu_is_omap44xx()) {
+               omap_mbox_unregister(&mbox_2_info);
+               omap_mbox_unregister(&mbox_1_info);
+       } else
+               omap_mbox_unregister(&mbox_dsp_info);
        iounmap(mbox_base);
        return 0;
 }
@@ -354,7 +446,7 @@ static struct platform_driver omap2_mbox_driver = {
        .probe = omap2_mbox_probe,
        .remove = __devexit_p(omap2_mbox_remove),
        .driver = {
-               .name = "omap2-mailbox",
+               .name = DRV_NAME,
        },
 };
 
@@ -372,6 +464,6 @@ module_init(omap2_mbox_init);
 module_exit(omap2_mbox_exit);
 
 MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("omap mailbox: omap2/3 architecture specific functions");
+MODULE_DESCRIPTION("omap mailbox: omap2/3/4 architecture specific functions");
 MODULE_AUTHOR("Hiroshi DOYU <Hiroshi.DOYU@nokia.com>, Paul Mundt");
-MODULE_ALIAS("platform:omap2-mailbox");
+MODULE_ALIAS("platform:"DRV_NAME);
index a846aa1..baa4517 100644 (file)
 #include <linux/platform_device.h>
 
 #include <mach/irqs.h>
-#include <mach/dma.h>
-#include <mach/mux.h>
-#include <mach/cpu.h>
-#include <mach/mcbsp.h>
+#include <plat/dma.h>
+#include <plat/mux.h>
+#include <plat/cpu.h>
+#include <plat/mcbsp.h>
 
 static void omap2_mcbsp2_mux_setup(void)
 {
index c9c59a2..0c3c72d 100644 (file)
@@ -20,9 +20,9 @@
 #include <linux/regulator/consumer.h>
 
 #include <mach/hardware.h>
-#include <mach/control.h>
-#include <mach/mmc.h>
-#include <mach/board.h>
+#include <plat/control.h>
+#include <plat/mmc.h>
+#include <plat/board.h>
 
 #include "mmc-twl4030.h"
 
@@ -213,7 +213,7 @@ static int twl4030_mmc_get_context_loss(struct device *dev)
 static int twl_mmc1_set_power(struct device *dev, int slot, int power_on,
                                int vdd)
 {
-       u32 reg;
+       u32 reg, prog_io;
        int ret = 0;
        struct twl_mmc_controller *c = &hsmmc[0];
        struct omap_mmc_platform_data *mmc = dev->platform_data;
@@ -245,7 +245,14 @@ static int twl_mmc1_set_power(struct device *dev, int slot, int power_on,
                }
 
                reg = omap_ctrl_readl(control_pbias_offset);
-               reg |= OMAP2_PBIASSPEEDCTRL0;
+               if (cpu_is_omap3630()) {
+                       /* Set MMC I/O to 52Mhz */
+                       prog_io = omap_ctrl_readl(OMAP343X_CONTROL_PROG_IO1);
+                       prog_io |= OMAP3630_PRG_SDMMC1_SPEEDCTRL;
+                       omap_ctrl_writel(prog_io, OMAP343X_CONTROL_PROG_IO1);
+               } else {
+                       reg |= OMAP2_PBIASSPEEDCTRL0;
+               }
                reg &= ~OMAP2_PBIASLITEPWRDNZ0;
                omap_ctrl_writel(reg, control_pbias_offset);
 
@@ -489,6 +496,12 @@ void __init twl4030_mmc_init(struct twl4030_hsmmc_info *controllers)
                        /* on-chip level shifting via PBIAS0/PBIAS1 */
                        mmc->slots[0].set_power = twl_mmc1_set_power;
                        mmc->slots[0].set_sleep = twl_mmc1_set_sleep;
+
+                       /* Omap3630 HSMMC1 supports only 4-bit */
+                       if (cpu_is_omap3630() && c->wires > 4) {
+                               c->wires = 4;
+                               mmc->slots[0].wires = c->wires;
+                       }
                        break;
                case 2:
                        if (c->ext_clock)
index b5fac32..c18a94e 100644 (file)
@@ -30,8 +30,8 @@
 
 #include <asm/system.h>
 
-#include <mach/control.h>
-#include <mach/mux.h>
+#include <plat/control.h>
+#include <plat/mux.h>
 
 #ifdef CONFIG_OMAP_MUX
 
@@ -532,6 +532,14 @@ MUX_CFG_34XX("AG4_3430_MMC2_DAT2", 0x160,
                OMAP34XX_MUX_MODE0 | OMAP34XX_PIN_INPUT_PULLUP)
 MUX_CFG_34XX("AF4_3430_MMC2_DAT3", 0x162,
                OMAP34XX_MUX_MODE0 | OMAP34XX_PIN_INPUT_PULLUP)
+MUX_CFG_34XX("AE4_3430_MMC2_DAT4", 0x164,
+               OMAP34XX_MUX_MODE0 | OMAP34XX_PIN_INPUT_PULLUP)
+MUX_CFG_34XX("AH3_3430_MMC2_DAT5", 0x166,
+               OMAP34XX_MUX_MODE0 | OMAP34XX_PIN_INPUT_PULLUP)
+MUX_CFG_34XX("AF3_3430_MMC2_DAT6", 0x168,
+               OMAP34XX_MUX_MODE0 | OMAP34XX_PIN_INPUT_PULLUP)
+MUX_CFG_34XX("AE3_3430_MMC2_DAT7", 0x16A,
+               OMAP34XX_MUX_MODE0 | OMAP34XX_PIN_INPUT_PULLUP)
 
 /* MMC3 */
 MUX_CFG_34XX("AF10_3430_MMC3_CLK", 0x5d8,
@@ -551,6 +559,13 @@ MUX_CFG_34XX("AF13_3430_MMC3_DAT3", 0x5e2,
 MUX_CFG_34XX("AF26_34XX_SYS_NIRQ", 0x1E0,
                OMAP3_WAKEUP_EN | OMAP34XX_PIN_INPUT_PULLUP |
                OMAP34XX_MUX_MODE0)
+/* EHCI GPIO's on OMAP3EVM (Rev >= E) */
+MUX_CFG_34XX("AH14_34XX_GPIO21", 0x5ea,
+       OMAP34XX_MUX_MODE4 | OMAP34XX_PIN_INPUT_PULLUP)
+MUX_CFG_34XX("AF9_34XX_GPIO22", 0x5ec,
+       OMAP34XX_MUX_MODE4 | OMAP34XX_PIN_INPUT_PULLUP)
+MUX_CFG_34XX("U3_34XX_GPIO61", 0x0c8,
+       OMAP34XX_MUX_MODE4 | OMAP34XX_PIN_INPUT_PULLUP)
 };
 
 #define OMAP34XX_PINS_SZ       ARRAY_SIZE(omap34xx_pins)
index 48ee295..4890bcf 100644 (file)
 #include <asm/localtimer.h>
 #include <asm/smp_scu.h>
 #include <mach/hardware.h>
+#include <plat/common.h>
 
 /* Registers used for communicating startup information */
-#define OMAP4_AUXCOREBOOT_REG0         (OMAP44XX_VA_WKUPGEN_BASE + 0x800)
-#define OMAP4_AUXCOREBOOT_REG1         (OMAP44XX_VA_WKUPGEN_BASE + 0x804)
+static void __iomem *omap4_auxcoreboot_reg0;
+static void __iomem *omap4_auxcoreboot_reg1;
 
 /* SCU base address */
-static void __iomem *scu_base = OMAP44XX_VA_SCU_BASE;
+static void __iomem *scu_base;
 
 /*
  * Use SCU config register to count number of cores
@@ -53,8 +54,7 @@ void __cpuinit platform_secondary_init(unsigned int cpu)
         * core (e.g. timer irq), then they will not have been enabled
         * for us: do so
         */
-
-       gic_cpu_init(0, OMAP2_IO_ADDRESS(OMAP44XX_GIC_CPU_BASE));
+       gic_cpu_init(0, gic_cpu_base_addr);
 
        /*
         * Synchronise with the boot thread.
@@ -79,7 +79,7 @@ int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle)
         * the AuxCoreBoot1 register is updated with cpu state
         * A barrier is added to ensure that write buffer is drained
         */
-       __raw_writel(cpu, OMAP4_AUXCOREBOOT_REG1);
+       __raw_writel(cpu, omap4_auxcoreboot_reg1);
        smp_wmb();
 
        timeout = jiffies + (1 * HZ);
@@ -104,7 +104,7 @@ static void __init wakeup_secondary(void)
         * A barrier is added to ensure that write buffer is drained
         */
        __raw_writel(virt_to_phys(omap_secondary_startup),         \
-                                       OMAP4_AUXCOREBOOT_REG0);
+                                       omap4_auxcoreboot_reg0);
        smp_wmb();
 
        /*
@@ -120,7 +120,13 @@ static void __init wakeup_secondary(void)
  */
 void __init smp_init_cpus(void)
 {
-       unsigned int i, ncores = get_core_count();
+       unsigned int i, ncores;
+
+       /* Never released */
+       scu_base = ioremap(OMAP44XX_SCU_BASE, SZ_256);
+       BUG_ON(!scu_base);
+
+       ncores = get_core_count();
 
        for (i = 0; i < ncores; i++)
                set_cpu_possible(i, true);
@@ -130,6 +136,7 @@ void __init smp_prepare_cpus(unsigned int max_cpus)
 {
        unsigned int ncores = get_core_count();
        unsigned int cpu = smp_processor_id();
+       void __iomem *omap4_wkupgen_base;
        int i;
 
        /* sanity check */
@@ -161,6 +168,12 @@ void __init smp_prepare_cpus(unsigned int max_cpus)
        for (i = 0; i < max_cpus; i++)
                set_cpu_present(i, true);
 
+       /* Never released */
+       omap4_wkupgen_base = ioremap(OMAP44XX_WKUPGEN_BASE, SZ_4K);
+       BUG_ON(!omap4_wkupgen_base);
+       omap4_auxcoreboot_reg0 = omap4_wkupgen_base + 0x800;
+       omap4_auxcoreboot_reg1 = omap4_wkupgen_base + 0x804;
+
        if (max_cpus > 1) {
                /*
                 * Enable the local timer or broadcast device for the
index 194189c..fbbcb5c 100644 (file)
 
 #include <linux/platform_device.h>
 
-#include <mach/iommu.h>
+#include <plat/iommu.h>
 
-#define OMAP3_MMU1_BASE        0x480bd400
-#define OMAP3_MMU2_BASE        0x5d000000
-#define OMAP3_MMU1_IRQ 24
-#define OMAP3_MMU2_IRQ 28
-
-
-static unsigned long iommu_base[] __initdata = {
-       OMAP3_MMU1_BASE,
-       OMAP3_MMU2_BASE,
-};
-
-static int iommu_irq[] __initdata = {
-       OMAP3_MMU1_IRQ,
-       OMAP3_MMU2_IRQ,
+struct iommu_device {
+       resource_size_t base;
+       int irq;
+       struct iommu_platform_data pdata;
+       struct resource res[2];
 };
 
-static const struct iommu_platform_data omap3_iommu_pdata[] __initconst = {
+static struct iommu_device devices[] = {
        {
-               .name = "isp",
-               .nr_tlb_entries = 8,
-               .clk_name = "cam_ick",
+               .base = 0x480bd400,
+               .irq = 24,
+               .pdata = {
+                       .name = "isp",
+                       .nr_tlb_entries = 8,
+                       .clk_name = "cam_ick",
+               },
        },
 #if defined(CONFIG_MPU_BRIDGE_IOMMU)
        {
-               .name = "iva2",
-               .nr_tlb_entries = 32,
-               .clk_name = "iva2_ck",
+               .base = 0x5d000000,
+               .irq = 28,
+               .pdata = {
+                       .name = "iva2",
+                       .nr_tlb_entries = 32,
+                       .clk_name = "iva2_ck",
+               },
        },
 #endif
 };
-#define NR_IOMMU_DEVICES ARRAY_SIZE(omap3_iommu_pdata)
+#define NR_IOMMU_DEVICES ARRAY_SIZE(devices)
 
 static struct platform_device *omap3_iommu_pdev[NR_IOMMU_DEVICES];
 
 static int __init omap3_iommu_init(void)
 {
        int i, err;
+       struct resource res[] = {
+               { .flags = IORESOURCE_MEM },
+               { .flags = IORESOURCE_IRQ },
+       };
 
        for (i = 0; i < NR_IOMMU_DEVICES; i++) {
                struct platform_device *pdev;
-               struct resource res[2];
+               const struct iommu_device *d = &devices[i];
 
                pdev = platform_device_alloc("omap-iommu", i);
                if (!pdev) {
@@ -62,19 +65,16 @@ static int __init omap3_iommu_init(void)
                        goto err_out;
                }
 
-               memset(res, 0,  sizeof(res));
-               res[0].start = iommu_base[i];
-               res[0].end = iommu_base[i] + MMU_REG_SIZE - 1;
-               res[0].flags = IORESOURCE_MEM;
-               res[1].start = res[1].end = iommu_irq[i];
-               res[1].flags = IORESOURCE_IRQ;
+               res[0].start = d->base;
+               res[0].end = d->base + MMU_REG_SIZE - 1;
+               res[1].start = res[1].end = d->irq;
 
                err = platform_device_add_resources(pdev, res,
                                                    ARRAY_SIZE(res));
                if (err)
                        goto err_out;
-               err = platform_device_add_data(pdev, &omap3_iommu_pdata[i],
-                                              sizeof(omap3_iommu_pdata[0]));
+               err = platform_device_add_data(pdev, &d->pdata,
+                                              sizeof(d->pdata));
                if (err)
                        goto err_out;
                err = platform_device_add(pdev);
index d2e0f1c..633b216 100644 (file)
 #include <linux/mutex.h>
 #include <linux/bootmem.h>
 
-#include <mach/cpu.h>
-#include <mach/clockdomain.h>
-#include <mach/powerdomain.h>
-#include <mach/clock.h>
-#include <mach/omap_hwmod.h>
+#include <plat/cpu.h>
+#include <plat/clockdomain.h>
+#include <plat/powerdomain.h>
+#include <plat/clock.h>
+#include <plat/omap_hwmod.h>
 
 #include "cm.h"
 
@@ -496,6 +496,7 @@ static void __iomem *_find_mpu_rt_base(struct omap_hwmod *oh, u8 index)
        struct omap_hwmod_addr_space *mem;
        int i;
        int found = 0;
+       void __iomem *va_start;
 
        if (!oh || oh->slaves_cnt == 0)
                return NULL;
@@ -509,16 +510,20 @@ static void __iomem *_find_mpu_rt_base(struct omap_hwmod *oh, u8 index)
                }
        }
 
-       /* XXX use ioremap() instead? */
-
-       if (found)
+       if (found) {
+               va_start = ioremap(mem->pa_start, mem->pa_end - mem->pa_start);
+               if (!va_start) {
+                       pr_err("omap_hwmod: %s: Could not ioremap\n", oh->name);
+                       return NULL;
+               }
                pr_debug("omap_hwmod: %s: MPU register target at va %p\n",
-                        oh->name, OMAP2_IO_ADDRESS(mem->pa_start));
-       else
+                        oh->name, va_start);
+       } else {
                pr_debug("omap_hwmod: %s: no MPU register target found\n",
                         oh->name);
+       }
 
-       return (found) ? OMAP2_IO_ADDRESS(mem->pa_start) : NULL;
+       return (found) ? va_start : NULL;
 }
 
 /**
@@ -1148,6 +1153,7 @@ int omap_hwmod_unregister(struct omap_hwmod *oh)
        pr_debug("omap_hwmod: %s: unregistering\n", oh->name);
 
        mutex_lock(&omap_hwmod_mutex);
+       iounmap(oh->_rt_va);
        list_del(&oh->node);
        mutex_unlock(&omap_hwmod_mutex);
 
index 767e496..a9ca1b9 100644 (file)
 
 #ifdef CONFIG_ARCH_OMAP2420
 
-#include <mach/omap_hwmod.h>
+#include <plat/omap_hwmod.h>
 #include <mach/irqs.h>
-#include <mach/cpu.h>
-#include <mach/dma.h>
+#include <plat/cpu.h>
+#include <plat/dma.h>
 
 #include "prm-regbits-24xx.h"
 
index a412be6..59a208b 100644 (file)
 
 #ifdef CONFIG_ARCH_OMAP2430
 
-#include <mach/omap_hwmod.h>
+#include <plat/omap_hwmod.h>
 #include <mach/irqs.h>
-#include <mach/cpu.h>
-#include <mach/dma.h>
+#include <plat/cpu.h>
+#include <plat/dma.h>
 
 #include "prm-regbits-24xx.h"
 
index 1e069f8..b6076b9 100644 (file)
 
 #ifdef CONFIG_ARCH_OMAP34XX
 
-#include <mach/omap_hwmod.h>
+#include <plat/omap_hwmod.h>
 #include <mach/irqs.h>
-#include <mach/cpu.h>
-#include <mach/dma.h>
+#include <plat/cpu.h>
+#include <plat/dma.h>
 
 #include "prm-regbits-34xx.h"
 
index 2fc4d6a..8baa30d 100644 (file)
 #include <linux/io.h>
 #include <linux/module.h>
 
-#include <mach/clock.h>
-#include <mach/board.h>
-#include <mach/powerdomain.h>
-#include <mach/clockdomain.h>
+#include <plat/clock.h>
+#include <plat/board.h>
+#include <plat/powerdomain.h>
+#include <plat/clockdomain.h>
 
 #include "prm.h"
 #include "cm.h"
@@ -51,7 +51,8 @@ int omap2_pm_debug;
        regs[reg_count++].val = __raw_readl(reg)
 #define DUMP_INTC_REG(reg, off) \
        regs[reg_count].name = #reg; \
-       regs[reg_count++].val = __raw_readl(OMAP2_IO_ADDRESS(0x480fe000 + (off)))
+       regs[reg_count++].val = \
+                        __raw_readl(OMAP2_L4_IO_ADDRESS(0x480fe000 + (off)))
 
 static int __init pm_dbg_init(void);
 
@@ -526,6 +527,29 @@ static int __init pwrdms_setup(struct powerdomain *pwrdm, void *dir)
        return 0;
 }
 
+static int option_get(void *data, u64 *val)
+{
+       u32 *option = data;
+
+       *val = *option;
+
+       return 0;
+}
+
+static int option_set(void *data, u64 val)
+{
+       u32 *option = data;
+
+       *option = val;
+
+       if (option == &enable_off_mode)
+               omap3_pm_off_mode_enable(val);
+
+       return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(pm_dbg_option_fops, option_get, option_set, "%llu\n");
+
 static int __init pm_dbg_init(void)
 {
        int i;
@@ -568,6 +592,12 @@ static int __init pm_dbg_init(void)
 
                }
 
+       (void) debugfs_create_file("enable_off_mode", S_IRUGO | S_IWUGO, d,
+                                  &enable_off_mode, &pm_dbg_option_fops);
+       (void) debugfs_create_file("sleep_while_idle", S_IRUGO | S_IWUGO, d,
+                                  &sleep_while_idle, &pm_dbg_option_fops);
+       (void) debugfs_create_file("wakeup_timer_seconds", S_IRUGO | S_IWUGO, d,
+                                  &wakeup_timer_seconds, &pm_dbg_option_fops);
        pm_dbg_init_done = 1;
 
        return 0;
index 8400f57..0bf345d 100644 (file)
 #ifndef __ARCH_ARM_MACH_OMAP2_PM_H
 #define __ARCH_ARM_MACH_OMAP2_PM_H
 
-#include <mach/powerdomain.h>
+#include <plat/powerdomain.h>
+
+extern u32 enable_off_mode;
+extern u32 sleep_while_idle;
+
+extern void *omap3_secure_ram_storage;
+extern void omap3_pm_off_mode_enable(int);
+extern void omap_sram_idle(void);
+extern int omap3_can_sleep(void);
+extern int set_pwrdm_state(struct powerdomain *pwrdm, u32 state);
+extern int omap3_idle_init(void);
 
 extern int omap3_pm_get_suspend_state(struct powerdomain *pwrdm);
 extern int omap3_pm_set_suspend_state(struct powerdomain *pwrdm, int state);
 
+extern u32 wakeup_timer_seconds;
+extern struct omap_dm_timer *gptimer_wakeup;
+
 #ifdef CONFIG_PM_DEBUG
 extern void omap2_pm_dump(int mode, int resume, unsigned int us);
 extern int omap2_pm_debug;
@@ -36,6 +49,7 @@ extern void omap24xx_cpu_suspend(u32 dll_ctrl, void __iomem *sdrc_dlla_ctrl,
                                        void __iomem *sdrc_power);
 extern void omap34xx_cpu_suspend(u32 *addr, int save_state);
 extern void save_secure_ram_context(u32 *addr);
+extern void omap3_save_scratchpad_contents(void);
 
 extern unsigned int omap24xx_idle_loop_suspend_sz;
 extern unsigned int omap34xx_suspend_sz;
index bff5c4e..cba05b9 100644 (file)
 #include <asm/mach-types.h>
 
 #include <mach/irqs.h>
-#include <mach/clock.h>
-#include <mach/sram.h>
-#include <mach/control.h>
-#include <mach/mux.h>
-#include <mach/dma.h>
-#include <mach/board.h>
+#include <plat/clock.h>
+#include <plat/sram.h>
+#include <plat/control.h>
+#include <plat/mux.h>
+#include <plat/dma.h>
+#include <plat/board.h>
 
 #include "prm.h"
 #include "prm-regbits-24xx.h"
@@ -50,8 +50,8 @@
 #include "sdrc.h"
 #include "pm.h"
 
-#include <mach/powerdomain.h>
-#include <mach/clockdomain.h>
+#include <plat/powerdomain.h>
+#include <plat/clockdomain.h>
 
 static void (*omap2_sram_idle)(void);
 static void (*omap2_sram_suspend)(u32 dllctrl, void __iomem *sdrc_dlla_ctrl,
index 8946319..81ed252 100644 (file)
@@ -5,6 +5,9 @@
  * Tony Lindgren <tony@atomide.com>
  * Jouni Hogander
  *
+ * Copyright (C) 2007 Texas Instruments, Inc.
+ * Rajendra Nayak <rnayak@ti.com>
+ *
  * Copyright (C) 2005 Texas Instruments, Inc.
  * Richard Woodruff <r-woodruff2@ti.com>
  *
 #include <linux/list.h>
 #include <linux/err.h>
 #include <linux/gpio.h>
+#include <linux/clk.h>
+
+#include <plat/sram.h>
+#include <plat/clockdomain.h>
+#include <plat/powerdomain.h>
+#include <plat/control.h>
+#include <plat/serial.h>
+#include <plat/sdrc.h>
+#include <plat/prcm.h>
+#include <plat/gpmc.h>
+#include <plat/dma.h>
+#include <plat/dmtimer.h>
 
-#include <mach/sram.h>
-#include <mach/clockdomain.h>
-#include <mach/powerdomain.h>
-#include <mach/control.h>
-#include <mach/serial.h>
+#include <asm/tlbflush.h>
 
 #include "cm.h"
 #include "cm-regbits-34xx.h"
 
 #include "prm.h"
 #include "pm.h"
+#include "sdrc.h"
+
+/* Scratchpad offsets */
+#define OMAP343X_TABLE_ADDRESS_OFFSET     0x31
+#define OMAP343X_TABLE_VALUE_OFFSET       0x30
+#define OMAP343X_CONTROL_REG_VALUE_OFFSET  0x32
+
+u32 enable_off_mode;
+u32 sleep_while_idle;
+u32 wakeup_timer_seconds;
 
 struct power_state {
        struct powerdomain *pwrdm;
@@ -49,7 +70,112 @@ static LIST_HEAD(pwrst_list);
 
 static void (*_omap_sram_idle)(u32 *addr, int save_state);
 
-static struct powerdomain *mpu_pwrdm;
+static int (*_omap_save_secure_sram)(u32 *addr);
+
+static struct powerdomain *mpu_pwrdm, *neon_pwrdm;
+static struct powerdomain *core_pwrdm, *per_pwrdm;
+static struct powerdomain *cam_pwrdm;
+
+static inline void omap3_per_save_context(void)
+{
+       omap_gpio_save_context();
+}
+
+static inline void omap3_per_restore_context(void)
+{
+       omap_gpio_restore_context();
+}
+
+static void omap3_enable_io_chain(void)
+{
+       int timeout = 0;
+
+       if (omap_rev() >= OMAP3430_REV_ES3_1) {
+               prm_set_mod_reg_bits(OMAP3430_EN_IO_CHAIN, WKUP_MOD, PM_WKEN);
+               /* Do a readback to assure write has been done */
+               prm_read_mod_reg(WKUP_MOD, PM_WKEN);
+
+               while (!(prm_read_mod_reg(WKUP_MOD, PM_WKST) &
+                        OMAP3430_ST_IO_CHAIN)) {
+                       timeout++;
+                       if (timeout > 1000) {
+                               printk(KERN_ERR "Wake up daisy chain "
+                                      "activation failed.\n");
+                               return;
+                       }
+                       prm_set_mod_reg_bits(OMAP3430_ST_IO_CHAIN,
+                                            WKUP_MOD, PM_WKST);
+               }
+       }
+}
+
+static void omap3_disable_io_chain(void)
+{
+       if (omap_rev() >= OMAP3430_REV_ES3_1)
+               prm_clear_mod_reg_bits(OMAP3430_EN_IO_CHAIN, WKUP_MOD, PM_WKEN);
+}
+
+static void omap3_core_save_context(void)
+{
+       u32 control_padconf_off;
+
+       /* Save the padconf registers */
+       control_padconf_off = omap_ctrl_readl(OMAP343X_CONTROL_PADCONF_OFF);
+       control_padconf_off |= START_PADCONF_SAVE;
+       omap_ctrl_writel(control_padconf_off, OMAP343X_CONTROL_PADCONF_OFF);
+       /* wait for the save to complete */
+       while (!omap_ctrl_readl(OMAP343X_CONTROL_GENERAL_PURPOSE_STATUS)
+                       & PADCONF_SAVE_DONE)
+               ;
+       /* Save the Interrupt controller context */
+       omap_intc_save_context();
+       /* Save the GPMC context */
+       omap3_gpmc_save_context();
+       /* Save the system control module context, padconf already save above*/
+       omap3_control_save_context();
+       omap_dma_global_context_save();
+}
+
+static void omap3_core_restore_context(void)
+{
+       /* Restore the control module context, padconf restored by h/w */
+       omap3_control_restore_context();
+       /* Restore the GPMC context */
+       omap3_gpmc_restore_context();
+       /* Restore the interrupt controller context */
+       omap_intc_restore_context();
+       omap_dma_global_context_restore();
+}
+
+/*
+ * FIXME: This function should be called before entering off-mode after
+ * OMAP3 secure services have been accessed. Currently it is only called
+ * once during boot sequence, but this works as we are not using secure
+ * services.
+ */
+static void omap3_save_secure_ram_context(u32 target_mpu_state)
+{
+       u32 ret;
+
+       if (omap_type() != OMAP2_DEVICE_TYPE_GP) {
+               /*
+                * MPU next state must be set to POWER_ON temporarily,
+                * otherwise the WFI executed inside the ROM code
+                * will hang the system.
+                */
+               pwrdm_set_next_pwrst(mpu_pwrdm, PWRDM_POWER_ON);
+               ret = _omap_save_secure_sram((u32 *)
+                               __pa(omap3_secure_ram_storage));
+               pwrdm_set_next_pwrst(mpu_pwrdm, target_mpu_state);
+               /* Following is for error tracking, it should not happen */
+               if (ret) {
+                       printk(KERN_ERR "save_secure_sram() returns %08x\n",
+                               ret);
+                       while (1)
+                               ;
+               }
+       }
+}
 
 /*
  * PRCM Interrupt Handler Helper Function
@@ -161,7 +287,36 @@ static irqreturn_t prcm_interrupt_handler (int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-static void omap_sram_idle(void)
+static void restore_control_register(u32 val)
+{
+       __asm__ __volatile__ ("mcr p15, 0, %0, c1, c0, 0" : : "r" (val));
+}
+
+/* Function to restore the table entry that was modified for enabling MMU */
+static void restore_table_entry(void)
+{
+       u32 *scratchpad_address;
+       u32 previous_value, control_reg_value;
+       u32 *address;
+
+       scratchpad_address = OMAP2_L4_IO_ADDRESS(OMAP343X_SCRATCHPAD);
+
+       /* Get address of entry that was modified */
+       address = (u32 *)__raw_readl(scratchpad_address +
+                                    OMAP343X_TABLE_ADDRESS_OFFSET);
+       /* Get the previous value which needs to be restored */
+       previous_value = __raw_readl(scratchpad_address +
+                                    OMAP343X_TABLE_VALUE_OFFSET);
+       address = __va(address);
+       *address = previous_value;
+       flush_tlb_all();
+       control_reg_value = __raw_readl(scratchpad_address
+                                       + OMAP343X_CONTROL_REG_VALUE_OFFSET);
+       /* This will enable caches and prediction */
+       restore_control_register(control_reg_value);
+}
+
+void omap_sram_idle(void)
 {
        /* Variable to tell what needs to be saved and restored
         * in omap_sram_idle*/
@@ -169,17 +324,32 @@ static void omap_sram_idle(void)
        /* save_state = 1 => Only L1 and logic lost */
        /* save_state = 2 => Only L2 lost */
        /* save_state = 3 => L1, L2 and logic lost */
-       int save_state = 0, mpu_next_state;
+       int save_state = 0;
+       int mpu_next_state = PWRDM_POWER_ON;
+       int per_next_state = PWRDM_POWER_ON;
+       int core_next_state = PWRDM_POWER_ON;
+       int core_prev_state, per_prev_state;
+       u32 sdrc_pwr = 0;
+       int per_state_modified = 0;
 
        if (!_omap_sram_idle)
                return;
 
+       pwrdm_clear_all_prev_pwrst(mpu_pwrdm);
+       pwrdm_clear_all_prev_pwrst(neon_pwrdm);
+       pwrdm_clear_all_prev_pwrst(core_pwrdm);
+       pwrdm_clear_all_prev_pwrst(per_pwrdm);
+
        mpu_next_state = pwrdm_read_next_pwrst(mpu_pwrdm);
        switch (mpu_next_state) {
+       case PWRDM_POWER_ON:
        case PWRDM_POWER_RET:
                /* No need to save context */
                save_state = 0;
                break;
+       case PWRDM_POWER_OFF:
+               save_state = 3;
+               break;
        default:
                /* Invalid state */
                printk(KERN_ERR "Invalid mpu state in sram_idle\n");
@@ -187,68 +357,115 @@ static void omap_sram_idle(void)
        }
        pwrdm_pre_transition();
 
-       omap2_gpio_prepare_for_retention();
-       omap_uart_prepare_idle(0);
-       omap_uart_prepare_idle(1);
-       omap_uart_prepare_idle(2);
+       /* NEON control */
+       if (pwrdm_read_pwrst(neon_pwrdm) == PWRDM_POWER_ON)
+               pwrdm_set_next_pwrst(neon_pwrdm, mpu_next_state);
+
+       /* PER */
+       per_next_state = pwrdm_read_next_pwrst(per_pwrdm);
+       core_next_state = pwrdm_read_next_pwrst(core_pwrdm);
+       if (per_next_state < PWRDM_POWER_ON) {
+               omap_uart_prepare_idle(2);
+               omap2_gpio_prepare_for_retention();
+               if (per_next_state == PWRDM_POWER_OFF) {
+                       if (core_next_state == PWRDM_POWER_ON) {
+                               per_next_state = PWRDM_POWER_RET;
+                               pwrdm_set_next_pwrst(per_pwrdm, per_next_state);
+                               per_state_modified = 1;
+                       } else
+                               omap3_per_save_context();
+               }
+       }
+
+       if (pwrdm_read_pwrst(cam_pwrdm) == PWRDM_POWER_ON)
+               omap2_clkdm_deny_idle(mpu_pwrdm->pwrdm_clkdms[0]);
+
+       /* CORE */
+       if (core_next_state < PWRDM_POWER_ON) {
+               omap_uart_prepare_idle(0);
+               omap_uart_prepare_idle(1);
+               if (core_next_state == PWRDM_POWER_OFF) {
+                       omap3_core_save_context();
+                       omap3_prcm_save_context();
+               }
+               /* Enable IO-PAD and IO-CHAIN wakeups */
+               prm_set_mod_reg_bits(OMAP3430_EN_IO, WKUP_MOD, PM_WKEN);
+               omap3_enable_io_chain();
+       }
+
+       /*
+       * On EMU/HS devices ROM code restores a SRDC value
+       * from scratchpad which has automatic self refresh on timeout
+       * of AUTO_CNT = 1 enabled. This takes care of errata 1.142.
+       * Hence store/restore the SDRC_POWER register here.
+       */
+       if (omap_rev() >= OMAP3430_REV_ES3_0 &&
+           omap_type() != OMAP2_DEVICE_TYPE_GP &&
+           core_next_state == PWRDM_POWER_OFF)
+               sdrc_pwr = sdrc_read_reg(SDRC_POWER);
 
-       _omap_sram_idle(NULL, save_state);
+       /*
+        * omap3_arm_context is the location where ARM registers
+        * get saved. The restore path then reads from this
+        * location and restores them back.
+        */
+       _omap_sram_idle(omap3_arm_context, save_state);
        cpu_init();
 
-       omap_uart_resume_idle(2);
-       omap_uart_resume_idle(1);
-       omap_uart_resume_idle(0);
-       omap2_gpio_resume_after_retention();
+       /* Restore normal SDRC POWER settings */
+       if (omap_rev() >= OMAP3430_REV_ES3_0 &&
+           omap_type() != OMAP2_DEVICE_TYPE_GP &&
+           core_next_state == PWRDM_POWER_OFF)
+               sdrc_write_reg(sdrc_pwr, SDRC_POWER);
+
+       /* Restore table entry modified during MMU restoration */
+       if (pwrdm_read_prev_pwrst(mpu_pwrdm) == PWRDM_POWER_OFF)
+               restore_table_entry();
+
+       /* CORE */
+       if (core_next_state < PWRDM_POWER_ON) {
+               core_prev_state = pwrdm_read_prev_pwrst(core_pwrdm);
+               if (core_prev_state == PWRDM_POWER_OFF) {
+                       omap3_core_restore_context();
+                       omap3_prcm_restore_context();
+                       omap3_sram_restore_context();
+                       omap2_sms_restore_context();
+               }
+               omap_uart_resume_idle(0);
+               omap_uart_resume_idle(1);
+               if (core_next_state == PWRDM_POWER_OFF)
+                       prm_clear_mod_reg_bits(OMAP3430_AUTO_OFF,
+                                              OMAP3430_GR_MOD,
+                                              OMAP3_PRM_VOLTCTRL_OFFSET);
+       }
 
-       pwrdm_post_transition();
+       /* PER */
+       if (per_next_state < PWRDM_POWER_ON) {
+               per_prev_state = pwrdm_read_prev_pwrst(per_pwrdm);
+               if (per_prev_state == PWRDM_POWER_OFF)
+                       omap3_per_restore_context();
+               omap2_gpio_resume_after_retention();
+               omap_uart_resume_idle(2);
+               if (per_state_modified)
+                       pwrdm_set_next_pwrst(per_pwrdm, PWRDM_POWER_OFF);
+       }
 
-}
+       /* Disable IO-PAD and IO-CHAIN wakeup */
+       if (core_next_state < PWRDM_POWER_ON) {
+               prm_clear_mod_reg_bits(OMAP3430_EN_IO, WKUP_MOD, PM_WKEN);
+               omap3_disable_io_chain();
+       }
 
-/*
- * Check if functional clocks are enabled before entering
- * sleep. This function could be behind CONFIG_PM_DEBUG
- * when all drivers are configuring their sysconfig registers
- * properly and using their clocks properly.
- */
-static int omap3_fclks_active(void)
-{
-       u32 fck_core1 = 0, fck_core3 = 0, fck_sgx = 0, fck_dss = 0,
-               fck_cam = 0, fck_per = 0, fck_usbhost = 0;
+       pwrdm_post_transition();
 
-       fck_core1 = cm_read_mod_reg(CORE_MOD,
-                                   CM_FCLKEN1);
-       if (omap_rev() > OMAP3430_REV_ES1_0) {
-               fck_core3 = cm_read_mod_reg(CORE_MOD,
-                                           OMAP3430ES2_CM_FCLKEN3);
-               fck_sgx = cm_read_mod_reg(OMAP3430ES2_SGX_MOD,
-                                         CM_FCLKEN);
-               fck_usbhost = cm_read_mod_reg(OMAP3430ES2_USBHOST_MOD,
-                                             CM_FCLKEN);
-       } else
-               fck_sgx = cm_read_mod_reg(GFX_MOD,
-                                         OMAP3430ES2_CM_FCLKEN3);
-       fck_dss = cm_read_mod_reg(OMAP3430_DSS_MOD,
-                                 CM_FCLKEN);
-       fck_cam = cm_read_mod_reg(OMAP3430_CAM_MOD,
-                                 CM_FCLKEN);
-       fck_per = cm_read_mod_reg(OMAP3430_PER_MOD,
-                                 CM_FCLKEN);
-
-       /* Ignore UART clocks.  These are handled by UART core (serial.c) */
-       fck_core1 &= ~(OMAP3430_EN_UART1 | OMAP3430_EN_UART2);
-       fck_per &= ~OMAP3430_EN_UART3;
-
-       if (fck_core1 | fck_core3 | fck_sgx | fck_dss |
-           fck_cam | fck_per | fck_usbhost)
-               return 1;
-       return 0;
+       omap2_clkdm_allow_idle(mpu_pwrdm->pwrdm_clkdms[0]);
 }
 
-static int omap3_can_sleep(void)
+int omap3_can_sleep(void)
 {
-       if (!omap_uart_can_sleep())
+       if (!sleep_while_idle)
                return 0;
-       if (omap3_fclks_active())
+       if (!omap_uart_can_sleep())
                return 0;
        return 1;
 }
@@ -256,7 +473,7 @@ static int omap3_can_sleep(void)
 /* This sets pwrdm state (other than mpu & core. Currently only ON &
  * RET are supported. Function is assuming that clkdm doesn't have
  * hw_sup mode enabled. */
-static int set_pwrdm_state(struct powerdomain *pwrdm, u32 state)
+int set_pwrdm_state(struct powerdomain *pwrdm, u32 state)
 {
        u32 cur_state;
        int sleep_switch = 0;
@@ -306,7 +523,7 @@ static void omap3_pm_idle(void)
        if (!omap3_can_sleep())
                goto out;
 
-       if (omap_irq_pending())
+       if (omap_irq_pending() || need_resched())
                goto out;
 
        omap_sram_idle();
@@ -319,6 +536,22 @@ out:
 #ifdef CONFIG_SUSPEND
 static suspend_state_t suspend_state;
 
+static void omap2_pm_wakeup_on_timer(u32 seconds)
+{
+       u32 tick_rate, cycles;
+
+       if (!seconds)
+               return;
+
+       tick_rate = clk_get_rate(omap_dm_timer_get_fclk(gptimer_wakeup));
+       cycles = tick_rate * seconds;
+       omap_dm_timer_stop(gptimer_wakeup);
+       omap_dm_timer_set_load_start(gptimer_wakeup, 0, 0xffffffff - cycles);
+
+       pr_info("PM: Resume timer in %d secs (%d ticks at %d ticks/sec.)\n",
+               seconds, cycles, tick_rate);
+}
+
 static int omap3_pm_prepare(void)
 {
        disable_hlt();
@@ -330,6 +563,9 @@ static int omap3_pm_suspend(void)
        struct power_state *pwrst;
        int state, ret = 0;
 
+       if (wakeup_timer_seconds)
+               omap2_pm_wakeup_on_timer(wakeup_timer_seconds);
+
        /* Read current next_pwrsts */
        list_for_each_entry(pwrst, &pwrst_list, node)
                pwrst->saved_state = pwrdm_read_next_pwrst(pwrst->pwrdm);
@@ -690,6 +926,22 @@ static void __init prcm_setup_regs(void)
        omap3_d2d_idle();
 }
 
+void omap3_pm_off_mode_enable(int enable)
+{
+       struct power_state *pwrst;
+       u32 state;
+
+       if (enable)
+               state = PWRDM_POWER_OFF;
+       else
+               state = PWRDM_POWER_RET;
+
+       list_for_each_entry(pwrst, &pwrst_list, node) {
+               pwrst->next_state = state;
+               set_pwrdm_state(pwrst->pwrdm, state);
+       }
+}
+
 int omap3_pm_get_suspend_state(struct powerdomain *pwrdm)
 {
        struct power_state *pwrst;
@@ -749,6 +1001,15 @@ static int __init clkdms_setup(struct clockdomain *clkdm, void *unused)
        return 0;
 }
 
+void omap_push_sram_idle(void)
+{
+       _omap_sram_idle = omap_sram_push(omap34xx_cpu_suspend,
+                                       omap34xx_cpu_suspend_sz);
+       if (omap_type() != OMAP2_DEVICE_TYPE_GP)
+               _omap_save_secure_sram = omap_sram_push(save_secure_ram_context,
+                               save_secure_ram_context_sz);
+}
+
 static int __init omap3_pm_init(void)
 {
        struct power_state *pwrst, *tmp;
@@ -786,15 +1047,47 @@ static int __init omap3_pm_init(void)
                goto err2;
        }
 
-       _omap_sram_idle = omap_sram_push(omap34xx_cpu_suspend,
-                                        omap34xx_cpu_suspend_sz);
+       neon_pwrdm = pwrdm_lookup("neon_pwrdm");
+       per_pwrdm = pwrdm_lookup("per_pwrdm");
+       core_pwrdm = pwrdm_lookup("core_pwrdm");
+       cam_pwrdm = pwrdm_lookup("cam_pwrdm");
 
+       omap_push_sram_idle();
 #ifdef CONFIG_SUSPEND
        suspend_set_ops(&omap_pm_ops);
 #endif /* CONFIG_SUSPEND */
 
        pm_idle = omap3_pm_idle;
+       omap3_idle_init();
+
+       pwrdm_add_wkdep(neon_pwrdm, mpu_pwrdm);
+       /*
+        * REVISIT: This wkdep is only necessary when GPIO2-6 are enabled for
+        * IO-pad wakeup.  Otherwise it will unnecessarily waste power
+        * waking up PER with every CORE wakeup - see
+        * http://marc.info/?l=linux-omap&m=121852150710062&w=2
+       */
+       pwrdm_add_wkdep(per_pwrdm, core_pwrdm);
+
+       if (omap_type() != OMAP2_DEVICE_TYPE_GP) {
+               omap3_secure_ram_storage =
+                       kmalloc(0x803F, GFP_KERNEL);
+               if (!omap3_secure_ram_storage)
+                       printk(KERN_ERR "Memory allocation failed when"
+                                       "allocating for secure sram context\n");
+
+               local_irq_disable();
+               local_fiq_disable();
+
+               omap_dma_global_context_save();
+               omap3_save_secure_ram_context(PWRDM_POWER_ON);
+               omap_dma_global_context_restore();
+
+               local_irq_enable();
+               local_fiq_enable();
+       }
 
+       omap3_save_scratchpad_contents();
 err1:
        return ret;
 err2:
index f00289a..b6990e3 100644 (file)
@@ -31,9 +31,9 @@
 #include "prm.h"
 #include "prm-regbits-34xx.h"
 
-#include <mach/cpu.h>
-#include <mach/powerdomain.h>
-#include <mach/clockdomain.h>
+#include <plat/cpu.h>
+#include <plat/powerdomain.h>
+#include <plat/clockdomain.h>
 
 #include "pm.h"
 
index 691470e..057b2e3 100644 (file)
@@ -63,7 +63,7 @@
  * XXX encode hardware fixed wakeup dependencies -- esp. for 3430 CORE
  */
 
-#include <mach/powerdomain.h>
+#include <plat/powerdomain.h>
 
 #include "prcm-common.h"
 #include "prm.h"
index 9f08dc3..bd249a4 100644 (file)
@@ -20,7 +20,7 @@
  * the array in mach-omap2/powerdomains.h.
  */
 
-#include <mach/powerdomain.h>
+#include <plat/powerdomain.h>
 
 #include "prcm-common.h"
 #include "prm.h"
index 4dcf94b..fd09b08 100644 (file)
@@ -20,7 +20,7 @@
  * the array in mach-omap2/powerdomains.h.
  */
 
-#include <mach/powerdomain.h>
+#include <plat/powerdomain.h>
 
 #include "prcm-common.h"
 #include "prm.h"
@@ -338,7 +338,13 @@ static struct powerdomain usbhost_pwrdm = {
        .sleepdep_srcs    = dss_per_usbhost_sleepdeps,
        .pwrsts           = PWRSTS_OFF_RET_ON,
        .pwrsts_logic_ret = PWRDM_POWER_RET,
-       .flags            = PWRDM_HAS_HDWR_SAR, /* for USBHOST ctrlr only */
+       /*
+        * REVISIT: Enabling usb host save and restore mechanism seems to
+        * leave the usb host domain permanently in ACTIVE mode after
+        * changing the usb host power domain state from OFF to active once.
+        * Disabling for now.
+        */
+       /*.flags          = PWRDM_HAS_HDWR_SAR,*/ /* for USBHOST ctrlr only */
        .banks            = 1,
        .pwrsts_mem_ret   = {
                [0] = PWRDM_POWER_RET, /* MEMRETSTATE */
index ced555a..029d376 100644 (file)
@@ -7,6 +7,9 @@
  *
  * Written by Tony Lindgren <tony.lindgren@nokia.com>
  *
+ * Copyright (C) 2007 Texas Instruments, Inc.
+ * Rajendra Nayak <rnayak@ti.com>
+ *
  * Some pieces of code Copyright (C) 2005 Texas Instruments, Inc.
  *
  * This program is free software; you can redistribute it and/or modify
 #include <linux/io.h>
 #include <linux/delay.h>
 
-#include <mach/common.h>
-#include <mach/prcm.h>
+#include <plat/common.h>
+#include <plat/prcm.h>
+#include <plat/irqs.h>
+#include <plat/control.h>
 
 #include "clock.h"
+#include "cm.h"
 #include "prm.h"
 #include "prm-regbits-24xx.h"
 
@@ -31,6 +37,89 @@ static void __iomem *cm_base;
 
 #define MAX_MODULE_ENABLE_WAIT         100000
 
+struct omap3_prcm_regs {
+       u32 control_padconf_sys_nirq;
+       u32 iva2_cm_clksel1;
+       u32 iva2_cm_clksel2;
+       u32 cm_sysconfig;
+       u32 sgx_cm_clksel;
+       u32 wkup_cm_clksel;
+       u32 dss_cm_clksel;
+       u32 cam_cm_clksel;
+       u32 per_cm_clksel;
+       u32 emu_cm_clksel;
+       u32 emu_cm_clkstctrl;
+       u32 pll_cm_autoidle2;
+       u32 pll_cm_clksel4;
+       u32 pll_cm_clksel5;
+       u32 pll_cm_clken;
+       u32 pll_cm_clken2;
+       u32 cm_polctrl;
+       u32 iva2_cm_fclken;
+       u32 iva2_cm_clken_pll;
+       u32 core_cm_fclken1;
+       u32 core_cm_fclken3;
+       u32 sgx_cm_fclken;
+       u32 wkup_cm_fclken;
+       u32 dss_cm_fclken;
+       u32 cam_cm_fclken;
+       u32 per_cm_fclken;
+       u32 usbhost_cm_fclken;
+       u32 core_cm_iclken1;
+       u32 core_cm_iclken2;
+       u32 core_cm_iclken3;
+       u32 sgx_cm_iclken;
+       u32 wkup_cm_iclken;
+       u32 dss_cm_iclken;
+       u32 cam_cm_iclken;
+       u32 per_cm_iclken;
+       u32 usbhost_cm_iclken;
+       u32 iva2_cm_autiidle2;
+       u32 mpu_cm_autoidle2;
+       u32 pll_cm_autoidle;
+       u32 iva2_cm_clkstctrl;
+       u32 mpu_cm_clkstctrl;
+       u32 core_cm_clkstctrl;
+       u32 sgx_cm_clkstctrl;
+       u32 dss_cm_clkstctrl;
+       u32 cam_cm_clkstctrl;
+       u32 per_cm_clkstctrl;
+       u32 neon_cm_clkstctrl;
+       u32 usbhost_cm_clkstctrl;
+       u32 core_cm_autoidle1;
+       u32 core_cm_autoidle2;
+       u32 core_cm_autoidle3;
+       u32 wkup_cm_autoidle;
+       u32 dss_cm_autoidle;
+       u32 cam_cm_autoidle;
+       u32 per_cm_autoidle;
+       u32 usbhost_cm_autoidle;
+       u32 sgx_cm_sleepdep;
+       u32 dss_cm_sleepdep;
+       u32 cam_cm_sleepdep;
+       u32 per_cm_sleepdep;
+       u32 usbhost_cm_sleepdep;
+       u32 cm_clkout_ctrl;
+       u32 prm_clkout_ctrl;
+       u32 sgx_pm_wkdep;
+       u32 dss_pm_wkdep;
+       u32 cam_pm_wkdep;
+       u32 per_pm_wkdep;
+       u32 neon_pm_wkdep;
+       u32 usbhost_pm_wkdep;
+       u32 core_pm_mpugrpsel1;
+       u32 iva2_pm_ivagrpsel1;
+       u32 core_pm_mpugrpsel3;
+       u32 core_pm_ivagrpsel3;
+       u32 wkup_pm_mpugrpsel;
+       u32 wkup_pm_ivagrpsel;
+       u32 per_pm_mpugrpsel;
+       u32 per_pm_ivagrpsel;
+       u32 wkup_pm_wken;
+};
+
+struct omap3_prcm_regs prcm_context;
+
 u32 omap_prcm_get_reset_sources(void)
 {
        /* XXX This presumably needs modification for 34XX */
@@ -46,9 +135,18 @@ void omap_prcm_arch_reset(char mode)
 
        if (cpu_is_omap24xx())
                prcm_offs = WKUP_MOD;
-       else if (cpu_is_omap34xx())
+       else if (cpu_is_omap34xx()) {
+               u32 l;
+
                prcm_offs = OMAP3430_GR_MOD;
-       else
+               l = ('B' << 24) | ('M' << 16) | mode;
+               /* Reserve the first word in scratchpad for communicating
+                * with the boot ROM. A pointer to a data structure
+                * describing the boot process can be stored there,
+                * cf. OMAP34xx TRM, Initialization / Software Booting
+                * Configuration. */
+               omap_writel(l, OMAP343X_SCRATCHPAD + 4);
+       } else
                WARN_ON(1);
 
        prm_set_mod_reg_bits(OMAP_RST_DPLL3, prcm_offs, RM_RSTCTRL);
@@ -168,3 +266,308 @@ void __init omap2_set_globals_prcm(struct omap_globals *omap2_globals)
        prm_base = omap2_globals->prm;
        cm_base = omap2_globals->cm;
 }
+
+#ifdef CONFIG_ARCH_OMAP3
+void omap3_prcm_save_context(void)
+{
+       prcm_context.control_padconf_sys_nirq =
+                        omap_ctrl_readl(OMAP343X_CONTROL_PADCONF_SYSNIRQ);
+       prcm_context.iva2_cm_clksel1 =
+                        cm_read_mod_reg(OMAP3430_IVA2_MOD, CM_CLKSEL1);
+       prcm_context.iva2_cm_clksel2 =
+                        cm_read_mod_reg(OMAP3430_IVA2_MOD, CM_CLKSEL2);
+       prcm_context.cm_sysconfig = __raw_readl(OMAP3430_CM_SYSCONFIG);
+       prcm_context.sgx_cm_clksel =
+                        cm_read_mod_reg(OMAP3430ES2_SGX_MOD, CM_CLKSEL);
+       prcm_context.wkup_cm_clksel = cm_read_mod_reg(WKUP_MOD, CM_CLKSEL);
+       prcm_context.dss_cm_clksel =
+                        cm_read_mod_reg(OMAP3430_DSS_MOD, CM_CLKSEL);
+       prcm_context.cam_cm_clksel =
+                        cm_read_mod_reg(OMAP3430_CAM_MOD, CM_CLKSEL);
+       prcm_context.per_cm_clksel =
+                        cm_read_mod_reg(OMAP3430_PER_MOD, CM_CLKSEL);
+       prcm_context.emu_cm_clksel =
+                        cm_read_mod_reg(OMAP3430_EMU_MOD, CM_CLKSEL1);
+       prcm_context.emu_cm_clkstctrl =
+                        cm_read_mod_reg(OMAP3430_EMU_MOD, CM_CLKSTCTRL);
+       prcm_context.pll_cm_autoidle2 =
+                        cm_read_mod_reg(PLL_MOD, CM_AUTOIDLE2);
+       prcm_context.pll_cm_clksel4 =
+                       cm_read_mod_reg(PLL_MOD, OMAP3430ES2_CM_CLKSEL4);
+       prcm_context.pll_cm_clksel5 =
+                        cm_read_mod_reg(PLL_MOD, OMAP3430ES2_CM_CLKSEL5);
+       prcm_context.pll_cm_clken =
+                       cm_read_mod_reg(PLL_MOD, CM_CLKEN);
+       prcm_context.pll_cm_clken2 =
+                       cm_read_mod_reg(PLL_MOD, OMAP3430ES2_CM_CLKEN2);
+       prcm_context.cm_polctrl = __raw_readl(OMAP3430_CM_POLCTRL);
+       prcm_context.iva2_cm_fclken =
+                        cm_read_mod_reg(OMAP3430_IVA2_MOD, CM_FCLKEN);
+       prcm_context.iva2_cm_clken_pll = cm_read_mod_reg(OMAP3430_IVA2_MOD,
+                       OMAP3430_CM_CLKEN_PLL);
+       prcm_context.core_cm_fclken1 =
+                        cm_read_mod_reg(CORE_MOD, CM_FCLKEN1);
+       prcm_context.core_cm_fclken3 =
+                        cm_read_mod_reg(CORE_MOD, OMAP3430ES2_CM_FCLKEN3);
+       prcm_context.sgx_cm_fclken =
+                        cm_read_mod_reg(OMAP3430ES2_SGX_MOD, CM_FCLKEN);
+       prcm_context.wkup_cm_fclken =
+                        cm_read_mod_reg(WKUP_MOD, CM_FCLKEN);
+       prcm_context.dss_cm_fclken =
+                        cm_read_mod_reg(OMAP3430_DSS_MOD, CM_FCLKEN);
+       prcm_context.cam_cm_fclken =
+                        cm_read_mod_reg(OMAP3430_CAM_MOD, CM_FCLKEN);
+       prcm_context.per_cm_fclken =
+                        cm_read_mod_reg(OMAP3430_PER_MOD, CM_FCLKEN);
+       prcm_context.usbhost_cm_fclken =
+                        cm_read_mod_reg(OMAP3430ES2_USBHOST_MOD, CM_FCLKEN);
+       prcm_context.core_cm_iclken1 =
+                        cm_read_mod_reg(CORE_MOD, CM_ICLKEN1);
+       prcm_context.core_cm_iclken2 =
+                        cm_read_mod_reg(CORE_MOD, CM_ICLKEN2);
+       prcm_context.core_cm_iclken3 =
+                        cm_read_mod_reg(CORE_MOD, CM_ICLKEN3);
+       prcm_context.sgx_cm_iclken =
+                        cm_read_mod_reg(OMAP3430ES2_SGX_MOD, CM_ICLKEN);
+       prcm_context.wkup_cm_iclken =
+                        cm_read_mod_reg(WKUP_MOD, CM_ICLKEN);
+       prcm_context.dss_cm_iclken =
+                        cm_read_mod_reg(OMAP3430_DSS_MOD, CM_ICLKEN);
+       prcm_context.cam_cm_iclken =
+                        cm_read_mod_reg(OMAP3430_CAM_MOD, CM_ICLKEN);
+       prcm_context.per_cm_iclken =
+                        cm_read_mod_reg(OMAP3430_PER_MOD, CM_ICLKEN);
+       prcm_context.usbhost_cm_iclken =
+                        cm_read_mod_reg(OMAP3430ES2_USBHOST_MOD, CM_ICLKEN);
+       prcm_context.iva2_cm_autiidle2 =
+                        cm_read_mod_reg(OMAP3430_IVA2_MOD, CM_AUTOIDLE2);
+       prcm_context.mpu_cm_autoidle2 =
+                        cm_read_mod_reg(MPU_MOD, CM_AUTOIDLE2);
+       prcm_context.pll_cm_autoidle =
+                        cm_read_mod_reg(PLL_MOD, CM_AUTOIDLE);
+       prcm_context.iva2_cm_clkstctrl =
+                        cm_read_mod_reg(OMAP3430_IVA2_MOD, CM_CLKSTCTRL);
+       prcm_context.mpu_cm_clkstctrl =
+                        cm_read_mod_reg(MPU_MOD, CM_CLKSTCTRL);
+       prcm_context.core_cm_clkstctrl =
+                        cm_read_mod_reg(CORE_MOD, CM_CLKSTCTRL);
+       prcm_context.sgx_cm_clkstctrl =
+                        cm_read_mod_reg(OMAP3430ES2_SGX_MOD, CM_CLKSTCTRL);
+       prcm_context.dss_cm_clkstctrl =
+                        cm_read_mod_reg(OMAP3430_DSS_MOD, CM_CLKSTCTRL);
+       prcm_context.cam_cm_clkstctrl =
+                        cm_read_mod_reg(OMAP3430_CAM_MOD, CM_CLKSTCTRL);
+       prcm_context.per_cm_clkstctrl =
+                        cm_read_mod_reg(OMAP3430_PER_MOD, CM_CLKSTCTRL);
+       prcm_context.neon_cm_clkstctrl =
+                        cm_read_mod_reg(OMAP3430_NEON_MOD, CM_CLKSTCTRL);
+       prcm_context.usbhost_cm_clkstctrl =
+                        cm_read_mod_reg(OMAP3430ES2_USBHOST_MOD, CM_CLKSTCTRL);
+       prcm_context.core_cm_autoidle1 =
+                        cm_read_mod_reg(CORE_MOD, CM_AUTOIDLE1);
+       prcm_context.core_cm_autoidle2 =
+                        cm_read_mod_reg(CORE_MOD, CM_AUTOIDLE2);
+       prcm_context.core_cm_autoidle3 =
+                        cm_read_mod_reg(CORE_MOD, CM_AUTOIDLE3);
+       prcm_context.wkup_cm_autoidle =
+                        cm_read_mod_reg(WKUP_MOD, CM_AUTOIDLE);
+       prcm_context.dss_cm_autoidle =
+                        cm_read_mod_reg(OMAP3430_DSS_MOD, CM_AUTOIDLE);
+       prcm_context.cam_cm_autoidle =
+                        cm_read_mod_reg(OMAP3430_CAM_MOD, CM_AUTOIDLE);
+       prcm_context.per_cm_autoidle =
+                        cm_read_mod_reg(OMAP3430_PER_MOD, CM_AUTOIDLE);
+       prcm_context.usbhost_cm_autoidle =
+                        cm_read_mod_reg(OMAP3430ES2_USBHOST_MOD, CM_AUTOIDLE);
+       prcm_context.sgx_cm_sleepdep =
+                cm_read_mod_reg(OMAP3430ES2_SGX_MOD, OMAP3430_CM_SLEEPDEP);
+       prcm_context.dss_cm_sleepdep =
+                cm_read_mod_reg(OMAP3430_DSS_MOD, OMAP3430_CM_SLEEPDEP);
+       prcm_context.cam_cm_sleepdep =
+                cm_read_mod_reg(OMAP3430_CAM_MOD, OMAP3430_CM_SLEEPDEP);
+       prcm_context.per_cm_sleepdep =
+                cm_read_mod_reg(OMAP3430_PER_MOD, OMAP3430_CM_SLEEPDEP);
+       prcm_context.usbhost_cm_sleepdep =
+                cm_read_mod_reg(OMAP3430ES2_USBHOST_MOD, OMAP3430_CM_SLEEPDEP);
+       prcm_context.cm_clkout_ctrl = cm_read_mod_reg(OMAP3430_CCR_MOD,
+                OMAP3_CM_CLKOUT_CTRL_OFFSET);
+       prcm_context.prm_clkout_ctrl = prm_read_mod_reg(OMAP3430_CCR_MOD,
+               OMAP3_PRM_CLKOUT_CTRL_OFFSET);
+       prcm_context.sgx_pm_wkdep =
+                prm_read_mod_reg(OMAP3430ES2_SGX_MOD, PM_WKDEP);
+       prcm_context.dss_pm_wkdep =
+                prm_read_mod_reg(OMAP3430_DSS_MOD, PM_WKDEP);
+       prcm_context.cam_pm_wkdep =
+                prm_read_mod_reg(OMAP3430_CAM_MOD, PM_WKDEP);
+       prcm_context.per_pm_wkdep =
+                prm_read_mod_reg(OMAP3430_PER_MOD, PM_WKDEP);
+       prcm_context.neon_pm_wkdep =
+                prm_read_mod_reg(OMAP3430_NEON_MOD, PM_WKDEP);
+       prcm_context.usbhost_pm_wkdep =
+                prm_read_mod_reg(OMAP3430ES2_USBHOST_MOD, PM_WKDEP);
+       prcm_context.core_pm_mpugrpsel1 =
+                prm_read_mod_reg(CORE_MOD, OMAP3430_PM_MPUGRPSEL1);
+       prcm_context.iva2_pm_ivagrpsel1 =
+                prm_read_mod_reg(OMAP3430_IVA2_MOD, OMAP3430_PM_IVAGRPSEL1);
+       prcm_context.core_pm_mpugrpsel3 =
+                prm_read_mod_reg(CORE_MOD, OMAP3430ES2_PM_MPUGRPSEL3);
+       prcm_context.core_pm_ivagrpsel3 =
+                prm_read_mod_reg(CORE_MOD, OMAP3430ES2_PM_IVAGRPSEL3);
+       prcm_context.wkup_pm_mpugrpsel =
+                prm_read_mod_reg(WKUP_MOD, OMAP3430_PM_MPUGRPSEL);
+       prcm_context.wkup_pm_ivagrpsel =
+                prm_read_mod_reg(WKUP_MOD, OMAP3430_PM_IVAGRPSEL);
+       prcm_context.per_pm_mpugrpsel =
+                prm_read_mod_reg(OMAP3430_PER_MOD, OMAP3430_PM_MPUGRPSEL);
+       prcm_context.per_pm_ivagrpsel =
+                prm_read_mod_reg(OMAP3430_PER_MOD, OMAP3430_PM_IVAGRPSEL);
+       prcm_context.wkup_pm_wken = prm_read_mod_reg(WKUP_MOD, PM_WKEN);
+       return;
+}
+
+void omap3_prcm_restore_context(void)
+{
+       omap_ctrl_writel(prcm_context.control_padconf_sys_nirq,
+                                        OMAP343X_CONTROL_PADCONF_SYSNIRQ);
+       cm_write_mod_reg(prcm_context.iva2_cm_clksel1, OMAP3430_IVA2_MOD,
+                                        CM_CLKSEL1);
+       cm_write_mod_reg(prcm_context.iva2_cm_clksel2, OMAP3430_IVA2_MOD,
+                                        CM_CLKSEL2);
+       __raw_writel(prcm_context.cm_sysconfig, OMAP3430_CM_SYSCONFIG);
+       cm_write_mod_reg(prcm_context.sgx_cm_clksel, OMAP3430ES2_SGX_MOD,
+                                        CM_CLKSEL);
+       cm_write_mod_reg(prcm_context.wkup_cm_clksel, WKUP_MOD, CM_CLKSEL);
+       cm_write_mod_reg(prcm_context.dss_cm_clksel, OMAP3430_DSS_MOD,
+                                        CM_CLKSEL);
+       cm_write_mod_reg(prcm_context.cam_cm_clksel, OMAP3430_CAM_MOD,
+                                        CM_CLKSEL);
+       cm_write_mod_reg(prcm_context.per_cm_clksel, OMAP3430_PER_MOD,
+                                        CM_CLKSEL);
+       cm_write_mod_reg(prcm_context.emu_cm_clksel, OMAP3430_EMU_MOD,
+                                        CM_CLKSEL1);
+       cm_write_mod_reg(prcm_context.emu_cm_clkstctrl, OMAP3430_EMU_MOD,
+                                        CM_CLKSTCTRL);
+       cm_write_mod_reg(prcm_context.pll_cm_autoidle2, PLL_MOD,
+                                        CM_AUTOIDLE2);
+       cm_write_mod_reg(prcm_context.pll_cm_clksel4, PLL_MOD,
+                                       OMAP3430ES2_CM_CLKSEL4);
+       cm_write_mod_reg(prcm_context.pll_cm_clksel5, PLL_MOD,
+                                        OMAP3430ES2_CM_CLKSEL5);
+       cm_write_mod_reg(prcm_context.pll_cm_clken, PLL_MOD, CM_CLKEN);
+       cm_write_mod_reg(prcm_context.pll_cm_clken2, PLL_MOD,
+                                       OMAP3430ES2_CM_CLKEN2);
+       __raw_writel(prcm_context.cm_polctrl, OMAP3430_CM_POLCTRL);
+       cm_write_mod_reg(prcm_context.iva2_cm_fclken, OMAP3430_IVA2_MOD,
+                                        CM_FCLKEN);
+       cm_write_mod_reg(prcm_context.iva2_cm_clken_pll, OMAP3430_IVA2_MOD,
+                                       OMAP3430_CM_CLKEN_PLL);
+       cm_write_mod_reg(prcm_context.core_cm_fclken1, CORE_MOD, CM_FCLKEN1);
+       cm_write_mod_reg(prcm_context.core_cm_fclken3, CORE_MOD,
+                                        OMAP3430ES2_CM_FCLKEN3);
+       cm_write_mod_reg(prcm_context.sgx_cm_fclken, OMAP3430ES2_SGX_MOD,
+                                        CM_FCLKEN);
+       cm_write_mod_reg(prcm_context.wkup_cm_fclken, WKUP_MOD, CM_FCLKEN);
+       cm_write_mod_reg(prcm_context.dss_cm_fclken, OMAP3430_DSS_MOD,
+                                        CM_FCLKEN);
+       cm_write_mod_reg(prcm_context.cam_cm_fclken, OMAP3430_CAM_MOD,
+                                        CM_FCLKEN);
+       cm_write_mod_reg(prcm_context.per_cm_fclken, OMAP3430_PER_MOD,
+                                        CM_FCLKEN);
+       cm_write_mod_reg(prcm_context.usbhost_cm_fclken,
+                                        OMAP3430ES2_USBHOST_MOD, CM_FCLKEN);
+       cm_write_mod_reg(prcm_context.core_cm_iclken1, CORE_MOD, CM_ICLKEN1);
+       cm_write_mod_reg(prcm_context.core_cm_iclken2, CORE_MOD, CM_ICLKEN2);
+       cm_write_mod_reg(prcm_context.core_cm_iclken3, CORE_MOD, CM_ICLKEN3);
+       cm_write_mod_reg(prcm_context.sgx_cm_iclken, OMAP3430ES2_SGX_MOD,
+                                       CM_ICLKEN);
+       cm_write_mod_reg(prcm_context.wkup_cm_iclken, WKUP_MOD, CM_ICLKEN);
+       cm_write_mod_reg(prcm_context.dss_cm_iclken, OMAP3430_DSS_MOD,
+                                       CM_ICLKEN);
+       cm_write_mod_reg(prcm_context.cam_cm_iclken, OMAP3430_CAM_MOD,
+                                       CM_ICLKEN);
+       cm_write_mod_reg(prcm_context.per_cm_iclken, OMAP3430_PER_MOD,
+                                       CM_ICLKEN);
+       cm_write_mod_reg(prcm_context.usbhost_cm_iclken,
+                                       OMAP3430ES2_USBHOST_MOD, CM_ICLKEN);
+       cm_write_mod_reg(prcm_context.iva2_cm_autiidle2, OMAP3430_IVA2_MOD,
+                                       CM_AUTOIDLE2);
+       cm_write_mod_reg(prcm_context.mpu_cm_autoidle2, MPU_MOD, CM_AUTOIDLE2);
+       cm_write_mod_reg(prcm_context.pll_cm_autoidle, PLL_MOD, CM_AUTOIDLE);
+       cm_write_mod_reg(prcm_context.iva2_cm_clkstctrl, OMAP3430_IVA2_MOD,
+                                       CM_CLKSTCTRL);
+       cm_write_mod_reg(prcm_context.mpu_cm_clkstctrl, MPU_MOD, CM_CLKSTCTRL);
+       cm_write_mod_reg(prcm_context.core_cm_clkstctrl, CORE_MOD,
+                                       CM_CLKSTCTRL);
+       cm_write_mod_reg(prcm_context.sgx_cm_clkstctrl, OMAP3430ES2_SGX_MOD,
+                                       CM_CLKSTCTRL);
+       cm_write_mod_reg(prcm_context.dss_cm_clkstctrl, OMAP3430_DSS_MOD,
+                                       CM_CLKSTCTRL);
+       cm_write_mod_reg(prcm_context.cam_cm_clkstctrl, OMAP3430_CAM_MOD,
+                                       CM_CLKSTCTRL);
+       cm_write_mod_reg(prcm_context.per_cm_clkstctrl, OMAP3430_PER_MOD,
+                                       CM_CLKSTCTRL);
+       cm_write_mod_reg(prcm_context.neon_cm_clkstctrl, OMAP3430_NEON_MOD,
+                                       CM_CLKSTCTRL);
+       cm_write_mod_reg(prcm_context.usbhost_cm_clkstctrl,
+                                       OMAP3430ES2_USBHOST_MOD, CM_CLKSTCTRL);
+       cm_write_mod_reg(prcm_context.core_cm_autoidle1, CORE_MOD,
+                                       CM_AUTOIDLE1);
+       cm_write_mod_reg(prcm_context.core_cm_autoidle2, CORE_MOD,
+                                       CM_AUTOIDLE2);
+       cm_write_mod_reg(prcm_context.core_cm_autoidle3, CORE_MOD,
+                                       CM_AUTOIDLE3);
+       cm_write_mod_reg(prcm_context.wkup_cm_autoidle, WKUP_MOD, CM_AUTOIDLE);
+       cm_write_mod_reg(prcm_context.dss_cm_autoidle, OMAP3430_DSS_MOD,
+                                       CM_AUTOIDLE);
+       cm_write_mod_reg(prcm_context.cam_cm_autoidle, OMAP3430_CAM_MOD,
+                                       CM_AUTOIDLE);
+       cm_write_mod_reg(prcm_context.per_cm_autoidle, OMAP3430_PER_MOD,
+                                       CM_AUTOIDLE);
+       cm_write_mod_reg(prcm_context.usbhost_cm_autoidle,
+                                       OMAP3430ES2_USBHOST_MOD, CM_AUTOIDLE);
+       cm_write_mod_reg(prcm_context.sgx_cm_sleepdep, OMAP3430ES2_SGX_MOD,
+                                       OMAP3430_CM_SLEEPDEP);
+       cm_write_mod_reg(prcm_context.dss_cm_sleepdep, OMAP3430_DSS_MOD,
+                                       OMAP3430_CM_SLEEPDEP);
+       cm_write_mod_reg(prcm_context.cam_cm_sleepdep, OMAP3430_CAM_MOD,
+                                       OMAP3430_CM_SLEEPDEP);
+       cm_write_mod_reg(prcm_context.per_cm_sleepdep, OMAP3430_PER_MOD,
+                                       OMAP3430_CM_SLEEPDEP);
+       cm_write_mod_reg(prcm_context.usbhost_cm_sleepdep,
+                               OMAP3430ES2_USBHOST_MOD, OMAP3430_CM_SLEEPDEP);
+       cm_write_mod_reg(prcm_context.cm_clkout_ctrl, OMAP3430_CCR_MOD,
+                                       OMAP3_CM_CLKOUT_CTRL_OFFSET);
+       prm_write_mod_reg(prcm_context.prm_clkout_ctrl, OMAP3430_CCR_MOD,
+                                       OMAP3_PRM_CLKOUT_CTRL_OFFSET);
+       prm_write_mod_reg(prcm_context.sgx_pm_wkdep, OMAP3430ES2_SGX_MOD,
+                                       PM_WKDEP);
+       prm_write_mod_reg(prcm_context.dss_pm_wkdep, OMAP3430_DSS_MOD,
+                                       PM_WKDEP);
+       prm_write_mod_reg(prcm_context.cam_pm_wkdep, OMAP3430_CAM_MOD,
+                                       PM_WKDEP);
+       prm_write_mod_reg(prcm_context.per_pm_wkdep, OMAP3430_PER_MOD,
+                                       PM_WKDEP);
+       prm_write_mod_reg(prcm_context.neon_pm_wkdep, OMAP3430_NEON_MOD,
+                                       PM_WKDEP);
+       prm_write_mod_reg(prcm_context.usbhost_pm_wkdep,
+                                       OMAP3430ES2_USBHOST_MOD, PM_WKDEP);
+       prm_write_mod_reg(prcm_context.core_pm_mpugrpsel1, CORE_MOD,
+                                       OMAP3430_PM_MPUGRPSEL1);
+       prm_write_mod_reg(prcm_context.iva2_pm_ivagrpsel1, OMAP3430_IVA2_MOD,
+                                       OMAP3430_PM_IVAGRPSEL1);
+       prm_write_mod_reg(prcm_context.core_pm_mpugrpsel3, CORE_MOD,
+                                       OMAP3430ES2_PM_MPUGRPSEL3);
+       prm_write_mod_reg(prcm_context.core_pm_ivagrpsel3, CORE_MOD,
+                                       OMAP3430ES2_PM_IVAGRPSEL3);
+       prm_write_mod_reg(prcm_context.wkup_pm_mpugrpsel, WKUP_MOD,
+                                       OMAP3430_PM_MPUGRPSEL);
+       prm_write_mod_reg(prcm_context.wkup_pm_ivagrpsel, WKUP_MOD,
+                                       OMAP3430_PM_IVAGRPSEL);
+       prm_write_mod_reg(prcm_context.per_pm_mpugrpsel, OMAP3430_PER_MOD,
+                                       OMAP3430_PM_MPUGRPSEL);
+       prm_write_mod_reg(prcm_context.per_pm_ivagrpsel, OMAP3430_PER_MOD,
+                                        OMAP3430_PM_IVAGRPSEL);
+       prm_write_mod_reg(prcm_context.wkup_pm_wken, WKUP_MOD, PM_WKEN);
+       return;
+}
+#endif
index 9fd03a2..8f21bae 100644 (file)
 /* PM_PREPWSTST_GFX specific bits */
 
 /* PM_WKEN_WKUP specific bits */
+#define OMAP3430_EN_IO_CHAIN                           (1 << 16)
 #define OMAP3430_EN_IO                                 (1 << 8)
 #define OMAP3430_EN_GPIO1                              (1 << 3)
 
 /* PM_IVA2GRPSEL_WKUP specific bits */
 
 /* PM_WKST_WKUP specific bits */
+#define OMAP3430_ST_IO_CHAIN                           (1 << 16)
 #define OMAP3430_ST_IO                                 (1 << 8)
 
 /* PRM_CLKSEL */
index 03c467c..a117f85 100644 (file)
 #include "prcm-common.h"
 
 #define OMAP2420_PRM_REGADDR(module, reg)                              \
-                       OMAP2_IO_ADDRESS(OMAP2420_PRM_BASE + (module) + (reg))
+               OMAP2_L4_IO_ADDRESS(OMAP2420_PRM_BASE + (module) + (reg))
 #define OMAP2430_PRM_REGADDR(module, reg)                              \
-                       OMAP2_IO_ADDRESS(OMAP2430_PRM_BASE + (module) + (reg))
+               OMAP2_L4_IO_ADDRESS(OMAP2430_PRM_BASE + (module) + (reg))
 #define OMAP34XX_PRM_REGADDR(module, reg)                              \
-                       OMAP2_IO_ADDRESS(OMAP3430_PRM_BASE + (module) + (reg))
+               OMAP2_L4_IO_ADDRESS(OMAP3430_PRM_BASE + (module) + (reg))
 
 /*
  * Architecture-specific global PRM registers
diff --git a/arch/arm/mach-omap2/sdram-hynix-h8mbx00u0mer-0em.h b/arch/arm/mach-omap2/sdram-hynix-h8mbx00u0mer-0em.h
new file mode 100644 (file)
index 0000000..8bfaf34
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * SDRC register values for the Hynix H8MBX00U0MER-0EM
+ *
+ * Copyright (C) 2009 Texas Instruments, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __ARCH_ARM_MACH_OMAP2_SDRAM_HYNIX_H8MBX00U0MER0EM
+#define __ARCH_ARM_MACH_OMAP2_SDRAM_HYNIX_H8MBX00U0MER0EM
+
+#include <plat/sdrc.h>
+
+/* Hynix H8MBX00U0MER-0EM */
+static struct omap_sdrc_params h8mbx00u0mer0em_sdrc_params[] = {
+       [0] = {
+               .rate        = 200000000,
+               .actim_ctrla = 0xa2e1b4c6,
+               .actim_ctrlb = 0x0002131c,
+               .rfr_ctrl    = 0x0005e601,
+               .mr          = 0x00000032,
+       },
+       [1] = {
+               .rate        = 166000000,
+               .actim_ctrla = 0x629db4c6,
+               .actim_ctrlb = 0x00012214,
+               .rfr_ctrl    = 0x0004dc01,
+               .mr          = 0x00000032,
+       },
+       [2] = {
+               .rate        = 100000000,
+               .actim_ctrla = 0x51912284,
+               .actim_ctrlb = 0x0002120e,
+               .rfr_ctrl    = 0x0002d101,
+               .mr          = 0x00000022,
+       },
+       [3] = {
+               .rate        = 83000000,
+               .actim_ctrla = 0x31512283,
+               .actim_ctrlb = 0x0001220a,
+               .rfr_ctrl    = 0x00025501,
+               .mr          = 0x00000022,
+       },
+       [4] = {
+               .rate        = 0
+       },
+};
+
+#endif
index 02e1c2d..a391b49 100644 (file)
@@ -14,7 +14,7 @@
 #ifndef ARCH_ARM_MACH_OMAP2_SDRAM_MICRON_MT46H32M32LF
 #define ARCH_ARM_MACH_OMAP2_SDRAM_MICRON_MT46H32M32LF
 
-#include <mach/sdrc.h>
+#include <plat/sdrc.h>
 
 /* Micron MT46H32M32LF-6 */
 /* XXX Using ARE = 0x1 (no autorefresh burst) -- can this be changed? */
index 3751d29..0e518a7 100644 (file)
@@ -14,7 +14,7 @@
 #ifndef ARCH_ARM_MACH_OMAP2_SDRAM_QIMONDA_HYB18M512160AF6
 #define ARCH_ARM_MACH_OMAP2_SDRAM_QIMONDA_HYB18M512160AF6
 
-#include <mach/sdrc.h>
+#include <plat/sdrc.h>
 
 /* Qimonda HYB18M512160AF-6 */
 static struct omap_sdrc_params hyb18m512160af6_sdrc_params[] = {
index 9e3bd4f..9a59219 100644 (file)
 #include <linux/clk.h>
 #include <linux/io.h>
 
-#include <mach/common.h>
-#include <mach/clock.h>
-#include <mach/sram.h>
+#include <plat/common.h>
+#include <plat/clock.h>
+#include <plat/sram.h>
 
 #include "prm.h"
 
-#include <mach/sdrc.h>
+#include <plat/sdrc.h>
 #include "sdrc.h"
 
 static struct omap_sdrc_params *sdrc_init_params_cs0, *sdrc_init_params_cs1;
@@ -37,12 +37,38 @@ static struct omap_sdrc_params *sdrc_init_params_cs0, *sdrc_init_params_cs1;
 void __iomem *omap2_sdrc_base;
 void __iomem *omap2_sms_base;
 
+struct omap2_sms_regs {
+       u32     sms_sysconfig;
+};
+
+static struct omap2_sms_regs sms_context;
+
 /* SDRC_POWER register bits */
 #define SDRC_POWER_EXTCLKDIS_SHIFT             3
 #define SDRC_POWER_PWDENA_SHIFT                        2
 #define SDRC_POWER_PAGEPOLICY_SHIFT            0
 
 /**
+ * omap2_sms_save_context - Save SMS registers
+ *
+ * Save SMS registers that need to be restored after off mode.
+ */
+void omap2_sms_save_context(void)
+{
+       sms_context.sms_sysconfig = sms_read_reg(SMS_SYSCONFIG);
+}
+
+/**
+ * omap2_sms_restore_context - Restore SMS registers
+ *
+ * Restore SMS registers that need to be Restored after off mode.
+ */
+void omap2_sms_restore_context(void)
+{
+       sms_write_reg(sms_context.sms_sysconfig, SMS_SYSCONFIG);
+}
+
+/**
  * omap2_sdrc_get_params - return SDRC register values for a given clock rate
  * @r: SDRC clock rate (in Hz)
  * @sdrc_cs0: chip select 0 ram timings **
@@ -132,4 +158,5 @@ void __init omap2_sdrc_init(struct omap_sdrc_params *sdrc_cs0,
        l = (1 << SDRC_POWER_EXTCLKDIS_SHIFT) |
                (1 << SDRC_POWER_PAGEPOLICY_SHIFT);
        sdrc_write_reg(l, SDRC_POWER);
+       omap2_sms_save_context();
 }
index 0837eda..48207b0 100644 (file)
@@ -15,7 +15,7 @@
  */
 #undef DEBUG
 
-#include <mach/sdrc.h>
+#include <plat/sdrc.h>
 
 #ifndef __ASSEMBLER__
 extern void __iomem *omap2_sdrc_base;
@@ -48,9 +48,12 @@ static inline u32 sms_read_reg(u16 reg)
        return __raw_readl(OMAP_SMS_REGADDR(reg));
 }
 #else
-#define OMAP242X_SDRC_REGADDR(reg)     OMAP2_IO_ADDRESS(OMAP2420_SDRC_BASE + (reg))
-#define OMAP243X_SDRC_REGADDR(reg)     OMAP2_IO_ADDRESS(OMAP243X_SDRC_BASE + (reg))
-#define OMAP34XX_SDRC_REGADDR(reg)     OMAP2_IO_ADDRESS(OMAP343X_SDRC_BASE + (reg))
+#define OMAP242X_SDRC_REGADDR(reg)                                     \
+                       OMAP2_L3_IO_ADDRESS(OMAP2420_SDRC_BASE + (reg))
+#define OMAP243X_SDRC_REGADDR(reg)                                     \
+                       OMAP2_L3_IO_ADDRESS(OMAP243X_SDRC_BASE + (reg))
+#define OMAP34XX_SDRC_REGADDR(reg)                                     \
+                       OMAP2_L3_IO_ADDRESS(OMAP343X_SDRC_BASE + (reg))
 #endif /* __ASSEMBLER__ */
 
 #endif
index feaec7e..0f4d27a 100644 (file)
 #include <linux/clk.h>
 #include <linux/io.h>
 
-#include <mach/common.h>
-#include <mach/clock.h>
-#include <mach/sram.h>
+#include <plat/common.h>
+#include <plat/clock.h>
+#include <plat/sram.h>
 
 #include "prm.h"
 #include "clock.h"
-#include <mach/sdrc.h>
+#include <plat/sdrc.h>
 #include "sdrc.h"
 
 /* Memory timing, DLL mode flags */
index 54dfeb5..2e17b57 100644 (file)
 #include <linux/clk.h>
 #include <linux/io.h>
 
-#include <mach/common.h>
-#include <mach/board.h>
-#include <mach/clock.h>
-#include <mach/control.h>
+#include <plat/common.h>
+#include <plat/board.h>
+#include <plat/clock.h>
+#include <plat/control.h>
 
 #include "prm.h"
 #include "pm.h"
@@ -73,7 +73,6 @@ static LIST_HEAD(uart_list);
 
 static struct plat_serial8250_port serial_platform_data0[] = {
        {
-               .membase        = OMAP2_IO_ADDRESS(OMAP_UART1_BASE),
                .mapbase        = OMAP_UART1_BASE,
                .irq            = 72,
                .flags          = UPF_BOOT_AUTOCONF,
@@ -87,7 +86,6 @@ static struct plat_serial8250_port serial_platform_data0[] = {
 
 static struct plat_serial8250_port serial_platform_data1[] = {
        {
-               .membase        = OMAP2_IO_ADDRESS(OMAP_UART2_BASE),
                .mapbase        = OMAP_UART2_BASE,
                .irq            = 73,
                .flags          = UPF_BOOT_AUTOCONF,
@@ -101,7 +99,6 @@ static struct plat_serial8250_port serial_platform_data1[] = {
 
 static struct plat_serial8250_port serial_platform_data2[] = {
        {
-               .membase        = OMAP2_IO_ADDRESS(OMAP_UART3_BASE),
                .mapbase        = OMAP_UART3_BASE,
                .irq            = 74,
                .flags          = UPF_BOOT_AUTOCONF,
@@ -116,7 +113,6 @@ static struct plat_serial8250_port serial_platform_data2[] = {
 #ifdef CONFIG_ARCH_OMAP4
 static struct plat_serial8250_port serial_platform_data3[] = {
        {
-               .membase        = OMAP2_IO_ADDRESS(OMAP_UART4_BASE),
                .mapbase        = OMAP_UART4_BASE,
                .irq            = 70,
                .flags          = UPF_BOOT_AUTOCONF,
@@ -159,8 +155,6 @@ static inline void __init omap_uart_reset(struct omap_uart_state *uart)
 
 #if defined(CONFIG_PM) && defined(CONFIG_ARCH_OMAP3)
 
-static int enable_off_mode; /* to be removed by full off-mode patches */
-
 static void omap_uart_save_context(struct omap_uart_state *uart)
 {
        u16 lcr = 0;
@@ -539,7 +533,7 @@ static inline void omap_uart_idle_init(struct omap_uart_state *uart) {}
 #define DEV_CREATE_FILE(dev, attr)
 #endif /* CONFIG_PM */
 
-static struct omap_uart_state omap_uart[OMAP_MAX_NR_PORTS] = {
+static struct omap_uart_state omap_uart[] = {
        {
                .pdev = {
                        .name                   = "serial8250",
@@ -589,12 +583,22 @@ void __init omap_serial_early_init(void)
         * if not needed.
         */
 
-       for (i = 0; i < OMAP_MAX_NR_PORTS; i++) {
+       for (i = 0; i < ARRAY_SIZE(omap_uart); i++) {
                struct omap_uart_state *uart = &omap_uart[i];
                struct platform_device *pdev = &uart->pdev;
                struct device *dev = &pdev->dev;
                struct plat_serial8250_port *p = dev->platform_data;
 
+               /*
+                * Module 4KB + L4 interconnect 4KB
+                * Static mapping, never released
+                */
+               p->membase = ioremap(p->mapbase, SZ_8K);
+               if (!p->membase) {
+                       printk(KERN_ERR "ioremap failed for uart%i\n", i + 1);
+                       continue;
+               }
+
                sprintf(name, "uart%d_ick", i+1);
                uart->ick = clk_get(NULL, name);
                if (IS_ERR(uart->ick)) {
@@ -631,7 +635,7 @@ void __init omap_serial_init(void)
 {
        int i;
 
-       for (i = 0; i < OMAP_MAX_NR_PORTS; i++) {
+       for (i = 0; i < ARRAY_SIZE(omap_uart); i++) {
                struct omap_uart_state *uart = &omap_uart[i];
                struct platform_device *pdev = &uart->pdev;
                struct device *dev = &pdev->dev;
index 130aadb..c7780cc 100644 (file)
@@ -29,7 +29,7 @@
 #include <asm/assembler.h>
 #include <mach/io.h>
 
-#include <mach/omap24xx.h>
+#include <plat/omap24xx.h>
 
 #include "sdrc.h"
 
index e5e2553..15268f8 100644 (file)
 #include <linux/linkage.h>
 #include <asm/assembler.h>
 #include <mach/io.h>
-#include <mach/control.h>
+#include <plat/control.h>
 
+#include "cm.h"
 #include "prm.h"
 #include "sdrc.h"
 
 #define PM_PREPWSTST_CORE_V    OMAP34XX_PRM_REGADDR(CORE_MOD, \
                                OMAP3430_PM_PREPWSTST)
+#define PM_PREPWSTST_CORE_P    0x48306AE8
 #define PM_PREPWSTST_MPU_V     OMAP34XX_PRM_REGADDR(MPU_MOD, \
                                OMAP3430_PM_PREPWSTST)
-#define PM_PWSTCTRL_MPU_P      OMAP34XX_PRM_REGADDR(MPU_MOD, PM_PWSTCTRL)
+#define PM_PWSTCTRL_MPU_P      OMAP3430_PRM_BASE + MPU_MOD + PM_PWSTCTRL
+#define CM_IDLEST1_CORE_V      OMAP34XX_CM_REGADDR(CORE_MOD, CM_IDLEST1)
+#define SRAM_BASE_P            0x40200000
+#define CONTROL_STAT           0x480022F0
 #define SCRATCHPAD_MEM_OFFS    0x310 /* Move this as correct place is
                                       * available */
-#define SCRATCHPAD_BASE_P      OMAP343X_CTRL_REGADDR(\
-                               OMAP343X_CONTROL_MEM_WKUP +\
-                               SCRATCHPAD_MEM_OFFS)
+#define SCRATCHPAD_BASE_P      (OMAP343X_CTRL_BASE + OMAP343X_CONTROL_MEM_WKUP\
+                                               + SCRATCHPAD_MEM_OFFS)
 #define SDRC_POWER_V           OMAP34XX_SDRC_REGADDR(SDRC_POWER)
+#define SDRC_SYSCONFIG_P       (OMAP343X_SDRC_BASE + SDRC_SYSCONFIG)
+#define SDRC_MR_0_P            (OMAP343X_SDRC_BASE + SDRC_MR_0)
+#define SDRC_EMR2_0_P          (OMAP343X_SDRC_BASE + SDRC_EMR2_0)
+#define SDRC_MANUAL_0_P                (OMAP343X_SDRC_BASE + SDRC_MANUAL_0)
+#define SDRC_MR_1_P            (OMAP343X_SDRC_BASE + SDRC_MR_1)
+#define SDRC_EMR2_1_P          (OMAP343X_SDRC_BASE + SDRC_EMR2_1)
+#define SDRC_MANUAL_1_P                (OMAP343X_SDRC_BASE + SDRC_MANUAL_1)
+#define SDRC_DLLA_STATUS_V     OMAP34XX_SDRC_REGADDR(SDRC_DLLA_STATUS)
+#define SDRC_DLLA_CTRL_V       OMAP34XX_SDRC_REGADDR(SDRC_DLLA_CTRL)
 
        .text
 /* Function call to get the restore pointer for resume from OFF */
@@ -51,7 +64,93 @@ ENTRY(get_restore_pointer)
        adr     r0, restore
         ldmfd   sp!, {pc}     @ restore regs and return
 ENTRY(get_restore_pointer_sz)
-        .word   . - get_restore_pointer_sz
+        .word   . - get_restore_pointer
+
+       .text
+/* Function call to get the restore pointer for for ES3 to resume from OFF */
+ENTRY(get_es3_restore_pointer)
+       stmfd   sp!, {lr}       @ save registers on stack
+       adr     r0, restore_es3
+       ldmfd   sp!, {pc}       @ restore regs and return
+ENTRY(get_es3_restore_pointer_sz)
+       .word   . - get_es3_restore_pointer
+
+ENTRY(es3_sdrc_fix)
+       ldr     r4, sdrc_syscfg         @ get config addr
+       ldr     r5, [r4]                @ get value
+       tst     r5, #0x100              @ is part access blocked
+       it      eq
+       biceq   r5, r5, #0x100          @ clear bit if set
+       str     r5, [r4]                @ write back change
+       ldr     r4, sdrc_mr_0           @ get config addr
+       ldr     r5, [r4]                @ get value
+       str     r5, [r4]                @ write back change
+       ldr     r4, sdrc_emr2_0         @ get config addr
+       ldr     r5, [r4]                @ get value
+       str     r5, [r4]                @ write back change
+       ldr     r4, sdrc_manual_0       @ get config addr
+       mov     r5, #0x2                @ autorefresh command
+       str     r5, [r4]                @ kick off refreshes
+       ldr     r4, sdrc_mr_1           @ get config addr
+       ldr     r5, [r4]                @ get value
+       str     r5, [r4]                @ write back change
+       ldr     r4, sdrc_emr2_1         @ get config addr
+       ldr     r5, [r4]                @ get value
+       str     r5, [r4]                @ write back change
+       ldr     r4, sdrc_manual_1       @ get config addr
+       mov     r5, #0x2                @ autorefresh command
+       str     r5, [r4]                @ kick off refreshes
+       bx      lr
+sdrc_syscfg:
+       .word   SDRC_SYSCONFIG_P
+sdrc_mr_0:
+       .word   SDRC_MR_0_P
+sdrc_emr2_0:
+       .word   SDRC_EMR2_0_P
+sdrc_manual_0:
+       .word   SDRC_MANUAL_0_P
+sdrc_mr_1:
+       .word   SDRC_MR_1_P
+sdrc_emr2_1:
+       .word   SDRC_EMR2_1_P
+sdrc_manual_1:
+       .word   SDRC_MANUAL_1_P
+ENTRY(es3_sdrc_fix_sz)
+       .word   . - es3_sdrc_fix
+
+/* Function to call rom code to save secure ram context */
+ENTRY(save_secure_ram_context)
+       stmfd   sp!, {r1-r12, lr}       @ save registers on stack
+save_secure_ram_debug:
+       /* b save_secure_ram_debug */   @ enable to debug save code
+       adr     r3, api_params          @ r3 points to parameters
+       str     r0, [r3,#0x4]           @ r0 has sdram address
+       ldr     r12, high_mask
+       and     r3, r3, r12
+       ldr     r12, sram_phy_addr_mask
+       orr     r3, r3, r12
+       mov     r0, #25                 @ set service ID for PPA
+       mov     r12, r0                 @ copy secure service ID in r12
+       mov     r1, #0                  @ set task id for ROM code in r1
+       mov     r2, #4                  @ set some flags in r2, r6
+       mov     r6, #0xff
+       mcr     p15, 0, r0, c7, c10, 4  @ data write barrier
+       mcr     p15, 0, r0, c7, c10, 5  @ data memory barrier
+       .word   0xE1600071              @ call SMI monitor (smi #1)
+       nop
+       nop
+       nop
+       nop
+       ldmfd   sp!, {r1-r12, pc}
+sram_phy_addr_mask:
+       .word   SRAM_BASE_P
+high_mask:
+       .word   0xffff
+api_params:
+       .word   0x4, 0x0, 0x0, 0x1, 0x1
+ENTRY(save_secure_ram_context_sz)
+       .word   . - save_secure_ram_context
+
 /*
  * Forces OMAP into idle state
  *
@@ -92,11 +191,29 @@ loop:
        nop
        nop
        nop
-       bl i_dll_wait
+       bl wait_sdrc_ok
 
        ldmfd   sp!, {r0-r12, pc}               @ restore regs and return
+restore_es3:
+       /*b restore_es3*/               @ Enable to debug restore code
+       ldr     r5, pm_prepwstst_core_p
+       ldr     r4, [r5]
+       and     r4, r4, #0x3
+       cmp     r4, #0x0        @ Check if previous power state of CORE is OFF
+       bne     restore
+       adr     r0, es3_sdrc_fix
+       ldr     r1, sram_base
+       ldr     r2, es3_sdrc_fix_sz
+       mov     r2, r2, ror #2
+copy_to_sram:
+       ldmia   r0!, {r3}       @ val = *src
+       stmia   r1!, {r3}       @ *dst = val
+       subs    r2, r2, #0x1    @ num_words--
+       bne     copy_to_sram
+       ldr     r1, sram_base
+       blx     r1
 restore:
-       /* b restore*/  @ Enable to debug restore code
+       /* b restore*/  @ Enable to debug restore code
         /* Check what was the reason for mpu reset and store the reason in r9*/
         /* 1 - Only L1 and logic lost */
         /* 2 - Only L2 lost - In this case, we wont be here */
@@ -108,9 +225,44 @@ restore:
         moveq   r9, #0x3        @ MPU OFF => L1 and L2 lost
        movne   r9, #0x1        @ Only L1 and L2 lost => avoid L2 invalidation
        bne     logic_l1_restore
+       ldr     r0, control_stat
+       ldr     r1, [r0]
+       and     r1, #0x700
+       cmp     r1, #0x300
+       beq     l2_inv_gp
+       mov     r0, #40         @ set service ID for PPA
+       mov     r12, r0         @ copy secure Service ID in r12
+       mov     r1, #0          @ set task id for ROM code in r1
+       mov     r2, #4          @ set some flags in r2, r6
+       mov     r6, #0xff
+       adr     r3, l2_inv_api_params   @ r3 points to dummy parameters
+       mcr     p15, 0, r0, c7, c10, 4  @ data write barrier
+       mcr     p15, 0, r0, c7, c10, 5  @ data memory barrier
+       .word   0xE1600071              @ call SMI monitor (smi #1)
+       /* Write to Aux control register to set some bits */
+       mov     r0, #42         @ set service ID for PPA
+       mov     r12, r0         @ copy secure Service ID in r12
+       mov     r1, #0          @ set task id for ROM code in r1
+       mov     r2, #4          @ set some flags in r2, r6
+       mov     r6, #0xff
+       adr     r3, write_aux_control_params    @ r3 points to parameters
+       mcr     p15, 0, r0, c7, c10, 4  @ data write barrier
+       mcr     p15, 0, r0, c7, c10, 5  @ data memory barrier
+       .word   0xE1600071              @ call SMI monitor (smi #1)
+
+       b       logic_l1_restore
+l2_inv_api_params:
+       .word   0x1, 0x00
+write_aux_control_params:
+       .word   0x1, 0x72
+l2_inv_gp:
        /* Execute smi to invalidate L2 cache */
        mov r12, #0x1                         @ set up to invalide L2
-smi:    .word 0xE1600070                @ Call SMI monitor (smieq)
+smi:    .word 0xE1600070               @ Call SMI monitor (smieq)
+       /* Write to Aux control register to set some bits */
+       mov     r0, #0x72
+       mov     r12, #0x3
+       .word 0xE1600070        @ Call SMI monitor (smieq)
 logic_l1_restore:
        mov     r1, #0
        /* Invalidate all instruction caches to PoU
@@ -391,33 +543,55 @@ skip_l2_inval:
        nop
        nop
        nop
-       bl i_dll_wait
+       bl wait_sdrc_ok
        /* restore regs and return */
        ldmfd   sp!, {r0-r12, pc}
 
-i_dll_wait:
-       ldr     r4, clk_stabilize_delay
+/* Make sure SDRC accesses are ok */
+wait_sdrc_ok:
+        ldr     r4, cm_idlest1_core
+        ldr     r5, [r4]
+        and     r5, r5, #0x2
+        cmp     r5, #0
+        bne     wait_sdrc_ok
+        ldr     r4, sdrc_power
+        ldr     r5, [r4]
+        bic     r5, r5, #0x40
+        str     r5, [r4]
+wait_dll_lock:
+        /* Is dll in lock mode? */
+        ldr     r4, sdrc_dlla_ctrl
+        ldr     r5, [r4]
+        tst     r5, #0x4
+        bxne    lr
+        /* wait till dll locks */
+        ldr     r4, sdrc_dlla_status
+        ldr     r5, [r4]
+        and     r5, r5, #0x4
+        cmp     r5, #0x4
+        bne     wait_dll_lock
+        bx      lr
 
-i_dll_delay:
-       subs    r4, r4, #0x1
-       bne     i_dll_delay
-       ldr     r4, sdrc_power
-       ldr     r5, [r4]
-       bic     r5, r5, #0x40
-       str     r5, [r4]
-       bx      lr
+cm_idlest1_core:
+       .word   CM_IDLEST1_CORE_V
+sdrc_dlla_status:
+       .word   SDRC_DLLA_STATUS_V
+sdrc_dlla_ctrl:
+       .word   SDRC_DLLA_CTRL_V
 pm_prepwstst_core:
        .word   PM_PREPWSTST_CORE_V
+pm_prepwstst_core_p:
+       .word   PM_PREPWSTST_CORE_P
 pm_prepwstst_mpu:
        .word   PM_PREPWSTST_MPU_V
 pm_pwstctrl_mpu:
        .word   PM_PWSTCTRL_MPU_P
 scratchpad_base:
        .word   SCRATCHPAD_BASE_P
+sram_base:
+       .word   SRAM_BASE_P + 0x8000
 sdrc_power:
        .word SDRC_POWER_V
-context_mem:
-       .word   0x803E3E14
 clk_stabilize_delay:
        .word 0x000001FF
 assoc_mask:
@@ -432,5 +606,7 @@ table_entry:
        .word   0x00000C02
 cache_pred_disable_mask:
        .word   0xFFFFE7FB
+control_stat:
+       .word   CONTROL_STAT
 ENTRY(omap34xx_cpu_suspend_sz)
        .word   . - omap34xx_cpu_suspend
index 9b62208..92e6e1a 100644 (file)
@@ -128,7 +128,7 @@ omap242x_sdi_prcm_voltctrl:
 prcm_mask_val:
        .word 0xFFFF3FFC
 omap242x_sdi_timer_32ksynct_cr:
-       .word OMAP2_IO_ADDRESS(OMAP2420_32KSYNCT_BASE + 0x010)
+       .word OMAP2_L4_IO_ADDRESS(OMAP2420_32KSYNCT_BASE + 0x010)
 ENTRY(omap242x_sram_ddr_init_sz)
        .word   . - omap242x_sram_ddr_init
 
@@ -224,7 +224,7 @@ omap242x_srs_prcm_voltctrl:
 ddr_prcm_mask_val:
        .word 0xFFFF3FFC
 omap242x_srs_timer_32ksynct:
-       .word OMAP2_IO_ADDRESS(OMAP2420_32KSYNCT_BASE + 0x010)
+       .word OMAP2_L4_IO_ADDRESS(OMAP2420_32KSYNCT_BASE + 0x010)
 
 ENTRY(omap242x_sram_reprogram_sdrc_sz)
        .word   . - omap242x_sram_reprogram_sdrc
index df2cd92..ab49736 100644 (file)
@@ -128,7 +128,7 @@ omap243x_sdi_prcm_voltctrl:
 prcm_mask_val:
        .word 0xFFFF3FFC
 omap243x_sdi_timer_32ksynct_cr:
-       .word OMAP2_IO_ADDRESS(OMAP2430_32KSYNCT_BASE + 0x010)
+       .word OMAP2_L4_IO_ADDRESS(OMAP2430_32KSYNCT_BASE + 0x010)
 ENTRY(omap243x_sram_ddr_init_sz)
        .word   . - omap243x_sram_ddr_init
 
@@ -224,7 +224,7 @@ omap243x_srs_prcm_voltctrl:
 ddr_prcm_mask_val:
        .word 0xFFFF3FFC
 omap243x_srs_timer_32ksynct:
-       .word OMAP2_IO_ADDRESS(OMAP2430_32KSYNCT_BASE + 0x010)
+       .word OMAP2_L4_IO_ADDRESS(OMAP2430_32KSYNCT_BASE + 0x010)
 
 ENTRY(omap243x_sram_reprogram_sdrc_sz)
        .word   . - omap243x_sram_reprogram_sdrc
index e2338c0..cd04dea 100644 (file)
@@ -37,7 +37,7 @@
 #include <linux/clockchips.h>
 
 #include <asm/mach/time.h>
-#include <mach/dmtimer.h>
+#include <plat/dmtimer.h>
 #include <asm/localtimer.h>
 
 /* MAX_GPTIMER_ID: number of GPTIMERs on the chip */
@@ -47,6 +47,7 @@ static struct omap_dm_timer *gptimer;
 static struct clock_event_device clockevent_gpt;
 static u8 __initdata gptimer_id = 1;
 static u8 __initdata inited;
+struct omap_dm_timer *gptimer_wakeup;
 
 static irqreturn_t omap2_gp_timer_interrupt(int irq, void *dev_id)
 {
@@ -134,6 +135,7 @@ static void __init omap2_gp_clockevent_init(void)
 
        gptimer = omap_dm_timer_request_specific(gptimer_id);
        BUG_ON(gptimer == NULL);
+       gptimer_wakeup = gptimer;
 
 #if defined(CONFIG_OMAP_32K_TIMER)
        src = OMAP_TIMER_SRC_32_KHZ;
@@ -231,7 +233,8 @@ static void __init omap2_gp_clocksource_init(void)
 static void __init omap2_gp_timer_init(void)
 {
 #ifdef CONFIG_LOCAL_TIMERS
-       twd_base = OMAP2_IO_ADDRESS(OMAP44XX_LOCAL_TWD_BASE);
+       twd_base = ioremap(OMAP44XX_LOCAL_TWD_BASE, SZ_256);
+       BUG_ON(!twd_base);
 #endif
        omap_dm_timer_init();
 
diff --git a/arch/arm/mach-omap2/usb-ehci.c b/arch/arm/mach-omap2/usb-ehci.c
new file mode 100644 (file)
index 0000000..e448abd
--- /dev/null
@@ -0,0 +1,192 @@
+/*
+ * linux/arch/arm/mach-omap2/usb-ehci.c
+ *
+ * This file will contain the board specific details for the
+ * Synopsys EHCI host controller on OMAP3430
+ *
+ * Copyright (C) 2007 Texas Instruments
+ * Author: Vikram Pandita <vikram.pandita@ti.com>
+ *
+ * Generalization by:
+ * Felipe Balbi <felipe.balbi@nokia.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/types.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <asm/io.h>
+#include <plat/mux.h>
+
+#include <mach/hardware.h>
+#include <mach/irqs.h>
+#include <plat/usb.h>
+
+#if defined(CONFIG_USB_EHCI_HCD) || defined(CONFIG_USB_EHCI_HCD_MODULE)
+
+static struct resource ehci_resources[] = {
+       {
+               .start  = OMAP34XX_EHCI_BASE,
+               .end    = OMAP34XX_EHCI_BASE + SZ_1K - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       {
+               .start  = OMAP34XX_UHH_CONFIG_BASE,
+               .end    = OMAP34XX_UHH_CONFIG_BASE + SZ_1K - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       {
+               .start  = OMAP34XX_USBTLL_BASE,
+               .end    = OMAP34XX_USBTLL_BASE + SZ_4K - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       {         /* general IRQ */
+               .start   = INT_34XX_EHCI_IRQ,
+               .flags   = IORESOURCE_IRQ,
+       }
+};
+
+static u64 ehci_dmamask = ~(u32)0;
+static struct platform_device ehci_device = {
+       .name           = "ehci-omap",
+       .id             = 0,
+       .dev = {
+               .dma_mask               = &ehci_dmamask,
+               .coherent_dma_mask      = 0xffffffff,
+               .platform_data          = NULL,
+       },
+       .num_resources  = ARRAY_SIZE(ehci_resources),
+       .resource       = ehci_resources,
+};
+
+/* MUX settings for EHCI pins */
+/*
+ * setup_ehci_io_mux - initialize IO pad mux for USBHOST
+ */
+static void setup_ehci_io_mux(enum ehci_hcd_omap_mode *port_mode)
+{
+       switch (port_mode[0]) {
+       case EHCI_HCD_OMAP_MODE_PHY:
+               omap_cfg_reg(Y9_3430_USB1HS_PHY_STP);
+               omap_cfg_reg(Y8_3430_USB1HS_PHY_CLK);
+               omap_cfg_reg(AA14_3430_USB1HS_PHY_DIR);
+               omap_cfg_reg(AA11_3430_USB1HS_PHY_NXT);
+               omap_cfg_reg(W13_3430_USB1HS_PHY_DATA0);
+               omap_cfg_reg(W12_3430_USB1HS_PHY_DATA1);
+               omap_cfg_reg(W11_3430_USB1HS_PHY_DATA2);
+               omap_cfg_reg(Y11_3430_USB1HS_PHY_DATA3);
+               omap_cfg_reg(W9_3430_USB1HS_PHY_DATA4);
+               omap_cfg_reg(Y12_3430_USB1HS_PHY_DATA5);
+               omap_cfg_reg(W8_3430_USB1HS_PHY_DATA6);
+               omap_cfg_reg(Y13_3430_USB1HS_PHY_DATA7);
+               break;
+       case EHCI_HCD_OMAP_MODE_TLL:
+               omap_cfg_reg(Y9_3430_USB1HS_TLL_STP);
+               omap_cfg_reg(Y8_3430_USB1HS_TLL_CLK);
+               omap_cfg_reg(AA14_3430_USB1HS_TLL_DIR);
+               omap_cfg_reg(AA11_3430_USB1HS_TLL_NXT);
+               omap_cfg_reg(W13_3430_USB1HS_TLL_DATA0);
+               omap_cfg_reg(W12_3430_USB1HS_TLL_DATA1);
+               omap_cfg_reg(W11_3430_USB1HS_TLL_DATA2);
+               omap_cfg_reg(Y11_3430_USB1HS_TLL_DATA3);
+               omap_cfg_reg(W9_3430_USB1HS_TLL_DATA4);
+               omap_cfg_reg(Y12_3430_USB1HS_TLL_DATA5);
+               omap_cfg_reg(W8_3430_USB1HS_TLL_DATA6);
+               omap_cfg_reg(Y13_3430_USB1HS_TLL_DATA7);
+               break;
+       case EHCI_HCD_OMAP_MODE_UNKNOWN:
+               /* FALLTHROUGH */
+       default:
+               break;
+       }
+
+       switch (port_mode[1]) {
+       case EHCI_HCD_OMAP_MODE_PHY:
+               omap_cfg_reg(AA10_3430_USB2HS_PHY_STP);
+               omap_cfg_reg(AA8_3430_USB2HS_PHY_CLK);
+               omap_cfg_reg(AA9_3430_USB2HS_PHY_DIR);
+               omap_cfg_reg(AB11_3430_USB2HS_PHY_NXT);
+               omap_cfg_reg(AB10_3430_USB2HS_PHY_DATA0);
+               omap_cfg_reg(AB9_3430_USB2HS_PHY_DATA1);
+               omap_cfg_reg(W3_3430_USB2HS_PHY_DATA2);
+               omap_cfg_reg(T4_3430_USB2HS_PHY_DATA3);
+               omap_cfg_reg(T3_3430_USB2HS_PHY_DATA4);
+               omap_cfg_reg(R3_3430_USB2HS_PHY_DATA5);
+               omap_cfg_reg(R4_3430_USB2HS_PHY_DATA6);
+               omap_cfg_reg(T2_3430_USB2HS_PHY_DATA7);
+               break;
+       case EHCI_HCD_OMAP_MODE_TLL:
+               omap_cfg_reg(AA10_3430_USB2HS_TLL_STP);
+               omap_cfg_reg(AA8_3430_USB2HS_TLL_CLK);
+               omap_cfg_reg(AA9_3430_USB2HS_TLL_DIR);
+               omap_cfg_reg(AB11_3430_USB2HS_TLL_NXT);
+               omap_cfg_reg(AB10_3430_USB2HS_TLL_DATA0);
+               omap_cfg_reg(AB9_3430_USB2HS_TLL_DATA1);
+               omap_cfg_reg(W3_3430_USB2HS_TLL_DATA2);
+               omap_cfg_reg(T4_3430_USB2HS_TLL_DATA3);
+               omap_cfg_reg(T3_3430_USB2HS_TLL_DATA4);
+               omap_cfg_reg(R3_3430_USB2HS_TLL_DATA5);
+               omap_cfg_reg(R4_3430_USB2HS_TLL_DATA6);
+               omap_cfg_reg(T2_3430_USB2HS_TLL_DATA7);
+               break;
+       case EHCI_HCD_OMAP_MODE_UNKNOWN:
+               /* FALLTHROUGH */
+       default:
+               break;
+       }
+
+       switch (port_mode[2]) {
+       case EHCI_HCD_OMAP_MODE_PHY:
+               printk(KERN_WARNING "Port3 can't be used in PHY mode\n");
+               break;
+       case EHCI_HCD_OMAP_MODE_TLL:
+               omap_cfg_reg(AB3_3430_USB3HS_TLL_STP);
+               omap_cfg_reg(AA6_3430_USB3HS_TLL_CLK);
+               omap_cfg_reg(AA3_3430_USB3HS_TLL_DIR);
+               omap_cfg_reg(Y3_3430_USB3HS_TLL_NXT);
+               omap_cfg_reg(AA5_3430_USB3HS_TLL_DATA0);
+               omap_cfg_reg(Y4_3430_USB3HS_TLL_DATA1);
+               omap_cfg_reg(Y5_3430_USB3HS_TLL_DATA2);
+               omap_cfg_reg(W5_3430_USB3HS_TLL_DATA3);
+               omap_cfg_reg(AB12_3430_USB3HS_TLL_DATA4);
+               omap_cfg_reg(AB13_3430_USB3HS_TLL_DATA5);
+               omap_cfg_reg(AA13_3430_USB3HS_TLL_DATA6);
+               omap_cfg_reg(AA12_3430_USB3HS_TLL_DATA7);
+               break;
+       case EHCI_HCD_OMAP_MODE_UNKNOWN:
+               /* FALLTHROUGH */
+       default:
+               break;
+       }
+
+       return;
+}
+
+void __init usb_ehci_init(struct ehci_hcd_omap_platform_data *pdata)
+{
+       platform_device_add_data(&ehci_device, pdata, sizeof(*pdata));
+
+       /* Setup Pin IO MUX for EHCI */
+       if (cpu_is_omap34xx())
+               setup_ehci_io_mux(pdata->port_mode);
+
+       if (platform_device_register(&ehci_device) < 0) {
+               printk(KERN_ERR "Unable to register HS-USB (EHCI) device\n");
+               return;
+       }
+}
+
+#else
+
+void __init usb_ehci_init(struct ehci_hcd_omap_platform_data *pdata)
+
+{
+}
+
+#endif /* CONFIG_USB_EHCI_HCD */
+
index 1145a25..a80441d 100644 (file)
@@ -28,8 +28,8 @@
 
 #include <mach/hardware.h>
 #include <mach/irqs.h>
-#include <mach/mux.h>
-#include <mach/usb.h>
+#include <plat/mux.h>
+#include <plat/usb.h>
 
 #ifdef CONFIG_USB_MUSB_SOC
 
index 8622c24..10a2013 100644 (file)
@@ -16,8 +16,8 @@
 
 #include <linux/usb/musb.h>
 
-#include <mach/gpmc.h>
-#include <mach/mux.h>
+#include <plat/gpmc.h>
+#include <plat/mux.h>
 
 
 static u8              async_cs, sync_cs;
index a6f8eab..d89c6ad 100644 (file)
@@ -2,34 +2,105 @@ if ARCH_PXA
 
 menu "Intel PXA2xx/PXA3xx Implementations"
 
-if PXA3xx
+comment "Intel/Marvell Dev Platforms (sorted by hardware release time)"
 
-menu "Supported PXA3xx Processor Variants"
+config ARCH_LUBBOCK
+       bool "Intel DBPXA250 Development Platform (aka Lubbock)"
+       select PXA25x
+       select SA1111
+       select PXA_HAVE_BOARD_IRQS
 
-config CPU_PXA300
-       bool "PXA300 (codename Monahans-L)"
+config MACH_MAINSTONE
+       bool "Intel HCDDBBVA0 Development Platform (aka Mainstone)"
+       select PXA27x
+       select HAVE_PWM
+       select PXA_HAVE_BOARD_IRQS
 
-config CPU_PXA310
-       bool "PXA310 (codename Monahans-LV)"
+config MACH_ZYLONITE
+       bool
+       select PXA3xx
+       select PXA_SSP
+       select HAVE_PWM
+       select PXA_HAVE_BOARD_IRQS
+
+config MACH_ZYLONITE300
+       bool "PXA3xx Development Platform (aka Zylonite) PXA300/310"
        select CPU_PXA300
+       select CPU_PXA310
+       select MACH_ZYLONITE
 
-config CPU_PXA320
-       bool "PXA320 (codename Monahans-P)"
+config MACH_ZYLONITE320
+       bool "PXA3xx Development Platform (aka Zylonite) PXA320"
+       select CPU_PXA320
+       select MACH_ZYLONITE
 
-config CPU_PXA930
-       bool "PXA930 (codename Tavor-P)"
+config MACH_LITTLETON
+       bool "PXA3xx Form Factor Platform (aka Littleton)"
+       select PXA3xx
+       select PXA_SSP
 
-config CPU_PXA935
-       bool "PXA935 (codename Tavor-P65)"
+config MACH_TAVOREVB
+       bool "PXA930 Evaluation Board (aka TavorEVB)"
+       select PXA3xx
        select CPU_PXA930
 
-config CPU_PXA950
-       bool "PXA950 (codename Tavor-PV2)"
+config MACH_SAAR
+       bool "PXA930 Handheld Platform (aka SAAR)"
+       select PXA3xx
        select CPU_PXA930
 
-endmenu
+comment "Third Party Dev Platforms (sorted by vendor name)"
 
-endif
+config ARCH_PXA_IDP
+       bool "Accelent Xscale IDP"
+       select PXA25x
+
+config ARCH_VIPER
+       bool "Arcom/Eurotech VIPER SBC"
+       select PXA25x
+       select ISA
+       select I2C_GPIO
+       select HAVE_PWM
+       select PXA_HAVE_BOARD_IRQS
+       select PXA_HAVE_ISA_IRQS
+
+config MACH_BALLOON3
+       bool "Balloon 3 board"
+       select PXA27x
+       select IWMMXT
+       select PXA_HAVE_BOARD_IRQS
+
+config MACH_CSB726
+       bool "Enable Cogent CSB726 System On a Module"
+       select PXA27x
+       select IWMMXT
+       help
+         Say Y here if you intend to run this kernel on a Cogent
+         CSB726 System On Module.
+
+config CSB726_CSB701
+       bool "Enable support for CSB701 baseboard"
+       depends on MACH_CSB726
+
+config MACH_ARMCORE
+       bool "CompuLab CM-X255/CM-X270 modules"
+       select PXA27x
+       select IWMMXT
+       select PXA25x
+       select PXA_SSP
+
+config MACH_EM_X270
+       bool "CompuLab EM-x270 platform"
+       select PXA27x
+
+config MACH_EXEDA
+       bool "CompuLab eXeda platform"
+       select PXA27x
+
+config MACH_CM_X300
+       bool "CompuLab CM-X300 modules"
+       select PXA3xx
+       select CPU_PXA300
 
 config ARCH_GUMSTIX
        bool "Gumstix XScale 255 boards"
@@ -62,185 +133,24 @@ config MACH_STARGATE2
        select IWMMXT
        select PXA_HAVE_BOARD_IRQS
 
-config ARCH_LUBBOCK
-       bool "Intel DBPXA250 Development Platform"
-       select PXA25x
-       select SA1111
-       select PXA_HAVE_BOARD_IRQS
-
-config MACH_LOGICPD_PXA270
-       bool "LogicPD PXA270 Card Engine Development Platform"
-       select PXA27x
-       select HAVE_PWM
-       select PXA_HAVE_BOARD_IRQS
-
-config MACH_MAINSTONE
-       bool "Intel HCDDBBVA0 Development Platform"
-       select PXA27x
-       select HAVE_PWM
-       select PXA_HAVE_BOARD_IRQS
-
-config MACH_MP900C
-       bool "Nec Mobilepro 900/c"
-       select PXA25x
-
-config MACH_BALLOON3
-       bool "Balloon 3 board"
-       select PXA27x
-       select IWMMXT
-       select PXA_HAVE_BOARD_IRQS
-
-config ARCH_PXA_IDP
-       bool "Accelent Xscale IDP"
-       select PXA25x
-
-config PXA_SHARPSL
-       bool "SHARP Zaurus SL-5600, SL-C7xx and SL-Cxx00 Models"
-       select SHARP_SCOOP
-       select SHARP_PARAM
-       help
-         Say Y here if you intend to run this kernel on a
-         Sharp Zaurus SL-5600 (Poodle), SL-C700 (Corgi),
-         SL-C750 (Shepherd), SL-C760 (Husky), SL-C1000 (Akita),
-         SL-C3000 (Spitz), SL-C3100 (Borzoi) or SL-C6000x (Tosa)
-         handheld computer.
-
-config SHARPSL_PM
-       bool
-       select APM_EMULATION
-
-config CORGI_SSP_DEPRECATED
-       bool
-       select PXA_SSP
-       help
-         This option will include corgi_ssp.c and corgi_lcd.c
-         that corgi_ts.c and other legacy drivers (corgi_bl.c
-         and sharpsl_pm.c) may depend on.
-
-config MACH_POODLE
-       bool "Enable Sharp SL-5600 (Poodle) Support"
-       depends on PXA_SHARPSL
+config MACH_XCEP
+       bool "Iskratel Electronics XCEP"
        select PXA25x
-       select SHARP_LOCOMO
+       select MTD
+       select MTD_PARTITIONS
+       select MTD_PHYSMAP
+       select MTD_CFI_INTELEXT
+       select MTD_CFI
+       select MTD_CHAR
+       select SMC91X
        select PXA_SSP
-
-config MACH_CORGI
-       bool "Enable Sharp SL-C700 (Corgi) Support"
-       depends on PXA_SHARPSL
-       select PXA25x
-       select PXA_SHARP_C7xx
-
-config MACH_SHEPHERD
-       bool "Enable Sharp SL-C750 (Shepherd) Support"
-       depends on PXA_SHARPSL
-       select PXA25x
-       select PXA_SHARP_C7xx
-
-config MACH_HUSKY
-       bool "Enable Sharp SL-C760 (Husky) Support"
-       depends on PXA_SHARPSL
-       select PXA25x
-       select PXA_SHARP_C7xx
-
-config MACH_AKITA
-       bool "Enable Sharp SL-1000 (Akita) Support"
-       depends on PXA_SHARPSL
-       select PXA27x
-       select PXA_SHARP_Cxx00
-       select MACH_SPITZ
-       select I2C
-       select I2C_PXA
-
-config MACH_SPITZ
-       bool "Enable Sharp Zaurus SL-3000 (Spitz) Support"
-       depends on PXA_SHARPSL
-       select PXA27x
-       select PXA_SHARP_Cxx00
-
-config MACH_BORZOI
-       bool "Enable Sharp Zaurus SL-3100 (Borzoi) Support"
-       depends on PXA_SHARPSL
-       select PXA27x
-       select PXA_SHARP_Cxx00
-
-config MACH_TOSA
-       bool "Enable Sharp SL-6000x (Tosa) Support"
-       depends on PXA_SHARPSL
-       select PXA25x
-       select PXA_HAVE_BOARD_IRQS
-
-config ARCH_VIPER
-       bool "Arcom/Eurotech VIPER SBC"
-       select PXA25x
-       select ISA
-       select I2C_GPIO
-       select HAVE_PWM
-       select PXA_HAVE_BOARD_IRQS
-       select PXA_HAVE_ISA_IRQS
-
-config ARCH_PXA_ESERIES
-       bool "PXA based Toshiba e-series PDAs"
-       select PXA25x
-       select PXA_HAVE_BOARD_IRQS
-
-config MACH_E330
-       bool "Toshiba e330"
-       default y
-       depends on ARCH_PXA_ESERIES
-       help
-         Say Y here if you intend to run this kernel on a Toshiba
-         e330 family PDA.
-
-config MACH_E350
-       bool "Toshiba e350"
-       default y
-       depends on ARCH_PXA_ESERIES
-       help
-         Say Y here if you intend to run this kernel on a Toshiba
-         e350 family PDA.
-
-config MACH_E740
-       bool "Toshiba e740"
-       default y
-       depends on ARCH_PXA_ESERIES
-       select FB_W100
        help
-         Say Y here if you intend to run this kernel on a Toshiba
-         e740 family PDA.
-
-config MACH_E750
-       bool "Toshiba e750"
-       default y
-       depends on ARCH_PXA_ESERIES
-       select FB_W100
-       help
-         Say Y here if you intend to run this kernel on a Toshiba
-         e750 family PDA.
-
-config MACH_E400
-       bool "Toshiba e400"
-       default y
-       depends on ARCH_PXA_ESERIES
-       help
-         Say Y here if you intend to run this kernel on a Toshiba
-         e400 family PDA.
-
-config MACH_E800
-       bool "Toshiba e800"
-       default y
-       depends on ARCH_PXA_ESERIES
-       select FB_W100
-       help
-         Say Y here if you intend to run this kernel on a Toshiba
-         e800 family PDA.
+         PXA255 based Single Board Computer with SMC 91C111 ethernet chip and 64 MB of flash.
+         Tuned for usage in Libera instruments for particle accelerators.
 
 config TRIZEPS_PXA
        bool "PXA based Keith und Koep Trizeps DIMM-Modules"
 
-config MACH_H5000
-       bool "HP iPAQ h5000"
-       select PXA25x
-
 config MACH_TRIZEPS4
        bool "Keith und Koep Trizeps4 DIMM-Module"
        depends on TRIZEPS_PXA
@@ -274,13 +184,38 @@ config TRIZEPS_PCMCIA
        help
          Enable PCMCIA support for Trizeps modules
 
-config MACH_EM_X270
-       bool "CompuLab EM-x270 platform"
+config MACH_LOGICPD_PXA270
+       bool "LogicPD PXA270 Card Engine Development Platform"
        select PXA27x
+       select HAVE_PWM
+       select PXA_HAVE_BOARD_IRQS
 
-config MACH_EXEDA
-       bool "CompuLab eXeda platform"
+config MACH_PCM027
+       bool "Phytec phyCORE-PXA270 CPU module (PCM-027)"
        select PXA27x
+       select IWMMXT
+       select PXA_SSP
+       select PXA_HAVE_BOARD_IRQS
+
+config MACH_PCM990_BASEBOARD
+       bool "PHYTEC PCM-990 development board"
+       select HAVE_PWM
+       depends on MACH_PCM027
+
+choice
+       prompt "display on pcm990"
+       depends on MACH_PCM990_BASEBOARD
+
+config PCM990_DISPLAY_SHARP
+       bool "sharp lq084v1dg21 stn display"
+
+config PCM990_DISPLAY_NEC
+       bool "nec nl6448bc20_18d tft display"
+
+config PCM990_DISPLAY_NONE
+       bool "no display"
+
+endchoice
 
 config MACH_COLIBRI
        bool "Toradex Colibri PXA270"
@@ -290,45 +225,15 @@ config MACH_COLIBRI300
        bool "Toradex Colibri PXA300/310"
        select PXA3xx
        select CPU_PXA300
+       select CPU_PXA310
+       select HAVE_PWM
 
 config MACH_COLIBRI320
        bool "Toradex Colibri PXA320"
        select PXA3xx
        select CPU_PXA320
 
-config MACH_ZYLONITE
-       bool "PXA3xx Development Platform (aka Zylonite)"
-       select PXA3xx
-       select PXA_SSP
-       select HAVE_PWM
-       select PXA_HAVE_BOARD_IRQS
-
-config MACH_LITTLETON
-       bool "PXA3xx Form Factor Platform (aka Littleton)"
-       select PXA3xx
-       select PXA_SSP
-
-config MACH_TAVOREVB
-       bool "PXA930 Evaluation Board (aka TavorEVB)"
-       select PXA3xx
-       select CPU_PXA930
-
-config MACH_SAAR
-       bool "PXA930 Handheld Platform (aka SAAR)"
-       select PXA3xx
-       select CPU_PXA930
-
-config MACH_ARMCORE
-       bool "CompuLab CM-X255/CM-X270 modules"
-       select PXA27x
-       select IWMMXT
-       select PXA25x
-       select PXA_SSP
-
-config MACH_CM_X300
-       bool "CompuLab CM-X300 modules"
-       select PXA3xx
-       select CPU_PXA300
+comment "End-user Products (sorted by vendor name)"
 
 config MACH_H4700
        bool "HP iPAQ hx4700"
@@ -338,6 +243,15 @@ config MACH_H4700
        select HAVE_PWM
        select PXA_HAVE_BOARD_IRQS
 
+config MACH_H5000
+       bool "HP iPAQ h5000"
+       select PXA25x
+
+config MACH_HIMALAYA
+       bool "HTC Himalaya Support"
+       select CPU_PXA26x
+       select FB_W100
+
 config MACH_MAGICIAN
        bool "Enable HTC Magician Support"
        select PXA27x
@@ -346,11 +260,6 @@ config MACH_MAGICIAN
        select HAVE_PWM
        select PXA_HAVE_BOARD_IRQS
 
-config MACH_HIMALAYA
-       bool "HTC Himalaya Support"
-       select CPU_PXA26x
-       select FB_W100
-
 config MACH_MIOA701
        bool "Mitac Mio A701 Support"
        select PXA27x
@@ -362,13 +271,47 @@ config MACH_MIOA701
          MIO A701. Currently there is only basic support
          for this PDA.
 
-config MACH_PCM027
-       bool "Phytec phyCORE-PXA270 CPU module (PCM-027)"
+config PXA_EZX
+       bool "Motorola EZX Platform"
        select PXA27x
        select IWMMXT
-       select PXA_SSP
+       select HAVE_PWM
        select PXA_HAVE_BOARD_IRQS
 
+config MACH_EZX_A780
+       bool "Motorola EZX A780"
+       default y
+       depends on PXA_EZX
+
+config MACH_EZX_E680
+       bool "Motorola EZX E680"
+       default y
+       depends on PXA_EZX
+
+config MACH_EZX_A1200
+       bool "Motorola EZX A1200"
+       default y
+       depends on PXA_EZX
+
+config MACH_EZX_A910
+       bool "Motorola EZX A910"
+       default y
+       depends on PXA_EZX
+
+config MACH_EZX_E6
+       bool "Motorola EZX E6"
+       default y
+       depends on PXA_EZX
+
+config MACH_EZX_E2
+       bool "Motorola EZX E2"
+       default y
+       depends on PXA_EZX
+
+config MACH_MP900C
+       bool "Nec Mobilepro 900/c"
+       select PXA25x
+
 config ARCH_PXA_PALM
        bool "PXA based Palm PDAs"
        select HAVE_PWM
@@ -421,109 +364,172 @@ config MACH_PALMZ72
          Say Y here if you intend to run this kernel on Palm Zire 72
          handheld computer.
 
-config MACH_TREO680
-       bool "Palm Treo 680"
+config MACH_PALMLD
+       bool "Palm LifeDrive"
        default y
        depends on ARCH_PXA_PALM
        select PXA27x
        select IWMMXT
        help
-         Say Y here if you intend to run this kernel on Palm Treo 680
+         Say Y here if you intend to run this kernel on a Palm LifeDrive
+         handheld computer.
+
+config PALM_TREO
+       bool
+       depends on ARCH_PXA_PALM
+
+config MACH_CENTRO
+       bool "Palm Centro 685 (GSM)"
+       default y
+       depends on ARCH_PXA_PALM
+       select PXA27x
+       select IWMMXT
+       select PALM_TREO
+       help
+         Say Y here if you intend to run this kernel on Palm Centro 685 (GSM)
          smartphone.
 
-config MACH_PALMLD
-       bool "Palm LifeDrive"
+config MACH_TREO680
+       bool "Palm Treo 680"
        default y
        depends on ARCH_PXA_PALM
        select PXA27x
        select IWMMXT
+       select PALM_TREO
        help
-         Say Y here if you intend to run this kernel on a Palm LifeDrive
+         Say Y here if you intend to run this kernel on Palm Treo 680
+         smartphone.
+
+config PXA_SHARPSL
+       bool "SHARP Zaurus SL-5600, SL-C7xx and SL-Cxx00 Models"
+       select SHARP_SCOOP
+       select SHARP_PARAM
+       help
+         Say Y here if you intend to run this kernel on a
+         Sharp Zaurus SL-5600 (Poodle), SL-C700 (Corgi),
+         SL-C750 (Shepherd), SL-C760 (Husky), SL-C1000 (Akita),
+         SL-C3000 (Spitz), SL-C3100 (Borzoi) or SL-C6000x (Tosa)
          handheld computer.
 
-config MACH_PCM990_BASEBOARD
-       bool "PHYTEC PCM-990 development board"
-       select HAVE_PWM
-       depends on MACH_PCM027
+config SHARPSL_PM
+       bool
+       select APM_EMULATION
 
-choice
-       prompt "display on pcm990"
-       depends on MACH_PCM990_BASEBOARD
+config CORGI_SSP_DEPRECATED
+       bool
+       select PXA_SSP
+       help
+         This option will include corgi_ssp.c and corgi_lcd.c
+         that corgi_ts.c and other legacy drivers (corgi_bl.c
+         and sharpsl_pm.c) may depend on.
 
-config PCM990_DISPLAY_SHARP
-       bool "sharp lq084v1dg21 stn display"
+config MACH_POODLE
+       bool "Enable Sharp SL-5600 (Poodle) Support"
+       depends on PXA_SHARPSL
+       select PXA25x
+       select SHARP_LOCOMO
+       select PXA_SSP
 
-config PCM990_DISPLAY_NEC
-       bool "nec nl6448bc20_18d tft display"
+config MACH_CORGI
+       bool "Enable Sharp SL-C700 (Corgi) Support"
+       depends on PXA_SHARPSL
+       select PXA25x
+       select PXA_SHARP_C7xx
 
-config PCM990_DISPLAY_NONE
-       bool "no display"
+config MACH_SHEPHERD
+       bool "Enable Sharp SL-C750 (Shepherd) Support"
+       depends on PXA_SHARPSL
+       select PXA25x
+       select PXA_SHARP_C7xx
 
-endchoice
+config MACH_HUSKY
+       bool "Enable Sharp SL-C760 (Husky) Support"
+       depends on PXA_SHARPSL
+       select PXA25x
+       select PXA_SHARP_C7xx
 
-config MACH_CSB726
-       bool "Enable Cogent CSB726 System On a Module"
+config MACH_AKITA
+       bool "Enable Sharp SL-1000 (Akita) Support"
+       depends on PXA_SHARPSL
        select PXA27x
-       select IWMMXT
-       help
-         Say Y here if you intend to run this kernel on a Cogent
-         CSB726 System On Module.
+       select PXA_SHARP_Cxx00
+       select MACH_SPITZ
+       select I2C
+       select I2C_PXA
 
-config CSB726_CSB701
-       bool "Enable supprot for CSB701 baseboard"
-       depends on MACH_CSB726
+config MACH_SPITZ
+       bool "Enable Sharp Zaurus SL-3000 (Spitz) Support"
+       depends on PXA_SHARPSL
+       select PXA27x
+       select PXA_SHARP_Cxx00
 
-config PXA_EZX
-       bool "Motorola EZX Platform"
+config MACH_BORZOI
+       bool "Enable Sharp Zaurus SL-3100 (Borzoi) Support"
+       depends on PXA_SHARPSL
        select PXA27x
-       select IWMMXT
-       select HAVE_PWM
+       select PXA_SHARP_Cxx00
+
+config MACH_TOSA
+       bool "Enable Sharp SL-6000x (Tosa) Support"
+       depends on PXA_SHARPSL
+       select PXA25x
        select PXA_HAVE_BOARD_IRQS
 
-config MACH_EZX_A780
-       bool "Motorola EZX A780"
-       default y
-       depends on PXA_EZX
+config ARCH_PXA_ESERIES
+       bool "PXA based Toshiba e-series PDAs"
+       select PXA25x
+       select PXA_HAVE_BOARD_IRQS
 
-config MACH_EZX_E680
-       bool "Motorola EZX E680"
+config MACH_E330
+       bool "Toshiba e330"
        default y
-       depends on PXA_EZX
+       depends on ARCH_PXA_ESERIES
+       help
+         Say Y here if you intend to run this kernel on a Toshiba
+         e330 family PDA.
 
-config MACH_EZX_A1200
-       bool "Motorola EZX A1200"
+config MACH_E350
+       bool "Toshiba e350"
        default y
-       depends on PXA_EZX
+       depends on ARCH_PXA_ESERIES
+       help
+         Say Y here if you intend to run this kernel on a Toshiba
+         e350 family PDA.
 
-config MACH_EZX_A910
-       bool "Motorola EZX A910"
+config MACH_E740
+       bool "Toshiba e740"
        default y
-       depends on PXA_EZX
+       depends on ARCH_PXA_ESERIES
+       select FB_W100
+       help
+         Say Y here if you intend to run this kernel on a Toshiba
+         e740 family PDA.
 
-config MACH_EZX_E6
-       bool "Motorola EZX E6"
+config MACH_E750
+       bool "Toshiba e750"
        default y
-       depends on PXA_EZX
+       depends on ARCH_PXA_ESERIES
+       select FB_W100
+       help
+         Say Y here if you intend to run this kernel on a Toshiba
+         e750 family PDA.
 
-config MACH_EZX_E2
-       bool "Motorola EZX E2"
+config MACH_E400
+       bool "Toshiba e400"
        default y
-       depends on PXA_EZX
+       depends on ARCH_PXA_ESERIES
+       help
+         Say Y here if you intend to run this kernel on a Toshiba
+         e400 family PDA.
 
-config MACH_XCEP
-       bool "Iskratel Electronics XCEP"
-       select PXA25x
-       select MTD
-       select MTD_PARTITIONS
-       select MTD_PHYSMAP
-       select MTD_CFI_INTELEXT
-       select MTD_CFI
-       select MTD_CHAR
-       select SMC91X
-       select PXA_SSP
+config MACH_E800
+       bool "Toshiba e800"
+       default y
+       depends on ARCH_PXA_ESERIES
+       select FB_W100
        help
-         PXA255 based Single Board Computer with SMC 91C111 ethernet chip and 64 MB of flash.
-         Tuned for usage in Libera instruments for particle accelerators.
+         Say Y here if you intend to run this kernel on a Toshiba
+         e800 family PDA.
 
 endmenu
 
@@ -551,6 +557,42 @@ config PXA3xx
        help
          Select code specific to PXA3xx variants
 
+config CPU_PXA300
+       bool
+       select PXA3xx
+       help
+         PXA300 (codename Monahans-L)
+
+config CPU_PXA310
+       bool
+       select CPU_PXA300
+       help
+         PXA310 (codename Monahans-LV)
+
+config CPU_PXA320
+       bool
+       select PXA3xx
+       help
+         PXA320 (codename Monahans-P)
+
+config CPU_PXA930
+       bool
+       select PXA3xx
+       help
+         PXA930 (codename Tavor-P)
+
+config CPU_PXA935
+       bool
+       select CPU_PXA930
+       help
+         PXA935 (codename Tavor-P65)
+
+config CPU_PXA950
+       bool
+       select CPU_PXA930
+       help
+         PXA950 (codename Tavor-PV2)
+
 config PXA_SHARP_C7xx
        bool
        select PXA_SSP
index f10e152..b5d29e6 100644 (file)
@@ -24,33 +24,63 @@ obj-$(CONFIG_CPU_PXA300)    += pxa300.o
 obj-$(CONFIG_CPU_PXA320)       += pxa320.o
 obj-$(CONFIG_CPU_PXA930)       += pxa930.o
 
-# Specific board support
-obj-$(CONFIG_ARCH_GUMSTIX)     += gumstix.o
-obj-$(CONFIG_GUMSTIX_AM200EPD) += am200epd.o
-obj-$(CONFIG_GUMSTIX_AM300EPD) += am300epd.o
+# NOTE: keep the order of boards in accordance to their order in Kconfig
+
+# Intel/Marvell Dev Platforms
 obj-$(CONFIG_ARCH_LUBBOCK)     += lubbock.o
-obj-$(CONFIG_MACH_LOGICPD_PXA270) += lpd270.o
 obj-$(CONFIG_MACH_MAINSTONE)   += mainstone.o
-obj-$(CONFIG_MACH_BALLOON3)    += balloon3.o
-obj-$(CONFIG_MACH_MP900C)      += mp900.o
+obj-$(CONFIG_MACH_ZYLONITE300) += zylonite.o zylonite_pxa300.o
+obj-$(CONFIG_MACH_ZYLONITE320) += zylonite.o zylonite_pxa320.o
+obj-$(CONFIG_MACH_LITTLETON)   += littleton.o
+obj-$(CONFIG_MACH_TAVOREVB)    += tavorevb.o
+obj-$(CONFIG_MACH_SAAR)                += saar.o
+
+# 3rd Party Dev Platforms
 obj-$(CONFIG_ARCH_PXA_IDP)     += idp.o
+obj-$(CONFIG_ARCH_VIPER)       += viper.o
+obj-$(CONFIG_MACH_BALLOON3)    += balloon3.o
+obj-$(CONFIG_MACH_CSB726)      += csb726.o
+obj-$(CONFIG_CSB726_CSB701)    += csb701.o
+obj-$(CONFIG_MACH_ARMCORE)      += cm-x2xx.o cm-x255.o cm-x270.o
+ifeq ($(CONFIG_PCI),y)
+obj-$(CONFIG_MACH_ARMCORE)     += cm-x2xx-pci.o
+endif
+obj-$(CONFIG_MACH_EM_X270)     += em-x270.o
+obj-$(CONFIG_MACH_CM_X300)      += cm-x300.o
+obj-$(CONFIG_ARCH_GUMSTIX)     += gumstix.o
+obj-$(CONFIG_GUMSTIX_AM200EPD) += am200epd.o
+obj-$(CONFIG_GUMSTIX_AM300EPD) += am300epd.o
+obj-$(CONFIG_MACH_INTELMOTE2)   += imote2.o
+obj-$(CONFIG_MACH_STARGATE2)   += stargate2.o
+obj-$(CONFIG_MACH_XCEP)         += xcep.o
 obj-$(CONFIG_MACH_TRIZEPS4)    += trizeps4.o
+obj-$(CONFIG_MACH_LOGICPD_PXA270)      += lpd270.o
+obj-$(CONFIG_MACH_PCM027)              += pcm027.o
+obj-$(CONFIG_MACH_PCM990_BASEBOARD)    += pcm990-baseboard.o
 obj-$(CONFIG_MACH_COLIBRI)     += colibri-pxa270.o
 obj-$(CONFIG_MACH_COLIBRI300)  += colibri-pxa3xx.o colibri-pxa300.o
 obj-$(CONFIG_MACH_COLIBRI320)  += colibri-pxa3xx.o colibri-pxa320.o
+
+# End-user Products
+obj-$(CONFIG_MACH_H4700)       += hx4700.o
 obj-$(CONFIG_MACH_H5000)       += h5000.o
+obj-$(CONFIG_MACH_HIMALAYA)    += himalaya.o
+obj-$(CONFIG_MACH_MAGICIAN)    += magician.o
+obj-$(CONFIG_MACH_MIOA701)     += mioa701.o mioa701_bootresume.o
+obj-$(CONFIG_PXA_EZX)           += ezx.o
+obj-$(CONFIG_MACH_MP900C)      += mp900.o
+obj-$(CONFIG_MACH_PALMTE2)     += palmte2.o
+obj-$(CONFIG_MACH_PALMTC)      += palmtc.o
+obj-$(CONFIG_MACH_PALMT5)      += palmt5.o
+obj-$(CONFIG_MACH_PALMTX)      += palmtx.o
+obj-$(CONFIG_MACH_PALMZ72)     += palmz72.o
+obj-$(CONFIG_MACH_PALMLD)      += palmld.o
+obj-$(CONFIG_PALM_TREO)                += palmtreo.o
 obj-$(CONFIG_PXA_SHARP_C7xx)   += corgi.o sharpsl_pm.o corgi_pm.o
 obj-$(CONFIG_PXA_SHARP_Cxx00)  += spitz.o sharpsl_pm.o spitz_pm.o
 obj-$(CONFIG_CORGI_SSP_DEPRECATED)     += corgi_ssp.o corgi_lcd.o
 obj-$(CONFIG_MACH_POODLE)      += poodle.o
-obj-$(CONFIG_MACH_PCM027)      += pcm027.o
-obj-$(CONFIG_MACH_PCM990_BASEBOARD)    += pcm990-baseboard.o
 obj-$(CONFIG_MACH_TOSA)                += tosa.o
-obj-$(CONFIG_MACH_EM_X270)     += em-x270.o
-obj-$(CONFIG_MACH_H4700)       += hx4700.o
-obj-$(CONFIG_MACH_MAGICIAN)    += magician.o
-obj-$(CONFIG_MACH_HIMALAYA)    += himalaya.o
-obj-$(CONFIG_MACH_MIOA701)     += mioa701.o mioa701_bootresume.o
 obj-$(CONFIG_ARCH_PXA_ESERIES) += eseries.o
 obj-$(CONFIG_MACH_E330)                += e330.o
 obj-$(CONFIG_MACH_E350)                += e350.o
@@ -58,34 +88,6 @@ obj-$(CONFIG_MACH_E740)              += e740.o
 obj-$(CONFIG_MACH_E750)                += e750.o
 obj-$(CONFIG_MACH_E400)                += e400.o
 obj-$(CONFIG_MACH_E800)                += e800.o
-obj-$(CONFIG_MACH_PALMTE2)     += palmte2.o
-obj-$(CONFIG_MACH_PALMTC)      += palmtc.o
-obj-$(CONFIG_MACH_PALMT5)      += palmt5.o
-obj-$(CONFIG_MACH_PALMTX)      += palmtx.o
-obj-$(CONFIG_MACH_PALMLD)      += palmld.o
-obj-$(CONFIG_MACH_PALMZ72)     += palmz72.o
-obj-$(CONFIG_MACH_TREO680)     += treo680.o
-obj-$(CONFIG_ARCH_VIPER)       += viper.o
-
-ifeq ($(CONFIG_MACH_ZYLONITE),y)
-  obj-y                                += zylonite.o
-  obj-$(CONFIG_CPU_PXA300)     += zylonite_pxa300.o
-  obj-$(CONFIG_CPU_PXA320)     += zylonite_pxa320.o
-endif
-obj-$(CONFIG_MACH_LITTLETON)   += littleton.o
-obj-$(CONFIG_MACH_TAVOREVB)    += tavorevb.o
-obj-$(CONFIG_MACH_SAAR)                += saar.o
-
-obj-$(CONFIG_MACH_ARMCORE)      += cm-x2xx.o cm-x255.o cm-x270.o
-obj-$(CONFIG_MACH_CM_X300)      += cm-x300.o
-obj-$(CONFIG_PXA_EZX)           += ezx.o
-
-obj-$(CONFIG_MACH_XCEP)         += xcep.o
-
-obj-$(CONFIG_MACH_INTELMOTE2)   += imote2.o
-obj-$(CONFIG_MACH_STARGATE2)   += stargate2.o
-obj-$(CONFIG_MACH_CSB726)      += csb726.o
-obj-$(CONFIG_CSB726_CSB701)    += csb701.o
 
 # Support for blinky lights
 led-y := leds.o
@@ -95,8 +97,4 @@ led-$(CONFIG_ARCH_PXA_IDP)    += leds-idp.o
 
 obj-$(CONFIG_LEDS)             += $(led-y)
 
-ifeq ($(CONFIG_PCI),y)
-obj-$(CONFIG_MACH_ARMCORE) += cm-x2xx-pci.o
-endif
-
 obj-$(CONFIG_TOSA_BT)          += tosa-bt.o
index f23138b..b8cd07c 100644 (file)
@@ -306,6 +306,10 @@ static void __init balloon3_init(void)
         */
        ARB_CNTRL = ARB_CORE_PARK | 0x234;
 
+       pxa_set_ffuart_info(NULL);
+       pxa_set_btuart_info(NULL);
+       pxa_set_stuart_info(NULL);
+
        pxa_set_i2c_info(NULL);
        if (balloon3_has(BALLOON3_FEATURE_AUDIO))
                pxa_set_ac97_info(NULL);
index b50ef39..bff6e78 100644 (file)
@@ -453,6 +453,10 @@ static inline void cmx2xx_init_ac97(void) {}
 
 static void __init cmx2xx_init(void)
 {
+       pxa_set_ffuart_info(NULL);
+       pxa_set_btuart_info(NULL);
+       pxa_set_stuart_info(NULL);
+
        cmx2xx_pm_init();
 
        if (cpu_is_pxa25x())
index 102916f..d37cfa1 100644 (file)
@@ -3,9 +3,10 @@
  *
  * Support for the CompuLab CM-X300 modules
  *
- * Copyright (C) 2008 CompuLab Ltd.
+ * Copyright (C) 2008,2009 CompuLab Ltd.
  *
  * Mike Rapoport <mike@compulab.co.il>
+ * Igor Grinberg <grinberg@compulab.co.il>
  *
  * 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
 #include <linux/kernel.h>
 #include <linux/interrupt.h>
 #include <linux/init.h>
+#include <linux/delay.h>
 #include <linux/platform_device.h>
 
 #include <linux/gpio.h>
 #include <linux/dm9000.h>
 #include <linux/leds.h>
 #include <linux/rtc-v3020.h>
+#include <linux/pwm_backlight.h>
 
 #include <linux/i2c.h>
 #include <linux/i2c/pca953x.h>
 
+#include <linux/mfd/da903x.h>
+
+#include <linux/spi/spi.h>
+#include <linux/spi/spi_gpio.h>
+#include <linux/spi/tdo24m.h>
+
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <asm/setup.h>
 
 #include <mach/pxa300.h>
+#include <mach/pxa27x-udc.h>
 #include <mach/pxafb.h>
 #include <mach/mmc.h>
 #include <mach/ohci.h>
 #include <plat/i2c.h>
-#include <mach/pxa3xx_nand.h>
+#include <plat/pxa3xx_nand.h>
+#include <mach/audio.h>
 
 #include <asm/mach/map.h>
 
 #include "generic.h"
+#include "devices.h"
 
 #define CM_X300_ETH_PHYS       0x08000010
 
@@ -53,7 +65,7 @@
 #define GPIO97_RTC_RD          (97)
 #define GPIO98_RTC_IO          (98)
 
-static mfp_cfg_t cm_x300_mfp_cfg[] __initdata = {
+static mfp_cfg_t cm_x3xx_mfp_cfg[] __initdata = {
        /* LCD */
        GPIO54_LCD_LDD_0,
        GPIO55_LCD_LDD_1,
@@ -137,7 +149,6 @@ static mfp_cfg_t cm_x300_mfp_cfg[] __initdata = {
        GPIO36_UART1_DTR,
 
        /* GPIOs */
-       GPIO79_GPIO,                    /* LED */
        GPIO82_GPIO | MFP_PULL_HIGH,    /* MMC CD */
        GPIO85_GPIO,                    /* MMC WP */
        GPIO99_GPIO,                    /* Ethernet IRQ */
@@ -151,6 +162,50 @@ static mfp_cfg_t cm_x300_mfp_cfg[] __initdata = {
        /* Standard I2C */
        GPIO21_I2C_SCL,
        GPIO22_I2C_SDA,
+
+       /* PWM Backlight */
+       GPIO19_PWM2_OUT,
+};
+
+static mfp_cfg_t cm_x3xx_rev_lt130_mfp_cfg[] __initdata = {
+       /* GPIOs */
+       GPIO79_GPIO,                    /* LED */
+       GPIO77_GPIO,                    /* WiFi reset */
+       GPIO78_GPIO,                    /* BT reset */
+};
+
+static mfp_cfg_t cm_x3xx_rev_ge130_mfp_cfg[] __initdata = {
+       /* GPIOs */
+       GPIO76_GPIO,                    /* LED */
+       GPIO71_GPIO,                    /* WiFi reset */
+       GPIO70_GPIO,                    /* BT reset */
+};
+
+static mfp_cfg_t cm_x310_mfp_cfg[] __initdata = {
+       /* USB PORT 2 */
+       ULPI_STP,
+       ULPI_NXT,
+       ULPI_DIR,
+       GPIO30_ULPI_DATA_OUT_0,
+       GPIO31_ULPI_DATA_OUT_1,
+       GPIO32_ULPI_DATA_OUT_2,
+       GPIO33_ULPI_DATA_OUT_3,
+       GPIO34_ULPI_DATA_OUT_4,
+       GPIO35_ULPI_DATA_OUT_5,
+       GPIO36_ULPI_DATA_OUT_6,
+       GPIO37_ULPI_DATA_OUT_7,
+       GPIO38_ULPI_CLK,
+       /* external PHY reset pin */
+       GPIO127_GPIO,
+
+       /* USB PORT 3 */
+       GPIO77_USB_P3_1,
+       GPIO78_USB_P3_2,
+       GPIO79_USB_P3_3,
+       GPIO80_USB_P3_4,
+       GPIO81_USB_P3_5,
+       GPIO82_USB_P3_6,
+       GPIO0_2_USBH_PEN,
 };
 
 #if defined(CONFIG_DM9000) || defined(CONFIG_DM9000_MODULE)
@@ -195,17 +250,18 @@ static void __init cm_x300_init_dm9000(void)
 static inline void cm_x300_init_dm9000(void) {}
 #endif
 
+/* LCD */
 #if defined(CONFIG_FB_PXA) || defined(CONFIG_FB_PXA_MODULE)
 static struct pxafb_mode_info cm_x300_lcd_modes[] = {
        [0] = {
-               .pixclock       = 38000,
+               .pixclock       = 38250,
                .bpp            = 16,
                .xres           = 480,
                .yres           = 640,
                .hsync_len      = 8,
                .vsync_len      = 2,
                .left_margin    = 8,
-               .upper_margin   = 0,
+               .upper_margin   = 2,
                .right_margin   = 24,
                .lower_margin   = 4,
                .cmap_greyscale = 0,
@@ -227,7 +283,7 @@ static struct pxafb_mode_info cm_x300_lcd_modes[] = {
 
 static struct pxafb_mach_info cm_x300_lcd = {
        .modes                  = cm_x300_lcd_modes,
-       .num_modes              = 2,
+       .num_modes              = ARRAY_SIZE(cm_x300_lcd_modes),
        .lcd_conn               = LCD_COLOR_TFT_16BPP | LCD_PCLK_EDGE_FALL,
 };
 
@@ -239,6 +295,87 @@ static void __init cm_x300_init_lcd(void)
 static inline void cm_x300_init_lcd(void) {}
 #endif
 
+#if defined(CONFIG_BACKLIGHT_PWM) || defined(CONFIG_BACKLIGHT_PWM_MODULE)
+static struct platform_pwm_backlight_data cm_x300_backlight_data = {
+       .pwm_id         = 2,
+       .max_brightness = 100,
+       .dft_brightness = 100,
+       .pwm_period_ns  = 10000,
+};
+
+static struct platform_device cm_x300_backlight_device = {
+       .name           = "pwm-backlight",
+       .dev            = {
+               .parent = &pxa27x_device_pwm0.dev,
+               .platform_data  = &cm_x300_backlight_data,
+       },
+};
+
+static void cm_x300_init_bl(void)
+{
+       platform_device_register(&cm_x300_backlight_device);
+}
+#else
+static inline void cm_x300_init_bl(void) {}
+#endif
+
+#if defined(CONFIG_SPI_GPIO) || defined(CONFIG_SPI_GPIO_MODULE)
+#define GPIO_LCD_BASE  (144)
+#define GPIO_LCD_DIN   (GPIO_LCD_BASE + 8)     /* aux_gpio3_0 */
+#define GPIO_LCD_DOUT  (GPIO_LCD_BASE + 9)     /* aux_gpio3_1 */
+#define GPIO_LCD_SCL   (GPIO_LCD_BASE + 10)    /* aux_gpio3_2 */
+#define GPIO_LCD_CS    (GPIO_LCD_BASE + 11)    /* aux_gpio3_3 */
+#define LCD_SPI_BUS_NUM        (1)
+
+static struct spi_gpio_platform_data cm_x300_spi_gpio_pdata = {
+       .sck            = GPIO_LCD_SCL,
+       .mosi           = GPIO_LCD_DIN,
+       .miso           = GPIO_LCD_DOUT,
+       .num_chipselect = 1,
+};
+
+static struct platform_device cm_x300_spi_gpio = {
+       .name           = "spi_gpio",
+       .id             = LCD_SPI_BUS_NUM,
+       .dev            = {
+               .platform_data  = &cm_x300_spi_gpio_pdata,
+       },
+};
+
+static struct tdo24m_platform_data cm_x300_tdo24m_pdata = {
+       .model = TDO35S,
+};
+
+static struct spi_board_info cm_x300_spi_devices[] __initdata = {
+       {
+               .modalias               = "tdo24m",
+               .max_speed_hz           = 1000000,
+               .bus_num                = LCD_SPI_BUS_NUM,
+               .chip_select            = 0,
+               .controller_data        = (void *) GPIO_LCD_CS,
+               .platform_data          = &cm_x300_tdo24m_pdata,
+       },
+};
+
+static void __init cm_x300_init_spi(void)
+{
+       spi_register_board_info(cm_x300_spi_devices,
+                               ARRAY_SIZE(cm_x300_spi_devices));
+       platform_device_register(&cm_x300_spi_gpio);
+}
+#else
+static inline void cm_x300_init_spi(void) {}
+#endif
+
+#if defined(CONFIG_SND_PXA2XX_LIB_AC97)
+static void __init cm_x300_init_ac97(void)
+{
+       pxa_set_ac97_info(NULL);
+}
+#else
+static inline void cm_x300_init_ac97(void) {}
+#endif
+
 #if defined(CONFIG_MTD_NAND_PXA3xx) || defined(CONFIG_MTD_NAND_PXA3xx_MODULE)
 static struct mtd_partition cm_x300_nand_partitions[] = {
        [0] = {
@@ -333,9 +470,19 @@ static inline void cm_x300_init_mmc(void) {}
 #endif
 
 #if defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE)
+static int cm_x300_ohci_init(struct device *dev)
+{
+       if (cpu_is_pxa300())
+               UP2OCR = UP2OCR_HXS
+                       | UP2OCR_HXOE | UP2OCR_DMPDE | UP2OCR_DPPDE;
+
+       return 0;
+}
+
 static struct pxaohci_platform_data cm_x300_ohci_platform_data = {
        .port_mode      = PMM_PERPORT_MODE,
-       .flags          = ENABLE_PORT1 | ENABLE_PORT2 | POWER_CONTROL_LOW,
+       .flags          = ENABLE_PORT_ALL | POWER_CONTROL_LOW,
+       .init           = cm_x300_ohci_init,
 };
 
 static void __init cm_x300_init_ohci(void)
@@ -351,7 +498,6 @@ static struct gpio_led cm_x300_leds[] = {
        [0] = {
                .name = "cm-x300:green",
                .default_trigger = "heartbeat",
-               .gpio = 79,
                .active_low = 1,
        },
 };
@@ -371,6 +517,11 @@ static struct platform_device cm_x300_led_device = {
 
 static void __init cm_x300_init_leds(void)
 {
+       if (system_rev < 130)
+               cm_x300_leds[0].gpio = 79;
+       else
+               cm_x300_leds[0].gpio = 76;
+
        platform_device_register(&cm_x300_led_device);
 }
 #else
@@ -433,11 +584,94 @@ static void __init cm_x300_init_rtc(void)
 static inline void cm_x300_init_rtc(void) {}
 #endif
 
-static void __init cm_x300_init(void)
+/* DA9030 */
+struct da903x_subdev_info cm_x300_da9030_subdevs[] = {
+       {
+               .name = "da903x-backlight",
+               .id = DA9030_ID_WLED,
+       }
+};
+
+static struct da903x_platform_data cm_x300_da9030_info = {
+       .num_subdevs = ARRAY_SIZE(cm_x300_da9030_subdevs),
+       .subdevs = cm_x300_da9030_subdevs,
+};
+
+static struct i2c_board_info cm_x300_pmic_info = {
+       I2C_BOARD_INFO("da9030", 0x49),
+       .irq = IRQ_GPIO(0),
+       .platform_data = &cm_x300_da9030_info,
+};
+
+static struct i2c_pxa_platform_data cm_x300_pwr_i2c_info = {
+       .use_pio = 1,
+};
+
+static void __init cm_x300_init_da9030(void)
+{
+       pxa3xx_set_i2c_power_info(&cm_x300_pwr_i2c_info);
+       i2c_register_board_info(1, &cm_x300_pmic_info, 1);
+}
+
+static void __init cm_x300_init_wi2wi(void)
+{
+       int bt_reset, wlan_en;
+       int err;
+
+       if (system_rev < 130) {
+               wlan_en = 77;
+               bt_reset = 78;
+       } else {
+               wlan_en = 71;
+               bt_reset = 70;
+       }
+
+       /* Libertas and CSR reset */
+       err = gpio_request(wlan_en, "wlan en");
+       if (err) {
+               pr_err("CM-X300: failed to request wlan en gpio: %d\n", err);
+       } else {
+               gpio_direction_output(wlan_en, 1);
+               gpio_free(wlan_en);
+       }
+
+       err = gpio_request(bt_reset, "bt reset");
+       if (err) {
+               pr_err("CM-X300: failed to request bt reset gpio: %d\n", err);
+       } else {
+               gpio_direction_output(bt_reset, 1);
+               udelay(10);
+               gpio_set_value(bt_reset, 0);
+               udelay(10);
+               gpio_set_value(bt_reset, 1);
+               gpio_free(bt_reset);
+       }
+}
+
+/* MFP */
+static void __init cm_x300_init_mfp(void)
 {
        /* board-processor specific GPIO initialization */
-       pxa3xx_mfp_config(ARRAY_AND_SIZE(cm_x300_mfp_cfg));
+       pxa3xx_mfp_config(ARRAY_AND_SIZE(cm_x3xx_mfp_cfg));
+
+       if (system_rev < 130)
+               pxa3xx_mfp_config(ARRAY_AND_SIZE(cm_x3xx_rev_lt130_mfp_cfg));
+       else
+               pxa3xx_mfp_config(ARRAY_AND_SIZE(cm_x3xx_rev_ge130_mfp_cfg));
+
+       if (cpu_is_pxa310())
+               pxa3xx_mfp_config(ARRAY_AND_SIZE(cm_x310_mfp_cfg));
+}
+
+static void __init cm_x300_init(void)
+{
+       cm_x300_init_mfp();
+
+       pxa_set_ffuart_info(NULL);
+       pxa_set_btuart_info(NULL);
+       pxa_set_stuart_info(NULL);
 
+       cm_x300_init_da9030();
        cm_x300_init_dm9000();
        cm_x300_init_lcd();
        cm_x300_init_ohci();
@@ -445,7 +679,11 @@ static void __init cm_x300_init(void)
        cm_x300_init_nand();
        cm_x300_init_leds();
        cm_x300_init_i2c();
+       cm_x300_init_spi();
        cm_x300_init_rtc();
+       cm_x300_init_ac97();
+       cm_x300_init_wi2wi();
+       cm_x300_init_bl();
 }
 
 static void __init cm_x300_fixup(struct machine_desc *mdesc, struct tag *tags,
index 01bcfaa..061c453 100644 (file)
@@ -130,6 +130,9 @@ static struct platform_device *colibri_pxa270_devices[] __initdata = {
 static void __init colibri_pxa270_init(void)
 {
        pxa2xx_mfp_config(ARRAY_AND_SIZE(colibri_pxa270_pin_config));
+       pxa_set_ffuart_info(NULL);
+       pxa_set_btuart_info(NULL);
+       pxa_set_stuart_info(NULL);
        platform_add_devices(ARRAY_AND_SIZE(colibri_pxa270_devices));
 }
 
index 37c239c..45c23fd 100644 (file)
@@ -170,6 +170,10 @@ static inline void colibri_pxa310_init_ac97(void) {}
 
 void __init colibri_pxa300_init(void)
 {
+       pxa_set_ffuart_info(NULL);
+       pxa_set_btuart_info(NULL);
+       pxa_set_stuart_info(NULL);
+
        colibri_pxa300_init_eth();
        colibri_pxa300_init_ohci();
        colibri_pxa3xx_init_nand();
index ec0e14b..ae835fa 100644 (file)
@@ -199,6 +199,10 @@ static void __init colibri_pxa320_init_uart(void)
 
 void __init colibri_pxa320_init(void)
 {
+       pxa_set_ffuart_info(NULL);
+       pxa_set_btuart_info(NULL);
+       pxa_set_stuart_info(NULL);
+
        colibri_pxa320_init_eth();
        colibri_pxa320_init_ohci();
        colibri_pxa3xx_init_nand();
index efebaf4..e6c0a22 100644 (file)
@@ -25,7 +25,7 @@
 #include <mach/colibri.h>
 #include <mach/mmc.h>
 #include <mach/pxafb.h>
-#include <mach/pxa3xx_nand.h>
+#include <plat/pxa3xx_nand.h>
 
 #include "generic.h"
 #include "devices.h"
index b536b5a..74446cf 100644 (file)
@@ -671,6 +671,10 @@ static void __init corgi_init(void)
 
        pxa2xx_mfp_config(ARRAY_AND_SIZE(corgi_pin_config));
 
+       pxa_set_ffuart_info(NULL);
+       pxa_set_btuart_info(NULL);
+       pxa_set_stuart_info(NULL);
+
        corgi_init_spi();
 
        pxa_set_udc_info(&udc_info);
index a093282..d4a0733 100644 (file)
@@ -214,8 +214,8 @@ static struct sharpsl_charger_machinfo corgi_pm_machinfo = {
        .fatal_acin_volt  = SHARPSL_FATAL_ACIN_VOLT,
        .fatal_noacin_volt= SHARPSL_FATAL_NOACIN_VOLT,
        .bat_levels       = 40,
-       .bat_levels_noac  = spitz_battery_levels_noac,
-       .bat_levels_acin  = spitz_battery_levels_acin,
+       .bat_levels_noac  = sharpsl_battery_levels_noac,
+       .bat_levels_acin  = sharpsl_battery_levels_acin,
        .status_high_acin = 188,
        .status_low_acin  = 178,
        .status_high_noac = 185,
index 965480e..88575b8 100644 (file)
@@ -268,6 +268,9 @@ static void __init csb726_init(void)
 /*     MSC2 = 0x06697ff4; *//* none/SM501 */
        MSC2 = (MSC2 & ~0xffff) | 0x7ff4; /* SM501 */
 
+       pxa_set_ffuart_info(NULL);
+       pxa_set_btuart_info(NULL);
+       pxa_set_stuart_info(NULL);
        pxa_set_i2c_info(NULL);
        pxa27x_set_i2c_power_info(NULL);
        pxa_set_mci_info(&csb726_mci);
index 46fabe1..3395463 100644 (file)
@@ -4,17 +4,18 @@
 #include <linux/platform_device.h>
 #include <linux/dma-mapping.h>
 
+#include <mach/hardware.h>
 #include <mach/udc.h>
 #include <mach/pxafb.h>
 #include <mach/mmc.h>
 #include <mach/irda.h>
-#include <plat/i2c.h>
 #include <mach/ohci.h>
 #include <mach/pxa27x_keypad.h>
 #include <mach/pxa2xx_spi.h>
 #include <mach/camera.h>
 #include <mach/audio.h>
-#include <mach/pxa3xx_nand.h>
+#include <plat/i2c.h>
+#include <plat/pxa3xx_nand.h>
 
 #include "devices.h"
 #include "generic.h"
@@ -167,13 +168,18 @@ static struct resource pxa_resource_ffuart[] = {
        }
 };
 
-struct platform_device pxa_device_ffuart= {
+struct platform_device pxa_device_ffuart = {
        .name           = "pxa2xx-uart",
        .id             = 0,
        .resource       = pxa_resource_ffuart,
        .num_resources  = ARRAY_SIZE(pxa_resource_ffuart),
 };
 
+void __init pxa_set_ffuart_info(void *info)
+{
+       pxa_register_device(&pxa_device_ffuart, info);
+}
+
 static struct resource pxa_resource_btuart[] = {
        {
                .start  = 0x40200000,
@@ -193,6 +199,11 @@ struct platform_device pxa_device_btuart = {
        .num_resources  = ARRAY_SIZE(pxa_resource_btuart),
 };
 
+void __init pxa_set_btuart_info(void *info)
+{
+       pxa_register_device(&pxa_device_btuart, info);
+}
+
 static struct resource pxa_resource_stuart[] = {
        {
                .start  = 0x40700000,
@@ -212,6 +223,11 @@ struct platform_device pxa_device_stuart = {
        .num_resources  = ARRAY_SIZE(pxa_resource_stuart),
 };
 
+void __init pxa_set_stuart_info(void *info)
+{
+       pxa_register_device(&pxa_device_stuart, info);
+}
+
 static struct resource pxa_resource_hwuart[] = {
        {
                .start  = 0x41600000,
@@ -231,6 +247,14 @@ struct platform_device pxa_device_hwuart = {
        .num_resources  = ARRAY_SIZE(pxa_resource_hwuart),
 };
 
+void __init pxa_set_hwuart_info(void *info)
+{
+       if (cpu_is_pxa255())
+               pxa_register_device(&pxa_device_hwuart, info);
+       else
+               pr_info("UART: Ignoring attempt to register HWUART on non-PXA255 hardware");
+}
+
 static struct resource pxai2c_resources[] = {
        {
                .start  = 0x40301680,
index 74d3f89..8fde338 100644 (file)
@@ -55,6 +55,9 @@ static struct platform_device *devices[] __initdata = {
 
 static void __init e330_init(void)
 {
+       pxa_set_ffuart_info(NULL);
+       pxa_set_btuart_info(NULL);
+       pxa_set_stuart_info(NULL);
        eseries_register_clks();
        eseries_get_tmio_gpios();
        platform_add_devices(devices, ARRAY_SIZE(devices));
index 0800362..f50f055 100644 (file)
@@ -56,6 +56,9 @@ static struct platform_device *devices[] __initdata = {
 
 static void __init e350_init(void)
 {
+       pxa_set_ffuart_info(NULL);
+       pxa_set_btuart_info(NULL);
+       pxa_set_stuart_info(NULL);
        eseries_register_clks();
        eseries_get_tmio_gpios();
        platform_add_devices(devices, ARRAY_SIZE(devices));
index ed9c0c3..55b950f 100644 (file)
@@ -130,6 +130,9 @@ static struct platform_device *devices[] __initdata = {
 static void __init e400_init(void)
 {
        pxa2xx_mfp_config(ARRAY_AND_SIZE(e400_pin_config));
+       pxa_set_ffuart_info(NULL);
+       pxa_set_btuart_info(NULL);
+       pxa_set_stuart_info(NULL);
        /* Fixme - e400 may have a switched clock */
        eseries_register_clks();
        eseries_get_tmio_gpios();
index 49acdfa..94b23a9 100644 (file)
@@ -192,6 +192,9 @@ static struct platform_device *devices[] __initdata = {
 static void __init e740_init(void)
 {
        pxa2xx_mfp_config(ARRAY_AND_SIZE(e740_pin_config));
+       pxa_set_ffuart_info(NULL);
+       pxa_set_btuart_info(NULL);
+       pxa_set_stuart_info(NULL);
        eseries_register_clks();
        clk_add_alias("CLK_CK48M", e740_t7l66xb_device.name,
                        "UDCCLK", &pxa25x_device_udc.dev),
index 4052ece..5eccbce 100644 (file)
@@ -194,6 +194,9 @@ static struct platform_device *devices[] __initdata = {
 static void __init e750_init(void)
 {
        pxa2xx_mfp_config(ARRAY_AND_SIZE(e750_pin_config));
+       pxa_set_ffuart_info(NULL);
+       pxa_set_btuart_info(NULL);
+       pxa_set_stuart_info(NULL);
        clk_add_alias("CLK_CK3P6MI", e750_tc6393xb_device.name,
                        "GPIO11_CLK", NULL),
        eseries_get_tmio_gpios();
index 9866c7b..aad129b 100644 (file)
@@ -195,6 +195,9 @@ static struct platform_device *devices[] __initdata = {
 
 static void __init e800_init(void)
 {
+       pxa_set_ffuart_info(NULL);
+       pxa_set_btuart_info(NULL);
+       pxa_set_stuart_info(NULL);
        clk_add_alias("CLK_CK3P6MI", e800_tc6393xb_device.name,
                        "GPIO11_CLK", NULL),
        eseries_get_tmio_gpios();
index aec7f42..1c0de80 100644 (file)
@@ -967,7 +967,7 @@ static inline void em_x270_init_gpio_keys(void) {}
 #if defined(CONFIG_VIDEO_PXA27x) || defined(CONFIG_VIDEO_PXA27x_MODULE)
 static struct regulator *em_x270_camera_ldo;
 
-static int em_x270_sensor_init(struct device *dev)
+static int em_x270_sensor_init(void)
 {
        int ret;
 
@@ -996,7 +996,6 @@ static int em_x270_sensor_init(struct device *dev)
 }
 
 struct pxacamera_platform_data em_x270_camera_platform_data = {
-       .init   = em_x270_sensor_init,
        .flags  = PXA_CAMERA_MASTER | PXA_CAMERA_DATAWIDTH_8 |
                PXA_CAMERA_PCLK_EN | PXA_CAMERA_MCLK_EN,
        .mclk_10khz = 2600,
@@ -1049,8 +1048,10 @@ static struct platform_device em_x270_camera = {
 
 static void  __init em_x270_init_camera(void)
 {
-       pxa_set_camera_info(&em_x270_camera_platform_data);
-       platform_device_register(&em_x270_camera);
+       if (em_x270_sensor_init() == 0) {
+               pxa_set_camera_info(&em_x270_camera_platform_data);
+               platform_device_register(&em_x270_camera);
+       }
 }
 #else
 static inline void em_x270_init_camera(void) {}
@@ -1286,6 +1287,10 @@ static void __init em_x270_init(void)
 {
        pxa2xx_mfp_config(ARRAY_AND_SIZE(common_pin_config));
 
+       pxa_set_ffuart_info(NULL);
+       pxa_set_btuart_info(NULL);
+       pxa_set_stuart_info(NULL);
+
 #ifdef CONFIG_PM
        pxa27x_set_pwrmode(PWRMODE_DEEPSLEEP);
 #endif
index 588b265..626c82b 100644 (file)
 #include <linux/delay.h>
 #include <linux/pwm_backlight.h>
 #include <linux/input.h>
+#include <linux/gpio.h>
 #include <linux/gpio_keys.h>
+#include <linux/leds-lp3944.h>
+
+#include <media/soc_camera.h>
 
 #include <asm/setup.h>
 #include <asm/mach-types.h>
@@ -29,6 +33,7 @@
 #include <plat/i2c.h>
 #include <mach/hardware.h>
 #include <mach/pxa27x_keypad.h>
+#include <mach/camera.h>
 
 #include "devices.h"
 #include "generic.h"
@@ -38,6 +43,9 @@
 #define GPIO15_A910_FLIP_LID           15
 #define GPIO12_E680_LOCK_SWITCH        12
 #define GPIO15_E6_LOCK_SWITCH          15
+#define GPIO50_nCAM_EN                 50
+#define GPIO19_GEN1_CAM_RST            19
+#define GPIO28_GEN2_CAM_RST            28
 
 static struct platform_pwm_backlight_data ezx_backlight_data = {
        .pwm_id         = 0,
@@ -191,8 +199,8 @@ static unsigned long gen1_pin_config[] __initdata = {
        GPIO94_CIF_DD_5,
        GPIO17_CIF_DD_6,
        GPIO108_CIF_DD_7,
-       GPIO50_GPIO,                            /* CAM_EN */
-       GPIO19_GPIO,                            /* CAM_RST */
+       GPIO50_GPIO | MFP_LPM_DRIVE_HIGH,       /* CAM_EN */
+       GPIO19_GPIO | MFP_LPM_DRIVE_HIGH,       /* CAM_RST */
 
        /* EMU */
        GPIO120_GPIO,                           /* EMU_MUX1 */
@@ -248,8 +256,8 @@ static unsigned long gen2_pin_config[] __initdata = {
        GPIO48_CIF_DD_5,
        GPIO93_CIF_DD_6,
        GPIO12_CIF_DD_7,
-       GPIO50_GPIO,                            /* CAM_EN */
-       GPIO28_GPIO,                            /* CAM_RST */
+       GPIO50_GPIO | MFP_LPM_DRIVE_HIGH,       /* CAM_EN */
+       GPIO28_GPIO | MFP_LPM_DRIVE_HIGH,       /* CAM_RST */
        GPIO17_GPIO,                            /* CAM_FLASH */
 };
 #endif
@@ -683,6 +691,81 @@ static struct platform_device a780_gpio_keys = {
        },
 };
 
+/* camera */
+static int a780_camera_init(void)
+{
+       int err;
+
+       /*
+        * GPIO50_nCAM_EN is active low
+        * GPIO19_GEN1_CAM_RST is active on rising edge
+        */
+       err = gpio_request(GPIO50_nCAM_EN, "nCAM_EN");
+       if (err) {
+               pr_err("%s: Failed to request nCAM_EN\n", __func__);
+               goto fail;
+       }
+
+       err = gpio_request(GPIO19_GEN1_CAM_RST, "CAM_RST");
+       if (err) {
+               pr_err("%s: Failed to request CAM_RST\n", __func__);
+               goto fail_gpio_cam_rst;
+       }
+
+       gpio_direction_output(GPIO50_nCAM_EN, 1);
+       gpio_direction_output(GPIO19_GEN1_CAM_RST, 0);
+
+       return 0;
+
+fail_gpio_cam_rst:
+       gpio_free(GPIO50_nCAM_EN);
+fail:
+       return err;
+}
+
+static int a780_camera_power(struct device *dev, int on)
+{
+       gpio_set_value(GPIO50_nCAM_EN, !on);
+       return 0;
+}
+
+static int a780_camera_reset(struct device *dev)
+{
+       gpio_set_value(GPIO19_GEN1_CAM_RST, 0);
+       msleep(10);
+       gpio_set_value(GPIO19_GEN1_CAM_RST, 1);
+
+       return 0;
+}
+
+struct pxacamera_platform_data a780_pxacamera_platform_data = {
+       .flags  = PXA_CAMERA_MASTER | PXA_CAMERA_DATAWIDTH_8 |
+               PXA_CAMERA_PCLK_EN | PXA_CAMERA_MCLK_EN,
+       .mclk_10khz = 5000,
+};
+
+static struct i2c_board_info a780_camera_i2c_board_info = {
+       I2C_BOARD_INFO("mt9m111", 0x5d),
+};
+
+static struct soc_camera_link a780_iclink = {
+       .bus_id         = 0,
+       .flags          = SOCAM_SENSOR_INVERT_PCLK,
+       .i2c_adapter_id = 0,
+       .board_info     = &a780_camera_i2c_board_info,
+       .module_name    = "mt9m111",
+       .power          = a780_camera_power,
+       .reset          = a780_camera_reset,
+};
+
+static struct platform_device a780_camera = {
+       .name   = "soc-camera-pdrv",
+       .id     = 0,
+       .dev    = {
+               .platform_data = &a780_iclink,
+       },
+};
+
 static struct platform_device *a780_devices[] __initdata = {
        &a780_gpio_keys,
 };
@@ -693,12 +776,21 @@ static void __init a780_init(void)
        pxa2xx_mfp_config(ARRAY_AND_SIZE(gen1_pin_config));
        pxa2xx_mfp_config(ARRAY_AND_SIZE(a780_pin_config));
 
+       pxa_set_ffuart_info(NULL);
+       pxa_set_btuart_info(NULL);
+       pxa_set_stuart_info(NULL);
+
        pxa_set_i2c_info(NULL);
 
        set_pxa_fb_info(&ezx_fb_info_1);
 
        pxa_set_keypad_info(&a780_keypad_platform_data);
 
+       if (a780_camera_init() == 0) {
+               pxa_set_camera_info(&a780_pxacamera_platform_data);
+               platform_device_register(&a780_camera);
+       }
+
        platform_add_devices(ARRAY_AND_SIZE(ezx_devices));
        platform_add_devices(ARRAY_AND_SIZE(a780_devices));
 }
@@ -754,6 +846,10 @@ static void __init e680_init(void)
        pxa2xx_mfp_config(ARRAY_AND_SIZE(gen1_pin_config));
        pxa2xx_mfp_config(ARRAY_AND_SIZE(e680_pin_config));
 
+       pxa_set_ffuart_info(NULL);
+       pxa_set_btuart_info(NULL);
+       pxa_set_stuart_info(NULL);
+
        pxa_set_i2c_info(NULL);
        i2c_register_board_info(0, ARRAY_AND_SIZE(e680_i2c_board_info));
 
@@ -816,6 +912,10 @@ static void __init a1200_init(void)
        pxa2xx_mfp_config(ARRAY_AND_SIZE(gen2_pin_config));
        pxa2xx_mfp_config(ARRAY_AND_SIZE(a1200_pin_config));
 
+       pxa_set_ffuart_info(NULL);
+       pxa_set_btuart_info(NULL);
+       pxa_set_stuart_info(NULL);
+
        pxa_set_i2c_info(NULL);
        i2c_register_board_info(0, ARRAY_AND_SIZE(a1200_i2c_board_info));
 
@@ -864,6 +964,131 @@ static struct platform_device a910_gpio_keys = {
        },
 };
 
+/* camera */
+static int a910_camera_init(void)
+{
+       int err;
+
+       /*
+        * GPIO50_nCAM_EN is active low
+        * GPIO28_GEN2_CAM_RST is active on rising edge
+        */
+       err = gpio_request(GPIO50_nCAM_EN, "nCAM_EN");
+       if (err) {
+               pr_err("%s: Failed to request nCAM_EN\n", __func__);
+               goto fail;
+       }
+
+       err = gpio_request(GPIO28_GEN2_CAM_RST, "CAM_RST");
+       if (err) {
+               pr_err("%s: Failed to request CAM_RST\n", __func__);
+               goto fail_gpio_cam_rst;
+       }
+
+       gpio_direction_output(GPIO50_nCAM_EN, 1);
+       gpio_direction_output(GPIO28_GEN2_CAM_RST, 0);
+
+       return 0;
+
+fail_gpio_cam_rst:
+       gpio_free(GPIO50_nCAM_EN);
+fail:
+       return err;
+}
+
+static int a910_camera_power(struct device *dev, int on)
+{
+       gpio_set_value(GPIO50_nCAM_EN, !on);
+       return 0;
+}
+
+static int a910_camera_reset(struct device *dev)
+{
+       gpio_set_value(GPIO28_GEN2_CAM_RST, 0);
+       msleep(10);
+       gpio_set_value(GPIO28_GEN2_CAM_RST, 1);
+
+       return 0;
+}
+
+struct pxacamera_platform_data a910_pxacamera_platform_data = {
+       .flags  = PXA_CAMERA_MASTER | PXA_CAMERA_DATAWIDTH_8 |
+               PXA_CAMERA_PCLK_EN | PXA_CAMERA_MCLK_EN,
+       .mclk_10khz = 5000,
+};
+
+static struct i2c_board_info a910_camera_i2c_board_info = {
+       I2C_BOARD_INFO("mt9m111", 0x5d),
+};
+
+static struct soc_camera_link a910_iclink = {
+       .bus_id         = 0,
+       .i2c_adapter_id = 0,
+       .board_info     = &a910_camera_i2c_board_info,
+       .module_name    = "mt9m111",
+       .power          = a910_camera_power,
+       .reset          = a910_camera_reset,
+};
+
+static struct platform_device a910_camera = {
+       .name   = "soc-camera-pdrv",
+       .id     = 0,
+       .dev    = {
+               .platform_data = &a910_iclink,
+       },
+};
+
+/* leds-lp3944 */
+static struct lp3944_platform_data a910_lp3944_leds = {
+       .leds_size = LP3944_LEDS_MAX,
+       .leds = {
+               [0] = {
+                       .name = "a910:red:",
+                       .status = LP3944_LED_STATUS_OFF,
+                       .type = LP3944_LED_TYPE_LED,
+               },
+               [1] = {
+                       .name = "a910:green:",
+                       .status = LP3944_LED_STATUS_OFF,
+                       .type = LP3944_LED_TYPE_LED,
+               },
+               [2] {
+                       .name = "a910:blue:",
+                       .status = LP3944_LED_STATUS_OFF,
+                       .type = LP3944_LED_TYPE_LED,
+               },
+               /* Leds 3 and 4 are used as display power switches */
+               [3] = {
+                       .name = "a910::cli_display",
+                       .status = LP3944_LED_STATUS_OFF,
+                       .type = LP3944_LED_TYPE_LED_INVERTED
+               },
+               [4] = {
+                       .name = "a910::main_display",
+                       .status = LP3944_LED_STATUS_ON,
+                       .type = LP3944_LED_TYPE_LED_INVERTED
+               },
+               [5] = { .type = LP3944_LED_TYPE_NONE },
+               [6] = {
+                       .name = "a910::torch",
+                       .status = LP3944_LED_STATUS_OFF,
+                       .type = LP3944_LED_TYPE_LED,
+               },
+               [7] = {
+                       .name = "a910::flash",
+                       .status = LP3944_LED_STATUS_OFF,
+                       .type = LP3944_LED_TYPE_LED_INVERTED,
+               },
+       },
+};
+
+static struct i2c_board_info __initdata a910_i2c_board_info[] = {
+       {
+               I2C_BOARD_INFO("lp3944", 0x60),
+               .platform_data = &a910_lp3944_leds,
+       },
+};
+
 static struct platform_device *a910_devices[] __initdata = {
        &a910_gpio_keys,
 };
@@ -874,12 +1099,22 @@ static void __init a910_init(void)
        pxa2xx_mfp_config(ARRAY_AND_SIZE(gen2_pin_config));
        pxa2xx_mfp_config(ARRAY_AND_SIZE(a910_pin_config));
 
+       pxa_set_ffuart_info(NULL);
+       pxa_set_btuart_info(NULL);
+       pxa_set_stuart_info(NULL);
+
        pxa_set_i2c_info(NULL);
+       i2c_register_board_info(0, ARRAY_AND_SIZE(a910_i2c_board_info));
 
        set_pxa_fb_info(&ezx_fb_info_2);
 
        pxa_set_keypad_info(&a910_keypad_platform_data);
 
+       if (a910_camera_init() == 0) {
+               pxa_set_camera_info(&a910_pxacamera_platform_data);
+               platform_device_register(&a910_camera);
+       }
+
        platform_add_devices(ARRAY_AND_SIZE(ezx_devices));
        platform_add_devices(ARRAY_AND_SIZE(a910_devices));
 }
@@ -935,6 +1170,10 @@ static void __init e6_init(void)
        pxa2xx_mfp_config(ARRAY_AND_SIZE(gen2_pin_config));
        pxa2xx_mfp_config(ARRAY_AND_SIZE(e6_pin_config));
 
+       pxa_set_ffuart_info(NULL);
+       pxa_set_btuart_info(NULL);
+       pxa_set_stuart_info(NULL);
+
        pxa_set_i2c_info(NULL);
        i2c_register_board_info(0, ARRAY_AND_SIZE(e6_i2c_board_info));
 
@@ -971,6 +1210,10 @@ static void __init e2_init(void)
        pxa2xx_mfp_config(ARRAY_AND_SIZE(gen2_pin_config));
        pxa2xx_mfp_config(ARRAY_AND_SIZE(e2_pin_config));
 
+       pxa_set_ffuart_info(NULL);
+       pxa_set_btuart_info(NULL);
+       pxa_set_stuart_info(NULL);
+
        pxa_set_i2c_info(NULL);
        i2c_register_board_info(0, ARRAY_AND_SIZE(e2_i2c_board_info));
 
index 485fede..890fb90 100644 (file)
@@ -67,3 +67,8 @@ extern struct sysdev_class pxa_irq_sysclass;
 extern struct sysdev_class pxa_gpio_sysclass;
 extern struct sysdev_class pxa2xx_mfp_sysclass;
 extern struct sysdev_class pxa3xx_mfp_sysclass;
+
+void __init pxa_set_ffuart_info(void *info);
+void __init pxa_set_btuart_info(void *info);
+void __init pxa_set_stuart_info(void *info);
+void __init pxa_set_hwuart_info(void *info);
index 1708c01..96c3451 100644 (file)
@@ -211,6 +211,11 @@ static void __init gumstix_init(void)
 {
        pxa2xx_mfp_config(ARRAY_AND_SIZE(gumstix_pin_config));
 
+       pxa_set_ffuart_info(NULL);
+       pxa_set_btuart_info(NULL);
+       pxa_set_stuart_info(NULL);
+       pxa_set_hwuart_info(NULL);
+
        gumstix_bluetooth_init();
        gumstix_udc_init();
        gumstix_mmc_init();
index f3d220c..c1cab08 100644 (file)
@@ -193,6 +193,9 @@ static void __init h5000_init(void)
        fix_msc();
 
        pxa2xx_mfp_config(ARRAY_AND_SIZE(h5000_pin_config));
+       pxa_set_ffuart_info(NULL);
+       pxa_set_btuart_info(NULL);
+       pxa_set_stuart_info(NULL);
        pxa_set_udc_info(&h5000_udc_mach_info);
        platform_add_devices(ARRAY_AND_SIZE(devices));
 }
index cea99fe..f9a2e4b 100644 (file)
@@ -150,6 +150,9 @@ static void __init himalaya_lcd_init(void)
 
 static void __init himalaya_init(void)
 {
+       pxa_set_ffuart_info(NULL);
+       pxa_set_btuart_info(NULL);
+       pxa_set_stuart_info(NULL);
        himalaya_lcd_init();
        platform_add_devices(devices, ARRAY_SIZE(devices));
 }
index 83bd3c6..848c861 100644 (file)
@@ -820,6 +820,7 @@ static struct platform_device *devices[] __initdata = {
        &gpio_keys,
        &backlight,
        &w3220,
+       &hx4700_lcd,
        &egpio,
        &bq24022,
        &gpio_vbus,
@@ -849,6 +850,10 @@ static void __init hx4700_init(void)
        pxa2xx_mfp_config(ARRAY_AND_SIZE(hx4700_pin_config));
        hx4700_gpio_request(ARRAY_AND_SIZE(global_gpios));
 
+       pxa_set_ffuart_info(NULL);
+       pxa_set_btuart_info(NULL);
+       pxa_set_stuart_info(NULL);
+
        platform_add_devices(devices, ARRAY_SIZE(devices));
 
        pxa_set_ficp_info(&ficp_info);
index b6486ef..5c9e11d 100644 (file)
@@ -179,6 +179,9 @@ static void __init idp_init(void)
        printk("idp_init()\n");
 
        pxa2xx_mfp_config(ARRAY_AND_SIZE(idp_pin_config));
+       pxa_set_ffuart_info(NULL);
+       pxa_set_btuart_info(NULL);
+       pxa_set_stuart_info(NULL);
 
        platform_device_register(&smc91x_device);
        //platform_device_register(&mst_audio_device);
index 2a4945d..5b0862d 100644 (file)
@@ -554,8 +554,12 @@ static struct i2c_pxa_platform_data i2c_pdata = {
 
 static void __init imote2_init(void)
 {
-
        pxa2xx_mfp_config(ARRAY_AND_SIZE(imote2_pin_config));
+
+       pxa_set_ffuart_info(NULL);
+       pxa_set_btuart_info(NULL);
+       pxa_set_stuart_info(NULL);
+
        /* SPI chip select directions - all other directions should
         * be handled by drivers.*/
        gpio_direction_output(37, 0);
index aa3d9f7..50f1297 100644 (file)
  *
  *  PXA935     A0      0x56056931      0x1E653013
  *  PXA935     B0      0x56056936      0x6E653013
+ *  PXA935     B1      0x56056938      0x8E653013
  */
 #ifdef CONFIG_PXA25x
 #define __cpu_is_pxa210(id)                            \
                _id == 0x3;                             \
         })
 
-#define __cpu_is_pxa9xx(id)                            \
+#define __cpu_is_pxa93x(id)                            \
        ({                                              \
                unsigned int _id = (id) >> 4 & 0xfff;   \
                _id == 0x683 || _id == 0x693;           \
                __cpu_is_pxa3xx(read_cpuid_id());       \
         })
 
-#define cpu_is_pxa9xx()                                        \
+#define cpu_is_pxa93x()                                        \
        ({                                              \
-               __cpu_is_pxa9xx(read_cpuid_id());       \
+               __cpu_is_pxa93x(read_cpuid_id());       \
         })
 /*
  * return current memory and LCD clock frequency in units of 10kHz
diff --git a/arch/arm/mach-pxa/include/mach/palmtreo.h b/arch/arm/mach-pxa/include/mach/palmtreo.h
new file mode 100644 (file)
index 0000000..2d3f14e
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * GPIOs and interrupts for Palm Treo smartphones
+ *
+ * currently supported:
+ *     Palm Treo 680 (GSM)
+ *     Palm Centro 685 (GSM)
+ *
+ * Author:     Tomas Cech <sleep_walker@suse.cz>
+ *
+ * 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.
+ *
+ * find more info at www.hackndev.com
+ *
+ */
+
+#ifndef _INCLUDE_TREO_H_
+#define _INCLUDE_TREO_H_
+
+/* GPIOs */
+#define GPIO_NR_TREO_POWER_DETECT      0
+#define GPIO_NR_TREO_AMP_EN            27
+#define GPIO_NR_TREO_GREEN_LED 20
+#define GPIO_NR_TREO_RED_LED           79
+#define GPIO_NR_TREO_SD_DETECT_N       113
+#define GPIO_NR_TREO_EP_DETECT_N       116
+#define GPIO_NR_TREO_USB_DETECT        1
+#define GPIO_NR_TREO_USB_PULLUP        114
+#define GPIO_NR_TREO_GSM_POWER 40
+#define GPIO_NR_TREO_GSM_RESET 87
+#define GPIO_NR_TREO_GSM_WAKE  57
+#define GPIO_NR_TREO_GSM_HOST_WAKE     14
+#define GPIO_NR_TREO_GSM_TRIGGER       10
+#define GPIO_NR_TREO_IR_EN             115
+#define GPIO_NR_TREO_IR_TXD            47
+#define GPIO_NR_TREO_BL_POWER  38
+#define GPIO_NR_TREO_LCD_POWER 25
+
+/* Treo680 specific GPIOs */
+#ifdef CONFIG_MACH_TREO680
+#define GPIO_NR_TREO680_SD_READONLY    33
+#define GPIO_NR_TREO680_SD_POWER       42
+#define GPIO_NR_TREO680_VIBRATE_EN     44
+#define GPIO_NR_TREO680_KEYB_BL                24
+#define GPIO_NR_TREO680_BT_EN          43
+#endif /* CONFIG_MACH_TREO680 */
+
+/* Centro685 specific GPIOs */
+#define GPIO_NR_CENTRO_SD_POWER                21
+#define GPIO_NR_CENTRO_VIBRATE_EN      22
+#define GPIO_NR_CENTRO_KEYB_BL         33
+#define GPIO_NR_CENTRO_BT_EN           80
+
+/* Various addresses  */
+#define TREO_PHYS_RAM_START    0xa0000000
+#define TREO_PHYS_IO_START     0x40000000
+#define TREO_STR_BASE  0xa2000000
+
+/* BACKLIGHT */
+#define TREO_MAX_INTENSITY             254
+#define TREO_DEFAULT_INTENSITY 160
+#define TREO_LIMIT_MASK                0x7F
+#define TREO_PRESCALER         63
+#define TREO_PERIOD_NS         3500
+
+#endif
index f73061c..160ec83 100644 (file)
@@ -76,7 +76,8 @@ struct pxafb_mode_info {
        u_char          bpp;
        u_int           cmap_greyscale:1,
                        depth:8,
-                       unused:23;
+                       transparency:1,
+                       unused:22;
 
        /* Parallel Mode Timing */
        u_char          hsync_len;
diff --git a/arch/arm/mach-pxa/include/mach/regs-u2d.h b/arch/arm/mach-pxa/include/mach/regs-u2d.h
new file mode 100644 (file)
index 0000000..44b0b20
--- /dev/null
@@ -0,0 +1,199 @@
+#ifndef __ASM_ARCH_PXA3xx_U2D_H
+#define __ASM_ARCH_PXA3xx_U2D_H
+
+#include <mach/bitfield.h>
+
+/*
+ * USB2 device controller registers and bits definitions
+ */
+#define U2DCR          (0x0000)        /* U2D Control Register */
+#define U2DCR_NDC      (1   << 31)     /* NAK During Config */
+#define U2DCR_HSTC     (0x7 << 28)     /* High Speed Timeout Calibration */
+#define U2DCR_SPEOREN  (1   << 27)     /* Short Packet EOR INTR generation Enable */
+#define U2DCR_FSTC     (0x7 << 24)     /* Full Speed Timeout Calibration */
+#define U2DCR_UCLKOVR  (1   << 22)     /* UTM Clock Override */
+#define U2DCR_ABP      (1   << 21)     /* Application Bus Power */
+#define U2DCR_ADD      (1   << 20)     /* Application Device Disconnect */
+#define U2DCR_CC       (1   << 19)     /* Configuration Change */
+#define U2DCR_HS       (1   << 18)     /* High Speed USB Detection */
+#define U2DCR_SMAC     (1   << 17)     /* Switch Endpoint Memory to Active Configuration */
+#define U2DCR_DWRE     (1   << 16)     /* Device Remote Wake-up Feature */
+#define U2DCR_ACN      (0xf << 12)     /* Active U2D Configuration Number */
+#define U2DCR_AIN      (0xf << 8)      /* Active U2D Interface Number */
+#define U2DCR_AAISN    (0xf << 4)      /* Active U2D Alternate Interface Setting Number */
+#define U2DCR_EMCE     (1   << 3)      /* Endpoint Memory Configuration Error */
+#define U2DCR_UDR      (1   << 2)      /* U2D Resume */
+#define U2DCR_UDA      (1   << 1)      /* U2D Active */
+#define U2DCR_UDE      (1   << 0)      /* U2D Enable */
+
+#define U2DICR                 (0x0004)        /* U2D Interrupt Control Register */
+#define U2DISR                 (0x000C)        /* U2D Interrupt Status Register */
+#define U2DINT_CC              (1 << 31)       /* Interrupt - Configuration Change */
+#define U2DINT_SOF             (1 << 30)       /* Interrupt - SOF */
+#define U2DINT_USOF            (1 << 29)       /* Interrupt - micro SOF */
+#define U2DINT_RU              (1 << 28)       /* Interrupt - Resume */
+#define U2DINT_SU              (1 << 27)       /* Interrupt - Suspend */
+#define U2DINT_RS              (1 << 26)       /* Interrupt - Reset */
+#define U2DINT_DPE             (1 << 25)       /* Interrupt - Data Packet Error */
+#define U2DINT_FIFOERR         (0x4)           /* Interrupt - endpoint FIFO error */
+#define U2DINT_PACKETCMP       (0x2)           /* Interrupt - endpoint packet complete */
+#define U2DINT_SPACKETCMP      (0x1)           /* Interrupt - endpoint short packet complete */
+
+#define U2DFNR                 (0x0014)        /* U2D Frame Number Register */
+
+#define U2DINT(n, intr)                (((intr) & 0x07) << (((n) & 0x07) * 3))
+#define U2DICR2                        (0x0008)        /* U2D Interrupt Control Register 2 */
+#define U2DISR2                        (0x0010)        /* U2D Interrupt Status Register 2 */
+
+#define U2DOTGCR               (0x0020)        /* U2D OTG Control Register */
+#define U2DOTGCR_OTGEN         (1 << 31)       /* On-The-Go Enable */
+#define U2DOTGCR_AALTHNP       (1 << 30)       /* A-device Alternate Host Negotiation Protocal Port Support */
+#define U2DOTGCR_AHNP          (1 << 29)       /* A-device Host Negotiation Protocal Support */
+#define U2DOTGCR_BHNP          (1 << 28)       /* B-device Host Negotiation Protocal Enable */
+
+#ifdef CONFIG_CPU_PXA930
+#define U2DOTGCR_LPA           (1 << 15)       /* ULPI low power mode active */
+#define U2DOTGCR_IESI          (1 << 13)       /* OTG interrupt Enable */
+#define U2DOTGCR_ISSI          (1 << 12)       /* OTG interrupt status */
+#endif
+
+#define U2DOTGCR_CKAF  (1 << 5)        /* Carkit Mode Alternate Function Select */
+#define U2DOTGCR_UTMID (1 << 4)        /* UTMI Interface Disable */
+#define U2DOTGCR_ULAF  (1 << 3)        /* ULPI Mode Alternate Function Select */
+#define U2DOTGCR_SMAF  (1 << 2)        /* Serial Mode Alternate Function Select */
+#define U2DOTGCR_RTSM  (1 << 1)        /* Return to Synchronous Mode (ULPI Mode) */
+#define U2DOTGCR_ULE   (1 << 0)        /* ULPI Wrapper Enable */
+
+#define U2DOTGICR      (0x0024)        /* U2D OTG Interrupt Control Register */
+#define U2DOTGISR      (0x0028)        /* U2D OTG Interrupt Status Register */
+
+#define U2DOTGINT_SF   (1 << 17)       /* OTG Set Feature Command Received */
+#define U2DOTGINT_SI   (1 << 16)       /* OTG Interrupt */
+#define U2DOTGINT_RLS1 (1 << 14)       /* RXCMD Linestate[1] Change Interrupt Rise */
+#define U2DOTGINT_RLS0 (1 << 13)       /* RXCMD Linestate[0] Change Interrupt Rise */
+#define U2DOTGINT_RID  (1 << 12)       /* RXCMD OTG ID Change Interrupt Rise */
+#define U2DOTGINT_RSE  (1 << 11)       /* RXCMD OTG Session End Interrupt Rise */
+#define U2DOTGINT_RSV  (1 << 10)       /* RXCMD OTG Session Valid Interrupt Rise */
+#define U2DOTGINT_RVV  (1 << 9)        /* RXCMD OTG Vbus Valid Interrupt Rise */
+#define U2DOTGINT_RCK  (1 << 8)        /* RXCMD Carkit Interrupt Rise */
+#define U2DOTGINT_FLS1 (1 << 6)        /* RXCMD Linestate[1] Change Interrupt Fall */
+#define U2DOTGINT_FLS0 (1 << 5)        /* RXCMD Linestate[0] Change Interrupt Fall */
+#define U2DOTGINT_FID  (1 << 4)        /* RXCMD OTG ID Change Interrupt Fall */
+#define U2DOTGINT_FSE  (1 << 3)        /* RXCMD OTG Session End Interrupt Fall */
+#define U2DOTGINT_FSV  (1 << 2)        /* RXCMD OTG Session Valid Interrupt Fall */
+#define U2DOTGINT_FVV  (1 << 1)        /* RXCMD OTG Vbus Valid Interrupt Fall */
+#define U2DOTGINT_FCK  (1 << 0)        /* RXCMD Carkit Interrupt Fall */
+
+#define U2DOTGUSR      (0x002C)        /* U2D OTG ULPI Status Register */
+#define U2DOTGUSR_LPA  (1 << 31)       /* ULPI Low Power Mode Active */
+#define U2DOTGUSR_S6A  (1 << 30)       /* ULPI Serial Mode (6-pin) Active */
+#define U2DOTGUSR_S3A  (1 << 29)       /* ULPI Serial Mode (3-pin) Active */
+#define U2DOTGUSR_CKA  (1 << 28)       /* ULPI Car Kit Mode Active */
+#define U2DOTGUSR_LS1  (1 << 6)        /* RXCMD Linestate 1 Status */
+#define U2DOTGUSR_LS0  (1 << 5)        /* RXCMD Linestate 0 Status */
+#define U2DOTGUSR_ID   (1 << 4)        /* OTG IDGnd Status */
+#define U2DOTGUSR_SE   (1 << 3)        /* OTG Session End Status */
+#define U2DOTGUSR_SV   (1 << 2)        /* OTG Session Valid Status */
+#define U2DOTGUSR_VV   (1 << 1)        /* OTG Vbus Valid Status */
+#define U2DOTGUSR_CK   (1 << 0)        /* Carkit Interrupt Status */
+
+#define U2DOTGUCR      (0x0030)        /* U2D OTG ULPI Control Register */
+#define U2DOTGUCR_RUN  (1    << 25)    /* RUN */
+#define U2DOTGUCR_RNW  (1    << 24)    /* Read or Write operation */
+#define U2DOTGUCR_ADDR (0x3f << 16)    /* Address of the ULPI PHY register */
+#define U2DOTGUCR_WDATA        (0xff << 8)     /* The data for a WRITE command */
+#define U2DOTGUCR_RDATA        (0xff << 0)     /* The data for a READ command */
+
+#define U2DP3CR                (0x0034)        /* U2D Port 3 Control Register */
+#define U2DP3CR_P2SS   (0x3 << 8)      /* Host Port 2 Serial Mode Select */
+#define U2DP3CR_P3SS   (0x7 << 4)      /* Host Port 3 Serial Mode Select */
+#define U2DP3CR_VPVMBEN        (0x1 << 2)      /* Host Port 3 Vp/Vm Block Enable */
+#define U2DP3CR_CFG    (0x3 << 0)      /* Host Port 3 Configuration */
+
+#define U2DCSR0                (0x0100)        /* U2D Control/Status Register - Endpoint 0 */
+#define U2DCSR0_IPA    (1 << 8)        /* IN Packet Adjusted */
+#define U2DCSR0_SA     (1 << 7)        /* SETUP Active */
+#define U2DCSR0_RNE    (1 << 6)        /* Receive FIFO Not Empty */
+#define U2DCSR0_FST    (1 << 5)        /* Force Stall */
+#define U2DCSR0_SST    (1 << 4)        /* Send Stall */
+#define U2DCSR0_DME    (1 << 3)        /* DMA Enable */
+#define U2DCSR0_FTF    (1 << 2)        /* Flush Transmit FIFO */
+#define U2DCSR0_IPR    (1 << 1)        /* IN Packet Ready */
+#define U2DCSR0_OPC    (1 << 0)        /* OUT Packet Complete */
+
+#define U2DCSR(x)      (0x0100 + ((x) << 2))   /* U2D Control/Status Register - Endpoint x */
+#define U2DCSR_BF      (1 << 10)       /* Buffer Full, for OUT eps */
+#define U2DCSR_BE      (1 << 10)       /* Buffer Empty, for IN eps */
+#define U2DCSR_DPE     (1 << 9)        /* Data Packet Error, for ISO eps only */
+#define U2DCSR_FEF     (1 << 8)        /* Flush Endpoint FIFO */
+#define U2DCSR_SP      (1 << 7)        /* Short Packet Control/Status, for OUT eps only, readonly */
+#define U2DCSR_BNE     (1 << 6)        /* Buffer Not Empty, for OUT eps */
+#define U2DCSR_BNF     (1 << 6)        /* Buffer Not Full, for IN eps */
+#define U2DCSR_FST     (1 << 5)        /* Force STALL, write 1 set */
+#define U2DCSR_SST     (1 << 4)        /* Sent STALL, write 1 clear */
+#define U2DCSR_DME     (1 << 3)        /* DMA Enable */
+#define U2DCSR_TRN     (1 << 2)        /* Tx/Rx NAK, write 1 clear */
+#define U2DCSR_PC      (1 << 1)        /* Packet Complete, write 1 clear */
+#define U2DCSR_FS      (1 << 0)        /* FIFO needs Service */
+
+#define U2DBCR0                (0x0200)                /* U2D Byte Count Register - Endpoint 0 */
+#define U2DBCR(x)      (0x0200 + ((x) << 2))   /* U2D Byte Count Register - Endpoint x */
+
+#define U2DDR0         (0x0300)                /* U2D Data Register - Endpoint 0 */
+
+#define U2DEPCR(x)     (0x0400 + ((x) << 2))   /* U2D Configuration Register - Endpoint x */
+#define U2DEPCR_EE     (1 << 0)                /* Endpoint Enable */
+#define U2DEPCR_BS_MASK        (0x3FE)                 /* Buffer Size, BS*8=FIFO size, max 8184B = 8KB */
+
+#define U2DSCA         (0x0500)                /* U2D Setup Command Address */
+#define U2DSCA_VALUE   (0x0120)
+
+#define U2DEN0         (0x0504)                /* U2D Endpoint Information Register - Endpoint 0 */
+#define U2DEN(x)       (0x0504 + ((x) << 2))   /* U2D Endpoint Information Register - Endpoint x */
+
+/* U2DMA registers */
+#define U2DMACSR0              (0x1000)        /* U2DMA Control/Status Register - Channel 0 */
+#define U2DMACSR(x)            (0x1000 + ((x) << 2))   /* U2DMA Control/Status Register - Channel x */
+#define U2DMACSR_RUN           (1 << 31)       /* Run Bit (read / write) */
+#define U2DMACSR_STOPIRQEN     (1 << 29)       /* Stop Interrupt Enable (read / write) */
+#define U2DMACSR_EORIRQEN      (1 << 28)       /* End of Receive Interrupt Enable (R/W) */
+#define U2DMACSR_EORJMPEN      (1 << 27)       /* Jump to next descriptor on EOR */
+#define U2DMACSR_EORSTOPEN     (1 << 26)       /* STOP on an EOR */
+#define U2DMACSR_RASIRQEN      (1 << 23)       /* Request After Cnannel Stopped Interrupt Enable */
+#define U2DMACSR_MASKRUN       (1 << 22)       /* Mask Run */
+#define U2DMACSR_SCEMC         (3 << 18)       /* System Bus Split Completion Error Message Class */
+#define U2DMACSR_SCEMI         (0x1f << 13)    /* System Bus Split Completion Error Message Index */
+#define U2DMACSR_BUSERRTYPE    (7 << 10)       /* PX Bus Error Type */
+#define U2DMACSR_EORINTR       (1 << 9)        /* End Of Receive */
+#define U2DMACSR_REQPEND       (1 << 8)        /* Request Pending */
+#define U2DMACSR_RASINTR       (1 << 4)        /* Request After Channel Stopped (read / write 1 clear) */#define U2DMACSR_STOPINTR     (1 << 3)        /* Stop Interrupt (read only) */
+#define U2DMACSR_ENDINTR       (1 << 2)        /* End Interrupt (read / write 1 clear) */
+#define U2DMACSR_STARTINTR     (1 << 1)        /* Start Interrupt (read / write 1 clear) */
+#define U2DMACSR_BUSERRINTR    (1 << 0)        /* Bus Error Interrupt (read / write 1 clear) */
+
+#define U2DMACR                (0x1080)                /* U2DMA Control Register */
+#define U2DMAINT       (0x10F0)                /* U2DMA Interrupt Register */
+
+#define U2DMABR0       (0x1100)                /* U2DMA Branch Register - Channel 0 */
+#define U2DMABR(x)      (0x1100 + (x) << 2)    /* U2DMA Branch Register - Channel x */
+
+#define U2DMADADR0      (0x1200)               /* U2DMA Descriptor Address Register - Channel 0 */
+#define U2DMADADR(x)    (0x1200 + (x) * 0x10)  /* U2DMA Descriptor Address Register - Channel x */
+
+#define U2DMADADR_STOP (1U << 0)
+
+#define U2DMASADR0     (0x1204)                /* U2DMA Source Address Register - Channel 0 */
+#define U2DMASADR(x)   (0x1204 + (x) * 0x10)   /* U2DMA Source Address Register - Channel x */
+#define U2DMATADR0     (0x1208)                /* U2DMA Target Address Register - Channel 0 */
+#define U2DMATADR(x)   (0x1208 + (x) * 0x10)   /* U2DMA Target Address Register - Channel x */
+
+#define U2DMACMDR0     (0x120C)                /* U2DMA Command Address Register - Channel 0 */
+#define U2DMACMDR(x)   (0x120C + (x) * 0x10)   /* U2DMA Command Address Register - Channel x */
+
+#define U2DMACMDR_XFRDIS       (1 << 31)       /* Transfer Direction */
+#define U2DMACMDR_STARTIRQEN   (1 << 22)       /* Start Interrupt Enable */
+#define U2DMACMDR_ENDIRQEN     (1 << 21)       /* End Interrupt Enable */
+#define U2DMACMDR_PACKCOMP     (1 << 13)       /* Packet Complete */
+#define U2DMACMDR_LEN          (0x07ff)        /* length mask (max = 2K - 1) */
+
+#endif /* __ASM_ARCH_PXA3xx_U2D_H */
diff --git a/arch/arm/mach-pxa/include/mach/treo680.h b/arch/arm/mach-pxa/include/mach/treo680.h
deleted file mode 100644 (file)
index af443b2..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * GPIOs and interrupts for Palm Treo 680 smartphone
- *
- * 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 _INCLUDE_TREO680_H_
-#define _INCLUDE_TREO680_H_
-
-/* GPIOs */
-#define GPIO_NR_TREO680_POWER_DETECT   0
-#define GPIO_NR_TREO680_AMP_EN         27
-#define GPIO_NR_TREO680_KEYB_BL                24
-#define GPIO_NR_TREO680_VIBRATE_EN     44
-#define GPIO_NR_TREO680_GREEN_LED      20
-#define GPIO_NR_TREO680_RED_LED                79
-#define GPIO_NR_TREO680_SD_DETECT_N    113
-#define GPIO_NR_TREO680_SD_READONLY    33
-#define GPIO_NR_TREO680_EP_DETECT_N    116
-#define GPIO_NR_TREO680_SD_POWER       42
-#define GPIO_NR_TREO680_USB_DETECT     1
-#define GPIO_NR_TREO680_USB_PULLUP     114
-#define GPIO_NR_TREO680_GSM_POWER      40
-#define GPIO_NR_TREO680_GSM_RESET      87
-#define GPIO_NR_TREO680_GSM_WAKE       57
-#define GPIO_NR_TREO680_GSM_HOST_WAKE  14
-#define GPIO_NR_TREO680_GSM_TRIGGER    10
-#define GPIO_NR_TREO680_BT_EN          43
-#define GPIO_NR_TREO680_IR_EN          115
-#define GPIO_NR_TREO680_IR_TXD         47
-#define GPIO_NR_TREO680_BL_POWER       38
-#define GPIO_NR_TREO680_LCD_POWER      25
-
-/* Various addresses  */
-#define TREO680_PHYS_RAM_START 0xa0000000
-#define TREO680_PHYS_IO_START  0x40000000
-#define TREO680_STR_BASE       0xa2000000
-
-/* BACKLIGHT */
-#define TREO680_MAX_INTENSITY          254
-#define TREO680_DEFAULT_INTENSITY      160
-#define TREO680_LIMIT_MASK             0x7F
-#define TREO680_PRESCALER              63
-#define TREO680_PERIOD_NS              3500
-
-#endif
index 1384895..f28c171 100644 (file)
 #include <mach/ssp.h>
 #include <mach/mmc.h>
 #include <mach/pxa2xx_spi.h>
-#include <plat/i2c.h>
 #include <mach/pxa27x_keypad.h>
-#include <mach/pxa3xx_nand.h>
 #include <mach/littleton.h>
+#include <plat/i2c.h>
+#include <plat/pxa3xx_nand.h>
 
 #include "generic.h"
 
@@ -413,6 +413,10 @@ static void __init littleton_init(void)
        /* initialize MFP configurations */
        pxa3xx_mfp_config(ARRAY_AND_SIZE(littleton_mfp_cfg));
 
+       pxa_set_ffuart_info(NULL);
+       pxa_set_btuart_info(NULL);
+       pxa_set_stuart_info(NULL);
+
        /*
         * Note: we depend bootloader set the correct
         * value to MSC register for SMC91x.
index d64395f..1373c22 100644 (file)
@@ -455,6 +455,10 @@ static void __init lpd270_init(void)
 {
        pxa2xx_mfp_config(ARRAY_AND_SIZE(lpd270_pin_config));
 
+       pxa_set_ffuart_info(NULL);
+       pxa_set_btuart_info(NULL);
+       pxa_set_stuart_info(NULL);
+
        lpd270_flash_data[0].width = (BOOT_DEF & 1) ? 2 : 4;
        lpd270_flash_data[1].width = 4;
 
index c6a94d3..98ee7e5 100644 (file)
@@ -518,6 +518,10 @@ static void __init lubbock_init(void)
 
        pxa2xx_mfp_config(ARRAY_AND_SIZE(lubbock_pin_config));
 
+       pxa_set_ffuart_info(NULL);
+       pxa_set_btuart_info(NULL);
+       pxa_set_stuart_info(NULL);
+
        clk_add_alias("SA1111_CLK", NULL, "GPIO11_CLK", NULL);
        pxa_set_udc_info(&udc_info);
        set_pxa_fb_info(&sharp_lm8v31);
index 5360c07..8a38d60 100644 (file)
@@ -742,6 +742,10 @@ static void __init magician_init(void)
 
        pxa2xx_mfp_config(ARRAY_AND_SIZE(magician_pin_config));
 
+       pxa_set_ffuart_info(NULL);
+       pxa_set_btuart_info(NULL);
+       pxa_set_stuart_info(NULL);
+
        platform_add_devices(ARRAY_AND_SIZE(devices));
 
        err = gpio_request(GPIO83_MAGICIAN_nIR_EN, "nIR_EN");
index a4eeae3..851ee0f 100644 (file)
@@ -576,6 +576,10 @@ static void __init mainstone_init(void)
 
        pxa2xx_mfp_config(ARRAY_AND_SIZE(mainstone_pin_config));
 
+       pxa_set_ffuart_info(NULL);
+       pxa_set_btuart_info(NULL);
+       pxa_set_stuart_info(NULL);
+
        mst_flash_data[0].width = (BOOT_DEF & 1) ? 2 : 4;
        mst_flash_data[1].width = 4;
 
index 3cab452..2466a44 100644 (file)
@@ -798,6 +798,9 @@ static void __init mioa701_machine_init(void)
        UP2OCR = UP2OCR_HXOE;
 
        pxa2xx_mfp_config(ARRAY_AND_SIZE(mioa701_pin_config));
+       pxa_set_ffuart_info(NULL);
+       pxa_set_btuart_info(NULL);
+       pxa_set_stuart_info(NULL);
        mio_gpio_request(ARRAY_AND_SIZE(global_gpios));
        bootstrap_init();
        set_pxa_fb_info(&mioa701_pxafb_info);
index a65713c..6d45039 100644 (file)
@@ -84,6 +84,9 @@ static struct platform_device *devices[] __initdata = {
 static void __init mp900c_init(void)
 {
        printk(KERN_INFO "MobilePro 900/C machine init\n");
+       pxa_set_ffuart_info(NULL);
+       pxa_set_btuart_info(NULL);
+       pxa_set_stuart_info(NULL);
        platform_add_devices(devices, ARRAY_SIZE(devices));
 }
 
index 1ad029d..5914021 100644 (file)
@@ -530,6 +530,10 @@ static void __init palmld_init(void)
 {
        pxa2xx_mfp_config(ARRAY_AND_SIZE(palmld_pin_config));
 
+       pxa_set_ffuart_info(NULL);
+       pxa_set_btuart_info(NULL);
+       pxa_set_stuart_info(NULL);
+
        palmld_pm_init();
        set_pxa_fb_info(&palmld_lcd_screen);
        pxa_set_mci_info(&palmld_mci_platform_data);
index 2dd7ce2..7f89ca2 100644 (file)
@@ -419,6 +419,10 @@ static void __init palmt5_init(void)
 {
        pxa2xx_mfp_config(ARRAY_AND_SIZE(palmt5_pin_config));
 
+       pxa_set_ffuart_info(NULL);
+       pxa_set_btuart_info(NULL);
+       pxa_set_stuart_info(NULL);
+
        palmt5_pm_init();
        set_pxa_fb_info(&palmt5_lcd_screen);
        pxa_set_mci_info(&palmt5_mci_platform_data);
index 0b92291..3084175 100644 (file)
@@ -416,6 +416,11 @@ static void __init palmtc_init(void)
 {
        pxa2xx_mfp_config(ARRAY_AND_SIZE(palmtc_pin_config));
 
+       pxa_set_ffuart_info(NULL);
+       pxa_set_btuart_info(NULL);
+       pxa_set_stuart_info(NULL);
+       pxa_set_hwuart_info(NULL);
+
        set_pxa_fb_info(&palmtc_lcd_screen);
        pxa_set_mci_info(&palmtc_mci_platform_data);
        pxa_set_udc_info(&palmtc_udc_info);
index 277c406..265d62b 100644 (file)
@@ -373,6 +373,10 @@ static void __init palmte2_init(void)
 {
        pxa2xx_mfp_config(ARRAY_AND_SIZE(palmte2_pin_config));
 
+       pxa_set_ffuart_info(NULL);
+       pxa_set_btuart_info(NULL);
+       pxa_set_stuart_info(NULL);
+
        set_pxa_fb_info(&palmte2_lcd_screen);
        pxa_set_mci_info(&palmte2_mci_platform_data);
        palmte2_udc_init();
similarity index 53%
rename from arch/arm/mach-pxa/treo680.c
rename to arch/arm/mach-pxa/palmtreo.c
index fe08507..606eb7e 100644 (file)
@@ -1,5 +1,9 @@
 /*
- * Hardware definitions for Palm Treo 680
+ * Hardware definitions for Palm Treo smartphones
+ *
+ * currently supported:
+ *     Palm Treo 680 (GSM)
+ *     Palm Centro 685 (GSM)
  *
  * Author:     Tomas Cech <sleep_walker@suse.cz>
  *
@@ -31,7 +35,7 @@
 #include <mach/pxa27x.h>
 #include <mach/pxa27x-udc.h>
 #include <mach/audio.h>
-#include <mach/treo680.h>
+#include <mach/palmtreo.h>
 #include <mach/mmc.h>
 #include <mach/pxafb.h>
 #include <mach/irda.h>
@@ -50,7 +54,7 @@
 /******************************************************************************
  * Pin configuration
  ******************************************************************************/
-static unsigned long treo680_pin_config[] __initdata = {
+static unsigned long treo_pin_config[] __initdata = {
        /* MMC */
        GPIO32_MMC_CLK,
        GPIO92_MMC_DAT_0,
@@ -58,7 +62,6 @@ static unsigned long treo680_pin_config[] __initdata = {
        GPIO110_MMC_DAT_2,
        GPIO111_MMC_DAT_3,
        GPIO112_MMC_CMD,
-       GPIO33_GPIO,                            /* SD read only */
        GPIO113_GPIO,                           /* SD detect */
 
        /* AC97 */
@@ -80,12 +83,10 @@ static unsigned long treo680_pin_config[] __initdata = {
        GPIO1_GPIO | WAKEUP_ON_EDGE_BOTH,       /* usb detect */
 
        /* MATRIX KEYPAD */
-       GPIO100_KP_MKIN_0 | WAKEUP_ON_LEVEL_HIGH,
        GPIO101_KP_MKIN_1,
        GPIO102_KP_MKIN_2,
        GPIO97_KP_MKIN_3,
        GPIO98_KP_MKIN_4,
-       GPIO99_KP_MKIN_5,
        GPIO91_KP_MKIN_6,
        GPIO13_KP_MKIN_7,
        GPIO103_KP_MKOUT_0 | MFP_LPM_DRIVE_HIGH,
@@ -150,19 +151,57 @@ static unsigned long treo680_pin_config[] __initdata = {
        GPIO11_GPIO | WAKEUP_ON_EDGE_BOTH,      /* bluetooth host wake up */
 };
 
+#ifdef CONFIG_MACH_TREO680
+static unsigned long treo680_pin_config[] __initdata = {
+       GPIO33_GPIO,    /* SD read only */
+
+       /* MATRIX KEYPAD - different wake up source */
+       GPIO100_KP_MKIN_0 | WAKEUP_ON_LEVEL_HIGH,
+       GPIO99_KP_MKIN_5,
+};
+#endif /* CONFIG_MACH_TREO680 */
+
+#ifdef CONFIG_MACH_CENTRO
+static unsigned long centro685_pin_config[] __initdata = {
+       /* Bluetooth attached to BT UART*/
+       MFP_CFG_OUT(GPIO80, AF0, DRIVE_LOW),    /* power: LOW = off */
+       GPIO42_BTUART_RXD,
+       GPIO43_BTUART_TXD,
+       GPIO44_BTUART_CTS,
+       GPIO45_BTUART_RTS,
+
+       /* MATRIX KEYPAD - different wake up source */
+       GPIO100_KP_MKIN_0,
+       GPIO99_KP_MKIN_5 | WAKEUP_ON_LEVEL_HIGH,
+};
+#endif /* CONFIG_MACH_CENTRO */
+
 /******************************************************************************
  * SD/MMC card controller
  ******************************************************************************/
+#ifdef CONFIG_MACH_TREO680
 static struct pxamci_platform_data treo680_mci_platform_data = {
        .ocr_mask               = MMC_VDD_32_33 | MMC_VDD_33_34,
-       .gpio_card_detect       = GPIO_NR_TREO680_SD_DETECT_N,
+       .gpio_card_detect       = GPIO_NR_TREO_SD_DETECT_N,
        .gpio_card_ro           = GPIO_NR_TREO680_SD_READONLY,
        .gpio_power             = GPIO_NR_TREO680_SD_POWER,
 };
+#endif /* CONFIG_MACH_TREO680 */
+
+#ifdef CONFIG_MACH_CENTRO
+static struct pxamci_platform_data centro_mci_platform_data = {
+       .ocr_mask               = MMC_VDD_32_33 | MMC_VDD_33_34,
+       .gpio_card_detect       = GPIO_NR_TREO_SD_DETECT_N,
+       .gpio_card_ro           = -1,
+       .gpio_power             = GPIO_NR_CENTRO_SD_POWER,
+       .gpio_power_invert      = 1,
+};
+#endif /* CONFIG_MACH_CENTRO */
 
 /******************************************************************************
  * GPIO keyboard
  ******************************************************************************/
+#ifdef CONFIG_MACH_TREO680
 static unsigned int treo680_matrix_keys[] = {
        KEY(0, 0, KEY_F8),              /* Red/Off/Power */
        KEY(0, 1, KEY_LEFT),
@@ -232,92 +271,167 @@ static struct pxa27x_keypad_platform_data treo680_keypad_platform_data = {
 
        .debounce_interval      = 30,
 };
+#endif /* CONFIG_MACH_TREO680 */
+
+#ifdef CONFIG_MACH_CENTRO
+static unsigned int centro_matrix_keys[] = {
+       KEY(0, 0, KEY_F9),              /* Home */
+       KEY(0, 1, KEY_LEFT),
+       KEY(0, 2, KEY_LEFTCTRL),        /* Alternate */
+       KEY(0, 3, KEY_L),
+       KEY(0, 4, KEY_A),
+       KEY(0, 5, KEY_Q),
+       KEY(0, 6, KEY_P),
+
+       KEY(1, 0, KEY_RIGHTCTRL),       /* Menu */
+       KEY(1, 1, KEY_RIGHT),
+       KEY(1, 2, KEY_LEFTSHIFT),       /* Left shift */
+       KEY(1, 3, KEY_Z),
+       KEY(1, 4, KEY_S),
+       KEY(1, 5, KEY_W),
+
+       KEY(2, 0, KEY_F1),              /* Phone */
+       KEY(2, 1, KEY_UP),
+       KEY(2, 2, KEY_0),
+       KEY(2, 3, KEY_X),
+       KEY(2, 4, KEY_D),
+       KEY(2, 5, KEY_E),
+
+       KEY(3, 0, KEY_F10),             /* Calendar */
+       KEY(3, 1, KEY_DOWN),
+       KEY(3, 2, KEY_SPACE),
+       KEY(3, 3, KEY_C),
+       KEY(3, 4, KEY_F),
+       KEY(3, 5, KEY_R),
+
+       KEY(4, 0, KEY_F12),             /* Mail */
+       KEY(4, 1, KEY_KPENTER),
+       KEY(4, 2, KEY_RIGHTALT),        /* Alt */
+       KEY(4, 3, KEY_V),
+       KEY(4, 4, KEY_G),
+       KEY(4, 5, KEY_T),
+
+       KEY(5, 0, KEY_F8),              /* Red/Off/Power */
+       KEY(5, 1, KEY_PAGEUP),          /* Side up */
+       KEY(5, 2, KEY_DOT),
+       KEY(5, 3, KEY_B),
+       KEY(5, 4, KEY_H),
+       KEY(5, 5, KEY_Y),
+
+       KEY(6, 0, KEY_TAB),             /* Side Activate */
+       KEY(6, 1, KEY_PAGEDOWN),        /* Side down */
+       KEY(6, 2, KEY_ENTER),
+       KEY(6, 3, KEY_N),
+       KEY(6, 4, KEY_J),
+       KEY(6, 5, KEY_U),
+
+       KEY(7, 0, KEY_F6),              /* Green/Call */
+       KEY(7, 1, KEY_O),
+       KEY(7, 2, KEY_BACKSPACE),
+       KEY(7, 3, KEY_M),
+       KEY(7, 4, KEY_K),
+       KEY(7, 5, KEY_I),
+};
+
+static struct pxa27x_keypad_platform_data centro_keypad_platform_data = {
+       .matrix_key_rows        = 8,
+       .matrix_key_cols        = 7,
+       .matrix_key_map         = centro_matrix_keys,
+       .matrix_key_map_size    = ARRAY_SIZE(centro_matrix_keys),
+       .direct_key_map         = { KEY_CONNECT },
+       .direct_key_num         = 1,
+
+       .debounce_interval      = 30,
+};
+#endif /* CONFIG_MACH_CENTRO */
 
 /******************************************************************************
  * aSoC audio
  ******************************************************************************/
 
-static pxa2xx_audio_ops_t treo680_ac97_pdata = {
+static pxa2xx_audio_ops_t treo_ac97_pdata = {
        .reset_gpio     = 95,
 };
 
 /******************************************************************************
  * Backlight
  ******************************************************************************/
-static int treo680_backlight_init(struct device *dev)
+static int treo_backlight_init(struct device *dev)
 {
        int ret;
 
-       ret = gpio_request(GPIO_NR_TREO680_BL_POWER, "BL POWER");
+       ret = gpio_request(GPIO_NR_TREO_BL_POWER, "BL POWER");
        if (ret)
                goto err;
-       ret = gpio_direction_output(GPIO_NR_TREO680_BL_POWER, 0);
+       ret = gpio_direction_output(GPIO_NR_TREO_BL_POWER, 0);
        if (ret)
                goto err2;
 
        return 0;
 
 err2:
-       gpio_free(GPIO_NR_TREO680_BL_POWER);
+       gpio_free(GPIO_NR_TREO_BL_POWER);
 err:
        return ret;
 }
 
-static int treo680_backlight_notify(int brightness)
+static int treo_backlight_notify(int brightness)
 {
-       gpio_set_value(GPIO_NR_TREO680_BL_POWER, brightness);
-       return TREO680_MAX_INTENSITY - brightness;
+       gpio_set_value(GPIO_NR_TREO_BL_POWER, brightness);
+       return TREO_MAX_INTENSITY - brightness;
 };
 
-static void treo680_backlight_exit(struct device *dev)
+static void treo_backlight_exit(struct device *dev)
 {
-       gpio_free(GPIO_NR_TREO680_BL_POWER);
+       gpio_free(GPIO_NR_TREO_BL_POWER);
 }
 
-static struct platform_pwm_backlight_data treo680_backlight_data = {
+static struct platform_pwm_backlight_data treo_backlight_data = {
        .pwm_id         = 0,
-       .max_brightness = TREO680_MAX_INTENSITY,
-       .dft_brightness = TREO680_DEFAULT_INTENSITY,
-       .pwm_period_ns  = TREO680_PERIOD_NS,
-       .init           = treo680_backlight_init,
-       .notify         = treo680_backlight_notify,
-       .exit           = treo680_backlight_exit,
+       .max_brightness = TREO_MAX_INTENSITY,
+       .dft_brightness = TREO_DEFAULT_INTENSITY,
+       .pwm_period_ns  = TREO_PERIOD_NS,
+       .init           = treo_backlight_init,
+       .notify         = treo_backlight_notify,
+       .exit           = treo_backlight_exit,
 };
 
-static struct platform_device treo680_backlight = {
+static struct platform_device treo_backlight = {
        .name   = "pwm-backlight",
        .dev    = {
                .parent         = &pxa27x_device_pwm0.dev,
-               .platform_data  = &treo680_backlight_data,
+               .platform_data  = &treo_backlight_data,
        },
 };
 
 /******************************************************************************
  * IrDA
  ******************************************************************************/
-static struct pxaficp_platform_data treo680_ficp_info = {
-       .gpio_pwdown            = GPIO_NR_TREO680_IR_EN,
+static struct pxaficp_platform_data treo_ficp_info = {
+       .gpio_pwdown            = GPIO_NR_TREO_IR_EN,
        .transceiver_cap        = IR_SIRMODE | IR_OFF,
 };
 
 /******************************************************************************
  * UDC
  ******************************************************************************/
-static struct pxa2xx_udc_mach_info treo680_udc_info __initdata = {
-       .gpio_vbus              = GPIO_NR_TREO680_USB_DETECT,
+static struct pxa2xx_udc_mach_info treo_udc_info __initdata = {
+       .gpio_vbus              = GPIO_NR_TREO_USB_DETECT,
        .gpio_vbus_inverted     = 1,
-       .gpio_pullup            = GPIO_NR_TREO680_USB_PULLUP,
+       .gpio_pullup            = GPIO_NR_TREO_USB_PULLUP,
 };
 
 
 /******************************************************************************
  * USB host
  ******************************************************************************/
+#ifdef CONFIG_MACH_TREO680
 static struct pxaohci_platform_data treo680_ohci_info = {
        .port_mode    = PMM_PERPORT_MODE,
        .flags        = ENABLE_PORT1 | ENABLE_PORT3,
        .power_budget = 0,
 };
+#endif /* CONFIG_MACH_TREO680 */
 
 /******************************************************************************
  * Power supply
@@ -326,41 +440,41 @@ static int power_supply_init(struct device *dev)
 {
        int ret;
 
-       ret = gpio_request(GPIO_NR_TREO680_POWER_DETECT, "CABLE_STATE_AC");
+       ret = gpio_request(GPIO_NR_TREO_POWER_DETECT, "CABLE_STATE_AC");
        if (ret)
                goto err1;
-       ret = gpio_direction_input(GPIO_NR_TREO680_POWER_DETECT);
+       ret = gpio_direction_input(GPIO_NR_TREO_POWER_DETECT);
        if (ret)
                goto err2;
 
        return 0;
 
 err2:
-       gpio_free(GPIO_NR_TREO680_POWER_DETECT);
+       gpio_free(GPIO_NR_TREO_POWER_DETECT);
 err1:
        return ret;
 }
 
-static int treo680_is_ac_online(void)
+static int treo_is_ac_online(void)
 {
-       return gpio_get_value(GPIO_NR_TREO680_POWER_DETECT);
+       return gpio_get_value(GPIO_NR_TREO_POWER_DETECT);
 }
 
 static void power_supply_exit(struct device *dev)
 {
-       gpio_free(GPIO_NR_TREO680_POWER_DETECT);
+       gpio_free(GPIO_NR_TREO_POWER_DETECT);
 }
 
-static char *treo680_supplicants[] = {
+static char *treo_supplicants[] = {
        "main-battery",
 };
 
 static struct pda_power_pdata power_supply_info = {
        .init            = power_supply_init,
-       .is_ac_online    = treo680_is_ac_online,
+       .is_ac_online    = treo_is_ac_online,
        .exit            = power_supply_exit,
-       .supplied_to     = treo680_supplicants,
-       .num_supplicants = ARRAY_SIZE(treo680_supplicants),
+       .supplied_to     = treo_supplicants,
+       .num_supplicants = ARRAY_SIZE(treo_supplicants),
 };
 
 static struct platform_device power_supply = {
@@ -374,7 +488,8 @@ static struct platform_device power_supply = {
 /******************************************************************************
  * Vibra and LEDs
  ******************************************************************************/
-static struct gpio_led gpio_leds[] = {
+#ifdef CONFIG_MACH_TREO680
+static struct gpio_led treo680_gpio_leds[] = {
        {
                .name                   = "treo680:vibra:vibra",
                .default_trigger        = "none",
@@ -383,34 +498,68 @@ static struct gpio_led gpio_leds[] = {
        {
                .name                   = "treo680:green:led",
                .default_trigger        = "mmc0",
-               .gpio                   = GPIO_NR_TREO680_GREEN_LED,
+               .gpio                   = GPIO_NR_TREO_GREEN_LED,
        },
        {
-               .name                   = "treo680:keybbl:keybbl",
+               .name                   = "treo680:white:keybbl",
                .default_trigger        = "none",
                .gpio                   = GPIO_NR_TREO680_KEYB_BL,
        },
 };
 
-static struct gpio_led_platform_data gpio_led_info = {
-       .leds           = gpio_leds,
-       .num_leds       = ARRAY_SIZE(gpio_leds),
+static struct gpio_led_platform_data treo680_gpio_led_info = {
+       .leds           = treo680_gpio_leds,
+       .num_leds       = ARRAY_SIZE(treo680_gpio_leds),
 };
 
 static struct platform_device treo680_leds = {
        .name   = "leds-gpio",
        .id     = -1,
        .dev    = {
-               .platform_data  = &gpio_led_info,
+               .platform_data  = &treo680_gpio_led_info,
        }
 };
+#endif /* CONFIG_MACH_TREO680 */
 
+#ifdef CONFIG_MACH_CENTRO
+static struct gpio_led centro_gpio_leds[] = {
+       {
+               .name                   = "centro:vibra:vibra",
+               .default_trigger        = "none",
+               .gpio                   = GPIO_NR_CENTRO_VIBRATE_EN,
+       },
+       {
+               .name                   = "centro:green:led",
+               .default_trigger        = "mmc0",
+               .gpio                   = GPIO_NR_TREO_GREEN_LED,
+       },
+       {
+               .name                   = "centro:white:keybbl",
+               .default_trigger        = "none",
+               .active_low             = 1,
+               .gpio                   = GPIO_NR_CENTRO_KEYB_BL,
+       },
+};
+
+static struct gpio_led_platform_data centro_gpio_led_info = {
+       .leds           = centro_gpio_leds,
+       .num_leds       = ARRAY_SIZE(centro_gpio_leds),
+};
+
+static struct platform_device centro_leds = {
+       .name   = "leds-gpio",
+       .id     = -1,
+       .dev    = {
+               .platform_data  = &centro_gpio_led_info,
+       }
+};
+#endif /* CONFIG_MACH_CENTRO */
 
 /******************************************************************************
  * Framebuffer
  ******************************************************************************/
 /* TODO: add support for 324x324 */
-static struct pxafb_mode_info treo680_lcd_modes[] = {
+static struct pxafb_mode_info treo_lcd_modes[] = {
 {
        .pixclock               = 86538,
        .xres                   = 320,
@@ -427,21 +576,21 @@ static struct pxafb_mode_info treo680_lcd_modes[] = {
 },
 };
 
-static void treo680_lcd_power(int on, struct fb_var_screeninfo *info)
+static void treo_lcd_power(int on, struct fb_var_screeninfo *info)
 {
-       gpio_set_value(GPIO_NR_TREO680_BL_POWER, on);
+       gpio_set_value(GPIO_NR_TREO_BL_POWER, on);
 }
 
-static struct pxafb_mach_info treo680_lcd_screen = {
-       .modes          = treo680_lcd_modes,
-       .num_modes      = ARRAY_SIZE(treo680_lcd_modes),
+static struct pxafb_mach_info treo_lcd_screen = {
+       .modes          = treo_lcd_modes,
+       .num_modes      = ARRAY_SIZE(treo_lcd_modes),
        .lcd_conn       = LCD_COLOR_TFT_16BPP | LCD_PCLK_EDGE_FALL,
 };
 
 /******************************************************************************
  * Power management - standby
  ******************************************************************************/
-static void __init treo680_pm_init(void)
+static void __init treo_pm_init(void)
 {
        static u32 resume[] = {
                0xe3a00101,     /* mov  r0,     #0x40000000 */
@@ -450,70 +599,118 @@ static void __init treo680_pm_init(void)
        };
 
        /* this is where the bootloader jumps */
-       memcpy(phys_to_virt(TREO680_STR_BASE), resume, sizeof(resume));
+       memcpy(phys_to_virt(TREO_STR_BASE), resume, sizeof(resume));
 }
 
 /******************************************************************************
  * Machine init
  ******************************************************************************/
-static struct platform_device *devices[] __initdata = {
-       &treo680_backlight,
-       &treo680_leds,
+static struct platform_device *treo_devices[] __initdata = {
+       &treo_backlight,
        &power_supply,
 };
 
+#ifdef CONFIG_MACH_TREO680
+static struct platform_device *treo680_devices[] __initdata = {
+       &treo680_leds,
+};
+#endif /* CONFIG_MACH_TREO680 */
+
+#ifdef CONFIG_MACH_CENTRO
+static struct platform_device *centro_devices[] __initdata = {
+       &centro_leds,
+};
+#endif /* CONFIG_MACH_CENTRO */
+
 /* setup udc GPIOs initial state */
-static void __init treo680_udc_init(void)
+static void __init treo_udc_init(void)
 {
-       if (!gpio_request(GPIO_NR_TREO680_USB_PULLUP, "UDC Vbus")) {
-               gpio_direction_output(GPIO_NR_TREO680_USB_PULLUP, 1);
-               gpio_free(GPIO_NR_TREO680_USB_PULLUP);
+       if (!gpio_request(GPIO_NR_TREO_USB_PULLUP, "UDC Vbus")) {
+               gpio_direction_output(GPIO_NR_TREO_USB_PULLUP, 1);
+               gpio_free(GPIO_NR_TREO_USB_PULLUP);
        }
 }
 
-static void __init treo680_lcd_power_init(void)
+static void __init treo_lcd_power_init(void)
 {
        int ret;
 
-       ret = gpio_request(GPIO_NR_TREO680_LCD_POWER, "LCD POWER");
+       ret = gpio_request(GPIO_NR_TREO_LCD_POWER, "LCD POWER");
        if (ret) {
                pr_err("Treo680: LCD power GPIO request failed!\n");
                return;
        }
 
-       ret = gpio_direction_output(GPIO_NR_TREO680_LCD_POWER, 0);
+       ret = gpio_direction_output(GPIO_NR_TREO_LCD_POWER, 0);
        if (ret) {
                pr_err("Treo680: setting LCD power GPIO direction failed!\n");
-               gpio_free(GPIO_NR_TREO680_LCD_POWER);
+               gpio_free(GPIO_NR_TREO_LCD_POWER);
                return;
        }
 
-       treo680_lcd_screen.pxafb_lcd_power = treo680_lcd_power;
+       treo_lcd_screen.pxafb_lcd_power = treo_lcd_power;
 }
 
+static void __init treo_init(void)
+{
+       pxa_set_ffuart_info(NULL);
+       pxa_set_btuart_info(NULL);
+       pxa_set_stuart_info(NULL);
+
+       treo_pm_init();
+       pxa2xx_mfp_config(ARRAY_AND_SIZE(treo_pin_config));
+       treo_lcd_power_init();
+       set_pxa_fb_info(&treo_lcd_screen);
+       treo_udc_init();
+       pxa_set_udc_info(&treo_udc_info);
+       pxa_set_ac97_info(&treo_ac97_pdata);
+       pxa_set_ficp_info(&treo_ficp_info);
+
+       platform_add_devices(ARRAY_AND_SIZE(treo_devices));
+}
+
+#ifdef CONFIG_MACH_TREO680
 static void __init treo680_init(void)
 {
-       treo680_pm_init();
+       treo_init();
        pxa2xx_mfp_config(ARRAY_AND_SIZE(treo680_pin_config));
-       pxa_set_keypad_info(&treo680_keypad_platform_data);
-       treo680_lcd_power_init();
-       set_pxa_fb_info(&treo680_lcd_screen);
        pxa_set_mci_info(&treo680_mci_platform_data);
-       treo680_udc_init();
-       pxa_set_udc_info(&treo680_udc_info);
-       pxa_set_ac97_info(&treo680_ac97_pdata);
-       pxa_set_ficp_info(&treo680_ficp_info);
+       pxa_set_keypad_info(&treo680_keypad_platform_data);
        pxa_set_ohci_info(&treo680_ohci_info);
 
-       platform_add_devices(devices, ARRAY_SIZE(devices));
+       platform_add_devices(ARRAY_AND_SIZE(treo680_devices));
 }
 
 MACHINE_START(TREO680, "Palm Treo 680")
-       .phys_io        = TREO680_PHYS_IO_START,
-       .io_pg_offst    = io_p2v(0x40000000),
-       .boot_params    = 0xa0000100,
-       .map_io         = pxa_map_io,
-       .init_irq       = pxa27x_init_irq,
-       .timer          = &pxa_timer,
-       .init_machine   = treo680_init,
+       .phys_io        = TREO_PHYS_IO_START,
+       .io_pg_offst    = io_p2v(0x40000000),
+       .boot_params    = 0xa0000100,
+       .map_io         = pxa_map_io,
+       .init_irq       = pxa27x_init_irq,
+       .timer          = &pxa_timer,
+       .init_machine   = treo680_init,
+MACHINE_END
+#endif /* CONFIG_MACH_TREO680 */
+
+#ifdef CONFIG_MACH_CENTRO
+static void __init centro_init(void)
+{
+       treo_init();
+       pxa2xx_mfp_config(ARRAY_AND_SIZE(centro685_pin_config));
+       pxa_set_mci_info(&centro_mci_platform_data);
+
+       pxa_set_keypad_info(&centro_keypad_platform_data);
+
+       platform_add_devices(ARRAY_AND_SIZE(centro_devices));
+}
+
+MACHINE_START(CENTRO, "Palm Centro 685")
+       .phys_io        = TREO_PHYS_IO_START,
+       .io_pg_offst    = io_p2v(0x40000000),
+       .boot_params    = 0xa0000100,
+       .map_io         = pxa_map_io,
+       .init_irq       = pxa27x_init_irq,
+       .timer          = &pxa_timer,
+       .init_machine   = centro_init,
 MACHINE_END
+#endif /* CONFIG_MACH_CENTRO */
index 76a2b37..7bf18c2 100644 (file)
@@ -570,6 +570,10 @@ static void __init palmtx_init(void)
 {
        pxa2xx_mfp_config(ARRAY_AND_SIZE(palmtx_pin_config));
 
+       pxa_set_ffuart_info(NULL);
+       pxa_set_btuart_info(NULL);
+       pxa_set_stuart_info(NULL);
+
        palmtx_pm_init();
        set_pxa_fb_info(&palmtx_lcd_screen);
        pxa_set_mci_info(&palmtx_mci_platform_data);
index c2bf493..d787ac7 100644 (file)
@@ -491,6 +491,10 @@ static void __init palmz72_init(void)
 {
        pxa2xx_mfp_config(ARRAY_AND_SIZE(palmz72_pin_config));
 
+       pxa_set_ffuart_info(NULL);
+       pxa_set_btuart_info(NULL);
+       pxa_set_stuart_info(NULL);
+
        set_pxa_fb_info(&palmz72_lcd_screen);
        pxa_set_mci_info(&palmz72_mci_platform_data);
        palmz72_udc_init();
index 6abfa29..2190af0 100644 (file)
@@ -227,6 +227,10 @@ static void __init pcm027_init(void)
 
        pxa2xx_mfp_config(pcm027_pin_config, ARRAY_SIZE(pcm027_pin_config));
 
+       pxa_set_ffuart_info(NULL);
+       pxa_set_btuart_info(NULL);
+       pxa_set_stuart_info(NULL);
+
        platform_add_devices(devices, ARRAY_SIZE(devices));
 
        /* at last call the baseboard to initialize itself */
index bbda570..d5255ae 100644 (file)
@@ -359,19 +359,12 @@ static unsigned long pcm990_camera_pin_config[] = {
        GPIO44_CIF_LV,
 };
 
-static int pcm990_pxacamera_init(struct device *dev)
-{
-       pxa2xx_mfp_config(ARRAY_AND_SIZE(pcm990_camera_pin_config));
-       return 0;
-}
-
 /*
  * CICR4: PCLK_EN:     Pixel clock is supplied by the sensor
  *     MCLK_EN:        Master clock is generated by PXA
  *     PCP:            Data sampled on the falling edge of pixel clock
  */
 struct pxacamera_platform_data pcm990_pxacamera_platform_data = {
-       .init   = pcm990_pxacamera_init,
        .flags  = PXA_CAMERA_MASTER | PXA_CAMERA_DATAWIDTH_8 | PXA_CAMERA_DATAWIDTH_10 |
                PXA_CAMERA_PCLK_EN | PXA_CAMERA_MCLK_EN/* | PXA_CAMERA_PCP*/,
        .mclk_10khz = 1000,
@@ -532,6 +525,7 @@ void __init pcm990_baseboard_init(void)
        pxa_set_ac97_info(NULL);
 
 #if defined(CONFIG_VIDEO_PXA27x) || defined(CONFIG_VIDEO_PXA27x_MODULE)
+       pxa2xx_mfp_config(ARRAY_AND_SIZE(pcm990_camera_pin_config));
        pxa_set_camera_info(&pcm990_pxacamera_platform_data);
 
        i2c_register_board_info(0, ARRAY_AND_SIZE(pcm990_i2c_devices));
index a186994..e5eeb3a 100644 (file)
@@ -449,6 +449,10 @@ static void __init poodle_init(void)
 
        pxa2xx_mfp_config(ARRAY_AND_SIZE(poodle_pin_config));
 
+       pxa_set_ffuart_info(NULL);
+       pxa_set_btuart_info(NULL);
+       pxa_set_stuart_info(NULL);
+
        platform_scoop_config = &poodle_pcmcia_config;
 
        ret = platform_add_devices(devices, ARRAY_SIZE(devices));
index 77c2693..2c1b0b7 100644 (file)
@@ -322,9 +322,6 @@ void __init pxa26x_init_irq(void)
 
 static struct platform_device *pxa25x_devices[] __initdata = {
        &pxa25x_device_udc,
-       &pxa_device_ffuart,
-       &pxa_device_btuart,
-       &pxa_device_stuart,
        &pxa_device_i2s,
        &sa1100_device_rtc,
        &pxa25x_device_ssp,
@@ -372,10 +369,8 @@ static int __init pxa25x_init(void)
        }
 
        /* Only add HWUART for PXA255/26x; PXA210/250 do not have it. */
-       if (cpu_is_pxa255()) {
+       if (cpu_is_pxa255())
                clks_register(&pxa25x_hwuart_clkreg, 1);
-               ret = platform_device_register(&pxa_device_hwuart);
-       }
 
        return ret;
 }
index ec68cc1..6a0b731 100644 (file)
@@ -364,9 +364,6 @@ void __init pxa27x_set_i2c_power_info(struct i2c_pxa_platform_data *info)
 
 static struct platform_device *devices[] __initdata = {
        &pxa27x_device_udc,
-       &pxa_device_ffuart,
-       &pxa_device_btuart,
-       &pxa_device_stuart,
        &pxa_device_i2s,
        &sa1100_device_rtc,
        &pxa_device_rtc,
index 09b7b1a..fcb0721 100644 (file)
@@ -30,6 +30,7 @@
 #include <mach/pm.h>
 #include <mach/dma.h>
 #include <mach/ssp.h>
+#include <mach/regs-intc.h>
 #include <plat/i2c.h>
 
 #include "generic.h"
@@ -45,6 +46,9 @@
 #define ACCR_D0CS      (1 << 26)
 #define ACCR_PCCE      (1 << 11)
 
+#define PECR_IE(n)     ((1 << ((n) * 2)) << 28)
+#define PECR_IS(n)     ((1 << ((n) * 2)) << 29)
+
 /* crystal frequency to static memory controller multiplier (SMCFS) */
 static unsigned char smcfs_mult[8] = { 6, 0, 8, 0, 0, 16, };
 
@@ -237,6 +241,7 @@ static DEFINE_PXA3_CKEN(pxa3xx_stuart, STUART, 14857000, 1);
 static DEFINE_PXA3_CKEN(pxa3xx_i2c, I2C, 32842000, 0);
 static DEFINE_PXA3_CKEN(pxa3xx_udc, UDC, 48000000, 5);
 static DEFINE_PXA3_CKEN(pxa3xx_usbh, USBH, 48000000, 0);
+static DEFINE_PXA3_CKEN(pxa3xx_u2d, USB2, 48000000, 0);
 static DEFINE_PXA3_CKEN(pxa3xx_keypad, KEYPAD, 32768, 0);
 static DEFINE_PXA3_CKEN(pxa3xx_ssp1, SSP1, 13000000, 0);
 static DEFINE_PXA3_CKEN(pxa3xx_ssp2, SSP2, 13000000, 0);
@@ -261,6 +266,7 @@ static struct clk_lookup pxa3xx_clkregs[] = {
        INIT_CLKREG(&clk_pxa3xx_i2c, "pxa2xx-i2c.0", NULL),
        INIT_CLKREG(&clk_pxa3xx_udc, "pxa27x-udc", NULL),
        INIT_CLKREG(&clk_pxa3xx_usbh, "pxa27x-ohci", NULL),
+       INIT_CLKREG(&clk_pxa3xx_u2d, NULL, "U2DCLK"),
        INIT_CLKREG(&clk_pxa3xx_keypad, "pxa27x-keypad", NULL),
        INIT_CLKREG(&clk_pxa3xx_ssp1, "pxa27x-ssp.0", NULL),
        INIT_CLKREG(&clk_pxa3xx_ssp2, "pxa27x-ssp.1", NULL),
@@ -530,6 +536,43 @@ static inline void pxa3xx_init_pm(void) {}
 #define pxa3xx_set_wake        NULL
 #endif
 
+static void pxa_ack_ext_wakeup(unsigned int irq)
+{
+       PECR |= PECR_IS(irq - IRQ_WAKEUP0);
+}
+
+static void pxa_mask_ext_wakeup(unsigned int irq)
+{
+       ICMR2 &= ~(1 << ((irq - PXA_IRQ(0)) & 0x1f));
+       PECR &= ~PECR_IE(irq - IRQ_WAKEUP0);
+}
+
+static void pxa_unmask_ext_wakeup(unsigned int irq)
+{
+       ICMR2 |= 1 << ((irq - PXA_IRQ(0)) & 0x1f);
+       PECR |= PECR_IE(irq - IRQ_WAKEUP0);
+}
+
+static struct irq_chip pxa_ext_wakeup_chip = {
+       .name           = "WAKEUP",
+       .ack            = pxa_ack_ext_wakeup,
+       .mask           = pxa_mask_ext_wakeup,
+       .unmask         = pxa_unmask_ext_wakeup,
+};
+
+static void __init pxa_init_ext_wakeup_irq(set_wake_t fn)
+{
+       int irq;
+
+       for (irq = IRQ_WAKEUP0; irq <= IRQ_WAKEUP1; irq++) {
+               set_irq_chip(irq, &pxa_ext_wakeup_chip);
+               set_irq_handler(irq, handle_edge_irq);
+               set_irq_flags(irq, IRQF_VALID);
+       }
+
+       pxa_ext_wakeup_chip.set_wake = fn;
+}
+
 void __init pxa3xx_init_irq(void)
 {
        /* enable CP6 access */
@@ -539,6 +582,7 @@ void __init pxa3xx_init_irq(void)
        __asm__ __volatile__("mcr p15, 0, %0, c15, c1, 0\n": :"r"(value));
 
        pxa_init_irq(56, pxa3xx_set_wake);
+       pxa_init_ext_wakeup_irq(pxa3xx_set_wake);
        pxa_init_gpio(IRQ_GPIO_2_x, 2, 127, NULL);
 }
 
@@ -553,9 +597,6 @@ void __init pxa3xx_set_i2c_power_info(struct i2c_pxa_platform_data *info)
 
 static struct platform_device *devices[] __initdata = {
        &pxa27x_device_udc,
-       &pxa_device_ffuart,
-       &pxa_device_btuart,
-       &pxa_device_stuart,
        &pxa_device_i2s,
        &sa1100_device_rtc,
        &pxa_device_rtc,
index 8241a63..115b6f2 100644 (file)
 #include <linux/i2c.h>
 #include <linux/smc91x.h>
 #include <linux/mfd/da903x.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/onenand.h>
 
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
+#include <asm/mach/flash.h>
 
 #include <mach/pxa930.h>
 #include <plat/i2c.h>
@@ -33,7 +37,7 @@
 #include "devices.h"
 #include "generic.h"
 
-#define GPIO_LCD_RESET (16)
+#define GPIO_LCD_RESET         (16)
 
 /* SAAR MFP configurations */
 static mfp_cfg_t saar_mfp_cfg[] __initdata = {
@@ -56,6 +60,31 @@ static mfp_cfg_t saar_mfp_cfg[] __initdata = {
        /* Ethernet */
        DF_nCS1_nCS3,
        GPIO97_GPIO,
+
+       /* DFI */
+       DF_INT_RnB_ND_INT_RnB,
+       DF_nRE_nOE_ND_nRE,
+       DF_nWE_ND_nWE,
+       DF_CLE_nOE_ND_CLE,
+       DF_nADV1_ALE_ND_ALE,
+       DF_nADV2_ALE_nCS3,
+       DF_nCS0_ND_nCS0,
+       DF_IO0_ND_IO0,
+       DF_IO1_ND_IO1,
+       DF_IO2_ND_IO2,
+       DF_IO3_ND_IO3,
+       DF_IO4_ND_IO4,
+       DF_IO5_ND_IO5,
+       DF_IO6_ND_IO6,
+       DF_IO7_ND_IO7,
+       DF_IO8_ND_IO8,
+       DF_IO9_ND_IO9,
+       DF_IO10_ND_IO10,
+       DF_IO11_ND_IO11,
+       DF_IO12_ND_IO12,
+       DF_IO13_ND_IO13,
+       DF_IO14_ND_IO14,
+       DF_IO15_ND_IO15,
 };
 
 #define SAAR_ETH_PHYS  (0x14000000)
@@ -451,10 +480,15 @@ static inline void saar_init_lcd(void) {}
 #endif
 
 #if defined(CONFIG_I2C_PXA) || defined(CONFIG_I2C_PXA_MODULE)
+static struct da9034_backlight_pdata saar_da9034_backlight = {
+       .output_current = 4,    /* 4mA */
+};
+
 static struct da903x_subdev_info saar_da9034_subdevs[] = {
        [0] = {
                .name           = "da903x-backlight",
                .id             = DA9034_ID_WLED,
+               .platform_data  = &saar_da9034_backlight,
        },
 };
 
@@ -480,12 +514,81 @@ static void __init saar_init_i2c(void)
 #else
 static inline void saar_init_i2c(void) {}
 #endif
+
+#if defined(CONFIG_MTD_ONENAND) || defined(CONFIG_MTD_ONENAND_MODULE)
+static struct mtd_partition saar_onenand_partitions[] = {
+       {
+               .name           = "bootloader",
+               .offset         = 0,
+               .size           = SZ_1M,
+               .mask_flags     = MTD_WRITEABLE,
+       }, {
+               .name           = "reserved",
+               .offset         = MTDPART_OFS_APPEND,
+               .size           = SZ_128K,
+               .mask_flags     = MTD_WRITEABLE,
+       }, {
+               .name           = "reserved",
+               .offset         = MTDPART_OFS_APPEND,
+               .size           = SZ_8M,
+               .mask_flags     = MTD_WRITEABLE,
+       }, {
+               .name           = "kernel",
+               .offset         = MTDPART_OFS_APPEND,
+               .size           = (SZ_2M + SZ_1M),
+               .mask_flags     = 0,
+       }, {
+               .name           = "filesystem",
+               .offset         = MTDPART_OFS_APPEND,
+               .size           = SZ_48M,
+               .mask_flags     = 0,
+       }
+};
+
+static struct onenand_platform_data saar_onenand_info = {
+       .parts          = saar_onenand_partitions,
+       .nr_parts       = ARRAY_SIZE(saar_onenand_partitions),
+};
+
+#define SMC_CS0_PHYS_BASE      (0x10000000)
+
+static struct resource saar_resource_onenand[] = {
+       [0] = {
+               .start  = SMC_CS0_PHYS_BASE,
+               .end    = SMC_CS0_PHYS_BASE + SZ_1M,
+               .flags  = IORESOURCE_MEM,
+       },
+};
+
+static struct platform_device saar_device_onenand = {
+       .name           = "onenand-flash",
+       .id             = -1,
+       .dev            = {
+               .platform_data  = &saar_onenand_info,
+       },
+       .resource       = saar_resource_onenand,
+       .num_resources  = ARRAY_SIZE(saar_resource_onenand),
+};
+
+static void __init saar_init_onenand(void)
+{
+       platform_device_register(&saar_device_onenand);
+}
+#else
+static void __init saar_init_onenand(void) {}
+#endif
+
 static void __init saar_init(void)
 {
        /* initialize MFP configurations */
        pxa3xx_mfp_config(ARRAY_AND_SIZE(saar_mfp_cfg));
 
+       pxa_set_ffuart_info(NULL);
+       pxa_set_btuart_info(NULL);
+       pxa_set_stuart_info(NULL);
+
        platform_device_register(&smc91x_device);
+       saar_init_onenand();
 
        saar_init_i2c();
        saar_init_lcd();
index 55259f4..1439785 100644 (file)
@@ -42,8 +42,8 @@ void corgi_lcdtg_hw_init(int mode);
 #define MAX1111_BATT_TEMP   2u
 #define MAX1111_ACIN_VOLT   6u
 
-extern struct battery_thresh spitz_battery_levels_acin[];
-extern struct battery_thresh spitz_battery_levels_noac[];
+extern struct battery_thresh sharpsl_battery_levels_acin[];
+extern struct battery_thresh sharpsl_battery_levels_noac[];
 int sharpsl_pm_pxa_read_max1111(int channel);
 
 
index 629e05d..67229a1 100644 (file)
@@ -78,7 +78,7 @@ DEFINE_LED_TRIGGER(sharpsl_charge_led_trigger);
 
 
 
-struct battery_thresh spitz_battery_levels_acin[] = {
+struct battery_thresh sharpsl_battery_levels_acin[] = {
        { 213, 100},
        { 212,  98},
        { 211,  95},
@@ -121,7 +121,7 @@ struct battery_thresh spitz_battery_levels_acin[] = {
        {   0,   0},
 };
 
-struct battery_thresh  spitz_battery_levels_noac[] = {
+struct battery_thresh sharpsl_battery_levels_noac[] = {
        { 213, 100},
        { 212,  98},
        { 211,  95},
@@ -165,19 +165,20 @@ struct battery_thresh  spitz_battery_levels_noac[] = {
 };
 
 /* MAX1111 Commands */
-#define MAXCTRL_PD0      1u << 0
-#define MAXCTRL_PD1      1u << 1
-#define MAXCTRL_SGL      1u << 2
-#define MAXCTRL_UNI      1u << 3
+#define MAXCTRL_PD0      (1u << 0)
+#define MAXCTRL_PD1      (1u << 1)
+#define MAXCTRL_SGL      (1u << 2)
+#define MAXCTRL_UNI      (1u << 3)
 #define MAXCTRL_SEL_SH   4
-#define MAXCTRL_STR      1u << 7
+#define MAXCTRL_STR      (1u << 7)
 
 /*
  * Read MAX1111 ADC
  */
 int sharpsl_pm_pxa_read_max1111(int channel)
 {
-       if (machine_is_tosa()) // Ugly, better move this function into another module
+       /* Ugly, better move this function into another module */
+       if (machine_is_tosa())
            return 0;
 
 #ifdef CONFIG_CORGI_SSP_DEPRECATED
@@ -238,7 +239,7 @@ EXPORT_SYMBOL(sharpsl_battery_kick);
 
 static void sharpsl_battery_thread(struct work_struct *private_)
 {
-       int voltage, percent, apm_status, i = 0;
+       int voltage, percent, apm_status, i;
 
        if (!sharpsl_pm.machinfo)
                return;
@@ -250,15 +251,14 @@ static void sharpsl_battery_thread(struct work_struct *private_)
                        && time_after(jiffies, sharpsl_pm.charge_start_time +  SHARPSL_CHARGE_ON_TIME_INTERVAL))
                schedule_delayed_work(&toggle_charger, 0);
 
-       while(1) {
+       for (i = 0; i < 5; i++) {
                voltage = sharpsl_pm.machinfo->read_devdata(SHARPSL_BATT_VOLT);
-
-               if (voltage > 0) break;
-               if (i++ > 5) {
-                       voltage = sharpsl_pm.machinfo->bat_levels_noac[0].voltage;
-                       dev_warn(sharpsl_pm.dev, "Warning: Cannot read main battery!\n");
+               if (voltage > 0)
                        break;
-               }
+       }
+       if (voltage <= 0) {
+               voltage = sharpsl_pm.machinfo->bat_levels_noac[0].voltage;
+               dev_warn(sharpsl_pm.dev, "Warning: Cannot read main battery!\n");
        }
 
        voltage = sharpsl_average_value(voltage);
@@ -266,8 +266,10 @@ static void sharpsl_battery_thread(struct work_struct *private_)
        percent = get_percentage(voltage);
 
        /* At low battery voltages, the voltage has a tendency to start
-           creeping back up so we try to avoid this here */
-       if ((sharpsl_pm.battstat.ac_status == APM_AC_ONLINE) || (apm_status == APM_BATTERY_STATUS_HIGH) ||  percent <= sharpsl_pm.battstat.mainbat_percent) {
+          creeping back up so we try to avoid this here */
+       if ((sharpsl_pm.battstat.ac_status == APM_AC_ONLINE)
+           || (apm_status == APM_BATTERY_STATUS_HIGH)
+           || percent <= sharpsl_pm.battstat.mainbat_percent) {
                sharpsl_pm.battstat.mainbat_voltage = voltage;
                sharpsl_pm.battstat.mainbat_status = apm_status;
                sharpsl_pm.battstat.mainbat_percent = percent;
@@ -279,8 +281,8 @@ static void sharpsl_battery_thread(struct work_struct *private_)
 #ifdef CONFIG_BACKLIGHT_CORGI
        /* If battery is low. limit backlight intensity to save power. */
        if ((sharpsl_pm.battstat.ac_status != APM_AC_ONLINE)
-                       && ((sharpsl_pm.battstat.mainbat_status == APM_BATTERY_STATUS_LOW) ||
-                       (sharpsl_pm.battstat.mainbat_status == APM_BATTERY_STATUS_CRITICAL))) {
+           && ((sharpsl_pm.battstat.mainbat_status == APM_BATTERY_STATUS_LOW)
+           || (sharpsl_pm.battstat.mainbat_status == APM_BATTERY_STATUS_CRITICAL))) {
                if (!(sharpsl_pm.flags & SHARPSL_BL_LIMIT)) {
                        sharpsl_pm.machinfo->backlight_limit(1);
                        sharpsl_pm.flags |= SHARPSL_BL_LIMIT;
@@ -293,8 +295,8 @@ static void sharpsl_battery_thread(struct work_struct *private_)
 
        /* Suspend if critical battery level */
        if ((sharpsl_pm.battstat.ac_status != APM_AC_ONLINE)
-                       && (sharpsl_pm.battstat.mainbat_status == APM_BATTERY_STATUS_CRITICAL)
-                       && !(sharpsl_pm.flags & SHARPSL_APM_QUEUED)) {
+            && (sharpsl_pm.battstat.mainbat_status == APM_BATTERY_STATUS_CRITICAL)
+            && !(sharpsl_pm.flags & SHARPSL_APM_QUEUED)) {
                sharpsl_pm.flags |= SHARPSL_APM_QUEUED;
                dev_err(sharpsl_pm.dev, "Fatal Off\n");
                apm_queue_event(APM_CRITICAL_SUSPEND);
@@ -346,7 +348,7 @@ static void sharpsl_charge_error(void)
 
 static void sharpsl_charge_toggle(struct work_struct *private_)
 {
-       dev_dbg(sharpsl_pm.dev, "Toogling Charger at time: %lx\n", jiffies);
+       dev_dbg(sharpsl_pm.dev, "Toggling Charger at time: %lx\n", jiffies);
 
        if (!sharpsl_pm.machinfo->read_devdata(SHARPSL_STATUS_ACIN)) {
                sharpsl_charge_off();
@@ -368,7 +370,7 @@ static void sharpsl_ac_timer(unsigned long data)
 {
        int acin = sharpsl_pm.machinfo->read_devdata(SHARPSL_STATUS_ACIN);
 
-       dev_dbg(sharpsl_pm.dev, "AC Status: %d\n",acin);
+       dev_dbg(sharpsl_pm.dev, "AC Status: %d\n", acin);
 
        sharpsl_average_clear();
        if (acin && (sharpsl_pm.charge_mode != CHRG_ON))
@@ -472,14 +474,14 @@ static int sharpsl_average_value(int ad)
        sharpsl_ad[sharpsl_ad_index] = ad;
        sharpsl_ad_index++;
        if (sharpsl_ad_index >= SHARPSL_CNV_VALUE_NUM) {
-               for (i=0; i < (SHARPSL_CNV_VALUE_NUM-1); i++)
+               for (i = 0; i < (SHARPSL_CNV_VALUE_NUM-1); i++)
                        sharpsl_ad[i] = sharpsl_ad[i+1];
                sharpsl_ad_index = SHARPSL_CNV_VALUE_NUM - 1;
        }
-       for (i=0; i < sharpsl_ad_index; i++)
+       for (i = 0; i < sharpsl_ad_index; i++)
                ad_val += sharpsl_ad[i];
 
-       return (ad_val / sharpsl_ad_index);
+       return ad_val / sharpsl_ad_index;
 }
 
 /*
@@ -492,8 +494,8 @@ static int get_select_val(int *val)
 
        /* Find MAX val */
        temp = val[0];
-       j=0;
-       for (i=1; i<5; i++) {
+       j = 0;
+       for (i = 1; i < 5; i++) {
                if (temp < val[i]) {
                        temp = val[i];
                        j = i;
@@ -502,21 +504,21 @@ static int get_select_val(int *val)
 
        /* Find MIN val */
        temp = val[4];
-       k=4;
-       for (i=3; i>=0; i--) {
+       k = 4;
+       for (i = 3; i >= 0; i--) {
                if (temp > val[i]) {
                        temp = val[i];
                        k = i;
                }
        }
 
-       for (i=0; i<5; i++)
-               if (i != j && i != k )
+       for (i = 0; i < 5; i++)
+               if (i != j && i != k)
                        sum += val[i];
 
        dev_dbg(sharpsl_pm.dev, "Average: %d from values: %d, %d, %d, %d, %d\n", sum/3, val[0], val[1], val[2], val[3], val[4]);
 
-       return (sum/3);
+       return sum/3;
 }
 
 static int sharpsl_check_battery_temp(void)
@@ -524,7 +526,7 @@ static int sharpsl_check_battery_temp(void)
        int val, i, buff[5];
 
        /* Check battery temperature */
-       for (i=0; i<5; i++) {
+       for (i = 0; i < 5; i++) {
                mdelay(SHARPSL_CHECK_BATTERY_WAIT_TIME_TEMP);
                sharpsl_pm.machinfo->measure_temp(1);
                mdelay(SHARPSL_CHECK_BATTERY_WAIT_TIME_TEMP);
@@ -557,7 +559,7 @@ static int sharpsl_check_battery_voltage(void)
                sharpsl_pm.machinfo->discharge1(1);
 
        /* Check battery voltage */
-       for (i=0; i<5; i++) {
+       for (i = 0; i < 5; i++) {
                buff[i] = sharpsl_pm.machinfo->read_devdata(SHARPSL_BATT_VOLT);
                mdelay(SHARPSL_CHECK_BATTERY_WAIT_TIME_VOLT);
        }
@@ -581,16 +583,16 @@ static int sharpsl_ac_check(void)
 {
        int temp, i, buff[5];
 
-       for (i=0; i<5; i++) {
+       for (i = 0; i < 5; i++) {
                buff[i] = sharpsl_pm.machinfo->read_devdata(SHARPSL_ACIN_VOLT);
                mdelay(SHARPSL_CHECK_BATTERY_WAIT_TIME_ACIN);
        }
 
        temp = get_select_val(buff);
-       dev_dbg(sharpsl_pm.dev, "AC Voltage: %d\n",temp);
+       dev_dbg(sharpsl_pm.dev, "AC Voltage: %d\n", temp);
 
        if ((temp > sharpsl_pm.machinfo->charge_acin_high) || (temp < sharpsl_pm.machinfo->charge_acin_low)) {
-               dev_err(sharpsl_pm.dev, "Error: AC check failed.\n");
+               dev_err(sharpsl_pm.dev, "Error: AC check failed: voltage %d.\n", temp);
                return -1;
        }
 
@@ -624,9 +626,9 @@ static int sharpsl_pm_resume(struct platform_device *pdev)
 
 static void corgi_goto_sleep(unsigned long alarm_time, unsigned int alarm_enable, suspend_state_t state)
 {
-       dev_dbg(sharpsl_pm.dev, "Time is: %08x\n",RCNR);
+       dev_dbg(sharpsl_pm.dev, "Time is: %08x\n", RCNR);
 
-       dev_dbg(sharpsl_pm.dev, "Offline Charge Activate = %d\n",sharpsl_pm.flags & SHARPSL_DO_OFFLINE_CHRG);
+       dev_dbg(sharpsl_pm.dev, "Offline Charge Activate = %d\n", sharpsl_pm.flags & SHARPSL_DO_OFFLINE_CHRG);
        /* not charging and AC-IN! */
 
        if ((sharpsl_pm.flags & SHARPSL_DO_OFFLINE_CHRG) && (sharpsl_pm.machinfo->read_devdata(SHARPSL_STATUS_ACIN))) {
@@ -644,12 +646,12 @@ static void corgi_goto_sleep(unsigned long alarm_time, unsigned int alarm_enable
        if ((sharpsl_pm.charge_mode == CHRG_ON) && ((alarm_enable && ((alarm_time - RCNR) > (SHARPSL_BATCHK_TIME_SUSPEND + 30))) || !alarm_enable)) {
                RTSR &= RTSR_ALE;
                RTAR = RCNR + SHARPSL_BATCHK_TIME_SUSPEND;
-               dev_dbg(sharpsl_pm.dev, "Charging alarm at: %08x\n",RTAR);
+               dev_dbg(sharpsl_pm.dev, "Charging alarm at: %08x\n", RTAR);
                sharpsl_pm.flags |= SHARPSL_ALARM_ACTIVE;
        } else if (alarm_enable) {
                RTSR &= RTSR_ALE;
                RTAR = alarm_time;
-               dev_dbg(sharpsl_pm.dev, "User alarm at: %08x\n",RTAR);
+               dev_dbg(sharpsl_pm.dev, "User alarm at: %08x\n", RTAR);
        } else {
                dev_dbg(sharpsl_pm.dev, "No alarms set.\n");
        }
@@ -658,19 +660,18 @@ static void corgi_goto_sleep(unsigned long alarm_time, unsigned int alarm_enable
 
        sharpsl_pm.machinfo->postsuspend();
 
-       dev_dbg(sharpsl_pm.dev, "Corgi woken up from suspend: %08x\n",PEDR);
+       dev_dbg(sharpsl_pm.dev, "Corgi woken up from suspend: %08x\n", PEDR);
 }
 
 static int corgi_enter_suspend(unsigned long alarm_time, unsigned int alarm_enable, suspend_state_t state)
 {
-       if (!sharpsl_pm.machinfo->should_wakeup(!(sharpsl_pm.flags & SHARPSL_ALARM_ACTIVE) && alarm_enable) )
-       {
+       if (!sharpsl_pm.machinfo->should_wakeup(!(sharpsl_pm.flags & SHARPSL_ALARM_ACTIVE) && alarm_enable)) {
                if (!(sharpsl_pm.flags & SHARPSL_ALARM_ACTIVE)) {
                        dev_dbg(sharpsl_pm.dev, "No user triggered wakeup events and not charging. Strange. Suspend.\n");
                        corgi_goto_sleep(alarm_time, alarm_enable, state);
                        return 1;
                }
-               if(sharpsl_off_charge_battery()) {
+               if (sharpsl_off_charge_battery()) {
                        dev_dbg(sharpsl_pm.dev, "Charging. Suspend...\n");
                        corgi_goto_sleep(alarm_time, alarm_enable, state);
                        return 1;
@@ -697,7 +698,7 @@ static int corgi_pxa_pm_enter(suspend_state_t state)
 
        corgi_goto_sleep(alarm_time, alarm_status, state);
 
-       while (corgi_enter_suspend(alarm_time,alarm_status,state))
+       while (corgi_enter_suspend(alarm_time, alarm_status, state))
                {}
 
        if (sharpsl_pm.machinfo->earlyresume)
@@ -732,7 +733,7 @@ static int sharpsl_fatal_check(void)
                sharpsl_pm.machinfo->discharge1(1);
 
        /* Check battery : check inserting battery ? */
-       for (i=0; i<5; i++) {
+       for (i = 0; i < 5; i++) {
                buff[i] = sharpsl_pm.machinfo->read_devdata(SHARPSL_BATT_VOLT);
                mdelay(SHARPSL_CHECK_BATTERY_WAIT_TIME_VOLT);
        }
@@ -812,7 +813,7 @@ static int sharpsl_off_charge_battery(void)
                mdelay(SHARPSL_CHARGE_CO_CHECK_TIME);
 
                time = RCNR;
-               while(1) {
+               while (1) {
                        /* Check if any wakeup event had occurred */
                        if (sharpsl_pm.machinfo->charger_wakeup() != 0)
                                return 0;
@@ -835,9 +836,9 @@ static int sharpsl_off_charge_battery(void)
        mdelay(SHARPSL_CHARGE_CO_CHECK_TIME);
 
        time = RCNR;
-       while(1) {
+       while (1) {
                /* Check if any wakeup event had occurred */
-               if (sharpsl_pm.machinfo->charger_wakeup() != 0)
+               if (sharpsl_pm.machinfo->charger_wakeup())
                        return 0;
                /* Check for timeout */
                if ((RCNR-time) > SHARPSL_WAIT_CO_TIME) {
@@ -864,12 +865,12 @@ static int sharpsl_off_charge_battery(void)
 
 static ssize_t battery_percentage_show(struct device *dev, struct device_attribute *attr, char *buf)
 {
-       return sprintf(buf, "%d\n",sharpsl_pm.battstat.mainbat_percent);
+       return sprintf(buf, "%d\n", sharpsl_pm.battstat.mainbat_percent);
 }
 
 static ssize_t battery_voltage_show(struct device *dev, struct device_attribute *attr, char *buf)
 {
-       return sprintf(buf, "%d\n",sharpsl_pm.battstat.mainbat_voltage);
+       return sprintf(buf, "%d\n", sharpsl_pm.battstat.mainbat_voltage);
 }
 
 static DEVICE_ATTR(battery_percentage, 0444, battery_percentage_show, NULL);
@@ -943,8 +944,7 @@ static int __init sharpsl_pm_probe(struct platform_device *pdev)
                }
        }
 
-       if (sharpsl_pm.machinfo->batfull_irq)
-       {
+       if (sharpsl_pm.machinfo->batfull_irq) {
                /* Register interrupt handler. */
                if (request_irq(IRQ_GPIO(sharpsl_pm.machinfo->gpio_batfull), sharpsl_chrg_full_isr, IRQF_DISABLED | IRQF_TRIGGER_RISING, "CO", sharpsl_chrg_full_isr)) {
                        dev_err(sharpsl_pm.dev, "Could not get irq %d.\n", IRQ_GPIO(sharpsl_pm.machinfo->gpio_batfull));
index d98023f..4b50f14 100644 (file)
@@ -768,6 +768,10 @@ static void __init common_init(void)
 
        pxa2xx_mfp_config(ARRAY_AND_SIZE(spitz_pin_config));
 
+       pxa_set_ffuart_info(NULL);
+       pxa_set_btuart_info(NULL);
+       pxa_set_stuart_info(NULL);
+
        spitz_init_spi();
 
        platform_add_devices(devices, ARRAY_SIZE(devices));
index 724ffb0..fc5a70c 100644 (file)
@@ -103,7 +103,7 @@ static void spitz_presuspend(void)
        PFER = GPIO_bit(SPITZ_GPIO_KEY_INT) | GPIO_bit(SPITZ_GPIO_RESET);
        PWER = GPIO_bit(SPITZ_GPIO_KEY_INT) | GPIO_bit(SPITZ_GPIO_RESET) | PWER_RTC;
        PKWR = GPIO_bit(SPITZ_GPIO_SYNC) | GPIO_bit(SPITZ_GPIO_KEY_INT) | GPIO_bit(SPITZ_GPIO_RESET);
-       PKSR = 0xffffffff; // clear
+       PKSR = 0xffffffff; /* clear */
 
        /* nRESET_OUT Disable */
        PSLR |= PSLR_SL_ROD;
@@ -149,7 +149,7 @@ static int spitz_should_wakeup(unsigned int resume_on_alarm)
        if (resume_on_alarm && (PEDR & PWER_RTC))
                is_resume |= PWER_RTC;
 
-       dev_dbg(sharpsl_pm.dev, "is_resume: %x\n",is_resume);
+       dev_dbg(sharpsl_pm.dev, "is_resume: %x\n", is_resume);
        return is_resume;
 }
 
@@ -160,7 +160,7 @@ static unsigned long spitz_charger_wakeup(void)
 
 unsigned long spitzpm_read_devdata(int type)
 {
-       switch(type) {
+       switch (type) {
        case SHARPSL_STATUS_ACIN:
                return (((~GPLR(SPITZ_GPIO_AC_IN)) & GPIO_bit(SPITZ_GPIO_AC_IN)) != 0);
        case SHARPSL_STATUS_LOCK:
@@ -199,7 +199,7 @@ struct sharpsl_charger_machinfo spitz_pm_machinfo = {
 #if defined(CONFIG_LCD_CORGI)
        .backlight_limit = corgi_lcd_limit_intensity,
 #elif defined(CONFIG_BACKLIGHT_CORGI)
-        .backlight_limit  = corgibl_limit_intensity,
+       .backlight_limit  = corgibl_limit_intensity,
 #endif
        .charge_on_volt   = SHARPSL_CHARGE_ON_VOLT,
        .charge_on_temp   = SHARPSL_CHARGE_ON_TEMP,
@@ -208,8 +208,8 @@ struct sharpsl_charger_machinfo spitz_pm_machinfo = {
        .fatal_acin_volt  = SHARPSL_FATAL_ACIN_VOLT,
        .fatal_noacin_volt= SHARPSL_FATAL_NOACIN_VOLT,
        .bat_levels       = 40,
-       .bat_levels_noac  = spitz_battery_levels_noac,
-       .bat_levels_acin  = spitz_battery_levels_acin,
+       .bat_levels_noac  = sharpsl_battery_levels_noac,
+       .bat_levels_acin  = sharpsl_battery_levels_acin,
        .status_high_acin = 188,
        .status_low_acin  = 178,
        .status_high_noac = 185,
@@ -241,7 +241,7 @@ static int __devinit spitzpm_init(void)
 
 static void spitzpm_exit(void)
 {
-       platform_device_unregister(spitzpm_device);
+       platform_device_unregister(spitzpm_device);
 }
 
 module_init(spitzpm_init);
index 965e38c..9ebe658 100644 (file)
@@ -342,8 +342,9 @@ void ssp_free(struct ssp_device *ssp)
 }
 EXPORT_SYMBOL(ssp_free);
 
-static int __devinit ssp_probe(struct platform_device *pdev, int type)
+static int __devinit ssp_probe(struct platform_device *pdev)
 {
+       const struct platform_device_id *id = platform_get_device_id(pdev);
        struct resource *res;
        struct ssp_device *ssp;
        int ret = 0;
@@ -413,7 +414,7 @@ static int __devinit ssp_probe(struct platform_device *pdev, int type)
         */
        ssp->port_id = pdev->id + 1;
        ssp->use_count = 0;
-       ssp->type = type;
+       ssp->type = (int)id->driver_data;
 
        mutex_lock(&ssp_lock);
        list_add(&ssp->node, &ssp_list);
@@ -457,75 +458,31 @@ static int __devexit ssp_remove(struct platform_device *pdev)
        return 0;
 }
 
-static int __devinit pxa25x_ssp_probe(struct platform_device *pdev)
-{
-       return ssp_probe(pdev, PXA25x_SSP);
-}
-
-static int __devinit pxa25x_nssp_probe(struct platform_device *pdev)
-{
-       return ssp_probe(pdev, PXA25x_NSSP);
-}
-
-static int __devinit pxa27x_ssp_probe(struct platform_device *pdev)
-{
-       return ssp_probe(pdev, PXA27x_SSP);
-}
-
-static struct platform_driver pxa25x_ssp_driver = {
-       .driver         = {
-               .name   = "pxa25x-ssp",
-       },
-       .probe          = pxa25x_ssp_probe,
-       .remove         = __devexit_p(ssp_remove),
+static const struct platform_device_id ssp_id_table[] = {
+       { "pxa25x-ssp",         PXA25x_SSP },
+       { "pxa25x-nssp",        PXA25x_NSSP },
+       { "pxa27x-ssp",         PXA27x_SSP },
+       { },
 };
 
-static struct platform_driver pxa25x_nssp_driver = {
-       .driver         = {
-               .name   = "pxa25x-nssp",
-       },
-       .probe          = pxa25x_nssp_probe,
+static struct platform_driver ssp_driver = {
+       .probe          = ssp_probe,
        .remove         = __devexit_p(ssp_remove),
-};
-
-static struct platform_driver pxa27x_ssp_driver = {
        .driver         = {
-               .name   = "pxa27x-ssp",
+               .owner  = THIS_MODULE,
+               .name   = "pxa2xx-ssp",
        },
-       .probe          = pxa27x_ssp_probe,
-       .remove         = __devexit_p(ssp_remove),
+       .id_table       = ssp_id_table,
 };
 
 static int __init pxa_ssp_init(void)
 {
-       int ret = 0;
-
-       ret = platform_driver_register(&pxa25x_ssp_driver);
-       if (ret) {
-               printk(KERN_ERR "failed to register pxa25x_ssp_driver");
-               return ret;
-       }
-
-       ret = platform_driver_register(&pxa25x_nssp_driver);
-       if (ret) {
-               printk(KERN_ERR "failed to register pxa25x_nssp_driver");
-               return ret;
-       }
-
-       ret = platform_driver_register(&pxa27x_ssp_driver);
-       if (ret) {
-               printk(KERN_ERR "failed to register pxa27x_ssp_driver");
-               return ret;
-       }
-
-       return ret;
+       return platform_driver_register(&ssp_driver);
 }
 
 static void __exit pxa_ssp_exit(void)
 {
-       platform_driver_unregister(&pxa25x_ssp_driver);
-       platform_driver_unregister(&pxa25x_nssp_driver);
-       platform_driver_unregister(&pxa27x_ssp_driver);
+       platform_driver_unregister(&ssp_driver);
 }
 
 arch_initcall(pxa_ssp_init);
index 3b205b6..a98a434 100644 (file)
@@ -760,6 +760,10 @@ static void __init stargate2_init(void)
 
        pxa2xx_mfp_config(ARRAY_AND_SIZE(stargate2_pin_config));
 
+       pxa_set_ffuart_info(NULL);
+       pxa_set_btuart_info(NULL);
+       pxa_set_stuart_info(NULL);
+
        /* spi chip selects */
        gpio_direction_output(37, 0);
        gpio_direction_output(24, 0);
index b75353a..f02dcb5 100644 (file)
@@ -477,6 +477,10 @@ static void __init tavorevb_init(void)
        /* initialize MFP configurations */
        pxa3xx_mfp_config(ARRAY_AND_SIZE(tavorevb_mfp_cfg));
 
+       pxa_set_ffuart_info(NULL);
+       pxa_set_btuart_info(NULL);
+       pxa_set_stuart_info(NULL);
+
        platform_device_register(&smc91x_device);
 
        tavorevb_init_lcd();
index e81a526..c854c16 100644 (file)
@@ -825,6 +825,11 @@ static void __init tosa_init(void)
        int dummy;
 
        pxa2xx_mfp_config(ARRAY_AND_SIZE(tosa_pin_config));
+
+       pxa_set_ffuart_info(NULL);
+       pxa_set_btuart_info(NULL);
+       pxa_set_stuart_info(NULL);
+
        gpio_set_wake(MFP_PIN_GPIO1, 1);
        /* We can't pass to gpio-keys since it will drop the Reset altfunc */
 
index 3981e03..0aa858e 100644 (file)
@@ -524,6 +524,10 @@ static void __init trizeps4_init(void)
                                        ARRAY_SIZE(trizeps4_devices));
        }
 
+       pxa_set_ffuart_info(NULL);
+       pxa_set_btuart_info(NULL);
+       pxa_set_stuart_info(NULL);
+
        if (0)  /* dont know how to determine LCD */
                set_pxa_fb_info(&sharp_lcd);
        else
index d33c232..cf0d71b 100644 (file)
@@ -301,15 +301,6 @@ static void __init viper_init_irq(void)
        set_irq_chained_handler(gpio_to_irq(VIPER_CPLD_GPIO),
                                viper_irq_handler);
        set_irq_type(gpio_to_irq(VIPER_CPLD_GPIO), IRQ_TYPE_EDGE_BOTH);
-
-#ifndef CONFIG_SERIAL_PXA
-       /*
-        * 8250 doesn't support IRQ_TYPE being passed as part
-        * of the plat_serial8250_port structure...
-        */
-       set_irq_type(gpio_to_irq(VIPER_UARTA_GPIO), IRQ_TYPE_EDGE_RISING);
-       set_irq_type(gpio_to_irq(VIPER_UARTB_GPIO), IRQ_TYPE_EDGE_RISING);
-#endif
 }
 
 /* Flat Panel */
@@ -539,6 +530,7 @@ static struct plat_serial8250_port serial_platform_data[] = {
        {
                .mapbase        = VIPER_UARTA_PHYS,
                .irq            = gpio_to_irq(VIPER_UARTA_GPIO),
+               .irqflags       = IRQF_TRIGGER_RISING,
                .uartclk        = 1843200,
                .regshift       = 1,
                .iotype         = UPIO_MEM,
@@ -548,6 +540,7 @@ static struct plat_serial8250_port serial_platform_data[] = {
        {
                .mapbase        = VIPER_UARTB_PHYS,
                .irq            = gpio_to_irq(VIPER_UARTB_GPIO),
+               .irqflags       = IRQF_TRIGGER_RISING,
                .uartclk        = 1843200,
                .regshift       = 1,
                .iotype         = UPIO_MEM,
@@ -908,6 +901,10 @@ static void __init viper_init(void)
 
        pxa2xx_mfp_config(ARRAY_AND_SIZE(viper_pin_config));
 
+       pxa_set_ffuart_info(NULL);
+       pxa_set_btuart_info(NULL);
+       pxa_set_stuart_info(NULL);
+
        /* Wake-up serial console */
        viper_init_serial_gpio();
 
index 3fd79cb..d3b4e3f 100644 (file)
@@ -165,6 +165,11 @@ static void __init xcep_init(void)
 {
        pxa2xx_mfp_config(ARRAY_AND_SIZE(xcep_pin_config));
 
+       pxa_set_ffuart_info(NULL);
+       pxa_set_btuart_info(NULL);
+       pxa_set_stuart_info(NULL);
+       pxa_set_hwuart_info(NULL);
+
        /* See Intel XScale Developer's Guide for details */
        /* Set RDF and RDN to appropriate values (chip select 3 (smc91x)) */
        MSC1 = (MSC1 & 0xffff) | 0xD5540000;
index 09784d3..b66e9e2 100644 (file)
@@ -31,7 +31,7 @@
 #include <mach/mmc.h>
 #include <mach/ohci.h>
 #include <mach/pxa27x_keypad.h>
-#include <mach/pxa3xx_nand.h>
+#include <plat/pxa3xx_nand.h>
 
 #include "devices.h"
 #include "generic.h"
@@ -444,6 +444,10 @@ static inline void zylonite_init_ohci(void) {}
 
 static void __init zylonite_init(void)
 {
+       pxa_set_ffuart_info(NULL);
+       pxa_set_btuart_info(NULL);
+       pxa_set_stuart_info(NULL);
+
        /* board-processor specific initialization */
        zylonite_pxa300_init();
        zylonite_pxa320_init();
index 1535540..3fd8892 100644 (file)
@@ -1,6 +1,6 @@
 /* arch/arm/mach-s3c2400/include/mach/map.h
  *
- * Copyright 2003,2007  Simtec Electronics
+ * Copyright 2003-2007 Simtec Electronics
  *     http://armlinux.simtec.co.uk/
  *     Ben Dooks <ben@simtec.co.uk>
  *
index 3d4e9da..dd1fcc7 100644 (file)
@@ -81,6 +81,14 @@ config ARCH_H1940
        help
          Say Y here if you are using the HP IPAQ H1940
 
+config H1940BT
+        tristate "Control the state of H1940 bluetooth chip"
+        depends on ARCH_H1940
+        select RFKILL
+        help
+          This is a simple driver that is able to control
+          the state of built in bluetooth chip on h1940.
+
 config PM_H1940
        bool
        help
index 2ab5ba4..0d468e9 100644 (file)
@@ -21,7 +21,8 @@ obj-$(CONFIG_S3C2410_PLLTABLE)        += pll.o
 # Machine support
 
 obj-$(CONFIG_ARCH_SMDK2410)    += mach-smdk2410.o
-obj-$(CONFIG_ARCH_H1940)       += mach-h1940.o h1940-bluetooth.o
+obj-$(CONFIG_ARCH_H1940)       += mach-h1940.o
+obj-$(CONFIG_H1940BT)          += h1940-bluetooth.o
 obj-$(CONFIG_PM_H1940)         += pm-h1940.o
 obj-$(CONFIG_MACH_N30)         += mach-n30.o
 obj-$(CONFIG_ARCH_BAST)                += mach-bast.o usb-simtec.o
index 9a37c87..217b102 100644 (file)
@@ -1,6 +1,6 @@
 /* linux/arch/arm/mach-s3c2410/bast-irq.c
  *
- * Copyright (c) 2003,2005 Simtec Electronics
+ * Copyright 2003-2005 Simtec Electronics
  *   Ben Dooks <ben@simtec.co.uk>
  *
  * http://www.simtec.co.uk/products/EB2410ITX/
@@ -141,7 +141,7 @@ static __init int bast_irq_init(void)
        unsigned int i;
 
        if (machine_is_bast()) {
-               printk(KERN_INFO "BAST PC104 IRQ routing, (c) 2005 Simtec Electronics\n");
+               printk(KERN_INFO "BAST PC104 IRQ routing, Copyright 2005 Simtec Electronics\n");
 
                /* zap all the IRQs */
 
index 9d11868..75189df 100644 (file)
@@ -1,6 +1,6 @@
 /* linux/arch/arm/mach-s3c2410/cpu-freq.c
  *
- * Copyright (c) 2006,2008 Simtec Electronics
+ * Copyright (c) 2006-2008 Simtec Electronics
  *     http://armlinux.simtec.co.uk/
  *     Ben Dooks <ben@simtec.co.uk>
  *
index 5aabf11..b7d1f8d 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/ctype.h>
 #include <linux/leds.h>
 #include <linux/gpio.h>
+#include <linux/rfkill.h>
 
 #include <mach/regs-gpio.h>
 #include <mach/hardware.h>
 
 #define DRV_NAME              "h1940-bt"
 
-#ifdef CONFIG_LEDS_H1940
-DEFINE_LED_TRIGGER(bt_led_trigger);
-#endif
-
-static int state;
-
 /* Bluetooth control */
 static void h1940bt_enable(int on)
 {
        if (on) {
-#ifdef CONFIG_LEDS_H1940
-               /* flashing Blue */
-               led_trigger_event(bt_led_trigger, LED_HALF);
-#endif
-
                /* Power on the chip */
                h1940_latch_control(0, H1940_LATCH_BLUETOOTH_POWER);
                /* Reset the chip */
@@ -46,48 +36,31 @@ static void h1940bt_enable(int on)
                s3c2410_gpio_setpin(S3C2410_GPH(1), 1);
                mdelay(10);
                s3c2410_gpio_setpin(S3C2410_GPH(1), 0);
-
-               state = 1;
        }
        else {
-#ifdef CONFIG_LEDS_H1940
-               led_trigger_event(bt_led_trigger, 0);
-#endif
-
                s3c2410_gpio_setpin(S3C2410_GPH(1), 1);
                mdelay(10);
                s3c2410_gpio_setpin(S3C2410_GPH(1), 0);
                mdelay(10);
                h1940_latch_control(H1940_LATCH_BLUETOOTH_POWER, 0);
-
-               state = 0;
        }
 }
 
-static ssize_t h1940bt_show(struct device *dev, struct device_attribute *attr, char *buf)
+static int h1940bt_set_block(void *data, bool blocked)
 {
-       return snprintf(buf, PAGE_SIZE, "%d\n", state);
+       h1940bt_enable(!blocked);
+       return 0;
 }
 
-static ssize_t h1940bt_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
-{
-       int new_state;
-       char *endp;
-
-       new_state = simple_strtoul(buf, &endp, 0);
-       if (*endp && !isspace(*endp))
-               return -EINVAL;
-
-       h1940bt_enable(new_state);
-
-       return count;
-}
-static DEVICE_ATTR(enable, 0644,
-               h1940bt_show,
-               h1940bt_store);
+static const struct rfkill_ops h1940bt_rfkill_ops = {
+       .set_block = h1940bt_set_block,
+};
 
 static int __init h1940bt_probe(struct platform_device *pdev)
 {
+       struct rfkill *rfk;
+       int ret = 0;
+
        /* Configures BT serial port GPIOs */
        s3c2410_gpio_cfgpin(S3C2410_GPH(0), S3C2410_GPH0_nCTS0);
        s3c2410_gpio_pullup(S3C2410_GPH(0), 1);
@@ -98,21 +71,44 @@ static int __init h1940bt_probe(struct platform_device *pdev)
        s3c2410_gpio_cfgpin(S3C2410_GPH(3), S3C2410_GPH3_RXD0);
        s3c2410_gpio_pullup(S3C2410_GPH(3), 1);
 
-#ifdef CONFIG_LEDS_H1940
-       led_trigger_register_simple("h1940-bluetooth", &bt_led_trigger);
-#endif
 
-       /* disable BT by default */
-       h1940bt_enable(0);
+       rfk = rfkill_alloc(DRV_NAME, &pdev->dev, RFKILL_TYPE_BLUETOOTH,
+                       &h1940bt_rfkill_ops, NULL);
+       if (!rfk) {
+               ret = -ENOMEM;
+               goto err_rfk_alloc;
+       }
+
+       rfkill_set_led_trigger_name(rfk, "h1940-bluetooth");
+
+       ret = rfkill_register(rfk);
+       if (ret)
+               goto err_rfkill;
+
+       platform_set_drvdata(pdev, rfk);
+
+       return 0;
 
-       return device_create_file(&pdev->dev, &dev_attr_enable);
+err_rfkill:
+       rfkill_destroy(rfk);
+err_rfk_alloc:
+       return ret;
 }
 
 static int h1940bt_remove(struct platform_device *pdev)
 {
-#ifdef CONFIG_LEDS_H1940
-       led_trigger_unregister_simple(bt_led_trigger);
-#endif
+       struct rfkill *rfk = platform_get_drvdata(pdev);
+
+       platform_set_drvdata(pdev, NULL);
+
+       if (rfk) {
+               rfkill_unregister(rfk);
+               rfkill_destroy(rfk);
+       }
+       rfk = NULL;
+
+       h1940bt_enable(0);
+
        return 0;
 }
 
index 20493b0..bee2a7a 100644 (file)
@@ -1,6 +1,6 @@
 /* arch/arm/mach-s3c2410/include/mach/bast-cpld.h
  *
- * Copyright (c) 2003,2004 Simtec Electronics
+ * Copyright (c) 2003-2004 Simtec Electronics
  *     Ben Dooks <ben@simtec.co.uk>
  *
  * BAST - CPLD control constants
index 501c202..cac428c 100644 (file)
@@ -1,6 +1,6 @@
 /* arch/arm/mach-s3c2410/include/mach/bast-irq.h
  *
- * Copyright (c) 2003,2004 Simtec Electronics
+ * Copyright (c) 2003-2004 Simtec Electronics
  *     Ben Dooks <ben@simtec.co.uk>
  *
  * Machine BAST - IRQ Number definitions
index c2c5baf..6e7dc9d 100644 (file)
@@ -1,6 +1,6 @@
 /* arch/arm/mach-s3c2410/include/mach/bast-map.h
  *
- * Copyright (c) 2003,2004 Simtec Electronics
+ * Copyright (c) 2003-2004 Simtec Electronics
  *     Ben Dooks <ben@simtec.co.uk>
  *
  * Machine BAST - Memory map definitions
index 61684cb..4c38b39 100644 (file)
@@ -1,6 +1,6 @@
 /* arch/arm/mach-s3c2410/include/mach/bast-pmu.h
  *
- * Copyright (c) 2003,2004 Simtec Electronics
+ * Copyright (c) 2003-2004 Simtec Electronics
  *     Ben Dooks <ben@simtec.co.uk>
  *     Vincent Sanders <vince@simtec.co.uk>
  *
index 92e2687..08ac5f9 100644 (file)
@@ -1,6 +1,6 @@
 /* arch/arm/mach-s3c2410/include/mach/dma.h
  *
- * Copyright (C) 2003,2004,2006 Simtec Electronics
+ * Copyright (C) 2003-2006 Simtec Electronics
  *     Ben Dooks <ben@simtec.co.uk>
  *
  * Samsung S3C24XX DMA support
index 801dff1..035a493 100644 (file)
@@ -1,6 +1,6 @@
 /* arch/arm/mach-s3c2410/include/mach/gpio-fns.h
  *
- * Copyright (c) 2003,2009 Simtec Electronics
+ * Copyright (c) 2003-2009 Simtec Electronics
  *     Ben Dooks <ben@simtec.co.uk>
  *
  * S3C2410 - hardware
index 639eff5..17380f8 100644 (file)
@@ -1,6 +1,6 @@
 /* arch/arm/mach-s3c2410/include/mach/osiris-map.h
  *
- * (c) 2005 Simtec Electronics
+ * Copyright 2005 Simtec Electronics
  *     http://www.simtec.co.uk/products/
  *     Ben Dooks <ben@simtec.co.uk>
  *
index 2a5d90e..9a0d169 100644 (file)
@@ -1,7 +1,7 @@
 /* arch/arm/mach-s3c2410/include/mach/regs-clock.h
  *
- * Copyright (c) 2003,2004,2005,2006 Simtec Electronics <linux@simtec.co.uk>
- *                   http://armlinux.simtec.co.uk/
+ * Copyright (c) 2003-2006 Simtec Electronics <linux@simtec.co.uk>
+ *     http://armlinux.simtec.co.uk/
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
index f6e8eec..ebc85c6 100644 (file)
@@ -1,7 +1,7 @@
 /* arch/arm/mach-s3c2410/include/mach/regs-gpio.h
  *
- * Copyright (c) 2003,2004 Simtec Electronics <linux@simtec.co.uk>
- *                        http://www.simtec.co.uk/products/SWLINUX/
+ * Copyright (c) 2003-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
index 2d36353..4932b87 100644 (file)
@@ -1,7 +1,7 @@
 /* arch/arm/mach-s3c2410/include/mach/regs-power.h
  *
- * Copyright (c) 2003,2004,2005,2006 Simtec Electronics <linux@simtec.co.uk>
- *                   http://armlinux.simtec.co.uk/
+ * Copyright (c) 2003-2006 Simtec Electronics <linux@simtec.co.uk>
+ *     http://armlinux.simtec.co.uk/
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
index c943210..72f756c 100644 (file)
@@ -1,7 +1,6 @@
-
 /* arch/arm/mach-s3c2410/include/mach/uncompress.h
  *
- * Copyright (c) 20032007 Simtec Electronics
+ * Copyright (c) 2003-2007 Simtec Electronics
  *     http://armlinux.simtec.co.uk/
  *     Ben Dooks <ben@simtec.co.uk>
  *
index f53f85b..47add13 100644 (file)
@@ -1,6 +1,6 @@
 /* arch/arm/mach-s3c2410/include/mach/vr1000-irq.h
  *
- * Copyright (c) 2003,2004 Simtec Electronics
+ * Copyright (c) 2003-2004 Simtec Electronics
  *     Ben Dooks <ben@simtec.co.uk>
  *
  * Machine VR1000 - IRQ Number definitions
index 647c9ad..4c79ac8 100644 (file)
@@ -1,6 +1,6 @@
 /* linux/arch/arm/mach-s3c2410/mach-bast.c
  *
- * Copyright (c) 2003-2005,2008 Simtec Electronics
+ * Copyright 2003-2008 Simtec Electronics
  *   Ben Dooks <ben@simtec.co.uk>
  *
  * http://www.simtec.co.uk/products/EB2410ITX/
 #include <plat/devs.h>
 #include <plat/cpu.h>
 #include <plat/cpu-freq.h>
+#include <plat/audio-simtec.h>
 
 #include "usb-simtec.h"
 #include "nor-simtec.h"
 
-#define COPYRIGHT ", (c) 2004-2005 Simtec Electronics"
+#define COPYRIGHT ", Copyright 2004-2008 Simtec Electronics"
 
 /* macros for virtual address mods for the io space entries */
 #define VA_C5(item) ((unsigned long)(item) + BAST_VAM_CS5)
@@ -247,7 +248,7 @@ static int chip0_map[] = { 1 };
 static int chip1_map[] = { 2 };
 static int chip2_map[] = { 3 };
 
-static struct mtd_partition bast_default_nand_part[] = {
+static struct mtd_partition __initdata bast_default_nand_part[] = {
        [0] = {
                .name   = "Boot Agent",
                .size   = SZ_16K,
@@ -273,7 +274,7 @@ static struct mtd_partition bast_default_nand_part[] = {
  * socket.
 */
 
-static struct s3c2410_nand_set bast_nand_sets[] = {
+static struct s3c2410_nand_set __initdata bast_nand_sets[] = {
        [0] = {
                .name           = "SmartMedia",
                .nr_chips       = 1,
@@ -323,7 +324,7 @@ static void bast_nand_select(struct s3c2410_nand_set *set, int slot)
        __raw_writeb(tmp, BAST_VA_CTRL2);
 }
 
-static struct s3c2410_platform_nand bast_nand_info = {
+static struct s3c2410_platform_nand __initdata bast_nand_info = {
        .tacls          = 30,
        .twrph0         = 60,
        .twrph1         = 60,
@@ -608,6 +609,11 @@ static struct s3c_cpufreq_board __initdata bast_cpufreq = {
        .need_io        = 1,
 };
 
+static struct s3c24xx_audio_simtec_pdata __initdata bast_audio = {
+       .have_mic       = 1,
+       .have_lout      = 1,
+};
+
 static void __init bast_map_io(void)
 {
        /* initialise the clocks */
@@ -625,7 +631,6 @@ static void __init bast_map_io(void)
 
        s3c24xx_register_clocks(bast_clocks, ARRAY_SIZE(bast_clocks));
 
-       s3c_device_nand.dev.platform_data = &bast_nand_info;
        s3c_device_hwmon.dev.platform_data = &bast_hwmon_info;
 
        s3c24xx_init_io(bast_iodesc, ARRAY_SIZE(bast_iodesc));
@@ -639,6 +644,7 @@ static void __init bast_init(void)
        sysdev_register(&bast_pm_sysdev);
 
        s3c_i2c0_set_platdata(&bast_i2c_info);
+       s3c_nand_set_platdata(&bast_nand_info);
        s3c24xx_fb_set_platdata(&bast_fb_info);
        platform_add_devices(bast_devices, ARRAY_SIZE(bast_devices));
 
@@ -647,6 +653,7 @@ static void __init bast_init(void)
 
        usb_simtec_init();
        nor_simtec_init();
+       simtec_audio_add(NULL, true, &bast_audio);
 
        s3c_cpufreq_setboard(&bast_cpufreq);
 }
index d9cd5dd..4905325 100644 (file)
 #include <linux/serial_core.h>
 #include <linux/platform_device.h>
 #include <linux/io.h>
+#include <linux/gpio.h>
+#include <linux/pwm_backlight.h>
+#include <video/platform_lcd.h>
+
+#include <linux/mmc/host.h>
 
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
 
 #include <plat/regs-serial.h>
 #include <mach/regs-lcd.h>
-#include <mach/regs-gpio.h>
 #include <mach/regs-clock.h>
 
+#include <mach/regs-gpio.h>
+#include <mach/gpio-fns.h>
+#include <mach/gpio-nrs.h>
+
 #include <mach/h1940.h>
 #include <mach/h1940-latch.h>
 #include <mach/fb.h>
@@ -46,6 +54,7 @@
 #include <plat/cpu.h>
 #include <plat/pll.h>
 #include <plat/pm.h>
+#include <plat/mci.h>
 
 static struct map_desc h1940_iodesc[] __initdata = {
        [0] = {
@@ -171,16 +180,90 @@ static struct s3c2410fb_mach_info h1940_fb_info __initdata = {
        .gpdup_mask=    0xffffffff,
 };
 
-static struct platform_device s3c_device_leds = {
+static struct platform_device h1940_device_leds = {
        .name             = "h1940-leds",
        .id               = -1,
 };
 
-static struct platform_device s3c_device_bluetooth = {
+static struct platform_device h1940_device_bluetooth = {
        .name             = "h1940-bt",
        .id               = -1,
 };
 
+static struct s3c24xx_mci_pdata h1940_mmc_cfg = {
+       .gpio_detect   = S3C2410_GPF(5),
+       .gpio_wprotect = S3C2410_GPH(8),
+       .set_power     = NULL,
+       .ocr_avail     = MMC_VDD_32_33,
+};
+
+static int h1940_backlight_init(struct device *dev)
+{
+       gpio_request(S3C2410_GPB(0), "Backlight");
+
+       s3c2410_gpio_setpin(S3C2410_GPB(0), 0);
+       s3c2410_gpio_pullup(S3C2410_GPB(0), 0);
+       s3c2410_gpio_cfgpin(S3C2410_GPB(0), S3C2410_GPB0_TOUT0);
+
+       return 0;
+}
+
+static void h1940_backlight_exit(struct device *dev)
+{
+       s3c2410_gpio_cfgpin(S3C2410_GPB(0), 1/*S3C2410_GPB0_OUTP*/);
+}
+
+static struct platform_pwm_backlight_data backlight_data = {
+       .pwm_id         = 0,
+       .max_brightness = 100,
+       .dft_brightness = 50,
+       /* tcnt = 0x31 */
+       .pwm_period_ns  = 36296,
+       .init           = h1940_backlight_init,
+       .exit           = h1940_backlight_exit,
+};
+
+static struct platform_device h1940_backlight = {
+       .name = "pwm-backlight",
+       .dev  = {
+               .parent = &s3c_device_timer[0].dev,
+               .platform_data = &backlight_data,
+       },
+       .id   = -1,
+};
+
+static void h1940_lcd_power_set(struct plat_lcd_data *pd,
+                                       unsigned int power)
+{
+       int value;
+
+       if (!power) {
+               /* set to 3ec */
+               s3c2410_gpio_setpin(S3C2410_GPC(0), 0);
+               /* wait for 3ac */
+               do {
+                       value = s3c2410_gpio_getpin(S3C2410_GPC(6));
+               } while (value);
+               /* set to 38c */
+               s3c2410_gpio_setpin(S3C2410_GPC(5), 0);
+       } else {
+               /* Set to 3ac */
+               s3c2410_gpio_setpin(S3C2410_GPC(5), 1);
+               /* Set to 3ad */
+               s3c2410_gpio_setpin(S3C2410_GPC(0), 1);
+       }
+}
+
+static struct plat_lcd_data h1940_lcd_power_data = {
+       .set_power      = h1940_lcd_power_set,
+};
+
+static struct platform_device h1940_lcd_powerdev = {
+       .name                   = "platform-lcd",
+       .dev.parent             = &s3c_device_lcd.dev,
+       .dev.platform_data      = &h1940_lcd_power_data,
+};
+
 static struct platform_device *h1940_devices[] __initdata = {
        &s3c_device_usb,
        &s3c_device_lcd,
@@ -188,8 +271,13 @@ static struct platform_device *h1940_devices[] __initdata = {
        &s3c_device_i2c0,
        &s3c_device_iis,
        &s3c_device_usbgadget,
-       &s3c_device_leds,
-       &s3c_device_bluetooth,
+       &h1940_device_leds,
+       &h1940_device_bluetooth,
+       &s3c_device_sdi,
+       &s3c_device_rtc,
+       &s3c_device_timer[0],
+       &h1940_backlight,
+       &h1940_lcd_powerdev,
 };
 
 static void __init h1940_map_io(void)
@@ -219,6 +307,8 @@ static void __init h1940_init(void)
        s3c24xx_udc_set_platdata(&h1940_udc_cfg);
        s3c_i2c0_set_platdata(NULL);
 
+       s3c_device_sdi.dev.platform_data = &h1940_mmc_cfg;
+
        /* Turn off suspend on both USB ports, and switch the
         * selectable USB port to USB device mode. */
 
@@ -231,6 +321,11 @@ static void __init h1940_init(void)
              | (0x03 << S3C24XX_PLLCON_SDIVSHIFT);
        writel(tmp, S3C2410_UPLLCON);
 
+       gpio_request(S3C2410_GPC(0), "LCD power");
+       gpio_request(S3C2410_GPC(5), "LCD power");
+       gpio_request(S3C2410_GPC(6), "LCD power");
+
+
        platform_add_devices(h1940_devices, ARRAY_SIZE(h1940_devices));
 }
 
index 0f6ed61..0405712 100644 (file)
@@ -338,7 +338,7 @@ static struct platform_device *n35_devices[] __initdata = {
        &n35_button_device,
 };
 
-static struct s3c2410_platform_i2c n30_i2ccfg = {
+static struct s3c2410_platform_i2c __initdata n30_i2ccfg = {
        .flags          = 0,
        .slave_addr     = 0x10,
        .frequency      = 10*1000,
@@ -500,8 +500,8 @@ static void __init n30_init_irq(void)
 static void __init n30_init(void)
 {
        s3c24xx_fb_set_platdata(&n30_fb_info);
-       s3c_device_i2c0.dev.platform_data = &n30_i2ccfg;
        s3c24xx_udc_set_platdata(&n30_udc_cfg);
+       s3c_i2c0_set_platdata(&n30_i2ccfg);
 
        /* Turn off suspend on both USB ports, and switch the
         * selectable USB port to USB device mode. */
index 2cc9849..ab092bc 100644 (file)
@@ -258,7 +258,7 @@ static struct platform_device *qt2410_devices[] __initdata = {
        &qt2410_led,
 };
 
-static struct mtd_partition qt2410_nand_part[] = {
+static struct mtd_partition __initdata qt2410_nand_part[] = {
        [0] = {
                .name   = "U-Boot",
                .size   = 0x30000,
@@ -286,7 +286,7 @@ static struct mtd_partition qt2410_nand_part[] = {
        },
 };
 
-static struct s3c2410_nand_set qt2410_nand_sets[] = {
+static struct s3c2410_nand_set __initdata qt2410_nand_sets[] = {
        [0] = {
                .name           = "NAND",
                .nr_chips       = 1,
@@ -299,7 +299,7 @@ static struct s3c2410_nand_set qt2410_nand_sets[] = {
  * chips and beyond.
  */
 
-static struct s3c2410_platform_nand qt2410_nand_info = {
+static struct s3c2410_platform_nand __initdata qt2410_nand_info = {
        .tacls          = 20,
        .twrph0         = 60,
        .twrph1         = 20,
@@ -331,7 +331,7 @@ static void __init qt2410_map_io(void)
 
 static void __init qt2410_machine_init(void)
 {
-       s3c_device_nand.dev.platform_data = &qt2410_nand_info;
+       s3c_nand_set_platdata(&qt2410_nand_info);
 
        switch (tft_type) {
        case 'p': /* production */
index 1628cc7..0d61fb5 100644 (file)
@@ -1,6 +1,6 @@
 /* linux/arch/arm/mach-s3c2410/mach-vr1000.c
  *
- * Copyright (c) 2003-2005,2008 Simtec Electronics
+ * Copyright (c) 2003-2008 Simtec Electronics
  *   Ben Dooks <ben@simtec.co.uk>
  *
  * Machine support for Thorcom VR1000 board. Designed for Thorcom by
@@ -49,6 +49,7 @@
 #include <plat/devs.h>
 #include <plat/cpu.h>
 #include <plat/iic.h>
+#include <plat/audio-simtec.h>
 
 #include "usb-simtec.h"
 #include "nor-simtec.h"
@@ -393,6 +394,7 @@ static void __init vr1000_init(void)
                                ARRAY_SIZE(vr1000_i2c_devs));
 
        nor_simtec_init();
+       simtec_audio_add(NULL, true, NULL);
 }
 
 MACHINE_START(VR1000, "Thorcom-VR1000")
index f178c2f..8338865 100644 (file)
@@ -1,6 +1,6 @@
 /* arch/arm/mach-s3c2410/pll.c
  *
- * Copyright (c) 2006,2007 Simtec Electronics
+ * Copyright (c) 2006-2007 Simtec Electronics
  *     http://armlinux.simtec.co.uk/
  *     Ben Dooks <ben@simtec.co.uk>
  *     Vincent Sanders <vince@arm.linux.org.uk>
index 50e25fc..6b9d0d8 100644 (file)
@@ -1,6 +1,6 @@
 /* linux/arch/arm/mach-s3c2410/usb-simtec.c
  *
- * Copyright (c) 2004,2005 Simtec Electronics
+ * Copyright 2004-2005 Simtec Electronics
  *   Ben Dooks <ben@simtec.co.uk>
  *
  * http://www.simtec.co.uk/products/EB2410ITX/
@@ -108,7 +108,7 @@ int usb_simtec_init(void)
 {
        int ret;
 
-       printk("USB Power Control, (c) 2004 Simtec Electronics\n");
+       printk("USB Power Control, Copyright 2004 Simtec Electronics\n");
 
        ret = gpio_request(S3C2410_GPB(4), "USB power control");
        if (ret < 0) {
index 8df506e..c9fa3fc 100644 (file)
@@ -96,7 +96,7 @@ static struct s3c2410_uartcfg jive_uartcfgs[] = {
  * 0x017d0000-0x02bd0000 : cramfs B
  * 0x02bd0000-0x03fd0000 : yaffs
  */
-static struct mtd_partition jive_imageA_nand_part[] = {
+static struct mtd_partition __initdata jive_imageA_nand_part[] = {
 
 #ifdef CONFIG_MACH_JIVE_SHOW_BOOTLOADER
        /* Don't allow access to the bootloader from linux */
@@ -154,7 +154,7 @@ static struct mtd_partition jive_imageA_nand_part[] = {
         },
 };
 
-static struct mtd_partition jive_imageB_nand_part[] = {
+static struct mtd_partition __initdata jive_imageB_nand_part[] = {
 
 #ifdef CONFIG_MACH_JIVE_SHOW_BOOTLOADER
        /* Don't allow access to the bootloader from linux */
@@ -213,7 +213,7 @@ static struct mtd_partition jive_imageB_nand_part[] = {
         },
 };
 
-static struct s3c2410_nand_set jive_nand_sets[] = {
+static struct s3c2410_nand_set __initdata jive_nand_sets[] = {
        [0] = {
                .name           = "flash",
                .nr_chips       = 1,
@@ -222,7 +222,7 @@ static struct s3c2410_nand_set jive_nand_sets[] = {
        },
 };
 
-static struct s3c2410_platform_nand jive_nand_info = {
+static struct s3c2410_platform_nand __initdata jive_nand_info = {
        /* set taken from osiris nand timings, possibly still conservative */
        .tacls          = 30,
        .twrph0         = 55,
@@ -631,7 +631,8 @@ static void __init jive_machine_init(void)
 
        s3c_pm_init();
 
-       s3c_device_nand.dev.platform_data = &jive_nand_info;
+       /** TODO - check that this is after the cmdline option! */
+       s3c_nand_set_platdata(&jive_nand_info);
 
        /* initialise the spi */
 
index 11e8ad4..a6ba591 100644 (file)
@@ -76,7 +76,7 @@ static struct s3c2410_uartcfg vstms_uartcfgs[] __initdata = {
        }
 };
 
-static struct mtd_partition vstms_nand_part[] = {
+static struct mtd_partition __initdata vstms_nand_part[] = {
        [0] = {
                .name   = "Boot Agent",
                .size   = 0x7C000,
@@ -99,7 +99,7 @@ static struct mtd_partition vstms_nand_part[] = {
        },
 };
 
-static struct s3c2410_nand_set vstms_nand_sets[] = {
+static struct s3c2410_nand_set __initdata vstms_nand_sets[] = {
        [0] = {
                .name           = "NAND",
                .nr_chips       = 1,
@@ -112,7 +112,7 @@ static struct s3c2410_nand_set vstms_nand_sets[] = {
  * chips and beyond.
 */
 
-static struct s3c2410_platform_nand vstms_nand_info = {
+static struct s3c2410_platform_nand __initdata vstms_nand_info = {
        .tacls          = 20,
        .twrph0         = 60,
        .twrph1         = 20,
@@ -143,8 +143,6 @@ static void __init vstms_fixup(struct machine_desc *desc,
 
 static void __init vstms_map_io(void)
 {
-       s3c_device_nand.dev.platform_data = &vstms_nand_info;
-
        s3c24xx_init_io(vstms_iodesc, ARRAY_SIZE(vstms_iodesc));
        s3c24xx_init_clocks(12000000);
        s3c24xx_init_uarts(vstms_uartcfgs, ARRAY_SIZE(vstms_uartcfgs));
@@ -153,6 +151,8 @@ static void __init vstms_map_io(void)
 static void __init vstms_init(void)
 {
        s3c_i2c0_set_platdata(NULL);
+       s3c_nand_set_platdata(&vstms_nand_info);
+
        platform_add_devices(vstms_devices, ARRAY_SIZE(vstms_devices));
 }
 
index a8b69d7..cf10e14 100644 (file)
@@ -53,6 +53,19 @@ config MACH_OSIRIS
          Say Y here if you are using the Simtec IM2440D20 module, also
          known as the Osiris.
 
+config MACH_OSIRIS_DVS
+       tristate "Simtec IM2440D20 (OSIRIS) Dynamic Voltage Scaling driver"
+       depends on MACH_OSIRIS
+       select TPS65010
+       help
+         Say Y/M here if you want to have dynamic voltage scaling support
+         on the Simtec IM2440D20 (OSIRIS) module via the TPS65011.
+
+         The DVS driver alters the voltage supplied to the ARM core
+         depending on the frequency it is running at. The driver itself
+         does not do any of the frequency alteration, which is left up
+         to the cpufreq driver.
+
 config MACH_RX3715
        bool "HP iPAQ rx3715"
        select CPU_S3C2440
index bfadcf6..5f32245 100644 (file)
@@ -23,3 +23,7 @@ obj-$(CONFIG_ARCH_S3C2440)    += mach-smdk2440.o
 obj-$(CONFIG_MACH_NEXCODER_2440) += mach-nexcoder.o
 obj-$(CONFIG_MACH_AT2440EVB) += mach-at2440evb.o
 obj-$(CONFIG_MACH_MINI2440) += mach-mini2440.o
+
+# extra machine support
+
+obj-$(CONFIG_MACH_OSIRIS_DVS)  += mach-osiris-dvs.o
index 63c5ab6..0c049b9 100644 (file)
@@ -1,6 +1,6 @@
 /* linux/arch/arm/mach-s3c2440/irq.c
  *
- * Copyright (c) 2003,2004 Simtec Electronics
+ * Copyright (c) 2003-2004 Simtec Electronics
  *     Ben Dooks <ben@simtec.co.uk>
  *
  * This program is free software; you can redistribute it and/or modify
index 68f3870..62a4c3e 100644 (file)
@@ -1,6 +1,6 @@
 /* linux/arch/arm/mach-s3c2440/mach-anubis.c
  *
- * Copyright (c) 2003-2005,2008 Simtec Electronics
+ * Copyright 2003-2009 Simtec Electronics
  *     http://armlinux.simtec.co.uk/
  *     Ben Dooks <ben@simtec.co.uk>
  *
@@ -53,8 +53,9 @@
 #include <plat/clock.h>
 #include <plat/devs.h>
 #include <plat/cpu.h>
+#include <plat/audio-simtec.h>
 
-#define COPYRIGHT ", (c) 2005 Simtec Electronics"
+#define COPYRIGHT ", Copyright 2005-2009 Simtec Electronics"
 
 static struct map_desc anubis_iodesc[] __initdata = {
   /* ISA IO areas */
@@ -138,7 +139,7 @@ static int external_map[]   = { 2 };
 static int chip0_map[]      = { 0 };
 static int chip1_map[]      = { 1 };
 
-static struct mtd_partition anubis_default_nand_part[] = {
+static struct mtd_partition __initdata anubis_default_nand_part[] = {
        [0] = {
                .name   = "Boot Agent",
                .size   = SZ_16K,
@@ -161,7 +162,7 @@ static struct mtd_partition anubis_default_nand_part[] = {
        }
 };
 
-static struct mtd_partition anubis_default_nand_part_large[] = {
+static struct mtd_partition __initdata anubis_default_nand_part_large[] = {
        [0] = {
                .name   = "Boot Agent",
                .size   = SZ_128K,
@@ -191,7 +192,7 @@ static struct mtd_partition anubis_default_nand_part_large[] = {
  * socket.
 */
 
-static struct s3c2410_nand_set anubis_nand_sets[] = {
+static struct s3c2410_nand_set __initdata anubis_nand_sets[] = {
        [1] = {
                .name           = "External",
                .nr_chips       = 1,
@@ -233,7 +234,7 @@ static void anubis_nand_select(struct s3c2410_nand_set *set, int slot)
        __raw_writeb(tmp, ANUBIS_VA_CTRL1);
 }
 
-static struct s3c2410_platform_nand anubis_nand_info = {
+static struct s3c2410_platform_nand __initdata anubis_nand_info = {
        .tacls          = 25,
        .twrph0         = 55,
        .twrph1         = 40,
@@ -437,6 +438,17 @@ static struct i2c_board_info anubis_i2c_devs[] __initdata = {
        }
 };
 
+/* Audio setup */
+static struct s3c24xx_audio_simtec_pdata __initdata anubis_audio = {
+       .have_mic       = 1,
+       .have_lout      = 1,
+       .output_cdclk   = 1,
+       .use_mpllin     = 1,
+       .amp_gpio       = S3C2410_GPB(2),
+       .amp_gain[0]    = S3C2410_GPD(10),
+       .amp_gain[1]    = S3C2410_GPD(11),
+};
+
 static void __init anubis_map_io(void)
 {
        /* initialise the clocks */
@@ -454,8 +466,6 @@ static void __init anubis_map_io(void)
 
        s3c24xx_register_clocks(anubis_clocks, ARRAY_SIZE(anubis_clocks));
 
-       s3c_device_nand.dev.platform_data = &anubis_nand_info;
-
        s3c24xx_init_io(anubis_iodesc, ARRAY_SIZE(anubis_iodesc));
        s3c24xx_init_clocks(0);
        s3c24xx_init_uarts(anubis_uartcfgs, ARRAY_SIZE(anubis_uartcfgs));
@@ -476,6 +486,9 @@ static void __init anubis_map_io(void)
 static void __init anubis_init(void)
 {
        s3c_i2c0_set_platdata(NULL);
+       s3c_nand_set_platdata(&anubis_nand_info);
+       simtec_audio_add(NULL, false, &anubis_audio);
+
        platform_add_devices(anubis_devices, ARRAY_SIZE(anubis_devices));
 
        i2c_register_board_info(0, anubis_i2c_devs,
index dfc7010..aa69290 100644 (file)
@@ -96,7 +96,7 @@ static struct s3c2410_uartcfg at2440evb_uartcfgs[] __initdata = {
 
 /* NAND Flash on AT2440EVB board */
 
-static struct mtd_partition at2440evb_default_nand_part[] = {
+static struct mtd_partition __initdata at2440evb_default_nand_part[] = {
        [0] = {
                .name   = "Boot Agent",
                .size   = SZ_256K,
@@ -114,7 +114,7 @@ static struct mtd_partition at2440evb_default_nand_part[] = {
        },
 };
 
-static struct s3c2410_nand_set at2440evb_nand_sets[] = {
+static struct s3c2410_nand_set __initdata at2440evb_nand_sets[] = {
        [0] = {
                .name           = "nand",
                .nr_chips       = 1,
@@ -123,7 +123,7 @@ static struct s3c2410_nand_set at2440evb_nand_sets[] = {
        },
 };
 
-static struct s3c2410_platform_nand at2440evb_nand_info = {
+static struct s3c2410_platform_nand __initdata at2440evb_nand_info = {
        .tacls          = 25,
        .twrph0         = 55,
        .twrph1         = 40,
@@ -216,8 +216,6 @@ static struct platform_device *at2440evb_devices[] __initdata = {
 
 static void __init at2440evb_map_io(void)
 {
-       s3c_device_nand.dev.platform_data = &at2440evb_nand_info;
-       s3c_device_sdi.name = "s3c2440-sdi";
        s3c_device_sdi.dev.platform_data = &at2440evb_mci_pdata;
 
        s3c24xx_init_io(at2440evb_iodesc, ARRAY_SIZE(at2440evb_iodesc));
@@ -228,6 +226,7 @@ static void __init at2440evb_map_io(void)
 static void __init at2440evb_init(void)
 {
        s3c24xx_fb_set_platdata(&at2440evb_fb_info);
+       s3c_nand_set_platdata(&at2440evb_nand_info);
        s3c_i2c0_set_platdata(NULL);
 
        platform_add_devices(at2440evb_devices, ARRAY_SIZE(at2440evb_devices));
index 1c3382f..547d4fc 100644 (file)
@@ -532,7 +532,6 @@ static void __init mini2440_map_io(void)
        s3c24xx_init_clocks(12000000);
        s3c24xx_init_uarts(mini2440_uartcfgs, ARRAY_SIZE(mini2440_uartcfgs));
 
-       s3c_device_nand.dev.platform_data = &mini2440_nand_info;
        s3c_device_sdi.dev.platform_data = &mini2440_mmc_cfg;
 }
 
@@ -677,8 +676,11 @@ static void __init mini2440_init(void)
                printk("\n");
                s3c24xx_fb_set_platdata(&mini2440_fb_info);
        }
+
        s3c24xx_udc_set_platdata(&mini2440_udc_cfg);
+       s3c_nand_set_platdata(&mini2440_nand_info);
        s3c_i2c0_set_platdata(NULL);
+
        i2c_register_board_info(0, mini2440_i2c_devs,
                                ARRAY_SIZE(mini2440_i2c_devs));
 
diff --git a/arch/arm/mach-s3c2440/mach-osiris-dvs.c b/arch/arm/mach-s3c2440/mach-osiris-dvs.c
new file mode 100644 (file)
index 0000000..ad2792d
--- /dev/null
@@ -0,0 +1,194 @@
+/* linux/arch/arm/mach-s3c2440/mach-osiris-dvs.c
+ *
+ * Copyright (c) 2009 Simtec Electronics
+ *     http://armlinux.simtec.co.uk/
+ *     Ben Dooks <ben@simtec.co.uk>
+ *
+ * Simtec Osiris Dynamic Voltage Scaling support.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/cpufreq.h>
+#include <linux/gpio.h>
+
+#include <linux/i2c/tps65010.h>
+
+#include <plat/cpu-freq.h>
+
+#define OSIRIS_GPIO_DVS        S3C2410_GPB(5)
+
+static bool dvs_en;
+
+static void osiris_dvs_tps_setdvs(bool on)
+{
+       unsigned vregs1 = 0, vdcdc2 = 0;
+
+       if (!on) {
+               vdcdc2 = TPS_VCORE_DISCH | TPS_LP_COREOFF;
+               vregs1 = TPS_LDO1_OFF;  /* turn off in low-power mode */
+       }
+
+       dvs_en = on;
+       vdcdc2 |= TPS_VCORE_1_3V | TPS_VCORE_LP_1_0V;
+       vregs1 |= TPS_LDO2_ENABLE | TPS_LDO1_ENABLE;
+
+       tps65010_config_vregs1(vregs1);
+       tps65010_config_vdcdc2(vdcdc2);
+}
+
+static bool is_dvs(struct s3c_freq *f)
+{
+       /* at the moment, we assume ARMCLK = HCLK => DVS */
+       return f->armclk == f->hclk;
+}
+
+/* keep track of current state */
+static bool cur_dvs = false;
+
+static int osiris_dvs_notify(struct notifier_block *nb,
+                             unsigned long val, void *data)
+{
+       struct cpufreq_freqs *cf = data;
+       struct s3c_cpufreq_freqs *freqs = to_s3c_cpufreq(cf);
+       bool old_dvs = is_dvs(&freqs->old);
+       bool new_dvs = is_dvs(&freqs->new);
+       int ret = 0;
+
+       if (!dvs_en)
+               return 0;
+
+       printk(KERN_DEBUG "%s: old %ld,%ld new %ld,%ld\n", __func__,
+              freqs->old.armclk, freqs->old.hclk,
+              freqs->new.armclk, freqs->new.hclk);
+
+       switch (val) {
+       case CPUFREQ_PRECHANGE:
+               if (old_dvs & !new_dvs ||
+                   cur_dvs & !new_dvs) {
+                       pr_debug("%s: exiting dvs\n", __func__);
+                       cur_dvs = false;
+                       gpio_set_value(OSIRIS_GPIO_DVS, 1);
+               }
+               break;
+       case CPUFREQ_POSTCHANGE:
+               if (!old_dvs & new_dvs ||
+                   !cur_dvs & new_dvs) {
+                       pr_debug("entering dvs\n");
+                       cur_dvs = true;
+                       gpio_set_value(OSIRIS_GPIO_DVS, 0);
+               }
+               break;
+       }
+
+       return ret;
+}
+
+static struct notifier_block osiris_dvs_nb = {
+       .notifier_call  = osiris_dvs_notify,
+};
+
+static int __devinit osiris_dvs_probe(struct platform_device *pdev)
+{
+       int ret;
+
+       dev_info(&pdev->dev, "initialising\n");
+
+       ret = gpio_request(OSIRIS_GPIO_DVS, "osiris-dvs");
+       if (ret) {
+               dev_err(&pdev->dev, "cannot claim gpio\n");
+               goto err_nogpio;
+       }
+
+       /* start with dvs disabled */
+       gpio_direction_output(OSIRIS_GPIO_DVS, 1);
+
+       ret = cpufreq_register_notifier(&osiris_dvs_nb,
+                                       CPUFREQ_TRANSITION_NOTIFIER);
+       if (ret) {
+               dev_err(&pdev->dev, "failed to register with cpufreq\n");
+               goto err_nofreq;
+       }
+
+       osiris_dvs_tps_setdvs(true);
+
+       return 0;
+
+err_nofreq:
+       gpio_free(OSIRIS_GPIO_DVS);
+
+err_nogpio:
+       return ret;
+}
+
+static int __devexit osiris_dvs_remove(struct platform_device *pdev)
+{
+       dev_info(&pdev->dev, "exiting\n");
+
+       /* disable any current dvs */
+       gpio_set_value(OSIRIS_GPIO_DVS, 1);
+       osiris_dvs_tps_setdvs(false);
+
+       cpufreq_unregister_notifier(&osiris_dvs_nb,
+                                   CPUFREQ_TRANSITION_NOTIFIER);
+
+       gpio_free(OSIRIS_GPIO_DVS);
+
+       return 0;
+}
+
+/* the CONFIG_PM block is so small, it isn't worth actaully compiling it
+ * out if the configuration isn't set. */
+
+static int osiris_dvs_suspend(struct device *dev)
+{
+       gpio_set_value(OSIRIS_GPIO_DVS, 1);
+       osiris_dvs_tps_setdvs(false);
+       cur_dvs = false;
+
+       return 0;
+}
+
+static int osiris_dvs_resume(struct device *dev)
+{
+       osiris_dvs_tps_setdvs(true);
+       return 0;
+}
+
+static const struct dev_pm_ops osiris_dvs_pm = {
+       .suspend        = osiris_dvs_suspend,
+       .resume         = osiris_dvs_resume,
+};
+
+static struct platform_driver osiris_dvs_driver = {
+       .probe          = osiris_dvs_probe,
+       .remove         = __devexit_p(osiris_dvs_remove),
+       .driver         = {
+               .name   = "osiris-dvs",
+               .owner  = THIS_MODULE,
+               .pm     = &osiris_dvs_pm,
+       },
+};
+
+static int __init osiris_dvs_init(void)
+{
+       return platform_driver_register(&osiris_dvs_driver);
+}
+
+static void __exit osiris_dvs_exit(void)
+{
+       platform_driver_unregister(&osiris_dvs_driver);
+}
+
+module_init(osiris_dvs_init);
+module_exit(osiris_dvs_exit);
+
+MODULE_DESCRIPTION("Simtec OSIRIS DVS support");
+MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:osiris-dvs");
index 2105a41..015dfb2 100644 (file)
@@ -1,6 +1,6 @@
 /* linux/arch/arm/mach-s3c2440/mach-osiris.c
  *
- * Copyright (c) 2005,2008 Simtec Electronics
+ * Copyright (c) 2005-2008 Simtec Electronics
  *     http://armlinux.simtec.co.uk/
  *     Ben Dooks <ben@simtec.co.uk>
  *
@@ -23,6 +23,8 @@
 #include <linux/i2c.h>
 #include <linux/io.h>
 
+#include <linux/i2c/tps65010.h>
+
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
 #include <asm/mach/irq.h>
@@ -148,7 +150,7 @@ static int external_map[]   = { 2 };
 static int chip0_map[]      = { 0 };
 static int chip1_map[]      = { 1 };
 
-static struct mtd_partition osiris_default_nand_part[] = {
+static struct mtd_partition __initdata osiris_default_nand_part[] = {
        [0] = {
                .name   = "Boot Agent",
                .size   = SZ_16K,
@@ -171,7 +173,7 @@ static struct mtd_partition osiris_default_nand_part[] = {
        }
 };
 
-static struct mtd_partition osiris_default_nand_part_large[] = {
+static struct mtd_partition __initdata osiris_default_nand_part_large[] = {
        [0] = {
                .name   = "Boot Agent",
                .size   = SZ_128K,
@@ -201,7 +203,7 @@ static struct mtd_partition osiris_default_nand_part_large[] = {
  * socket.
 */
 
-static struct s3c2410_nand_set osiris_nand_sets[] = {
+static struct s3c2410_nand_set __initdata osiris_nand_sets[] = {
        [1] = {
                .name           = "External",
                .nr_chips       = 1,
@@ -243,7 +245,7 @@ static void osiris_nand_select(struct s3c2410_nand_set *set, int slot)
        __raw_writeb(tmp, OSIRIS_VA_CTRL0);
 }
 
-static struct s3c2410_platform_nand osiris_nand_info = {
+static struct s3c2410_platform_nand __initdata osiris_nand_info = {
        .tacls          = 25,
        .twrph0         = 60,
        .twrph1         = 60,
@@ -326,12 +328,44 @@ static struct sys_device osiris_pm_sysdev = {
        .cls            = &osiris_pm_sysclass,
 };
 
+/* Link for DVS driver to TPS65011 */
+
+static void osiris_tps_release(struct device *dev)
+{
+       /* static device, do not need to release anything */
+}
+
+static struct platform_device osiris_tps_device = {
+       .name   = "osiris-dvs",
+       .id     = -1,
+       .dev.release = osiris_tps_release,
+};
+
+static int osiris_tps_setup(struct i2c_client *client, void *context)
+{
+       osiris_tps_device.dev.parent = &client->dev;
+       return platform_device_register(&osiris_tps_device);
+}
+
+static int osiris_tps_remove(struct i2c_client *client, void *context)
+{
+       platform_device_unregister(&osiris_tps_device);
+       return 0;
+}
+
+static struct tps65010_board osiris_tps_board = {
+       .base           = -1,   /* GPIO can go anywhere at the moment */
+       .setup          = osiris_tps_setup,
+       .teardown       = osiris_tps_remove,
+};
+
 /* I2C devices fitted. */
 
 static struct i2c_board_info osiris_i2c_devs[] __initdata = {
        {
                I2C_BOARD_INFO("tps65011", 0x48),
                .irq    = IRQ_EINT20,
+               .platform_data = &osiris_tps_board,
        },
 };
 
@@ -377,8 +411,6 @@ static void __init osiris_map_io(void)
 
        s3c24xx_register_clocks(osiris_clocks, ARRAY_SIZE(osiris_clocks));
 
-       s3c_device_nand.dev.platform_data = &osiris_nand_info;
-
        s3c24xx_init_io(osiris_iodesc, ARRAY_SIZE(osiris_iodesc));
        s3c24xx_init_clocks(0);
        s3c24xx_init_uarts(osiris_uartcfgs, ARRAY_SIZE(osiris_uartcfgs));
@@ -408,6 +440,7 @@ static void __init osiris_init(void)
        sysdev_register(&osiris_pm_sysdev);
 
        s3c_i2c0_set_platdata(NULL);
+       s3c_nand_set_platdata(&osiris_nand_info);
 
        s3c_cpufreq_setboard(&osiris_cpufreq);
 
index bc8d8d1..a952a13 100644 (file)
@@ -1,6 +1,6 @@
 /* linux/arch/arm/mach-s3c2440/mach-rx3715.c
  *
- * Copyright (c) 2003,2004 Simtec Electronics
+ * Copyright (c) 2003-2004 Simtec Electronics
  *     Ben Dooks <ben@simtec.co.uk>
  *
  * http://www.handhelds.org/projects/rx3715.html
@@ -149,7 +149,7 @@ static struct s3c2410fb_mach_info rx3715_fb_info __initdata = {
        .gpdup_mask =   0xffffffff,
 };
 
-static struct mtd_partition rx3715_nand_part[] = {
+static struct mtd_partition __initdata rx3715_nand_part[] = {
        [0] = {
                .name           = "Whole Flash",
                .offset         = 0,
@@ -158,7 +158,7 @@ static struct mtd_partition rx3715_nand_part[] = {
        }
 };
 
-static struct s3c2410_nand_set rx3715_nand_sets[] = {
+static struct s3c2410_nand_set __initdata rx3715_nand_sets[] = {
        [0] = {
                .name           = "Internal",
                .nr_chips       = 1,
@@ -167,7 +167,7 @@ static struct s3c2410_nand_set rx3715_nand_sets[] = {
        },
 };
 
-static struct s3c2410_platform_nand rx3715_nand_info = {
+static struct s3c2410_platform_nand __initdata rx3715_nand_info = {
        .tacls          = 25,
        .twrph0         = 50,
        .twrph1         = 15,
@@ -186,8 +186,6 @@ static struct platform_device *rx3715_devices[] __initdata = {
 
 static void __init rx3715_map_io(void)
 {
-       s3c_device_nand.dev.platform_data = &rx3715_nand_info;
-
        s3c24xx_init_io(rx3715_iodesc, ARRAY_SIZE(rx3715_iodesc));
        s3c24xx_init_clocks(16934000);
        s3c24xx_init_uarts(rx3715_uartcfgs, ARRAY_SIZE(rx3715_uartcfgs));
@@ -205,6 +203,7 @@ static void __init rx3715_init_machine(void)
 #endif
        s3c_pm_init();
 
+       s3c_nand_set_platdata(&rx3715_nand_info);
        s3c24xx_fb_set_platdata(&rx3715_fb_info);
        platform_add_devices(rx3715_devices, ARRAY_SIZE(rx3715_devices));
 }
index db6eafb..ec13e74 100644 (file)
@@ -1,6 +1,6 @@
 /* linux/arch/arm/mach-s3c2440/mach-smdk2440.c
  *
- * Copyright (c) 2004,2005 Simtec Electronics
+ * Copyright (c) 2004-2005 Simtec Electronics
  *     Ben Dooks <ben@simtec.co.uk>
  *
  * http://www.fluff.org/ben/smdk2440/
index 0fb385b..f76d6ff 100644 (file)
@@ -423,7 +423,7 @@ static struct i2c_board_info gta02_i2c_devs[] __initdata = {
        },
 };
 
-static struct s3c2410_nand_set gta02_nand_sets[] = {
+static struct s3c2410_nand_set __initdata gta02_nand_sets[] = {
        [0] = {
                /*
                 * This name is also hard-coded in the boot loaders, so
@@ -442,7 +442,7 @@ static struct s3c2410_nand_set gta02_nand_sets[] = {
  * data sheet (K5D2G13ACM-D075 MCP Memory).
  */
 
-static struct s3c2410_platform_nand gta02_nand_info = {
+static struct s3c2410_platform_nand __initdata gta02_nand_info = {
        .tacls          = 0,
        .twrph0         = 25,
        .twrph1         = 15,
@@ -621,9 +621,9 @@ static void __init gta02_machine_init(void)
 #endif
 
        s3c_device_usb.dev.platform_data = &gta02_usb_info;
-       s3c_device_nand.dev.platform_data = &gta02_nand_info;
 
        s3c24xx_udc_set_platdata(&gta02_udc_cfg);
+       s3c_nand_set_platdata(&gta02_nand_info);
        s3c_i2c0_set_platdata(NULL);
 
        i2c_register_board_info(0, gta02_i2c_devs, ARRAY_SIZE(gta02_i2c_devs));
index 79e4d93..d88c8b2 100644 (file)
@@ -1,6 +1,6 @@
 /* linux/arch/arm/mach-s3c24a0/include/mach/map.h
  *
- * Copyright 2003,2007  Simtec Electronics
+ * Copyright 2003-2007  Simtec Electronics
  *     http://armlinux.simtec.co.uk/
  *     Ben Dooks <ben@simtec.co.uk>
  *
index af2abd7..be0af51 100644 (file)
@@ -1,7 +1,7 @@
 /* linux/arch/arm/mach-s3c24a0/include/mach/regs-clock.h
  *
- * Copyright (c) 2003,2004,2005,2006 Simtec Electronics <linux@simtec.co.uk>
- *                   http://armlinux.simtec.co.uk/
+ * Copyright (c) 2003-2006 Simtec Electronics <linux@simtec.co.uk>
+ *     http://armlinux.simtec.co.uk/
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
index fc8b223..106ee13 100644 (file)
@@ -48,6 +48,8 @@
 #define S3C64XX_PA_IIS1                (0x7F003000)
 #define S3C64XX_PA_TIMER       (0x7F006000)
 #define S3C64XX_PA_IIC0                (0x7F004000)
+#define S3C64XX_PA_PCM0                (0x7F009000)
+#define S3C64XX_PA_PCM1                (0x7F00A000)
 #define S3C64XX_PA_IISV4       (0x7F00D000)
 #define S3C64XX_PA_IIC1                (0x7F00F000)
 
@@ -64,6 +66,9 @@
 
 #define S3C64XX_PA_USBHOST     (0x74300000)
 
+#define S3C64XX_PA_USB_HSPHY   (0x7C100000)
+#define S3C64XX_VA_USB_HSPHY   S3C_ADDR_CPU(0x00200000)
+
 /* place VICs close together */
 #define S3C_VA_VIC0            (S3C_VA_IRQ + 0x00)
 #define S3C_VA_VIC1            (S3C_VA_IRQ + 0x10000)
@@ -79,5 +84,6 @@
 #define S3C_PA_FB              S3C64XX_PA_FB
 #define S3C_PA_USBHOST         S3C64XX_PA_USBHOST
 #define S3C_PA_USB_HSOTG       S3C64XX_PA_USB_HSOTG
+#define S3C_VA_USB_HSPHY       S3C64XX_VA_USB_HSPHY
 
 #endif /* __ASM_ARCH_6400_MAP_H */
index 4701979..f566115 100644 (file)
-/* arch/arm/mach-s3c6400/include/mach/regs-fb.h
- *
+/*
  * Copyright 2008 Openmoko, Inc.
  * Copyright 2008 Simtec Electronics
- *      http://armlinux.simtec.co.uk/
- *      Ben Dooks <ben@simtec.co.uk>
- *
- * S3C64XX - new-style framebuffer register definitions
+ * Copyright 2009 Samsung Electronics Co.
  *
- * This is the register set for the new style framebuffer interface
- * found from the S3C2443 onwards and specifically the S3C64XX series
- * S3C6400 and S3C6410.
+ * Pawel Osciak <p.osciak@samsung.com>
+ * Based on plat-s3c/include/plat/regs-fb.h by Ben Dooks <ben@simtec.co.uk>
  *
- * The file contains the cpu specific items which change between whichever
- * architecture is selected. See <plat/regs-fb.h> for the core definitions
- * that are the same.
+ * Framebuffer register definitions for Samsung S3C64xx.
  *
  * 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 the core definitions here, in case we really do need to
- * override them at a later date.
-*/
-
-#include <plat/regs-fb.h>
-
-#define S3C_FB_MAX_WIN (5)  /* number of hardware windows available. */
-#define VIDCON1_FSTATUS_EVEN   (1 << 15)
-
-/* Video timing controls */
-#define VIDTCON0                               (0x10)
-#define VIDTCON1                               (0x14)
-#define VIDTCON2                               (0x18)
-
-/* Window position controls */
-
-#define WINCON(_win)                           (0x20 + ((_win) * 4))
-
-/* OSD1 and OSD4 do not have register D */
-
-#define VIDOSD_A(_win)                         (0x40 + ((_win) * 16))
-#define VIDOSD_B(_win)                         (0x44 + ((_win) * 16))
-#define VIDOSD_C(_win)                         (0x48 + ((_win) * 16))
-#define VIDOSD_D(_win)                         (0x4C + ((_win) * 16))
-
-/* Video buffer addresses */
-
-#define VIDW_BUF_START(_buff)                  (0xA0 + ((_buff) * 8))
-#define VIDW_BUF_START1(_buff)                 (0xA4 + ((_buff) * 8))
-#define VIDW_BUF_END(_buff)                    (0xD0 + ((_buff) * 8))
-#define VIDW_BUF_END1(_buff)                   (0xD4 + ((_buff) * 8))
-#define VIDW_BUF_SIZE(_buff)                   (0x100 + ((_buff) * 4))
-
-#define VIDINTCON0                             (0x130)
-
-#define WxKEYCONy(_win, _con)                  ((0x140 + ((_win) * 8)) + ((_con) * 4))
-
-/* WINCONx */
-
-#define WINCONx_CSCWIDTH_MASK                  (0x3 << 26)
-#define WINCONx_CSCWIDTH_SHIFT                 (26)
-#define WINCONx_CSCWIDTH_WIDE                  (0x0 << 26)
-#define WINCONx_CSCWIDTH_NARROW                        (0x3 << 26)
-
-#define WINCONx_ENLOCAL                                (1 << 22)
-#define WINCONx_BUFSTATUS                      (1 << 21)
-#define WINCONx_BUFSEL                         (1 << 20)
-#define WINCONx_BUFAUTOEN                      (1 << 19)
-#define WINCONx_YCbCr                          (1 << 13)
-
-#define WINCON1_LOCALSEL_CAMIF                 (1 << 23)
-
-#define WINCON2_LOCALSEL_CAMIF                 (1 << 23)
-#define WINCON2_BLD_PIX                                (1 << 6)
-
-#define WINCON2_ALPHA_SEL                      (1 << 1)
-#define WINCON2_BPPMODE_MASK                   (0xf << 2)
-#define WINCON2_BPPMODE_SHIFT                  (2)
-#define WINCON2_BPPMODE_1BPP                   (0x0 << 2)
-#define WINCON2_BPPMODE_2BPP                   (0x1 << 2)
-#define WINCON2_BPPMODE_4BPP                   (0x2 << 2)
-#define WINCON2_BPPMODE_8BPP_1232              (0x4 << 2)
-#define WINCON2_BPPMODE_16BPP_565              (0x5 << 2)
-#define WINCON2_BPPMODE_16BPP_A1555            (0x6 << 2)
-#define WINCON2_BPPMODE_16BPP_I1555            (0x7 << 2)
-#define WINCON2_BPPMODE_18BPP_666              (0x8 << 2)
-#define WINCON2_BPPMODE_18BPP_A1665            (0x9 << 2)
-#define WINCON2_BPPMODE_19BPP_A1666            (0xa << 2)
-#define WINCON2_BPPMODE_24BPP_888              (0xb << 2)
-#define WINCON2_BPPMODE_24BPP_A1887            (0xc << 2)
-#define WINCON2_BPPMODE_25BPP_A1888            (0xd << 2)
-#define WINCON2_BPPMODE_28BPP_A4888            (0xd << 2)
-
-#define WINCON3_BLD_PIX                                (1 << 6)
-
-#define WINCON3_ALPHA_SEL                      (1 << 1)
-#define WINCON3_BPPMODE_MASK                   (0xf << 2)
-#define WINCON3_BPPMODE_SHIFT                  (2)
-#define WINCON3_BPPMODE_1BPP                   (0x0 << 2)
-#define WINCON3_BPPMODE_2BPP                   (0x1 << 2)
-#define WINCON3_BPPMODE_4BPP                   (0x2 << 2)
-#define WINCON3_BPPMODE_16BPP_565              (0x5 << 2)
-#define WINCON3_BPPMODE_16BPP_A1555            (0x6 << 2)
-#define WINCON3_BPPMODE_16BPP_I1555            (0x7 << 2)
-#define WINCON3_BPPMODE_18BPP_666              (0x8 << 2)
-#define WINCON3_BPPMODE_18BPP_A1665            (0x9 << 2)
-#define WINCON3_BPPMODE_19BPP_A1666            (0xa << 2)
-#define WINCON3_BPPMODE_24BPP_888              (0xb << 2)
-#define WINCON3_BPPMODE_24BPP_A1887            (0xc << 2)
-#define WINCON3_BPPMODE_25BPP_A1888            (0xd << 2)
-#define WINCON3_BPPMODE_28BPP_A4888            (0xd << 2)
-
-#define VIDINTCON0_FIFIOSEL_WINDOW2            (0x10 << 5)
-#define VIDINTCON0_FIFIOSEL_WINDOW3            (0x20 << 5)
-#define VIDINTCON0_FIFIOSEL_WINDOW4            (0x40 << 5)
-
-#define DITHMODE                               (0x170)
-#define WINxMAP(_win)                          (0x180 + ((_win) * 4))
-
-
-#define DITHMODE_R_POS_MASK                    (0x3 << 5)
-#define DITHMODE_R_POS_SHIFT                   (5)
-#define DITHMODE_R_POS_8BIT                    (0x0 << 5)
-#define DITHMODE_R_POS_6BIT                    (0x1 << 5)
-#define DITHMODE_R_POS_5BIT                    (0x2 << 5)
-
-#define DITHMODE_G_POS_MASK                    (0x3 << 3)
-#define DITHMODE_G_POS_SHIFT                   (3)
-#define DITHMODE_G_POS_8BIT                    (0x0 << 3)
-#define DITHMODE_G_POS_6BIT                    (0x1 << 3)
-#define DITHMODE_G_POS_5BIT                    (0x2 << 3)
-
-#define DITHMODE_B_POS_MASK                    (0x3 << 1)
-#define DITHMODE_B_POS_SHIFT                   (1)
-#define DITHMODE_B_POS_8BIT                    (0x0 << 1)
-#define DITHMODE_B_POS_6BIT                    (0x1 << 1)
-#define DITHMODE_B_POS_5BIT                    (0x2 << 1)
+#ifndef __ASM_ARCH_MACH_REGS_FB_H
+#define __ASM_ARCH_MACH_REGS_FB_H __FILE__
 
-#define DITHMODE_DITH_EN                       (1 << 0)
-
-#define WPALCON                                        (0x1A0)
-
-#define WPALCON_W4PAL_16BPP_A555               (1 << 8)
-#define WPALCON_W3PAL_16BPP_A555               (1 << 7)
-#define WPALCON_W2PAL_16BPP_A555               (1 << 6)
+#include <plat/regs-fb-v4.h>
 
 /* Palette registers */
-
 #define WIN2_PAL(_entry)                       (0x300 + ((_entry) * 2))
 #define WIN3_PAL(_entry)                       (0x320 + ((_entry) * 2))
 #define WIN4_PAL(_entry)                       (0x340 + ((_entry) * 2))
 #define WIN0_PAL(_entry)                       (0x400 + ((_entry) * 4))
 #define WIN1_PAL(_entry)                       (0x800 + ((_entry) * 4))
 
-/* system specific implementation code for palette sizes, and other
- * information that changes depending on which architecture is being
- * compiled.
-*/
-
-/* return true if window _win has OSD register D */
-#define s3c_fb_has_osd_d(_win) ((_win) != 4 && (_win) != 0)
-
-static inline unsigned int s3c_fb_win_pal_size(unsigned int win)
-{
-       if (win < 2)
-               return 256;
-       if (win < 4)
-               return 16;
-       if (win == 4)
-               return 4;
-
-       BUG();  /* shouldn't get here */
-}
-
-static inline int s3c_fb_validate_win_bpp(unsigned int win, unsigned int bpp)
-{
-       /* all windows can do 1/2 bpp */
-
-       if ((bpp == 25 || bpp == 19) && win == 0)
-               return 0;       /* win 0 does not have 19 or 25bpp modes */
-
-       if (bpp == 4 && win == 4)
-               return 0;
-
-       if (bpp == 8 && (win >= 3))
-               return 0;       /* win 3/4 cannot do 8bpp in any mode */
-
-       return 1;
-}
-
 static inline unsigned int s3c_fb_pal_reg(unsigned int window, int reg)
 {
        switch (window) {
@@ -203,57 +38,4 @@ static inline unsigned int s3c_fb_pal_reg(unsigned int window, int reg)
        BUG();
 }
 
-static inline int s3c_fb_pal_is16(unsigned int window)
-{
-       return window > 1;
-}
-
-struct s3c_fb_palette {
-       struct fb_bitfield      r;
-       struct fb_bitfield      g;
-       struct fb_bitfield      b;
-       struct fb_bitfield      a;
-};
-
-static inline void s3c_fb_init_palette(unsigned int window,
-                                      struct s3c_fb_palette *palette)
-{
-       if (window < 2) {
-               /* Windows 0/1 are 8/8/8 or A/8/8/8 */
-               palette->r.offset = 16;
-               palette->r.length = 8;
-               palette->g.offset = 8;
-               palette->g.length = 8;
-               palette->b.offset = 0;
-               palette->b.length = 8;
-       } else {
-               /* currently we assume RGB 5/6/5 */
-               palette->r.offset = 11;
-               palette->r.length = 5;
-               palette->g.offset = 5;
-               palette->g.length = 6;
-               palette->b.offset = 0;
-               palette->b.length = 5;
-       }
-}
-
-/* Notes on per-window bpp settings
- *
- * Value       Win0     Win1     Win2     Win3     Win 4
- * 0000                1(P)     1(P)     1(P)     1(P)     1(P)
- * 0001                2(P)     2(P)     2(P)     2(P)     2(P)
- * 0010                4(P)     4(P)     4(P)     4(P)     -none-
- * 0011                8(P)     8(P)     -none-   -none-   -none-
- * 0100                -none-   8(A232)  8(A232)  -none-   -none-
- * 0101                16(565)  16(565)  16(565)  16(565)   16(565)
- * 0110                -none-   16(A555) 16(A555) 16(A555)  16(A555)
- * 0111                16(I555) 16(I565) 16(I555) 16(I555)  16(I555)
- * 1000                18(666)  18(666)  18(666)  18(666)   18(666)
- * 1001                -none-   18(A665) 18(A665) 18(A665)  16(A665)
- * 1010                -none-   19(A666) 19(A666) 19(A666)  19(A666)
- * 1011                24(888)  24(888)  24(888)  24(888)   24(888)
- * 1100                -none-   24(A887) 24(A887) 24(A887)  24(A887)
- * 1101                -none-   25(A888) 25(A888) 25(A888)  25(A888)
- * 1110                -none-   -none-   -none-   -none-    -none-
- * 1111                -none-   -none-   -none-   -none-    -none-
-*/
+#endif /* __ASM_ARCH_MACH_REGS_FB_H */
index b42bdd0..d876ee5 100644 (file)
@@ -45,6 +45,7 @@ void __init s3c6400_map_io(void)
 
        s3c6400_default_sdhci0();
        s3c6400_default_sdhci1();
+       s3c6400_default_sdhci2();
 
        /* the i2c devices are directly compatible with s3c2440 */
        s3c_i2c0_setname("s3c2440-i2c");
index 9b67c66..522c086 100644 (file)
@@ -58,6 +58,7 @@ void __init s3c6410_map_io(void)
        /* initialise device information early */
        s3c6410_default_sdhci0();
        s3c6410_default_sdhci1();
+       s3c6410_default_sdhci2();
 
        /* the i2c devices are directly compatible with s3c2440 */
        s3c_i2c0_setname("s3c2440-i2c");
index c574105..cdd4b53 100644 (file)
@@ -250,7 +250,7 @@ static void __init hmt_machine_init(void)
 {
        s3c_i2c0_set_platdata(NULL);
        s3c_fb_set_platdata(&hmt_lcd_pdata);
-       s3c_device_nand.dev.platform_data = &hmt_nand_info;
+       s3c_nand_set_platdata(&hmt_nand_info);
 
        gpio_request(S3C64XX_GPC(7), "usb power");
        gpio_direction_output(S3C64XX_GPC(7), 0);
index 9f1a214..480d297 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/gpio.h>
 #include <linux/delay.h>
 #include <linux/smsc911x.h>
+#include <linux/regulator/fixed.h>
 
 #ifdef CONFIG_SMDK6410_WM1190_EV1
 #include <linux/mfd/wm8350/core.h>
@@ -184,6 +185,43 @@ static struct platform_device smdk6410_smsc911x = {
        },
 };
 
+#ifdef CONFIG_REGULATOR
+static struct regulator_consumer_supply smdk6410_b_pwr_5v_consumers[] = {
+       {
+               /* WM8580 */
+               .supply = "PVDD",
+               .dev_name = "0-001b",
+       },
+       {
+               /* WM8580 */
+               .supply = "AVDD",
+               .dev_name = "0-001b",
+       },
+};
+
+static struct regulator_init_data smdk6410_b_pwr_5v_data = {
+       .constraints = {
+               .always_on = 1,
+       },
+       .num_consumer_supplies = ARRAY_SIZE(smdk6410_b_pwr_5v_consumers),
+       .consumer_supplies = smdk6410_b_pwr_5v_consumers,
+};
+
+static struct fixed_voltage_config smdk6410_b_pwr_5v_pdata = {
+       .supply_name = "B_PWR_5V",
+       .microvolts = 5000000,
+       .init_data = &smdk6410_b_pwr_5v_data,
+};
+
+static struct platform_device smdk6410_b_pwr_5v = {
+       .name          = "reg-fixed-voltage",
+       .id            = -1,
+       .dev = {
+               .platform_data = &smdk6410_b_pwr_5v_pdata,
+       },
+};
+#endif
+
 static struct map_desc smdk6410_iodesc[] = {};
 
 static struct platform_device *smdk6410_devices[] __initdata = {
@@ -198,6 +236,10 @@ static struct platform_device *smdk6410_devices[] __initdata = {
        &s3c_device_fb,
        &s3c_device_usb,
        &s3c_device_usb_hsotg,
+
+#ifdef CONFIG_REGULATOR
+       &smdk6410_b_pwr_5v,
+#endif
        &smdk6410_lcd_powerdev,
 
        &smdk6410_smsc911x,
@@ -232,6 +274,14 @@ static struct regulator_init_data wm8350_dcdc3_data = {
 };
 
 /* USB, EXT, PCM, ADC/DAC, USB, MMC */
+static struct regulator_consumer_supply wm8350_dcdc4_consumers[] = {
+       {
+               /* WM8580 */
+               .supply = "DVDD",
+               .dev_name = "0-001b",
+       },
+};
+
 static struct regulator_init_data wm8350_dcdc4_data = {
        .constraints = {
                .name = "PVDD_HI/PVDD_EXT/PVDD_SYS/PVCCM2MTV",
@@ -239,6 +289,8 @@ static struct regulator_init_data wm8350_dcdc4_data = {
                .max_uV = 3000000,
                .always_on = 1,
        },
+       .num_consumer_supplies = ARRAY_SIZE(wm8350_dcdc4_consumers),
+       .consumer_supplies = wm8350_dcdc4_consumers,
 };
 
 /* ARM core */
index b1a4ba5..0dd2b8c 100644 (file)
@@ -14,9 +14,23 @@ config CPU_S5PC100
        help
          Enable S5PC100 CPU support
 
+config S5PC100_SETUP_SDHCI
+        bool
+        select S5PC1XX_SETUP_SDHCI_GPIO
+        help
+          Internal helper functions for S5PC100 based SDHCI systems
+
 config MACH_SMDKC100
        bool "SMDKC100"
        select CPU_S5PC100
+       select S3C_DEV_FB
+       select S3C_DEV_I2C1
+       select S3C_DEV_HSMMC
+       select S3C_DEV_HSMMC1
+       select S3C_DEV_HSMMC2
+       select S5PC1XX_SETUP_I2C0
        select S5PC1XX_SETUP_I2C1
+       select S5PC1XX_SETUP_FB_24BPP
+       select S5PC100_SETUP_SDHCI
        help
          Machine support for the Samsung SMDKC100
index afc89b3..809ff10 100644 (file)
@@ -13,5 +13,9 @@ obj-                          :=
 
 obj-$(CONFIG_CPU_S5PC100)      += cpu.o
 
+# Helper and device support
+
+obj-$(CONFIG_S5PC100_SETUP_SDHCI)       += setup-sdhci.o
+
 # machine support
 obj-$(CONFIG_MACH_SMDKC100)    += mach-smdkc100.o
index 0e71889..d79e757 100644 (file)
@@ -22,6 +22,8 @@
 #include <linux/serial_core.h>
 #include <linux/platform_device.h>
 
+#include <asm/proc-fns.h>
+
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
 #include <asm/mach/irq.h>
@@ -32,6 +34,7 @@
 
 #include <plat/cpu-freq.h>
 #include <plat/regs-serial.h>
+#include <plat/regs-power.h>
 
 #include <plat/cpu.h>
 #include <plat/devs.h>
 static struct map_desc s5pc100_iodesc[] __initdata = {
 };
 
+static void s5pc100_idle(void)
+{
+       unsigned long tmp;
+
+       tmp = __raw_readl(S5PC100_PWR_CFG);
+       tmp &= ~S5PC100_PWRCFG_CFG_DEEP_IDLE;
+       tmp &= ~S5PC100_PWRCFG_CFG_WFI_MASK;
+       tmp |= S5PC100_PWRCFG_CFG_WFI_DEEP_IDLE;
+       __raw_writel(tmp, S5PC100_PWR_CFG);
+
+       tmp = __raw_readl(S5PC100_OTHERS);
+       tmp |= S5PC100_PMU_INT_DISABLE;
+       __raw_writel(tmp, S5PC100_OTHERS);
+
+       cpu_do_idle();
+}
+
 /* s5pc100_map_io
  *
  * register the standard cpu IO areas
@@ -55,6 +75,13 @@ void __init s5pc100_map_io(void)
        iotable_init(s5pc100_iodesc, ARRAY_SIZE(s5pc100_iodesc));
 
        /* initialise device information early */
+       s5pc100_default_sdhci0();
+       s5pc100_default_sdhci1();
+       s5pc100_default_sdhci2();
+
+       /* the i2c devices are directly compatible with s3c2440 */
+       s3c_i2c0_setname("s3c2440-i2c");
+       s3c_i2c1_setname("s3c2440-i2c");
 }
 
 void __init s5pc100_init_clocks(int xtal)
@@ -93,5 +120,7 @@ int __init s5pc100_init(void)
 {
        printk(KERN_DEBUG "S5PC100: Initialising architecture\n");
 
+       s5pc1xx_idle = s5pc100_idle;
+
        return sysdev_register(&s5pc100_sysdev);
 }
index c74fc93..2c4cbe8 100644 (file)
 #define gpio_to_irq    __gpio_to_irq
 
 /* GPIO bank sizes */
-#define S5PC1XX_GPIO_A0_NR     (8)
-#define S5PC1XX_GPIO_A1_NR     (5)
-#define S5PC1XX_GPIO_B_NR      (8)
-#define S5PC1XX_GPIO_C_NR      (5)
-#define S5PC1XX_GPIO_D_NR      (7)
-#define S5PC1XX_GPIO_E0_NR     (8)
-#define S5PC1XX_GPIO_E1_NR     (6)
-#define S5PC1XX_GPIO_F0_NR     (8)
-#define S5PC1XX_GPIO_F1_NR     (8)
-#define S5PC1XX_GPIO_F2_NR     (8)
-#define S5PC1XX_GPIO_F3_NR     (4)
-#define S5PC1XX_GPIO_G0_NR     (8)
-#define S5PC1XX_GPIO_G1_NR     (3)
-#define S5PC1XX_GPIO_G2_NR     (7)
-#define S5PC1XX_GPIO_G3_NR     (7)
-#define S5PC1XX_GPIO_H0_NR     (8)
-#define S5PC1XX_GPIO_H1_NR     (8)
-#define S5PC1XX_GPIO_H2_NR     (8)
-#define S5PC1XX_GPIO_H3_NR     (8)
-#define S5PC1XX_GPIO_I_NR      (8)
-#define S5PC1XX_GPIO_J0_NR     (8)
-#define S5PC1XX_GPIO_J1_NR     (5)
-#define S5PC1XX_GPIO_J2_NR     (8)
-#define S5PC1XX_GPIO_J3_NR     (8)
-#define S5PC1XX_GPIO_J4_NR     (4)
-#define S5PC1XX_GPIO_K0_NR     (8)
-#define S5PC1XX_GPIO_K1_NR     (6)
-#define S5PC1XX_GPIO_K2_NR     (8)
-#define S5PC1XX_GPIO_K3_NR     (8)
-#define S5PC1XX_GPIO_MP00_NR   (8)
-#define S5PC1XX_GPIO_MP01_NR   (8)
-#define S5PC1XX_GPIO_MP02_NR   (8)
-#define S5PC1XX_GPIO_MP03_NR   (8)
-#define S5PC1XX_GPIO_MP04_NR   (5)
+#define S5PC100_GPIO_A0_NR     (8)
+#define S5PC100_GPIO_A1_NR     (5)
+#define S5PC100_GPIO_B_NR      (8)
+#define S5PC100_GPIO_C_NR      (5)
+#define S5PC100_GPIO_D_NR      (7)
+#define S5PC100_GPIO_E0_NR     (8)
+#define S5PC100_GPIO_E1_NR     (6)
+#define S5PC100_GPIO_F0_NR     (8)
+#define S5PC100_GPIO_F1_NR     (8)
+#define S5PC100_GPIO_F2_NR     (8)
+#define S5PC100_GPIO_F3_NR     (4)
+#define S5PC100_GPIO_G0_NR     (8)
+#define S5PC100_GPIO_G1_NR     (3)
+#define S5PC100_GPIO_G2_NR     (7)
+#define S5PC100_GPIO_G3_NR     (7)
+#define S5PC100_GPIO_H0_NR     (8)
+#define S5PC100_GPIO_H1_NR     (8)
+#define S5PC100_GPIO_H2_NR     (8)
+#define S5PC100_GPIO_H3_NR     (8)
+#define S5PC100_GPIO_I_NR      (8)
+#define S5PC100_GPIO_J0_NR     (8)
+#define S5PC100_GPIO_J1_NR     (5)
+#define S5PC100_GPIO_J2_NR     (8)
+#define S5PC100_GPIO_J3_NR     (8)
+#define S5PC100_GPIO_J4_NR     (4)
+#define S5PC100_GPIO_K0_NR     (8)
+#define S5PC100_GPIO_K1_NR     (6)
+#define S5PC100_GPIO_K2_NR     (8)
+#define S5PC100_GPIO_K3_NR     (8)
+#define S5PC100_GPIO_L0_NR     (8)
+#define S5PC100_GPIO_L1_NR     (8)
+#define S5PC100_GPIO_L2_NR     (8)
+#define S5PC100_GPIO_L3_NR     (8)
+#define S5PC100_GPIO_L4_NR     (8)
+#define S5PC100_GPIO_MP00_NR   (8)
+#define S5PC100_GPIO_MP01_NR   (8)
+#define S5PC100_GPIO_MP02_NR   (8)
+#define S5PC100_GPIO_MP03_NR   (8)
+#define S5PC100_GPIO_MP04_NR   (5)
 
 /* GPIO bank numbes */
 
        ((__gpio##_START) + (__gpio##_NR) + CONFIG_S3C_GPIO_SPACE + 1)
 
 enum s3c_gpio_number {
-       S5PC1XX_GPIO_A0_START   = 0,
-       S5PC1XX_GPIO_A1_START   = S5PC1XX_GPIO_NEXT(S5PC1XX_GPIO_A0),
-       S5PC1XX_GPIO_B_START    = S5PC1XX_GPIO_NEXT(S5PC1XX_GPIO_A1),
-       S5PC1XX_GPIO_C_START    = S5PC1XX_GPIO_NEXT(S5PC1XX_GPIO_B),
-       S5PC1XX_GPIO_D_START    = S5PC1XX_GPIO_NEXT(S5PC1XX_GPIO_C),
-       S5PC1XX_GPIO_E0_START   = S5PC1XX_GPIO_NEXT(S5PC1XX_GPIO_D),
-       S5PC1XX_GPIO_E1_START   = S5PC1XX_GPIO_NEXT(S5PC1XX_GPIO_E0),
-       S5PC1XX_GPIO_F0_START   = S5PC1XX_GPIO_NEXT(S5PC1XX_GPIO_E1),
-       S5PC1XX_GPIO_F1_START   = S5PC1XX_GPIO_NEXT(S5PC1XX_GPIO_F0),
-       S5PC1XX_GPIO_F2_START   = S5PC1XX_GPIO_NEXT(S5PC1XX_GPIO_F1),
-       S5PC1XX_GPIO_F3_START   = S5PC1XX_GPIO_NEXT(S5PC1XX_GPIO_F2),
-       S5PC1XX_GPIO_G0_START   = S5PC1XX_GPIO_NEXT(S5PC1XX_GPIO_F3),
-       S5PC1XX_GPIO_G1_START   = S5PC1XX_GPIO_NEXT(S5PC1XX_GPIO_G0),
-       S5PC1XX_GPIO_G2_START   = S5PC1XX_GPIO_NEXT(S5PC1XX_GPIO_G1),
-       S5PC1XX_GPIO_G3_START   = S5PC1XX_GPIO_NEXT(S5PC1XX_GPIO_G2),
-       S5PC1XX_GPIO_H0_START   = S5PC1XX_GPIO_NEXT(S5PC1XX_GPIO_G3),
-       S5PC1XX_GPIO_H1_START   = S5PC1XX_GPIO_NEXT(S5PC1XX_GPIO_H0),
-       S5PC1XX_GPIO_H2_START   = S5PC1XX_GPIO_NEXT(S5PC1XX_GPIO_H1),
-       S5PC1XX_GPIO_H3_START   = S5PC1XX_GPIO_NEXT(S5PC1XX_GPIO_H2),
-       S5PC1XX_GPIO_I_START    = S5PC1XX_GPIO_NEXT(S5PC1XX_GPIO_H3),
-       S5PC1XX_GPIO_J0_START   = S5PC1XX_GPIO_NEXT(S5PC1XX_GPIO_I),
-       S5PC1XX_GPIO_J1_START   = S5PC1XX_GPIO_NEXT(S5PC1XX_GPIO_J0),
-       S5PC1XX_GPIO_J2_START   = S5PC1XX_GPIO_NEXT(S5PC1XX_GPIO_J1),
-       S5PC1XX_GPIO_J3_START   = S5PC1XX_GPIO_NEXT(S5PC1XX_GPIO_J2),
-       S5PC1XX_GPIO_J4_START   = S5PC1XX_GPIO_NEXT(S5PC1XX_GPIO_J3),
-       S5PC1XX_GPIO_K0_START   = S5PC1XX_GPIO_NEXT(S5PC1XX_GPIO_J4),
-       S5PC1XX_GPIO_K1_START   = S5PC1XX_GPIO_NEXT(S5PC1XX_GPIO_K0),
-       S5PC1XX_GPIO_K2_START   = S5PC1XX_GPIO_NEXT(S5PC1XX_GPIO_K1),
-       S5PC1XX_GPIO_K3_START   = S5PC1XX_GPIO_NEXT(S5PC1XX_GPIO_K2),
-       S5PC1XX_GPIO_MP00_START = S5PC1XX_GPIO_NEXT(S5PC1XX_GPIO_K3),
-       S5PC1XX_GPIO_MP01_START = S5PC1XX_GPIO_NEXT(S5PC1XX_GPIO_MP00),
-       S5PC1XX_GPIO_MP02_START = S5PC1XX_GPIO_NEXT(S5PC1XX_GPIO_MP01),
-       S5PC1XX_GPIO_MP03_START = S5PC1XX_GPIO_NEXT(S5PC1XX_GPIO_MP02),
-       S5PC1XX_GPIO_MP04_START = S5PC1XX_GPIO_NEXT(S5PC1XX_GPIO_MP03),
+       S5PC100_GPIO_A0_START   = 0,
+       S5PC100_GPIO_A1_START   = S5PC1XX_GPIO_NEXT(S5PC100_GPIO_A0),
+       S5PC100_GPIO_B_START    = S5PC1XX_GPIO_NEXT(S5PC100_GPIO_A1),
+       S5PC100_GPIO_C_START    = S5PC1XX_GPIO_NEXT(S5PC100_GPIO_B),
+       S5PC100_GPIO_D_START    = S5PC1XX_GPIO_NEXT(S5PC100_GPIO_C),
+       S5PC100_GPIO_E0_START   = S5PC1XX_GPIO_NEXT(S5PC100_GPIO_D),
+       S5PC100_GPIO_E1_START   = S5PC1XX_GPIO_NEXT(S5PC100_GPIO_E0),
+       S5PC100_GPIO_F0_START   = S5PC1XX_GPIO_NEXT(S5PC100_GPIO_E1),
+       S5PC100_GPIO_F1_START   = S5PC1XX_GPIO_NEXT(S5PC100_GPIO_F0),
+       S5PC100_GPIO_F2_START   = S5PC1XX_GPIO_NEXT(S5PC100_GPIO_F1),
+       S5PC100_GPIO_F3_START   = S5PC1XX_GPIO_NEXT(S5PC100_GPIO_F2),
+       S5PC100_GPIO_G0_START   = S5PC1XX_GPIO_NEXT(S5PC100_GPIO_F3),
+       S5PC100_GPIO_G1_START   = S5PC1XX_GPIO_NEXT(S5PC100_GPIO_G0),
+       S5PC100_GPIO_G2_START   = S5PC1XX_GPIO_NEXT(S5PC100_GPIO_G1),
+       S5PC100_GPIO_G3_START   = S5PC1XX_GPIO_NEXT(S5PC100_GPIO_G2),
+       S5PC100_GPIO_H0_START   = S5PC1XX_GPIO_NEXT(S5PC100_GPIO_G3),
+       S5PC100_GPIO_H1_START   = S5PC1XX_GPIO_NEXT(S5PC100_GPIO_H0),
+       S5PC100_GPIO_H2_START   = S5PC1XX_GPIO_NEXT(S5PC100_GPIO_H1),
+       S5PC100_GPIO_H3_START   = S5PC1XX_GPIO_NEXT(S5PC100_GPIO_H2),
+       S5PC100_GPIO_I_START    = S5PC1XX_GPIO_NEXT(S5PC100_GPIO_H3),
+       S5PC100_GPIO_J0_START   = S5PC1XX_GPIO_NEXT(S5PC100_GPIO_I),
+       S5PC100_GPIO_J1_START   = S5PC1XX_GPIO_NEXT(S5PC100_GPIO_J0),
+       S5PC100_GPIO_J2_START   = S5PC1XX_GPIO_NEXT(S5PC100_GPIO_J1),
+       S5PC100_GPIO_J3_START   = S5PC1XX_GPIO_NEXT(S5PC100_GPIO_J2),
+       S5PC100_GPIO_J4_START   = S5PC1XX_GPIO_NEXT(S5PC100_GPIO_J3),
+       S5PC100_GPIO_K0_START   = S5PC1XX_GPIO_NEXT(S5PC100_GPIO_J4),
+       S5PC100_GPIO_K1_START   = S5PC1XX_GPIO_NEXT(S5PC100_GPIO_K0),
+       S5PC100_GPIO_K2_START   = S5PC1XX_GPIO_NEXT(S5PC100_GPIO_K1),
+       S5PC100_GPIO_K3_START   = S5PC1XX_GPIO_NEXT(S5PC100_GPIO_K2),
+       S5PC100_GPIO_L0_START   = S5PC1XX_GPIO_NEXT(S5PC100_GPIO_K3),
+       S5PC100_GPIO_L1_START   = S5PC1XX_GPIO_NEXT(S5PC100_GPIO_L0),
+       S5PC100_GPIO_L2_START   = S5PC1XX_GPIO_NEXT(S5PC100_GPIO_L1),
+       S5PC100_GPIO_L3_START   = S5PC1XX_GPIO_NEXT(S5PC100_GPIO_L2),
+       S5PC100_GPIO_L4_START   = S5PC1XX_GPIO_NEXT(S5PC100_GPIO_L3),
+       S5PC100_GPIO_MP00_START = S5PC1XX_GPIO_NEXT(S5PC100_GPIO_L4),
+       S5PC100_GPIO_MP01_START = S5PC1XX_GPIO_NEXT(S5PC100_GPIO_MP00),
+       S5PC100_GPIO_MP02_START = S5PC1XX_GPIO_NEXT(S5PC100_GPIO_MP01),
+       S5PC100_GPIO_MP03_START = S5PC1XX_GPIO_NEXT(S5PC100_GPIO_MP02),
+       S5PC100_GPIO_MP04_START = S5PC1XX_GPIO_NEXT(S5PC100_GPIO_MP03),
+       S5PC100_GPIO_END        = S5PC1XX_GPIO_NEXT(S5PC100_GPIO_MP04),
 };
 
-/* S5PC1XX GPIO number definitions. */
-#define S5PC1XX_GPA0(_nr)      (S5PC1XX_GPIO_A0_START + (_nr))
-#define S5PC1XX_GPA1(_nr)      (S5PC1XX_GPIO_A1_START + (_nr))
-#define S5PC1XX_GPB(_nr)       (S5PC1XX_GPIO_B_START + (_nr))
-#define S5PC1XX_GPC(_nr)       (S5PC1XX_GPIO_C_START + (_nr))
-#define S5PC1XX_GPD(_nr)       (S5PC1XX_GPIO_D_START + (_nr))
-#define S5PC1XX_GPE0(_nr)      (S5PC1XX_GPIO_E0_START + (_nr))
-#define S5PC1XX_GPE1(_nr)      (S5PC1XX_GPIO_E1_START + (_nr))
-#define S5PC1XX_GPF0(_nr)      (S5PC1XX_GPIO_F0_START + (_nr))
-#define S5PC1XX_GPF1(_nr)      (S5PC1XX_GPIO_F1_START + (_nr))
-#define S5PC1XX_GPF2(_nr)      (S5PC1XX_GPIO_F2_START + (_nr))
-#define S5PC1XX_GPF3(_nr)      (S5PC1XX_GPIO_F3_START + (_nr))
-#define S5PC1XX_GPG0(_nr)      (S5PC1XX_GPIO_G0_START + (_nr))
-#define S5PC1XX_GPG1(_nr)      (S5PC1XX_GPIO_G1_START + (_nr))
-#define S5PC1XX_GPG2(_nr)      (S5PC1XX_GPIO_G2_START + (_nr))
-#define S5PC1XX_GPG3(_nr)      (S5PC1XX_GPIO_G3_START + (_nr))
-#define S5PC1XX_GPH0(_nr)      (S5PC1XX_GPIO_H0_START + (_nr))
-#define S5PC1XX_GPH1(_nr)      (S5PC1XX_GPIO_H1_START + (_nr))
-#define S5PC1XX_GPH2(_nr)      (S5PC1XX_GPIO_H2_START + (_nr))
-#define S5PC1XX_GPH3(_nr)      (S5PC1XX_GPIO_H3_START + (_nr))
-#define S5PC1XX_GPI(_nr)       (S5PC1XX_GPIO_I_START + (_nr))
-#define S5PC1XX_GPJ0(_nr)      (S5PC1XX_GPIO_J0_START + (_nr))
-#define S5PC1XX_GPJ1(_nr)      (S5PC1XX_GPIO_J1_START + (_nr))
-#define S5PC1XX_GPJ2(_nr)      (S5PC1XX_GPIO_J2_START + (_nr))
-#define S5PC1XX_GPJ3(_nr)      (S5PC1XX_GPIO_J3_START + (_nr))
-#define S5PC1XX_GPJ4(_nr)      (S5PC1XX_GPIO_J4_START + (_nr))
-#define S5PC1XX_GPK0(_nr)      (S5PC1XX_GPIO_K0_START + (_nr))
-#define S5PC1XX_GPK1(_nr)      (S5PC1XX_GPIO_K1_START + (_nr))
-#define S5PC1XX_GPK2(_nr)      (S5PC1XX_GPIO_K2_START + (_nr))
-#define S5PC1XX_GPK3(_nr)      (S5PC1XX_GPIO_K3_START + (_nr))
-#define S5PC1XX_MP00(_nr)      (S5PC1XX_GPIO_MP00_START + (_nr))
-#define S5PC1XX_MP01(_nr)      (S5PC1XX_GPIO_MP01_START + (_nr))
-#define S5PC1XX_MP02(_nr)      (S5PC1XX_GPIO_MP02_START + (_nr))
-#define S5PC1XX_MP03(_nr)      (S5PC1XX_GPIO_MP03_START + (_nr))
-#define S5PC1XX_MP04(_nr)      (S5PC1XX_GPIO_MP04_START + (_nr))
+/* S5PC100 GPIO number definitions. */
+#define S5PC100_GPA0(_nr)      (S5PC100_GPIO_A0_START + (_nr))
+#define S5PC100_GPA1(_nr)      (S5PC100_GPIO_A1_START + (_nr))
+#define S5PC100_GPB(_nr)       (S5PC100_GPIO_B_START + (_nr))
+#define S5PC100_GPC(_nr)       (S5PC100_GPIO_C_START + (_nr))
+#define S5PC100_GPD(_nr)       (S5PC100_GPIO_D_START + (_nr))
+#define S5PC100_GPE0(_nr)      (S5PC100_GPIO_E0_START + (_nr))
+#define S5PC100_GPE1(_nr)      (S5PC100_GPIO_E1_START + (_nr))
+#define S5PC100_GPF0(_nr)      (S5PC100_GPIO_F0_START + (_nr))
+#define S5PC100_GPF1(_nr)      (S5PC100_GPIO_F1_START + (_nr))
+#define S5PC100_GPF2(_nr)      (S5PC100_GPIO_F2_START + (_nr))
+#define S5PC100_GPF3(_nr)      (S5PC100_GPIO_F3_START + (_nr))
+#define S5PC100_GPG0(_nr)      (S5PC100_GPIO_G0_START + (_nr))
+#define S5PC100_GPG1(_nr)      (S5PC100_GPIO_G1_START + (_nr))
+#define S5PC100_GPG2(_nr)      (S5PC100_GPIO_G2_START + (_nr))
+#define S5PC100_GPG3(_nr)      (S5PC100_GPIO_G3_START + (_nr))
+#define S5PC100_GPH0(_nr)      (S5PC100_GPIO_H0_START + (_nr))
+#define S5PC100_GPH1(_nr)      (S5PC100_GPIO_H1_START + (_nr))
+#define S5PC100_GPH2(_nr)      (S5PC100_GPIO_H2_START + (_nr))
+#define S5PC100_GPH3(_nr)      (S5PC100_GPIO_H3_START + (_nr))
+#define S5PC100_GPI(_nr)       (S5PC100_GPIO_I_START + (_nr))
+#define S5PC100_GPJ0(_nr)      (S5PC100_GPIO_J0_START + (_nr))
+#define S5PC100_GPJ1(_nr)      (S5PC100_GPIO_J1_START + (_nr))
+#define S5PC100_GPJ2(_nr)      (S5PC100_GPIO_J2_START + (_nr))
+#define S5PC100_GPJ3(_nr)      (S5PC100_GPIO_J3_START + (_nr))
+#define S5PC100_GPJ4(_nr)      (S5PC100_GPIO_J4_START + (_nr))
+#define S5PC100_GPK0(_nr)      (S5PC100_GPIO_K0_START + (_nr))
+#define S5PC100_GPK1(_nr)      (S5PC100_GPIO_K1_START + (_nr))
+#define S5PC100_GPK2(_nr)      (S5PC100_GPIO_K2_START + (_nr))
+#define S5PC100_GPK3(_nr)      (S5PC100_GPIO_K3_START + (_nr))
+#define S5PC100_GPL0(_nr)      (S5PC100_GPIO_L0_START + (_nr))
+#define S5PC100_GPL1(_nr)      (S5PC100_GPIO_L1_START + (_nr))
+#define S5PC100_GPL2(_nr)      (S5PC100_GPIO_L2_START + (_nr))
+#define S5PC100_GPL3(_nr)      (S5PC100_GPIO_L3_START + (_nr))
+#define S5PC100_GPL4(_nr)      (S5PC100_GPIO_L4_START + (_nr))
+#define S5PC100_MP00(_nr)      (S5PC100_GPIO_MP00_START + (_nr))
+#define S5PC100_MP01(_nr)      (S5PC100_GPIO_MP01_START + (_nr))
+#define S5PC100_MP02(_nr)      (S5PC100_GPIO_MP02_START + (_nr))
+#define S5PC100_MP03(_nr)      (S5PC100_GPIO_MP03_START + (_nr))
+#define S5PC100_MP04(_nr)      (S5PC100_GPIO_MP04_START + (_nr))
+#define S5PC100_MP05(_nr)      (S5PC100_GPIO_MP05_START + (_nr))
 
-/* the end of the S5PC1XX specific gpios */
-#define S5PC1XX_GPIO_END       (S5PC1XX_MP04(S5PC1XX_GPIO_MP04_NR) + 1)
-#define S3C_GPIO_END           S5PC1XX_GPIO_END
+/* It used the end of the S5PC1XX gpios */
+#define S3C_GPIO_END           S5PC100_GPIO_END
 
 /* define the number of gpios we need to the one after the MP04() range */
-#define ARCH_NR_GPIOS  (S5PC1XX_MP04(S5PC1XX_GPIO_MP04_NR) + 1)
+#define ARCH_NR_GPIOS          (S5PC100_GPIO_END + 1)
 
 #include <asm-generic/gpio.h>
index 622720d..b53fa48 100644 (file)
@@ -11,4 +11,9 @@
 
 #include <plat/irqs.h>
 
+/* LCD */
+#define IRQ_LCD_FIFO           IRQ_LCD0
+#define IRQ_LCD_VSYNC          IRQ_LCD1
+#define IRQ_LCD_SYSTEM         IRQ_LCD2
+
 #endif /* __ASM_ARCH_IRQ_H */
index 9e9f391..4681ebe 100644 (file)
 
 #include <plat/map-base.h>
 
+/*
+ * map-base.h has already defined virtual memory address
+ * S3C_VA_IRQ          S3C_ADDR(0x00000000)    irq controller(s)
+ * S3C_VA_SYS          S3C_ADDR(0x00100000)    system control
+ * S3C_VA_MEM          S3C_ADDR(0x00200000)    system control (not used)
+ * S3C_VA_TIMER                S3C_ADDR(0x00300000)    timer block
+ * S3C_VA_WATCHDOG     S3C_ADDR(0x00400000)    watchdog
+ * S3C_VA_UART         S3C_ADDR(0x01000000)    UART
+ *
+ * S5PC100 specific virtual memory address can be defined here
+ * S5PC1XX_VA_GPIO     S3C_ADDR(0x00500000)    GPIO
+ *
+ */
 
 /* Chip ID */
 #define S5PC100_PA_CHIPID      (0xE0000000)
 #define S5PC1XX_VA_CHIPID      S3C_VA_SYS
 
 /* System */
-#define S5PC100_PA_SYS         (0xE0100000)
-#define S5PC100_PA_CLK         (S5PC100_PA_SYS + 0x0)
-#define S5PC100_PA_PWR         (S5PC100_PA_SYS + 0x8000)
+#define S5PC100_PA_CLK         (0xE0100000)
+#define S5PC100_PA_CLK_OTHER   (0xE0200000)
+#define S5PC100_PA_PWR         (0xE0108000)
 #define S5PC1XX_PA_CLK         S5PC100_PA_CLK
 #define S5PC1XX_PA_PWR         S5PC100_PA_PWR
+#define S5PC1XX_PA_CLK_OTHER   S5PC100_PA_CLK_OTHER
 #define S5PC1XX_VA_CLK         (S3C_VA_SYS + 0x10000)
 #define S5PC1XX_VA_PWR         (S3C_VA_SYS + 0x20000)
+#define S5PC1XX_VA_CLK_OTHER   (S3C_VA_SYS + 0x30000)
+
+/* GPIO */
+#define S5PC100_PA_GPIO                (0xE0300000)
+#define S5PC1XX_PA_GPIO                S5PC100_PA_GPIO
+#define S5PC1XX_VA_GPIO                S3C_ADDR(0x00500000)
 
 /* Interrupt */
 #define S5PC100_PA_VIC         (0xE4000000)
 #define S5PC1XX_PA_VIC(x)      (S5PC100_PA_VIC + ((x) * S5PC100_PA_VIC_OFFSET))
 #define S5PC1XX_VA_VIC(x)      (S5PC100_VA_VIC + ((x) * S5PC100_VA_VIC_OFFSET))
 
+/* DMA */
+#define S5PC100_PA_MDMA                (0xE8100000)
+#define S5PC100_PA_PDMA0       (0xE9000000)
+#define S5PC100_PA_PDMA1       (0xE9200000)
+
 /* Timer */
 #define S5PC100_PA_TIMER       (0xEA000000)
 #define S5PC1XX_PA_TIMER       S5PC100_PA_TIMER
 #define S5PC1XX_VA_TIMER       S3C_VA_TIMER
 
+/* RTC */
+#define S5PC100_PA_RTC         (0xEA300000)
+
 /* UART */
 #define S5PC100_PA_UART                (0xEC000000)
 #define S5PC1XX_PA_UART                S5PC100_PA_UART
 #define S5PC1XX_VA_UART                S3C_VA_UART
 
-/* IIC */
-#define S5PC100_PA_IIC         (0xEC100000)
+/* I2C */
+#define S5PC100_PA_I2C         (0xEC100000)
+#define S5PC100_PA_I2C1                (0xEC200000)
+
+/* USB HS OTG */
+#define S5PC100_PA_USB_HSOTG   (0xED200000)
+#define S5PC100_PA_USB_HSPHY   (0xED300000)
+
+/* SD/MMC */
+#define S5PC100_PA_HSMMC(x)    (0xED800000 + ((x) * 0x100000))
+#define S5PC100_PA_HSMMC0      S5PC100_PA_HSMMC(0)
+#define S5PC100_PA_HSMMC1      S5PC100_PA_HSMMC(1)
+#define S5PC100_PA_HSMMC2      S5PC100_PA_HSMMC(2)
+
+/* LCD */
+#define S5PC100_PA_FB          (0xEE000000)
+
+/* Multimedia */
+#define S5PC100_PA_G2D         (0xEE800000)
+#define S5PC100_PA_JPEG                (0xEE500000)
+#define S5PC100_PA_ROTATOR     (0xEE100000)
+#define S5PC100_PA_G3D         (0xEF000000)
+
+/* I2S */
+#define S5PC100_PA_I2S0                (0xF2000000)
+#define S5PC100_PA_I2S1                (0xF2100000)
+#define S5PC100_PA_I2S2                (0xF2200000)
+
+/* KEYPAD */
+#define S5PC100_PA_KEYPAD      (0xF3100000)
+
+/* ADC & TouchScreen */
+#define S5PC100_PA_TSADC       (0xF3000000)
 
 /* ETC */
 #define S5PC100_PA_SDRAM       (0x20000000)
+#define S5PC1XX_PA_SDRAM       S5PC100_PA_SDRAM
 
 /* compatibility defines. */
+#define S3C_PA_RTC             S5PC100_PA_RTC
 #define S3C_PA_UART            S5PC100_PA_UART
 #define S3C_PA_UART0           (S5PC100_PA_UART + 0x0)
 #define S3C_PA_UART1           (S5PC100_PA_UART + 0x400)
 #define S3C_VA_UART2           (S3C_VA_UART + 0x800)
 #define S3C_VA_UART3           (S3C_VA_UART + 0xC00)
 #define S3C_UART_OFFSET                0x400
+#define S3C_VA_UARTx(x)                (S3C_VA_UART + ((x) * S3C_UART_OFFSET))
+#define S3C_PA_FB              S5PC100_PA_FB
+#define S3C_PA_G2D             S5PC100_PA_G2D
+#define S3C_PA_G3D             S5PC100_PA_G3D
+#define S3C_PA_JPEG            S5PC100_PA_JPEG
+#define S3C_PA_ROTATOR         S5PC100_PA_ROTATOR
 #define S3C_VA_VIC0            (S3C_VA_IRQ + 0x0)
 #define S3C_VA_VIC1            (S3C_VA_IRQ + 0x10000)
 #define S3C_VA_VIC2            (S3C_VA_IRQ + 0x20000)
-#define S3C_PA_IIC             S5PC100_PA_IIC
+#define S3C_PA_IIC             S5PC100_PA_I2C
+#define S3C_PA_IIC1            S5PC100_PA_I2C1
+#define S3C_PA_USB_HSOTG       S5PC100_PA_USB_HSOTG
+#define S3C_PA_USB_HSPHY       S5PC100_PA_USB_HSPHY
+#define S3C_PA_HSMMC0          S5PC100_PA_HSMMC0
+#define S3C_PA_HSMMC1          S5PC100_PA_HSMMC1
+#define S3C_PA_HSMMC2          S5PC100_PA_HSMMC2
+#define S3C_PA_KEYPAD          S5PC100_PA_KEYPAD
+#define S3C_PA_TSADC           S5PC100_PA_TSADC
 
 #endif /* __ASM_ARCH_C100_MAP_H */
diff --git a/arch/arm/mach-s5pc100/include/mach/regs-fb.h b/arch/arm/mach-s5pc100/include/mach/regs-fb.h
new file mode 100644 (file)
index 0000000..1732cd2
--- /dev/null
@@ -0,0 +1,139 @@
+/* arch/arm/mach-s5pc100/include/mach/regs-fb.h
+ *
+ * Copyright 2009 Samsung Electronics Co.
+ *   Pawel Osciak <p.osciak@samsung.com>
+ *
+ * Framebuffer register definitions for Samsung S5PC100.
+ *
+ * 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_REGS_FB_H
+#define __ASM_ARCH_REGS_FB_H __FILE__
+
+#include <plat/regs-fb-v4.h>
+
+/* VP1 interface timing control */
+#define VP1CON0                                                (0x118)
+#define VP1_RATECON_EN                                 (1 << 31)
+#define VP1_CLKRATE_MASK                               (0xff)
+
+#define VP1CON1                                                (0x11c)
+#define VP1_VTREGCON_EN                                        (1 << 31)
+#define VP1_VBPD_MASK                                  (0xfff)
+#define VP1_VBPD_SHIFT                                 (16)
+
+
+#define WPALCON_H                                      (0x19c)
+#define WPALCON_L                                      (0x1a0)
+
+/* Pallete contro for WPAL0 and WPAL1 is the same as in S3C64xx, but
+ * different for WPAL2-4
+ */
+/* In WPALCON_L (aka WPALCON) */
+#define WPALCON_W1PAL_32BPP_A888                       (0x7 << 3)
+#define WPALCON_W0PAL_32BPP_A888                       (0x7 << 0)
+
+/* To set W2PAL-W4PAL consist of one bit from WPALCON_L and two from WPALCON_H,
+ * e.g. W2PAL[2..0] is made of (WPALCON_H[10..9], WPALCON_L[6]).
+ */
+#define WPALCON_L_WxPAL_L_MASK                         (0x1)
+#define WPALCON_L_W2PAL_L_SHIFT                                (6)
+#define WPALCON_L_W3PAL_L_SHIFT                                (7)
+#define WPALCON_L_W4PAL_L_SHIFT                                (8)
+
+#define WPALCON_L_WxPAL_H_MASK                         (0x3)
+#define WPALCON_H_W2PAL_H_SHIFT                                (9)
+#define WPALCON_H_W3PAL_H_SHIFT                                (13)
+#define WPALCON_H_W4PAL_H_SHIFT                                (17)
+
+/* Per-window alpha value registers */
+/* For window 0 8-bit alpha values are in VIDW0ALPHAx,
+ * for windows 1-4 alpha values consist of two parts, the 4 low bits are
+ * taken from VIDWxALPHAx and 4 high bits are from VIDOSDxC,
+ * e.g. WIN1_ALPHA0_B[7..0] = (VIDOSD1C[3..0], VIDW1ALPHA0[3..0])
+ */
+#define VIDWxALPHA0(_win)                              (0x200 + (_win * 8))
+#define VIDWxALPHA1(_win)                              (0x204 + (_win * 8))
+
+/* Only for window 0 in VIDW0ALPHAx. */
+#define VIDW0ALPHAx_R(_x)                              ((_x) << 16)
+#define VIDW0ALPHAx_R_MASK                             (0xff << 16)
+#define VIDW0ALPHAx_R_SHIFT                            (16)
+#define VIDW0ALPHAx_G(_x)                              ((_x) << 8)
+#define VIDW0ALPHAx_G_MASK                             (0xff << 8)
+#define VIDW0ALPHAx_G_SHIFT                            (8)
+#define VIDW0ALPHAx_B(_x)                              ((_x) << 0)
+#define VIDW0ALPHAx_B_MASK                             (0xff << 0)
+#define VIDW0ALPHAx_B_SHIFT                            (0)
+
+/* Low 4 bits of alpha0-1 for windows 1-4 */
+#define VIDW14ALPHAx_R_L(_x)                           ((_x) << 16)
+#define VIDW14ALPHAx_R_L_MASK                          (0xf << 16)
+#define VIDW14ALPHAx_R_L_SHIFT                         (16)
+#define VIDW14ALPHAx_G_L(_x)                           ((_x) << 8)
+#define VIDW14ALPHAx_G_L_MASK                          (0xf << 8)
+#define VIDW14ALPHAx_G_L_SHIFT                         (8)
+#define VIDW14ALPHAx_B_L(_x)                           ((_x) << 0)
+#define VIDW14ALPHAx_B_L_MASK                          (0xf << 0)
+#define VIDW14ALPHAx_B_L_SHIFT                         (0)
+
+
+/* Per-window blending equation control registers */
+#define BLENDEQx(_win)                                 (0x244 + ((_win) * 4))
+#define BLENDEQ1                                       (0x244)
+#define BLENDEQ2                                       (0x248)
+#define BLENDEQ3                                       (0x24c)
+#define BLENDEQ4                                       (0x250)
+
+#define BLENDEQx_Q_FUNC(_x)                            ((_x) << 18)
+#define BLENDEQx_Q_FUNC_MASK                           (0xf << 18)
+#define BLENDEQx_P_FUNC(_x)                            ((_x) << 12)
+#define BLENDEQx_P_FUNC_MASK                           (0xf << 12)
+#define BLENDEQx_B_FUNC(_x)                            ((_x) << 6)
+#define BLENDEQx_B_FUNC_MASK                           (0xf << 6)
+#define BLENDEQx_A_FUNC(_x)                            ((_x) << 0)
+#define BLENDEQx_A_FUNC_MASK                           (0xf << 0)
+
+#define BLENDCON                                       (0x260)
+#define BLENDCON_8BIT_ALPHA                            (1 << 0)
+
+/* Per-window palette base addresses (start of palette memory).
+ * Each window palette area consists of 256 32-bit entries.
+ * START is the first address (entry 0th), END is the address of 255th entry.
+ */
+#define WIN0_PAL_BASE                                  (0x2400)
+#define WIN0_PAL_END                                   (0x27fc)
+#define WIN1_PAL_BASE                                  (0x2800)
+#define WIN1_PAL_END                                   (0x2bfc)
+#define WIN2_PAL_BASE                                  (0x2c00)
+#define WIN2_PAL_END                                   (0x2ffc)
+#define WIN3_PAL_BASE                                  (0x3000)
+#define WIN3_PAL_END                                   (0x33fc)
+#define WIN4_PAL_BASE                                  (0x3400)
+#define WIN4_PAL_END                                   (0x37fc)
+
+#define WIN0_PAL(_entry)                       (WIN0_PAL_BASE + ((_entry) * 4))
+#define WIN1_PAL(_entry)                       (WIN1_PAL_BASE + ((_entry) * 4))
+#define WIN2_PAL(_entry)                       (WIN2_PAL_BASE + ((_entry) * 4))
+#define WIN3_PAL(_entry)                       (WIN3_PAL_BASE + ((_entry) * 4))
+#define WIN4_PAL(_entry)                       (WIN4_PAL_BASE + ((_entry) * 4))
+
+static inline unsigned int s3c_fb_pal_reg(unsigned int window, int reg)
+{
+       switch (window) {
+       case 0: return WIN0_PAL(reg);
+       case 1: return WIN1_PAL(reg);
+       case 2: return WIN2_PAL(reg);
+       case 3: return WIN3_PAL(reg);
+       case 4: return WIN4_PAL(reg);
+       }
+
+       BUG();
+}
+
+
+#endif /* __ASM_ARCH_REGS_FB_H */
+
index e390143..f0d31a2 100644 (file)
 #ifndef __ASM_ARCH_SYSTEM_H
 #define __ASM_ARCH_SYSTEM_H __FILE__
 
+#include <linux/io.h>
+#include <mach/map.h>
+#include <plat/regs-clock.h>
+
+void (*s5pc1xx_idle)(void);
+
 static void arch_idle(void)
 {
-       /* nothing here yet */
+       if (s5pc1xx_idle)
+               s5pc1xx_idle();
 }
 
 static void arch_reset(char mode, const char *cmd)
 {
-       /* nothing here yet */
+       __raw_writel(S5PC100_SWRESET_RESETVAL, S5PC100_SWRESET);
+       return;
 }
-
 #endif /* __ASM_ARCH_IRQ_H */
index 214093c..ae3c52c 100644 (file)
 #include <asm/mach/map.h>
 
 #include <mach/map.h>
+#include <mach/regs-fb.h>
+#include <video/platform_lcd.h>
 
 #include <asm/irq.h>
 #include <asm/mach-types.h>
 
 #include <plat/regs-serial.h>
+#include <plat/gpio-cfg.h>
+#include <plat/regs-gpio.h>
 
 #include <plat/clock.h>
 #include <plat/devs.h>
 #include <plat/cpu.h>
 #include <plat/s5pc100.h>
+#include <plat/fb.h>
+#include <plat/iic.h>
 
 #define UCON (S3C2410_UCON_DEFAULT | S3C2410_UCON_UCLK)
 #define ULCON (S3C2410_LCON_CS8 | S3C2410_LCON_PNONE | S3C2410_LCON_STOPB)
@@ -73,9 +79,78 @@ static struct s3c2410_uartcfg smdkc100_uartcfgs[] __initdata = {
        },
 };
 
+/* I2C0 */
+static struct i2c_board_info i2c_devs0[] __initdata = {
+};
+
+/* I2C1 */
+static struct i2c_board_info i2c_devs1[] __initdata = {
+};
+
+/* LCD power controller */
+static void smdkc100_lcd_power_set(struct plat_lcd_data *pd,
+                                  unsigned int power)
+{
+       /* backlight */
+       gpio_direction_output(S5PC100_GPD(0), power);
+
+       if (power) {
+               /* module reset */
+               gpio_direction_output(S5PC100_GPH0(6), 1);
+               mdelay(100);
+               gpio_direction_output(S5PC100_GPH0(6), 0);
+               mdelay(10);
+               gpio_direction_output(S5PC100_GPH0(6), 1);
+               mdelay(10);
+       }
+}
+
+static struct plat_lcd_data smdkc100_lcd_power_data = {
+       .set_power      = smdkc100_lcd_power_set,
+};
+
+static struct platform_device smdkc100_lcd_powerdev = {
+       .name                   = "platform-lcd",
+       .dev.parent             = &s3c_device_fb.dev,
+       .dev.platform_data      = &smdkc100_lcd_power_data,
+};
+
+/* Frame Buffer */
+static struct s3c_fb_pd_win smdkc100_fb_win0 = {
+       /* this is to ensure we use win0 */
+       .win_mode       = {
+               .refresh        = 70,
+               .pixclock       = (8+13+3+800)*(7+5+1+480),
+               .left_margin    = 8,
+               .right_margin   = 13,
+               .upper_margin   = 7,
+               .lower_margin   = 5,
+               .hsync_len      = 3,
+               .vsync_len      = 1,
+               .xres           = 800,
+               .yres           = 480,
+       },
+       .max_bpp        = 32,
+       .default_bpp    = 16,
+};
+
+static struct s3c_fb_platdata smdkc100_lcd_pdata __initdata = {
+       .win[0]         = &smdkc100_fb_win0,
+       .vidcon0        = VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB,
+       .vidcon1        = VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC,
+       .setup_gpio     = s5pc100_fb_gpio_setup_24bpp,
+};
+
 static struct map_desc smdkc100_iodesc[] = {};
 
 static struct platform_device *smdkc100_devices[] __initdata = {
+       &s3c_device_i2c0,
+       &s3c_device_i2c1,
+       &s3c_device_fb,
+       &s3c_device_hsmmc0,
+       &s3c_device_hsmmc1,
+       &s3c_device_hsmmc2,
+       &smdkc100_lcd_powerdev,
 };
 
 static void __init smdkc100_map_io(void)
@@ -87,12 +162,24 @@ static void __init smdkc100_map_io(void)
 
 static void __init smdkc100_machine_init(void)
 {
+       /* I2C */
+       s3c_i2c0_set_platdata(NULL);
+       s3c_i2c1_set_platdata(NULL);
+       i2c_register_board_info(0, i2c_devs0, ARRAY_SIZE(i2c_devs0));
+       i2c_register_board_info(1, i2c_devs1, ARRAY_SIZE(i2c_devs1));
+
+       s3c_fb_set_platdata(&smdkc100_lcd_pdata);
+
+       /* LCD init */
+       gpio_request(S5PC100_GPD(0), "GPD");
+       gpio_request(S5PC100_GPH0(6), "GPH0");
+       smdkc100_lcd_power_set(&smdkc100_lcd_power_data, 0);
        platform_add_devices(smdkc100_devices, ARRAY_SIZE(smdkc100_devices));
 }
 
 MACHINE_START(SMDKC100, "SMDKC100")
        /* Maintainer: Byungho Min <bhmin@samsung.com> */
-       .phys_io        = S5PC1XX_PA_UART & 0xfff00000,
+       .phys_io        = S5PC100_PA_UART & 0xfff00000,
        .io_pg_offst    = (((u32)S5PC1XX_VA_UART) >> 18) & 0xfffc,
        .boot_params    = S5PC100_PA_SDRAM + 0x100,
 
diff --git a/arch/arm/mach-s5pc100/setup-sdhci.c b/arch/arm/mach-s5pc100/setup-sdhci.c
new file mode 100644 (file)
index 0000000..4385986
--- /dev/null
@@ -0,0 +1,65 @@
+/* linux/arch/arm/mach-s5pc100/setup-sdhci.c
+ *
+ * Copyright 2008 Samsung Electronics
+ *
+ * S5PC100 - Helper functions for settign up SDHCI device(s) (HSMMC)
+ *
+ * Based on mach-s3c6410/setup-sdhci.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.
+*/
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+
+#include <linux/mmc/card.h>
+#include <linux/mmc/host.h>
+
+#include <plat/regs-sdhci.h>
+#include <plat/sdhci.h>
+
+/* clock sources for the mmc bus clock, order as for the ctrl2[5..4] */
+
+char *s5pc100_hsmmc_clksrcs[4] = {
+       [0] = "hsmmc",
+       [1] = "hsmmc",
+       /* [2] = "mmc_bus", not yet succesfuuly used yet */
+       /* [3] = "48m", - note not succesfully used yet */
+};
+
+
+void s5pc100_setup_sdhci0_cfg_card(struct platform_device *dev,
+                                   void __iomem *r,
+                                   struct mmc_ios *ios,
+                                   struct mmc_card *card)
+{
+       u32 ctrl2, ctrl3;
+
+       /* don't need to alter anything acording to card-type */
+
+       writel(S3C64XX_SDHCI_CONTROL4_DRIVE_9mA, r + S3C64XX_SDHCI_CONTROL4);
+
+       ctrl2 = readl(r + S3C_SDHCI_CONTROL2);
+       ctrl2 &= S3C_SDHCI_CTRL2_SELBASECLK_MASK;
+       ctrl2 |= (S3C64XX_SDHCI_CTRL2_ENSTAASYNCCLR |
+                 S3C64XX_SDHCI_CTRL2_ENCMDCNFMSK |
+                 S3C_SDHCI_CTRL2_ENFBCLKRX |
+                 S3C_SDHCI_CTRL2_DFCNT_NONE |
+                 S3C_SDHCI_CTRL2_ENCLKOUTHOLD);
+
+       if (ios->clock < 25 * 1000000)
+               ctrl3 = (S3C_SDHCI_CTRL3_FCSEL3 |
+                        S3C_SDHCI_CTRL3_FCSEL2 |
+                        S3C_SDHCI_CTRL3_FCSEL1 |
+                        S3C_SDHCI_CTRL3_FCSEL0);
+       else
+               ctrl3 = (S3C_SDHCI_CTRL3_FCSEL1 | S3C_SDHCI_CTRL3_FCSEL0);
+
+       writel(ctrl2, r + S3C_SDHCI_CONTROL2);
+       writel(ctrl3, r + S3C_SDHCI_CONTROL3);
+}
index 4e5c07f..03a7f38 100644 (file)
@@ -53,23 +53,23 @@ config SA1100_COLLIE
 
 config SA1100_H3100
        bool "Compaq iPAQ H3100"
+       select HTC_EGPIO
        help
          Say Y here if you intend to run this kernel on the Compaq iPAQ
          H3100 handheld computer.  Information about this machine and the
          Linux port to this machine can be found at:
 
          <http://www.handhelds.org/Compaq/index.html#iPAQ_H3100>
-         <http://www.compaq.com/products/handhelds/pocketpc/>
 
 config SA1100_H3600
        bool "Compaq iPAQ H3600/H3700"
+       select HTC_EGPIO
        help
          Say Y here if you intend to run this kernel on the Compaq iPAQ
          H3600 handheld computer.  Information about this machine and the
          Linux port to this machine can be found at:
 
          <http://www.handhelds.org/Compaq/index.html#iPAQ_H3600>
-         <http://www.compaq.com/products/handhelds/pocketpc/>
 
 config SA1100_BADGE4
        bool "HP Labs BadgePAD 4"
index bb7b819..89349c1 100644 (file)
@@ -25,8 +25,8 @@ led-$(CONFIG_SA1100_CERF)             += leds-cerf.o
 
 obj-$(CONFIG_SA1100_COLLIE)            += collie.o
 
-obj-$(CONFIG_SA1100_H3100)             += h3600.o
-obj-$(CONFIG_SA1100_H3600)             += h3600.o
+obj-$(CONFIG_SA1100_H3100)             += h3100.o h3xxx.o
+obj-$(CONFIG_SA1100_H3600)             += h3600.o h3xxx.o
 
 obj-$(CONFIG_SA1100_HACKKIT)           += hackkit.o
 led-$(CONFIG_SA1100_HACKKIT)           += leds-hackkit.o
index 55e6447..169e5b8 100644 (file)
@@ -249,10 +249,10 @@ static void __init assabet_init(void)
 #endif
        }
 
-       sa11x0_set_flash_data(&assabet_flash_data, assabet_flash_resources,
-                             ARRAY_SIZE(assabet_flash_resources));
-       sa11x0_set_irda_data(&assabet_irda_data);
-       sa11x0_set_mcp_data(&assabet_mcp_data);
+       sa11x0_register_mtd(&assabet_flash_data, assabet_flash_resources,
+                           ARRAY_SIZE(assabet_flash_resources));
+       sa11x0_register_irda(&assabet_irda_data);
+       sa11x0_register_mcp(&assabet_mcp_data);
 }
 
 /*
index ab5883b..051ec0f 100644 (file)
@@ -212,7 +212,7 @@ static int __init badge4_init(void)
        /* maybe turn on 5v0 from the start */
        badge4_set_5V(BADGE4_5V_INITIALLY, five_v_on);
 
-       sa11x0_set_flash_data(&badge4_flash_data, &badge4_flash_resource, 1);
+       sa11x0_register_mtd(&badge4_flash_data, &badge4_flash_resource, 1);
 
        return 0;
 }
index fd3ad9c..bc950ef 100644 (file)
@@ -129,8 +129,8 @@ static struct mcp_plat_data cerf_mcp_data = {
 static void __init cerf_init(void)
 {
        platform_add_devices(cerf_devices, ARRAY_SIZE(cerf_devices));
-       sa11x0_set_flash_data(&cerf_flash_data, &cerf_flash_resource, 1);
-       sa11x0_set_mcp_data(&cerf_mcp_data);
+       sa11x0_register_mtd(&cerf_flash_data, &cerf_flash_resource, 1);
+       sa11x0_register_mcp(&cerf_mcp_data);
 }
 
 MACHINE_START(CERF, "Intrinsyc CerfBoard/CerfCube")
index bbf2ebc..9982c5c 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/mtd/partitions.h>
 #include <linux/timer.h>
 #include <linux/gpio.h>
+#include <linux/pda_power.h>
 
 #include <mach/hardware.h>
 #include <asm/mach-types.h>
@@ -56,6 +57,7 @@ static struct resource collie_scoop_resources[] = {
 static struct scoop_config collie_scoop_setup = {
        .io_dir         = COLLIE_SCOOP_IO_DIR,
        .io_out         = COLLIE_SCOOP_IO_OUT,
+       .gpio_base      = COLLIE_SCOOP_GPIO_BASE,
 };
 
 struct platform_device colliescoop_device = {
@@ -85,6 +87,70 @@ static struct scoop_pcmcia_config collie_pcmcia_config = {
 static struct mcp_plat_data collie_mcp_data = {
        .mccr0          = MCCR0_ADM | MCCR0_ExtClk,
        .sclk_rate      = 9216000,
+       .gpio_base      = COLLIE_TC35143_GPIO_BASE,
+};
+
+/*
+ * Collie AC IN
+ */
+static int collie_power_init(struct device *dev)
+{
+       int ret = gpio_request(COLLIE_GPIO_AC_IN, "ac in");
+       if (ret)
+               goto err_gpio_req;
+
+       ret = gpio_direction_input(COLLIE_GPIO_AC_IN);
+       if (ret)
+               goto err_gpio_in;
+
+       return 0;
+
+err_gpio_in:
+       gpio_free(COLLIE_GPIO_AC_IN);
+err_gpio_req:
+       return ret;
+}
+
+static void collie_power_exit(struct device *dev)
+{
+       gpio_free(COLLIE_GPIO_AC_IN);
+}
+
+static int collie_power_ac_online(void)
+{
+       return gpio_get_value(COLLIE_GPIO_AC_IN) == 2;
+}
+
+static char *collie_ac_supplied_to[] = {
+       "main-battery",
+       "backup-battery",
+};
+
+static struct pda_power_pdata collie_power_data = {
+       .init                   = collie_power_init,
+       .is_ac_online           = collie_power_ac_online,
+       .exit                   = collie_power_exit,
+       .supplied_to            = collie_ac_supplied_to,
+       .num_supplicants        = ARRAY_SIZE(collie_ac_supplied_to),
+};
+
+static struct resource collie_power_resource[] = {
+       {
+               .name           = "ac",
+               .start          = gpio_to_irq(COLLIE_GPIO_AC_IN),
+               .end            = gpio_to_irq(COLLIE_GPIO_AC_IN),
+               .flags          = IORESOURCE_IRQ |
+                                 IORESOURCE_IRQ_HIGHEDGE |
+                                 IORESOURCE_IRQ_LOWEDGE,
+       },
+};
+
+static struct platform_device collie_power_device = {
+       .name                   = "pda-power",
+       .id                     = -1,
+       .dev.platform_data      = &collie_power_data,
+       .resource               = collie_power_resource,
+       .num_resources          = ARRAY_SIZE(collie_power_resource),
 };
 
 #ifdef CONFIG_SHARP_LOCOMO
@@ -178,6 +244,7 @@ struct platform_device collie_locomo_device = {
 static struct platform_device *devices[] __initdata = {
        &collie_locomo_device,
        &colliescoop_device,
+       &collie_power_device,
 };
 
 static struct mtd_partition collie_partitions[] = {
@@ -248,22 +315,24 @@ static void __init collie_init(void)
        GPDR = GPIO_LDD8 | GPIO_LDD9 | GPIO_LDD10 | GPIO_LDD11 | GPIO_LDD12 |
                GPIO_LDD13 | GPIO_LDD14 | GPIO_LDD15 | GPIO_SSP_TXD |
                GPIO_SSP_SCLK | GPIO_SSP_SFRM | GPIO_SDLC_SCLK |
-               COLLIE_GPIO_UCB1x00_RESET | COLLIE_GPIO_nMIC_ON |
-               COLLIE_GPIO_nREMOCON_ON | GPIO_32_768kHz;
+               _COLLIE_GPIO_UCB1x00_RESET | _COLLIE_GPIO_nMIC_ON |
+               _COLLIE_GPIO_nREMOCON_ON | GPIO_32_768kHz;
 
        PPDR = PPC_LDD0 | PPC_LDD1 | PPC_LDD2 | PPC_LDD3 | PPC_LDD4 | PPC_LDD5 |
                PPC_LDD6 | PPC_LDD7 | PPC_L_PCLK | PPC_L_LCLK | PPC_L_FCLK | PPC_L_BIAS |
                PPC_TXD1 | PPC_TXD2 | PPC_TXD3 | PPC_TXD4 | PPC_SCLK | PPC_SFRM;
 
-       PWER = COLLIE_GPIO_AC_IN | COLLIE_GPIO_CO | COLLIE_GPIO_ON_KEY |
-               COLLIE_GPIO_WAKEUP | COLLIE_GPIO_nREMOCON_INT | PWER_RTC;
+       PWER = _COLLIE_GPIO_AC_IN | _COLLIE_GPIO_CO | _COLLIE_GPIO_ON_KEY |
+               _COLLIE_GPIO_WAKEUP | _COLLIE_GPIO_nREMOCON_INT | PWER_RTC;
 
-       PGSR = COLLIE_GPIO_nREMOCON_ON;
+       PGSR = _COLLIE_GPIO_nREMOCON_ON;
 
        PSDR = PPC_RXD1 | PPC_RXD2 | PPC_RXD3 | PPC_RXD4;
 
        PCFR = PCFR_OPDE;
 
+       GPSR |= _COLLIE_GPIO_UCB1x00_RESET;
+
 
        platform_scoop_config = &collie_pcmcia_config;
 
@@ -272,9 +341,9 @@ static void __init collie_init(void)
                printk(KERN_WARNING "collie: Unable to register LoCoMo device\n");
        }
 
-       sa11x0_set_flash_data(&collie_flash_data, collie_flash_resources,
-                             ARRAY_SIZE(collie_flash_resources));
-       sa11x0_set_mcp_data(&collie_mcp_data);
+       sa11x0_register_mtd(&collie_flash_data, collie_flash_resources,
+                           ARRAY_SIZE(collie_flash_resources));
+       sa11x0_register_mcp(&collie_mcp_data);
 
        sharpsl_save_param();
 }
index 23cfdd5..9faea15 100644 (file)
@@ -162,6 +162,17 @@ static void sa1100_power_off(void)
        PMCR = PMCR_SF;
 }
 
+static void sa11x0_register_device(struct platform_device *dev, void *data)
+{
+       int err;
+       dev->dev.platform_data = data;
+       err = platform_device_register(dev);
+       if (err)
+               printk(KERN_ERR "Unable to register device %s: %d\n",
+                       dev->name, err);
+}
+
+
 static struct resource sa11x0udc_resources[] = {
        [0] = {
                .start  = 0x80000000,
@@ -234,9 +245,9 @@ static struct platform_device sa11x0mcp_device = {
        .resource       = sa11x0mcp_resources,
 };
 
-void sa11x0_set_mcp_data(struct mcp_plat_data *data)
+void sa11x0_register_mcp(struct mcp_plat_data *data)
 {
-       sa11x0mcp_device.dev.platform_data = data;
+       sa11x0_register_device(&sa11x0mcp_device, data);
 }
 
 static struct resource sa11x0ssp_resources[] = {
@@ -293,13 +304,13 @@ static struct platform_device sa11x0mtd_device = {
        .id             = -1,
 };
 
-void sa11x0_set_flash_data(struct flash_platform_data *flash,
-                          struct resource *res, int nr)
+void sa11x0_register_mtd(struct flash_platform_data *flash,
+                        struct resource *res, int nr)
 {
        flash->name = "sa1100";
-       sa11x0mtd_device.dev.platform_data = flash;
        sa11x0mtd_device.resource = res;
        sa11x0mtd_device.num_resources = nr;
+       sa11x0_register_device(&sa11x0mtd_device, flash);
 }
 
 static struct resource sa11x0ir_resources[] = {
@@ -329,9 +340,9 @@ static struct platform_device sa11x0ir_device = {
        .resource       = sa11x0ir_resources,
 };
 
-void sa11x0_set_irda_data(struct irda_platform_data *irda)
+void sa11x0_register_irda(struct irda_platform_data *irda)
 {
-       sa11x0ir_device.dev.platform_data = irda;
+       sa11x0_register_device(&sa11x0ir_device, irda);
 }
 
 static struct platform_device sa11x0rtc_device = {
@@ -343,21 +354,15 @@ static struct platform_device *sa11x0_devices[] __initdata = {
        &sa11x0udc_device,
        &sa11x0uart1_device,
        &sa11x0uart3_device,
-       &sa11x0mcp_device,
        &sa11x0ssp_device,
        &sa11x0pcmcia_device,
        &sa11x0fb_device,
-       &sa11x0mtd_device,
        &sa11x0rtc_device,
 };
 
 static int __init sa1100_init(void)
 {
        pm_power_off = sa1100_power_off;
-
-       if (sa11x0ir_device.dev.platform_data)
-               platform_device_register(&sa11x0ir_device);
-
        return platform_add_devices(sa11x0_devices, ARRAY_SIZE(sa11x0_devices));
 }
 
index 793c2e6..ec03f18 100644 (file)
@@ -32,14 +32,11 @@ extern unsigned int sa11x0_ppcr_to_freq(unsigned int idx);
 struct flash_platform_data;
 struct resource;
 
-extern void sa11x0_set_flash_data(struct flash_platform_data *flash,
-                                 struct resource *res, int nr);
-
-struct sa11x0_ssp_plat_ops;
-extern void sa11x0_set_ssp_data(struct sa11x0_ssp_plat_ops *ops);
+void sa11x0_register_mtd(struct flash_platform_data *flash,
+                        struct resource *res, int nr);
 
 struct irda_platform_data;
-void sa11x0_set_irda_data(struct irda_platform_data *irda);
+void sa11x0_register_irda(struct irda_platform_data *irda);
 
 struct mcp_plat_data;
-void sa11x0_set_mcp_data(struct mcp_plat_data *data);
+void sa11x0_register_mcp(struct mcp_plat_data *data);
diff --git a/arch/arm/mach-sa1100/h3100.c b/arch/arm/mach-sa1100/h3100.c
new file mode 100644 (file)
index 0000000..0c7cea0
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * Support for Compaq iPAQ H3100 handheld computer
+ *
+ * Copyright (c) 2000,1 Compaq Computer Corporation. (Author: Jamey Hicks)
+ * Copyright (c) 2009 Dmitry Artamonow <mad_soft@inbox.ru>
+ *
+ * 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/kernel.h>
+#include <linux/gpio.h>
+
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/irda.h>
+
+#include <mach/h3xxx.h>
+
+#include "generic.h"
+
+/*
+ * helper for sa1100fb
+ */
+static void h3100_lcd_power(int enable)
+{
+       if (!gpio_request(H3XXX_EGPIO_LCD_ON, "LCD ON")) {
+               gpio_set_value(H3100_GPIO_LCD_3V_ON, enable);
+               gpio_direction_output(H3XXX_EGPIO_LCD_ON, enable);
+               gpio_free(H3XXX_EGPIO_LCD_ON);
+       } else {
+               pr_err("%s: can't request H3XXX_EGPIO_LCD_ON\n", __func__);
+       }
+}
+
+
+static void __init h3100_map_io(void)
+{
+       h3xxx_map_io();
+
+       sa1100fb_lcd_power = h3100_lcd_power;
+
+       /* Older bootldrs put GPIO2-9 in alternate mode on the
+          assumption that they are used for video */
+       GAFR &= ~0x000001fb;
+}
+
+/*
+ * This turns the IRDA power on or off on the Compaq H3100
+ */
+static int h3100_irda_set_power(struct device *dev, unsigned int state)
+{
+       gpio_set_value(H3100_GPIO_IR_ON, state);
+       return 0;
+}
+
+static void h3100_irda_set_speed(struct device *dev, unsigned int speed)
+{
+       gpio_set_value(H3100_GPIO_IR_FSEL, !(speed < 4000000));
+}
+
+static struct irda_platform_data h3100_irda_data = {
+       .set_power      = h3100_irda_set_power,
+       .set_speed      = h3100_irda_set_speed,
+};
+
+static struct gpio_default_state h3100_default_gpio[] = {
+       { H3100_GPIO_IR_ON,     GPIO_MODE_OUT0, "IrDA power" },
+       { H3100_GPIO_IR_FSEL,   GPIO_MODE_OUT0, "IrDA fsel" },
+       { H3XXX_GPIO_COM_DCD,   GPIO_MODE_IN,   "COM DCD" },
+       { H3XXX_GPIO_COM_CTS,   GPIO_MODE_IN,   "COM CTS" },
+       { H3XXX_GPIO_COM_RTS,   GPIO_MODE_OUT0, "COM RTS" },
+       { H3100_GPIO_LCD_3V_ON, GPIO_MODE_OUT0, "LCD 3v" },
+};
+
+static void __init h3100_mach_init(void)
+{
+       h3xxx_init_gpio(h3100_default_gpio, ARRAY_SIZE(h3100_default_gpio));
+       h3xxx_mach_init();
+       sa11x0_register_irda(&h3100_irda_data);
+}
+
+MACHINE_START(H3100, "Compaq iPAQ H3100")
+       .phys_io        = 0x80000000,
+       .io_pg_offst    = ((0xf8000000) >> 18) & 0xfffc,
+       .boot_params    = 0xc0000100,
+       .map_io         = h3100_map_io,
+       .init_irq       = sa1100_init_irq,
+       .timer          = &sa1100_timer,
+       .init_machine   = h3100_mach_init,
+MACHINE_END
+
index 0eb2f15..af3b714 100644 (file)
 /*
- * Hardware definitions for Compaq iPAQ H3xxx Handheld Computers
+ * Support for Compaq iPAQ H3600 handheld computer
  *
- * Copyright 2000,1 Compaq Computer Corporation.
+ * Copyright (c) 2000,1 Compaq Computer Corporation. (Author: Jamey Hicks)
+ * Copyright (c) 2009 Dmitry Artamonow <mad_soft@inbox.ru>
  *
- * Use consistent with the GNU GPL is permitted,
- * provided that this copyright notice is
- * preserved in its entirety in all copies and derived works.
- *
- * COMPAQ COMPUTER CORPORATION MAKES NO WARRANTIES, EXPRESSED OR IMPLIED,
- * AS TO THE USEFULNESS OR CORRECTNESS OF THIS CODE OR ITS
- * FITNESS FOR ANY PARTICULAR PURPOSE.
- *
- * Author: Jamey Hicks.
- *
- * History:
- *
- * 2001-10-??  Andrew Christian   Added support for iPAQ H3800
- *                                and abstracted EGPIO interface.
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
  *
  */
-#include <linux/module.h>
+
 #include <linux/init.h>
 #include <linux/kernel.h>
-#include <linux/tty.h>
-#include <linux/pm.h>
-#include <linux/device.h>
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/partitions.h>
-#include <linux/serial_core.h>
+#include <linux/gpio.h>
 
-#include <asm/irq.h>
-#include <mach/hardware.h>
 #include <asm/mach-types.h>
-#include <asm/setup.h>
-
-#include <asm/mach/irq.h>
 #include <asm/mach/arch.h>
-#include <asm/mach/flash.h>
 #include <asm/mach/irda.h>
-#include <asm/mach/map.h>
-#include <asm/mach/serial_sa1100.h>
 
-#include <mach/h3600.h>
-#include <mach/h3600_gpio.h>
+#include <mach/h3xxx.h>
 
 #include "generic.h"
 
-void (*assign_h3600_egpio)(enum ipaq_egpio_type x, int level);
-EXPORT_SYMBOL(assign_h3600_egpio);
-
-static struct mtd_partition h3xxx_partitions[] = {
-       {
-               .name           = "H3XXX boot firmware",
-               .size           = 0x00040000,
-               .offset         = 0,
-               .mask_flags     = MTD_WRITEABLE,  /* force read-only */
-       }, {
-               .name           = "H3XXX rootfs",
-               .size           = MTDPART_SIZ_FULL,
-               .offset         = 0x00040000,
-       }
-};
-
-static void h3xxx_set_vpp(int vpp)
-{
-       assign_h3600_egpio(IPAQ_EGPIO_VPP_ON, vpp);
-}
-
-static struct flash_platform_data h3xxx_flash_data = {
-       .map_name       = "cfi_probe",
-       .set_vpp        = h3xxx_set_vpp,
-       .parts          = h3xxx_partitions,
-       .nr_parts       = ARRAY_SIZE(h3xxx_partitions),
-};
-
-static struct resource h3xxx_flash_resource = {
-       .start          = SA1100_CS0_PHYS,
-       .end            = SA1100_CS0_PHYS + SZ_32M - 1,
-       .flags          = IORESOURCE_MEM,
-};
-
 /*
- * This turns the IRDA power on or off on the Compaq H3600
- */
-static int h3600_irda_set_power(struct device *dev, unsigned int state)
-{
-       assign_h3600_egpio( IPAQ_EGPIO_IR_ON, state );
-
-       return 0;
-}
-
-static void h3600_irda_set_speed(struct device *dev, unsigned int speed)
-{
-       assign_h3600_egpio(IPAQ_EGPIO_IR_FSEL, !(speed < 4000000));
-}
-
-static struct irda_platform_data h3600_irda_data = {
-       .set_power      = h3600_irda_set_power,
-       .set_speed      = h3600_irda_set_speed,
-};
-
-static void h3xxx_mach_init(void)
-{
-       sa11x0_set_flash_data(&h3xxx_flash_data, &h3xxx_flash_resource, 1);
-       sa11x0_set_irda_data(&h3600_irda_data);
-}
-
-/*
- * low-level UART features
+ * helper for sa1100fb
  */
-
-static void h3600_uart_set_mctrl(struct uart_port *port, u_int mctrl)
+static void h3600_lcd_power(int enable)
 {
-       if (port->mapbase == _Ser3UTCR0) {
-               if (mctrl & TIOCM_RTS)
-                       GPCR = GPIO_H3600_COM_RTS;
-               else
-                       GPSR = GPIO_H3600_COM_RTS;
+       if (gpio_request(H3XXX_EGPIO_LCD_ON, "LCD power")) {
+               pr_err("%s: can't request H3XXX_EGPIO_LCD_ON\n", __func__);
+               goto err1;
        }
-}
-
-static u_int h3600_uart_get_mctrl(struct uart_port *port)
-{
-       u_int ret = TIOCM_CD | TIOCM_CTS | TIOCM_DSR;
-
-       if (port->mapbase == _Ser3UTCR0) {
-               int gplr = GPLR;
-               /* DCD and CTS bits are inverted in GPLR by RS232 transceiver */
-               if (gplr & GPIO_H3600_COM_DCD)
-                       ret &= ~TIOCM_CD;
-               if (gplr & GPIO_H3600_COM_CTS)
-                       ret &= ~TIOCM_CTS;
+       if (gpio_request(H3600_EGPIO_LCD_PCI, "LCD control")) {
+               pr_err("%s: can't request H3XXX_EGPIO_LCD_PCI\n", __func__);
+               goto err2;
+       }
+       if (gpio_request(H3600_EGPIO_LCD_5V_ON, "LCD 5v")) {
+               pr_err("%s: can't request H3XXX_EGPIO_LCD_5V_ON\n", __func__);
+               goto err3;
+       }
+       if (gpio_request(H3600_EGPIO_LVDD_ON, "LCD 9v/-6.5v")) {
+               pr_err("%s: can't request H3600_EGPIO_LVDD_ON\n", __func__);
+               goto err4;
        }
 
-       return ret;
-}
+       gpio_direction_output(H3XXX_EGPIO_LCD_ON, enable);
+       gpio_direction_output(H3600_EGPIO_LCD_PCI, enable);
+       gpio_direction_output(H3600_EGPIO_LCD_5V_ON, enable);
+       gpio_direction_output(H3600_EGPIO_LVDD_ON, enable);
 
-static void h3600_uart_pm(struct uart_port *port, u_int state, u_int oldstate)
-{
-       if (port->mapbase == _Ser2UTCR0) { /* TODO: REMOVE THIS */
-               assign_h3600_egpio(IPAQ_EGPIO_IR_ON, !state);
-       } else if (port->mapbase == _Ser3UTCR0) {
-               assign_h3600_egpio(IPAQ_EGPIO_RS232_ON, !state);
-       }
+       gpio_free(H3600_EGPIO_LVDD_ON);
+err4:  gpio_free(H3600_EGPIO_LCD_5V_ON);
+err3:  gpio_free(H3600_EGPIO_LCD_PCI);
+err2:  gpio_free(H3XXX_EGPIO_LCD_ON);
+err1:  return;
 }
 
-/*
- * Enable/Disable wake up events for this serial port.
- * Obviously, we only support this on the normal COM port.
- */
-static int h3600_uart_set_wake(struct uart_port *port, u_int enable)
+static void __init h3600_map_io(void)
 {
-       int err = -EINVAL;
+       h3xxx_map_io();
 
-       if (port->mapbase == _Ser3UTCR0) {
-               if (enable)
-                       PWER |= PWER_GPIO23 | PWER_GPIO25; /* DCD and CTS */
-               else
-                       PWER &= ~(PWER_GPIO23 | PWER_GPIO25); /* DCD and CTS */
-               err = 0;
-       }
-       return err;
+       sa1100fb_lcd_power = h3600_lcd_power;
 }
 
-static struct sa1100_port_fns h3600_port_fns __initdata = {
-       .set_mctrl      = h3600_uart_set_mctrl,
-       .get_mctrl      = h3600_uart_get_mctrl,
-       .pm             = h3600_uart_pm,
-       .set_wake       = h3600_uart_set_wake,
-};
-
 /*
- * helper for sa1100fb
+ * This turns the IRDA power on or off on the Compaq H3600
  */
-static void h3xxx_lcd_power(int enable)
+static int h3600_irda_set_power(struct device *dev, unsigned int state)
 {
-       assign_h3600_egpio(IPAQ_EGPIO_LCD_POWER, enable);
+       gpio_set_value(H3600_EGPIO_IR_ON, state);
+       return 0;
 }
 
-static struct map_desc h3600_io_desc[] __initdata = {
-       {       /* static memory bank 2  CS#2 */
-               .virtual        =  H3600_BANK_2_VIRT,
-               .pfn            = __phys_to_pfn(SA1100_CS2_PHYS),
-               .length         = 0x02800000,
-               .type           = MT_DEVICE
-       }, {    /* static memory bank 4  CS#4 */
-               .virtual        =  H3600_BANK_4_VIRT,
-               .pfn            = __phys_to_pfn(SA1100_CS4_PHYS),
-               .length         = 0x00800000,
-               .type           = MT_DEVICE
-       }, {    /* EGPIO 0              CS#5 */
-               .virtual        =  H3600_EGPIO_VIRT,
-               .pfn            = __phys_to_pfn(H3600_EGPIO_PHYS),
-               .length         = 0x01000000,
-               .type           = MT_DEVICE
-       }
-};
-
-/*
- * Common map_io initialization
- */
-
-static void __init h3xxx_map_io(void)
+static void h3600_irda_set_speed(struct device *dev, unsigned int speed)
 {
-       sa1100_map_io();
-       iotable_init(h3600_io_desc, ARRAY_SIZE(h3600_io_desc));
-
-       sa1100_register_uart_fns(&h3600_port_fns);
-       sa1100_register_uart(0, 3); /* Common serial port */
-//     sa1100_register_uart(1, 1); /* Microcontroller on 3100/3600 */
-
-       /* Ensure those pins are outputs and driving low  */
-       PPDR |= PPC_TXD4 | PPC_SCLK | PPC_SFRM;
-       PPSR &= ~(PPC_TXD4 | PPC_SCLK | PPC_SFRM);
-
-       /* Configure suspend conditions */
-       PGSR = 0;
-       PWER = PWER_GPIO0 | PWER_RTC;
-       PCFR = PCFR_OPDE;
-       PSDR = 0;
-
-       sa1100fb_lcd_power = h3xxx_lcd_power;
+       gpio_set_value(H3600_EGPIO_IR_FSEL, !(speed < 4000000));
 }
 
-/************************* H3100 *************************/
-
-#ifdef CONFIG_SA1100_H3100
-
-#define H3100_EGPIO    (*(volatile unsigned int *)H3600_EGPIO_VIRT)
-static unsigned int h3100_egpio = 0;
-
-static void h3100_control_egpio(enum ipaq_egpio_type x, int setp)
+static int h3600_irda_startup(struct device *dev)
 {
-       unsigned int egpio = 0;
-       long         gpio = 0;
-       unsigned long flags;
-
-       switch (x) {
-       case IPAQ_EGPIO_LCD_POWER:
-               egpio |= EGPIO_H3600_LCD_ON;
-               gpio  |= GPIO_H3100_LCD_3V_ON;
-               break;
-       case IPAQ_EGPIO_LCD_ENABLE:
-               break;
-       case IPAQ_EGPIO_CODEC_NRESET:
-               egpio |= EGPIO_H3600_CODEC_NRESET;
-               break;
-       case IPAQ_EGPIO_AUDIO_ON:
-               gpio |= GPIO_H3100_AUD_PWR_ON
-                       | GPIO_H3100_AUD_ON;
-               break;
-       case IPAQ_EGPIO_QMUTE:
-               gpio |= GPIO_H3100_QMUTE;
-               break;
-       case IPAQ_EGPIO_OPT_NVRAM_ON:
-               egpio |= EGPIO_H3600_OPT_NVRAM_ON;
-               break;
-       case IPAQ_EGPIO_OPT_ON:
-               egpio |= EGPIO_H3600_OPT_ON;
-               break;
-       case IPAQ_EGPIO_CARD_RESET:
-               egpio |= EGPIO_H3600_CARD_RESET;
-               break;
-       case IPAQ_EGPIO_OPT_RESET:
-               egpio |= EGPIO_H3600_OPT_RESET;
-               break;
-       case IPAQ_EGPIO_IR_ON:
-               gpio |= GPIO_H3100_IR_ON;
-               break;
-       case IPAQ_EGPIO_IR_FSEL:
-               gpio |= GPIO_H3100_IR_FSEL;
-               break;
-       case IPAQ_EGPIO_RS232_ON:
-               egpio |= EGPIO_H3600_RS232_ON;
-               break;
-       case IPAQ_EGPIO_VPP_ON:
-               egpio |= EGPIO_H3600_VPP_ON;
-               break;
-       }
+       int err = gpio_request(H3600_EGPIO_IR_ON, "IrDA power");
+       if (err)
+               goto err1;
+       err = gpio_direction_output(H3600_EGPIO_IR_ON, 0);
+       if (err)
+               goto err2;
+       err = gpio_request(H3600_EGPIO_IR_FSEL, "IrDA fsel");
+       if (err)
+               goto err2;
+       err = gpio_direction_output(H3600_EGPIO_IR_FSEL, 0);
+       if (err)
+               goto err3;
+       return 0;
 
-       if (egpio || gpio) {
-               local_irq_save(flags);
-               if (setp) {
-                       h3100_egpio |= egpio;
-                       GPSR = gpio;
-               } else {
-                       h3100_egpio &= ~egpio;
-                       GPCR = gpio;
-               }
-               H3100_EGPIO = h3100_egpio;
-               local_irq_restore(flags);
-       }
+err3:  gpio_free(H3600_EGPIO_IR_FSEL);
+err2:  gpio_free(H3600_EGPIO_IR_ON);
+err1:  return err;
 }
 
-#define H3100_DIRECT_EGPIO (GPIO_H3100_BT_ON     \
-                         | GPIO_H3100_GPIO3      \
-                         | GPIO_H3100_QMUTE      \
-                         | GPIO_H3100_LCD_3V_ON  \
-                         | GPIO_H3100_AUD_ON     \
-                         | GPIO_H3100_AUD_PWR_ON \
-                         | GPIO_H3100_IR_ON      \
-                         | GPIO_H3100_IR_FSEL)
-
-static void __init h3100_map_io(void)
+static void h3600_irda_shutdown(struct device *dev)
 {
-       h3xxx_map_io();
-
-       /* Initialize h3100-specific values here */
-       GPCR = 0x0fffffff;       /* All outputs are set low by default */
-       GPDR = GPIO_H3600_COM_RTS  | GPIO_H3600_L3_CLOCK |
-              GPIO_H3600_L3_MODE  | GPIO_H3600_L3_DATA  |
-              GPIO_H3600_CLK_SET1 | GPIO_H3600_CLK_SET0 |
-              H3100_DIRECT_EGPIO;
-
-       /* Older bootldrs put GPIO2-9 in alternate mode on the
-          assumption that they are used for video */
-       GAFR &= ~H3100_DIRECT_EGPIO;
-
-       H3100_EGPIO = h3100_egpio;
-       assign_h3600_egpio = h3100_control_egpio;
+       gpio_free(H3600_EGPIO_IR_ON);
+       gpio_free(H3600_EGPIO_IR_FSEL);
 }
 
-MACHINE_START(H3100, "Compaq iPAQ H3100")
-       .phys_io        = 0x80000000,
-       .io_pg_offst    = ((0xf8000000) >> 18) & 0xfffc,
-       .boot_params    = 0xc0000100,
-       .map_io         = h3100_map_io,
-       .init_irq       = sa1100_init_irq,
-       .timer          = &sa1100_timer,
-       .init_machine   = h3xxx_mach_init,
-MACHINE_END
-
-#endif /* CONFIG_SA1100_H3100 */
-
-/************************* H3600 *************************/
-
-#ifdef CONFIG_SA1100_H3600
-
-#define H3600_EGPIO    (*(volatile unsigned int *)H3600_EGPIO_VIRT)
-static unsigned int h3600_egpio = EGPIO_H3600_RS232_ON;
-
-static void h3600_control_egpio(enum ipaq_egpio_type x, int setp)
-{
-       unsigned int egpio = 0;
-       unsigned long flags;
-
-       switch (x) {
-       case IPAQ_EGPIO_LCD_POWER:
-               egpio |= EGPIO_H3600_LCD_ON |
-                        EGPIO_H3600_LCD_PCI |
-                        EGPIO_H3600_LCD_5V_ON |
-                        EGPIO_H3600_LVDD_ON;
-               break;
-       case IPAQ_EGPIO_LCD_ENABLE:
-               break;
-       case IPAQ_EGPIO_CODEC_NRESET:
-               egpio |= EGPIO_H3600_CODEC_NRESET;
-               break;
-       case IPAQ_EGPIO_AUDIO_ON:
-               egpio |= EGPIO_H3600_AUD_AMP_ON |
-                        EGPIO_H3600_AUD_PWR_ON;
-               break;
-       case IPAQ_EGPIO_QMUTE:
-               egpio |= EGPIO_H3600_QMUTE;
-               break;
-       case IPAQ_EGPIO_OPT_NVRAM_ON:
-               egpio |= EGPIO_H3600_OPT_NVRAM_ON;
-               break;
-       case IPAQ_EGPIO_OPT_ON:
-               egpio |= EGPIO_H3600_OPT_ON;
-               break;
-       case IPAQ_EGPIO_CARD_RESET:
-               egpio |= EGPIO_H3600_CARD_RESET;
-               break;
-       case IPAQ_EGPIO_OPT_RESET:
-               egpio |= EGPIO_H3600_OPT_RESET;
-               break;
-       case IPAQ_EGPIO_IR_ON:
-               egpio |= EGPIO_H3600_IR_ON;
-               break;
-       case IPAQ_EGPIO_IR_FSEL:
-               egpio |= EGPIO_H3600_IR_FSEL;
-               break;
-       case IPAQ_EGPIO_RS232_ON:
-               egpio |= EGPIO_H3600_RS232_ON;
-               break;
-       case IPAQ_EGPIO_VPP_ON:
-               egpio |= EGPIO_H3600_VPP_ON;
-               break;
-       }
+static struct irda_platform_data h3600_irda_data = {
+       .set_power      = h3600_irda_set_power,
+       .set_speed      = h3600_irda_set_speed,
+       .startup        = h3600_irda_startup,
+       .shutdown       = h3600_irda_shutdown,
+};
 
-       if (egpio) {
-               local_irq_save(flags);
-               if (setp)
-                       h3600_egpio |= egpio;
-               else
-                       h3600_egpio &= ~egpio;
-               H3600_EGPIO = h3600_egpio;
-               local_irq_restore(flags);
-       }
-}
+static struct gpio_default_state h3600_default_gpio[] = {
+       { H3XXX_GPIO_COM_DCD,   GPIO_MODE_IN,   "COM DCD" },
+       { H3XXX_GPIO_COM_CTS,   GPIO_MODE_IN,   "COM CTS" },
+       { H3XXX_GPIO_COM_RTS,   GPIO_MODE_OUT0, "COM RTS" },
+};
 
-static void __init h3600_map_io(void)
+static void __init h3600_mach_init(void)
 {
-       h3xxx_map_io();
-
-       /* Initialize h3600-specific values here */
-
-       GPCR = 0x0fffffff;       /* All outputs are set low by default */
-       GPDR = GPIO_H3600_COM_RTS  | GPIO_H3600_L3_CLOCK |
-              GPIO_H3600_L3_MODE  | GPIO_H3600_L3_DATA  |
-              GPIO_H3600_CLK_SET1 | GPIO_H3600_CLK_SET0 |
-              GPIO_LDD15 | GPIO_LDD14 | GPIO_LDD13 | GPIO_LDD12 |
-              GPIO_LDD11 | GPIO_LDD10 | GPIO_LDD9  | GPIO_LDD8;
-
-       H3600_EGPIO = h3600_egpio;         /* Maintains across sleep? */
-       assign_h3600_egpio = h3600_control_egpio;
+       h3xxx_init_gpio(h3600_default_gpio, ARRAY_SIZE(h3600_default_gpio));
+       h3xxx_mach_init();
+       sa11x0_register_irda(&h3600_irda_data);
 }
 
 MACHINE_START(H3600, "Compaq iPAQ H3600")
@@ -425,8 +131,6 @@ MACHINE_START(H3600, "Compaq iPAQ H3600")
        .map_io         = h3600_map_io,
        .init_irq       = sa1100_init_irq,
        .timer          = &sa1100_timer,
-       .init_machine   = h3xxx_mach_init,
+       .init_machine   = h3600_mach_init,
 MACHINE_END
 
-#endif /* CONFIG_SA1100_H3600 */
-
diff --git a/arch/arm/mach-sa1100/h3xxx.c b/arch/arm/mach-sa1100/h3xxx.c
new file mode 100644 (file)
index 0000000..b0784c9
--- /dev/null
@@ -0,0 +1,313 @@
+/*
+ * Support for Compaq iPAQ H3100 and H3600 handheld computers (common code)
+ *
+ * Copyright (c) 2000,1 Compaq Computer Corporation. (Author: Jamey Hicks)
+ * Copyright (c) 2009 Dmitry Artamonow <mad_soft@inbox.ru>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/gpio.h>
+#include <linux/gpio_keys.h>
+#include <linux/input.h>
+#include <linux/mfd/htc-egpio.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/platform_device.h>
+#include <linux/serial_core.h>
+
+#include <asm/mach/flash.h>
+#include <asm/mach/map.h>
+#include <asm/mach/serial_sa1100.h>
+
+#include <mach/h3xxx.h>
+
+#include "generic.h"
+
+void h3xxx_init_gpio(struct gpio_default_state *s, size_t n)
+{
+       while (n--) {
+               const char *name = s->name;
+               int err;
+
+               if (!name)
+                       name = "[init]";
+               err = gpio_request(s->gpio, name);
+               if (err) {
+                       printk(KERN_ERR "gpio%u: unable to request: %d\n",
+                               s->gpio, err);
+                       continue;
+               }
+               if (s->mode >= 0) {
+                       err = gpio_direction_output(s->gpio, s->mode);
+               } else {
+                       err = gpio_direction_input(s->gpio);
+               }
+               if (err) {
+                       printk(KERN_ERR "gpio%u: unable to set direction: %d\n",
+                               s->gpio, err);
+                       continue;
+               }
+               if (!s->name)
+                       gpio_free(s->gpio);
+               s++;
+       }
+}
+
+
+/*
+ * H3xxx flash support
+ */
+static struct mtd_partition h3xxx_partitions[] = {
+       {
+               .name           = "H3XXX boot firmware",
+               .size           = 0x00040000,
+               .offset         = 0,
+               .mask_flags     = MTD_WRITEABLE,  /* force read-only */
+       }, {
+               .name           = "H3XXX rootfs",
+               .size           = MTDPART_SIZ_FULL,
+               .offset         = 0x00040000,
+       }
+};
+
+static void h3xxx_set_vpp(int vpp)
+{
+       gpio_set_value(H3XXX_EGPIO_VPP_ON, vpp);
+}
+
+static int h3xxx_flash_init(void)
+{
+       int err = gpio_request(H3XXX_EGPIO_VPP_ON, "Flash Vpp");
+       if (err) {
+               pr_err("%s: can't request H3XXX_EGPIO_VPP_ON\n", __func__);
+               return err;
+       }
+
+       err = gpio_direction_output(H3XXX_EGPIO_VPP_ON, 0);
+       if (err)
+               gpio_free(H3XXX_EGPIO_VPP_ON);
+
+       return err;
+}
+
+static void h3xxx_flash_exit(void)
+{
+       gpio_free(H3XXX_EGPIO_VPP_ON);
+}
+
+static struct flash_platform_data h3xxx_flash_data = {
+       .map_name       = "cfi_probe",
+       .set_vpp        = h3xxx_set_vpp,
+       .init           = h3xxx_flash_init,
+       .exit           = h3xxx_flash_exit,
+       .parts          = h3xxx_partitions,
+       .nr_parts       = ARRAY_SIZE(h3xxx_partitions),
+};
+
+static struct resource h3xxx_flash_resource = {
+       .start          = SA1100_CS0_PHYS,
+       .end            = SA1100_CS0_PHYS + SZ_32M - 1,
+       .flags          = IORESOURCE_MEM,
+};
+
+
+/*
+ * H3xxx uart support
+ */
+static void h3xxx_uart_set_mctrl(struct uart_port *port, u_int mctrl)
+{
+       if (port->mapbase == _Ser3UTCR0) {
+               gpio_set_value(H3XXX_GPIO_COM_RTS, !(mctrl & TIOCM_RTS));
+       }
+}
+
+static u_int h3xxx_uart_get_mctrl(struct uart_port *port)
+{
+       u_int ret = TIOCM_CD | TIOCM_CTS | TIOCM_DSR;
+
+       if (port->mapbase == _Ser3UTCR0) {
+               /*
+                * DCD and CTS bits are inverted in GPLR by RS232 transceiver
+                */
+               if (gpio_get_value(H3XXX_GPIO_COM_DCD))
+                       ret &= ~TIOCM_CD;
+               if (gpio_get_value(H3XXX_GPIO_COM_CTS))
+                       ret &= ~TIOCM_CTS;
+       }
+
+       return ret;
+}
+
+static void h3xxx_uart_pm(struct uart_port *port, u_int state, u_int oldstate)
+{
+       if (port->mapbase == _Ser3UTCR0) {
+               if (!gpio_request(H3XXX_EGPIO_RS232_ON, "RS232 transceiver")) {
+                       gpio_direction_output(H3XXX_EGPIO_RS232_ON, !state);
+                       gpio_free(H3XXX_EGPIO_RS232_ON);
+               } else {
+                       pr_err("%s: can't request H3XXX_EGPIO_RS232_ON\n",
+                               __func__);
+               }
+       }
+}
+
+/*
+ * Enable/Disable wake up events for this serial port.
+ * Obviously, we only support this on the normal COM port.
+ */
+static int h3xxx_uart_set_wake(struct uart_port *port, u_int enable)
+{
+       int err = -EINVAL;
+
+       if (port->mapbase == _Ser3UTCR0) {
+               if (enable)
+                       PWER |= PWER_GPIO23 | PWER_GPIO25; /* DCD and CTS */
+               else
+                       PWER &= ~(PWER_GPIO23 | PWER_GPIO25); /* DCD and CTS */
+               err = 0;
+       }
+       return err;
+}
+
+static struct sa1100_port_fns h3xxx_port_fns __initdata = {
+       .set_mctrl      = h3xxx_uart_set_mctrl,
+       .get_mctrl      = h3xxx_uart_get_mctrl,
+       .pm             = h3xxx_uart_pm,
+       .set_wake       = h3xxx_uart_set_wake,
+};
+
+/*
+ * EGPIO
+ */
+
+static struct resource egpio_resources[] = {
+       [0] = {
+               .start  = H3600_EGPIO_PHYS,
+               .end    = H3600_EGPIO_PHYS + 0x4 - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+};
+
+static struct htc_egpio_chip egpio_chips[] = {
+       [0] = {
+               .reg_start      = 0,
+               .gpio_base      = H3XXX_EGPIO_BASE,
+               .num_gpios      = 16,
+               .direction      = HTC_EGPIO_OUTPUT,
+               .initial_values = 0x0080, /* H3XXX_EGPIO_RS232_ON */
+       },
+};
+
+static struct htc_egpio_platform_data egpio_info = {
+       .reg_width      = 16,
+       .bus_width      = 16,
+       .chip           = egpio_chips,
+       .num_chips      = ARRAY_SIZE(egpio_chips),
+};
+
+static struct platform_device h3xxx_egpio = {
+       .name           = "htc-egpio",
+       .id             = -1,
+       .resource       = egpio_resources,
+       .num_resources  = ARRAY_SIZE(egpio_resources),
+       .dev            = {
+               .platform_data = &egpio_info,
+       },
+};
+
+/*
+ * GPIO keys
+ */
+
+static struct gpio_keys_button h3xxx_button_table[] = {
+       {
+               .code           = KEY_POWER,
+               .gpio           = H3XXX_GPIO_PWR_BUTTON,
+               .desc           = "Power Button",
+               .active_low     = 1,
+               .type           = EV_KEY,
+               .wakeup         = 1,
+       }, {
+               .code           = KEY_ENTER,
+               .gpio           = H3XXX_GPIO_ACTION_BUTTON,
+               .active_low     = 1,
+               .desc           = "Action button",
+               .type           = EV_KEY,
+               .wakeup         = 0,
+       },
+};
+
+static struct gpio_keys_platform_data h3xxx_keys_data = {
+       .buttons  = h3xxx_button_table,
+       .nbuttons = ARRAY_SIZE(h3xxx_button_table),
+};
+
+static struct platform_device h3xxx_keys = {
+       .name   = "gpio-keys",
+       .id     = -1,
+       .dev    = {
+               .platform_data = &h3xxx_keys_data,
+       },
+};
+
+static struct platform_device *h3xxx_devices[] = {
+       &h3xxx_egpio,
+       &h3xxx_keys,
+};
+
+void __init h3xxx_mach_init(void)
+{
+       sa1100_register_uart_fns(&h3xxx_port_fns);
+       sa11x0_register_mtd(&h3xxx_flash_data, &h3xxx_flash_resource, 1);
+       platform_add_devices(h3xxx_devices, ARRAY_SIZE(h3xxx_devices));
+}
+
+static struct map_desc h3600_io_desc[] __initdata = {
+       {       /* static memory bank 2  CS#2 */
+               .virtual        =  H3600_BANK_2_VIRT,
+               .pfn            = __phys_to_pfn(SA1100_CS2_PHYS),
+               .length         = 0x02800000,
+               .type           = MT_DEVICE
+       }, {    /* static memory bank 4  CS#4 */
+               .virtual        =  H3600_BANK_4_VIRT,
+               .pfn            = __phys_to_pfn(SA1100_CS4_PHYS),
+               .length         = 0x00800000,
+               .type           = MT_DEVICE
+       }, {    /* EGPIO 0              CS#5 */
+               .virtual        =  H3600_EGPIO_VIRT,
+               .pfn            = __phys_to_pfn(H3600_EGPIO_PHYS),
+               .length         = 0x01000000,
+               .type           = MT_DEVICE
+       }
+};
+
+/*
+ * Common map_io initialization
+ */
+
+void __init h3xxx_map_io(void)
+{
+       sa1100_map_io();
+       iotable_init(h3600_io_desc, ARRAY_SIZE(h3600_io_desc));
+
+       sa1100_register_uart(0, 3); /* Common serial port */
+//     sa1100_register_uart(1, 1); /* Microcontroller on 3100/3600 */
+
+       /* Ensure those pins are outputs and driving low  */
+       PPDR |= PPC_TXD4 | PPC_SCLK | PPC_SFRM;
+       PPSR &= ~(PPC_TXD4 | PPC_SCLK | PPC_SFRM);
+
+       /* Configure suspend conditions */
+       PGSR = 0;
+       PCFR = PCFR_OPDE;
+       PSDR = 0;
+
+       GPCR = 0x0fffffff;      /* All outputs are set low by default */
+       GPDR = 0;               /* Configure all GPIOs as input */
+}
+
index e7056c0..51568df 100644 (file)
@@ -187,7 +187,7 @@ static struct resource hackkit_flash_resource = {
 
 static void __init hackkit_init(void)
 {
-       sa11x0_set_flash_data(&hackkit_flash_data, &hackkit_flash_resource, 1);
+       sa11x0_register_mtd(&hackkit_flash_data, &hackkit_flash_resource, 1);
 }
 
 /**********************************************************************
index 9efb569..71a0b3f 100644 (file)
 #define COLLIE_GPIO_VPEN       (COLLIE_SCOOP_GPIO_BASE + 7)
 #define COLLIE_SCP_LB_VOL_CHG  SCOOP_GPCR_PA19
 
-#define COLLIE_SCOOP_IO_DIR    ( COLLIE_SCP_MUTE_L | COLLIE_SCP_MUTE_R | \
+#define COLLIE_SCOOP_IO_DIR    (COLLIE_SCP_MUTE_L | COLLIE_SCP_MUTE_R | \
                                COLLIE_SCP_5VON | COLLIE_SCP_AMP_ON | \
-                               COLLIE_SCP_LB_VOL_CHG )
-#define COLLIE_SCOOP_IO_OUT    ( COLLIE_SCP_MUTE_L | COLLIE_SCP_MUTE_R )
+                               COLLIE_SCP_LB_VOL_CHG)
+#define COLLIE_SCOOP_IO_OUT    (COLLIE_SCP_MUTE_L | COLLIE_SCP_MUTE_R)
 
-/* GPIOs for which the generic definition doesn't say much */
+/* GPIOs for gpiolib  */
 
-#define COLLIE_GPIO_ON_KEY             GPIO_GPIO (0)
-#define COLLIE_GPIO_AC_IN              GPIO_GPIO (1)
-#define COLLIE_GPIO_SDIO_INT           GPIO_GPIO (11)
-#define COLLIE_GPIO_CF_IRQ             GPIO_GPIO (14)
-#define COLLIE_GPIO_nREMOCON_INT       GPIO_GPIO (15)
-#define COLLIE_GPIO_UCB1x00_RESET      GPIO_GPIO (16)
-#define COLLIE_GPIO_nMIC_ON            GPIO_GPIO (17)
-#define COLLIE_GPIO_nREMOCON_ON                GPIO_GPIO (18)
-#define COLLIE_GPIO_CO                 GPIO_GPIO (20)
-#define COLLIE_GPIO_MCP_CLK            GPIO_GPIO (21)
-#define COLLIE_GPIO_CF_CD              GPIO_GPIO (22)
-#define COLLIE_GPIO_UCB1x00_IRQ                GPIO_GPIO (23)
-#define COLLIE_GPIO_WAKEUP             GPIO_GPIO (24)
-#define COLLIE_GPIO_GA_INT             GPIO_GPIO (25)
-#define COLLIE_GPIO_MAIN_BAT_LOW       GPIO_GPIO (26)
+#define COLLIE_GPIO_ON_KEY             (0)
+#define COLLIE_GPIO_AC_IN              (1)
+#define COLLIE_GPIO_SDIO_INT           (11)
+#define COLLIE_GPIO_CF_IRQ             (14)
+#define COLLIE_GPIO_nREMOCON_INT       (15)
+#define COLLIE_GPIO_UCB1x00_RESET      (16)
+#define COLLIE_GPIO_nMIC_ON            (17)
+#define COLLIE_GPIO_nREMOCON_ON                (18)
+#define COLLIE_GPIO_CO                 (20)
+#define COLLIE_GPIO_MCP_CLK            (21)
+#define COLLIE_GPIO_CF_CD              (22)
+#define COLLIE_GPIO_UCB1x00_IRQ                (23)
+#define COLLIE_GPIO_WAKEUP             (24)
+#define COLLIE_GPIO_GA_INT             (25)
+#define COLLIE_GPIO_MAIN_BAT_LOW       (26)
 
+/* GPIO definitions for direct register access */
+
+#define _COLLIE_GPIO_ON_KEY            GPIO_GPIO(0)
+#define _COLLIE_GPIO_AC_IN             GPIO_GPIO(1)
+#define _COLLIE_GPIO_nREMOCON_INT      GPIO_GPIO(15)
+#define _COLLIE_GPIO_UCB1x00_RESET     GPIO_GPIO(16)
+#define _COLLIE_GPIO_nMIC_ON           GPIO_GPIO(17)
+#define _COLLIE_GPIO_nREMOCON_ON       GPIO_GPIO(18)
+#define _COLLIE_GPIO_CO                        GPIO_GPIO(20)
+#define _COLLIE_GPIO_WAKEUP            GPIO_GPIO(24)
 /* Interrupts */
 
 #define COLLIE_IRQ_GPIO_ON_KEY         IRQ_GPIO0
 #define COLLIE_LCM_IRQ_GPIO_nSD_WP     IRQ_LOCOMO_GPIO14
 
 /* GPIO's on the TC35143AF (Toshiba Analog Frontend) */
-#define COLLIE_TC35143_GPIO_VERSION0    UCB_IO_0       /* GPIO0=Version                 */
-#define COLLIE_TC35143_GPIO_TBL_CHK     UCB_IO_1       /* GPIO1=TBL_CHK                 */
-#define COLLIE_TC35143_GPIO_VPEN_ON     UCB_IO_2       /* GPIO2=VPNE_ON                 */
-#define COLLIE_TC35143_GPIO_IR_ON       UCB_IO_3       /* GPIO3=IR_ON                   */
-#define COLLIE_TC35143_GPIO_AMP_ON      UCB_IO_4       /* GPIO4=AMP_ON                  */
-#define COLLIE_TC35143_GPIO_VERSION1    UCB_IO_5       /* GPIO5=Version                 */
-#define COLLIE_TC35143_GPIO_FS8KLPF     UCB_IO_5       /* GPIO5=fs 8k LPF               */
-#define COLLIE_TC35143_GPIO_BUZZER_BIAS UCB_IO_6       /* GPIO6=BUZZER BIAS             */
-#define COLLIE_TC35143_GPIO_MBAT_ON     UCB_IO_7       /* GPIO7=MBAT_ON                 */
-#define COLLIE_TC35143_GPIO_BBAT_ON     UCB_IO_8       /* GPIO8=BBAT_ON                 */
-#define COLLIE_TC35143_GPIO_TMP_ON      UCB_IO_9       /* GPIO9=TMP_ON                  */
-#define COLLIE_TC35143_GPIO_IN         ( UCB_IO_0 | UCB_IO_2 | UCB_IO_5 )
-#define COLLIE_TC35143_GPIO_OUT                ( UCB_IO_1 | UCB_IO_3 | UCB_IO_4 | UCB_IO_6 | \
-                                       UCB_IO_7 | UCB_IO_8 | UCB_IO_9 )
+#define COLLIE_TC35143_GPIO_BASE       (GPIO_MAX + 13)
+#define COLLIE_TC35143_GPIO_VERSION0    UCB_IO_0
+#define COLLIE_TC35143_GPIO_TBL_CHK     UCB_IO_1
+#define COLLIE_TC35143_GPIO_VPEN_ON     UCB_IO_2
+#define COLLIE_TC35143_GPIO_IR_ON       UCB_IO_3
+#define COLLIE_TC35143_GPIO_AMP_ON      UCB_IO_4
+#define COLLIE_TC35143_GPIO_VERSION1    UCB_IO_5
+#define COLLIE_TC35143_GPIO_FS8KLPF     UCB_IO_5
+#define COLLIE_TC35143_GPIO_BUZZER_BIAS UCB_IO_6
+#define COLLIE_GPIO_MBAT_ON            (COLLIE_TC35143_GPIO_BASE + 7)
+#define COLLIE_GPIO_BBAT_ON            (COLLIE_TC35143_GPIO_BASE + 8)
+#define COLLIE_GPIO_TMP_ON             (COLLIE_TC35143_GPIO_BASE + 9)
+#define COLLIE_TC35143_GPIO_IN         (UCB_IO_0 | UCB_IO_2 | UCB_IO_5)
+#define COLLIE_TC35143_GPIO_OUT                (UCB_IO_1 | UCB_IO_3 | UCB_IO_4 \
+                                               | UCB_IO_6)
 
 #endif
index 582a0c9..7befc10 100644 (file)
@@ -49,20 +49,9 @@ static inline void gpio_set_value(unsigned gpio, int value)
 
 #define gpio_cansleep  __gpio_cansleep
 
-static inline unsigned gpio_to_irq(unsigned gpio)
-{
-       if (gpio < 11)
-               return IRQ_GPIO0 + gpio;
-       else
-               return IRQ_GPIO11 - 11 + gpio;
-}
-
-static inline unsigned irq_to_gpio(unsigned irq)
-{
-       if (irq < IRQ_GPIO11_27)
-               return irq - IRQ_GPIO0;
-       else
-               return irq - IRQ_GPIO11 + 11;
-}
+#define gpio_to_irq(gpio)      ((gpio < 11) ? (IRQ_GPIO0 + gpio) : \
+                                       (IRQ_GPIO11 - 11 + gpio))
+#define irq_to_gpio(irq)       ((irq < IRQ_GPIO11_27) ? (irq - IRQ_GPIO0) : \
+                                       (irq - IRQ_GPIO11 + 11))
 
 #endif
diff --git a/arch/arm/mach-sa1100/include/mach/h3600.h b/arch/arm/mach-sa1100/include/mach/h3600.h
deleted file mode 100644 (file)
index 2827faa..0000000
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- *
- * Definitions for H3600 Handheld Computer
- *
- * Copyright 2000 Compaq Computer Corporation.
- *
- * Use consistent with the GNU GPL is permitted,
- * provided that this copyright notice is
- * preserved in its entirety in all copies and derived works.
- *
- * COMPAQ COMPUTER CORPORATION MAKES NO WARRANTIES, EXPRESSED OR IMPLIED,
- * AS TO THE USEFULNESS OR CORRECTNESS OF THIS CODE OR ITS
- * FITNESS FOR ANY PARTICULAR PURPOSE.
- *
- * Author: Jamey Hicks.
- *
- * History:
- *
- * 2001-10-??  Andrew Christian   Added support for iPAQ H3800
- *
- */
-
-#ifndef _INCLUDE_H3600_H_
-#define _INCLUDE_H3600_H_
-
-typedef int __bitwise pm_request_t;
-
-#define PM_SUSPEND     ((__force pm_request_t) 1)      /* enter D1-D3 */
-#define PM_RESUME      ((__force pm_request_t) 2)      /* enter D0 */
-
-/* generalized support for H3xxx series Compaq Pocket PC's */
-#define machine_is_h3xxx() (machine_is_h3100() || machine_is_h3600())
-
-/* Physical memory regions corresponding to chip selects */
-#define H3600_EGPIO_PHYS       (SA1100_CS5_PHYS + 0x01000000)
-#define H3600_BANK_2_PHYS      SA1100_CS2_PHYS
-#define H3600_BANK_4_PHYS      SA1100_CS4_PHYS
-
-/* Virtual memory regions corresponding to chip selects 2 & 4 (used on sleeves) */
-#define H3600_EGPIO_VIRT       0xf0000000
-#define H3600_BANK_2_VIRT      0xf1000000
-#define H3600_BANK_4_VIRT      0xf3800000
-
-/*
-   Machine-independent GPIO definitions
-   --- these are common across all current iPAQ platforms
-*/
-
-#define GPIO_H3600_NPOWER_BUTTON       GPIO_GPIO (0)   /* Also known as the "off button"  */
-
-#define GPIO_H3600_PCMCIA_CD1          GPIO_GPIO (10)
-#define GPIO_H3600_PCMCIA_IRQ1         GPIO_GPIO (11)
-
-/* UDA1341 L3 Interface */
-#define GPIO_H3600_L3_DATA             GPIO_GPIO (14)
-#define GPIO_H3600_L3_MODE             GPIO_GPIO (15)
-#define GPIO_H3600_L3_CLOCK            GPIO_GPIO (16)
-
-#define GPIO_H3600_PCMCIA_CD0          GPIO_GPIO (17)
-#define GPIO_H3600_SYS_CLK             GPIO_GPIO (19)
-#define GPIO_H3600_PCMCIA_IRQ0         GPIO_GPIO (21)
-
-#define GPIO_H3600_COM_DCD             GPIO_GPIO (23)
-#define GPIO_H3600_OPT_IRQ             GPIO_GPIO (24)
-#define GPIO_H3600_COM_CTS             GPIO_GPIO (25)
-#define GPIO_H3600_COM_RTS             GPIO_GPIO (26)
-
-#define IRQ_GPIO_H3600_NPOWER_BUTTON   IRQ_GPIO0
-#define IRQ_GPIO_H3600_PCMCIA_CD1      IRQ_GPIO10
-#define IRQ_GPIO_H3600_PCMCIA_IRQ1     IRQ_GPIO11
-#define IRQ_GPIO_H3600_PCMCIA_CD0      IRQ_GPIO17
-#define IRQ_GPIO_H3600_PCMCIA_IRQ0     IRQ_GPIO21
-#define IRQ_GPIO_H3600_COM_DCD         IRQ_GPIO23
-#define IRQ_GPIO_H3600_OPT_IRQ         IRQ_GPIO24
-#define IRQ_GPIO_H3600_COM_CTS         IRQ_GPIO25
-
-
-#ifndef __ASSEMBLY__
-
-enum ipaq_egpio_type {
-       IPAQ_EGPIO_LCD_POWER,     /* Power to the LCD panel */
-       IPAQ_EGPIO_CODEC_NRESET,  /* Clear to reset the audio codec (remember to return high) */
-       IPAQ_EGPIO_AUDIO_ON,      /* Audio power */
-       IPAQ_EGPIO_QMUTE,         /* Audio muting */
-       IPAQ_EGPIO_OPT_NVRAM_ON,  /* Non-volatile RAM on extension sleeves (SPI interface) */
-       IPAQ_EGPIO_OPT_ON,        /* Power to extension sleeves */
-       IPAQ_EGPIO_CARD_RESET,    /* Reset PCMCIA cards on extension sleeve (???) */
-       IPAQ_EGPIO_OPT_RESET,     /* Reset option pack (???) */
-       IPAQ_EGPIO_IR_ON,         /* IR sensor/emitter power */
-       IPAQ_EGPIO_IR_FSEL,       /* IR speed selection 1->fast, 0->slow */
-       IPAQ_EGPIO_RS232_ON,      /* Maxim RS232 chip power */
-       IPAQ_EGPIO_VPP_ON,        /* Turn on power to flash programming */
-       IPAQ_EGPIO_LCD_ENABLE,    /* Enable/disable LCD controller */
-};
-
-extern void (*assign_h3600_egpio)(enum ipaq_egpio_type x, int level);
-
-#endif /* ASSEMBLY */
-
-#endif /* _INCLUDE_H3600_H_ */
diff --git a/arch/arm/mach-sa1100/include/mach/h3600_gpio.h b/arch/arm/mach-sa1100/include/mach/h3600_gpio.h
deleted file mode 100644 (file)
index a36ca76..0000000
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- *
- * Definitions for H3600 Handheld Computer
- *
- * Copyright 2000 Compaq Computer Corporation.
- *
- * Use consistent with the GNU GPL is permitted,
- * provided that this copyright notice is
- * preserved in its entirety in all copies and derived works.
- *
- * COMPAQ COMPUTER CORPORATION MAKES NO WARRANTIES, EXPRESSED OR IMPLIED,
- * AS TO THE USEFULNESS OR CORRECTNESS OF THIS CODE OR ITS
- * FITNESS FOR ANY PARTICULAR PURPOSE.
- *
- * Author: Jamey Hicks.
- *
- * History:
- *
- * 2001-10-??   Andrew Christian   Added support for iPAQ H3800
- *
- */
-
-#ifndef _INCLUDE_H3600_GPIO_H_
-#define _INCLUDE_H3600_GPIO_H_
-
-/*
- * GPIO lines that are common across ALL iPAQ models are in "h3600.h"
- * This file contains machine-specific definitions
- */
-
-#define GPIO_H3600_SUSPEND              GPIO_GPIO (0)
-/* GPIO[2:9] used by LCD on H3600/3800, used as GPIO on H3100 */
-#define GPIO_H3100_BT_ON               GPIO_GPIO (2)
-#define GPIO_H3100_GPIO3               GPIO_GPIO (3)
-#define GPIO_H3100_QMUTE               GPIO_GPIO (4)
-#define GPIO_H3100_LCD_3V_ON           GPIO_GPIO (5)
-#define GPIO_H3100_AUD_ON              GPIO_GPIO (6)
-#define GPIO_H3100_AUD_PWR_ON          GPIO_GPIO (7)
-#define GPIO_H3100_IR_ON               GPIO_GPIO (8)
-#define GPIO_H3100_IR_FSEL             GPIO_GPIO (9)
-
-/* for H3600, audio sample rate clock generator */
-#define GPIO_H3600_CLK_SET0            GPIO_GPIO (12)
-#define GPIO_H3600_CLK_SET1            GPIO_GPIO (13)
-
-#define GPIO_H3600_ACTION_BUTTON       GPIO_GPIO (18)
-#define GPIO_H3600_SOFT_RESET           GPIO_GPIO (20)   /* Also known as BATT_FAULT */
-#define GPIO_H3600_OPT_LOCK            GPIO_GPIO (22)
-#define GPIO_H3600_OPT_DET             GPIO_GPIO (27)
-
-/****************************************************/
-
-#define IRQ_GPIO_H3600_ACTION_BUTTON    IRQ_GPIO18
-#define IRQ_GPIO_H3600_OPT_DET         IRQ_GPIO27
-
-/* H3100 / 3600 EGPIO pins */
-#define EGPIO_H3600_VPP_ON             (1 << 0)
-#define EGPIO_H3600_CARD_RESET         (1 << 1)   /* reset the attached pcmcia/compactflash card.  active high. */
-#define EGPIO_H3600_OPT_RESET          (1 << 2)   /* reset the attached option pack.  active high. */
-#define EGPIO_H3600_CODEC_NRESET       (1 << 3)   /* reset the onboard UDA1341.  active low. */
-#define EGPIO_H3600_OPT_NVRAM_ON       (1 << 4)   /* apply power to optionpack nvram, active high. */
-#define EGPIO_H3600_OPT_ON             (1 << 5)   /* full power to option pack.  active high. */
-#define EGPIO_H3600_LCD_ON             (1 << 6)   /* enable 3.3V to LCD.  active high. */
-#define EGPIO_H3600_RS232_ON           (1 << 7)   /* UART3 transceiver force on.  Active high. */
-
-/* H3600 only EGPIO pins */
-#define EGPIO_H3600_LCD_PCI            (1 << 8)   /* LCD control IC enable.  active high. */
-#define EGPIO_H3600_IR_ON              (1 << 9)   /* apply power to IR module.  active high. */
-#define EGPIO_H3600_AUD_AMP_ON         (1 << 10)  /* apply power to audio power amp.  active high. */
-#define EGPIO_H3600_AUD_PWR_ON         (1 << 11)  /* apply power to reset of audio circuit.  active high. */
-#define EGPIO_H3600_QMUTE              (1 << 12)  /* mute control for onboard UDA1341.  active high. */
-#define EGPIO_H3600_IR_FSEL            (1 << 13)  /* IR speed select: 1->fast, 0->slow */
-#define EGPIO_H3600_LCD_5V_ON          (1 << 14)  /* enable 5V to LCD. active high. */
-#define EGPIO_H3600_LVDD_ON            (1 << 15)  /* enable 9V and -6.5V to LCD. */
-
-
-#endif /* _INCLUDE_H3600_GPIO_H_ */
diff --git a/arch/arm/mach-sa1100/include/mach/h3xxx.h b/arch/arm/mach-sa1100/include/mach/h3xxx.h
new file mode 100644 (file)
index 0000000..7d9df16
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * Definitions for Compaq iPAQ H3100 and H3600 handheld computers
+ *
+ * (c) 2000 Compaq Computer Corporation. (Author: Jamey Hicks)
+ * (c) 2009 Dmitry Artamonow <mad_soft@inbox.ru>
+ *
+ * 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 _INCLUDE_H3XXX_H_
+#define _INCLUDE_H3XXX_H_
+
+/* Physical memory regions corresponding to chip selects */
+#define H3600_EGPIO_PHYS       (SA1100_CS5_PHYS + 0x01000000)
+#define H3600_BANK_2_PHYS      SA1100_CS2_PHYS
+#define H3600_BANK_4_PHYS      SA1100_CS4_PHYS
+
+/* Virtual memory regions corresponding to chip selects 2 & 4 (used on sleeves) */
+#define H3600_EGPIO_VIRT       0xf0000000
+#define H3600_BANK_2_VIRT      0xf1000000
+#define H3600_BANK_4_VIRT      0xf3800000
+
+/*
+ * gpiolib numbers for all iPAQs
+ */
+#define H3XXX_GPIO_PWR_BUTTON          0
+#define H3XXX_GPIO_PCMCIA_CD1          10
+#define H3XXX_GPIO_PCMCIA_IRQ1         11
+#define H3XXX_GPIO_PCMCIA_CD0          17
+#define H3XXX_GPIO_ACTION_BUTTON       18
+#define H3XXX_GPIO_SYS_CLK             19
+#define H3XXX_GPIO_PCMCIA_IRQ0         21
+#define H3XXX_GPIO_COM_DCD             23
+#define H3XXX_GPIO_OPTION              24
+#define H3XXX_GPIO_COM_CTS             25
+#define H3XXX_GPIO_COM_RTS             26
+
+/* machine-specific gpios */
+
+#define H3100_GPIO_BT_ON               2
+#define H3100_GPIO_QMUTE               4
+#define H3100_GPIO_LCD_3V_ON           5
+#define H3100_GPIO_AUD_ON              6
+#define H3100_GPIO_AUD_PWR_ON          7
+#define H3100_GPIO_IR_ON               8
+#define H3100_GPIO_IR_FSEL             9
+
+#define H3600_GPIO_CLK_SET0            12      /* audio sample rate clock generator */
+#define H3600_GPIO_CLK_SET1            13
+#define H3600_GPIO_SOFT_RESET          20      /* also known as BATT_FAULT */
+#define H3600_GPIO_OPT_LOCK            22
+#define H3600_GPIO_OPT_DET             27
+
+
+/* H3100 / 3600 EGPIO pins */
+#define H3XXX_EGPIO_BASE               (GPIO_MAX + 1)
+
+#define H3XXX_EGPIO_VPP_ON             (H3XXX_EGPIO_BASE + 0)
+#define H3XXX_EGPIO_CARD_RESET         (H3XXX_EGPIO_BASE + 1) /* reset the attached pcmcia/compactflash card.  active high. */
+#define H3XXX_EGPIO_OPT_RESET          (H3XXX_EGPIO_BASE + 2) /* reset the attached option pack.  active high. */
+#define H3XXX_EGPIO_CODEC_NRESET       (H3XXX_EGPIO_BASE + 3) /* reset the onboard UDA1341.  active low. */
+#define H3XXX_EGPIO_OPT_NVRAM_ON       (H3XXX_EGPIO_BASE + 4) /* apply power to optionpack nvram, active high. */
+#define H3XXX_EGPIO_OPT_ON             (H3XXX_EGPIO_BASE + 5) /* full power to option pack.  active high. */
+#define H3XXX_EGPIO_LCD_ON             (H3XXX_EGPIO_BASE + 6) /* enable 3.3V to LCD.  active high. */
+#define H3XXX_EGPIO_RS232_ON           (H3XXX_EGPIO_BASE + 7) /* UART3 transceiver force on.  Active high. */
+
+/* H3600 only EGPIO pins */
+#define H3600_EGPIO_LCD_PCI            (H3XXX_EGPIO_BASE + 8) /* LCD control IC enable.  active high. */
+#define H3600_EGPIO_IR_ON              (H3XXX_EGPIO_BASE + 9) /* apply power to IR module.  active high. */
+#define H3600_EGPIO_AUD_AMP_ON         (H3XXX_EGPIO_BASE + 10) /* apply power to audio power amp.  active high. */
+#define H3600_EGPIO_AUD_PWR_ON         (H3XXX_EGPIO_BASE + 11) /* apply power to reset of audio circuit.  active high. */
+#define H3600_EGPIO_QMUTE              (H3XXX_EGPIO_BASE + 12) /* mute control for onboard UDA1341.  active high. */
+#define H3600_EGPIO_IR_FSEL            (H3XXX_EGPIO_BASE + 13) /* IR speed select: 1->fast, 0->slow */
+#define H3600_EGPIO_LCD_5V_ON          (H3XXX_EGPIO_BASE + 14) /* enable 5V to LCD. active high. */
+#define H3600_EGPIO_LVDD_ON            (H3XXX_EGPIO_BASE + 15) /* enable 9V and -6.5V to LCD. */
+
+struct gpio_default_state {
+       int gpio;
+       int mode;
+       const char *name;
+};
+
+#define GPIO_MODE_IN   -1
+#define GPIO_MODE_OUT0 0
+#define GPIO_MODE_OUT1 1
+
+void h3xxx_init_gpio(struct gpio_default_state *s, size_t n);
+void __init h3xxx_map_io(void);
+void __init h3xxx_mach_init(void);
+
+#endif /* _INCLUDE_H3XXX_H_ */
index fb8b09a..ed1a331 100644 (file)
@@ -16,6 +16,7 @@ struct mcp_plat_data {
        u32 mccr0;
        u32 mccr1;
        unsigned int sclk_rate;
+       int gpio_base;
 };
 
 #endif
index fd776bb..13ebd2d 100644 (file)
@@ -354,7 +354,7 @@ static struct resource jornada720_flash_resource = {
 
 static void __init jornada720_mach_init(void)
 {
-       sa11x0_set_flash_data(&jornada720_flash_data, &jornada720_flash_resource, 1);
+       sa11x0_register_mtd(&jornada720_flash_data, &jornada720_flash_resource, 1);
 }
 
 MACHINE_START(JORNADA720, "HP Jornada 720")
index 1f940df..68069d6 100644 (file)
@@ -28,7 +28,7 @@ static struct mcp_plat_data lart_mcp_data = {
 
 static void __init lart_init(void)
 {
-       sa11x0_set_mcp_data(&lart_mcp_data);
+       sa11x0_register_mcp(&lart_mcp_data);
 }
 
 static struct map_desc lart_io_desc[] __initdata = {
index e1458bc..1ccd601 100644 (file)
@@ -109,7 +109,7 @@ static struct flash_platform_data pleb_flash_data = {
 
 static void __init pleb_init(void)
 {
-       sa11x0_set_flash_data(&pleb_flash_data, pleb_flash_resources,
+       sa11x0_register_mtd(&pleb_flash_data, pleb_flash_resources,
                              ARRAY_SIZE(pleb_flash_resources));
 
 
index ddd917d..85e82bb 100644 (file)
@@ -59,8 +59,8 @@ static struct mcp_plat_data shannon_mcp_data = {
 
 static void __init shannon_init(void)
 {
-       sa11x0_set_flash_data(&shannon_flash_data, &shannon_flash_resource, 1);
-       sa11x0_set_mcp_data(&shannon_mcp_data);
+       sa11x0_register_mtd(&shannon_flash_data, &shannon_flash_resource, 1);
+       sa11x0_register_mcp(&shannon_mcp_data);
 }
 
 static void __init shannon_map_io(void)
index 3c74534..49cfd64 100644 (file)
@@ -166,9 +166,9 @@ static void __init simpad_map_io(void)
        PCFR = 0;
        PSDR = 0;
 
-       sa11x0_set_flash_data(&simpad_flash_data, simpad_flash_resources,
+       sa11x0_register_mtd(&simpad_flash_data, simpad_flash_resources,
                              ARRAY_SIZE(simpad_flash_resources));
-       sa11x0_set_mcp_data(&simpad_mcp_data);
+       sa11x0_register_mcp(&simpad_mcp_data);
 }
 
 static void simpad_power_off(void)
index 885b5c0..fab46fe 100644 (file)
@@ -12,3 +12,4 @@ obj-$(CONFIG_MMC)                 += mmc.o
 obj-$(CONFIG_SPI_PL022)           += spi.o
 obj-$(CONFIG_MACH_U300_SPIDUMMY)  += dummyspichip.o
 obj-$(CONFIG_I2C_STU300)          += i2c.o
+obj-$(CONFIG_REGULATOR_AB3100)    += regulator.o
index 10be1f8..c73ed06 100644 (file)
  */
 #include <linux/kernel.h>
 #include <linux/i2c.h>
+#include <linux/mfd/ab3100.h>
+#include <linux/regulator/machine.h>
+#include <linux/amba/bus.h>
 #include <mach/irqs.h>
 
+/*
+ * Initial settings of ab3100 registers.
+ * Common for below LDO regulator settings are that
+ * bit 7-5 controls voltage. Bit 4 turns regulator ON(1) or OFF(0).
+ * Bit 3-2 controls sleep enable and bit 1-0 controls sleep mode.
+ */
+
+/* LDO_A 0x16: 2.75V, ON, SLEEP_A, SLEEP OFF GND */
+#define LDO_A_SETTING          0x16
+/* LDO_C 0x10: 2.65V, ON, SLEEP_A or B, SLEEP full power */
+#define LDO_C_SETTING          0x10
+/* LDO_D 0x10: 2.65V, ON, sleep mode not used */
+#define LDO_D_SETTING          0x10
+/* LDO_E 0x10: 1.8V, ON, SLEEP_A or B, SLEEP full power */
+#define LDO_E_SETTING          0x10
+/* LDO_E SLEEP 0x00: 1.8V, not used, SLEEP_A or B, not used */
+#define LDO_E_SLEEP_SETTING    0x00
+/* LDO_F 0xD0: 2.5V, ON, SLEEP_A or B, SLEEP full power */
+#define LDO_F_SETTING          0xD0
+/* LDO_G 0x00: 2.85V, OFF, SLEEP_A or B, SLEEP full power */
+#define LDO_G_SETTING          0x00
+/* LDO_H 0x18: 2.75V, ON, SLEEP_B, SLEEP full power */
+#define LDO_H_SETTING          0x18
+/* LDO_K 0x00: 2.75V, OFF, SLEEP_A or B, SLEEP full power */
+#define LDO_K_SETTING          0x00
+/* LDO_EXT 0x00: Voltage not set, OFF, not used, not used */
+#define LDO_EXT_SETTING                0x00
+/* BUCK 0x7D: 1.2V, ON, SLEEP_A and B, SLEEP low power */
+#define BUCK_SETTING   0x7D
+/* BUCK SLEEP 0xAC: 1.05V, Not used, SLEEP_A and B, Not used */
+#define BUCK_SLEEP_SETTING     0xAC
+
+static struct regulator_consumer_supply supply_ldo_c[] = {
+       {
+               .dev_name = "ab3100-codec",
+               .supply = "vaudio", /* Powers the codec */
+       },
+};
+
+/*
+ * This one needs to be a supply so we can turn it off
+ * in order to shut down the system.
+ */
+static struct regulator_consumer_supply supply_ldo_d[] = {
+       {
+               .dev = NULL,
+               .supply = "vana15", /* Powers the SoC (CPU etc) */
+       },
+};
+
+static struct regulator_consumer_supply supply_ldo_g[] = {
+       {
+               .dev_name = "mmci",
+               .supply = "vmmc", /* Powers MMC/SD card */
+       },
+};
+
+static struct regulator_consumer_supply supply_ldo_h[] = {
+       {
+               .dev_name = "xgam_pdi",
+               .supply = "vdisp", /* Powers camera, display etc */
+       },
+};
+
+static struct regulator_consumer_supply supply_ldo_k[] = {
+       {
+               .dev_name = "irda",
+               .supply = "vir", /* Power IrDA */
+       },
+};
+
+/*
+ * This is a placeholder for whoever wish to use the
+ * external power.
+ */
+static struct regulator_consumer_supply supply_ldo_ext[] = {
+       {
+               .dev = NULL,
+               .supply = "vext", /* External power */
+       },
+};
+
+/* Preset (hardware defined) voltages for these regulators */
+#define LDO_A_VOLTAGE 2750000
+#define LDO_C_VOLTAGE 2650000
+#define LDO_D_VOLTAGE 2650000
+
+static struct ab3100_platform_data ab3100_plf_data = {
+       .reg_constraints = {
+               /* LDO A routing and constraints */
+               {
+                       .constraints = {
+                               .name = "vrad",
+                               .min_uV = LDO_A_VOLTAGE,
+                               .max_uV = LDO_A_VOLTAGE,
+                               .valid_modes_mask = REGULATOR_MODE_NORMAL,
+                               .always_on = 1,
+                               .boot_on = 1,
+                       },
+               },
+               /* LDO C routing and constraints */
+               {
+                       .constraints = {
+                               .min_uV = LDO_C_VOLTAGE,
+                               .max_uV = LDO_C_VOLTAGE,
+                               .valid_modes_mask = REGULATOR_MODE_NORMAL,
+                       },
+                       .num_consumer_supplies = ARRAY_SIZE(supply_ldo_c),
+                       .consumer_supplies = supply_ldo_c,
+               },
+               /* LDO D routing and constraints */
+               {
+                       .constraints = {
+                               .min_uV = LDO_D_VOLTAGE,
+                               .max_uV = LDO_D_VOLTAGE,
+                               .valid_modes_mask = REGULATOR_MODE_NORMAL,
+                               .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+                               /*
+                                * Actually this is boot_on but we need
+                                * to reference count it externally to
+                                * be able to shut down the system.
+                                */
+                       },
+                       .num_consumer_supplies = ARRAY_SIZE(supply_ldo_d),
+                       .consumer_supplies = supply_ldo_d,
+               },
+               /* LDO E routing and constraints */
+               {
+                       .constraints = {
+                               .name = "vio",
+                               .min_uV = 1800000,
+                               .max_uV = 1800000,
+                               .valid_modes_mask = REGULATOR_MODE_NORMAL,
+                               .valid_ops_mask =
+                               REGULATOR_CHANGE_VOLTAGE |
+                               REGULATOR_CHANGE_STATUS,
+                               .always_on = 1,
+                               .boot_on = 1,
+                       },
+               },
+               /* LDO F routing and constraints */
+               {
+                       .constraints = {
+                               .name = "vana25",
+                               .min_uV = 2500000,
+                               .max_uV = 2500000,
+                               .valid_modes_mask = REGULATOR_MODE_NORMAL,
+                               .valid_ops_mask =
+                               REGULATOR_CHANGE_VOLTAGE |
+                               REGULATOR_CHANGE_STATUS,
+                               .always_on = 1,
+                               .boot_on = 1,
+                       },
+               },
+               /* LDO G routing and constraints */
+               {
+                       .constraints = {
+                               .min_uV = 1500000,
+                               .max_uV = 2850000,
+                               .valid_modes_mask = REGULATOR_MODE_NORMAL,
+                               .valid_ops_mask =
+                               REGULATOR_CHANGE_VOLTAGE |
+                               REGULATOR_CHANGE_STATUS,
+                       },
+                       .num_consumer_supplies = ARRAY_SIZE(supply_ldo_g),
+                       .consumer_supplies = supply_ldo_g,
+               },
+               /* LDO H routing and constraints */
+               {
+                       .constraints = {
+                               .min_uV = 1200000,
+                               .max_uV = 2750000,
+                               .valid_modes_mask = REGULATOR_MODE_NORMAL,
+                               .valid_ops_mask =
+                               REGULATOR_CHANGE_VOLTAGE |
+                               REGULATOR_CHANGE_STATUS,
+                       },
+                       .num_consumer_supplies = ARRAY_SIZE(supply_ldo_h),
+                       .consumer_supplies = supply_ldo_h,
+               },
+               /* LDO K routing and constraints */
+               {
+                       .constraints = {
+                               .min_uV = 1800000,
+                               .max_uV = 2750000,
+                               .valid_modes_mask = REGULATOR_MODE_NORMAL,
+                               .valid_ops_mask =
+                               REGULATOR_CHANGE_VOLTAGE |
+                               REGULATOR_CHANGE_STATUS,
+                       },
+                       .num_consumer_supplies = ARRAY_SIZE(supply_ldo_k),
+                       .consumer_supplies = supply_ldo_k,
+               },
+               /* External regulator interface. No fixed voltage specified.
+                * If we knew the voltage of the external regulator and it
+                * was connected on the board, we could add the (fixed)
+                * voltage for it here.
+                */
+               {
+                       .constraints = {
+                               .min_uV = 0,
+                               .max_uV = 0,
+                               .valid_modes_mask = REGULATOR_MODE_NORMAL,
+                               .valid_ops_mask =
+                               REGULATOR_CHANGE_STATUS,
+                       },
+                       .num_consumer_supplies = ARRAY_SIZE(supply_ldo_ext),
+                       .consumer_supplies = supply_ldo_ext,
+               },
+               /* Buck converter routing and constraints */
+               {
+                       .constraints = {
+                               .name = "vcore",
+                               .min_uV = 1200000,
+                               .max_uV = 1800000,
+                               .valid_modes_mask = REGULATOR_MODE_NORMAL,
+                               .valid_ops_mask =
+                               REGULATOR_CHANGE_VOLTAGE |
+                               REGULATOR_CHANGE_STATUS,
+                               .always_on = 1,
+                               .boot_on = 1,
+                       },
+               },
+       },
+       .reg_initvals = {
+               LDO_A_SETTING,
+               LDO_C_SETTING,
+               LDO_E_SETTING,
+               LDO_E_SLEEP_SETTING,
+               LDO_F_SETTING,
+               LDO_G_SETTING,
+               LDO_H_SETTING,
+               LDO_K_SETTING,
+               LDO_EXT_SETTING,
+               BUCK_SETTING,
+               BUCK_SLEEP_SETTING,
+               LDO_D_SETTING,
+       },
+};
+
 static struct i2c_board_info __initdata bus0_i2c_board_info[] = {
        {
                .type = "ab3100",
                .addr = 0x48,
                .irq = IRQ_U300_IRQ0_EXT,
+               .platform_data = &ab3100_plf_data,
        },
 };
 
@@ -38,6 +282,11 @@ void __init u300_i2c_register_board_devices(void)
 {
        i2c_register_board_info(0, bus0_i2c_board_info,
                                ARRAY_SIZE(bus0_i2c_board_info));
+       /*
+        * This makes the core shut down all unused regulators
+        * after all the initcalls have completed.
+        */
+       regulator_has_full_constraints();
        i2c_register_board_info(1, bus1_i2c_board_info,
                                ARRAY_SIZE(bus1_i2c_board_info));
 }
index 7b6b016..109f5a6 100644 (file)
@@ -40,64 +40,6 @@ static unsigned int mmc_status(struct device *dev)
        return mmci_card->mmc_inserted;
 }
 
-/*
- * Here follows a large chunk of code which will only be enabled if you
- * have both the AB3100 chip mounted and the MMC subsystem activated.
- */
-
-static u32 mmc_translate_vdd(struct device *dev, unsigned int voltage)
-{
-       int v;
-
-       /*
-        * MMC Spec:
-        * bit 7:       1.70 - 1.95V
-        * bit 8 - 14:  2.0 - 2.6V
-        * bit 15 - 23: 2.7 - 3.6V
-        *
-        * ab3100 voltages:
-        * 000 - 2.85V
-        * 001 - 2.75V
-        * 010 - 1.8V
-        * 011 - 1.5V
-        */
-       switch (voltage) {
-       case 8:
-               v = 3;
-               break;
-       case 9:
-       case 10:
-       case 11:
-       case 12:
-       case 13:
-       case 14:
-       case 15:
-               v = 1;
-               break;
-       case 16:
-               v = 1;
-               break;
-       case 17:
-       case 18:
-       case 19:
-       case 20:
-       case 21:
-       case 22:
-       case 23:
-       case 24:
-               v = 0;
-               break;
-       default:
-               v = 0;
-               break;
-       }
-
-       /* PL180 voltage register bits */
-       return v << 2;
-}
-
-
-
 static int mmci_callback(void *data)
 {
        struct mmci_card_event *mmci_card = data;
@@ -154,9 +96,11 @@ int __devinit mmc_init(struct amba_device *adev)
        if (!mmci_card)
                return -ENOMEM;
 
+       /*
+        * Do not set ocr_mask or voltage translation function,
+        * we have a regulator we can control instead.
+        */
        /* Nominally 2.85V on our platform */
-       mmci_card->mmc0_plat_data.ocr_mask = MMC_VDD_28_29;
-       mmci_card->mmc0_plat_data.translate_vdd = mmc_translate_vdd;
        mmci_card->mmc0_plat_data.status = mmc_status;
        mmci_card->mmc0_plat_data.gpio_wp = -1;
        mmci_card->mmc0_plat_data.gpio_cd = -1;
diff --git a/arch/arm/mach-u300/regulator.c b/arch/arm/mach-u300/regulator.c
new file mode 100644 (file)
index 0000000..9c53f01
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * arch/arm/mach-u300/regulator.c
+ *
+ * Copyright (C) 2009 ST-Ericsson AB
+ * License terms: GNU General Public License (GPL) version 2
+ * Handle board-bound regulators and board power not related
+ * to any devices.
+ * Author: Linus Walleij <linus.walleij@stericsson.com>
+ */
+#include <linux/device.h>
+#include <linux/signal.h>
+#include <linux/err.h>
+#include <linux/regulator/consumer.h>
+/* Those are just for writing in syscon */
+#include <linux/io.h>
+#include <mach/hardware.h>
+#include <mach/syscon.h>
+
+/*
+ * Regulators that power the board and chip and which are
+ * not copuled to specific drivers are hogged in these
+ * instances.
+ */
+static struct regulator *main_power_15;
+
+/*
+ * This function is used from pm.h to shut down the system by
+ * resetting all regulators in turn and then disable regulator
+ * LDO D (main power).
+ */
+void u300_pm_poweroff(void)
+{
+       sigset_t old, all;
+
+       sigfillset(&all);
+       if (!sigprocmask(SIG_BLOCK, &all, &old)) {
+               /* Disable LDO D to shut down the system */
+               if (main_power_15)
+                       regulator_disable(main_power_15);
+               else
+                       pr_err("regulator not available to shut down system\n");
+               (void) sigprocmask(SIG_SETMASK, &old, NULL);
+       }
+       return;
+}
+
+/*
+ * Hog the regulators needed to power up the board.
+ */
+static int __init u300_init_boardpower(void)
+{
+       int err;
+       u32 val;
+
+       pr_info("U300: setting up board power\n");
+       main_power_15 = regulator_get(NULL, "vana15");
+       if (IS_ERR(main_power_15)) {
+               pr_err("could not get vana15");
+               return PTR_ERR(main_power_15);
+       }
+       err = regulator_enable(main_power_15);
+       if (err) {
+               pr_err("could not enable vana15\n");
+               return err;
+       }
+
+       /*
+        * On U300 a special system controller register pulls up the DC
+        * until the vana15 (LDO D) regulator comes up. At this point, all
+        * regulators are set and we do not need power control via
+        * DC ON anymore. This function will likely be moved whenever
+        * the rest of the U300 power management is implemented.
+        */
+       pr_info("U300: disable system controller pull-up\n");
+       val = readw(U300_SYSCON_VBASE + U300_SYSCON_PMCR);
+       val &= ~U300_SYSCON_PMCR_DCON_ENABLE;
+       writew(val, U300_SYSCON_VBASE + U300_SYSCON_PMCR);
+
+       /* Register globally exported PM poweroff hook */
+       pm_power_off = u300_pm_poweroff;
+
+       return 0;
+}
+
+/*
+ * So at module init time we hog the regulator!
+ */
+module_init(u300_init_boardpower);
diff --git a/arch/arm/mach-ux500/Kconfig b/arch/arm/mach-ux500/Kconfig
new file mode 100644 (file)
index 0000000..03625d7
--- /dev/null
@@ -0,0 +1,15 @@
+menu "ST-Ericsson platform type"
+       depends on ARCH_U8500
+
+comment "ST-Ericsson Multicore Mobile Platforms"
+
+config MACH_U8500_MOP
+       bool "U8500 Early Development platform"
+       default y
+       select ARM_GIC
+       select HAS_MTU
+       help
+         Include support for mop500 development platform
+         based on U8500 architecture. The platform is based
+         on early drop silicon version of 8500.
+endmenu
diff --git a/arch/arm/mach-ux500/Makefile b/arch/arm/mach-ux500/Makefile
new file mode 100644 (file)
index 0000000..95e6e24
--- /dev/null
@@ -0,0 +1,8 @@
+#
+# Makefile for the linux kernel, U8500 machine.
+#
+
+obj-y                          := clock.o
+obj-$(CONFIG_ARCH_U8500)       += cpu-u8500.o
+obj-$(CONFIG_MACH_U8500_MOP)   += board-mop500.o
+obj-$(CONFIG_SMP)              += platsmp.o headsmp.o localtimer.o
diff --git a/arch/arm/mach-ux500/Makefile.boot b/arch/arm/mach-ux500/Makefile.boot
new file mode 100644 (file)
index 0000000..c7e75ac
--- /dev/null
@@ -0,0 +1,4 @@
+   zreladdr-y  := 0x00008000
+params_phys-y  := 0x00000100
+initrd_phys-y  := 0x00800000
+
diff --git a/arch/arm/mach-ux500/board-mop500.c b/arch/arm/mach-ux500/board-mop500.c
new file mode 100644 (file)
index 0000000..aa5afbc
--- /dev/null
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2008-2009 ST-Ericsson
+ *
+ * Author: Srinidhi KASAGAR <srinidhi.kasagar@stericsson.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/kernel.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/amba/bus.h>
+#include <linux/amba/pl022.h>
+#include <linux/spi/spi.h>
+
+#include <asm/localtimer.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+
+#include <plat/mtu.h>
+
+#include <mach/hardware.h>
+#include <mach/setup.h>
+
+#define __MEM_4K_RESOURCE(x) \
+       .res = {.start = (x), .end = (x) + SZ_4K - 1, .flags = IORESOURCE_MEM}
+
+/* These are active devices on this board */
+static struct amba_device uart0_device = {
+       .dev = { .init_name = "uart0" },
+       __MEM_4K_RESOURCE(U8500_UART0_BASE),
+       .irq = {IRQ_UART0, NO_IRQ},
+};
+
+static struct amba_device uart1_device = {
+       .dev = { .init_name = "uart1" },
+       __MEM_4K_RESOURCE(U8500_UART1_BASE),
+       .irq = {IRQ_UART1, NO_IRQ},
+};
+
+static struct amba_device uart2_device = {
+       .dev = { .init_name = "uart2" },
+       __MEM_4K_RESOURCE(U8500_UART2_BASE),
+       .irq = {IRQ_UART2, NO_IRQ},
+};
+
+static void ab4500_spi_cs_control(u32 command)
+{
+       /* set the FRM signal, which is CS  - TODO */
+}
+
+struct pl022_config_chip ab4500_chip_info = {
+       .lbm = LOOPBACK_DISABLED,
+       .com_mode = INTERRUPT_TRANSFER,
+       .iface = SSP_INTERFACE_MOTOROLA_SPI,
+       /* we can act as master only */
+       .hierarchy = SSP_MASTER,
+       .slave_tx_disable = 0,
+       .endian_rx = SSP_RX_MSB,
+       .endian_tx = SSP_TX_MSB,
+       .data_size = SSP_DATA_BITS_24,
+       .rx_lev_trig = SSP_RX_1_OR_MORE_ELEM,
+       .tx_lev_trig = SSP_TX_1_OR_MORE_EMPTY_LOC,
+       .clk_phase = SSP_CLK_SECOND_EDGE,
+       .clk_pol = SSP_CLK_POL_IDLE_HIGH,
+       .cs_control = ab4500_spi_cs_control,
+};
+
+static struct spi_board_info u8500_spi_devices[] = {
+       {
+               .modalias = "ab4500",
+               .controller_data = &ab4500_chip_info,
+               .max_speed_hz = 12000000,
+               .bus_num = 0,
+               .chip_select = 0,
+               .mode = SPI_MODE_0,
+               .irq = IRQ_AB4500,
+       },
+};
+
+static struct pl022_ssp_controller ssp0_platform_data = {
+       .bus_id = 0,
+       /* pl022 not yet supports dma */
+       .enable_dma = 0,
+       /* on this platform, gpio 31,142,144,214 &
+        * 224 are connected as chip selects
+        */
+       .num_chipselect = 5,
+};
+
+static struct amba_device pl022_device = {
+       .dev = {
+               .coherent_dma_mask = ~0,
+               .init_name = "pl022",
+               .platform_data = &ssp0_platform_data,
+       },
+       .res = {
+               .start = U8500_SSP0_BASE,
+               .end   = U8500_SSP0_BASE + SZ_4K - 1,
+               .flags = IORESOURCE_MEM,
+       },
+       .irq = {IRQ_SSP0, NO_IRQ },
+       /* ST-Ericsson modified id */
+       .periphid = SSP_PER_ID,
+};
+
+static struct amba_device *amba_devs[] __initdata = {
+       &uart0_device,
+       &uart1_device,
+       &uart2_device,
+       &pl022_device,
+};
+
+static void __init u8500_timer_init(void)
+{
+#ifdef CONFIG_LOCAL_TIMERS
+       /* Setup the local timer base */
+       twd_base = __io_address(U8500_TWD_BASE);
+#endif
+       /* Setup the MTU base */
+       mtu_base = __io_address(U8500_MTU0_BASE);
+
+       nmdk_timer_init();
+}
+
+static struct sys_timer u8500_timer = {
+       .init   = u8500_timer_init,
+};
+
+static void __init u8500_init_machine(void)
+{
+       int i;
+
+       /* Register the active AMBA devices on this board */
+       for (i = 0; i < ARRAY_SIZE(amba_devs); i++)
+               amba_device_register(amba_devs[i], &iomem_resource);
+
+       spi_register_board_info(u8500_spi_devices,
+                       ARRAY_SIZE(u8500_spi_devices));
+
+       u8500_init_devices();
+}
+
+MACHINE_START(U8500, "ST-Ericsson MOP500 platform")
+       /* Maintainer: Srinidhi Kasagar <srinidhi.kasagar@stericsson.com> */
+       .phys_io        = U8500_UART2_BASE,
+       .io_pg_offst    = (IO_ADDRESS(U8500_UART2_BASE) >> 18) & 0xfffc,
+       .boot_params    = 0x100,
+       .map_io         = u8500_map_io,
+       .init_irq       = u8500_init_irq,
+       /* we re-use nomadik timer here */
+       .timer          = &u8500_timer,
+       .init_machine   = u8500_init_machine,
+MACHINE_END
diff --git a/arch/arm/mach-ux500/clock.c b/arch/arm/mach-ux500/clock.c
new file mode 100644 (file)
index 0000000..20b6ebb
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ *  Copyright (C) 2009 ST-Ericsson
+ *     heavily based on realview platform
+ *
+ * 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/kernel.h>
+#include <linux/list.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/mutex.h>
+
+#include <asm/clkdev.h>
+
+/* currently the clk structure
+ * just supports rate. This would
+ * be extended as and when new devices are
+ * added - TODO
+ */
+struct clk {
+       unsigned long           rate;
+};
+
+int clk_enable(struct clk *clk)
+{
+       return 0;
+}
+EXPORT_SYMBOL(clk_enable);
+
+void clk_disable(struct clk *clk)
+{
+}
+EXPORT_SYMBOL(clk_disable);
+
+unsigned long clk_get_rate(struct clk *clk)
+{
+       return clk->rate;
+}
+EXPORT_SYMBOL(clk_get_rate);
+
+long clk_round_rate(struct clk *clk, unsigned long rate)
+{
+       /*TODO*/
+       return rate;
+}
+EXPORT_SYMBOL(clk_round_rate);
+
+int clk_set_rate(struct clk *clk, unsigned long rate)
+{
+       clk->rate = rate;
+       return 0;
+}
+EXPORT_SYMBOL(clk_set_rate);
+
+/* ssp clock */
+static struct clk ssp_clk = {
+       .rate = 48000000,
+};
+
+/* fixed clock */
+static struct clk f38_clk = {
+       .rate = 38400000,
+};
+
+static struct clk_lookup lookups[] = {
+       {
+               /* UART0 */
+               .dev_id         = "uart0",
+               .clk            = &f38_clk,
+       }, {    /* UART1 */
+               .dev_id         = "uart1",
+               .clk            = &f38_clk,
+       }, {    /* UART2 */
+               .dev_id         = "uart2",
+               .clk            = &f38_clk,
+       }, {    /* SSP */
+               .dev_id         = "pl022",
+               .clk            = &ssp_clk,
+       }
+};
+
+static int __init clk_init(void)
+{
+       int i;
+
+       /* register the clock lookups */
+       for (i = 0; i < ARRAY_SIZE(lookups); i++)
+               clkdev_add(&lookups[i]);
+       return 0;
+}
+arch_initcall(clk_init);
diff --git a/arch/arm/mach-ux500/cpu-u8500.c b/arch/arm/mach-ux500/cpu-u8500.c
new file mode 100644 (file)
index 0000000..5f05e58
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2008-2009 ST-Ericsson
+ *
+ * Author: Srinidhi KASAGAR <srinidhi.kasagar@stericsson.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/types.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/amba/bus.h>
+#include <linux/irq.h>
+#include <linux/platform_device.h>
+
+#include <asm/hardware/gic.h>
+#include <asm/mach/map.h>
+#include <mach/hardware.h>
+
+/* add any platform devices here - TODO */
+static struct platform_device *platform_devs[] __initdata = {
+       /* yet to be added, add i2c0, gpio.. */
+};
+
+#define __IO_DEV_DESC(x, sz)   {               \
+       .virtual        = IO_ADDRESS(x),        \
+       .pfn            = __phys_to_pfn(x),     \
+       .length         = sz,                   \
+       .type           = MT_DEVICE,            \
+}
+
+/* minimum static i/o mapping required to boot U8500 platforms */
+static struct map_desc u8500_io_desc[] __initdata = {
+       __IO_DEV_DESC(U8500_GIC_CPU_BASE, SZ_4K),
+       __IO_DEV_DESC(U8500_GIC_DIST_BASE, SZ_4K),
+       __IO_DEV_DESC(U8500_MTU0_BASE, SZ_4K),
+       __IO_DEV_DESC(U8500_TWD_BASE, SZ_4K),
+       __IO_DEV_DESC(U8500_SCU_BASE, SZ_4K),
+       __IO_DEV_DESC(U8500_BACKUPRAM0_BASE, SZ_8K),
+};
+
+void __init u8500_map_io(void)
+{
+       iotable_init(u8500_io_desc, ARRAY_SIZE(u8500_io_desc));
+}
+
+void __init u8500_init_irq(void)
+{
+       gic_dist_init(0, __io_address(U8500_GIC_DIST_BASE), 29);
+       gic_cpu_init(0, __io_address(U8500_GIC_CPU_BASE));
+}
+
+/*
+ * This function is called from the board init
+ */
+void __init u8500_init_devices(void)
+{
+       /* Register the platform devices */
+       platform_add_devices(platform_devs, ARRAY_SIZE(platform_devs));
+
+       return ;
+}
diff --git a/arch/arm/mach-ux500/headsmp.S b/arch/arm/mach-ux500/headsmp.S
new file mode 100644 (file)
index 0000000..a6be2cd
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ *  Copyright (c) 2009 ST-Ericsson
+ *     This file is based  ARM Realview platform
+ *  Copyright (c) 2003 ARM Limited
+ *  All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/linkage.h>
+#include <linux/init.h>
+
+       __INIT
+
+/*
+ * U8500 specific entry point for secondary CPUs.
+ */
+ENTRY(u8500_secondary_startup)
+       mrc     p15, 0, r0, c0, c0, 5
+       and     r0, r0, #15
+       adr     r4, 1f
+       ldmia   r4, {r5, r6}
+       sub     r4, r4, r5
+       add     r6, r6, r4
+       dsb
+pen:   ldr     r7, [r6]
+       cmp     r7, r0
+       bne     pen
+
+       /*
+        * we've been released from the holding pen: secondary_stack
+        * should now contain the SVC stack for this core
+        */
+       b       secondary_startup
+
+1:     .long   .
+       .long   pen_release
diff --git a/arch/arm/mach-ux500/include/mach/clkdev.h b/arch/arm/mach-ux500/include/mach/clkdev.h
new file mode 100644 (file)
index 0000000..04b37a8
--- /dev/null
@@ -0,0 +1,7 @@
+#ifndef __ASM_MACH_CLKDEV_H
+#define __ASM_MACH_CLKDEV_H
+
+#define __clk_get(clk) ({ 1; })
+#define __clk_put(clk) do { } while (0)
+
+#endif
diff --git a/arch/arm/mach-ux500/include/mach/debug-macro.S b/arch/arm/mach-ux500/include/mach/debug-macro.S
new file mode 100644 (file)
index 0000000..8f21b6a
--- /dev/null
@@ -0,0 +1,19 @@
+/*
+ * Debugging macro include header
+ *
+ *  Copyright (C) 2009 ST-Ericsson
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+       .macro  addruart,rx
+       mrc     p15, 0, \rx, c1, c0
+       tst     \rx, #1                 @MMU enabled?
+       moveq   \rx, #0x80000000        @MMU off, Physical address
+       movne   \rx, #0xF0000000        @MMU on, Virtual address
+       orr     \rx, \rx, #0x7000
+       .endm
+
+#include <asm/hardware/debug-pl01x.S>
diff --git a/arch/arm/mach-ux500/include/mach/entry-macro.S b/arch/arm/mach-ux500/include/mach/entry-macro.S
new file mode 100644 (file)
index 0000000..eece330
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * Low-level IRQ helper macros for U8500 platforms
+ *
+ * Copyright (C) 2009 ST-Ericsson.
+ *
+ * This file is a copy of ARM Realview platform.
+ *     -just satisfied checkpatch script.
+ *
+ * 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 <asm/hardware/gic.h>
+
+               .macro  disable_fiq
+               .endm
+
+               .macro  get_irqnr_preamble, base, tmp
+               ldr     \base, =IO_ADDRESS(U8500_GIC_CPU_BASE)
+               .endm
+
+               .macro  arch_ret_to_user, tmp1, tmp2
+               .endm
+
+               /*
+                * The interrupt numbering scheme is defined in the
+                * interrupt controller spec.  To wit:
+                *
+                * Interrupts 0-15 are IPI
+                * 16-28 are reserved
+                * 29-31 are local.  We allow 30 to be used for the watchdog.
+                * 32-1020 are global
+                * 1021-1022 are reserved
+                * 1023 is "spurious" (no interrupt)
+                *
+                * For now, we ignore all local interrupts so only return an
+                * interrupt if it's between 30 and 1020. The test_for_ipi
+                * routine below will pick up on IPIs.
+                *
+                * A simple read from the controller will tell us the number
+                * of the highest priority enabled interrupt. We then just
+                * need to check whether it is in the valid range for an
+                * IRQ (30-1020 inclusive).
+                */
+
+               .macro  get_irqnr_and_base, irqnr, irqstat, base, tmp
+
+               /* bits 12-10 = src CPU, 9-0 = int # */
+               ldr     \irqstat, [\base, #GIC_CPU_INTACK]
+
+               ldr     \tmp, =1021
+
+               bic     \irqnr, \irqstat, #0x1c00
+
+               cmp     \irqnr, #29
+               cmpcc   \irqnr, \irqnr
+               cmpne   \irqnr, \tmp
+               cmpcs   \irqnr, \irqnr
+
+               .endm
+
+               /* We assume that irqstat (the raw value of the IRQ
+                * acknowledge register) is preserved from the macro above.
+                * If there is an IPI, we immediately signal end of
+                * interrupt on the controller, since this requires the
+                * original irqstat value which we won't easily be able
+                * to recreate later.
+                */
+
+               .macro test_for_ipi, irqnr, irqstat, base, tmp
+               bic     \irqnr, \irqstat, #0x1c00
+               cmp     \irqnr, #16
+               strcc   \irqstat, [\base, #GIC_CPU_EOI]
+               cmpcs   \irqnr, \irqnr
+               .endm
+
+               /* As above, this assumes that irqstat and base
+                * are preserved..
+                */
+
+               .macro test_for_ltirq, irqnr, irqstat, base, tmp
+               bic     \irqnr, \irqstat, #0x1c00
+               mov     \tmp, #0
+               cmp     \irqnr, #29
+               moveq   \tmp, #1
+               streq   \irqstat, [\base, #GIC_CPU_EOI]
+               cmp     \tmp, #0
+               .endm
diff --git a/arch/arm/mach-ux500/include/mach/hardware.h b/arch/arm/mach-ux500/include/mach/hardware.h
new file mode 100644 (file)
index 0000000..6da6502
--- /dev/null
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2009 ST-Ericsson.
+ *
+ * U8500 hardware definitions
+ *
+ * This file is licensed under  the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+#ifndef __MACH_HARDWARE_H
+#define __MACH_HARDWARE_H
+
+/* macros to get at IO space when running virtually
+ * We dont map all the peripherals, let ioremap do
+ * this for us. We map only very basic peripherals here.
+ */
+#define U8500_IO_VIRTUAL       0xf0000000
+#define U8500_IO_PHYSICAL      0xa0000000
+
+/* this macro is used in assembly, so no cast */
+#define IO_ADDRESS(x)           \
+       (((x) & 0x0fffffff) + (((x) >> 4) & 0x0f000000) + U8500_IO_VIRTUAL)
+
+/* typesafe io address */
+#define __io_address(n)                __io(IO_ADDRESS(n))
+
+/*
+ * Base address definitions for U8500 Onchip IPs. All the
+ * peripherals are contained in a single 1 Mbyte region, with
+ * AHB peripherals at the bottom and APB peripherals at the
+ * top of the region. PER stands for PERIPHERAL region which
+ * itself divided into sub regions.
+ */
+#define U8500_PER3_BASE                0x80000000
+#define U8500_PER2_BASE                0x80110000
+#define U8500_PER1_BASE                0x80120000
+#define U8500_PER4_BASE                0x80150000
+
+#define U8500_PER6_BASE                0xa03c0000
+#define U8500_PER5_BASE                0xa03e0000
+#define U8500_PER7_BASE                0xa03d0000
+
+#define U8500_SVA_BASE         0xa0100000
+#define U8500_SIA_BASE         0xa0200000
+
+#define U8500_SGA_BASE         0xa0300000
+#define U8500_MCDE_BASE                0xa0350000
+#define U8500_DMA_BASE         0xa0362000
+
+#define U8500_SCU_BASE         0xa0410000
+#define U8500_GIC_CPU_BASE     0xa0410100
+#define U8500_TWD_BASE         0xa0410600
+#define U8500_GIC_DIST_BASE    0xa0411000
+#define U8500_L2CC_BASE                0xa0412000
+
+#define U8500_TWD_SIZE         0x100
+
+/* per7 base addressess */
+#define U8500_CR_BASE          (U8500_PER7_BASE + 0x8000)
+#define U8500_MTU0_BASE                (U8500_PER7_BASE + 0xa000)
+#define U8500_MTU1_BASE                (U8500_PER7_BASE + 0xb000)
+#define U8500_TZPC0_BASE       (U8500_PER7_BASE + 0xc000)
+#define U8500_CLKRST7_BASE     (U8500_PER7_BASE + 0xf000)
+
+/* per6 base addressess */
+#define U8500_RNG_BASE         (U8500_PER6_BASE + 0x0000)
+#define U8500_PKA_BASE         (U8500_PER6_BASE + 0x1000)
+#define U8500_PKAM_BASE                (U8500_PER6_BASE + 0x2000)
+#define U8500_CRYPTO0_BASE     (U8500_PER6_BASE + 0xa000)
+#define U8500_CRYPTO1_BASE     (U8500_PER6_BASE + 0xb000)
+#define U8500_CLKRST6_BASE     (U8500_PER7_BASE + 0xf000)
+
+/* per5 base addressess */
+#define U8500_USBOTG_BASE      (U8500_PER5_BASE + 0x00000)
+#define U8500_GPIO5_BASE       (U8500_PER5_BASE + 0x1e000)
+#define U8500_CLKRST5_BASE     (U8500_PER7_BASE + 0x1f000)
+
+/* per4 base addressess */
+#define U8500_BACKUPRAM0_BASE  (U8500_PER4_BASE + 0x0000)
+#define U8500_BACKUPRAM1_BASE  (U8500_PER4_BASE + 0x1000)
+#define U8500_RTT0_BASE                (U8500_PER4_BASE + 0x2000)
+#define U8500_RTT1_BASE                (U8500_PER4_BASE + 0x3000)
+#define U8500_RTC_BASE         (U8500_PER4_BASE + 0x4000)
+#define U8500_SCR_BASE         (U8500_PER4_BASE + 0x5000)
+#define U8500_DMC_BASE         (U8500_PER4_BASE + 0x6000)
+#define U8500_PRCMU_BASE       (U8500_PER4_BASE + 0x7000)
+
+/* per3 base addressess */
+#define U8500_FSMC_BASE                (U8500_PER3_BASE + 0x0000)
+#define U8500_SSP0_BASE                (U8500_PER3_BASE + 0x2000)
+#define U8500_SSP1_BASE                (U8500_PER3_BASE + 0x3000)
+#define U8500_I2C0_BASE                (U8500_PER3_BASE + 0x4000)
+#define U8500_SDI2_BASE                (U8500_PER3_BASE + 0x5000)
+#define U8500_SKE_BASE         (U8500_PER3_BASE + 0x6000)
+#define U8500_UART2_BASE       (U8500_PER3_BASE + 0x7000)
+#define U8500_SDI5_BASE                (U8500_PER3_BASE + 0x8000)
+#define U8500_GPIO3_BASE       (U8500_PER3_BASE + 0xe000)
+#define U8500_CLKRST3_BASE     (U8500_PER7_BASE + 0xf000)
+
+/* per2 base addressess */
+#define U8500_I2C3_BASE                (U8500_PER2_BASE + 0x0000)
+#define U8500_SPI2_BASE                (U8500_PER2_BASE + 0x1000)
+#define U8500_SPI1_BASE                (U8500_PER2_BASE + 0x2000)
+#define U8500_PWL_BASE         (U8500_PER2_BASE + 0x3000)
+#define U8500_SDI4_BASE                (U8500_PER2_BASE + 0x4000)
+#define U8500_MSP2_BASE                (U8500_PER2_BASE + 0x7000)
+#define U8500_SDI1_BASE                (U8500_PER2_BASE + 0x8000)
+#define U8500_SDI3_BASE                (U8500_PER2_BASE + 0x9000)
+#define U8500_SPI0_BASE                (U8500_PER2_BASE + 0xa000)
+#define U8500_HSIR_BASE                (U8500_PER2_BASE + 0xb000)
+#define U8500_HSIT_BASE                (U8500_PER2_BASE + 0xc000)
+#define U8500_GPIO2_BASE       (U8500_PER2_BASE + 0xe000)
+#define U8500_CLKRST2_BASE     (U8500_PER2_BASE + 0xf000)
+
+/* per1 base addresses */
+#define U8500_UART0_BASE       (U8500_PER1_BASE + 0x0000)
+#define U8500_UART1_BASE       (U8500_PER1_BASE + 0x1000)
+#define U8500_I2C1_BASE                (U8500_PER1_BASE + 0x2000)
+#define U8500_MSP0_BASE                (U8500_PER1_BASE + 0x3000)
+#define U8500_MSP1_BASE                (U8500_PER1_BASE + 0x4000)
+#define U8500_SDI0_BASE                (U8500_PER1_BASE + 0x6000)
+#define U8500_I2C2_BASE                (U8500_PER1_BASE + 0x8000)
+#define U8500_SPI3_BASE                (U8500_PER1_BASE + 0x9000)
+#define U8500_SLIM0_BASE       (U8500_PER1_BASE + 0xa000)
+#define U8500_GPIO1_BASE       (U8500_PER1_BASE + 0xe000)
+#define U8500_CLKRST1_BASE     (U8500_PER2_BASE + 0xf000)
+
+/* ST-Ericsson modified pl022 id */
+#define SSP_PER_ID             0x01080022
+
+#endif                         /* __MACH_HARDWARE_H */
diff --git a/arch/arm/mach-ux500/include/mach/io.h b/arch/arm/mach-ux500/include/mach/io.h
new file mode 100644 (file)
index 0000000..1cf3f44
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * arch/arm/mach-u8500/include/mach/io.h
+ *
+ * Copyright (C) 1997-1999 Russell King
+ *
+ * Modifications:
+ *  06-12-1997 RMK     Created.
+ *  07-04-1999 RMK     Major cleanup
+ */
+#ifndef __ASM_ARM_ARCH_IO_H
+#define __ASM_ARM_ARCH_IO_H
+
+#define IO_SPACE_LIMIT 0xffffffff
+
+/*
+ * We don't actually have real ISA nor PCI buses, but there is so many
+ * drivers out there that might just work if we fake them...
+ */
+#define __io(a)                __typesafe_io(a)
+#define __mem_pci(a)   (a)
+
+#endif
diff --git a/arch/arm/mach-ux500/include/mach/irqs.h b/arch/arm/mach-ux500/include/mach/irqs.h
new file mode 100644 (file)
index 0000000..394b5dd
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ *  Copyright (C) 2008 STMicroelectronics
+ *  Copyright (C) 2009 ST-Ericsson.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+#ifndef ASM_ARCH_IRQS_H
+#define ASM_ARCH_IRQS_H
+
+#include <mach/hardware.h>
+
+#define IRQ_LOCALTIMER                  29
+#define IRQ_LOCALWDOG                   30
+
+/* Shared Peripheral Interrupt (SHPI) */
+#define IRQ_SHPI_START                 32
+
+/* Interrupt numbers generic for shared peripheral */
+#define IRQ_MTU0               (IRQ_SHPI_START + 4)
+#define IRQ_SPI2               (IRQ_SHPI_START + 6)
+#define IRQ_SPI0               (IRQ_SHPI_START + 8)
+#define IRQ_UART0              (IRQ_SHPI_START + 11)
+#define IRQ_I2C3               (IRQ_SHPI_START + 12)
+#define IRQ_SSP0               (IRQ_SHPI_START + 14)
+#define IRQ_MTU1               (IRQ_SHPI_START + 17)
+#define IRQ_RTC_RTT            (IRQ_SHPI_START + 18)
+#define IRQ_UART1              (IRQ_SHPI_START + 19)
+#define IRQ_I2C0               (IRQ_SHPI_START + 21)
+#define IRQ_I2C1               (IRQ_SHPI_START + 22)
+#define IRQ_USBOTG             (IRQ_SHPI_START + 23)
+#define IRQ_DMA                        (IRQ_SHPI_START + 25)
+#define IRQ_UART2              (IRQ_SHPI_START + 26)
+#define IRQ_HSIR_EXCEP         (IRQ_SHPI_START + 29)
+#define IRQ_MSP0               (IRQ_SHPI_START + 31)
+#define IRQ_HSIR_CH0_OVRRUN    (IRQ_SHPI_START + 32)
+#define IRQ_HSIR_CH1_OVRRUN    (IRQ_SHPI_START + 33)
+#define IRQ_HSIR_CH2_OVRRUN    (IRQ_SHPI_START + 34)
+#define IRQ_HSIR_CH3_OVRRUN    (IRQ_SHPI_START + 35)
+#define IRQ_AB4500             (IRQ_SHPI_START + 40)
+#define IRQ_DISP               (IRQ_SHPI_START + 48)
+#define IRQ_SiPI3              (IRQ_SHPI_START + 49)
+#define IRQ_SSP1               (IRQ_SHPI_START + 52)
+#define IRQ_I2C2               (IRQ_SHPI_START + 55)
+#define IRQ_SDMMC0             (IRQ_SHPI_START + 60)
+#define IRQ_MSP1               (IRQ_SHPI_START + 62)
+#define IRQ_SPI1               (IRQ_SHPI_START + 96)
+#define IRQ_MSP2               (IRQ_SHPI_START + 98)
+#define IRQ_SDMMC4             (IRQ_SHPI_START + 99)
+#define IRQ_HSIRD0             (IRQ_SHPI_START + 104)
+#define IRQ_HSIRD1             (IRQ_SHPI_START + 105)
+#define IRQ_HSITD0             (IRQ_SHPI_START + 106)
+#define IRQ_HSITD1             (IRQ_SHPI_START + 107)
+#define IRQ_GPIO0              (IRQ_SHPI_START + 119)
+#define IRQ_GPIO1              (IRQ_SHPI_START + 120)
+#define IRQ_GPIO2              (IRQ_SHPI_START + 121)
+#define IRQ_GPIO3              (IRQ_SHPI_START + 122)
+#define IRQ_GPIO4              (IRQ_SHPI_START + 123)
+#define IRQ_GPIO5              (IRQ_SHPI_START + 124)
+#define IRQ_GPIO6              (IRQ_SHPI_START + 125)
+#define IRQ_GPIO7              (IRQ_SHPI_START + 126)
+#define IRQ_GPIO8              (IRQ_SHPI_START + 127)
+
+/* There are 128 shared peripheral interrupts assigned to
+ * INTID[160:32]. The first 32 interrupts are reserved.
+ */
+#define NR_IRQS                        161
+
+#endif /*ASM_ARCH_IRQS_H*/
diff --git a/arch/arm/mach-ux500/include/mach/memory.h b/arch/arm/mach-ux500/include/mach/memory.h
new file mode 100644 (file)
index 0000000..510571a
--- /dev/null
@@ -0,0 +1,18 @@
+/*
+ * Copyright (C) 2009 ST-Ericsson
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+#ifndef __ASM_ARCH_MEMORY_H
+#define __ASM_ARCH_MEMORY_H
+
+/*
+ * Physical DRAM offset.
+ */
+#define PHYS_OFFSET    UL(0x00000000)
+#define BUS_OFFSET     UL(0x00000000)
+
+#endif
diff --git a/arch/arm/mach-ux500/include/mach/setup.h b/arch/arm/mach-ux500/include/mach/setup.h
new file mode 100644 (file)
index 0000000..cf0ce16
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2009 ST-Ericsson.
+ *
+ * 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.
+ *
+ * These symbols are needed for board-specific files to call their
+ * own cpu-specific files
+ */
+#ifndef __ASM_ARCH_SETUP_H
+#define __ASM_ARCH_SETUP_H
+
+#include <asm/mach/time.h>
+#include <linux/init.h>
+
+extern void u8500_map_io(void);
+extern void u8500_init_devices(void);
+extern void u8500_init_irq(void);
+/* We re-use nomadik_timer for this platform */
+extern void nmdk_timer_init(void);
+
+#endif /*  __ASM_ARCH_SETUP_H */
diff --git a/arch/arm/mach-ux500/include/mach/smp.h b/arch/arm/mach-ux500/include/mach/smp.h
new file mode 100644 (file)
index 0000000..b59f7bc
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * This file is based ARM realview platform.
+ * Copyright (C) ARM Limited.
+ *
+ * This file is licensed under  the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+#ifndef ASMARM_ARCH_SMP_H
+#define ASMARM_ARCH_SMP_H
+
+#include <asm/hardware/gic.h>
+
+/* This is required to wakeup the secondary core */
+extern void u8500_secondary_startup(void);
+
+#define hard_smp_processor_id()                                \
+       ({                                              \
+               unsigned int cpunum;                    \
+               __asm__("mrc p15, 0, %0, c0, c0, 5"     \
+                       : "=r" (cpunum));               \
+               cpunum &= 0x0F;                         \
+       })
+
+/*
+ * We use IRQ1 as the IPI
+ */
+static inline void smp_cross_call(const struct cpumask *mask)
+{
+       gic_raise_softirq(mask, 1);
+}
+#endif
diff --git a/arch/arm/mach-ux500/include/mach/system.h b/arch/arm/mach-ux500/include/mach/system.h
new file mode 100644 (file)
index 0000000..c0cd800
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2009 ST-Ericsson.
+ *
+ * This file is licensed under  the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+#ifndef __ASM_ARCH_SYSTEM_H
+#define __ASM_ARCH_SYSTEM_H
+
+static inline void arch_idle(void)
+{
+       /*
+        * This should do all the clock switching
+        * and wait for interrupt tricks
+        */
+       cpu_do_idle();
+}
+
+static inline void arch_reset(char mode, const char *cmd)
+{
+       /* yet to be implemented - TODO */
+}
+
+#endif
diff --git a/arch/arm/mach-ux500/include/mach/timex.h b/arch/arm/mach-ux500/include/mach/timex.h
new file mode 100644 (file)
index 0000000..d0942c1
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef __ASM_ARCH_TIMEX_H
+#define __ASM_ARCH_TIMEX_H
+
+#define CLOCK_TICK_RATE                110000000
+
+#endif
diff --git a/arch/arm/mach-ux500/include/mach/uncompress.h b/arch/arm/mach-ux500/include/mach/uncompress.h
new file mode 100644 (file)
index 0000000..8552eb1
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ *  Copyright (C) 2009 ST-Ericsson
+ *
+ * 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_UNCOMPRESS_H
+#define __ASM_ARCH_UNCOMPRESS_H
+
+#include <asm/setup.h>
+#include <linux/io.h>
+#include <mach/hardware.h>
+
+#define U8500_UART_DR          0x80007000
+#define U8500_UART_LCRH                0x8000702c
+#define U8500_UART_CR          0x80007030
+#define U8500_UART_FR          0x80007018
+
+static void putc(const char c)
+{
+       /* Do nothing if the UART is not enabled. */
+       if (!(readb(U8500_UART_CR) & 0x1))
+               return;
+
+       if (c == '\n')
+               putc('\r');
+
+       while (readb(U8500_UART_FR) & (1 << 5))
+               barrier();
+       writeb(c, U8500_UART_DR);
+}
+
+static void flush(void)
+{
+       if (!(readb(U8500_UART_CR) & 0x1))
+               return;
+       while (readb(U8500_UART_FR) & (1 << 3))
+               barrier();
+}
+
+static inline void arch_decomp_setup(void)
+{
+}
+
+#define arch_decomp_wdog() /* nothing to do here */
+
+#endif /* __ASM_ARCH_UNCOMPRESS_H */
diff --git a/arch/arm/mach-ux500/include/mach/vmalloc.h b/arch/arm/mach-ux500/include/mach/vmalloc.h
new file mode 100644 (file)
index 0000000..86cdbbc
--- /dev/null
@@ -0,0 +1,18 @@
+/*
+ *  Copyright (C) 2009 ST-Ericsson
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#define VMALLOC_END    0xf0000000
diff --git a/arch/arm/mach-ux500/localtimer.c b/arch/arm/mach-ux500/localtimer.c
new file mode 100644 (file)
index 0000000..2288f6a
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2008-2009 ST-Ericsson
+ * Srinidhi Kasagar <srinidhi.kasagar@stericsson.com>
+ *
+ * This file is heavily based on relaview platform, almost a copy.
+ *
+ * Copyright (C) 2002 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/init.h>
+#include <linux/smp.h>
+#include <linux/clockchips.h>
+
+#include <asm/irq.h>
+#include <asm/smp_twd.h>
+#include <asm/localtimer.h>
+
+/*
+ * Setup the local clock events for a CPU.
+ */
+void __cpuinit local_timer_setup(struct clock_event_device *evt)
+{
+       evt->irq = IRQ_LOCALTIMER;
+       twd_timer_setup(evt);
+}
diff --git a/arch/arm/mach-ux500/platsmp.c b/arch/arm/mach-ux500/platsmp.c
new file mode 100644 (file)
index 0000000..8dfe7ca
--- /dev/null
@@ -0,0 +1,177 @@
+/*
+ * Copyright (C) 2002 ARM Ltd.
+ * Copyright (C) 2008 STMicroelctronics.
+ * Copyright (C) 2009 ST-Ericsson.
+ * Author: Srinidhi Kasagar <srinidhi.kasagar@stericsson.com>
+ *
+ * This file is based on arm realview platform
+ *
+ * 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/errno.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/smp.h>
+#include <linux/io.h>
+
+#include <asm/cacheflush.h>
+#include <asm/localtimer.h>
+#include <asm/smp_scu.h>
+#include <mach/hardware.h>
+
+/*
+ * control for which core is the next to come out of the secondary
+ * boot "holding pen"
+ */
+volatile int __cpuinitdata pen_release = -1;
+
+static unsigned int __init get_core_count(void)
+{
+       return scu_get_core_count(__io_address(U8500_SCU_BASE));
+}
+
+static DEFINE_SPINLOCK(boot_lock);
+
+void __cpuinit platform_secondary_init(unsigned int cpu)
+{
+       trace_hardirqs_off();
+
+       /*
+        * if any interrupts are already enabled for the primary
+        * core (e.g. timer irq), then they will not have been enabled
+        * for us: do so
+        */
+       gic_cpu_init(0, __io_address(U8500_GIC_CPU_BASE));
+
+       /*
+        * let the primary processor know we're out of the
+        * pen, then head off into the C entry point
+        */
+       pen_release = -1;
+
+       /*
+        * Synchronise with the boot thread.
+        */
+       spin_lock(&boot_lock);
+       spin_unlock(&boot_lock);
+}
+
+int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle)
+{
+       unsigned long timeout;
+
+       /*
+        * set synchronisation state between this boot processor
+        * and the secondary one
+        */
+       spin_lock(&boot_lock);
+
+       /*
+        * The secondary processor is waiting to be released from
+        * the holding pen - release it, then wait for it to flag
+        * that it has been released by resetting pen_release.
+        */
+       pen_release = cpu;
+       flush_cache_all();
+
+       timeout = jiffies + (1 * HZ);
+       while (time_before(jiffies, timeout)) {
+               if (pen_release == -1)
+                       break;
+       }
+
+       /*
+        * now the secondary core is starting up let it run its
+        * calibrations, then wait for it to finish
+        */
+       spin_unlock(&boot_lock);
+
+       return pen_release != -1 ? -ENOSYS : 0;
+}
+
+static void __init wakeup_secondary(void)
+{
+       /* nobody is to be released from the pen yet */
+       pen_release = -1;
+
+       /*
+        * write the address of secondary startup into the backup ram register
+        * at offset 0x1FF4, then write the magic number 0xA1FEED01 to the
+        * backup ram register at offset 0x1FF0, which is what boot rom code
+        * is waiting for. This would wake up the secondary core from WFE
+        */
+#define U8500_CPU1_JUMPADDR_OFFSET 0x1FF4
+       __raw_writel(virt_to_phys(u8500_secondary_startup),
+               (void __iomem *)IO_ADDRESS(U8500_BACKUPRAM0_BASE) +
+               U8500_CPU1_JUMPADDR_OFFSET);
+
+#define U8500_CPU1_WAKEMAGIC_OFFSET 0x1FF0
+       __raw_writel(0xA1FEED01,
+               (void __iomem *)IO_ADDRESS(U8500_BACKUPRAM0_BASE) +
+               U8500_CPU1_WAKEMAGIC_OFFSET);
+
+       /* make sure write buffer is drained */
+       mb();
+}
+
+/*
+ * Initialise the CPU possible map early - this describes the CPUs
+ * which may be present or become present in the system.
+ */
+void __init smp_init_cpus(void)
+{
+       unsigned int i, ncores = get_core_count();
+
+       for (i = 0; i < ncores; i++)
+               set_cpu_possible(i, true);
+}
+
+void __init smp_prepare_cpus(unsigned int max_cpus)
+{
+       unsigned int ncores = get_core_count();
+       unsigned int cpu = smp_processor_id();
+       int i;
+
+       /* sanity check */
+       if (ncores == 0) {
+               printk(KERN_ERR
+                      "U8500: strange CM count of 0? Default to 1\n");
+               ncores = 1;
+       }
+
+       if (ncores > num_possible_cpus())       {
+               printk(KERN_WARNING
+                      "U8500: no. of cores (%d) greater than configured "
+                      "maximum of %d - clipping\n",
+                      ncores, num_possible_cpus());
+               ncores = num_possible_cpus();
+       }
+
+       smp_store_cpu_info(cpu);
+
+       /*
+        * are we trying to boot more cores than exist?
+        */
+       if (max_cpus > ncores)
+               max_cpus = ncores;
+
+       /*
+        * Initialise the present map, which describes the set of CPUs
+        * actually populated at the present time.
+        */
+       for (i = 0; i < max_cpus; i++)
+               set_cpu_present(i, true);
+
+       if (max_cpus > 1) {
+               /*
+                * Enable the local timer or broadcast device for the
+                * boot CPU, but only if we have more than one CPU.
+                */
+               percpu_timer_setup();
+               scu_enable(__io_address(U8500_SCU_BASE));
+               wakeup_secondary();
+       }
+}
index 2a6f98d..51f17b7 100644 (file)
@@ -32,6 +32,7 @@
 #include <asm/mach-types.h>
 
 #include <mach/regs-serial.h>
+#include <mach/nuc900_spi.h>
 #include <mach/map.h>
 
 #include "cpu.h"
@@ -196,6 +197,18 @@ static struct platform_device nuc900_device_emc = {
 
 /* SPI device */
 
+static struct w90p910_spi_info nuc900_spiflash_data = {
+       .num_cs         = 1,
+       .lsb            = 0,
+       .txneg          = 1,
+       .rxneg          = 0,
+       .divider        = 24,
+       .sleep          = 0,
+       .txnum          = 0,
+       .txbitlen       = 1,
+       .bus_num        = 0,
+};
+
 static struct resource nuc900_spi_resource[] = {
        [0] = {
                .start = W90X900_PA_I2C + SPIOFFSET,
@@ -214,6 +227,9 @@ static struct platform_device nuc900_device_spi = {
        .id             = -1,
        .num_resources  = ARRAY_SIZE(nuc900_spi_resource),
        .resource       = nuc900_spi_resource,
+       .dev            = {
+                               .platform_data = &nuc900_spiflash_data,
+                       }
 };
 
 /* spi device, spi flash info */
index 9264d81..dd4698c 100644 (file)
@@ -388,7 +388,7 @@ config CPU_FEROCEON_OLD_ID
 
 # ARMv6
 config CPU_V6
-       bool "Support ARM V6 processor" if ARCH_INTEGRATOR || MACH_REALVIEW_EB || MACH_REALVIEW_PBX
+       bool "Support ARM V6 processor" if ARCH_INTEGRATOR || MACH_REALVIEW_EB || MACH_REALVIEW_PBX || ARCH_DOVE
        select CPU_32v6
        select CPU_ABRT_EV6
        select CPU_PABRT_V6
@@ -764,6 +764,15 @@ config CACHE_L2X0
        help
          This option enables the L2x0 PrimeCell.
 
+config CACHE_TAUROS2
+       bool "Enable the Tauros2 L2 cache controller"
+       depends on ARCH_DOVE
+       default y
+       select OUTER_CACHE
+       help
+         This option enables the Tauros2 L2 cache controller (as
+         found on PJ1/PJ4).
+
 config CACHE_XSC3L2
        bool "Enable the L2 cache on XScale3"
        depends on CPU_XSC3
@@ -774,5 +783,5 @@ config CACHE_XSC3L2
 
 config ARM_L1_CACHE_SHIFT
        int
-       default 6 if ARCH_OMAP3
+       default 6 if ARCH_OMAP3 || ARCH_S5PC1XX
        default 5
index 055cb2a..827e238 100644 (file)
@@ -6,7 +6,7 @@ obj-y                           := dma-mapping.o extable.o fault.o init.o \
                                   iomap.o
 
 obj-$(CONFIG_MMU)              += fault-armv.o flush.o ioremap.o mmap.o \
-                                  pgd.o mmu.o
+                                  pgd.o mmu.o vmregion.o
 
 ifneq ($(CONFIG_MMU),y)
 obj-y                          += nommu.o
@@ -87,4 +87,4 @@ obj-$(CONFIG_CPU_V7)          += proc-v7.o
 obj-$(CONFIG_CACHE_FEROCEON_L2)        += cache-feroceon-l2.o
 obj-$(CONFIG_CACHE_L2X0)       += cache-l2x0.o
 obj-$(CONFIG_CACHE_XSC3L2)     += cache-xsc3l2.o
-
+obj-$(CONFIG_CACHE_TAUROS2)    += cache-tauros2.o
index b480f1d..747f9a9 100644 (file)
@@ -99,18 +99,25 @@ void __init l2x0_init(void __iomem *base, __u32 aux_val, __u32 aux_mask)
 
        l2x0_base = base;
 
-       /* disable L2X0 */
-       writel(0, l2x0_base + L2X0_CTRL);
+       /*
+        * Check if l2x0 controller is already enabled.
+        * If you are booting from non-secure mode
+        * accessing the below registers will fault.
+        */
+       if (!(readl(l2x0_base + L2X0_CTRL) & 1)) {
 
-       aux = readl(l2x0_base + L2X0_AUX_CTRL);
-       aux &= aux_mask;
-       aux |= aux_val;
-       writel(aux, l2x0_base + L2X0_AUX_CTRL);
+               /* l2x0 controller is disabled */
 
-       l2x0_inv_all();
+               aux = readl(l2x0_base + L2X0_AUX_CTRL);
+               aux &= aux_mask;
+               aux |= aux_val;
+               writel(aux, l2x0_base + L2X0_AUX_CTRL);
 
-       /* enable L2X0 */
-       writel(1, l2x0_base + L2X0_CTRL);
+               l2x0_inv_all();
+
+               /* enable L2X0 */
+               writel(1, l2x0_base + L2X0_CTRL);
+       }
 
        outer_cache.inv_range = l2x0_inv_range;
        outer_cache.clean_range = l2x0_clean_range;
diff --git a/arch/arm/mm/cache-tauros2.c b/arch/arm/mm/cache-tauros2.c
new file mode 100644 (file)
index 0000000..5086865
--- /dev/null
@@ -0,0 +1,263 @@
+/*
+ * arch/arm/mm/cache-tauros2.c - Tauros2 L2 cache controller support
+ *
+ * Copyright (C) 2008 Marvell Semiconductor
+ *
+ * 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.
+ *
+ * References:
+ * - PJ1 CPU Core Datasheet,
+ *   Document ID MV-S104837-01, Rev 0.7, January 24 2008.
+ * - PJ4 CPU Core Datasheet,
+ *   Document ID MV-S105190-00, Rev 0.7, March 14 2008.
+ */
+
+#include <linux/init.h>
+#include <asm/cacheflush.h>
+#include <asm/hardware/cache-tauros2.h>
+
+
+/*
+ * When Tauros2 is used on a CPU that supports the v7 hierarchical
+ * cache operations, the cache handling code in proc-v7.S takes care
+ * of everything, including handling DMA coherency.
+ *
+ * So, we only need to register outer cache operations here if we're
+ * being used on a pre-v7 CPU, and we only need to build support for
+ * outer cache operations into the kernel image if the kernel has been
+ * configured to support a pre-v7 CPU.
+ */
+#if __LINUX_ARM_ARCH__ < 7
+/*
+ * Low-level cache maintenance operations.
+ */
+static inline void tauros2_clean_pa(unsigned long addr)
+{
+       __asm__("mcr p15, 1, %0, c7, c11, 3" : : "r" (addr));
+}
+
+static inline void tauros2_clean_inv_pa(unsigned long addr)
+{
+       __asm__("mcr p15, 1, %0, c7, c15, 3" : : "r" (addr));
+}
+
+static inline void tauros2_inv_pa(unsigned long addr)
+{
+       __asm__("mcr p15, 1, %0, c7, c7, 3" : : "r" (addr));
+}
+
+
+/*
+ * Linux primitives.
+ *
+ * Note that the end addresses passed to Linux primitives are
+ * noninclusive.
+ */
+#define CACHE_LINE_SIZE                32
+
+static void tauros2_inv_range(unsigned long start, unsigned long end)
+{
+       /*
+        * Clean and invalidate partial first cache line.
+        */
+       if (start & (CACHE_LINE_SIZE - 1)) {
+               tauros2_clean_inv_pa(start & ~(CACHE_LINE_SIZE - 1));
+               start = (start | (CACHE_LINE_SIZE - 1)) + 1;
+       }
+
+       /*
+        * Clean and invalidate partial last cache line.
+        */
+       if (end & (CACHE_LINE_SIZE - 1)) {
+               tauros2_clean_inv_pa(end & ~(CACHE_LINE_SIZE - 1));
+               end &= ~(CACHE_LINE_SIZE - 1);
+       }
+
+       /*
+        * Invalidate all full cache lines between 'start' and 'end'.
+        */
+       while (start < end) {
+               tauros2_inv_pa(start);
+               start += CACHE_LINE_SIZE;
+       }
+
+       dsb();
+}
+
+static void tauros2_clean_range(unsigned long start, unsigned long end)
+{
+       start &= ~(CACHE_LINE_SIZE - 1);
+       while (start < end) {
+               tauros2_clean_pa(start);
+               start += CACHE_LINE_SIZE;
+       }
+
+       dsb();
+}
+
+static void tauros2_flush_range(unsigned long start, unsigned long end)
+{
+       start &= ~(CACHE_LINE_SIZE - 1);
+       while (start < end) {
+               tauros2_clean_inv_pa(start);
+               start += CACHE_LINE_SIZE;
+       }
+
+       dsb();
+}
+#endif
+
+static inline u32 __init read_extra_features(void)
+{
+       u32 u;
+
+       __asm__("mrc p15, 1, %0, c15, c1, 0" : "=r" (u));
+
+       return u;
+}
+
+static inline void __init write_extra_features(u32 u)
+{
+       __asm__("mcr p15, 1, %0, c15, c1, 0" : : "r" (u));
+}
+
+static void __init disable_l2_prefetch(void)
+{
+       u32 u;
+
+       /*
+        * Read the CPU Extra Features register and verify that the
+        * Disable L2 Prefetch bit is set.
+        */
+       u = read_extra_features();
+       if (!(u & 0x01000000)) {
+               printk(KERN_INFO "Tauros2: Disabling L2 prefetch.\n");
+               write_extra_features(u | 0x01000000);
+       }
+}
+
+static inline int __init cpuid_scheme(void)
+{
+       extern int processor_id;
+
+       return !!((processor_id & 0x000f0000) == 0x000f0000);
+}
+
+static inline u32 __init read_mmfr3(void)
+{
+       u32 mmfr3;
+
+       __asm__("mrc p15, 0, %0, c0, c1, 7\n" : "=r" (mmfr3));
+
+       return mmfr3;
+}
+
+static inline u32 __init read_actlr(void)
+{
+       u32 actlr;
+
+       __asm__("mrc p15, 0, %0, c1, c0, 1\n" : "=r" (actlr));
+
+       return actlr;
+}
+
+static inline void __init write_actlr(u32 actlr)
+{
+       __asm__("mcr p15, 0, %0, c1, c0, 1\n" : : "r" (actlr));
+}
+
+void __init tauros2_init(void)
+{
+       extern int processor_id;
+       char *mode;
+
+       disable_l2_prefetch();
+
+#ifdef CONFIG_CPU_32v5
+       if ((processor_id & 0xff0f0000) == 0x56050000) {
+               u32 feat;
+
+               /*
+                * v5 CPUs with Tauros2 have the L2 cache enable bit
+                * located in the CPU Extra Features register.
+                */
+               feat = read_extra_features();
+               if (!(feat & 0x00400000)) {
+                       printk(KERN_INFO "Tauros2: Enabling L2 cache.\n");
+                       write_extra_features(feat | 0x00400000);
+               }
+
+               mode = "ARMv5";
+               outer_cache.inv_range = tauros2_inv_range;
+               outer_cache.clean_range = tauros2_clean_range;
+               outer_cache.flush_range = tauros2_flush_range;
+       }
+#endif
+
+#ifdef CONFIG_CPU_32v6
+       /*
+        * Check whether this CPU lacks support for the v7 hierarchical
+        * cache ops.  (PJ4 is in its v6 personality mode if the MMFR3
+        * register indicates no support for the v7 hierarchical cache
+        * ops.)
+        */
+       if (cpuid_scheme() && (read_mmfr3() & 0xf) == 0) {
+               /*
+                * When Tauros2 is used in an ARMv6 system, the L2
+                * enable bit is in the ARMv6 ARM-mandated position
+                * (bit [26] of the System Control Register).
+                */
+               if (!(get_cr() & 0x04000000)) {
+                       printk(KERN_INFO "Tauros2: Enabling L2 cache.\n");
+                       adjust_cr(0x04000000, 0x04000000);
+               }
+
+               mode = "ARMv6";
+               outer_cache.inv_range = tauros2_inv_range;
+               outer_cache.clean_range = tauros2_clean_range;
+               outer_cache.flush_range = tauros2_flush_range;
+       }
+#endif
+
+#ifdef CONFIG_CPU_32v7
+       /*
+        * Check whether this CPU has support for the v7 hierarchical
+        * cache ops.  (PJ4 is in its v7 personality mode if the MMFR3
+        * register indicates support for the v7 hierarchical cache
+        * ops.)
+        *
+        * (Although strictly speaking there may exist CPUs that
+        * implement the v7 cache ops but are only ARMv6 CPUs (due to
+        * not complying with all of the other ARMv7 requirements),
+        * there are no real-life examples of Tauros2 being used on
+        * such CPUs as of yet.)
+        */
+       if (cpuid_scheme() && (read_mmfr3() & 0xf) == 1) {
+               u32 actlr;
+
+               /*
+                * When Tauros2 is used in an ARMv7 system, the L2
+                * enable bit is located in the Auxiliary System Control
+                * Register (which is the only register allowed by the
+                * ARMv7 spec to contain fine-grained cache control bits).
+                */
+               actlr = read_actlr();
+               if (!(actlr & 0x00000002)) {
+                       printk(KERN_INFO "Tauros2: Enabling L2 cache.\n");
+                       write_actlr(actlr | 0x00000002);
+               }
+
+               mode = "ARMv7";
+       }
+#endif
+
+       if (mode == NULL) {
+               printk(KERN_CRIT "Tauros2: Unable to detect CPU mode.\n");
+               return;
+       }
+
+       printk(KERN_INFO "Tauros2: L2 cache support initialised "
+                        "in %s mode.\n", mode);
+}
index 4127a7b..841f355 100644 (file)
@@ -41,6 +41,14 @@ static void v6_copy_user_highpage_nonaliasing(struct page *to,
        kfrom = kmap_atomic(from, KM_USER0);
        kto = kmap_atomic(to, KM_USER1);
        copy_page(kto, kfrom);
+#ifdef CONFIG_HIGHMEM
+       /*
+        * kmap_atomic() doesn't set the page virtual address, and
+        * kunmap_atomic() takes care of cache flushing already.
+        */
+       if (page_address(to) != NULL)
+#endif
+               __cpuc_flush_dcache_page(kto);
        kunmap_atomic(kto, KM_USER1);
        kunmap_atomic(kfrom, KM_USER0);
 }
index b9590a7..26325cb 100644 (file)
@@ -63,194 +63,152 @@ static u64 get_coherent_dma_mask(struct device *dev)
        return mask;
 }
 
-#ifdef CONFIG_MMU
 /*
- * These are the page tables (2MB each) covering uncached, DMA consistent allocations
+ * Allocate a DMA buffer for 'dev' of size 'size' using the
+ * specified gfp mask.  Note that 'size' must be page aligned.
  */
-static pte_t *consistent_pte[NUM_CONSISTENT_PTES];
-static DEFINE_SPINLOCK(consistent_lock);
+static struct page *__dma_alloc_buffer(struct device *dev, size_t size, gfp_t gfp)
+{
+       unsigned long order = get_order(size);
+       struct page *page, *p, *e;
+       void *ptr;
+       u64 mask = get_coherent_dma_mask(dev);
 
-/*
- * VM region handling support.
- *
- * This should become something generic, handling VM region allocations for
- * vmalloc and similar (ioremap, module space, etc).
- *
- * I envisage vmalloc()'s supporting vm_struct becoming:
- *
- *  struct vm_struct {
- *    struct vm_region region;
- *    unsigned long    flags;
- *    struct page      **pages;
- *    unsigned int     nr_pages;
- *    unsigned long    phys_addr;
- *  };
- *
- * get_vm_area() would then call vm_region_alloc with an appropriate
- * struct vm_region head (eg):
- *
- *  struct vm_region vmalloc_head = {
- *     .vm_list        = LIST_HEAD_INIT(vmalloc_head.vm_list),
- *     .vm_start       = VMALLOC_START,
- *     .vm_end         = VMALLOC_END,
- *  };
- *
- * However, vmalloc_head.vm_start is variable (typically, it is dependent on
- * the amount of RAM found at boot time.)  I would imagine that get_vm_area()
- * would have to initialise this each time prior to calling vm_region_alloc().
- */
-struct arm_vm_region {
-       struct list_head        vm_list;
-       unsigned long           vm_start;
-       unsigned long           vm_end;
-       struct page             *vm_pages;
-       int                     vm_active;
-};
+#ifdef CONFIG_DMA_API_DEBUG
+       u64 limit = (mask + 1) & ~mask;
+       if (limit && size >= limit) {
+               dev_warn(dev, "coherent allocation too big (requested %#x mask %#llx)\n",
+                       size, mask);
+               return NULL;
+       }
+#endif
 
-static struct arm_vm_region consistent_head = {
-       .vm_list        = LIST_HEAD_INIT(consistent_head.vm_list),
-       .vm_start       = CONSISTENT_BASE,
-       .vm_end         = CONSISTENT_END,
-};
+       if (!mask)
+               return NULL;
 
-static struct arm_vm_region *
-arm_vm_region_alloc(struct arm_vm_region *head, size_t size, gfp_t gfp)
-{
-       unsigned long addr = head->vm_start, end = head->vm_end - size;
-       unsigned long flags;
-       struct arm_vm_region *c, *new;
-
-       new = kmalloc(sizeof(struct arm_vm_region), gfp);
-       if (!new)
-               goto out;
-
-       spin_lock_irqsave(&consistent_lock, flags);
-
-       list_for_each_entry(c, &head->vm_list, vm_list) {
-               if ((addr + size) < addr)
-                       goto nospc;
-               if ((addr + size) <= c->vm_start)
-                       goto found;
-               addr = c->vm_end;
-               if (addr > end)
-                       goto nospc;
-       }
+       if (mask < 0xffffffffULL)
+               gfp |= GFP_DMA;
+
+       page = alloc_pages(gfp, order);
+       if (!page)
+               return NULL;
 
- found:
        /*
-        * Insert this entry _before_ the one we found.
+        * Now split the huge page and free the excess pages
         */
-       list_add_tail(&new->vm_list, &c->vm_list);
-       new->vm_start = addr;
-       new->vm_end = addr + size;
-       new->vm_active = 1;
-
-       spin_unlock_irqrestore(&consistent_lock, flags);
-       return new;
-
- nospc:
-       spin_unlock_irqrestore(&consistent_lock, flags);
-       kfree(new);
- out:
-       return NULL;
+       split_page(page, order);
+       for (p = page + (size >> PAGE_SHIFT), e = page + (1 << order); p < e; p++)
+               __free_page(p);
+
+       /*
+        * Ensure that the allocated pages are zeroed, and that any data
+        * lurking in the kernel direct-mapped region is invalidated.
+        */
+       ptr = page_address(page);
+       memset(ptr, 0, size);
+       dmac_flush_range(ptr, ptr + size);
+       outer_flush_range(__pa(ptr), __pa(ptr) + size);
+
+       return page;
 }
 
-static struct arm_vm_region *arm_vm_region_find(struct arm_vm_region *head, unsigned long addr)
+/*
+ * Free a DMA buffer.  'size' must be page aligned.
+ */
+static void __dma_free_buffer(struct page *page, size_t size)
 {
-       struct arm_vm_region *c;
-       
-       list_for_each_entry(c, &head->vm_list, vm_list) {
-               if (c->vm_active && c->vm_start == addr)
-                       goto out;
+       struct page *e = page + (size >> PAGE_SHIFT);
+
+       while (page < e) {
+               __free_page(page);
+               page++;
        }
-       c = NULL;
- out:
-       return c;
 }
 
+#ifdef CONFIG_MMU
+/*
+ * These are the page tables (2MB each) covering uncached, DMA consistent allocations
+ */
+static pte_t *consistent_pte[NUM_CONSISTENT_PTES];
+
+#include "vmregion.h"
+
+static struct arm_vmregion_head consistent_head = {
+       .vm_lock        = __SPIN_LOCK_UNLOCKED(&consistent_head.vm_lock),
+       .vm_list        = LIST_HEAD_INIT(consistent_head.vm_list),
+       .vm_start       = CONSISTENT_BASE,
+       .vm_end         = CONSISTENT_END,
+};
+
 #ifdef CONFIG_HUGETLB_PAGE
 #error ARM Coherent DMA allocator does not (yet) support huge TLB
 #endif
 
-static void *
-__dma_alloc(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp,
-           pgprot_t prot)
+/*
+ * Initialise the consistent memory allocation.
+ */
+static int __init consistent_init(void)
 {
-       struct page *page;
-       struct arm_vm_region *c;
-       unsigned long order;
-       u64 mask = get_coherent_dma_mask(dev);
-       u64 limit;
+       int ret = 0;
+       pgd_t *pgd;
+       pmd_t *pmd;
+       pte_t *pte;
+       int i = 0;
+       u32 base = CONSISTENT_BASE;
 
-       if (!consistent_pte[0]) {
-               printk(KERN_ERR "%s: not initialised\n", __func__);
-               dump_stack();
-               return NULL;
-       }
+       do {
+               pgd = pgd_offset(&init_mm, base);
+               pmd = pmd_alloc(&init_mm, pgd, base);
+               if (!pmd) {
+                       printk(KERN_ERR "%s: no pmd tables\n", __func__);
+                       ret = -ENOMEM;
+                       break;
+               }
+               WARN_ON(!pmd_none(*pmd));
 
-       if (!mask)
-               goto no_page;
+               pte = pte_alloc_kernel(pmd, base);
+               if (!pte) {
+                       printk(KERN_ERR "%s: no pte tables\n", __func__);
+                       ret = -ENOMEM;
+                       break;
+               }
 
-       /*
-        * Sanity check the allocation size.
-        */
-       size = PAGE_ALIGN(size);
-       limit = (mask + 1) & ~mask;
-       if ((limit && size >= limit) ||
-           size >= (CONSISTENT_END - CONSISTENT_BASE)) {
-               printk(KERN_WARNING "coherent allocation too big "
-                      "(requested %#x mask %#llx)\n", size, mask);
-               goto no_page;
-       }
+               consistent_pte[i++] = pte;
+               base += (1 << PGDIR_SHIFT);
+       } while (base < CONSISTENT_END);
 
-       order = get_order(size);
+       return ret;
+}
 
-       if (mask < 0xffffffffULL)
-               gfp |= GFP_DMA;
+core_initcall(consistent_init);
 
-       page = alloc_pages(gfp, order);
-       if (!page)
-               goto no_page;
+static void *
+__dma_alloc_remap(struct page *page, size_t size, gfp_t gfp, pgprot_t prot)
+{
+       struct arm_vmregion *c;
 
-       /*
-        * Invalidate any data that might be lurking in the
-        * kernel direct-mapped region for device DMA.
-        */
-       {
-               void *ptr = page_address(page);
-               memset(ptr, 0, size);
-               dmac_flush_range(ptr, ptr + size);
-               outer_flush_range(__pa(ptr), __pa(ptr) + size);
+       if (!consistent_pte[0]) {
+               printk(KERN_ERR "%s: not initialised\n", __func__);
+               dump_stack();
+               return NULL;
        }
 
        /*
         * Allocate a virtual address in the consistent mapping region.
         */
-       c = arm_vm_region_alloc(&consistent_head, size,
+       c = arm_vmregion_alloc(&consistent_head, size,
                            gfp & ~(__GFP_DMA | __GFP_HIGHMEM));
        if (c) {
                pte_t *pte;
-               struct page *end = page + (1 << order);
                int idx = CONSISTENT_PTE_INDEX(c->vm_start);
                u32 off = CONSISTENT_OFFSET(c->vm_start) & (PTRS_PER_PTE-1);
 
                pte = consistent_pte[idx] + off;
                c->vm_pages = page;
 
-               split_page(page, order);
-
-               /*
-                * Set the "dma handle"
-                */
-               *handle = page_to_dma(dev, page);
-
                do {
                        BUG_ON(!pte_none(*pte));
 
-                       /*
-                        * x86 does not mark the pages reserved...
-                        */
-                       SetPageReserved(page);
                        set_pte_ext(pte, mk_pte(page, prot), 0);
                        page++;
                        pte++;
@@ -261,48 +219,90 @@ __dma_alloc(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp,
                        }
                } while (size -= PAGE_SIZE);
 
-               /*
-                * Free the otherwise unused pages.
-                */
-               while (page < end) {
-                       __free_page(page);
-                       page++;
-               }
-
                return (void *)c->vm_start;
        }
-
-       if (page)
-               __free_pages(page, order);
- no_page:
-       *handle = ~0;
        return NULL;
 }
+
+static void __dma_free_remap(void *cpu_addr, size_t size)
+{
+       struct arm_vmregion *c;
+       unsigned long addr;
+       pte_t *ptep;
+       int idx;
+       u32 off;
+
+       c = arm_vmregion_find_remove(&consistent_head, (unsigned long)cpu_addr);
+       if (!c) {
+               printk(KERN_ERR "%s: trying to free invalid coherent area: %p\n",
+                      __func__, cpu_addr);
+               dump_stack();
+               return;
+       }
+
+       if ((c->vm_end - c->vm_start) != size) {
+               printk(KERN_ERR "%s: freeing wrong coherent size (%ld != %d)\n",
+                      __func__, c->vm_end - c->vm_start, size);
+               dump_stack();
+               size = c->vm_end - c->vm_start;
+       }
+
+       idx = CONSISTENT_PTE_INDEX(c->vm_start);
+       off = CONSISTENT_OFFSET(c->vm_start) & (PTRS_PER_PTE-1);
+       ptep = consistent_pte[idx] + off;
+       addr = c->vm_start;
+       do {
+               pte_t pte = ptep_get_and_clear(&init_mm, addr, ptep);
+
+               ptep++;
+               addr += PAGE_SIZE;
+               off++;
+               if (off >= PTRS_PER_PTE) {
+                       off = 0;
+                       ptep = consistent_pte[++idx];
+               }
+
+               if (pte_none(pte) || !pte_present(pte))
+                       printk(KERN_CRIT "%s: bad page in kernel page table\n",
+                              __func__);
+       } while (size -= PAGE_SIZE);
+
+       flush_tlb_kernel_range(c->vm_start, c->vm_end);
+
+       arm_vmregion_free(&consistent_head, c);
+}
+
 #else  /* !CONFIG_MMU */
+
+#define __dma_alloc_remap(page, size, gfp, prot)       page_address(page)
+#define __dma_free_remap(addr, size)                   do { } while (0)
+
+#endif /* CONFIG_MMU */
+
 static void *
 __dma_alloc(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp,
            pgprot_t prot)
 {
-       void *virt;
-       u64 mask = get_coherent_dma_mask(dev);
+       struct page *page;
+       void *addr;
 
-       if (!mask)
-               goto error;
+       *handle = ~0;
+       size = PAGE_ALIGN(size);
 
-       if (mask < 0xffffffffULL)
-               gfp |= GFP_DMA;
-       virt = kmalloc(size, gfp);
-       if (!virt)
-               goto error;
+       page = __dma_alloc_buffer(dev, size, gfp);
+       if (!page)
+               return NULL;
 
-       *handle =  virt_to_dma(dev, virt);
-       return virt;
+       if (!arch_is_coherent())
+               addr = __dma_alloc_remap(page, size, gfp, prot);
+       else
+               addr = page_address(page);
 
-error:
-       *handle = ~0;
-       return NULL;
+       if (addr)
+               *handle = page_to_dma(dev, page);
+
+       return addr;
 }
-#endif /* CONFIG_MMU */
 
 /*
  * Allocate DMA-coherent memory space and return both the kernel remapped
@@ -316,19 +316,8 @@ dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gf
        if (dma_alloc_from_coherent(dev, size, handle, &memory))
                return memory;
 
-       if (arch_is_coherent()) {
-               void *virt;
-
-               virt = kmalloc(size, gfp);
-               if (!virt)
-                       return NULL;
-               *handle =  virt_to_dma(dev, virt);
-
-               return virt;
-       }
-
        return __dma_alloc(dev, size, handle, gfp,
-                          pgprot_noncached(pgprot_kernel));
+                          pgprot_dmacoherent(pgprot_kernel));
 }
 EXPORT_SYMBOL(dma_alloc_coherent);
 
@@ -349,15 +338,12 @@ static int dma_mmap(struct device *dev, struct vm_area_struct *vma,
 {
        int ret = -ENXIO;
 #ifdef CONFIG_MMU
-       unsigned long flags, user_size, kern_size;
-       struct arm_vm_region *c;
+       unsigned long user_size, kern_size;
+       struct arm_vmregion *c;
 
        user_size = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
 
-       spin_lock_irqsave(&consistent_lock, flags);
-       c = arm_vm_region_find(&consistent_head, (unsigned long)cpu_addr);
-       spin_unlock_irqrestore(&consistent_lock, flags);
-
+       c = arm_vmregion_find(&consistent_head, (unsigned long)cpu_addr);
        if (c) {
                unsigned long off = vma->vm_pgoff;
 
@@ -379,7 +365,7 @@ static int dma_mmap(struct device *dev, struct vm_area_struct *vma,
 int dma_mmap_coherent(struct device *dev, struct vm_area_struct *vma,
                      void *cpu_addr, dma_addr_t dma_addr, size_t size)
 {
-       vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+       vma->vm_page_prot = pgprot_dmacoherent(vma->vm_page_prot);
        return dma_mmap(dev, vma, cpu_addr, dma_addr, size);
 }
 EXPORT_SYMBOL(dma_mmap_coherent);
@@ -396,144 +382,23 @@ EXPORT_SYMBOL(dma_mmap_writecombine);
  * free a page as defined by the above mapping.
  * Must not be called with IRQs disabled.
  */
-#ifdef CONFIG_MMU
 void dma_free_coherent(struct device *dev, size_t size, void *cpu_addr, dma_addr_t handle)
 {
-       struct arm_vm_region *c;
-       unsigned long flags, addr;
-       pte_t *ptep;
-       int idx;
-       u32 off;
-
        WARN_ON(irqs_disabled());
 
        if (dma_release_from_coherent(dev, get_order(size), cpu_addr))
                return;
 
-       if (arch_is_coherent()) {
-               kfree(cpu_addr);
-               return;
-       }
-
        size = PAGE_ALIGN(size);
 
-       spin_lock_irqsave(&consistent_lock, flags);
-       c = arm_vm_region_find(&consistent_head, (unsigned long)cpu_addr);
-       if (!c)
-               goto no_area;
-
-       c->vm_active = 0;
-       spin_unlock_irqrestore(&consistent_lock, flags);
-
-       if ((c->vm_end - c->vm_start) != size) {
-               printk(KERN_ERR "%s: freeing wrong coherent size (%ld != %d)\n",
-                      __func__, c->vm_end - c->vm_start, size);
-               dump_stack();
-               size = c->vm_end - c->vm_start;
-       }
-
-       idx = CONSISTENT_PTE_INDEX(c->vm_start);
-       off = CONSISTENT_OFFSET(c->vm_start) & (PTRS_PER_PTE-1);
-       ptep = consistent_pte[idx] + off;
-       addr = c->vm_start;
-       do {
-               pte_t pte = ptep_get_and_clear(&init_mm, addr, ptep);
-               unsigned long pfn;
-
-               ptep++;
-               addr += PAGE_SIZE;
-               off++;
-               if (off >= PTRS_PER_PTE) {
-                       off = 0;
-                       ptep = consistent_pte[++idx];
-               }
-
-               if (!pte_none(pte) && pte_present(pte)) {
-                       pfn = pte_pfn(pte);
-
-                       if (pfn_valid(pfn)) {
-                               struct page *page = pfn_to_page(pfn);
-
-                               /*
-                                * x86 does not mark the pages reserved...
-                                */
-                               ClearPageReserved(page);
-
-                               __free_page(page);
-                               continue;
-                       }
-               }
-
-               printk(KERN_CRIT "%s: bad page in kernel page table\n",
-                      __func__);
-       } while (size -= PAGE_SIZE);
-
-       flush_tlb_kernel_range(c->vm_start, c->vm_end);
-
-       spin_lock_irqsave(&consistent_lock, flags);
-       list_del(&c->vm_list);
-       spin_unlock_irqrestore(&consistent_lock, flags);
-
-       kfree(c);
-       return;
+       if (!arch_is_coherent())
+               __dma_free_remap(cpu_addr, size);
 
- no_area:
-       spin_unlock_irqrestore(&consistent_lock, flags);
-       printk(KERN_ERR "%s: trying to free invalid coherent area: %p\n",
-              __func__, cpu_addr);
-       dump_stack();
+       __dma_free_buffer(dma_to_page(dev, handle), size);
 }
-#else  /* !CONFIG_MMU */
-void dma_free_coherent(struct device *dev, size_t size, void *cpu_addr, dma_addr_t handle)
-{
-       if (dma_release_from_coherent(dev, get_order(size), cpu_addr))
-               return;
-       kfree(cpu_addr);
-}
-#endif /* CONFIG_MMU */
 EXPORT_SYMBOL(dma_free_coherent);
 
 /*
- * Initialise the consistent memory allocation.
- */
-static int __init consistent_init(void)
-{
-       int ret = 0;
-#ifdef CONFIG_MMU
-       pgd_t *pgd;
-       pmd_t *pmd;
-       pte_t *pte;
-       int i = 0;
-       u32 base = CONSISTENT_BASE;
-
-       do {
-               pgd = pgd_offset(&init_mm, base);
-               pmd = pmd_alloc(&init_mm, pgd, base);
-               if (!pmd) {
-                       printk(KERN_ERR "%s: no pmd tables\n", __func__);
-                       ret = -ENOMEM;
-                       break;
-               }
-               WARN_ON(!pmd_none(*pmd));
-
-               pte = pte_alloc_kernel(pmd, base);
-               if (!pte) {
-                       printk(KERN_ERR "%s: no pte tables\n", __func__);
-                       ret = -ENOMEM;
-                       break;
-               }
-
-               consistent_pte[i++] = pte;
-               base += (1 << PGDIR_SHIFT);
-       } while (base < CONSISTENT_END);
-#endif /* !CONFIG_MMU */
-
-       return ret;
-}
-
-core_initcall(consistent_init);
-
-/*
  * Make an area consistent for devices.
  * Note: Drivers should NOT use this function directly, as it will break
  * platforms with CONFIG_DMABOUNCE.
index d0d17b6..7296022 100644 (file)
@@ -23,6 +23,8 @@
 #include <asm/pgtable.h>
 #include <asm/tlbflush.h>
 
+#include "mm.h"
+
 static unsigned long shared_pte_mask = L_PTE_MT_BUFFERABLE;
 
 /*
@@ -151,7 +153,14 @@ void update_mmu_cache(struct vm_area_struct *vma, unsigned long addr, pte_t pte)
        if (!pfn_valid(pfn))
                return;
 
+       /*
+        * The zero page is never written to, so never has any dirty
+        * cache lines, and therefore never needs to be flushed.
+        */
        page = pfn_to_page(pfn);
+       if (page == ZERO_PAGE(0))
+               return;
+
        mapping = page_mapping(page);
 #ifndef CONFIG_SMP
        if (test_and_clear_bit(PG_dcache_dirty, &page->flags))
index 7f294f3..329594e 100644 (file)
@@ -35,14 +35,12 @@ static void flush_pfn_alias(unsigned long pfn, unsigned long vaddr)
            :
            : "r" (to), "r" (to + PAGE_SIZE - L1_CACHE_BYTES), "r" (zero)
            : "cc");
-       __flush_icache_all();
 }
 
 void flush_cache_mm(struct mm_struct *mm)
 {
        if (cache_is_vivt()) {
-               if (cpumask_test_cpu(smp_processor_id(), mm_cpumask(mm)))
-                       __cpuc_flush_user_all();
+               vivt_flush_cache_mm(mm);
                return;
        }
 
@@ -52,16 +50,13 @@ void flush_cache_mm(struct mm_struct *mm)
                    :
                    : "r" (0)
                    : "cc");
-               __flush_icache_all();
        }
 }
 
 void flush_cache_range(struct vm_area_struct *vma, unsigned long start, unsigned long end)
 {
        if (cache_is_vivt()) {
-               if (cpumask_test_cpu(smp_processor_id(), mm_cpumask(vma->vm_mm)))
-                       __cpuc_flush_user_range(start & PAGE_MASK, PAGE_ALIGN(end),
-                                               vma->vm_flags);
+               vivt_flush_cache_range(vma, start, end);
                return;
        }
 
@@ -71,22 +66,26 @@ void flush_cache_range(struct vm_area_struct *vma, unsigned long start, unsigned
                    :
                    : "r" (0)
                    : "cc");
-               __flush_icache_all();
        }
+
+       if (vma->vm_flags & VM_EXEC)
+               __flush_icache_all();
 }
 
 void flush_cache_page(struct vm_area_struct *vma, unsigned long user_addr, unsigned long pfn)
 {
        if (cache_is_vivt()) {
-               if (cpumask_test_cpu(smp_processor_id(), mm_cpumask(vma->vm_mm))) {
-                       unsigned long addr = user_addr & PAGE_MASK;
-                       __cpuc_flush_user_range(addr, addr + PAGE_SIZE, vma->vm_flags);
-               }
+               vivt_flush_cache_page(vma, user_addr, pfn);
                return;
        }
 
-       if (cache_is_vipt_aliasing())
+       if (cache_is_vipt_aliasing()) {
                flush_pfn_alias(pfn, user_addr);
+               __flush_icache_all();
+       }
+
+       if (vma->vm_flags & VM_EXEC && icache_is_vivt_asid_tagged())
+               __flush_icache_all();
 }
 
 void flush_ptrace_access(struct vm_area_struct *vma, struct page *page,
@@ -94,15 +93,13 @@ void flush_ptrace_access(struct vm_area_struct *vma, struct page *page,
                         unsigned long len, int write)
 {
        if (cache_is_vivt()) {
-               if (cpumask_test_cpu(smp_processor_id(), mm_cpumask(vma->vm_mm))) {
-                       unsigned long addr = (unsigned long)kaddr;
-                       __cpuc_coherent_kern_range(addr, addr + len);
-               }
+               vivt_flush_ptrace_access(vma, page, uaddr, kaddr, len, write);
                return;
        }
 
        if (cache_is_vipt_aliasing()) {
                flush_pfn_alias(page_to_pfn(page), uaddr);
+               __flush_icache_all();
                return;
        }
 
@@ -120,6 +117,8 @@ void flush_ptrace_access(struct vm_area_struct *vma, struct page *page,
 
 void __flush_dcache_page(struct address_space *mapping, struct page *page)
 {
+       void *addr = page_address(page);
+
        /*
         * Writeback any data associated with the kernel mapping of this
         * page.  This ensures that data in the physical page is mutually
@@ -130,9 +129,9 @@ void __flush_dcache_page(struct address_space *mapping, struct page *page)
         * kmap_atomic() doesn't set the page virtual address, and
         * kunmap_atomic() takes care of cache flushing already.
         */
-       if (page_address(page))
+       if (addr)
 #endif
-               __cpuc_flush_dcache_page(page_address(page));
+               __cpuc_flush_dcache_page(addr);
 
        /*
         * If this is a page cache page, and we have an aliasing VIPT cache,
@@ -196,7 +195,16 @@ static void __flush_dcache_aliases(struct address_space *mapping, struct page *p
  */
 void flush_dcache_page(struct page *page)
 {
-       struct address_space *mapping = page_mapping(page);
+       struct address_space *mapping;
+
+       /*
+        * The zero page is never written to, so never has any dirty
+        * cache lines, and therefore never needs to be flushed.
+        */
+       if (page == ZERO_PAGE(0))
+               return;
+
+       mapping = page_mapping(page);
 
 #ifndef CONFIG_SMP
        if (!PageHighMem(page) && mapping && !mapping_mapped(mapping))
@@ -242,6 +250,7 @@ void __flush_anon_page(struct vm_area_struct *vma, struct page *page, unsigned l
                 * userspace address only.
                 */
                flush_pfn_alias(pfn, vmaddr);
+               __flush_icache_all();
        }
 
        /*
index c4f6f05..a888363 100644 (file)
@@ -24,6 +24,8 @@ struct mem_type {
 
 const struct mem_type *get_mem_type(unsigned int type);
 
+extern void __flush_dcache_page(struct address_space *mapping, struct page *page);
+
 #endif
 
 struct map_desc;
index ea67be0..8c7fbd1 100644 (file)
@@ -881,7 +881,7 @@ void __init reserve_node_zero(pg_data_t *pgdat)
                                BOOTMEM_EXCLUSIVE);
        }
 
-       if (machine_is_treo680()) {
+       if (machine_is_treo680() || machine_is_centro()) {
                reserve_bootmem_node(pgdat, 0xa0000000, 0x1000,
                                BOOTMEM_EXCLUSIVE);
                reserve_bootmem_node(pgdat, 0xa2000000, 0x1000,
@@ -1036,7 +1036,7 @@ void __init paging_init(struct machine_desc *mdesc)
         */
        zero_page = alloc_bootmem_low_pages(PAGE_SIZE);
        empty_zero_page = virt_to_page(zero_page);
-       flush_dcache_page(empty_zero_page);
+       __flush_dcache_page(NULL, empty_zero_page);
 }
 
 /*
index 70f75d2..5485c82 100644 (file)
@@ -130,9 +130,16 @@ ENTRY(cpu_v6_set_pte_ext)
 
 
 
-
+       .type   cpu_v6_name, #object
 cpu_v6_name:
        .asciz  "ARMv6-compatible processor"
+       .size   cpu_v6_name, . - cpu_v6_name
+
+       .type   cpu_pj4_name, #object
+cpu_pj4_name:
+       .asciz  "Marvell PJ4 processor"
+       .size   cpu_pj4_name, . - cpu_pj4_name
+
        .align
 
        __INIT
@@ -241,3 +248,27 @@ __v6_proc_info:
        .long   v6_user_fns
        .long   v6_cache_fns
        .size   __v6_proc_info, . - __v6_proc_info
+
+       .type   __pj4_v6_proc_info, #object
+__pj4_v6_proc_info:
+       .long   0x560f5810
+       .long   0xff0ffff0
+       .long   PMD_TYPE_SECT | \
+               PMD_SECT_BUFFERABLE | \
+               PMD_SECT_CACHEABLE | \
+               PMD_SECT_AP_WRITE | \
+               PMD_SECT_AP_READ
+       .long   PMD_TYPE_SECT | \
+               PMD_SECT_XN | \
+               PMD_SECT_AP_WRITE | \
+               PMD_SECT_AP_READ
+       b       __v6_setup
+       .long   cpu_arch_name
+       .long   cpu_elf_name
+       .long   HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP
+       .long   cpu_pj4_name
+       .long   v6_processor_functions
+       .long   v6wbi_tlb_fns
+       .long   v6_user_fns
+       .long   v6_cache_fns
+       .size   __pj4_v6_proc_info, . - __pj4_v6_proc_info
index 2028f37..fab134e 100644 (file)
@@ -396,7 +396,7 @@ __xsc3_setup:
        orr     r4, r4, #0x18                   @ cache the page table in L2
        mcr     p15, 0, r4, c2, c0, 0           @ load page table pointer
 
-       mov     r0, #0                          @ don't allow CP access
+       mov     r0, #1 << 6                     @ cp6 access for early sched_clock
        mcr     p15, 0, r0, c15, c1, 0          @ write CP access register
 
        mrc     p15, 0, r0, c1, c0, 1           @ get auxiliary control reg
diff --git a/arch/arm/mm/vmregion.c b/arch/arm/mm/vmregion.c
new file mode 100644 (file)
index 0000000..19e09bd
--- /dev/null
@@ -0,0 +1,131 @@
+#include <linux/spinlock.h>
+#include <linux/list.h>
+#include <linux/slab.h>
+
+#include "vmregion.h"
+
+/*
+ * VM region handling support.
+ *
+ * This should become something generic, handling VM region allocations for
+ * vmalloc and similar (ioremap, module space, etc).
+ *
+ * I envisage vmalloc()'s supporting vm_struct becoming:
+ *
+ *  struct vm_struct {
+ *    struct vmregion  region;
+ *    unsigned long    flags;
+ *    struct page      **pages;
+ *    unsigned int     nr_pages;
+ *    unsigned long    phys_addr;
+ *  };
+ *
+ * get_vm_area() would then call vmregion_alloc with an appropriate
+ * struct vmregion head (eg):
+ *
+ *  struct vmregion vmalloc_head = {
+ *     .vm_list        = LIST_HEAD_INIT(vmalloc_head.vm_list),
+ *     .vm_start       = VMALLOC_START,
+ *     .vm_end         = VMALLOC_END,
+ *  };
+ *
+ * However, vmalloc_head.vm_start is variable (typically, it is dependent on
+ * the amount of RAM found at boot time.)  I would imagine that get_vm_area()
+ * would have to initialise this each time prior to calling vmregion_alloc().
+ */
+
+struct arm_vmregion *
+arm_vmregion_alloc(struct arm_vmregion_head *head, size_t size, gfp_t gfp)
+{
+       unsigned long addr = head->vm_start, end = head->vm_end - size;
+       unsigned long flags;
+       struct arm_vmregion *c, *new;
+
+       if (head->vm_end - head->vm_start < size) {
+               printk(KERN_WARNING "%s: allocation too big (requested %#x)\n",
+                       __func__, size);
+               goto out;
+       }
+
+       new = kmalloc(sizeof(struct arm_vmregion), gfp);
+       if (!new)
+               goto out;
+
+       spin_lock_irqsave(&head->vm_lock, flags);
+
+       list_for_each_entry(c, &head->vm_list, vm_list) {
+               if ((addr + size) < addr)
+                       goto nospc;
+               if ((addr + size) <= c->vm_start)
+                       goto found;
+               addr = c->vm_end;
+               if (addr > end)
+                       goto nospc;
+       }
+
+ found:
+       /*
+        * Insert this entry _before_ the one we found.
+        */
+       list_add_tail(&new->vm_list, &c->vm_list);
+       new->vm_start = addr;
+       new->vm_end = addr + size;
+       new->vm_active = 1;
+
+       spin_unlock_irqrestore(&head->vm_lock, flags);
+       return new;
+
+ nospc:
+       spin_unlock_irqrestore(&head->vm_lock, flags);
+       kfree(new);
+ out:
+       return NULL;
+}
+
+static struct arm_vmregion *__arm_vmregion_find(struct arm_vmregion_head *head, unsigned long addr)
+{
+       struct arm_vmregion *c;
+
+       list_for_each_entry(c, &head->vm_list, vm_list) {
+               if (c->vm_active && c->vm_start == addr)
+                       goto out;
+       }
+       c = NULL;
+ out:
+       return c;
+}
+
+struct arm_vmregion *arm_vmregion_find(struct arm_vmregion_head *head, unsigned long addr)
+{
+       struct arm_vmregion *c;
+       unsigned long flags;
+
+       spin_lock_irqsave(&head->vm_lock, flags);
+       c = __arm_vmregion_find(head, addr);
+       spin_unlock_irqrestore(&head->vm_lock, flags);
+       return c;
+}
+
+struct arm_vmregion *arm_vmregion_find_remove(struct arm_vmregion_head *head, unsigned long addr)
+{
+       struct arm_vmregion *c;
+       unsigned long flags;
+
+       spin_lock_irqsave(&head->vm_lock, flags);
+       c = __arm_vmregion_find(head, addr);
+       if (c)
+               c->vm_active = 0;
+       spin_unlock_irqrestore(&head->vm_lock, flags);
+       return c;
+}
+
+void arm_vmregion_free(struct arm_vmregion_head *head, struct arm_vmregion *c)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&head->vm_lock, flags);
+       list_del(&c->vm_list);
+       spin_unlock_irqrestore(&head->vm_lock, flags);
+
+       kfree(c);
+}
diff --git a/arch/arm/mm/vmregion.h b/arch/arm/mm/vmregion.h
new file mode 100644 (file)
index 0000000..6b2cdbd
--- /dev/null
@@ -0,0 +1,29 @@
+#ifndef VMREGION_H
+#define VMREGION_H
+
+#include <linux/spinlock.h>
+#include <linux/list.h>
+
+struct page;
+
+struct arm_vmregion_head {
+       spinlock_t              vm_lock;
+       struct list_head        vm_list;
+       unsigned long           vm_start;
+       unsigned long           vm_end;
+};
+
+struct arm_vmregion {
+       struct list_head        vm_list;
+       unsigned long           vm_start;
+       unsigned long           vm_end;
+       struct page             *vm_pages;
+       int                     vm_active;
+};
+
+struct arm_vmregion *arm_vmregion_alloc(struct arm_vmregion_head *, size_t, gfp_t);
+struct arm_vmregion *arm_vmregion_find(struct arm_vmregion_head *, unsigned long);
+struct arm_vmregion *arm_vmregion_find_remove(struct arm_vmregion_head *, unsigned long);
+void arm_vmregion_free(struct arm_vmregion_head *, struct arm_vmregion *);
+
+#endif
index 8da95d5..6c8a02a 100644 (file)
@@ -19,6 +19,8 @@
 #include <linux/init.h>
 #include <linux/timex.h>
 #include <linux/io.h>
+#include <linux/clocksource.h>
+#include <linux/clockchips.h>
 #include <mach/hardware.h>
 #include <asm/irq.h>
 #include <asm/uaccess.h>
 #include <asm/mach/time.h>
 #include <mach/time.h>
 
+/*
+ * IOP clocksource (free-running timer 1).
+ */
+static cycle_t iop_clocksource_read(struct clocksource *unused)
+{
+       return 0xffffffffu - read_tcr1();
+}
+
+static struct clocksource iop_clocksource = {
+       .name           = "iop_timer1",
+       .rating         = 300,
+       .read           = iop_clocksource_read,
+       .mask           = CLOCKSOURCE_MASK(32),
+       .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
+};
+
+static void __init iop_clocksource_set_hz(struct clocksource *cs, unsigned int hz)
+{
+       u64 temp;
+       u32 shift;
+
+       /* Find shift and mult values for hz. */
+       shift = 32;
+       do {
+               temp = (u64) NSEC_PER_SEC << shift;
+               do_div(temp, hz);
+               if ((temp >> 32) == 0)
+                       break;
+       } while (--shift != 0);
+
+       cs->shift = shift;
+       cs->mult = (u32) temp;
+
+       printk(KERN_INFO "clocksource: %s uses shift %u mult %#x\n",
+              cs->name, cs->shift, cs->mult);
+}
+
+/*
+ * IOP sched_clock() implementation via its clocksource.
+ */
+unsigned long long sched_clock(void)
+{
+       cycle_t cyc = iop_clocksource_read(NULL);
+       struct clocksource *cs = &iop_clocksource;
+
+       return clocksource_cyc2ns(cyc, cs->mult, cs->shift);
+}
+
+/*
+ * IOP clockevents (interrupting timer 0).
+ */
+static int iop_set_next_event(unsigned long delta,
+                             struct clock_event_device *unused)
+{
+       u32 tmr = IOP_TMR_PRIVILEGED | IOP_TMR_RATIO_1_1;
+
+       BUG_ON(delta == 0);
+       write_tmr0(tmr & ~(IOP_TMR_EN | IOP_TMR_RELOAD));
+       write_tcr0(delta);
+       write_tmr0((tmr & ~IOP_TMR_RELOAD) | IOP_TMR_EN);
+
+       return 0;
+}
+
 static unsigned long ticks_per_jiffy;
-static unsigned long ticks_per_usec;
-static unsigned long next_jiffy_time;
 
-unsigned long iop_gettimeoffset(void)
+static void iop_set_mode(enum clock_event_mode mode,
+                        struct clock_event_device *unused)
 {
-       unsigned long offset, temp;
+       u32 tmr = read_tmr0();
+
+       switch (mode) {
+       case CLOCK_EVT_MODE_PERIODIC:
+               write_tmr0(tmr & ~IOP_TMR_EN);
+               write_tcr0(ticks_per_jiffy - 1);
+               tmr |= (IOP_TMR_RELOAD | IOP_TMR_EN);
+               break;
+       case CLOCK_EVT_MODE_ONESHOT:
+               /* ->set_next_event sets period and enables timer */
+               tmr &= ~(IOP_TMR_RELOAD | IOP_TMR_EN);
+               break;
+       case CLOCK_EVT_MODE_RESUME:
+               tmr |= IOP_TMR_EN;
+               break;
+       case CLOCK_EVT_MODE_SHUTDOWN:
+       case CLOCK_EVT_MODE_UNUSED:
+       default:
+               tmr &= ~IOP_TMR_EN;
+               break;
+       }
 
-       /* enable cp6, if necessary, to avoid taking the overhead of an
-        * undefined instruction trap
-        */
-       asm volatile (
-       "mrc    p15, 0, %0, c15, c1, 0\n\t"
-       "tst    %0, #(1 << 6)\n\t"
-       "orreq  %0, %0, #(1 << 6)\n\t"
-       "mcreq  p15, 0, %0, c15, c1, 0\n\t"
-#ifdef CONFIG_CPU_XSCALE
-       "mrceq  p15, 0, %0, c15, c1, 0\n\t"
-       "moveq  %0, %0\n\t"
-       "subeq  pc, pc, #4\n\t"
-#endif
-       : "=r"(temp) : : "cc");
-
-       offset = next_jiffy_time - read_tcr1();
-
-       return offset / ticks_per_usec;
+       write_tmr0(tmr);
+}
+
+static struct clock_event_device iop_clockevent = {
+       .name           = "iop_timer0",
+       .features       = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
+       .rating         = 300,
+       .set_next_event = iop_set_next_event,
+       .set_mode       = iop_set_mode,
+};
+
+static void __init iop_clockevent_set_hz(struct clock_event_device *ce, unsigned int hz)
+{
+       u64 temp;
+       u32 shift;
+
+       /* Find shift and mult values for hz. */
+       shift = 32;
+       do {
+               temp = (u64) hz << shift;
+               do_div(temp, NSEC_PER_SEC);
+               if ((temp >> 32) == 0)
+                       break;
+       } while (--shift != 0);
+
+       ce->shift = shift;
+       ce->mult = (u32) temp;
+
+       printk(KERN_INFO "clockevent: %s uses shift %u mult %#lx\n",
+              ce->name, ce->shift, ce->mult);
 }
 
 static irqreturn_t
 iop_timer_interrupt(int irq, void *dev_id)
 {
-       write_tisr(1);
-
-       while ((signed long)(next_jiffy_time - read_tcr1())
-               >= ticks_per_jiffy) {
-               timer_tick();
-               next_jiffy_time -= ticks_per_jiffy;
-       }
+       struct clock_event_device *evt = dev_id;
 
+       write_tisr(1);
+       evt->event_handler(evt);
        return IRQ_HANDLED;
 }
 
@@ -72,6 +165,7 @@ static struct irqaction iop_timer_irq = {
        .name           = "IOP Timer Tick",
        .handler        = iop_timer_interrupt,
        .flags          = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
+       .dev_id         = &iop_clockevent,
 };
 
 static unsigned long iop_tick_rate;
@@ -86,21 +180,33 @@ void __init iop_init_time(unsigned long tick_rate)
        u32 timer_ctl;
 
        ticks_per_jiffy = DIV_ROUND_CLOSEST(tick_rate, HZ);
-       ticks_per_usec = tick_rate / 1000000;
-       next_jiffy_time = 0xffffffff;
        iop_tick_rate = tick_rate;
 
        timer_ctl = IOP_TMR_EN | IOP_TMR_PRIVILEGED |
                        IOP_TMR_RELOAD | IOP_TMR_RATIO_1_1;
 
        /*
-        * We use timer 0 for our timer interrupt, and timer 1 as
-        * monotonic counter for tracking missed jiffies.
+        * Set up interrupting clockevent timer 0.
         */
+       write_tmr0(timer_ctl & ~IOP_TMR_EN);
+       setup_irq(IRQ_IOP_TIMER0, &iop_timer_irq);
+       iop_clockevent_set_hz(&iop_clockevent, tick_rate);
+       iop_clockevent.max_delta_ns =
+               clockevent_delta2ns(0xfffffffe, &iop_clockevent);
+       iop_clockevent.min_delta_ns =
+               clockevent_delta2ns(0xf, &iop_clockevent);
+       iop_clockevent.cpumask = cpumask_of(0);
+       clockevents_register_device(&iop_clockevent);
        write_trr0(ticks_per_jiffy - 1);
+       write_tcr0(ticks_per_jiffy - 1);
        write_tmr0(timer_ctl);
+
+       /*
+        * Set up free-running clocksource timer 1.
+        */
        write_trr1(0xffffffff);
+       write_tcr1(0xffffffff);
        write_tmr1(timer_ctl);
-
-       setup_irq(IRQ_IOP_TIMER0, &iop_timer_irq);
+       iop_clocksource_set_hz(&iop_clocksource, tick_rate);
+       clocksource_register(&iop_clocksource);
 }
index ca5c7c2..8b0a1ee 100644 (file)
@@ -69,10 +69,20 @@ config MXC_PWM
        help
          Enable support for the i.MX PWM controller(s).
 
+config MXC_ULPI
+       bool
+
 config ARCH_HAS_RNGA
        bool
        depends on ARCH_MXC
 
 config ARCH_MXC_IOMUX_V3
        bool
+
+config ARCH_MXC_AUDMUX_V1
+       bool
+
+config ARCH_MXC_AUDMUX_V2
+       bool
+
 endif
index e3212c8..4cbca9d 100644 (file)
@@ -9,3 +9,6 @@ obj-$(CONFIG_ARCH_MX1) += iomux-mx1-mx2.o dma-mx1-mx2.o
 obj-$(CONFIG_ARCH_MX2) += iomux-mx1-mx2.o dma-mx1-mx2.o
 obj-$(CONFIG_ARCH_MXC_IOMUX_V3) += iomux-v3.o
 obj-$(CONFIG_MXC_PWM)  += pwm.o
+obj-$(CONFIG_MXC_ULPI) += ulpi.o
+obj-$(CONFIG_ARCH_MXC_AUDMUX_V1) += audmux-v1.o
+obj-$(CONFIG_ARCH_MXC_AUDMUX_V2) += audmux-v2.o
diff --git a/arch/arm/plat-mxc/audmux-v1.c b/arch/arm/plat-mxc/audmux-v1.c
new file mode 100644 (file)
index 0000000..da6387d
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2009 Pengutronix, Sascha Hauer <s.hauer@pengutronix.de>
+ *
+ * Initial development of this code was funded by
+ * Phytec Messtechnik GmbH, http://www.phytec.de
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <mach/audmux.h>
+#include <mach/hardware.h>
+
+static void __iomem *audmux_base;
+
+static unsigned char port_mapping[] = {
+       0x0, 0x4, 0x8, 0x10, 0x14, 0x1c,
+};
+
+int mxc_audmux_v1_configure_port(unsigned int port, unsigned int pcr)
+{
+       if (!audmux_base) {
+               printk("%s: not configured\n", __func__);
+               return -ENOSYS;
+       }
+
+       if (port >= ARRAY_SIZE(port_mapping))
+               return -EINVAL;
+
+       writel(pcr, audmux_base + port_mapping[port]);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(mxc_audmux_v1_configure_port);
+
+static int mxc_audmux_v1_init(void)
+{
+       if (cpu_is_mx27() || cpu_is_mx21())
+               audmux_base = IO_ADDRESS(AUDMUX_BASE_ADDR);
+       return 0;
+}
+
+postcore_initcall(mxc_audmux_v1_init);
diff --git a/arch/arm/plat-mxc/audmux-v2.c b/arch/arm/plat-mxc/audmux-v2.c
new file mode 100644 (file)
index 0000000..6f21096
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2009 Pengutronix, Sascha Hauer <s.hauer@pengutronix.de>
+ *
+ * Initial development of this code was funded by
+ * Phytec Messtechnik GmbH, http://www.phytec.de
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <mach/audmux.h>
+#include <mach/hardware.h>
+
+static struct clk *audmux_clk;
+static void __iomem *audmux_base;
+
+#define MXC_AUDMUX_V2_PTCR(x)          ((x) * 8)
+#define MXC_AUDMUX_V2_PDCR(x)          ((x) * 8 + 4)
+
+int mxc_audmux_v2_configure_port(unsigned int port, unsigned int ptcr,
+               unsigned int pdcr)
+{
+       if (!audmux_base)
+               return -ENOSYS;
+
+       if (audmux_clk)
+               clk_enable(audmux_clk);
+
+       writel(ptcr, audmux_base + MXC_AUDMUX_V2_PTCR(port));
+       writel(pdcr, audmux_base + MXC_AUDMUX_V2_PDCR(port));
+
+       if (audmux_clk)
+               clk_disable(audmux_clk);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(mxc_audmux_v2_configure_port);
+
+static int mxc_audmux_v2_init(void)
+{
+       int ret;
+
+       if (cpu_is_mx35()) {
+               audmux_clk = clk_get(NULL, "audmux");
+               if (IS_ERR(audmux_clk)) {
+                       ret = PTR_ERR(audmux_clk);
+                       printk(KERN_ERR "%s: cannot get clock: %d\n", __func__,
+                                       ret);
+                       return ret;
+               }
+       }
+
+       if (cpu_is_mx31() || cpu_is_mx35())
+               audmux_base = IO_ADDRESS(AUDMUX_BASE_ADDR);
+
+       return 0;
+}
+
+postcore_initcall(mxc_audmux_v2_init);
index 7764643..9c1b3f9 100644 (file)
@@ -156,7 +156,8 @@ static inline int imx_dma_sg_next(int channel, struct scatterlist *sg)
        }
 
        now = min(imxdma->resbytes, sg->length);
-       imxdma->resbytes -= now;
+       if (imxdma->resbytes != IMX_DMA_LENGTH_LOOP)
+               imxdma->resbytes -= now;
 
        if ((imxdma->dma_mode & DMA_MODE_MASK) == DMA_MODE_READ)
                __raw_writel(sg->dma_address, DMA_BASE + DMA_DAR(channel));
index cfc4a8b..d65ebe3 100644 (file)
@@ -282,7 +282,7 @@ int __init mxc_gpio_init(struct mxc_gpio_port *port, int cnt)
                for (j = port[i].virtual_irq_start;
                        j < port[i].virtual_irq_start + 32; j++) {
                        set_irq_chip(j, &gpio_irq_chip);
-                       set_irq_handler(j, handle_edge_irq);
+                       set_irq_handler(j, handle_level_irq);
                        set_irq_flags(j, IRQF_VALID);
                }
 
diff --git a/arch/arm/plat-mxc/include/mach/audmux.h b/arch/arm/plat-mxc/include/mach/audmux.h
new file mode 100644 (file)
index 0000000..5cd6466
--- /dev/null
@@ -0,0 +1,52 @@
+#ifndef __MACH_AUDMUX_H
+#define __MACH_AUDMUX_H
+
+#define MX27_AUDMUX_HPCR1_SSI0         0
+#define MX27_AUDMUX_HPCR2_SSI1         1
+#define MX27_AUDMUX_HPCR3_SSI_PINS_4   2
+#define MX27_AUDMUX_PPCR1_SSI_PINS_1   3
+#define MX27_AUDMUX_PPCR2_SSI_PINS_2   4
+#define MX27_AUDMUX_PPCR3_SSI_PINS_3   5
+
+#define MX31_AUDMUX_PORT1_SSI0         0
+#define MX31_AUDMUX_PORT2_SSI1         1
+#define MX31_AUDMUX_PORT3_SSI_PINS_3   2
+#define MX31_AUDMUX_PORT4_SSI_PINS_4   3
+#define MX31_AUDMUX_PORT5_SSI_PINS_5   4
+#define MX31_AUDMUX_PORT6_SSI_PINS_6   5
+
+/* Register definitions for the i.MX21/27 Digital Audio Multiplexer */
+#define MXC_AUDMUX_V1_PCR_INMMASK(x)   ((x) & 0xff)
+#define MXC_AUDMUX_V1_PCR_INMEN                (1 << 8)
+#define MXC_AUDMUX_V1_PCR_TXRXEN       (1 << 10)
+#define MXC_AUDMUX_V1_PCR_SYN          (1 << 12)
+#define MXC_AUDMUX_V1_PCR_RXDSEL(x)    (((x) & 0x7) << 13)
+#define MXC_AUDMUX_V1_PCR_RFCSEL(x)    (((x) & 0xf) << 20)
+#define MXC_AUDMUX_V1_PCR_RCLKDIR      (1 << 24)
+#define MXC_AUDMUX_V1_PCR_RFSDIR       (1 << 25)
+#define MXC_AUDMUX_V1_PCR_TFCSEL(x)    (((x) & 0xf) << 26)
+#define MXC_AUDMUX_V1_PCR_TCLKDIR      (1 << 30)
+#define MXC_AUDMUX_V1_PCR_TFSDIR       (1 << 31)
+
+/* Register definitions for the i.MX25/31/35 Digital Audio Multiplexer */
+#define MXC_AUDMUX_V2_PTCR_TFSDIR      (1 << 31)
+#define MXC_AUDMUX_V2_PTCR_TFSEL(x)    (((x) & 0xf) << 27)
+#define MXC_AUDMUX_V2_PTCR_TCLKDIR     (1 << 26)
+#define MXC_AUDMUX_V2_PTCR_TCSEL(x)    (((x) & 0xf) << 22)
+#define MXC_AUDMUX_V2_PTCR_RFSDIR      (1 << 21)
+#define MXC_AUDMUX_V2_PTCR_RFSEL(x)    (((x) & 0xf) << 17)
+#define MXC_AUDMUX_V2_PTCR_RCLKDIR     (1 << 16)
+#define MXC_AUDMUX_V2_PTCR_RCSEL(x)    (((x) & 0xf) << 12)
+#define MXC_AUDMUX_V2_PTCR_SYN         (1 << 11)
+
+#define MXC_AUDMUX_V2_PDCR_RXDSEL(x)   (((x) & 0x7) << 13)
+#define MXC_AUDMUX_V2_PDCR_TXRXEN      (1 << 12)
+#define MXC_AUDMUX_V2_PDCR_MODE(x)     (((x) & 0x3) << 8)
+#define MXC_AUDMUX_V2_PDCR_INMMASK(x)  ((x) & 0xff)
+
+int mxc_audmux_v1_configure_port(unsigned int port, unsigned int pcr);
+
+int mxc_audmux_v2_configure_port(unsigned int port, unsigned int ptcr,
+               unsigned int pdcr);
+
+#endif /* __MACH_AUDMUX_H */
diff --git a/arch/arm/plat-mxc/include/mach/board-kzmarm11.h b/arch/arm/plat-mxc/include/mach/board-kzmarm11.h
new file mode 100644 (file)
index 0000000..05ff2f3
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ *  Copyright (C) 2009  Yoichi Yuasa <yuasa@linux-mips.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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#ifndef __ARM_ARCH_BOARD_KZM_ARM11_H
+#define __ARM_ARCH_BOARD_KZM_ARM11_H
+
+/*
+ *  KZM-ARM11-01 Board Control Registers on FPGA
+ */
+#define KZM_ARM11_CTL1         (CS4_BASE_ADDR + 0x1000)
+#define KZM_ARM11_CTL2         (CS4_BASE_ADDR + 0x1001)
+#define KZM_ARM11_RSW1         (CS4_BASE_ADDR + 0x1002)
+#define KZM_ARM11_BACK_LIGHT   (CS4_BASE_ADDR + 0x1004)
+#define KZM_ARM11_FPGA_REV     (CS4_BASE_ADDR + 0x1008)
+#define KZM_ARM11_7SEG_LED     (CS4_BASE_ADDR + 0x1010)
+#define KZM_ARM11_LEDS         (CS4_BASE_ADDR + 0x1020)
+#define KZM_ARM11_DIPSW2       (CS4_BASE_ADDR + 0x1003)
+
+/*
+ * External UART for touch panel on FPGA
+ */
+#define KZM_ARM11_16550                (CS4_BASE_ADDR + 0x1050)
+
+#endif /* __ARM_ARCH_BOARD_KZM_ARM11_H */
+
index 8e64325..0184b63 100644 (file)
@@ -1,15 +1,42 @@
 /*
  * Copyright 2007 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright (C) 2009 Daniel Mack <daniel@caiaq.de>
+ *
+ * Based on code for mobots boards,
+ *   Copyright (C) 2009 Valentin Longchamp, EPFL Mobots group
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
  */
 
+#ifndef __ASM_ARCH_MXC_BOARD_MX31LITE_H__
+#define __ASM_ARCH_MXC_BOARD_MX31LITE_H__
+
+#ifndef __ASSEMBLY__
+
+enum mx31lilly_boards {
+       MX31LITE_NOBOARD        = 0,
+       MX31LITE_DB             = 1,
+};
+
 /*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
+ * This CPU module needs a baseboard to work. After basic initializing
+ * its own devices, it calls baseboard's init function.
  */
 
-#ifndef __ASM_ARCH_MXC_BOARD_MX31LITE_H__
-#define __ASM_ARCH_MXC_BOARD_MX31LITE_H__
+extern void mx31lite_db_init(void);
 
-#endif /* __ASM_ARCH_MXC_BOARD_MX31LITE_H__ */
+#endif
 
+#endif /* __ASM_ARCH_MXC_BOARD_MX31LITE_H__ */
index b3876cc..07be8ad 100644 (file)
@@ -58,6 +58,14 @@ imx_dma_setup_single(int channel, dma_addr_t dma_address,
                unsigned int dma_length, unsigned int dev_addr,
                unsigned int dmamode);
 
+
+/*
+ * Use this flag as the dma_length argument to imx_dma_setup_sg()
+ * to create an endless running dma loop. The end of the scatterlist
+ * must be linked to the beginning for this to work.
+ */
+#define IMX_DMA_LENGTH_LOOP    ((unsigned int)-1)
+
 int
 imx_dma_setup_sg(int channel, struct scatterlist *sg,
                unsigned int sgcount, unsigned int dma_length,
index 446f867..eaabd4e 100644 (file)
@@ -524,10 +524,18 @@ enum iomux_pins {
 #define MX31_PIN_RTS1__RTS1            IOMUX_MODE(MX31_PIN_RTS1, IOMUX_CONFIG_FUNC)
 #define MX31_PIN_TXD1__TXD1            IOMUX_MODE(MX31_PIN_TXD1, IOMUX_CONFIG_FUNC)
 #define MX31_PIN_RXD1__RXD1            IOMUX_MODE(MX31_PIN_RXD1, IOMUX_CONFIG_FUNC)
+#define MX31_PIN_DCD_DCE1__DCD_DCE1    IOMUX_MODE(MX31_PIN_DCD_DCE1, IOMUX_CONFIG_FUNC)
+#define MX31_PIN_RI_DCE1__RI_DCE1      IOMUX_MODE(MX31_PIN_RI_DCE1, IOMUX_CONFIG_FUNC)
+#define MX31_PIN_DSR_DCE1__DSR_DCE1    IOMUX_MODE(MX31_PIN_DSR_DCE1, IOMUX_CONFIG_FUNC)
+#define MX31_PIN_DTR_DCE1__DTR_DCE1    IOMUX_MODE(MX31_PIN_DTR_DCE1, IOMUX_CONFIG_FUNC)
 #define MX31_PIN_CTS2__CTS2            IOMUX_MODE(MX31_PIN_CTS2, IOMUX_CONFIG_FUNC)
 #define MX31_PIN_RTS2__RTS2            IOMUX_MODE(MX31_PIN_RTS2, IOMUX_CONFIG_FUNC)
 #define MX31_PIN_TXD2__TXD2            IOMUX_MODE(MX31_PIN_TXD2, IOMUX_CONFIG_FUNC)
 #define MX31_PIN_RXD2__RXD2            IOMUX_MODE(MX31_PIN_RXD2, IOMUX_CONFIG_FUNC)
+#define MX31_PIN_DCD_DTE1__DCD_DTE2    IOMUX_MODE(MX31_PIN_DCD_DTE1, IOMUX_CONFIG_ALT1)
+#define MX31_PIN_RI_DTE1__RI_DTE2      IOMUX_MODE(MX31_PIN_RI_DTE1, IOMUX_CONFIG_ALT1)
+#define MX31_PIN_DSR_DTE1__DSR_DTE2    IOMUX_MODE(MX31_PIN_DSR_DTE1, IOMUX_CONFIG_ALT1)
+#define MX31_PIN_DTR_DTE1__DTR_DTE2    IOMUX_MODE(MX31_PIN_DTR_DTE1, IOMUX_OCONFIG_ALT3 | IOMUX_ICONFIG_NONE)
 #define MX31_PIN_PC_RST__CTS5          IOMUX_MODE(MX31_PIN_PC_RST, IOMUX_CONFIG_ALT2)
 #define MX31_PIN_PC_VS2__RTS5          IOMUX_MODE(MX31_PIN_PC_VS2, IOMUX_CONFIG_ALT2)
 #define MX31_PIN_PC_BVD2__TXD5         IOMUX_MODE(MX31_PIN_PC_BVD2, IOMUX_CONFIG_ALT2)
@@ -623,6 +631,8 @@ enum iomux_pins {
 #define MX31_PIN_GPIO3_0__GPIO3_0      IOMUX_MODE(MX31_PIN_GPIO3_0, IOMUX_CONFIG_GPIO)
 #define MX31_PIN_GPIO3_1__GPIO3_1      IOMUX_MODE(MX31_PIN_GPIO3_1, IOMUX_CONFIG_GPIO)
 #define MX31_PIN_TXD2__GPIO1_28                IOMUX_MODE(MX31_PIN_TXD2, IOMUX_CONFIG_GPIO)
+#define MX31_PIN_CSI_D4__GPIO3_4       IOMUX_MODE(MX31_PIN_CSI_D4, IOMUX_CONFIG_GPIO)
+#define MX31_PIN_CSI_D5__GPIO3_5       IOMUX_MODE(MX31_PIN_CSI_D5, IOMUX_CONFIG_GPIO)
 #define MX31_PIN_USBOTG_DATA0__USBOTG_DATA0    IOMUX_MODE(MX31_PIN_USBOTG_DATA0, IOMUX_CONFIG_FUNC)
 #define MX31_PIN_USBOTG_DATA1__USBOTG_DATA1    IOMUX_MODE(MX31_PIN_USBOTG_DATA1, IOMUX_CONFIG_FUNC)
 #define MX31_PIN_USBOTG_DATA2__USBOTG_DATA2    IOMUX_MODE(MX31_PIN_USBOTG_DATA2, IOMUX_CONFIG_FUNC)
@@ -642,12 +652,22 @@ enum iomux_pins {
 #define MX31_PIN_CSPI1_SS2__USBH1_RCV          IOMUX_MODE(MX31_PIN_CSPI1_SS2,  IOMUX_CONFIG_ALT1)
 #define MX31_PIN_CSPI1_SCLK__USBH1_OEB         IOMUX_MODE(MX31_PIN_CSPI1_SCLK, IOMUX_CONFIG_ALT1)
 #define MX31_PIN_CSPI1_SPI_RDY__USBH1_FS       IOMUX_MODE(MX31_PIN_CSPI1_SPI_RDY, IOMUX_CONFIG_ALT1)
+#define MX31_PIN_SFS6__USBH1_SUSPEND   IOMUX_MODE(MX31_PIN_SFS6, IOMUX_CONFIG_FUNC)
+#define MX31_PIN_NFRE_B__GPIO1_11      IOMUX_MODE(MX31_PIN_NFRE_B, IOMUX_CONFIG_GPIO)
+#define MX31_PIN_NFALE__GPIO1_12       IOMUX_MODE(MX31_PIN_NFALE, IOMUX_CONFIG_GPIO)
 #define MX31_PIN_USBH2_DATA0__USBH2_DATA0      IOMUX_MODE(MX31_PIN_USBH2_DATA0, IOMUX_CONFIG_FUNC)
 #define MX31_PIN_USBH2_DATA1__USBH2_DATA1      IOMUX_MODE(MX31_PIN_USBH2_DATA1, IOMUX_CONFIG_FUNC)
+#define MX31_PIN_STXD3__USBH2_DATA2    IOMUX_MODE(MX31_PIN_STXD3, IOMUX_CONFIG_FUNC)
+#define MX31_PIN_SRXD3__USBH2_DATA3    IOMUX_MODE(MX31_PIN_SRXD3, IOMUX_CONFIG_FUNC)
+#define MX31_PIN_SCK3__USBH2_DATA4     IOMUX_MODE(MX31_PIN_SCK3, IOMUX_CONFIG_FUNC)
+#define MX31_PIN_SFS3__USBH2_DATA5     IOMUX_MODE(MX31_PIN_SFS3, IOMUX_CONFIG_FUNC)
+#define MX31_PIN_STXD6__USBH2_DATA6    IOMUX_MODE(MX31_PIN_STXD6, IOMUX_CONFIG_FUNC)
+#define MX31_PIN_SRXD6__USBH2_DATA7    IOMUX_MODE(MX31_PIN_SRXD6, IOMUX_CONFIG_FUNC)
 #define MX31_PIN_USBH2_CLK__USBH2_CLK          IOMUX_MODE(MX31_PIN_USBH2_CLK, IOMUX_CONFIG_FUNC)
 #define MX31_PIN_USBH2_DIR__USBH2_DIR          IOMUX_MODE(MX31_PIN_USBH2_DIR, IOMUX_CONFIG_FUNC)
 #define MX31_PIN_USBH2_NXT__USBH2_NXT          IOMUX_MODE(MX31_PIN_USBH2_NXT, IOMUX_CONFIG_FUNC)
 #define MX31_PIN_USBH2_STP__USBH2_STP          IOMUX_MODE(MX31_PIN_USBH2_STP, IOMUX_CONFIG_FUNC)
+#define MX31_PIN_SCK6__GPIO1_25                IOMUX_MODE(MX31_PIN_SCK6, IOMUX_CONFIG_GPIO)
 #define MX31_PIN_USB_OC__GPIO1_30      IOMUX_MODE(MX31_PIN_USB_OC, IOMUX_CONFIG_GPIO)
 #define MX31_PIN_I2C_DAT__I2C1_SDA     IOMUX_MODE(MX31_PIN_I2C_DAT, IOMUX_CONFIG_FUNC)
 #define MX31_PIN_I2C_CLK__I2C1_SCL     IOMUX_MODE(MX31_PIN_I2C_CLK, IOMUX_CONFIG_FUNC)
@@ -693,7 +713,19 @@ enum iomux_pins {
 #define MX31_PIN_DCD_DCE1__GPIO2_11    IOMUX_MODE(MX31_PIN_DCD_DCE1, IOMUX_CONFIG_GPIO)
 #define MX31_PIN_STXD5__GPIO1_21       IOMUX_MODE(MX31_PIN_STXD5, IOMUX_CONFIG_GPIO)
 #define MX31_PIN_SRXD5__GPIO1_22       IOMUX_MODE(MX31_PIN_SRXD5, IOMUX_CONFIG_GPIO)
-
+#define MX31_PIN_GPIO1_3__GPIO1_3      IOMUX_MODE(MX31_PIN_GPIO1_3, IOMUX_CONFIG_GPIO)
+#define MX31_PIN_CSPI2_SS1__CSPI3_SS1  IOMUX_MODE(MX31_PIN_CSPI2_SS1, IOMUX_CONFIG_ALT1)
+#define MX31_PIN_RTS1__GPIO2_6         IOMUX_MODE(MX31_PIN_RTS1, IOMUX_CONFIG_GPIO)
+#define MX31_PIN_CTS1__GPIO2_7         IOMUX_MODE(MX31_PIN_CTS1, IOMUX_CONFIG_GPIO)
+#define MX31_PIN_LCS0__GPIO3_23                IOMUX_MODE(MX31_PIN_LCS0, IOMUX_CONFIG_GPIO)
+#define MX31_PIN_STXD4__STXD4          IOMUX_MODE(MX31_PIN_STXD4, IOMUX_CONFIG_FUNC)
+#define MX31_PIN_SRXD4__SRXD4          IOMUX_MODE(MX31_PIN_SRXD4, IOMUX_CONFIG_FUNC)
+#define MX31_PIN_SCK4__SCK4            IOMUX_MODE(MX31_PIN_SCK4, IOMUX_CONFIG_FUNC)
+#define MX31_PIN_SFS4__SFS4            IOMUX_MODE(MX31_PIN_SFS4, IOMUX_CONFIG_FUNC)
+#define MX31_PIN_STXD5__STXD5          IOMUX_MODE(MX31_PIN_STXD5, IOMUX_CONFIG_FUNC)
+#define MX31_PIN_SRXD5__SRXD5          IOMUX_MODE(MX31_PIN_SRXD5, IOMUX_CONFIG_FUNC)
+#define MX31_PIN_SCK5__SCK5            IOMUX_MODE(MX31_PIN_SCK5, IOMUX_CONFIG_FUNC)
+#define MX31_PIN_SFS5__SFS5            IOMUX_MODE(MX31_PIN_SFS5, IOMUX_CONFIG_FUNC)
 
 /*XXX: The SS0, SS1, SS2, SS3 lines of spi3 are multiplexed by cspi2_ss0, cspi2_ss1, cspi1_ss0
  * cspi1_ss1*/
index a0fa402..1deda01 100644 (file)
@@ -88,9 +88,7 @@ struct pad_desc {
 #define PAD_CTL_SRE_FAST               (1 << 0)
 
 /*
- * setups a single pad:
- *     - reserves the pad so that it is not claimed by another driver
- *     - setups the iomux according to the configuration
+ * setups a single pad in the iomuxer
  */
 int mxc_iomux_v3_setup_pad(struct pad_desc *pad);
 
@@ -101,19 +99,6 @@ int mxc_iomux_v3_setup_pad(struct pad_desc *pad);
 int mxc_iomux_v3_setup_multiple_pads(struct pad_desc *pad_list, unsigned count);
 
 /*
- * releases a single pad:
- *     - make it available for a future use by another driver
- *     - DOES NOT reconfigure the IOMUX in its reset state
- */
-void mxc_iomux_v3_release_pad(struct pad_desc *pad);
-
-/*
- * releases multiple pads
- * convenvient way to call the above function with tables
- */
-void mxc_iomux_v3_release_multiple_pads(struct pad_desc *pad_list, int count);
-
-/*
  * Initialise the iomux controller
  */
 void mxc_iomux_v3_init(void __iomem *iomux_v3_base);
index 6d49f8a..011cfcd 100644 (file)
 #define IRQ_GPIOC(x)  (IRQ_GPIOB(32) + x)
 #define IRQ_GPIOD(x)  (IRQ_GPIOC(32) + x)
 #define IRQ_GPIOE(x)  (IRQ_GPIOD(32) + x)
+#define IRQ_GPIOF(x)  (IRQ_GPIOE(32) + x)
 
 
 extern void mxc_gpio_mode(int gpio_mode);
index 21112c6..bb297d8 100644 (file)
 #ifndef __ASM_ARCH_MXC_MX21_H__
 #define __ASM_ARCH_MXC_MX21_H__
 
+#define MX21_AIPI_BASE_ADDR            0x10000000
+#define MX21_AIPI_BASE_ADDR_VIRT       0xf4000000
+#define MX21_AIPI_SIZE                 SZ_1M
+#define MX21_DMA_BASE_ADDR                     (MX21_AIPI_BASE_ADDR + 0x01000)
+#define MX21_WDOG_BASE_ADDR                    (MX21_AIPI_BASE_ADDR + 0x02000)
+#define MX21_GPT1_BASE_ADDR                    (MX21_AIPI_BASE_ADDR + 0x03000)
+#define MX21_GPT2_BASE_ADDR                    (MX21_AIPI_BASE_ADDR + 0x04000)
+#define MX21_GPT3_BASE_ADDR                    (MX21_AIPI_BASE_ADDR + 0x05000)
+#define MX21_PWM_BASE_ADDR                     (MX21_AIPI_BASE_ADDR + 0x06000)
+#define MX21_RTC_BASE_ADDR                     (MX21_AIPI_BASE_ADDR + 0x07000)
+#define MX21_KPP_BASE_ADDR                     (MX21_AIPI_BASE_ADDR + 0x08000)
+#define MX21_OWIRE_BASE_ADDR                   (MX21_AIPI_BASE_ADDR + 0x09000)
+#define MX21_UART1_BASE_ADDR                   (MX21_AIPI_BASE_ADDR + 0x0a000)
+#define MX21_UART2_BASE_ADDR                   (MX21_AIPI_BASE_ADDR + 0x0b000)
+#define MX21_UART3_BASE_ADDR                   (MX21_AIPI_BASE_ADDR + 0x0c000)
+#define MX21_UART4_BASE_ADDR                   (MX21_AIPI_BASE_ADDR + 0x0d000)
+#define MX21_CSPI1_BASE_ADDR                   (MX21_AIPI_BASE_ADDR + 0x0e000)
+#define MX21_CSPI2_BASE_ADDR                   (MX21_AIPI_BASE_ADDR + 0x0f000)
+#define MX21_SSI1_BASE_ADDR                    (MX21_AIPI_BASE_ADDR + 0x10000)
+#define MX21_SSI2_BASE_ADDR                    (MX21_AIPI_BASE_ADDR + 0x11000)
+#define MX21_I2C_BASE_ADDR                     (MX21_AIPI_BASE_ADDR + 0x12000)
+#define MX21_SDHC1_BASE_ADDR                   (MX21_AIPI_BASE_ADDR + 0x13000)
+#define MX21_SDHC2_BASE_ADDR                   (MX21_AIPI_BASE_ADDR + 0x14000)
+#define MX21_GPIO_BASE_ADDR                    (MX21_AIPI_BASE_ADDR + 0x15000)
+#define MX21_AUDMUX_BASE_ADDR                  (MX21_AIPI_BASE_ADDR + 0x16000)
+#define MX21_CSPI3_BASE_ADDR                   (MX21_AIPI_BASE_ADDR + 0x17000)
+#define MX21_LCDC_BASE_ADDR                    (MX21_AIPI_BASE_ADDR + 0x21000)
+#define MX21_SLCDC_BASE_ADDR                   (MX21_AIPI_BASE_ADDR + 0x22000)
+#define MX21_USBOTG_BASE_ADDR                  (MX21_AIPI_BASE_ADDR + 0x24000)
+#define MX21_EMMA_PP_BASE_ADDR                 (MX21_AIPI_BASE_ADDR + 0x26000)
+#define MX21_EMMA_PRP_BASE_ADDR                        (MX21_AIPI_BASE_ADDR + 0x26400)
+#define MX21_CCM_BASE_ADDR                     (MX21_AIPI_BASE_ADDR + 0x27000)
+#define MX21_SYSCTRL_BASE_ADDR                 (MX21_AIPI_BASE_ADDR + 0x27800)
+#define MX21_JAM_BASE_ADDR                     (MX21_AIPI_BASE_ADDR + 0x3e000)
+#define MX21_MAX_BASE_ADDR                     (MX21_AIPI_BASE_ADDR + 0x3f000)
+
+#define MX21_AVIC_BASE_ADDR            0x10040000
+
+#define MX21_SAHB1_BASE_ADDR           0x80000000
+#define MX21_SAHB1_BASE_ADDR_VIRT      0xf4100000
+#define MX21_SAHB1_SIZE                        SZ_1M
+#define MX21_CSI_BASE_ADDR                     (MX2x_SAHB1_BASE_ADDR + 0x0000)
+
 /* Memory regions and CS */
-#define SDRAM_BASE_ADDR         0xC0000000
-#define CSD1_BASE_ADDR          0xC4000000
+#define MX21_SDRAM_BASE_ADDR           0xc0000000
+#define MX21_CSD1_BASE_ADDR            0xc4000000
 
-#define CS0_BASE_ADDR           0xC8000000
-#define CS1_BASE_ADDR           0xCC000000
-#define CS2_BASE_ADDR           0xD0000000
-#define CS3_BASE_ADDR           0xD1000000
-#define CS4_BASE_ADDR           0xD2000000
-#define CS5_BASE_ADDR           0xDD000000
-#define PCMCIA_MEM_BASE_ADDR    0xD4000000
+#define MX21_CS0_BASE_ADDR             0xc8000000
+#define MX21_CS1_BASE_ADDR             0xcc000000
+#define MX21_CS2_BASE_ADDR             0xd0000000
+#define MX21_CS3_BASE_ADDR             0xd1000000
+#define MX21_CS4_BASE_ADDR             0xd2000000
+#define MX21_PCMCIA_MEM_BASE_ADDR      0xd4000000
+#define MX21_CS5_BASE_ADDR             0xdd000000
 
 /* NAND, SDRAM, WEIM etc controllers */
-#define X_MEMC_BASE_ADDR        0xDF000000
-#define X_MEMC_BASE_ADDR_VIRT   0xF4200000
-#define X_MEMC_SIZE             SZ_256K
+#define MX21_X_MEMC_BASE_ADDR          0xdf000000
+#define MX21_X_MEMC_BASE_ADDR_VIRT     0xf4200000
+#define MX21_X_MEMC_SIZE               SZ_256K
 
-#define SDRAMC_BASE_ADDR        (X_MEMC_BASE_ADDR + 0x0000)
-#define EIM_BASE_ADDR           (X_MEMC_BASE_ADDR + 0x1000)
-#define PCMCIA_CTL_BASE_ADDR    (X_MEMC_BASE_ADDR + 0x2000)
-#define NFC_BASE_ADDR           (X_MEMC_BASE_ADDR + 0x3000)
+#define MX21_SDRAMC_BASE_ADDR          (MX21_X_MEMC_BASE_ADDR + 0x0000)
+#define MX21_EIM_BASE_ADDR             (MX21_X_MEMC_BASE_ADDR + 0x1000)
+#define MX21_PCMCIA_CTL_BASE_ADDR      (MX21_X_MEMC_BASE_ADDR + 0x2000)
+#define MX21_NFC_BASE_ADDR             (MX21_X_MEMC_BASE_ADDR + 0x3000)
 
-#define IRAM_BASE_ADDR          0xFFFFE800     /* internal ram */
+#define MX21_IRAM_BASE_ADDR            0xffffe800      /* internal ram */
 
 /* fixed interrupt numbers */
-#define MXC_INT_USBCTRL         58
-#define MXC_INT_USBCTRL         58
-#define MXC_INT_USBMNP          57
-#define MXC_INT_USBFUNC         56
-#define MXC_INT_USBHOST         55
-#define MXC_INT_USBDMA          54
-#define MXC_INT_USBWKUP         53
-#define MXC_INT_EMMADEC         50
-#define MXC_INT_EMMAENC         49
-#define MXC_INT_BMI             30
-#define MXC_INT_FIRI            9
+#define MX21_INT_CSPI3         6
+#define MX21_INT_GPIO          8
+#define MX21_INT_FIRI          9
+#define MX21_INT_SDHC2         10
+#define MX21_INT_SDHC1         11
+#define MX21_INT_I2C           12
+#define MX21_INT_SSI2          13
+#define MX21_INT_SSI1          14
+#define MX21_INT_CSPI2         15
+#define MX21_INT_CSPI1         16
+#define MX21_INT_UART4         17
+#define MX21_INT_UART3         18
+#define MX21_INT_UART2         19
+#define MX21_INT_UART1         20
+#define MX21_INT_KPP           21
+#define MX21_INT_RTC           22
+#define MX21_INT_PWM           23
+#define MX21_INT_GPT3          24
+#define MX21_INT_GPT2          25
+#define MX21_INT_GPT1          26
+#define MX21_INT_WDOG          27
+#define MX21_INT_PCMCIA                28
+#define MX21_INT_NANDFC                29
+#define MX21_INT_BMI           30
+#define MX21_INT_CSI           31
+#define MX21_INT_DMACH0                32
+#define MX21_INT_DMACH1                33
+#define MX21_INT_DMACH2                34
+#define MX21_INT_DMACH3                35
+#define MX21_INT_DMACH4                36
+#define MX21_INT_DMACH5                37
+#define MX21_INT_DMACH6                38
+#define MX21_INT_DMACH7                39
+#define MX21_INT_DMACH8                40
+#define MX21_INT_DMACH9                41
+#define MX21_INT_DMACH10       42
+#define MX21_INT_DMACH11       43
+#define MX21_INT_DMACH12       44
+#define MX21_INT_DMACH13       45
+#define MX21_INT_DMACH14       46
+#define MX21_INT_DMACH15       47
+#define MX21_INT_EMMAENC       49
+#define MX21_INT_EMMADEC       50
+#define MX21_INT_EMMAPRP       51
+#define MX21_INT_EMMAPP                52
+#define MX21_INT_USBWKUP       53
+#define MX21_INT_USBDMA                54
+#define MX21_INT_USBHOST       55
+#define MX21_INT_USBFUNC       56
+#define MX21_INT_USBMNP                57
+#define MX21_INT_USBCTRL       58
+#define MX21_INT_SLCDC         60
+#define MX21_INT_LCDC          61
 
 /* fixed DMA request numbers */
-#define DMA_REQ_BMI_RX          29
-#define DMA_REQ_BMI_TX          28
-#define DMA_REQ_FIRI_RX         4
+#define MX21_DMA_REQ_CSPI3_RX  1
+#define MX21_DMA_REQ_CSPI3_TX  2
+#define MX21_DMA_REQ_EXT       3
+#define MX21_DMA_REQ_FIRI_RX   4
+#define MX21_DMA_REQ_SDHC2     6
+#define MX21_DMA_REQ_SDHC1     7
+#define MX21_DMA_REQ_SSI2_RX0  8
+#define MX21_DMA_REQ_SSI2_TX0  9
+#define MX21_DMA_REQ_SSI2_RX1  10
+#define MX21_DMA_REQ_SSI2_TX1  11
+#define MX21_DMA_REQ_SSI1_RX0  12
+#define MX21_DMA_REQ_SSI1_TX0  13
+#define MX21_DMA_REQ_SSI1_RX1  14
+#define MX21_DMA_REQ_SSI1_TX1  15
+#define MX21_DMA_REQ_CSPI2_RX  16
+#define MX21_DMA_REQ_CSPI2_TX  17
+#define MX21_DMA_REQ_CSPI1_RX  18
+#define MX21_DMA_REQ_CSPI1_TX  19
+#define MX21_DMA_REQ_UART4_RX  20
+#define MX21_DMA_REQ_UART4_TX  21
+#define MX21_DMA_REQ_UART3_RX  22
+#define MX21_DMA_REQ_UART3_TX  23
+#define MX21_DMA_REQ_UART2_RX  24
+#define MX21_DMA_REQ_UART2_TX  25
+#define MX21_DMA_REQ_UART1_RX  26
+#define MX21_DMA_REQ_UART1_TX  27
+#define MX21_DMA_REQ_BMI_TX    28
+#define MX21_DMA_REQ_BMI_RX    29
+#define MX21_DMA_REQ_CSI_STAT  30
+#define MX21_DMA_REQ_CSI_RX    31
+
+/* these should go away */
+#define SDRAM_BASE_ADDR MX21_SDRAM_BASE_ADDR
+#define CSD1_BASE_ADDR MX21_CSD1_BASE_ADDR
+#define CS0_BASE_ADDR MX21_CS0_BASE_ADDR
+#define CS1_BASE_ADDR MX21_CS1_BASE_ADDR
+#define CS2_BASE_ADDR MX21_CS2_BASE_ADDR
+#define CS3_BASE_ADDR MX21_CS3_BASE_ADDR
+#define CS4_BASE_ADDR MX21_CS4_BASE_ADDR
+#define PCMCIA_MEM_BASE_ADDR MX21_PCMCIA_MEM_BASE_ADDR
+#define CS5_BASE_ADDR MX21_CS5_BASE_ADDR
+#define X_MEMC_BASE_ADDR MX21_X_MEMC_BASE_ADDR
+#define X_MEMC_BASE_ADDR_VIRT MX21_X_MEMC_BASE_ADDR_VIRT
+#define X_MEMC_SIZE MX21_X_MEMC_SIZE
+#define SDRAMC_BASE_ADDR MX21_SDRAMC_BASE_ADDR
+#define EIM_BASE_ADDR MX21_EIM_BASE_ADDR
+#define PCMCIA_CTL_BASE_ADDR MX21_PCMCIA_CTL_BASE_ADDR
+#define NFC_BASE_ADDR MX21_NFC_BASE_ADDR
+#define IRAM_BASE_ADDR MX21_IRAM_BASE_ADDR
+#define MXC_INT_FIRI MX21_INT_FIRI
+#define MXC_INT_BMI MX21_INT_BMI
+#define MXC_INT_EMMAENC MX21_INT_EMMAENC
+#define MXC_INT_EMMADEC MX21_INT_EMMADEC
+#define MXC_INT_USBWKUP MX21_INT_USBWKUP
+#define MXC_INT_USBDMA MX21_INT_USBDMA
+#define MXC_INT_USBHOST MX21_INT_USBHOST
+#define MXC_INT_USBFUNC MX21_INT_USBFUNC
+#define MXC_INT_USBMNP MX21_INT_USBMNP
+#define MXC_INT_USBCTRL MX21_INT_USBCTRL
+#define MXC_INT_USBCTRL MX21_INT_USBCTRL
+#define DMA_REQ_FIRI_RX MX21_DMA_REQ_FIRI_RX
+#define DMA_REQ_BMI_TX MX21_DMA_REQ_BMI_TX
+#define DMA_REQ_BMI_RX MX21_DMA_REQ_BMI_RX
 
 #endif /* __ASM_ARCH_MXC_MX21_H__ */
index ec64bd9..91e7381 100644 (file)
@@ -1,14 +1,14 @@
 #ifndef __MACH_MX25_H__
 #define __MACH_MX25_H__
 
-#define MX25_AIPS1_BASE_ADDR           0x43F00000
-#define MX25_AIPS1_BASE_ADDR_VIRT      0xFC000000
+#define MX25_AIPS1_BASE_ADDR           0x43f00000
+#define MX25_AIPS1_BASE_ADDR_VIRT      0xfc000000
 #define MX25_AIPS1_SIZE                        SZ_1M
-#define MX25_AIPS2_BASE_ADDR           0x53F00000
-#define MX25_AIPS2_BASE_ADDR_VIRT      0xFC200000
+#define MX25_AIPS2_BASE_ADDR           0x53f00000
+#define MX25_AIPS2_BASE_ADDR_VIRT      0xfc200000
 #define MX25_AIPS2_SIZE                        SZ_1M
 #define MX25_AVIC_BASE_ADDR            0x68000000
-#define MX25_AVIC_BASE_ADDR_VIRT       0xFC400000
+#define MX25_AVIC_BASE_ADDR_VIRT       0xfc400000
 #define MX25_AVIC_SIZE                 SZ_1M
 
 #define MX25_IOMUXC_BASE_ADDR          (MX25_AIPS1_BASE_ADDR + 0xac000)
index dc3ad9a..e2ae19f 100644 (file)
 #ifndef __ASM_ARCH_MXC_MX27_H__
 #define __ASM_ARCH_MXC_MX27_H__
 
-/* IRAM */
-#define IRAM_BASE_ADDR          0xFFFF4C00     /* internal ram */
-
-#define MSHC_BASE_ADDR          (AIPI_BASE_ADDR + 0x18000)
-#define GPT5_BASE_ADDR          (AIPI_BASE_ADDR + 0x19000)
-#define GPT4_BASE_ADDR          (AIPI_BASE_ADDR + 0x1A000)
-#define UART5_BASE_ADDR         (AIPI_BASE_ADDR + 0x1B000)
-#define UART6_BASE_ADDR         (AIPI_BASE_ADDR + 0x1C000)
-#define I2C2_BASE_ADDR          (AIPI_BASE_ADDR + 0x1D000)
-#define SDHC3_BASE_ADDR         (AIPI_BASE_ADDR + 0x1E000)
-#define GPT6_BASE_ADDR          (AIPI_BASE_ADDR + 0x1F000)
-#define VPU_BASE_ADDR           (AIPI_BASE_ADDR + 0x23000)
-#define OTG_BASE_ADDR           USBOTG_BASE_ADDR
-#define SAHARA_BASE_ADDR        (AIPI_BASE_ADDR + 0x25000)
-#define IIM_BASE_ADDR           (AIPI_BASE_ADDR + 0x28000)
-#define RTIC_BASE_ADDR          (AIPI_BASE_ADDR + 0x2A000)
-#define FEC_BASE_ADDR           (AIPI_BASE_ADDR + 0x2B000)
-#define SCC_BASE_ADDR           (AIPI_BASE_ADDR + 0x2C000)
-#define ETB_BASE_ADDR           (AIPI_BASE_ADDR + 0x3B000)
-#define ETB_RAM_BASE_ADDR       (AIPI_BASE_ADDR + 0x3C000)
+#define MX27_AIPI_BASE_ADDR            0x10000000
+#define MX27_AIPI_BASE_ADDR_VIRT       0xf4000000
+#define MX27_AIPI_SIZE                 SZ_1M
+#define MX27_DMA_BASE_ADDR                     (MX27_AIPI_BASE_ADDR + 0x01000)
+#define MX27_WDOG_BASE_ADDR                    (MX27_AIPI_BASE_ADDR + 0x02000)
+#define MX27_GPT1_BASE_ADDR                    (MX27_AIPI_BASE_ADDR + 0x03000)
+#define MX27_GPT2_BASE_ADDR                    (MX27_AIPI_BASE_ADDR + 0x04000)
+#define MX27_GPT3_BASE_ADDR                    (MX27_AIPI_BASE_ADDR + 0x05000)
+#define MX27_PWM_BASE_ADDR                     (MX27_AIPI_BASE_ADDR + 0x06000)
+#define MX27_RTC_BASE_ADDR                     (MX27_AIPI_BASE_ADDR + 0x07000)
+#define MX27_KPP_BASE_ADDR                     (MX27_AIPI_BASE_ADDR + 0x08000)
+#define MX27_OWIRE_BASE_ADDR                   (MX27_AIPI_BASE_ADDR + 0x09000)
+#define MX27_UART1_BASE_ADDR                   (MX27_AIPI_BASE_ADDR + 0x0a000)
+#define MX27_UART2_BASE_ADDR                   (MX27_AIPI_BASE_ADDR + 0x0b000)
+#define MX27_UART3_BASE_ADDR                   (MX27_AIPI_BASE_ADDR + 0x0c000)
+#define MX27_UART4_BASE_ADDR                   (MX27_AIPI_BASE_ADDR + 0x0d000)
+#define MX27_CSPI1_BASE_ADDR                   (MX27_AIPI_BASE_ADDR + 0x0e000)
+#define MX27_CSPI2_BASE_ADDR                   (MX27_AIPI_BASE_ADDR + 0x0f000)
+#define MX27_SSI1_BASE_ADDR                    (MX27_AIPI_BASE_ADDR + 0x10000)
+#define MX27_SSI2_BASE_ADDR                    (MX27_AIPI_BASE_ADDR + 0x11000)
+#define MX27_I2C_BASE_ADDR                     (MX27_AIPI_BASE_ADDR + 0x12000)
+#define MX27_SDHC1_BASE_ADDR                   (MX27_AIPI_BASE_ADDR + 0x13000)
+#define MX27_SDHC2_BASE_ADDR                   (MX27_AIPI_BASE_ADDR + 0x14000)
+#define MX27_GPIO_BASE_ADDR                    (MX27_AIPI_BASE_ADDR + 0x15000)
+#define MX27_AUDMUX_BASE_ADDR                  (MX27_AIPI_BASE_ADDR + 0x16000)
+#define MX27_CSPI3_BASE_ADDR                   (MX27_AIPI_BASE_ADDR + 0x17000)
+#define MX27_MSHC_BASE_ADDR                    (MX27_AIPI_BASE_ADDR + 0x18000)
+#define MX27_GPT5_BASE_ADDR                    (MX27_AIPI_BASE_ADDR + 0x19000)
+#define MX27_GPT4_BASE_ADDR                    (MX27_AIPI_BASE_ADDR + 0x1a000)
+#define MX27_UART5_BASE_ADDR                   (MX27_AIPI_BASE_ADDR + 0x1b000)
+#define MX27_UART6_BASE_ADDR                   (MX27_AIPI_BASE_ADDR + 0x1c000)
+#define MX27_I2C2_BASE_ADDR                    (MX27_AIPI_BASE_ADDR + 0x1d000)
+#define MX27_SDHC3_BASE_ADDR                   (MX27_AIPI_BASE_ADDR + 0x1e000)
+#define MX27_GPT6_BASE_ADDR                    (MX27_AIPI_BASE_ADDR + 0x1f000)
+#define MX27_LCDC_BASE_ADDR                    (MX27_AIPI_BASE_ADDR + 0x21000)
+#define MX27_SLCDC_BASE_ADDR                   (MX27_AIPI_BASE_ADDR + 0x22000)
+#define MX27_VPU_BASE_ADDR                     (MX27_AIPI_BASE_ADDR + 0x23000)
+#define MX27_USBOTG_BASE_ADDR                  (MX27_AIPI_BASE_ADDR + 0x24000)
+#define MX27_OTG_BASE_ADDR                     MX27_USBOTG_BASE_ADDR
+#define MX27_SAHARA_BASE_ADDR                  (MX27_AIPI_BASE_ADDR + 0x25000)
+#define MX27_EMMA_PP_BASE_ADDR                 (MX27_AIPI_BASE_ADDR + 0x26000)
+#define MX27_EMMA_PRP_BASE_ADDR                        (MX27_AIPI_BASE_ADDR + 0x26400)
+#define MX27_CCM_BASE_ADDR                     (MX27_AIPI_BASE_ADDR + 0x27000)
+#define MX27_SYSCTRL_BASE_ADDR                 (MX27_AIPI_BASE_ADDR + 0x27800)
+#define MX27_IIM_BASE_ADDR                     (MX27_AIPI_BASE_ADDR + 0x28000)
+#define MX27_RTIC_BASE_ADDR                    (MX27_AIPI_BASE_ADDR + 0x2a000)
+#define MX27_FEC_BASE_ADDR                     (MX27_AIPI_BASE_ADDR + 0x2b000)
+#define MX27_SCC_BASE_ADDR                     (MX27_AIPI_BASE_ADDR + 0x2c000)
+#define MX27_ETB_BASE_ADDR                     (MX27_AIPI_BASE_ADDR + 0x3b000)
+#define MX27_ETB_RAM_BASE_ADDR                 (MX27_AIPI_BASE_ADDR + 0x3c000)
+#define MX27_JAM_BASE_ADDR                     (MX27_AIPI_BASE_ADDR + 0x3e000)
+#define MX27_MAX_BASE_ADDR                     (MX27_AIPI_BASE_ADDR + 0x3f000)
+
+#define MX27_AVIC_BASE_ADDR            0x10040000
 
 /* ROM patch */
-#define ROMP_BASE_ADDR          0x10041000
+#define MX27_ROMP_BASE_ADDR            0x10041000
 
-#define ATA_BASE_ADDR           (SAHB1_BASE_ADDR + 0x1000)
+#define MX27_SAHB1_BASE_ADDR           0x80000000
+#define MX27_SAHB1_BASE_ADDR_VIRT      0xf4100000
+#define MX27_SAHB1_SIZE                        SZ_1M
+#define MX27_CSI_BASE_ADDR                     (MX27_SAHB1_BASE_ADDR + 0x0000)
+#define MX27_ATA_BASE_ADDR                     (MX27_SAHB1_BASE_ADDR + 0x1000)
 
 /* Memory regions and CS */
-#define SDRAM_BASE_ADDR         0xA0000000
-#define CSD1_BASE_ADDR          0xB0000000
+#define MX27_SDRAM_BASE_ADDR           0xa0000000
+#define MX27_CSD1_BASE_ADDR            0xb0000000
 
-#define CS0_BASE_ADDR           0xC0000000
-#define CS1_BASE_ADDR           0xC8000000
-#define CS2_BASE_ADDR           0xD0000000
-#define CS3_BASE_ADDR           0xD2000000
-#define CS4_BASE_ADDR           0xD4000000
-#define CS5_BASE_ADDR           0xD6000000
-#define PCMCIA_MEM_BASE_ADDR    0xDC000000
+#define MX27_CS0_BASE_ADDR             0xc0000000
+#define MX27_CS1_BASE_ADDR             0xc8000000
+#define MX27_CS2_BASE_ADDR             0xd0000000
+#define MX27_CS3_BASE_ADDR             0xd2000000
+#define MX27_CS4_BASE_ADDR             0xd4000000
+#define MX27_CS5_BASE_ADDR             0xd6000000
 
 /* NAND, SDRAM, WEIM, M3IF, EMI controllers */
-#define X_MEMC_BASE_ADDR        0xD8000000
-#define X_MEMC_BASE_ADDR_VIRT   0xF4200000
-#define X_MEMC_SIZE             SZ_1M
+#define MX27_X_MEMC_BASE_ADDR          0xd8000000
+#define MX27_X_MEMC_BASE_ADDR_VIRT     0xf4200000
+#define MX27_X_MEMC_SIZE               SZ_1M
+#define MX27_NFC_BASE_ADDR                     (MX27_X_MEMC_BASE_ADDR)
+#define MX27_SDRAMC_BASE_ADDR                  (MX27_X_MEMC_BASE_ADDR + 0x1000)
+#define MX27_WEIM_BASE_ADDR                    (MX27_X_MEMC_BASE_ADDR + 0x2000)
+#define MX27_M3IF_BASE_ADDR                    (MX27_X_MEMC_BASE_ADDR + 0x3000)
+#define MX27_PCMCIA_CTL_BASE_ADDR              (MX27_X_MEMC_BASE_ADDR + 0x4000)
 
-#define NFC_BASE_ADDR           (X_MEMC_BASE_ADDR)
-#define SDRAMC_BASE_ADDR        (X_MEMC_BASE_ADDR + 0x1000)
-#define WEIM_BASE_ADDR          (X_MEMC_BASE_ADDR + 0x2000)
-#define M3IF_BASE_ADDR          (X_MEMC_BASE_ADDR + 0x3000)
-#define PCMCIA_CTL_BASE_ADDR    (X_MEMC_BASE_ADDR + 0x4000)
+#define MX27_PCMCIA_MEM_BASE_ADDR      0xdc000000
+
+/* IRAM */
+#define MX27_IRAM_BASE_ADDR            0xffff4c00      /* internal ram */
 
 /* fixed interrupt numbers */
-#define MXC_INT_CCM            63
-#define MXC_INT_IIM            62
-#define MXC_INT_SAHARA         59
-#define MXC_INT_SCC_SCM                58
-#define MXC_INT_SCC_SMN                57
-#define MXC_INT_USB3           56
-#define MXC_INT_USB2           55
-#define MXC_INT_USB1           54
-#define MXC_INT_VPU            53
-#define MXC_INT_FEC            50
-#define MXC_INT_UART5          49
-#define MXC_INT_UART6          48
-#define MXC_INT_ATA            30
-#define MXC_INT_SDHC3          9
-#define MXC_INT_SDHC           7
-#define MXC_INT_RTIC           5
-#define MXC_INT_GPT4           4
-#define MXC_INT_GPT5           3
-#define MXC_INT_GPT6           2
-#define MXC_INT_I2C2           1
+#define MX27_INT_I2C2          1
+#define MX27_INT_GPT6          2
+#define MX27_INT_GPT5          3
+#define MX27_INT_GPT4          4
+#define MX27_INT_RTIC          5
+#define MX27_INT_CSPI3         6
+#define MX27_INT_SDHC          7
+#define MX27_INT_GPIO          8
+#define MX27_INT_SDHC3         9
+#define MX27_INT_SDHC2         10
+#define MX27_INT_SDHC1         11
+#define MX27_INT_I2C           12
+#define MX27_INT_SSI2          13
+#define MX27_INT_SSI1          14
+#define MX27_INT_CSPI2         15
+#define MX27_INT_CSPI1         16
+#define MX27_INT_UART4         17
+#define MX27_INT_UART3         18
+#define MX27_INT_UART2         19
+#define MX27_INT_UART1         20
+#define MX27_INT_KPP           21
+#define MX27_INT_RTC           22
+#define MX27_INT_PWM           23
+#define MX27_INT_GPT3          24
+#define MX27_INT_GPT2          25
+#define MX27_INT_GPT1          26
+#define MX27_INT_WDOG          27
+#define MX27_INT_PCMCIA                28
+#define MX27_INT_NANDFC                29
+#define MX27_INT_ATA           30
+#define MX27_INT_CSI           31
+#define MX27_INT_DMACH0                32
+#define MX27_INT_DMACH1                33
+#define MX27_INT_DMACH2                34
+#define MX27_INT_DMACH3                35
+#define MX27_INT_DMACH4                36
+#define MX27_INT_DMACH5                37
+#define MX27_INT_DMACH6                38
+#define MX27_INT_DMACH7                39
+#define MX27_INT_DMACH8                40
+#define MX27_INT_DMACH9                41
+#define MX27_INT_DMACH10       42
+#define MX27_INT_DMACH11       43
+#define MX27_INT_DMACH12       44
+#define MX27_INT_DMACH13       45
+#define MX27_INT_DMACH14       46
+#define MX27_INT_DMACH15       47
+#define MX27_INT_UART6         48
+#define MX27_INT_UART5         49
+#define MX27_INT_FEC           50
+#define MX27_INT_EMMAPRP       51
+#define MX27_INT_EMMAPP                52
+#define MX27_INT_VPU           53
+#define MX27_INT_USB1          54
+#define MX27_INT_USB2          55
+#define MX27_INT_USB3          56
+#define MX27_INT_SCC_SMN       57
+#define MX27_INT_SCC_SCM       58
+#define MX27_INT_SAHARA                59
+#define MX27_INT_SLCDC         60
+#define MX27_INT_LCDC          61
+#define MX27_INT_IIM           62
+#define MX27_INT_CCM           63
 
 /* fixed DMA request numbers */
-#define DMA_REQ_NFC             37
-#define DMA_REQ_SDHC3           36
-#define DMA_REQ_UART6_RX        35
-#define DMA_REQ_UART6_TX        34
-#define DMA_REQ_UART5_RX        33
-#define DMA_REQ_UART5_TX        32
-#define DMA_REQ_ATA_RCV         29
-#define DMA_REQ_ATA_TX          28
-#define DMA_REQ_MSHC            4
+#define MX27_DMA_REQ_CSPI3_RX  1
+#define MX27_DMA_REQ_CSPI3_TX  2
+#define MX27_DMA_REQ_EXT       3
+#define MX27_DMA_REQ_MSHC      4
+#define MX27_DMA_REQ_SDHC2     6
+#define MX27_DMA_REQ_SDHC1     7
+#define MX27_DMA_REQ_SSI2_RX0  8
+#define MX27_DMA_REQ_SSI2_TX0  9
+#define MX27_DMA_REQ_SSI2_RX1  10
+#define MX27_DMA_REQ_SSI2_TX1  11
+#define MX27_DMA_REQ_SSI1_RX0  12
+#define MX27_DMA_REQ_SSI1_TX0  13
+#define MX27_DMA_REQ_SSI1_RX1  14
+#define MX27_DMA_REQ_SSI1_TX1  15
+#define MX27_DMA_REQ_CSPI2_RX  16
+#define MX27_DMA_REQ_CSPI2_TX  17
+#define MX27_DMA_REQ_CSPI1_RX  18
+#define MX27_DMA_REQ_CSPI1_TX  19
+#define MX27_DMA_REQ_UART4_RX  20
+#define MX27_DMA_REQ_UART4_TX  21
+#define MX27_DMA_REQ_UART3_RX  22
+#define MX27_DMA_REQ_UART3_TX  23
+#define MX27_DMA_REQ_UART2_RX  24
+#define MX27_DMA_REQ_UART2_TX  25
+#define MX27_DMA_REQ_UART1_RX  26
+#define MX27_DMA_REQ_UART1_TX  27
+#define MX27_DMA_REQ_ATA_TX    28
+#define MX27_DMA_REQ_ATA_RCV   29
+#define MX27_DMA_REQ_CSI_STAT  30
+#define MX27_DMA_REQ_CSI_RX    31
+#define MX27_DMA_REQ_UART5_TX  32
+#define MX27_DMA_REQ_UART5_RX  33
+#define MX27_DMA_REQ_UART6_TX  34
+#define MX27_DMA_REQ_UART6_RX  35
+#define MX27_DMA_REQ_SDHC3     36
+#define MX27_DMA_REQ_NFC       37
 
 /* silicon revisions specific to i.MX27 */
 #define CHIP_REV_1_0           0x00
 extern int mx27_revision(void);
 #endif
 
-/* Mandatory defines used globally */
+/* these should go away */
+#define MSHC_BASE_ADDR MX27_MSHC_BASE_ADDR
+#define GPT5_BASE_ADDR MX27_GPT5_BASE_ADDR
+#define GPT4_BASE_ADDR MX27_GPT4_BASE_ADDR
+#define UART5_BASE_ADDR MX27_UART5_BASE_ADDR
+#define UART6_BASE_ADDR MX27_UART6_BASE_ADDR
+#define I2C2_BASE_ADDR MX27_I2C2_BASE_ADDR
+#define SDHC3_BASE_ADDR MX27_SDHC3_BASE_ADDR
+#define GPT6_BASE_ADDR MX27_GPT6_BASE_ADDR
+#define VPU_BASE_ADDR MX27_VPU_BASE_ADDR
+#define OTG_BASE_ADDR MX27_OTG_BASE_ADDR
+#define SAHARA_BASE_ADDR MX27_SAHARA_BASE_ADDR
+#define IIM_BASE_ADDR MX27_IIM_BASE_ADDR
+#define RTIC_BASE_ADDR MX27_RTIC_BASE_ADDR
+#define FEC_BASE_ADDR MX27_FEC_BASE_ADDR
+#define SCC_BASE_ADDR MX27_SCC_BASE_ADDR
+#define ETB_BASE_ADDR MX27_ETB_BASE_ADDR
+#define ETB_RAM_BASE_ADDR MX27_ETB_RAM_BASE_ADDR
+#define ROMP_BASE_ADDR MX27_ROMP_BASE_ADDR
+#define ATA_BASE_ADDR MX27_ATA_BASE_ADDR
+#define SDRAM_BASE_ADDR MX27_SDRAM_BASE_ADDR
+#define CSD1_BASE_ADDR MX27_CSD1_BASE_ADDR
+#define CS0_BASE_ADDR MX27_CS0_BASE_ADDR
+#define CS1_BASE_ADDR MX27_CS1_BASE_ADDR
+#define CS2_BASE_ADDR MX27_CS2_BASE_ADDR
+#define CS3_BASE_ADDR MX27_CS3_BASE_ADDR
+#define CS4_BASE_ADDR MX27_CS4_BASE_ADDR
+#define CS5_BASE_ADDR MX27_CS5_BASE_ADDR
+#define X_MEMC_BASE_ADDR MX27_X_MEMC_BASE_ADDR
+#define X_MEMC_BASE_ADDR_VIRT MX27_X_MEMC_BASE_ADDR_VIRT
+#define X_MEMC_SIZE MX27_X_MEMC_SIZE
+#define NFC_BASE_ADDR MX27_NFC_BASE_ADDR
+#define SDRAMC_BASE_ADDR MX27_SDRAMC_BASE_ADDR
+#define WEIM_BASE_ADDR MX27_WEIM_BASE_ADDR
+#define M3IF_BASE_ADDR MX27_M3IF_BASE_ADDR
+#define PCMCIA_CTL_BASE_ADDR MX27_PCMCIA_CTL_BASE_ADDR
+#define PCMCIA_MEM_BASE_ADDR MX27_PCMCIA_MEM_BASE_ADDR
+#define IRAM_BASE_ADDR MX27_IRAM_BASE_ADDR
+#define MXC_INT_I2C2 MX27_INT_I2C2
+#define MXC_INT_GPT6 MX27_INT_GPT6
+#define MXC_INT_GPT5 MX27_INT_GPT5
+#define MXC_INT_GPT4 MX27_INT_GPT4
+#define MXC_INT_RTIC MX27_INT_RTIC
+#define MXC_INT_SDHC MX27_INT_SDHC
+#define MXC_INT_SDHC3 MX27_INT_SDHC3
+#define MXC_INT_ATA MX27_INT_ATA
+#define MXC_INT_UART6 MX27_INT_UART6
+#define MXC_INT_UART5 MX27_INT_UART5
+#define MXC_INT_FEC MX27_INT_FEC
+#define MXC_INT_VPU MX27_INT_VPU
+#define MXC_INT_USB1 MX27_INT_USB1
+#define MXC_INT_USB2 MX27_INT_USB2
+#define MXC_INT_USB3 MX27_INT_USB3
+#define MXC_INT_SCC_SMN MX27_INT_SCC_SMN
+#define MXC_INT_SCC_SCM MX27_INT_SCC_SCM
+#define MXC_INT_SAHARA MX27_INT_SAHARA
+#define MXC_INT_IIM MX27_INT_IIM
+#define MXC_INT_CCM MX27_INT_CCM
+#define DMA_REQ_MSHC MX27_DMA_REQ_MSHC
+#define DMA_REQ_ATA_TX MX27_DMA_REQ_ATA_TX
+#define DMA_REQ_ATA_RCV MX27_DMA_REQ_ATA_RCV
+#define DMA_REQ_UART5_TX MX27_DMA_REQ_UART5_TX
+#define DMA_REQ_UART5_RX MX27_DMA_REQ_UART5_RX
+#define DMA_REQ_UART6_TX MX27_DMA_REQ_UART6_TX
+#define DMA_REQ_UART6_RX MX27_DMA_REQ_UART6_RX
+#define DMA_REQ_SDHC3 MX27_DMA_REQ_SDHC3
+#define DMA_REQ_NFC MX27_DMA_REQ_NFC
 
 #endif /* __ASM_ARCH_MXC_MX27_H__ */
index db5d921..f2eaf14 100644 (file)
 
 /* The following addresses are common between i.MX21 and i.MX27 */
 
-/* Register offests */
-#define AIPI_BASE_ADDR          0x10000000
-#define AIPI_BASE_ADDR_VIRT     0xF4000000
-#define AIPI_SIZE               SZ_1M
-
-#define DMA_BASE_ADDR           (AIPI_BASE_ADDR + 0x01000)
-#define WDOG_BASE_ADDR          (AIPI_BASE_ADDR + 0x02000)
-#define GPT1_BASE_ADDR          (AIPI_BASE_ADDR + 0x03000)
-#define GPT2_BASE_ADDR          (AIPI_BASE_ADDR + 0x04000)
-#define GPT3_BASE_ADDR          (AIPI_BASE_ADDR + 0x05000)
-#define PWM_BASE_ADDR           (AIPI_BASE_ADDR + 0x06000)
-#define RTC_BASE_ADDR           (AIPI_BASE_ADDR + 0x07000)
-#define KPP_BASE_ADDR           (AIPI_BASE_ADDR + 0x08000)
-#define OWIRE_BASE_ADDR         (AIPI_BASE_ADDR + 0x09000)
-#define UART1_BASE_ADDR         (AIPI_BASE_ADDR + 0x0A000)
-#define UART2_BASE_ADDR         (AIPI_BASE_ADDR + 0x0B000)
-#define UART3_BASE_ADDR         (AIPI_BASE_ADDR + 0x0C000)
-#define UART4_BASE_ADDR         (AIPI_BASE_ADDR + 0x0D000)
-#define CSPI1_BASE_ADDR         (AIPI_BASE_ADDR + 0x0E000)
-#define CSPI2_BASE_ADDR         (AIPI_BASE_ADDR + 0x0F000)
-#define SSI1_BASE_ADDR          (AIPI_BASE_ADDR + 0x10000)
-#define SSI2_BASE_ADDR          (AIPI_BASE_ADDR + 0x11000)
-#define I2C_BASE_ADDR           (AIPI_BASE_ADDR + 0x12000)
-#define SDHC1_BASE_ADDR         (AIPI_BASE_ADDR + 0x13000)
-#define SDHC2_BASE_ADDR         (AIPI_BASE_ADDR + 0x14000)
-#define GPIO_BASE_ADDR          (AIPI_BASE_ADDR + 0x15000)
-#define AUDMUX_BASE_ADDR        (AIPI_BASE_ADDR + 0x16000)
-#define CSPI3_BASE_ADDR         (AIPI_BASE_ADDR + 0x17000)
-#define LCDC_BASE_ADDR          (AIPI_BASE_ADDR + 0x21000)
-#define SLCDC_BASE_ADDR         (AIPI_BASE_ADDR + 0x22000)
-#define USBOTG_BASE_ADDR        (AIPI_BASE_ADDR + 0x24000)
-#define EMMA_PP_BASE_ADDR       (AIPI_BASE_ADDR + 0x26000)
-#define EMMA_PRP_BASE_ADDR      (AIPI_BASE_ADDR + 0x26400)
-#define CCM_BASE_ADDR           (AIPI_BASE_ADDR + 0x27000)
-#define SYSCTRL_BASE_ADDR       (AIPI_BASE_ADDR + 0x27800)
-#define JAM_BASE_ADDR           (AIPI_BASE_ADDR + 0x3E000)
-#define MAX_BASE_ADDR           (AIPI_BASE_ADDR + 0x3F000)
-
-#define AVIC_BASE_ADDR          0x10040000
-
-#define SAHB1_BASE_ADDR         0x80000000
-#define SAHB1_BASE_ADDR_VIRT    0xF4100000
-#define SAHB1_SIZE              SZ_1M
-
-#define CSI_BASE_ADDR           (SAHB1_BASE_ADDR + 0x0000)
+/* Register offsets */
+#define MX2x_AIPI_BASE_ADDR            0x10000000
+#define MX2x_AIPI_BASE_ADDR_VIRT       0xf4000000
+#define MX2x_AIPI_SIZE                 SZ_1M
+#define MX2x_DMA_BASE_ADDR                     (MX2x_AIPI_BASE_ADDR + 0x01000)
+#define MX2x_WDOG_BASE_ADDR                    (MX2x_AIPI_BASE_ADDR + 0x02000)
+#define MX2x_GPT1_BASE_ADDR                    (MX2x_AIPI_BASE_ADDR + 0x03000)
+#define MX2x_GPT2_BASE_ADDR                    (MX2x_AIPI_BASE_ADDR + 0x04000)
+#define MX2x_GPT3_BASE_ADDR                    (MX2x_AIPI_BASE_ADDR + 0x05000)
+#define MX2x_PWM_BASE_ADDR                     (MX2x_AIPI_BASE_ADDR + 0x06000)
+#define MX2x_RTC_BASE_ADDR                     (MX2x_AIPI_BASE_ADDR + 0x07000)
+#define MX2x_KPP_BASE_ADDR                     (MX2x_AIPI_BASE_ADDR + 0x08000)
+#define MX2x_OWIRE_BASE_ADDR                   (MX2x_AIPI_BASE_ADDR + 0x09000)
+#define MX2x_UART1_BASE_ADDR                   (MX2x_AIPI_BASE_ADDR + 0x0a000)
+#define MX2x_UART2_BASE_ADDR                   (MX2x_AIPI_BASE_ADDR + 0x0b000)
+#define MX2x_UART3_BASE_ADDR                   (MX2x_AIPI_BASE_ADDR + 0x0c000)
+#define MX2x_UART4_BASE_ADDR                   (MX2x_AIPI_BASE_ADDR + 0x0d000)
+#define MX2x_CSPI1_BASE_ADDR                   (MX2x_AIPI_BASE_ADDR + 0x0e000)
+#define MX2x_CSPI2_BASE_ADDR                   (MX2x_AIPI_BASE_ADDR + 0x0f000)
+#define MX2x_SSI1_BASE_ADDR                    (MX2x_AIPI_BASE_ADDR + 0x10000)
+#define MX2x_SSI2_BASE_ADDR                    (MX2x_AIPI_BASE_ADDR + 0x11000)
+#define MX2x_I2C_BASE_ADDR                     (MX2x_AIPI_BASE_ADDR + 0x12000)
+#define MX2x_SDHC1_BASE_ADDR                   (MX2x_AIPI_BASE_ADDR + 0x13000)
+#define MX2x_SDHC2_BASE_ADDR                   (MX2x_AIPI_BASE_ADDR + 0x14000)
+#define MX2x_GPIO_BASE_ADDR                    (MX2x_AIPI_BASE_ADDR + 0x15000)
+#define MX2x_AUDMUX_BASE_ADDR                  (MX2x_AIPI_BASE_ADDR + 0x16000)
+#define MX2x_CSPI3_BASE_ADDR                   (MX2x_AIPI_BASE_ADDR + 0x17000)
+#define MX2x_LCDC_BASE_ADDR                    (MX2x_AIPI_BASE_ADDR + 0x21000)
+#define MX2x_SLCDC_BASE_ADDR                   (MX2x_AIPI_BASE_ADDR + 0x22000)
+#define MX2x_USBOTG_BASE_ADDR                  (MX2x_AIPI_BASE_ADDR + 0x24000)
+#define MX2x_EMMA_PP_BASE_ADDR                 (MX2x_AIPI_BASE_ADDR + 0x26000)
+#define MX2x_EMMA_PRP_BASE_ADDR                        (MX2x_AIPI_BASE_ADDR + 0x26400)
+#define MX2x_CCM_BASE_ADDR                     (MX2x_AIPI_BASE_ADDR + 0x27000)
+#define MX2x_SYSCTRL_BASE_ADDR                 (MX2x_AIPI_BASE_ADDR + 0x27800)
+#define MX2x_JAM_BASE_ADDR                     (MX2x_AIPI_BASE_ADDR + 0x3e000)
+#define MX2x_MAX_BASE_ADDR                     (MX2x_AIPI_BASE_ADDR + 0x3f000)
+
+#define MX2x_AVIC_BASE_ADDR            0x10040000
+
+#define MX2x_SAHB1_BASE_ADDR           0x80000000
+#define MX2x_SAHB1_BASE_ADDR_VIRT      0xf4100000
+#define MX2x_SAHB1_SIZE                        SZ_1M
+#define MX2x_CSI_BASE_ADDR                     (MX2x_SAHB1_BASE_ADDR + 0x0000)
 
 /*
  * This macro defines the physical to virtual address mapping for all the
        (((x) - X_MEMC_BASE_ADDR) + X_MEMC_BASE_ADDR_VIRT)
 
 /* fixed interrupt numbers */
-#define MXC_INT_LCDC           61
-#define MXC_INT_SLCDC          60
-#define MXC_INT_EMMAPP         52
-#define MXC_INT_EMMAPRP                51
-#define MXC_INT_DMACH15                47
-#define MXC_INT_DMACH14                46
-#define MXC_INT_DMACH13                45
-#define MXC_INT_DMACH12                44
-#define MXC_INT_DMACH11                43
-#define MXC_INT_DMACH10                42
-#define MXC_INT_DMACH9         41
-#define MXC_INT_DMACH8         40
-#define MXC_INT_DMACH7         39
-#define MXC_INT_DMACH6         38
-#define MXC_INT_DMACH5         37
-#define MXC_INT_DMACH4         36
-#define MXC_INT_DMACH3         35
-#define MXC_INT_DMACH2         34
-#define MXC_INT_DMACH1         33
-#define MXC_INT_DMACH0         32
-#define MXC_INT_CSI            31
-#define MXC_INT_NANDFC         29
-#define MXC_INT_PCMCIA         28
-#define MXC_INT_WDOG           27
-#define MXC_INT_GPT1           26
-#define MXC_INT_GPT2           25
-#define MXC_INT_GPT3           24
-#define MXC_INT_GPT            INT_GPT1
-#define MXC_INT_PWM            23
-#define MXC_INT_RTC            22
-#define MXC_INT_KPP            21
-#define MXC_INT_UART1          20
-#define MXC_INT_UART2          19
-#define MXC_INT_UART3          18
-#define MXC_INT_UART4          17
-#define MXC_INT_CSPI1          16
-#define MXC_INT_CSPI2          15
-#define MXC_INT_SSI1           14
-#define MXC_INT_SSI2           13
-#define MXC_INT_I2C            12
-#define MXC_INT_SDHC1          11
-#define MXC_INT_SDHC2          10
-#define MXC_INT_GPIO           8
-#define MXC_INT_CSPI3          6
+#define MX2x_INT_CSPI3         6
+#define MX2x_INT_GPIO          8
+#define MX2x_INT_SDHC2         10
+#define MX2x_INT_SDHC1         11
+#define MX2x_INT_I2C           12
+#define MX2x_INT_SSI2          13
+#define MX2x_INT_SSI1          14
+#define MX2x_INT_CSPI2         15
+#define MX2x_INT_CSPI1         16
+#define MX2x_INT_UART4         17
+#define MX2x_INT_UART3         18
+#define MX2x_INT_UART2         19
+#define MX2x_INT_UART1         20
+#define MX2x_INT_KPP           21
+#define MX2x_INT_RTC           22
+#define MX2x_INT_PWM           23
+#define MX2x_INT_GPT3          24
+#define MX2x_INT_GPT2          25
+#define MX2x_INT_GPT1          26
+#define MX2x_INT_WDOG          27
+#define MX2x_INT_PCMCIA                28
+#define MX2x_INT_NANDFC                29
+#define MX2x_INT_CSI           31
+#define MX2x_INT_DMACH0                32
+#define MX2x_INT_DMACH1                33
+#define MX2x_INT_DMACH2                34
+#define MX2x_INT_DMACH3                35
+#define MX2x_INT_DMACH4                36
+#define MX2x_INT_DMACH5                37
+#define MX2x_INT_DMACH6                38
+#define MX2x_INT_DMACH7                39
+#define MX2x_INT_DMACH8                40
+#define MX2x_INT_DMACH9                41
+#define MX2x_INT_DMACH10       42
+#define MX2x_INT_DMACH11       43
+#define MX2x_INT_DMACH12       44
+#define MX2x_INT_DMACH13       45
+#define MX2x_INT_DMACH14       46
+#define MX2x_INT_DMACH15       47
+#define MX2x_INT_EMMAPRP       51
+#define MX2x_INT_EMMAPP                52
+#define MX2x_INT_SLCDC         60
+#define MX2x_INT_LCDC          61
 
 /* fixed DMA request numbers */
-#define DMA_REQ_CSI_RX          31
-#define DMA_REQ_CSI_STAT        30
-#define DMA_REQ_UART1_TX        27
-#define DMA_REQ_UART1_RX        26
-#define DMA_REQ_UART2_TX        25
-#define DMA_REQ_UART2_RX        24
-#define DMA_REQ_UART3_TX        23
-#define DMA_REQ_UART3_RX        22
-#define DMA_REQ_UART4_TX        21
-#define DMA_REQ_UART4_RX        20
-#define DMA_REQ_CSPI1_TX        19
-#define DMA_REQ_CSPI1_RX        18
-#define DMA_REQ_CSPI2_TX        17
-#define DMA_REQ_CSPI2_RX        16
-#define DMA_REQ_SSI1_TX1        15
-#define DMA_REQ_SSI1_RX1        14
-#define DMA_REQ_SSI1_TX0        13
-#define DMA_REQ_SSI1_RX0        12
-#define DMA_REQ_SSI2_TX1        11
-#define DMA_REQ_SSI2_RX1        10
-#define DMA_REQ_SSI2_TX0        9
-#define DMA_REQ_SSI2_RX0        8
-#define DMA_REQ_SDHC1           7
-#define DMA_REQ_SDHC2           6
-#define DMA_REQ_EXT             3
-#define DMA_REQ_CSPI3_TX        2
-#define DMA_REQ_CSPI3_RX        1
+#define MX2x_DMA_REQ_CSPI3_RX  1
+#define MX2x_DMA_REQ_CSPI3_TX  2
+#define MX2x_DMA_REQ_EXT       3
+#define MX2x_DMA_REQ_SDHC2     6
+#define MX2x_DMA_REQ_SDHC1     7
+#define MX2x_DMA_REQ_SSI2_RX0  8
+#define MX2x_DMA_REQ_SSI2_TX0  9
+#define MX2x_DMA_REQ_SSI2_RX1  10
+#define MX2x_DMA_REQ_SSI2_TX1  11
+#define MX2x_DMA_REQ_SSI1_RX0  12
+#define MX2x_DMA_REQ_SSI1_TX0  13
+#define MX2x_DMA_REQ_SSI1_RX1  14
+#define MX2x_DMA_REQ_SSI1_TX1  15
+#define MX2x_DMA_REQ_CSPI2_RX  16
+#define MX2x_DMA_REQ_CSPI2_TX  17
+#define MX2x_DMA_REQ_CSPI1_RX  18
+#define MX2x_DMA_REQ_CSPI1_TX  19
+#define MX2x_DMA_REQ_UART4_RX  20
+#define MX2x_DMA_REQ_UART4_TX  21
+#define MX2x_DMA_REQ_UART3_RX  22
+#define MX2x_DMA_REQ_UART3_TX  23
+#define MX2x_DMA_REQ_UART2_RX  24
+#define MX2x_DMA_REQ_UART2_TX  25
+#define MX2x_DMA_REQ_UART1_RX  26
+#define MX2x_DMA_REQ_UART1_TX  27
+#define MX2x_DMA_REQ_CSI_STAT  30
+#define MX2x_DMA_REQ_CSI_RX    31
+
+/* these should go away */
+#define AIPI_BASE_ADDR MX2x_AIPI_BASE_ADDR
+#define AIPI_BASE_ADDR_VIRT MX2x_AIPI_BASE_ADDR_VIRT
+#define AIPI_SIZE MX2x_AIPI_SIZE
+#define DMA_BASE_ADDR MX2x_DMA_BASE_ADDR
+#define WDOG_BASE_ADDR MX2x_WDOG_BASE_ADDR
+#define GPT1_BASE_ADDR MX2x_GPT1_BASE_ADDR
+#define GPT2_BASE_ADDR MX2x_GPT2_BASE_ADDR
+#define GPT3_BASE_ADDR MX2x_GPT3_BASE_ADDR
+#define PWM_BASE_ADDR MX2x_PWM_BASE_ADDR
+#define RTC_BASE_ADDR MX2x_RTC_BASE_ADDR
+#define KPP_BASE_ADDR MX2x_KPP_BASE_ADDR
+#define OWIRE_BASE_ADDR MX2x_OWIRE_BASE_ADDR
+#define UART1_BASE_ADDR MX2x_UART1_BASE_ADDR
+#define UART2_BASE_ADDR MX2x_UART2_BASE_ADDR
+#define UART3_BASE_ADDR MX2x_UART3_BASE_ADDR
+#define UART4_BASE_ADDR MX2x_UART4_BASE_ADDR
+#define CSPI1_BASE_ADDR MX2x_CSPI1_BASE_ADDR
+#define CSPI2_BASE_ADDR MX2x_CSPI2_BASE_ADDR
+#define SSI1_BASE_ADDR MX2x_SSI1_BASE_ADDR
+#define SSI2_BASE_ADDR MX2x_SSI2_BASE_ADDR
+#define I2C_BASE_ADDR MX2x_I2C_BASE_ADDR
+#define SDHC1_BASE_ADDR MX2x_SDHC1_BASE_ADDR
+#define SDHC2_BASE_ADDR MX2x_SDHC2_BASE_ADDR
+#define GPIO_BASE_ADDR MX2x_GPIO_BASE_ADDR
+#define AUDMUX_BASE_ADDR MX2x_AUDMUX_BASE_ADDR
+#define CSPI3_BASE_ADDR MX2x_CSPI3_BASE_ADDR
+#define LCDC_BASE_ADDR MX2x_LCDC_BASE_ADDR
+#define SLCDC_BASE_ADDR MX2x_SLCDC_BASE_ADDR
+#define USBOTG_BASE_ADDR MX2x_USBOTG_BASE_ADDR
+#define EMMA_PP_BASE_ADDR MX2x_EMMA_PP_BASE_ADDR
+#define EMMA_PRP_BASE_ADDR MX2x_EMMA_PRP_BASE_ADDR
+#define CCM_BASE_ADDR MX2x_CCM_BASE_ADDR
+#define SYSCTRL_BASE_ADDR MX2x_SYSCTRL_BASE_ADDR
+#define JAM_BASE_ADDR MX2x_JAM_BASE_ADDR
+#define MAX_BASE_ADDR MX2x_MAX_BASE_ADDR
+#define AVIC_BASE_ADDR MX2x_AVIC_BASE_ADDR
+#define SAHB1_BASE_ADDR MX2x_SAHB1_BASE_ADDR
+#define SAHB1_BASE_ADDR_VIRT MX2x_SAHB1_BASE_ADDR_VIRT
+#define SAHB1_SIZE MX2x_SAHB1_SIZE
+#define CSI_BASE_ADDR MX2x_CSI_BASE_ADDR
+#define MXC_INT_CSPI3 MX2x_INT_CSPI3
+#define MXC_INT_GPIO MX2x_INT_GPIO
+#define MXC_INT_SDHC2 MX2x_INT_SDHC2
+#define MXC_INT_SDHC1 MX2x_INT_SDHC1
+#define MXC_INT_I2C MX2x_INT_I2C
+#define MXC_INT_SSI2 MX2x_INT_SSI2
+#define MXC_INT_SSI1 MX2x_INT_SSI1
+#define MXC_INT_CSPI2 MX2x_INT_CSPI2
+#define MXC_INT_CSPI1 MX2x_INT_CSPI1
+#define MXC_INT_UART4 MX2x_INT_UART4
+#define MXC_INT_UART3 MX2x_INT_UART3
+#define MXC_INT_UART2 MX2x_INT_UART2
+#define MXC_INT_UART1 MX2x_INT_UART1
+#define MXC_INT_KPP MX2x_INT_KPP
+#define MXC_INT_RTC MX2x_INT_RTC
+#define MXC_INT_PWM MX2x_INT_PWM
+#define MXC_INT_GPT3 MX2x_INT_GPT3
+#define MXC_INT_GPT2 MX2x_INT_GPT2
+#define MXC_INT_GPT1 MX2x_INT_GPT1
+#define MXC_INT_WDOG MX2x_INT_WDOG
+#define MXC_INT_PCMCIA MX2x_INT_PCMCIA
+#define MXC_INT_NANDFC MX2x_INT_NANDFC
+#define MXC_INT_CSI MX2x_INT_CSI
+#define MXC_INT_DMACH0 MX2x_INT_DMACH0
+#define MXC_INT_DMACH1 MX2x_INT_DMACH1
+#define MXC_INT_DMACH2 MX2x_INT_DMACH2
+#define MXC_INT_DMACH3 MX2x_INT_DMACH3
+#define MXC_INT_DMACH4 MX2x_INT_DMACH4
+#define MXC_INT_DMACH5 MX2x_INT_DMACH5
+#define MXC_INT_DMACH6 MX2x_INT_DMACH6
+#define MXC_INT_DMACH7 MX2x_INT_DMACH7
+#define MXC_INT_DMACH8 MX2x_INT_DMACH8
+#define MXC_INT_DMACH9 MX2x_INT_DMACH9
+#define MXC_INT_DMACH10 MX2x_INT_DMACH10
+#define MXC_INT_DMACH11 MX2x_INT_DMACH11
+#define MXC_INT_DMACH12 MX2x_INT_DMACH12
+#define MXC_INT_DMACH13 MX2x_INT_DMACH13
+#define MXC_INT_DMACH14 MX2x_INT_DMACH14
+#define MXC_INT_DMACH15 MX2x_INT_DMACH15
+#define MXC_INT_EMMAPRP MX2x_INT_EMMAPRP
+#define MXC_INT_EMMAPP MX2x_INT_EMMAPP
+#define MXC_INT_SLCDC MX2x_INT_SLCDC
+#define MXC_INT_LCDC MX2x_INT_LCDC
+#define DMA_REQ_CSPI3_RX MX2x_DMA_REQ_CSPI3_RX
+#define DMA_REQ_CSPI3_TX MX2x_DMA_REQ_CSPI3_TX
+#define DMA_REQ_EXT MX2x_DMA_REQ_EXT
+#define DMA_REQ_SDHC2 MX2x_DMA_REQ_SDHC2
+#define DMA_REQ_SDHC1 MX2x_DMA_REQ_SDHC1
+#define DMA_REQ_SSI2_RX0 MX2x_DMA_REQ_SSI2_RX0
+#define DMA_REQ_SSI2_TX0 MX2x_DMA_REQ_SSI2_TX0
+#define DMA_REQ_SSI2_RX1 MX2x_DMA_REQ_SSI2_RX1
+#define DMA_REQ_SSI2_TX1 MX2x_DMA_REQ_SSI2_TX1
+#define DMA_REQ_SSI1_RX0 MX2x_DMA_REQ_SSI1_RX0
+#define DMA_REQ_SSI1_TX0 MX2x_DMA_REQ_SSI1_TX0
+#define DMA_REQ_SSI1_RX1 MX2x_DMA_REQ_SSI1_RX1
+#define DMA_REQ_SSI1_TX1 MX2x_DMA_REQ_SSI1_TX1
+#define DMA_REQ_CSPI2_RX MX2x_DMA_REQ_CSPI2_RX
+#define DMA_REQ_CSPI2_TX MX2x_DMA_REQ_CSPI2_TX
+#define DMA_REQ_CSPI1_RX MX2x_DMA_REQ_CSPI1_RX
+#define DMA_REQ_CSPI1_TX MX2x_DMA_REQ_CSPI1_TX
+#define DMA_REQ_UART4_RX MX2x_DMA_REQ_UART4_RX
+#define DMA_REQ_UART4_TX MX2x_DMA_REQ_UART4_TX
+#define DMA_REQ_UART3_RX MX2x_DMA_REQ_UART3_RX
+#define DMA_REQ_UART3_TX MX2x_DMA_REQ_UART3_TX
+#define DMA_REQ_UART2_RX MX2x_DMA_REQ_UART2_RX
+#define DMA_REQ_UART2_TX MX2x_DMA_REQ_UART2_TX
+#define DMA_REQ_UART1_RX MX2x_DMA_REQ_UART1_RX
+#define DMA_REQ_UART1_TX MX2x_DMA_REQ_UART1_TX
+#define DMA_REQ_CSI_STAT MX2x_DMA_REQ_CSI_STAT
+#define DMA_REQ_CSI_RX MX2x_DMA_REQ_CSI_RX
 
 #endif /* __ASM_ARCH_MXC_MX2x_H__ */
index 14ac0dc..b8b47d1 100644 (file)
 /*
  * IRAM
  */
-#define MX31_IRAM_BASE_ADDR            0x1FFC0000      /* internal ram */
+#define MX31_IRAM_BASE_ADDR            0x1ffc0000      /* internal ram */
 #define MX31_IRAM_SIZE                 SZ_16K
 
-#define MX31_OTG_BASE_ADDR     (AIPS1_BASE_ADDR + 0x00088000)
-#define ATA_BASE_ADDR          (AIPS1_BASE_ADDR + 0x0008C000)
-#define UART4_BASE_ADDR        (AIPS1_BASE_ADDR + 0x000B0000)
-#define UART5_BASE_ADDR        (AIPS1_BASE_ADDR + 0x000B4000)
+#define MX31_L2CC_BASE_ADDR            0x30000000
+#define MX31_L2CC_SIZE                 SZ_1M
 
-#define MMC_SDHC1_BASE_ADDR    (SPBA0_BASE_ADDR + 0x00004000)
-#define MMC_SDHC2_BASE_ADDR    (SPBA0_BASE_ADDR + 0x00008000)
-#define SIM1_BASE_ADDR         (SPBA0_BASE_ADDR + 0x00018000)
-#define IIM_BASE_ADDR          (SPBA0_BASE_ADDR + 0x0001C000)
+#define MX31_AIPS1_BASE_ADDR           0x43f00000
+#define MX31_AIPS1_BASE_ADDR_VIRT      0xfc000000
+#define MX31_AIPS1_SIZE                        SZ_1M
+#define MX31_MAX_BASE_ADDR                     (MX31_AIPS1_BASE_ADDR + 0x04000)
+#define MX31_EVTMON_BASE_ADDR                  (MX31_AIPS1_BASE_ADDR + 0x08000)
+#define MX31_CLKCTL_BASE_ADDR                  (MX31_AIPS1_BASE_ADDR + 0x0c000)
+#define MX31_ETB_SLOT4_BASE_ADDR               (MX31_AIPS1_BASE_ADDR + 0x10000)
+#define MX31_ETB_SLOT5_BASE_ADDR               (MX31_AIPS1_BASE_ADDR + 0x14000)
+#define MX31_ECT_CTIO_BASE_ADDR                        (MX31_AIPS1_BASE_ADDR + 0x18000)
+#define MX31_I2C_BASE_ADDR                     (MX31_AIPS1_BASE_ADDR + 0x80000)
+#define MX31_I2C3_BASE_ADDR                    (MX31_AIPS1_BASE_ADDR + 0x84000)
+#define MX31_OTG_BASE_ADDR                     (MX31_AIPS1_BASE_ADDR + 0x88000)
+#define MX31_ATA_BASE_ADDR                     (MX31_AIPS1_BASE_ADDR + 0x8c000)
+#define MX31_UART1_BASE_ADDR                   (MX31_AIPS1_BASE_ADDR + 0x90000)
+#define MX31_UART2_BASE_ADDR                   (MX31_AIPS1_BASE_ADDR + 0x94000)
+#define MX31_I2C2_BASE_ADDR                    (MX31_AIPS1_BASE_ADDR + 0x98000)
+#define MX31_OWIRE_BASE_ADDR                   (MX31_AIPS1_BASE_ADDR + 0x9c000)
+#define MX31_SSI1_BASE_ADDR                    (MX31_AIPS1_BASE_ADDR + 0xa0000)
+#define MX31_CSPI1_BASE_ADDR                   (MX31_AIPS1_BASE_ADDR + 0xa4000)
+#define MX31_KPP_BASE_ADDR                     (MX31_AIPS1_BASE_ADDR + 0xa8000)
+#define MX31_IOMUXC_BASE_ADDR                  (MX31_AIPS1_BASE_ADDR + 0xac000)
+#define MX31_UART4_BASE_ADDR                   (MX31_AIPS1_BASE_ADDR + 0xb0000)
+#define MX31_UART5_BASE_ADDR                   (MX31_AIPS1_BASE_ADDR + 0xb4000)
+#define MX31_ECT_IP1_BASE_ADDR                 (MX31_AIPS1_BASE_ADDR + 0xb8000)
+#define MX31_ECT_IP2_BASE_ADDR                 (MX31_AIPS1_BASE_ADDR + 0xbc000)
 
-#define CSPI3_BASE_ADDR                (AIPS2_BASE_ADDR + 0x00084000)
-#define FIRI_BASE_ADDR         (AIPS2_BASE_ADDR + 0x0008C000)
-#define SCM_BASE_ADDR          (AIPS2_BASE_ADDR + 0x000AE000)
-#define SMN_BASE_ADDR          (AIPS2_BASE_ADDR + 0x000AF000)
-#define MPEG4_ENC_BASE_ADDR    (AIPS2_BASE_ADDR + 0x000C8000)
+#define MX31_SPBA0_BASE_ADDR           0x50000000
+#define MX31_SPBA0_BASE_ADDR_VIRT      0xfc100000
+#define MX31_SPBA0_SIZE                        SZ_1M
+#define MX31_MMC_SDHC1_BASE_ADDR               (MX31_SPBA0_BASE_ADDR + 0x04000)
+#define MX31_MMC_SDHC2_BASE_ADDR               (MX31_SPBA0_BASE_ADDR + 0x08000)
+#define MX31_UART3_BASE_ADDR                   (MX31_SPBA0_BASE_ADDR + 0x0c000)
+#define MX31_CSPI2_BASE_ADDR                   (MX31_SPBA0_BASE_ADDR + 0x10000)
+#define MX31_SSI2_BASE_ADDR                    (MX31_SPBA0_BASE_ADDR + 0x14000)
+#define MX31_SIM1_BASE_ADDR                    (MX31_SPBA0_BASE_ADDR + 0x18000)
+#define MX31_IIM_BASE_ADDR                     (MX31_SPBA0_BASE_ADDR + 0x1c000)
+#define MX31_ATA_DMA_BASE_ADDR                 (MX31_SPBA0_BASE_ADDR + 0x20000)
+#define MX31_MSHC1_BASE_ADDR                   (MX31_SPBA0_BASE_ADDR + 0x24000)
+#define MX31_SPBA_CTRL_BASE_ADDR               (MX31_SPBA0_BASE_ADDR + 0x3c000)
 
-#define MX31_NFC_BASE_ADDR     (X_MEMC_BASE_ADDR + 0x0000)
+#define MX31_AIPS2_BASE_ADDR           0x53f00000
+#define MX31_AIPS2_BASE_ADDR_VIRT      0xfc200000
+#define MX31_AIPS2_SIZE                        SZ_1M
+#define MX31_CCM_BASE_ADDR                     (MX31_AIPS2_BASE_ADDR + 0x80000)
+#define MX31_CSPI3_BASE_ADDR                   (MX31_AIPS2_BASE_ADDR + 0x84000)
+#define MX31_FIRI_BASE_ADDR                    (MX31_AIPS2_BASE_ADDR + 0x8c000)
+#define MX31_GPT1_BASE_ADDR                    (MX31_AIPS2_BASE_ADDR + 0x90000)
+#define MX31_EPIT1_BASE_ADDR                   (MX31_AIPS2_BASE_ADDR + 0x94000)
+#define MX31_EPIT2_BASE_ADDR                   (MX31_AIPS2_BASE_ADDR + 0x98000)
+#define MX31_GPIO3_BASE_ADDR                   (MX31_AIPS2_BASE_ADDR + 0xa4000)
+#define MX31_SCC_BASE_ADDR                     (MX31_AIPS2_BASE_ADDR + 0xac000)
+#define MX31_SCM_BASE_ADDR                     (MX31_AIPS2_BASE_ADDR + 0xae000)
+#define MX31_SMN_BASE_ADDR                     (MX31_AIPS2_BASE_ADDR + 0xaf000)
+#define MX31_RNGA_BASE_ADDR                    (MX31_AIPS2_BASE_ADDR + 0xb0000)
+#define MX31_IPU_CTRL_BASE_ADDR                        (MX31_AIPS2_BASE_ADDR + 0xc0000)
+#define MX31_AUDMUX_BASE_ADDR                  (MX31_AIPS2_BASE_ADDR + 0xc4000)
+#define MX31_MPEG4_ENC_BASE_ADDR               (MX31_AIPS2_BASE_ADDR + 0xc8000)
+#define MX31_GPIO1_BASE_ADDR                   (MX31_AIPS2_BASE_ADDR + 0xcc000)
+#define MX31_GPIO2_BASE_ADDR                   (MX31_AIPS2_BASE_ADDR + 0xd0000)
+#define MX31_SDMA_BASE_ADDR                    (MX31_AIPS2_BASE_ADDR + 0xd4000)
+#define MX31_RTC_BASE_ADDR                     (MX31_AIPS2_BASE_ADDR + 0xd8000)
+#define MX31_WDOG_BASE_ADDR                    (MX31_AIPS2_BASE_ADDR + 0xdc000)
+#define MX31_PWM_BASE_ADDR                     (MX31_AIPS2_BASE_ADDR + 0xe0000)
+#define MX31_RTIC_BASE_ADDR                    (MX31_AIPS2_BASE_ADDR + 0xec000)
 
-#define MXC_INT_MPEG4_ENCODER  5
-#define MXC_INT_FIRI           7
+#define MX31_ROMP_BASE_ADDR            0x60000000
+#define MX31_ROMP_BASE_ADDR_VIRT       0xfc500000
+#define MX31_ROMP_SIZE                 SZ_1M
+
+#define MX31_AVIC_BASE_ADDR            0x68000000
+#define MX31_AVIC_BASE_ADDR_VIRT       0xfc400000
+#define MX31_AVIC_SIZE                 SZ_1M
+
+#define MX31_IPU_MEM_BASE_ADDR         0x70000000
+#define MX31_CSD0_BASE_ADDR            0x80000000
+#define MX31_CSD1_BASE_ADDR            0x90000000
+
+#define MX31_CS0_BASE_ADDR             0xa0000000
+#define MX31_CS1_BASE_ADDR             0xa8000000
+#define MX31_CS2_BASE_ADDR             0xb0000000
+#define MX31_CS3_BASE_ADDR             0xb2000000
+
+#define MX31_CS4_BASE_ADDR             0xb4000000
+#define MX31_CS4_BASE_ADDR_VIRT                0xf4000000
+#define MX31_CS4_SIZE                  SZ_32M
+
+#define MX31_CS5_BASE_ADDR             0xb6000000
+#define MX31_CS5_BASE_ADDR_VIRT                0xf6000000
+#define MX31_CS5_SIZE                  SZ_32M
+
+#define MX31_X_MEMC_BASE_ADDR          0xb8000000
+#define MX31_X_MEMC_BASE_ADDR_VIRT     0xfc320000
+#define MX31_X_MEMC_SIZE               SZ_64K
+#define MX31_NFC_BASE_ADDR                     (MX31_X_MEMC_BASE_ADDR + 0x0000)
+#define MX31_ESDCTL_BASE_ADDR                  (MX31_X_MEMC_BASE_ADDR + 0x1000)
+#define MX31_WEIM_BASE_ADDR                    (MX31_X_MEMC_BASE_ADDR + 0x2000)
+#define MX31_M3IF_BASE_ADDR                    (MX31_X_MEMC_BASE_ADDR + 0x3000)
+#define MX31_EMI_CTL_BASE_ADDR                 (MX31_X_MEMC_BASE_ADDR + 0x4000)
+#define MX31_PCMCIA_CTL_BASE_ADDR              MX31_EMI_CTL_BASE_ADDR
+
+#define MX31_PCMCIA_MEM_BASE_ADDR      0xbc000000
+
+#define MX31_INT_I2C3          3
+#define MX31_INT_I2C2          4
+#define MX31_INT_MPEG4_ENCODER 5
+#define MX31_INT_RTIC          6
+#define MX31_INT_FIRI          7
 #define MX31_INT_MMC_SDHC2     8
-#define MXC_INT_MMC_SDHC1      9
+#define MX31_INT_MMC_SDHC1     9
+#define MX31_INT_I2C           10
 #define MX31_INT_SSI2          11
 #define MX31_INT_SSI1          12
-#define MXC_INT_MBX            16
-#define MXC_INT_CSPI3          17
-#define MXC_INT_SIM2           20
-#define MXC_INT_SIM1           21
-#define MXC_INT_CCM_DVFS       31
-#define MXC_INT_USB1           35
-#define MXC_INT_USB2           36
-#define MXC_INT_USB3           37
-#define MXC_INT_USB4           38
-#define MXC_INT_MSHC2          40
-#define MXC_INT_UART4          46
-#define MXC_INT_UART5          47
-#define MXC_INT_CCM            53
-#define MXC_INT_PCMCIA         54
+#define MX31_INT_CSPI2         13
+#define MX31_INT_CSPI1         14
+#define MX31_INT_ATA           15
+#define MX31_INT_MBX           16
+#define MX31_INT_CSPI3         17
+#define MX31_INT_UART3         18
+#define MX31_INT_IIM           19
+#define MX31_INT_SIM2          20
+#define MX31_INT_SIM1          21
+#define MX31_INT_RNGA          22
+#define MX31_INT_EVTMON                23
+#define MX31_INT_KPP           24
+#define MX31_INT_RTC           25
+#define MX31_INT_PWM           26
+#define MX31_INT_EPIT2         27
+#define MX31_INT_EPIT1         28
+#define MX31_INT_GPT           29
+#define MX31_INT_POWER_FAIL    30
+#define MX31_INT_CCM_DVFS      31
+#define MX31_INT_UART2         32
+#define MX31_INT_NANDFC                33
+#define MX31_INT_SDMA          34
+#define MX31_INT_USB1          35
+#define MX31_INT_USB2          36
+#define MX31_INT_USB3          37
+#define MX31_INT_USB4          38
+#define MX31_INT_MSHC1         39
+#define MX31_INT_MSHC2         40
+#define MX31_INT_IPU_ERR       41
+#define MX31_INT_IPU_SYN       42
+#define MX31_INT_UART1         45
+#define MX31_INT_UART4         46
+#define MX31_INT_UART5         47
+#define MX31_INT_ECT           48
+#define MX31_INT_SCC_SCM       49
+#define MX31_INT_SCC_SMN       50
+#define MX31_INT_GPIO2         51
+#define MX31_INT_GPIO1         52
+#define MX31_INT_CCM           53
+#define MX31_INT_PCMCIA                54
+#define MX31_INT_WDOG          55
+#define MX31_INT_GPIO3         56
+#define MX31_INT_EXT_POWER     58
+#define MX31_INT_EXT_TEMPER    59
+#define MX31_INT_EXT_SENSOR60  60
+#define MX31_INT_EXT_SENSOR61  61
+#define MX31_INT_EXT_WDOG      62
+#define MX31_INT_EXT_TV                63
+
+#define MX31_PROD_SIGNATURE            0x1     /* For MX31 */
+
+/* silicon revisions specific to i.MX31 */
+#define MX31_CHIP_REV_1_0              0x10
+#define MX31_CHIP_REV_1_1              0x11
+#define MX31_CHIP_REV_1_2              0x12
+#define MX31_CHIP_REV_1_3              0x13
+#define MX31_CHIP_REV_2_0              0x20
+#define MX31_CHIP_REV_2_1              0x21
+#define MX31_CHIP_REV_2_2              0x22
+#define MX31_CHIP_REV_2_3              0x23
+#define MX31_CHIP_REV_3_0              0x30
+#define MX31_CHIP_REV_3_1              0x31
+#define MX31_CHIP_REV_3_2              0x32
+
+#define MX31_SYSTEM_REV_MIN            MX31_CHIP_REV_1_0
+#define MX31_SYSTEM_REV_NUM            3
 
+/* these should go away */
+#define ATA_BASE_ADDR MX31_ATA_BASE_ADDR
+#define UART4_BASE_ADDR MX31_UART4_BASE_ADDR
+#define UART5_BASE_ADDR MX31_UART5_BASE_ADDR
+#define MMC_SDHC1_BASE_ADDR MX31_MMC_SDHC1_BASE_ADDR
+#define MMC_SDHC2_BASE_ADDR MX31_MMC_SDHC2_BASE_ADDR
+#define SIM1_BASE_ADDR MX31_SIM1_BASE_ADDR
+#define IIM_BASE_ADDR MX31_IIM_BASE_ADDR
+#define CSPI3_BASE_ADDR MX31_CSPI3_BASE_ADDR
+#define FIRI_BASE_ADDR MX31_FIRI_BASE_ADDR
+#define SCM_BASE_ADDR MX31_SCM_BASE_ADDR
+#define SMN_BASE_ADDR MX31_SMN_BASE_ADDR
+#define MPEG4_ENC_BASE_ADDR MX31_MPEG4_ENC_BASE_ADDR
+#define MXC_INT_MPEG4_ENCODER MX31_INT_MPEG4_ENCODER
+#define MXC_INT_FIRI MX31_INT_FIRI
+#define MXC_INT_MMC_SDHC1 MX31_INT_MMC_SDHC1
+#define MXC_INT_MBX MX31_INT_MBX
+#define MXC_INT_CSPI3 MX31_INT_CSPI3
+#define MXC_INT_SIM2 MX31_INT_SIM2
+#define MXC_INT_SIM1 MX31_INT_SIM1
+#define MXC_INT_CCM_DVFS MX31_INT_CCM_DVFS
+#define MXC_INT_USB1 MX31_INT_USB1
+#define MXC_INT_USB2 MX31_INT_USB2
+#define MXC_INT_USB3 MX31_INT_USB3
+#define MXC_INT_USB4 MX31_INT_USB4
+#define MXC_INT_MSHC2 MX31_INT_MSHC2
+#define MXC_INT_UART4 MX31_INT_UART4
+#define MXC_INT_UART5 MX31_INT_UART5
+#define MXC_INT_CCM MX31_INT_CCM
+#define MXC_INT_PCMCIA MX31_INT_PCMCIA
index ab4cfec..af871bc 100644 (file)
  * IRAM
  */
 #define MX35_IRAM_BASE_ADDR            0x10000000      /* internal ram */
-#define MX35_IRAM_SIZE         SZ_128K
+#define MX35_IRAM_SIZE                 SZ_128K
 
-#define MXC_FEC_BASE_ADDR      0x50038000
-#define MX35_OTG_BASE_ADDR     0x53ff4000
-#define MX35_NFC_BASE_ADDR     0xBB000000
+#define MX35_L2CC_BASE_ADDR            0x30000000
+#define MX35_L2CC_SIZE                 SZ_1M
+
+#define MX35_AIPS1_BASE_ADDR           0x43f00000
+#define MX35_AIPS1_BASE_ADDR_VIRT      0xfc000000
+#define MX35_AIPS1_SIZE                        SZ_1M
+#define MX35_MAX_BASE_ADDR                     (MX35_AIPS1_BASE_ADDR + 0x04000)
+#define MX35_EVTMON_BASE_ADDR                  (MX35_AIPS1_BASE_ADDR + 0x08000)
+#define MX35_CLKCTL_BASE_ADDR                  (MX35_AIPS1_BASE_ADDR + 0x0c000)
+#define MX35_ETB_SLOT4_BASE_ADDR               (MX35_AIPS1_BASE_ADDR + 0x10000)
+#define MX35_ETB_SLOT5_BASE_ADDR               (MX35_AIPS1_BASE_ADDR + 0x14000)
+#define MX35_ECT_CTIO_BASE_ADDR                        (MX35_AIPS1_BASE_ADDR + 0x18000)
+#define MX35_I2C_BASE_ADDR                     (MX35_AIPS1_BASE_ADDR + 0x80000)
+#define MX35_I2C3_BASE_ADDR                    (MX35_AIPS1_BASE_ADDR + 0x84000)
+#define MX35_UART1_BASE_ADDR                   (MX35_AIPS1_BASE_ADDR + 0x90000)
+#define MX35_UART2_BASE_ADDR                   (MX35_AIPS1_BASE_ADDR + 0x94000)
+#define MX35_I2C2_BASE_ADDR                    (MX35_AIPS1_BASE_ADDR + 0x98000)
+#define MX35_OWIRE_BASE_ADDR                   (MX35_AIPS1_BASE_ADDR + 0x9c000)
+#define MX35_SSI1_BASE_ADDR                    (MX35_AIPS1_BASE_ADDR + 0xa0000)
+#define MX35_CSPI1_BASE_ADDR                   (MX35_AIPS1_BASE_ADDR + 0xa4000)
+#define MX35_KPP_BASE_ADDR                     (MX35_AIPS1_BASE_ADDR + 0xa8000)
+#define MX35_IOMUXC_BASE_ADDR                  (MX35_AIPS1_BASE_ADDR + 0xac000)
+#define MX35_ECT_IP1_BASE_ADDR                 (MX35_AIPS1_BASE_ADDR + 0xb8000)
+#define MX35_ECT_IP2_BASE_ADDR                 (MX35_AIPS1_BASE_ADDR + 0xbc000)
+
+#define MX35_SPBA0_BASE_ADDR           0x50000000
+#define MX35_SPBA0_BASE_ADDR_VIRT      0xfc100000
+#define MX35_SPBA0_SIZE                        SZ_1M
+#define MX35_UART3_BASE_ADDR                   (MX35_SPBA0_BASE_ADDR + 0x0c000)
+#define MX35_CSPI2_BASE_ADDR                   (MX35_SPBA0_BASE_ADDR + 0x10000)
+#define MX35_SSI2_BASE_ADDR                    (MX35_SPBA0_BASE_ADDR + 0x14000)
+#define MX35_ATA_DMA_BASE_ADDR                 (MX35_SPBA0_BASE_ADDR + 0x20000)
+#define MX35_MSHC1_BASE_ADDR                   (MX35_SPBA0_BASE_ADDR + 0x24000)
+#define MX35_FEC_BASE_ADDR             0x50038000
+#define MX35_SPBA_CTRL_BASE_ADDR               (MX35_SPBA0_BASE_ADDR + 0x3c000)
+
+#define MX35_AIPS2_BASE_ADDR           0x53f00000
+#define MX35_AIPS2_BASE_ADDR_VIRT      0xfc200000
+#define MX35_AIPS2_SIZE                        SZ_1M
+#define MX35_CCM_BASE_ADDR                     (MX35_AIPS2_BASE_ADDR + 0x80000)
+#define MX35_GPT1_BASE_ADDR                    (MX35_AIPS2_BASE_ADDR + 0x90000)
+#define MX35_EPIT1_BASE_ADDR                   (MX35_AIPS2_BASE_ADDR + 0x94000)
+#define MX35_EPIT2_BASE_ADDR                   (MX35_AIPS2_BASE_ADDR + 0x98000)
+#define MX35_GPIO3_BASE_ADDR                   (MX35_AIPS2_BASE_ADDR + 0xa4000)
+#define MX35_SCC_BASE_ADDR                     (MX35_AIPS2_BASE_ADDR + 0xac000)
+#define MX35_RNGA_BASE_ADDR                    (MX35_AIPS2_BASE_ADDR + 0xb0000)
+#define MX35_IPU_CTRL_BASE_ADDR                        (MX35_AIPS2_BASE_ADDR + 0xc0000)
+#define MX35_AUDMUX_BASE_ADDR                  (MX35_AIPS2_BASE_ADDR + 0xc4000)
+#define MX35_GPIO1_BASE_ADDR                   (MX35_AIPS2_BASE_ADDR + 0xcc000)
+#define MX35_GPIO2_BASE_ADDR                   (MX35_AIPS2_BASE_ADDR + 0xd0000)
+#define MX35_SDMA_BASE_ADDR                    (MX35_AIPS2_BASE_ADDR + 0xd4000)
+#define MX35_RTC_BASE_ADDR                     (MX35_AIPS2_BASE_ADDR + 0xd8000)
+#define MX35_WDOG_BASE_ADDR                    (MX35_AIPS2_BASE_ADDR + 0xdc000)
+#define MX35_PWM_BASE_ADDR                     (MX35_AIPS2_BASE_ADDR + 0xe0000)
+#define MX35_RTIC_BASE_ADDR                    (MX35_AIPS2_BASE_ADDR + 0xec000)
+#define MX35_OTG_BASE_ADDR             0x53ff4000
+
+#define MX35_ROMP_BASE_ADDR            0x60000000
+#define MX35_ROMP_BASE_ADDR_VIRT       0xfc500000
+#define MX35_ROMP_SIZE                 SZ_1M
+
+#define MX35_AVIC_BASE_ADDR            0x68000000
+#define MX35_AVIC_BASE_ADDR_VIRT       0xfc400000
+#define MX35_AVIC_SIZE                 SZ_1M
+
+/*
+ * Memory regions and CS
+ */
+#define MX35_IPU_MEM_BASE_ADDR         0x70000000
+#define MX35_CSD0_BASE_ADDR            0x80000000
+#define MX35_CSD1_BASE_ADDR            0x90000000
+
+#define MX35_CS0_BASE_ADDR             0xa0000000
+#define MX35_CS1_BASE_ADDR             0xa8000000
+#define MX35_CS2_BASE_ADDR             0xb0000000
+#define MX35_CS3_BASE_ADDR             0xb2000000
+
+#define MX35_CS4_BASE_ADDR             0xb4000000
+#define MX35_CS4_BASE_ADDR_VIRT                0xf4000000
+#define MX35_CS4_SIZE                  SZ_32M
+
+#define MX35_CS5_BASE_ADDR             0xb6000000
+#define MX35_CS5_BASE_ADDR_VIRT                0xf6000000
+#define MX35_CS5_SIZE                  SZ_32M
+
+/*
+ * NAND, SDRAM, WEIM, M3IF, EMI controllers
+ */
+#define MX35_X_MEMC_BASE_ADDR          0xb8000000
+#define MX35_X_MEMC_BASE_ADDR_VIRT     0xfc320000
+#define MX35_X_MEMC_SIZE               SZ_64K
+#define MX35_ESDCTL_BASE_ADDR                  (MX35_X_MEMC_BASE_ADDR + 0x1000)
+#define MX35_WEIM_BASE_ADDR                    (MX35_X_MEMC_BASE_ADDR + 0x2000)
+#define MX35_M3IF_BASE_ADDR                    (MX35_X_MEMC_BASE_ADDR + 0x3000)
+#define MX35_EMI_CTL_BASE_ADDR                 (MX35_X_MEMC_BASE_ADDR + 0x4000)
+#define MX35_PCMCIA_CTL_BASE_ADDR              MX35_EMI_CTL_BASE_ADDR
+
+#define MX35_NFC_BASE_ADDR             0xbb000000
+#define MX35_PCMCIA_MEM_BASE_ADDR      0xbc000000
 
 /*
  * Interrupt numbers
  */
-#define MXC_INT_OWIRE          2
+#define MX35_INT_OWIRE         2
+#define MX35_INT_I2C3          3
+#define MX35_INT_I2C2          4
+#define MX35_INT_RTIC          6
 #define MX35_INT_MMC_SDHC1     7
-#define MXC_INT_MMC_SDHC2      8
-#define MXC_INT_MMC_SDHC3      9
+#define MX35_INT_MMC_SDHC2     8
+#define MX35_INT_MMC_SDHC3     9
+#define MX35_INT_I2C           10
 #define MX35_INT_SSI1          11
 #define MX35_INT_SSI2          12
-#define MXC_INT_GPU2D          16
-#define MXC_INT_ASRC           17
-#define MXC_INT_USBHS          35
-#define MXC_INT_USBOTG         37
-#define MXC_INT_ESAI           40
-#define MXC_INT_CAN1           43
-#define MXC_INT_CAN2           44
-#define MXC_INT_MLB            46
-#define MXC_INT_SPDIF          47
-#define MXC_INT_FEC            57
+#define MX35_INT_CSPI2         13
+#define MX35_INT_CSPI1         14
+#define MX35_INT_ATA           15
+#define MX35_INT_GPU2D         16
+#define MX35_INT_ASRC          17
+#define MX35_INT_UART3         18
+#define MX35_INT_IIM           19
+#define MX35_INT_RNGA          22
+#define MX35_INT_EVTMON                23
+#define MX35_INT_KPP           24
+#define MX35_INT_RTC           25
+#define MX35_INT_PWM           26
+#define MX35_INT_EPIT2         27
+#define MX35_INT_EPIT1         28
+#define MX35_INT_GPT           29
+#define MX35_INT_POWER_FAIL    30
+#define MX35_INT_UART2         32
+#define MX35_INT_NANDFC                33
+#define MX35_INT_SDMA          34
+#define MX35_INT_USBHS         35
+#define MX35_INT_USBOTG                37
+#define MX35_INT_MSHC1         39
+#define MX35_INT_ESAI          40
+#define MX35_INT_IPU_ERR       41
+#define MX35_INT_IPU_SYN       42
+#define MX35_INT_CAN1          43
+#define MX35_INT_CAN2          44
+#define MX35_INT_UART1         45
+#define MX35_INT_MLB           46
+#define MX35_INT_SPDIF         47
+#define MX35_INT_ECT           48
+#define MX35_INT_SCC_SCM       49
+#define MX35_INT_SCC_SMN       50
+#define MX35_INT_GPIO2         51
+#define MX35_INT_GPIO1         52
+#define MX35_INT_WDOG          55
+#define MX35_INT_GPIO3         56
+#define MX35_INT_FEC           57
+#define MX35_INT_EXT_POWER     58
+#define MX35_INT_EXT_TEMPER    59
+#define MX35_INT_EXT_SENSOR60  60
+#define MX35_INT_EXT_SENSOR61  61
+#define MX35_INT_EXT_WDOG      62
+#define MX35_INT_EXT_TV                63
+
+#define MX35_PROD_SIGNATURE            0x1     /* For MX31 */
+
+/* silicon revisions specific to i.MX31 */
+#define MX35_CHIP_REV_1_0              0x10
+#define MX35_CHIP_REV_1_1              0x11
+#define MX35_CHIP_REV_1_2              0x12
+#define MX35_CHIP_REV_1_3              0x13
+#define MX35_CHIP_REV_2_0              0x20
+#define MX35_CHIP_REV_2_1              0x21
+#define MX35_CHIP_REV_2_2              0x22
+#define MX35_CHIP_REV_2_3              0x23
+#define MX35_CHIP_REV_3_0              0x30
+#define MX35_CHIP_REV_3_1              0x31
+#define MX35_CHIP_REV_3_2              0x32
+
+#define MX35_SYSTEM_REV_MIN            MX35_CHIP_REV_1_0
+#define MX35_SYSTEM_REV_NUM            3
 
+/* these should go away */
+#define MXC_FEC_BASE_ADDR MX35_FEC_BASE_ADDR
+#define MXC_INT_OWIRE MX35_INT_OWIRE
+#define MXC_INT_MMC_SDHC2 MX35_INT_MMC_SDHC2
+#define MXC_INT_MMC_SDHC3 MX35_INT_MMC_SDHC3
+#define MXC_INT_GPU2D MX35_INT_GPU2D
+#define MXC_INT_ASRC MX35_INT_ASRC
+#define MXC_INT_USBHS MX35_INT_USBHS
+#define MXC_INT_USBOTG MX35_INT_USBOTG
+#define MXC_INT_ESAI MX35_INT_ESAI
+#define MXC_INT_CAN1 MX35_INT_CAN1
+#define MXC_INT_CAN2 MX35_INT_CAN2
+#define MXC_INT_MLB MX35_INT_MLB
+#define MXC_INT_SPDIF MX35_INT_SPDIF
+#define MXC_INT_FEC MX35_INT_FEC
index 009f444..be69272 100644 (file)
  *             C0000000        64M     PCMCIA/CF
  */
 
-#define CS0_BASE_ADDR          0xA0000000
-#define CS1_BASE_ADDR          0xA8000000
-#define CS2_BASE_ADDR          0xB0000000
-#define CS3_BASE_ADDR          0xB2000000
-
-#define CS4_BASE_ADDR          0xB4000000
-#define CS4_BASE_ADDR_VIRT     0xF4000000
-#define CS4_SIZE               SZ_32M
-
-#define CS5_BASE_ADDR          0xB6000000
-#define CS5_BASE_ADDR_VIRT     0xF6000000
-#define CS5_SIZE               SZ_32M
-
-#define PCMCIA_MEM_BASE_ADDR   0xBC000000
-
 /*
  * L2CC
  */
-#define L2CC_BASE_ADDR         0x30000000
-#define L2CC_SIZE              SZ_1M
+#define MX3x_L2CC_BASE_ADDR            0x30000000
+#define MX3x_L2CC_SIZE                 SZ_1M
 
 /*
  * AIPS 1
  */
-#define AIPS1_BASE_ADDR                0x43F00000
-#define AIPS1_BASE_ADDR_VIRT   0xFC000000
-#define AIPS1_SIZE             SZ_1M
-
-#define MAX_BASE_ADDR          (AIPS1_BASE_ADDR + 0x00004000)
-#define EVTMON_BASE_ADDR       (AIPS1_BASE_ADDR + 0x00008000)
-#define CLKCTL_BASE_ADDR       (AIPS1_BASE_ADDR + 0x0000C000)
-#define ETB_SLOT4_BASE_ADDR    (AIPS1_BASE_ADDR + 0x00010000)
-#define ETB_SLOT5_BASE_ADDR    (AIPS1_BASE_ADDR + 0x00014000)
-#define ECT_CTIO_BASE_ADDR     (AIPS1_BASE_ADDR + 0x00018000)
-#define I2C_BASE_ADDR          (AIPS1_BASE_ADDR + 0x00080000)
-#define I2C3_BASE_ADDR         (AIPS1_BASE_ADDR + 0x00084000)
-#define UART1_BASE_ADDR        (AIPS1_BASE_ADDR + 0x00090000)
-#define UART2_BASE_ADDR        (AIPS1_BASE_ADDR + 0x00094000)
-#define I2C2_BASE_ADDR         (AIPS1_BASE_ADDR + 0x00098000)
-#define OWIRE_BASE_ADDR        (AIPS1_BASE_ADDR + 0x0009C000)
-#define SSI1_BASE_ADDR         (AIPS1_BASE_ADDR + 0x000A0000)
-#define CSPI1_BASE_ADDR        (AIPS1_BASE_ADDR + 0x000A4000)
-#define KPP_BASE_ADDR          (AIPS1_BASE_ADDR + 0x000A8000)
-#define IOMUXC_BASE_ADDR       (AIPS1_BASE_ADDR + 0x000AC000)
-#define ECT_IP1_BASE_ADDR      (AIPS1_BASE_ADDR + 0x000B8000)
-#define ECT_IP2_BASE_ADDR      (AIPS1_BASE_ADDR + 0x000BC000)
+#define MX3x_AIPS1_BASE_ADDR           0x43f00000
+#define MX3x_AIPS1_BASE_ADDR_VIRT      0xfc000000
+#define MX3x_AIPS1_SIZE                        SZ_1M
+#define MX3x_MAX_BASE_ADDR                     (MX3x_AIPS1_BASE_ADDR + 0x04000)
+#define MX3x_EVTMON_BASE_ADDR                  (MX3x_AIPS1_BASE_ADDR + 0x08000)
+#define MX3x_CLKCTL_BASE_ADDR                  (MX3x_AIPS1_BASE_ADDR + 0x0c000)
+#define MX3x_ETB_SLOT4_BASE_ADDR               (MX3x_AIPS1_BASE_ADDR + 0x10000)
+#define MX3x_ETB_SLOT5_BASE_ADDR               (MX3x_AIPS1_BASE_ADDR + 0x14000)
+#define MX3x_ECT_CTIO_BASE_ADDR                        (MX3x_AIPS1_BASE_ADDR + 0x18000)
+#define MX3x_I2C_BASE_ADDR                     (MX3x_AIPS1_BASE_ADDR + 0x80000)
+#define MX3x_I2C3_BASE_ADDR                    (MX3x_AIPS1_BASE_ADDR + 0x84000)
+#define MX3x_UART1_BASE_ADDR                   (MX3x_AIPS1_BASE_ADDR + 0x90000)
+#define MX3x_UART2_BASE_ADDR                   (MX3x_AIPS1_BASE_ADDR + 0x94000)
+#define MX3x_I2C2_BASE_ADDR                    (MX3x_AIPS1_BASE_ADDR + 0x98000)
+#define MX3x_OWIRE_BASE_ADDR                   (MX3x_AIPS1_BASE_ADDR + 0x9c000)
+#define MX3x_SSI1_BASE_ADDR                    (MX3x_AIPS1_BASE_ADDR + 0xa0000)
+#define MX3x_CSPI1_BASE_ADDR                   (MX3x_AIPS1_BASE_ADDR + 0xa4000)
+#define MX3x_KPP_BASE_ADDR                     (MX3x_AIPS1_BASE_ADDR + 0xa8000)
+#define MX3x_IOMUXC_BASE_ADDR                  (MX3x_AIPS1_BASE_ADDR + 0xac000)
+#define MX3x_ECT_IP1_BASE_ADDR                 (MX3x_AIPS1_BASE_ADDR + 0xb8000)
+#define MX3x_ECT_IP2_BASE_ADDR                 (MX3x_AIPS1_BASE_ADDR + 0xbc000)
 
 /*
  * SPBA global module enabled #0
  */
-#define SPBA0_BASE_ADDR        0x50000000
-#define SPBA0_BASE_ADDR_VIRT   0xFC100000
-#define SPBA0_SIZE             SZ_1M
-
-#define UART3_BASE_ADDR        (SPBA0_BASE_ADDR + 0x0000C000)
-#define CSPI2_BASE_ADDR        (SPBA0_BASE_ADDR + 0x00010000)
-#define SSI2_BASE_ADDR         (SPBA0_BASE_ADDR + 0x00014000)
-#define ATA_DMA_BASE_ADDR      (SPBA0_BASE_ADDR + 0x00020000)
-#define MSHC1_BASE_ADDR                (SPBA0_BASE_ADDR + 0x00024000)
-#define SPBA_CTRL_BASE_ADDR    (SPBA0_BASE_ADDR + 0x0003C000)
+#define MX3x_SPBA0_BASE_ADDR           0x50000000
+#define MX3x_SPBA0_BASE_ADDR_VIRT      0xfc100000
+#define MX3x_SPBA0_SIZE                        SZ_1M
+#define MX3x_UART3_BASE_ADDR                   (MX3x_SPBA0_BASE_ADDR + 0x0c000)
+#define MX3x_CSPI2_BASE_ADDR                   (MX3x_SPBA0_BASE_ADDR + 0x10000)
+#define MX3x_SSI2_BASE_ADDR                    (MX3x_SPBA0_BASE_ADDR + 0x14000)
+#define MX3x_ATA_DMA_BASE_ADDR                 (MX3x_SPBA0_BASE_ADDR + 0x20000)
+#define MX3x_MSHC1_BASE_ADDR                   (MX3x_SPBA0_BASE_ADDR + 0x24000)
+#define MX3x_SPBA_CTRL_BASE_ADDR               (MX3x_SPBA0_BASE_ADDR + 0x3c000)
 
 /*
  * AIPS 2
  */
-#define AIPS2_BASE_ADDR                0x53F00000
-#define AIPS2_BASE_ADDR_VIRT   0xFC200000
-#define AIPS2_SIZE             SZ_1M
-#define CCM_BASE_ADDR          (AIPS2_BASE_ADDR + 0x00080000)
-#define GPT1_BASE_ADDR         (AIPS2_BASE_ADDR + 0x00090000)
-#define EPIT1_BASE_ADDR                (AIPS2_BASE_ADDR + 0x00094000)
-#define EPIT2_BASE_ADDR                (AIPS2_BASE_ADDR + 0x00098000)
-#define GPIO3_BASE_ADDR                (AIPS2_BASE_ADDR + 0x000A4000)
-#define SCC_BASE_ADDR          (AIPS2_BASE_ADDR + 0x000AC000)
-#define RNGA_BASE_ADDR         (AIPS2_BASE_ADDR + 0x000B0000)
-#define IPU_CTRL_BASE_ADDR     (AIPS2_BASE_ADDR + 0x000C0000)
-#define AUDMUX_BASE_ADDR       (AIPS2_BASE_ADDR + 0x000C4000)
-#define GPIO1_BASE_ADDR                (AIPS2_BASE_ADDR + 0x000CC000)
-#define GPIO2_BASE_ADDR                (AIPS2_BASE_ADDR + 0x000D0000)
-#define SDMA_BASE_ADDR         (AIPS2_BASE_ADDR + 0x000D4000)
-#define RTC_BASE_ADDR          (AIPS2_BASE_ADDR + 0x000D8000)
-#define WDOG_BASE_ADDR         (AIPS2_BASE_ADDR + 0x000DC000)
-#define PWM_BASE_ADDR          (AIPS2_BASE_ADDR + 0x000E0000)
-#define RTIC_BASE_ADDR         (AIPS2_BASE_ADDR + 0x000EC000)
+#define MX3x_AIPS2_BASE_ADDR           0x53f00000
+#define MX3x_AIPS2_BASE_ADDR_VIRT      0xfc200000
+#define MX3x_AIPS2_SIZE                        SZ_1M
+#define MX3x_CCM_BASE_ADDR                     (MX3x_AIPS2_BASE_ADDR + 0x80000)
+#define MX3x_GPT1_BASE_ADDR                    (MX3x_AIPS2_BASE_ADDR + 0x90000)
+#define MX3x_EPIT1_BASE_ADDR                   (MX3x_AIPS2_BASE_ADDR + 0x94000)
+#define MX3x_EPIT2_BASE_ADDR                   (MX3x_AIPS2_BASE_ADDR + 0x98000)
+#define MX3x_GPIO3_BASE_ADDR                   (MX3x_AIPS2_BASE_ADDR + 0xa4000)
+#define MX3x_SCC_BASE_ADDR                     (MX3x_AIPS2_BASE_ADDR + 0xac000)
+#define MX3x_RNGA_BASE_ADDR                    (MX3x_AIPS2_BASE_ADDR + 0xb0000)
+#define MX3x_IPU_CTRL_BASE_ADDR                        (MX3x_AIPS2_BASE_ADDR + 0xc0000)
+#define MX3x_AUDMUX_BASE_ADDR                  (MX3x_AIPS2_BASE_ADDR + 0xc4000)
+#define MX3x_GPIO1_BASE_ADDR                   (MX3x_AIPS2_BASE_ADDR + 0xcc000)
+#define MX3x_GPIO2_BASE_ADDR                   (MX3x_AIPS2_BASE_ADDR + 0xd0000)
+#define MX3x_SDMA_BASE_ADDR                    (MX3x_AIPS2_BASE_ADDR + 0xd4000)
+#define MX3x_RTC_BASE_ADDR                     (MX3x_AIPS2_BASE_ADDR + 0xd8000)
+#define MX3x_WDOG_BASE_ADDR                    (MX3x_AIPS2_BASE_ADDR + 0xdc000)
+#define MX3x_PWM_BASE_ADDR                     (MX3x_AIPS2_BASE_ADDR + 0xe0000)
+#define MX3x_RTIC_BASE_ADDR                    (MX3x_AIPS2_BASE_ADDR + 0xec000)
 
 /*
  * ROMP and AVIC
  */
-#define ROMP_BASE_ADDR         0x60000000
-#define ROMP_BASE_ADDR_VIRT    0xFC500000
-#define ROMP_SIZE              SZ_1M
+#define MX3x_ROMP_BASE_ADDR            0x60000000
+#define MX3x_ROMP_BASE_ADDR_VIRT       0xfc500000
+#define MX3x_ROMP_SIZE                 SZ_1M
 
-#define AVIC_BASE_ADDR         0x68000000
-#define AVIC_BASE_ADDR_VIRT    0xFC400000
-#define AVIC_SIZE              SZ_1M
+#define MX3x_AVIC_BASE_ADDR            0x68000000
+#define MX3x_AVIC_BASE_ADDR_VIRT       0xfc400000
+#define MX3x_AVIC_SIZE                 SZ_1M
 
 /*
- * NAND, SDRAM, WEIM, M3IF, EMI controllers
+ * Memory regions and CS
  */
-#define X_MEMC_BASE_ADDR       0xB8000000
-#define X_MEMC_BASE_ADDR_VIRT  0xFC320000
-#define X_MEMC_SIZE            SZ_64K
+#define MX3x_IPU_MEM_BASE_ADDR         0x70000000
+#define MX3x_CSD0_BASE_ADDR            0x80000000
+#define MX3x_CSD1_BASE_ADDR            0x90000000
 
-#define ESDCTL_BASE_ADDR       (X_MEMC_BASE_ADDR + 0x1000)
-#define WEIM_BASE_ADDR         (X_MEMC_BASE_ADDR + 0x2000)
-#define M3IF_BASE_ADDR         (X_MEMC_BASE_ADDR + 0x3000)
-#define EMI_CTL_BASE_ADDR      (X_MEMC_BASE_ADDR + 0x4000)
-#define PCMCIA_CTL_BASE_ADDR   EMI_CTL_BASE_ADDR
+#define MX3x_CS0_BASE_ADDR             0xa0000000
+#define MX3x_CS1_BASE_ADDR             0xa8000000
+#define MX3x_CS2_BASE_ADDR             0xb0000000
+#define MX3x_CS3_BASE_ADDR             0xb2000000
+
+#define MX3x_CS4_BASE_ADDR             0xb4000000
+#define MX3x_CS4_BASE_ADDR_VIRT                0xf4000000
+#define MX3x_CS4_SIZE                  SZ_32M
+
+#define MX3x_CS5_BASE_ADDR             0xb6000000
+#define MX3x_CS5_BASE_ADDR_VIRT                0xf6000000
+#define MX3x_CS5_SIZE                  SZ_32M
 
 /*
- * Memory regions and CS
+ * NAND, SDRAM, WEIM, M3IF, EMI controllers
  */
-#define IPU_MEM_BASE_ADDR      0x70000000
-#define CSD0_BASE_ADDR         0x80000000
-#define CSD1_BASE_ADDR         0x90000000
+#define MX3x_X_MEMC_BASE_ADDR          0xb8000000
+#define MX3x_X_MEMC_BASE_ADDR_VIRT     0xfc320000
+#define MX3x_X_MEMC_SIZE               SZ_64K
+#define MX3x_ESDCTL_BASE_ADDR                  (MX3x_X_MEMC_BASE_ADDR + 0x1000)
+#define MX3x_WEIM_BASE_ADDR                    (MX3x_X_MEMC_BASE_ADDR + 0x2000)
+#define MX3x_M3IF_BASE_ADDR                    (MX3x_X_MEMC_BASE_ADDR + 0x3000)
+#define MX3x_EMI_CTL_BASE_ADDR                 (MX3x_X_MEMC_BASE_ADDR + 0x4000)
+#define MX3x_PCMCIA_CTL_BASE_ADDR              MX3x_EMI_CTL_BASE_ADDR
+
+#define MX3x_PCMCIA_MEM_BASE_ADDR      0xbc000000
 
 /*!
  * This macro defines the physical to virtual address mapping for all the
 /*
  * Interrupt numbers
  */
-#define MXC_INT_I2C3           3
-#define MXC_INT_I2C2           4
-#define MXC_INT_RTIC           6
-#define MXC_INT_I2C            10
-#define MXC_INT_CSPI2          13
-#define MXC_INT_CSPI1          14
-#define MXC_INT_ATA            15
-#define MXC_INT_UART3          18
-#define MXC_INT_IIM            19
-#define MXC_INT_RNGA           22
-#define MXC_INT_EVTMON         23
-#define MXC_INT_KPP            24
-#define MXC_INT_RTC            25
-#define MXC_INT_PWM            26
-#define MXC_INT_EPIT2          27
-#define MXC_INT_EPIT1          28
-#define MXC_INT_GPT            29
-#define MXC_INT_POWER_FAIL     30
-#define MXC_INT_UART2          32
-#define MXC_INT_NANDFC         33
-#define MXC_INT_SDMA           34
-#define MXC_INT_MSHC1          39
-#define MXC_INT_IPU_ERR                41
-#define MXC_INT_IPU_SYN                42
-#define MXC_INT_UART1          45
-#define MXC_INT_ECT            48
-#define MXC_INT_SCC_SCM                49
-#define MXC_INT_SCC_SMN                50
-#define MXC_INT_GPIO2          51
-#define MXC_INT_GPIO1          52
-#define MXC_INT_WDOG           55
-#define MXC_INT_GPIO3          56
-#define MXC_INT_EXT_POWER      58
-#define MXC_INT_EXT_TEMPER     59
-#define MXC_INT_EXT_SENSOR60   60
-#define MXC_INT_EXT_SENSOR61   61
-#define MXC_INT_EXT_WDOG       62
-#define MXC_INT_EXT_TV         63
-
-#define PROD_SIGNATURE         0x1     /* For MX31 */
+#define MX3x_INT_I2C3          3
+#define MX3x_INT_I2C2          4
+#define MX3x_INT_RTIC          6
+#define MX3x_INT_I2C           10
+#define MX3x_INT_CSPI2         13
+#define MX3x_INT_CSPI1         14
+#define MX3x_INT_ATA           15
+#define MX3x_INT_UART3         18
+#define MX3x_INT_IIM           19
+#define MX3x_INT_RNGA          22
+#define MX3x_INT_EVTMON                23
+#define MX3x_INT_KPP           24
+#define MX3x_INT_RTC           25
+#define MX3x_INT_PWM           26
+#define MX3x_INT_EPIT2         27
+#define MX3x_INT_EPIT1         28
+#define MX3x_INT_GPT           29
+#define MX3x_INT_POWER_FAIL    30
+#define MX3x_INT_UART2         32
+#define MX3x_INT_NANDFC                33
+#define MX3x_INT_SDMA          34
+#define MX3x_INT_MSHC1         39
+#define MX3x_INT_IPU_ERR       41
+#define MX3x_INT_IPU_SYN       42
+#define MX3x_INT_UART1         45
+#define MX3x_INT_ECT           48
+#define MX3x_INT_SCC_SCM       49
+#define MX3x_INT_SCC_SMN       50
+#define MX3x_INT_GPIO2         51
+#define MX3x_INT_GPIO1         52
+#define MX3x_INT_WDOG          55
+#define MX3x_INT_GPIO3         56
+#define MX3x_INT_EXT_POWER     58
+#define MX3x_INT_EXT_TEMPER    59
+#define MX3x_INT_EXT_SENSOR60  60
+#define MX3x_INT_EXT_SENSOR61  61
+#define MX3x_INT_EXT_WDOG      62
+#define MX3x_INT_EXT_TV                63
+
+#define MX3x_PROD_SIGNATURE            0x1     /* For MX31 */
 
 /* silicon revisions specific to i.MX31 */
-#define CHIP_REV_1_0           0x10
-#define CHIP_REV_1_1           0x11
-#define CHIP_REV_1_2           0x12
-#define CHIP_REV_1_3           0x13
-#define CHIP_REV_2_0           0x20
-#define CHIP_REV_2_1           0x21
-#define CHIP_REV_2_2           0x22
-#define CHIP_REV_2_3           0x23
-#define CHIP_REV_3_0           0x30
-#define CHIP_REV_3_1           0x31
-#define CHIP_REV_3_2           0x32
-
-#define SYSTEM_REV_MIN         CHIP_REV_1_0
-#define SYSTEM_REV_NUM         3
+#define MX3x_CHIP_REV_1_0              0x10
+#define MX3x_CHIP_REV_1_1              0x11
+#define MX3x_CHIP_REV_1_2              0x12
+#define MX3x_CHIP_REV_1_3              0x13
+#define MX3x_CHIP_REV_2_0              0x20
+#define MX3x_CHIP_REV_2_1              0x21
+#define MX3x_CHIP_REV_2_2              0x22
+#define MX3x_CHIP_REV_2_3              0x23
+#define MX3x_CHIP_REV_3_0              0x30
+#define MX3x_CHIP_REV_3_1              0x31
+#define MX3x_CHIP_REV_3_2              0x32
+
+#define MX3x_SYSTEM_REV_MIN            MX3x_CHIP_REV_1_0
+#define MX3x_SYSTEM_REV_NUM            3
 
 /* Mandatory defines used globally */
 
 #if !defined(__ASSEMBLY__) && !defined(__MXC_BOOT_UNCOMPRESS)
 
-extern unsigned int system_rev;
+extern unsigned int mx31_cpu_rev;
+extern void mx31_read_cpu_rev(void);
 
 static inline int mx31_revision(void)
 {
-       return system_rev;
+       return mx31_cpu_rev;
 }
 #endif
 
-#endif /*  __ASM_ARCH_MXC_MX31_H__ */
+/* these should go away */
+#define L2CC_BASE_ADDR MX3x_L2CC_BASE_ADDR
+#define L2CC_SIZE MX3x_L2CC_SIZE
+#define AIPS1_BASE_ADDR MX3x_AIPS1_BASE_ADDR
+#define AIPS1_BASE_ADDR_VIRT MX3x_AIPS1_BASE_ADDR_VIRT
+#define AIPS1_SIZE MX3x_AIPS1_SIZE
+#define MAX_BASE_ADDR MX3x_MAX_BASE_ADDR
+#define EVTMON_BASE_ADDR MX3x_EVTMON_BASE_ADDR
+#define CLKCTL_BASE_ADDR MX3x_CLKCTL_BASE_ADDR
+#define ETB_SLOT4_BASE_ADDR MX3x_ETB_SLOT4_BASE_ADDR
+#define ETB_SLOT5_BASE_ADDR MX3x_ETB_SLOT5_BASE_ADDR
+#define ECT_CTIO_BASE_ADDR MX3x_ECT_CTIO_BASE_ADDR
+#define I2C_BASE_ADDR MX3x_I2C_BASE_ADDR
+#define I2C3_BASE_ADDR MX3x_I2C3_BASE_ADDR
+#define UART1_BASE_ADDR MX3x_UART1_BASE_ADDR
+#define UART2_BASE_ADDR MX3x_UART2_BASE_ADDR
+#define I2C2_BASE_ADDR MX3x_I2C2_BASE_ADDR
+#define OWIRE_BASE_ADDR MX3x_OWIRE_BASE_ADDR
+#define SSI1_BASE_ADDR MX3x_SSI1_BASE_ADDR
+#define CSPI1_BASE_ADDR MX3x_CSPI1_BASE_ADDR
+#define KPP_BASE_ADDR MX3x_KPP_BASE_ADDR
+#define IOMUXC_BASE_ADDR MX3x_IOMUXC_BASE_ADDR
+#define ECT_IP1_BASE_ADDR MX3x_ECT_IP1_BASE_ADDR
+#define ECT_IP2_BASE_ADDR MX3x_ECT_IP2_BASE_ADDR
+#define SPBA0_BASE_ADDR MX3x_SPBA0_BASE_ADDR
+#define SPBA0_BASE_ADDR_VIRT MX3x_SPBA0_BASE_ADDR_VIRT
+#define SPBA0_SIZE MX3x_SPBA0_SIZE
+#define UART3_BASE_ADDR MX3x_UART3_BASE_ADDR
+#define CSPI2_BASE_ADDR MX3x_CSPI2_BASE_ADDR
+#define SSI2_BASE_ADDR MX3x_SSI2_BASE_ADDR
+#define ATA_DMA_BASE_ADDR MX3x_ATA_DMA_BASE_ADDR
+#define MSHC1_BASE_ADDR MX3x_MSHC1_BASE_ADDR
+#define SPBA_CTRL_BASE_ADDR MX3x_SPBA_CTRL_BASE_ADDR
+#define AIPS2_BASE_ADDR MX3x_AIPS2_BASE_ADDR
+#define AIPS2_BASE_ADDR_VIRT MX3x_AIPS2_BASE_ADDR_VIRT
+#define AIPS2_SIZE MX3x_AIPS2_SIZE
+#define CCM_BASE_ADDR MX3x_CCM_BASE_ADDR
+#define GPT1_BASE_ADDR MX3x_GPT1_BASE_ADDR
+#define EPIT1_BASE_ADDR MX3x_EPIT1_BASE_ADDR
+#define EPIT2_BASE_ADDR MX3x_EPIT2_BASE_ADDR
+#define GPIO3_BASE_ADDR MX3x_GPIO3_BASE_ADDR
+#define SCC_BASE_ADDR MX3x_SCC_BASE_ADDR
+#define RNGA_BASE_ADDR MX3x_RNGA_BASE_ADDR
+#define IPU_CTRL_BASE_ADDR MX3x_IPU_CTRL_BASE_ADDR
+#define AUDMUX_BASE_ADDR MX3x_AUDMUX_BASE_ADDR
+#define GPIO1_BASE_ADDR MX3x_GPIO1_BASE_ADDR
+#define GPIO2_BASE_ADDR MX3x_GPIO2_BASE_ADDR
+#define SDMA_BASE_ADDR MX3x_SDMA_BASE_ADDR
+#define RTC_BASE_ADDR MX3x_RTC_BASE_ADDR
+#define WDOG_BASE_ADDR MX3x_WDOG_BASE_ADDR
+#define PWM_BASE_ADDR MX3x_PWM_BASE_ADDR
+#define RTIC_BASE_ADDR MX3x_RTIC_BASE_ADDR
+#define ROMP_BASE_ADDR MX3x_ROMP_BASE_ADDR
+#define ROMP_BASE_ADDR_VIRT MX3x_ROMP_BASE_ADDR_VIRT
+#define ROMP_SIZE MX3x_ROMP_SIZE
+#define AVIC_BASE_ADDR MX3x_AVIC_BASE_ADDR
+#define AVIC_BASE_ADDR_VIRT MX3x_AVIC_BASE_ADDR_VIRT
+#define AVIC_SIZE MX3x_AVIC_SIZE
+#define IPU_MEM_BASE_ADDR MX3x_IPU_MEM_BASE_ADDR
+#define CSD0_BASE_ADDR MX3x_CSD0_BASE_ADDR
+#define CSD1_BASE_ADDR MX3x_CSD1_BASE_ADDR
+#define CS0_BASE_ADDR MX3x_CS0_BASE_ADDR
+#define CS1_BASE_ADDR MX3x_CS1_BASE_ADDR
+#define CS2_BASE_ADDR MX3x_CS2_BASE_ADDR
+#define CS3_BASE_ADDR MX3x_CS3_BASE_ADDR
+#define CS4_BASE_ADDR MX3x_CS4_BASE_ADDR
+#define CS4_BASE_ADDR_VIRT MX3x_CS4_BASE_ADDR_VIRT
+#define CS4_SIZE MX3x_CS4_SIZE
+#define CS5_BASE_ADDR MX3x_CS5_BASE_ADDR
+#define CS5_BASE_ADDR_VIRT MX3x_CS5_BASE_ADDR_VIRT
+#define CS5_SIZE MX3x_CS5_SIZE
+#define X_MEMC_BASE_ADDR MX3x_X_MEMC_BASE_ADDR
+#define X_MEMC_BASE_ADDR_VIRT MX3x_X_MEMC_BASE_ADDR_VIRT
+#define X_MEMC_SIZE MX3x_X_MEMC_SIZE
+#define ESDCTL_BASE_ADDR MX3x_ESDCTL_BASE_ADDR
+#define WEIM_BASE_ADDR MX3x_WEIM_BASE_ADDR
+#define M3IF_BASE_ADDR MX3x_M3IF_BASE_ADDR
+#define EMI_CTL_BASE_ADDR MX3x_EMI_CTL_BASE_ADDR
+#define PCMCIA_CTL_BASE_ADDR MX3x_PCMCIA_CTL_BASE_ADDR
+#define PCMCIA_MEM_BASE_ADDR MX3x_PCMCIA_MEM_BASE_ADDR
+#define MXC_INT_I2C3 MX3x_INT_I2C3
+#define MXC_INT_I2C2 MX3x_INT_I2C2
+#define MXC_INT_RTIC MX3x_INT_RTIC
+#define MXC_INT_I2C MX3x_INT_I2C
+#define MXC_INT_CSPI2 MX3x_INT_CSPI2
+#define MXC_INT_CSPI1 MX3x_INT_CSPI1
+#define MXC_INT_ATA MX3x_INT_ATA
+#define MXC_INT_UART3 MX3x_INT_UART3
+#define MXC_INT_IIM MX3x_INT_IIM
+#define MXC_INT_RNGA MX3x_INT_RNGA
+#define MXC_INT_EVTMON MX3x_INT_EVTMON
+#define MXC_INT_KPP MX3x_INT_KPP
+#define MXC_INT_RTC MX3x_INT_RTC
+#define MXC_INT_PWM MX3x_INT_PWM
+#define MXC_INT_EPIT2 MX3x_INT_EPIT2
+#define MXC_INT_EPIT1 MX3x_INT_EPIT1
+#define MXC_INT_GPT MX3x_INT_GPT
+#define MXC_INT_POWER_FAIL MX3x_INT_POWER_FAIL
+#define MXC_INT_UART2 MX3x_INT_UART2
+#define MXC_INT_NANDFC MX3x_INT_NANDFC
+#define MXC_INT_SDMA MX3x_INT_SDMA
+#define MXC_INT_MSHC1 MX3x_INT_MSHC1
+#define MXC_INT_IPU_ERR MX3x_INT_IPU_ERR
+#define MXC_INT_IPU_SYN MX3x_INT_IPU_SYN
+#define MXC_INT_UART1 MX3x_INT_UART1
+#define MXC_INT_ECT MX3x_INT_ECT
+#define MXC_INT_SCC_SCM MX3x_INT_SCC_SCM
+#define MXC_INT_SCC_SMN MX3x_INT_SCC_SMN
+#define MXC_INT_GPIO2 MX3x_INT_GPIO2
+#define MXC_INT_GPIO1 MX3x_INT_GPIO1
+#define MXC_INT_WDOG MX3x_INT_WDOG
+#define MXC_INT_GPIO3 MX3x_INT_GPIO3
+#define MXC_INT_EXT_POWER MX3x_INT_EXT_POWER
+#define MXC_INT_EXT_TEMPER MX3x_INT_EXT_TEMPER
+#define MXC_INT_EXT_SENSOR60 MX3x_INT_EXT_SENSOR60
+#define MXC_INT_EXT_SENSOR61 MX3x_INT_EXT_SENSOR61
+#define MXC_INT_EXT_WDOG MX3x_INT_EXT_WDOG
+#define MXC_INT_EXT_TV MX3x_INT_EXT_TV
+#define PROD_SIGNATURE MX3x_PROD_SIGNATURE
+#define CHIP_REV_1_0 MX3x_CHIP_REV_1_0
+#define CHIP_REV_1_1 MX3x_CHIP_REV_1_1
+#define CHIP_REV_1_2 MX3x_CHIP_REV_1_2
+#define CHIP_REV_1_3 MX3x_CHIP_REV_1_3
+#define CHIP_REV_2_0 MX3x_CHIP_REV_2_0
+#define CHIP_REV_2_1 MX3x_CHIP_REV_2_1
+#define CHIP_REV_2_2 MX3x_CHIP_REV_2_2
+#define CHIP_REV_2_3 MX3x_CHIP_REV_2_3
+#define CHIP_REV_3_0 MX3x_CHIP_REV_3_0
+#define CHIP_REV_3_1 MX3x_CHIP_REV_3_1
+#define CHIP_REV_3_2 MX3x_CHIP_REV_3_2
+#define SYSTEM_REV_MIN MX3x_SYSTEM_REV_MIN
+#define SYSTEM_REV_NUM MX3x_SYSTEM_REV_NUM
 
+#endif /*  __ASM_ARCH_MXC_MX31_H__ */
diff --git a/arch/arm/plat-mxc/include/mach/ulpi.h b/arch/arm/plat-mxc/include/mach/ulpi.h
new file mode 100644 (file)
index 0000000..96b6ab4
--- /dev/null
@@ -0,0 +1,7 @@
+#ifndef __MACH_ULPI_H
+#define __MACH_ULPI_H
+
+extern struct otg_io_access_ops mxc_ulpi_access_ops;
+
+#endif /* __MACH_ULPI_H */
+
index 082a390..4d5d395 100644 (file)
@@ -83,6 +83,8 @@ static __inline__ void __arch_decomp_setup(unsigned long arch_id)
        case MACH_TYPE_MX27ADS:
        case MACH_TYPE_PCM038:
        case MACH_TYPE_MX21ADS:
+       case MACH_TYPE_PCA100:
+       case MACH_TYPE_MXT_TD60:
                uart_base = MX2X_UART1_BASE_ADDR;
                break;
        case MACH_TYPE_MX31LITE:
@@ -94,6 +96,7 @@ static __inline__ void __arch_decomp_setup(unsigned long arch_id)
        case MACH_TYPE_MX31ADS:
        case MACH_TYPE_MX35_3DS:
        case MACH_TYPE_PCM043:
+       case MACH_TYPE_LILLY1131:
                uart_base = MX3X_UART1_BASE_ADDR;
                break;
        case MACH_TYPE_MAGX_ZN5:
index 851ca99..b318c6a 100644 (file)
 
 static void __iomem *base;
 
-static unsigned long iomux_v3_pad_alloc_map[0x200 / BITS_PER_LONG];
-
 /*
- * setups a single pin:
- *     - reserves the pin so that it is not claimed by another driver
- *     - setups the iomux according to the configuration
+ * setups a single pad in the iomuxer
  */
 int mxc_iomux_v3_setup_pad(struct pad_desc *pad)
 {
-       unsigned int pad_ofs = pad->pad_ctrl_ofs;
-
-       if (test_and_set_bit(pad_ofs >> 2, iomux_v3_pad_alloc_map))
-               return -EBUSY;
        if (pad->mux_ctrl_ofs)
                __raw_writel(pad->mux_mode, base + pad->mux_ctrl_ofs);
 
@@ -66,37 +58,13 @@ int mxc_iomux_v3_setup_multiple_pads(struct pad_desc *pad_list, unsigned count)
        for (i = 0; i < count; i++) {
                ret = mxc_iomux_v3_setup_pad(p);
                if (ret)
-                       goto setup_error;
+                       return ret;
                p++;
        }
        return 0;
-
-setup_error:
-       mxc_iomux_v3_release_multiple_pads(pad_list, i);
-       return ret;
 }
 EXPORT_SYMBOL(mxc_iomux_v3_setup_multiple_pads);
 
-void mxc_iomux_v3_release_pad(struct pad_desc *pad)
-{
-       unsigned int pad_ofs = pad->pad_ctrl_ofs;
-
-       clear_bit(pad_ofs >> 2, iomux_v3_pad_alloc_map);
-}
-EXPORT_SYMBOL(mxc_iomux_v3_release_pad);
-
-void mxc_iomux_v3_release_multiple_pads(struct pad_desc *pad_list, int count)
-{
-       struct pad_desc *p = pad_list;
-       int i;
-
-       for (i = 0; i < count; i++) {
-               mxc_iomux_v3_release_pad(p);
-               p++;
-       }
-}
-EXPORT_SYMBOL(mxc_iomux_v3_release_multiple_pads);
-
 void mxc_iomux_v3_init(void __iomem *iomux_v3_base)
 {
        base = iomux_v3_base;
diff --git a/arch/arm/plat-mxc/ulpi.c b/arch/arm/plat-mxc/ulpi.c
new file mode 100644 (file)
index 0000000..582c6df
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+ * Copyright 2008 Sascha Hauer, Pengutronix <s.hauer@pengutronix.de>
+ * Copyright 2009 Daniel Mack <daniel@caiaq.de>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA  02110-1301, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/usb/otg.h>
+
+#include <mach/ulpi.h>
+
+/* ULPIVIEW register bits */
+#define ULPIVW_WU              (1 << 31)       /* Wakeup */
+#define ULPIVW_RUN             (1 << 30)       /* read/write run */
+#define ULPIVW_WRITE           (1 << 29)       /* 0 = read  1 = write */
+#define ULPIVW_SS              (1 << 27)       /* SyncState */
+#define ULPIVW_PORT_MASK       0x07    /* Port field */
+#define ULPIVW_PORT_SHIFT      24
+#define ULPIVW_ADDR_MASK       0xff    /* data address field */
+#define ULPIVW_ADDR_SHIFT      16
+#define ULPIVW_RDATA_MASK      0xff    /* read data field */
+#define ULPIVW_RDATA_SHIFT     8
+#define ULPIVW_WDATA_MASK      0xff    /* write data field */
+#define ULPIVW_WDATA_SHIFT     0
+
+static int ulpi_poll(void __iomem *view, u32 bit)
+{
+       int timeout = 10000;
+
+       while (timeout--) {
+               u32 data = __raw_readl(view);
+
+               if (!(data & bit))
+                       return 0;
+
+               cpu_relax();
+       };
+
+       printk(KERN_WARNING "timeout polling for ULPI device\n");
+
+       return -ETIMEDOUT;
+}
+
+static int ulpi_read(struct otg_transceiver *otg, u32 reg)
+{
+       int ret;
+       void __iomem *view = otg->io_priv;
+
+       /* make sure interface is running */
+       if (!(__raw_readl(view) & ULPIVW_SS)) {
+               __raw_writel(ULPIVW_WU, view);
+
+               /* wait for wakeup */
+               ret = ulpi_poll(view, ULPIVW_WU);
+               if (ret)
+                       return ret;
+       }
+
+       /* read the register */
+       __raw_writel((ULPIVW_RUN | (reg << ULPIVW_ADDR_SHIFT)), view);
+
+       /* wait for completion */
+       ret = ulpi_poll(view, ULPIVW_RUN);
+       if (ret)
+               return ret;
+
+       return (__raw_readl(view) >> ULPIVW_RDATA_SHIFT) & ULPIVW_RDATA_MASK;
+}
+
+static int ulpi_write(struct otg_transceiver *otg, u32 val, u32 reg)
+{
+       int ret;
+       void __iomem *view = otg->io_priv;
+
+       /* make sure the interface is running */
+       if (!(__raw_readl(view) & ULPIVW_SS)) {
+               __raw_writel(ULPIVW_WU, view);
+               /* wait for wakeup */
+               ret = ulpi_poll(view, ULPIVW_WU);
+               if (ret)
+                       return ret;
+       }
+
+       __raw_writel((ULPIVW_RUN | ULPIVW_WRITE |
+                     (reg << ULPIVW_ADDR_SHIFT) |
+                     ((val & ULPIVW_WDATA_MASK) << ULPIVW_WDATA_SHIFT)), view);
+
+       /* wait for completion */
+       return ulpi_poll(view, ULPIVW_RUN);
+}
+
+struct otg_io_access_ops mxc_ulpi_access_ops = {
+       .read   = ulpi_read,
+       .write  = ulpi_write,
+};
+EXPORT_SYMBOL_GPL(mxc_ulpi_access_ops);
+
diff --git a/arch/arm/plat-nomadik/Kconfig b/arch/arm/plat-nomadik/Kconfig
new file mode 100644 (file)
index 0000000..159daf5
--- /dev/null
@@ -0,0 +1,22 @@
+# We keep common IP's here for Nomadik and other similar
+# familiy of processors from ST-Ericsson. At the moment we have
+# just MTU, others to follow soon.
+
+config PLAT_NOMADIK
+       bool
+       depends on ARCH_NOMADIK || ARCH_U8500
+       default y
+       help
+         Common platform code for Nomadik and other ST-Ericsson
+         platforms.
+
+if PLAT_NOMADIK
+
+config HAS_MTU
+       bool
+       help
+         Support for Multi Timer Unit. MTU provides access
+         to multiple interrupt generating programmable
+         32-bit free running decrementing counters.
+
+endif
diff --git a/arch/arm/plat-nomadik/Makefile b/arch/arm/plat-nomadik/Makefile
new file mode 100644 (file)
index 0000000..37c7cdd
--- /dev/null
@@ -0,0 +1,5 @@
+# arch/arm/plat-nomadik/Makefile
+# Copyright 2009 ST-Ericsson
+# Licensed under GPLv2
+
+obj-$(CONFIG_HAS_MTU)  += timer.o
similarity index 90%
rename from arch/arm/mach-nomadik/include/mach/mtu.h
rename to arch/arm/plat-nomadik/include/plat/mtu.h
index 76da7f0..42c9072 100644 (file)
@@ -1,5 +1,8 @@
-#ifndef __ASM_ARCH_MTU_H
-#define __ASM_ARCH_MTU_H
+#ifndef __PLAT_MTU_H
+#define __PLAT_MTU_H
+
+/* should be set by the platform code */
+extern void __iomem *mtu_base;
 
 /*
  * The MTU device hosts four different counters, with 4 set of
@@ -41,5 +44,5 @@
 #define MTU_PCELL2     0xff8
 #define MTU_PCELL3     0xffC
 
-#endif /* __ASM_ARCH_MTU_H */
+#endif /* __PLAT_MTU_H */
 
similarity index 81%
rename from arch/arm/mach-nomadik/timer.c
rename to arch/arm/plat-nomadik/timer.c
index d1738e7..62f18ad 100644 (file)
 #include <linux/clockchips.h>
 #include <linux/jiffies.h>
 #include <asm/mach/time.h>
-#include <mach/mtu.h>
 
-#define TIMER_CTRL     0x80    /* No divisor */
-#define TIMER_PERIODIC 0x40
-#define TIMER_SZ32BIT  0x02
-
-/* Initial value for SRC control register: all timers use MXTAL/8 source */
-#define SRC_CR_INIT_MASK       0x00007fff
-#define SRC_CR_INIT_VAL                0x2aaa8000
+#include <plat/mtu.h>
 
 static u32     nmdk_count;             /* accumulated count */
 static u32     nmdk_cycle;             /* write-once */
-static __iomem void *mtu_base;
+
+/* setup by the platform code */
+void __iomem *mtu_base;
 
 /*
  * clocksource: the MTU device is a decrementing counters, so we negate
@@ -93,7 +88,7 @@ static struct clock_event_device nmdk_clkevt = {
 static irqreturn_t nmdk_timer_interrupt(int irq, void *dev_id)
 {
        /* ack: "interrupt clear register" */
-       writel( 1 << 0, mtu_base + MTU_ICR);
+       writel(1 << 0, mtu_base + MTU_ICR);
 
        /* we can't count lost ticks, unfortunately */
        nmdk_count += nmdk_cycle;
@@ -125,24 +120,14 @@ static void nmdk_timer_reset(void)
        writel(cr | MTU_CRn_ENA, mtu_base + MTU_CR(0));
 }
 
-static void __init nmdk_timer_init(void)
+void __init nmdk_timer_init(void)
 {
-       u32 src_cr;
        unsigned long rate;
        int bits;
 
        rate = CLOCK_TICK_RATE; /* 2.4MHz */
        nmdk_cycle = (rate + HZ/2) / HZ;
 
-       /* Configure timer sources in "system reset controller" ctrl reg */
-       src_cr = readl(io_p2v(NOMADIK_SRC_BASE));
-       src_cr &= SRC_CR_INIT_MASK;
-       src_cr |= SRC_CR_INIT_VAL;
-       writel(src_cr, io_p2v(NOMADIK_SRC_BASE));
-
-       /* Save global pointer to mtu, used by functions above */
-       mtu_base = io_p2v(NOMADIK_MTU0_BASE);
-
        /* Init the timer and register clocksource */
        nmdk_timer_reset();
 
@@ -150,7 +135,9 @@ static void __init nmdk_timer_init(void)
        bits =  8*sizeof(nmdk_count);
        nmdk_clksrc.mask = CLOCKSOURCE_MASK(bits);
 
-       clocksource_register(&nmdk_clksrc);
+       if (clocksource_register(&nmdk_clksrc))
+               printk(KERN_ERR "timer: failed to initialize clock "
+                       "source %s\n", nmdk_clksrc.name);
 
        /* Register irq and clockevents */
        setup_irq(IRQ_MTU0, &nmdk_timer_irq);
@@ -158,7 +145,3 @@ static void __init nmdk_timer_init(void)
        nmdk_clkevt.cpumask = cpumask_of(0);
        clockevents_register_device(&nmdk_clkevt);
 }
-
-struct sys_timer nomadik_timer = {
-       .init           = nmdk_timer_init,
-};
index 64b3f52..f348ddf 100644 (file)
@@ -165,7 +165,7 @@ config OMAP_DM_TIMER
 choice
        prompt "Low-level debug console UART"
        depends on ARCH_OMAP
-       default OMAP_LL_DEBUG_UART1
+       default OMAP_LL_DEBUG_NONE
 
 config OMAP_LL_DEBUG_UART1
        bool "UART1"
@@ -176,6 +176,9 @@ config OMAP_LL_DEBUG_UART2
 config OMAP_LL_DEBUG_UART3
        bool "UART3"
 
+config OMAP_LL_DEBUG_NONE
+       bool "None"
+
 endchoice
 
 config OMAP_SERIAL_WAKE
index bf880e9..681bfc3 100644 (file)
@@ -24,7 +24,7 @@
 #include <linux/debugfs.h>
 #include <linux/io.h>
 
-#include <mach/clock.h>
+#include <plat/clock.h>
 
 static LIST_HEAD(clocks);
 static DEFINE_MUTEX(clocks_mutex);
index 3a4768d..cc050b3 100644 (file)
 #include <asm/mach/map.h>
 #include <asm/setup.h>
 
-#include <mach/common.h>
-#include <mach/board.h>
-#include <mach/control.h>
-#include <mach/mux.h>
-#include <mach/fpga.h>
+#include <plat/common.h>
+#include <plat/board.h>
+#include <plat/control.h>
+#include <plat/mux.h>
+#include <plat/fpga.h>
 
-#include <mach/clock.h>
+#include <plat/clock.h>
 
 #if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3)
 # include "../mach-omap2/sdrc.h"
@@ -49,6 +49,9 @@ int omap_bootloader_tag_len;
 struct omap_board_config_kernel *omap_board_config;
 int omap_board_config_size;
 
+/* used by omap-smp.c and board-4430sdp.c */
+void __iomem *gic_cpu_base_addr;
+
 static const void *get_config(u16 tag, size_t len, int skip, size_t *len_out)
 {
        struct omap_board_config_kernel *kinfo = NULL;
@@ -224,12 +227,12 @@ static void __init __omap2_set_globals(struct omap_globals *omap2_globals)
 
 static struct omap_globals omap242x_globals = {
        .class  = OMAP242X_CLASS,
-       .tap    = OMAP2_IO_ADDRESS(0x48014000),
-       .sdrc   = OMAP2_IO_ADDRESS(OMAP2420_SDRC_BASE),
-       .sms    = OMAP2_IO_ADDRESS(OMAP2420_SMS_BASE),
-       .ctrl   = OMAP2_IO_ADDRESS(OMAP2420_CTRL_BASE),
-       .prm    = OMAP2_IO_ADDRESS(OMAP2420_PRM_BASE),
-       .cm     = OMAP2_IO_ADDRESS(OMAP2420_CM_BASE),
+       .tap    = OMAP2_L4_IO_ADDRESS(0x48014000),
+       .sdrc   = OMAP2_L3_IO_ADDRESS(OMAP2420_SDRC_BASE),
+       .sms    = OMAP2_L3_IO_ADDRESS(OMAP2420_SMS_BASE),
+       .ctrl   = OMAP2_L4_IO_ADDRESS(OMAP2420_CTRL_BASE),
+       .prm    = OMAP2_L4_IO_ADDRESS(OMAP2420_PRM_BASE),
+       .cm     = OMAP2_L4_IO_ADDRESS(OMAP2420_CM_BASE),
 };
 
 void __init omap2_set_globals_242x(void)
@@ -242,12 +245,12 @@ void __init omap2_set_globals_242x(void)
 
 static struct omap_globals omap243x_globals = {
        .class  = OMAP243X_CLASS,
-       .tap    = OMAP2_IO_ADDRESS(0x4900a000),
-       .sdrc   = OMAP2_IO_ADDRESS(OMAP243X_SDRC_BASE),
-       .sms    = OMAP2_IO_ADDRESS(OMAP243X_SMS_BASE),
-       .ctrl   = OMAP2_IO_ADDRESS(OMAP243X_CTRL_BASE),
-       .prm    = OMAP2_IO_ADDRESS(OMAP2430_PRM_BASE),
-       .cm     = OMAP2_IO_ADDRESS(OMAP2430_CM_BASE),
+       .tap    = OMAP2_L4_IO_ADDRESS(0x4900a000),
+       .sdrc   = OMAP2_L3_IO_ADDRESS(OMAP243X_SDRC_BASE),
+       .sms    = OMAP2_L3_IO_ADDRESS(OMAP243X_SMS_BASE),
+       .ctrl   = OMAP2_L4_IO_ADDRESS(OMAP243X_CTRL_BASE),
+       .prm    = OMAP2_L4_IO_ADDRESS(OMAP2430_PRM_BASE),
+       .cm     = OMAP2_L4_IO_ADDRESS(OMAP2430_CM_BASE),
 };
 
 void __init omap2_set_globals_243x(void)
@@ -260,12 +263,12 @@ void __init omap2_set_globals_243x(void)
 
 static struct omap_globals omap343x_globals = {
        .class  = OMAP343X_CLASS,
-       .tap    = OMAP2_IO_ADDRESS(0x4830A000),
-       .sdrc   = OMAP2_IO_ADDRESS(OMAP343X_SDRC_BASE),
-       .sms    = OMAP2_IO_ADDRESS(OMAP343X_SMS_BASE),
-       .ctrl   = OMAP2_IO_ADDRESS(OMAP343X_CTRL_BASE),
-       .prm    = OMAP2_IO_ADDRESS(OMAP3430_PRM_BASE),
-       .cm     = OMAP2_IO_ADDRESS(OMAP3430_CM_BASE),
+       .tap    = OMAP2_L4_IO_ADDRESS(0x4830A000),
+       .sdrc   = OMAP2_L3_IO_ADDRESS(OMAP343X_SDRC_BASE),
+       .sms    = OMAP2_L3_IO_ADDRESS(OMAP343X_SMS_BASE),
+       .ctrl   = OMAP2_L4_IO_ADDRESS(OMAP343X_CTRL_BASE),
+       .prm    = OMAP2_L4_IO_ADDRESS(OMAP3430_PRM_BASE),
+       .cm     = OMAP2_L4_IO_ADDRESS(OMAP3430_CM_BASE),
 };
 
 void __init omap2_set_globals_343x(void)
@@ -277,10 +280,10 @@ void __init omap2_set_globals_343x(void)
 #if defined(CONFIG_ARCH_OMAP4)
 static struct omap_globals omap4_globals = {
        .class  = OMAP443X_CLASS,
-       .tap    = OMAP2_IO_ADDRESS(0x4830a000),
-       .ctrl   = OMAP2_IO_ADDRESS(OMAP443X_CTRL_BASE),
-       .prm    = OMAP2_IO_ADDRESS(OMAP4430_PRM_BASE),
-       .cm     = OMAP2_IO_ADDRESS(OMAP4430_CM_BASE),
+       .tap    = OMAP2_L4_IO_ADDRESS(0x4830a000),
+       .ctrl   = OMAP2_L4_IO_ADDRESS(OMAP443X_CTRL_BASE),
+       .prm    = OMAP2_L4_IO_ADDRESS(OMAP4430_PRM_BASE),
+       .cm     = OMAP2_L4_IO_ADDRESS(OMAP4430_CM_BASE),
 };
 
 void __init omap2_set_globals_443x(void)
index 341235c..f8ddbdd 100644 (file)
@@ -23,7 +23,7 @@
 #include <linux/io.h>
 
 #include <mach/hardware.h>
-#include <mach/clock.h>
+#include <plat/clock.h>
 #include <asm/system.h>
 
 #define VERY_HI_RATE   900000000
index f668483..09c1107 100644 (file)
@@ -16,7 +16,7 @@
 
 #include <mach/hardware.h>
 
-#include <mach/board.h>
+#include <plat/board.h>
 #include <mach/gpio.h>
 
 
index 9395898..6c768b7 100644 (file)
@@ -18,7 +18,7 @@
 #include <asm/system.h>
 #include <asm/mach-types.h>
 
-#include <mach/fpga.h>
+#include <plat/fpga.h>
 #include <mach/gpio.h>
 
 
index a64b692..f866178 100644 (file)
 #include <asm/mach-types.h>
 #include <asm/mach/map.h>
 
-#include <mach/tc.h>
-#include <mach/control.h>
-#include <mach/board.h>
-#include <mach/mmc.h>
-#include <mach/mux.h>
+#include <plat/tc.h>
+#include <plat/control.h>
+#include <plat/board.h>
+#include <plat/mmc.h>
+#include <plat/mux.h>
 #include <mach/gpio.h>
-#include <mach/menelaus.h>
-#include <mach/mcbsp.h>
-#include <mach/dsp_common.h>
+#include <plat/menelaus.h>
+#include <plat/mcbsp.h>
+#include <plat/dsp_common.h>
 
 #if    defined(CONFIG_OMAP_DSP) || defined(CONFIG_OMAP_DSP_MODULE)
 
@@ -113,17 +113,17 @@ static void omap_init_kp(void)
                omap_cfg_reg(E19_1610_KBR4);
                omap_cfg_reg(N19_1610_KBR5);
        } else if (machine_is_omap_perseus2() || machine_is_omap_fsample()) {
-               omap_cfg_reg(E2_730_KBR0);
-               omap_cfg_reg(J7_730_KBR1);
-               omap_cfg_reg(E1_730_KBR2);
-               omap_cfg_reg(F3_730_KBR3);
-               omap_cfg_reg(D2_730_KBR4);
-
-               omap_cfg_reg(C2_730_KBC0);
-               omap_cfg_reg(D3_730_KBC1);
-               omap_cfg_reg(E4_730_KBC2);
-               omap_cfg_reg(F4_730_KBC3);
-               omap_cfg_reg(E3_730_KBC4);
+               omap_cfg_reg(E2_7XX_KBR0);
+               omap_cfg_reg(J7_7XX_KBR1);
+               omap_cfg_reg(E1_7XX_KBR2);
+               omap_cfg_reg(F3_7XX_KBR3);
+               omap_cfg_reg(D2_7XX_KBR4);
+
+               omap_cfg_reg(C2_7XX_KBC0);
+               omap_cfg_reg(D3_7XX_KBC1);
+               omap_cfg_reg(E4_7XX_KBC2);
+               omap_cfg_reg(F4_7XX_KBC3);
+               omap_cfg_reg(E3_7XX_KBC4);
        } else if (machine_is_omap_h4()) {
                omap_cfg_reg(T19_24XX_KBR0);
                omap_cfg_reg(R19_24XX_KBR1);
index 68eaae3..be4ce07 100644 (file)
@@ -32,9 +32,9 @@
 
 #include <asm/system.h>
 #include <mach/hardware.h>
-#include <mach/dma.h>
+#include <plat/dma.h>
 
-#include <mach/tc.h>
+#include <plat/tc.h>
 
 #undef DEBUG
 
@@ -54,6 +54,12 @@ enum { DMA_CHAIN_STARTED, DMA_CHAIN_NOTSTARTED };
 
 static int enable_1510_mode;
 
+static struct omap_dma_global_context_registers {
+       u32 dma_irqenable_l0;
+       u32 dma_ocp_sysconfig;
+       u32 dma_gcr;
+} omap_dma_global_context;
+
 struct omap_dma_lch {
        int next_lch;
        int dev_id;
@@ -2355,44 +2361,83 @@ void omap_stop_lcd_dma(void)
 }
 EXPORT_SYMBOL(omap_stop_lcd_dma);
 
+void omap_dma_global_context_save(void)
+{
+       omap_dma_global_context.dma_irqenable_l0 =
+               dma_read(IRQENABLE_L0);
+       omap_dma_global_context.dma_ocp_sysconfig =
+               dma_read(OCP_SYSCONFIG);
+       omap_dma_global_context.dma_gcr = dma_read(GCR);
+}
+
+void omap_dma_global_context_restore(void)
+{
+       int ch;
+
+       dma_write(omap_dma_global_context.dma_gcr, GCR);
+       dma_write(omap_dma_global_context.dma_ocp_sysconfig,
+               OCP_SYSCONFIG);
+       dma_write(omap_dma_global_context.dma_irqenable_l0,
+               IRQENABLE_L0);
+
+       /*
+        * A bug in ROM code leaves IRQ status for channels 0 and 1 uncleared
+        * after secure sram context save and restore. Hence we need to
+        * manually clear those IRQs to avoid spurious interrupts. This
+        * affects only secure devices.
+        */
+       if (cpu_is_omap34xx() && (omap_type() != OMAP2_DEVICE_TYPE_GP))
+               dma_write(0x3 , IRQSTATUS_L0);
+
+       for (ch = 0; ch < dma_chan_count; ch++)
+               if (dma_chan[ch].dev_id != -1)
+                       omap_clear_dma(ch);
+}
+
 /*----------------------------------------------------------------------------*/
 
 static int __init omap_init_dma(void)
 {
+       unsigned long base;
        int ch, r;
 
        if (cpu_class_is_omap1()) {
-               omap_dma_base = OMAP1_IO_ADDRESS(OMAP1_DMA_BASE);
+               base = OMAP1_DMA_BASE;
                dma_lch_count = OMAP1_LOGICAL_DMA_CH_COUNT;
        } else if (cpu_is_omap24xx()) {
-               omap_dma_base = OMAP2_IO_ADDRESS(OMAP24XX_DMA4_BASE);
+               base = OMAP24XX_DMA4_BASE;
                dma_lch_count = OMAP_DMA4_LOGICAL_DMA_CH_COUNT;
        } else if (cpu_is_omap34xx()) {
-               omap_dma_base = OMAP2_IO_ADDRESS(OMAP34XX_DMA4_BASE);
+               base = OMAP34XX_DMA4_BASE;
                dma_lch_count = OMAP_DMA4_LOGICAL_DMA_CH_COUNT;
        } else if (cpu_is_omap44xx()) {
-               omap_dma_base = OMAP2_IO_ADDRESS(OMAP44XX_DMA4_BASE);
+               base = OMAP44XX_DMA4_BASE;
                dma_lch_count = OMAP_DMA4_LOGICAL_DMA_CH_COUNT;
        } else {
                pr_err("DMA init failed for unsupported omap\n");
                return -ENODEV;
        }
 
+       omap_dma_base = ioremap(base, SZ_4K);
+       BUG_ON(!omap_dma_base);
+
        if (cpu_class_is_omap2() && omap_dma_reserve_channels
                        && (omap_dma_reserve_channels <= dma_lch_count))
                dma_lch_count = omap_dma_reserve_channels;
 
        dma_chan = kzalloc(sizeof(struct omap_dma_lch) * dma_lch_count,
                                GFP_KERNEL);
-       if (!dma_chan)
-               return -ENOMEM;
+       if (!dma_chan) {
+               r = -ENOMEM;
+               goto out_unmap;
+       }
 
        if (cpu_class_is_omap2()) {
                dma_linked_lch = kzalloc(sizeof(struct dma_link_info) *
                                                dma_lch_count, GFP_KERNEL);
                if (!dma_linked_lch) {
-                       kfree(dma_chan);
-                       return -ENOMEM;
+                       r = -ENOMEM;
+                       goto out_free;
                }
        }
 
@@ -2466,7 +2511,7 @@ static int __init omap_init_dma(void)
                                for (i = 0; i < ch; i++)
                                        free_irq(omap1_dma_irq[i],
                                                 (void *) (i + 1));
-                               return r;
+                               goto out_free;
                        }
                }
        }
@@ -2484,8 +2529,8 @@ static int __init omap_init_dma(void)
                setup_irq(irq, &omap24xx_dma_irq);
        }
 
-       /* Enable smartidle idlemodes and autoidle */
        if (cpu_is_omap34xx()) {
+               /* Enable smartidle idlemodes and autoidle */
                u32 v = dma_read(OCP_SYSCONFIG);
                v &= ~(DMA_SYSCONFIG_MIDLEMODE_MASK |
                                DMA_SYSCONFIG_SIDLEMODE_MASK |
@@ -2494,6 +2539,13 @@ static int __init omap_init_dma(void)
                        DMA_SYSCONFIG_SIDLEMODE(DMA_IDLEMODE_SMARTIDLE) |
                        DMA_SYSCONFIG_AUTOIDLE);
                dma_write(v , OCP_SYSCONFIG);
+               /* reserve dma channels 0 and 1 in high security devices */
+               if (omap_type() != OMAP2_DEVICE_TYPE_GP) {
+                       printk(KERN_INFO "Reserving DMA channels 0 and 1 for "
+                                       "HS ROM code\n");
+                       dma_chan[0].dev_id = 0;
+                       dma_chan[1].dev_id = 1;
+               }
        }
 
 
@@ -2508,11 +2560,19 @@ static int __init omap_init_dma(void)
                               "(error %d)\n", r);
                        for (i = 0; i < dma_chan_count; i++)
                                free_irq(omap1_dma_irq[i], (void *) (i + 1));
-                       return r;
+                       goto out_free;
                }
        }
 
        return 0;
+
+out_free:
+       kfree(dma_chan);
+
+out_unmap:
+       iounmap(omap_dma_base);
+
+       return r;
 }
 
 arch_initcall(omap_init_dma);
index d325b54..64f407e 100644 (file)
@@ -38,7 +38,7 @@
 #include <linux/io.h>
 #include <linux/module.h>
 #include <mach/hardware.h>
-#include <mach/dmtimer.h>
+#include <plat/dmtimer.h>
 #include <mach/irqs.h>
 
 /* register offsets */
@@ -742,16 +742,17 @@ EXPORT_SYMBOL_GPL(omap_dm_timers_active);
 int __init omap_dm_timer_init(void)
 {
        struct omap_dm_timer *timer;
-       int i;
+       int i, map_size = SZ_8K;        /* Module 4KB + L4 4KB except on omap1 */
 
        if (!(cpu_is_omap16xx() || cpu_class_is_omap2()))
                return -ENODEV;
 
        spin_lock_init(&dm_timer_lock);
 
-       if (cpu_class_is_omap1())
+       if (cpu_class_is_omap1()) {
                dm_timers = omap1_dm_timers;
-       else if (cpu_is_omap24xx()) {
+               map_size = SZ_2K;
+       } else if (cpu_is_omap24xx()) {
                dm_timers = omap2_dm_timers;
                dm_source_names = omap2_dm_source_names;
                dm_source_clocks = omap2_dm_source_clocks;
@@ -774,10 +775,11 @@ int __init omap_dm_timer_init(void)
 
        for (i = 0; i < dm_timer_count; i++) {
                timer = &dm_timers[i];
-               if (cpu_class_is_omap1())
-                       timer->io_base = OMAP1_IO_ADDRESS(timer->phys_base);
-               else
-                       timer->io_base = OMAP2_IO_ADDRESS(timer->phys_base);
+
+               /* Static mapping, never released */
+               timer->io_base = ioremap(timer->phys_base, map_size);
+               BUG_ON(!timer->io_base);
+
 #if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3) || \
                                        defined(CONFIG_ARCH_OMAP4)
                if (cpu_class_is_omap2()) {
index 3746222..78a4ce5 100644 (file)
@@ -32,9 +32,9 @@
 #include <mach/hardware.h>
 #include <asm/mach/map.h>
 
-#include <mach/board.h>
-#include <mach/sram.h>
-#include <mach/omapfb.h>
+#include <plat/board.h>
+#include <plat/sram.h>
+#include <plat/omapfb.h>
 
 #if defined(CONFIG_FB_OMAP) || defined(CONFIG_FB_OMAP_MODULE)
 
index 7c345b7..055160e 100644 (file)
@@ -31,7 +31,7 @@
 /*
  * OMAP1510 GPIO registers
  */
-#define OMAP1510_GPIO_BASE             OMAP1_IO_ADDRESS(0xfffce000)
+#define OMAP1510_GPIO_BASE             0xfffce000
 #define OMAP1510_GPIO_DATA_INPUT       0x00
 #define OMAP1510_GPIO_DATA_OUTPUT      0x04
 #define OMAP1510_GPIO_DIR_CONTROL      0x08
 /*
  * OMAP1610 specific GPIO registers
  */
-#define OMAP1610_GPIO1_BASE            OMAP1_IO_ADDRESS(0xfffbe400)
-#define OMAP1610_GPIO2_BASE            OMAP1_IO_ADDRESS(0xfffbec00)
-#define OMAP1610_GPIO3_BASE            OMAP1_IO_ADDRESS(0xfffbb400)
-#define OMAP1610_GPIO4_BASE            OMAP1_IO_ADDRESS(0xfffbbc00)
+#define OMAP1610_GPIO1_BASE            0xfffbe400
+#define OMAP1610_GPIO2_BASE            0xfffbec00
+#define OMAP1610_GPIO3_BASE            0xfffbb400
+#define OMAP1610_GPIO4_BASE            0xfffbbc00
 #define OMAP1610_GPIO_REVISION         0x0000
 #define OMAP1610_GPIO_SYSCONFIG                0x0010
 #define OMAP1610_GPIO_SYSSTATUS                0x0014
 #define OMAP1610_GPIO_SET_DATAOUT      0x00f0
 
 /*
- * OMAP730 specific GPIO registers
+ * OMAP7XX specific GPIO registers
  */
-#define OMAP730_GPIO1_BASE             OMAP1_IO_ADDRESS(0xfffbc000)
-#define OMAP730_GPIO2_BASE             OMAP1_IO_ADDRESS(0xfffbc800)
-#define OMAP730_GPIO3_BASE             OMAP1_IO_ADDRESS(0xfffbd000)
-#define OMAP730_GPIO4_BASE             OMAP1_IO_ADDRESS(0xfffbd800)
-#define OMAP730_GPIO5_BASE             OMAP1_IO_ADDRESS(0xfffbe000)
-#define OMAP730_GPIO6_BASE             OMAP1_IO_ADDRESS(0xfffbe800)
-#define OMAP730_GPIO_DATA_INPUT                0x00
-#define OMAP730_GPIO_DATA_OUTPUT       0x04
-#define OMAP730_GPIO_DIR_CONTROL       0x08
-#define OMAP730_GPIO_INT_CONTROL       0x0c
-#define OMAP730_GPIO_INT_MASK          0x10
-#define OMAP730_GPIO_INT_STATUS                0x14
-
-/*
- * OMAP850 specific GPIO registers
- */
-#define OMAP850_GPIO1_BASE             OMAP1_IO_ADDRESS(0xfffbc000)
-#define OMAP850_GPIO2_BASE             OMAP1_IO_ADDRESS(0xfffbc800)
-#define OMAP850_GPIO3_BASE             OMAP1_IO_ADDRESS(0xfffbd000)
-#define OMAP850_GPIO4_BASE             OMAP1_IO_ADDRESS(0xfffbd800)
-#define OMAP850_GPIO5_BASE             OMAP1_IO_ADDRESS(0xfffbe000)
-#define OMAP850_GPIO6_BASE             OMAP1_IO_ADDRESS(0xfffbe800)
-#define OMAP850_GPIO_DATA_INPUT                0x00
-#define OMAP850_GPIO_DATA_OUTPUT       0x04
-#define OMAP850_GPIO_DIR_CONTROL       0x08
-#define OMAP850_GPIO_INT_CONTROL       0x0c
-#define OMAP850_GPIO_INT_MASK          0x10
-#define OMAP850_GPIO_INT_STATUS                0x14
-
-#define OMAP1_MPUIO_VBASE              OMAP1_IO_ADDRESS(OMAP1_MPUIO_BASE)
+#define OMAP7XX_GPIO1_BASE             0xfffbc000
+#define OMAP7XX_GPIO2_BASE             0xfffbc800
+#define OMAP7XX_GPIO3_BASE             0xfffbd000
+#define OMAP7XX_GPIO4_BASE             0xfffbd800
+#define OMAP7XX_GPIO5_BASE             0xfffbe000
+#define OMAP7XX_GPIO6_BASE             0xfffbe800
+#define OMAP7XX_GPIO_DATA_INPUT                0x00
+#define OMAP7XX_GPIO_DATA_OUTPUT       0x04
+#define OMAP7XX_GPIO_DIR_CONTROL       0x08
+#define OMAP7XX_GPIO_INT_CONTROL       0x0c
+#define OMAP7XX_GPIO_INT_MASK          0x10
+#define OMAP7XX_GPIO_INT_STATUS                0x14
+
+#define OMAP1_MPUIO_VBASE              OMAP1_MPUIO_BASE
 
 /*
  * omap24xx specific GPIO registers
  */
-#define OMAP242X_GPIO1_BASE            OMAP2_IO_ADDRESS(0x48018000)
-#define OMAP242X_GPIO2_BASE            OMAP2_IO_ADDRESS(0x4801a000)
-#define OMAP242X_GPIO3_BASE            OMAP2_IO_ADDRESS(0x4801c000)
-#define OMAP242X_GPIO4_BASE            OMAP2_IO_ADDRESS(0x4801e000)
+#define OMAP242X_GPIO1_BASE            0x48018000
+#define OMAP242X_GPIO2_BASE            0x4801a000
+#define OMAP242X_GPIO3_BASE            0x4801c000
+#define OMAP242X_GPIO4_BASE            0x4801e000
 
-#define OMAP243X_GPIO1_BASE            OMAP2_IO_ADDRESS(0x4900C000)
-#define OMAP243X_GPIO2_BASE            OMAP2_IO_ADDRESS(0x4900E000)
-#define OMAP243X_GPIO3_BASE            OMAP2_IO_ADDRESS(0x49010000)
-#define OMAP243X_GPIO4_BASE            OMAP2_IO_ADDRESS(0x49012000)
-#define OMAP243X_GPIO5_BASE            OMAP2_IO_ADDRESS(0x480B6000)
+#define OMAP243X_GPIO1_BASE            0x4900C000
+#define OMAP243X_GPIO2_BASE            0x4900E000
+#define OMAP243X_GPIO3_BASE            0x49010000
+#define OMAP243X_GPIO4_BASE            0x49012000
+#define OMAP243X_GPIO5_BASE            0x480B6000
 
 #define OMAP24XX_GPIO_REVISION         0x0000
 #define OMAP24XX_GPIO_SYSCONFIG                0x0010
  * omap34xx specific GPIO registers
  */
 
-#define OMAP34XX_GPIO1_BASE            OMAP2_IO_ADDRESS(0x48310000)
-#define OMAP34XX_GPIO2_BASE            OMAP2_IO_ADDRESS(0x49050000)
-#define OMAP34XX_GPIO3_BASE            OMAP2_IO_ADDRESS(0x49052000)
-#define OMAP34XX_GPIO4_BASE            OMAP2_IO_ADDRESS(0x49054000)
-#define OMAP34XX_GPIO5_BASE            OMAP2_IO_ADDRESS(0x49056000)
-#define OMAP34XX_GPIO6_BASE            OMAP2_IO_ADDRESS(0x49058000)
+#define OMAP34XX_GPIO1_BASE            0x48310000
+#define OMAP34XX_GPIO2_BASE            0x49050000
+#define OMAP34XX_GPIO3_BASE            0x49052000
+#define OMAP34XX_GPIO4_BASE            0x49054000
+#define OMAP34XX_GPIO5_BASE            0x49056000
+#define OMAP34XX_GPIO6_BASE            0x49058000
 
 /*
  * OMAP44XX  specific GPIO registers
  */
-#define OMAP44XX_GPIO1_BASE             OMAP2_IO_ADDRESS(0x4a310000)
-#define OMAP44XX_GPIO2_BASE             OMAP2_IO_ADDRESS(0x48055000)
-#define OMAP44XX_GPIO3_BASE             OMAP2_IO_ADDRESS(0x48057000)
-#define OMAP44XX_GPIO4_BASE             OMAP2_IO_ADDRESS(0x48059000)
-#define OMAP44XX_GPIO5_BASE             OMAP2_IO_ADDRESS(0x4805B000)
-#define OMAP44XX_GPIO6_BASE             OMAP2_IO_ADDRESS(0x4805D000)
+#define OMAP44XX_GPIO1_BASE             0x4a310000
+#define OMAP44XX_GPIO2_BASE             0x48055000
+#define OMAP44XX_GPIO3_BASE             0x48057000
+#define OMAP44XX_GPIO4_BASE             0x48059000
+#define OMAP44XX_GPIO5_BASE             0x4805B000
+#define OMAP44XX_GPIO6_BASE             0x4805D000
 
 struct gpio_bank {
+       unsigned long pbase;
        void __iomem *base;
        u16 irq;
        u16 virtual_irq_start;
@@ -210,101 +195,134 @@ struct gpio_bank {
        spinlock_t lock;
        struct gpio_chip chip;
        struct clk *dbck;
+       u32 mod_usage;
 };
 
 #define METHOD_MPUIO           0
 #define METHOD_GPIO_1510       1
 #define METHOD_GPIO_1610       2
-#define METHOD_GPIO_730                3
-#define METHOD_GPIO_850                4
+#define METHOD_GPIO_7XX                3
 #define METHOD_GPIO_24XX       5
 
 #ifdef CONFIG_ARCH_OMAP16XX
 static struct gpio_bank gpio_bank_1610[5] = {
-       { OMAP1_MPUIO_VBASE,    INT_MPUIO,          IH_MPUIO_BASE,     METHOD_MPUIO},
-       { OMAP1610_GPIO1_BASE, INT_GPIO_BANK1,      IH_GPIO_BASE,      METHOD_GPIO_1610 },
-       { OMAP1610_GPIO2_BASE, INT_1610_GPIO_BANK2, IH_GPIO_BASE + 16, METHOD_GPIO_1610 },
-       { OMAP1610_GPIO3_BASE, INT_1610_GPIO_BANK3, IH_GPIO_BASE + 32, METHOD_GPIO_1610 },
-       { OMAP1610_GPIO4_BASE, INT_1610_GPIO_BANK4, IH_GPIO_BASE + 48, METHOD_GPIO_1610 },
+       { OMAP1_MPUIO_VBASE, NULL, INT_MPUIO, IH_MPUIO_BASE,
+               METHOD_MPUIO },
+       { OMAP1610_GPIO1_BASE, NULL, INT_GPIO_BANK1, IH_GPIO_BASE,
+               METHOD_GPIO_1610 },
+       { OMAP1610_GPIO2_BASE, NULL, INT_1610_GPIO_BANK2, IH_GPIO_BASE + 16,
+               METHOD_GPIO_1610 },
+       { OMAP1610_GPIO3_BASE, NULL, INT_1610_GPIO_BANK3, IH_GPIO_BASE + 32,
+               METHOD_GPIO_1610 },
+       { OMAP1610_GPIO4_BASE, NULL, INT_1610_GPIO_BANK4, IH_GPIO_BASE + 48,
+               METHOD_GPIO_1610 },
 };
 #endif
 
 #ifdef CONFIG_ARCH_OMAP15XX
 static struct gpio_bank gpio_bank_1510[2] = {
-       { OMAP1_MPUIO_VBASE,   INT_MPUIO,      IH_MPUIO_BASE, METHOD_MPUIO },
-       { OMAP1510_GPIO_BASE, INT_GPIO_BANK1, IH_GPIO_BASE,  METHOD_GPIO_1510 }
-};
-#endif
-
-#ifdef CONFIG_ARCH_OMAP730
-static struct gpio_bank gpio_bank_730[7] = {
-       { OMAP1_MPUIO_VBASE,    INT_730_MPUIO,      IH_MPUIO_BASE,      METHOD_MPUIO },
-       { OMAP730_GPIO1_BASE,  INT_730_GPIO_BANK1,  IH_GPIO_BASE,       METHOD_GPIO_730 },
-       { OMAP730_GPIO2_BASE,  INT_730_GPIO_BANK2,  IH_GPIO_BASE + 32,  METHOD_GPIO_730 },
-       { OMAP730_GPIO3_BASE,  INT_730_GPIO_BANK3,  IH_GPIO_BASE + 64,  METHOD_GPIO_730 },
-       { OMAP730_GPIO4_BASE,  INT_730_GPIO_BANK4,  IH_GPIO_BASE + 96,  METHOD_GPIO_730 },
-       { OMAP730_GPIO5_BASE,  INT_730_GPIO_BANK5,  IH_GPIO_BASE + 128, METHOD_GPIO_730 },
-       { OMAP730_GPIO6_BASE,  INT_730_GPIO_BANK6,  IH_GPIO_BASE + 160, METHOD_GPIO_730 },
+       { OMAP1_MPUIO_VBASE, NULL, INT_MPUIO, IH_MPUIO_BASE,
+               METHOD_MPUIO },
+       { OMAP1510_GPIO_BASE, NULL, INT_GPIO_BANK1, IH_GPIO_BASE,
+               METHOD_GPIO_1510 }
 };
 #endif
 
-#ifdef CONFIG_ARCH_OMAP850
-static struct gpio_bank gpio_bank_850[7] = {
-       { OMAP1_MPUIO_VBASE,     INT_850_MPUIO,     IH_MPUIO_BASE,      METHOD_MPUIO },
-       { OMAP850_GPIO1_BASE,  INT_850_GPIO_BANK1,  IH_GPIO_BASE,       METHOD_GPIO_850 },
-       { OMAP850_GPIO2_BASE,  INT_850_GPIO_BANK2,  IH_GPIO_BASE + 32,  METHOD_GPIO_850 },
-       { OMAP850_GPIO3_BASE,  INT_850_GPIO_BANK3,  IH_GPIO_BASE + 64,  METHOD_GPIO_850 },
-       { OMAP850_GPIO4_BASE,  INT_850_GPIO_BANK4,  IH_GPIO_BASE + 96,  METHOD_GPIO_850 },
-       { OMAP850_GPIO5_BASE,  INT_850_GPIO_BANK5,  IH_GPIO_BASE + 128, METHOD_GPIO_850 },
-       { OMAP850_GPIO6_BASE,  INT_850_GPIO_BANK6,  IH_GPIO_BASE + 160, METHOD_GPIO_850 },
+#if defined(CONFIG_ARCH_OMAP730) || defined(CONFIG_ARCH_OMAP850)
+static struct gpio_bank gpio_bank_7xx[7] = {
+       { OMAP1_MPUIO_VBASE, NULL, INT_7XX_MPUIO, IH_MPUIO_BASE,
+               METHOD_MPUIO },
+       { OMAP7XX_GPIO1_BASE, NULL, INT_7XX_GPIO_BANK1, IH_GPIO_BASE,
+               METHOD_GPIO_7XX },
+       { OMAP7XX_GPIO2_BASE, NULL, INT_7XX_GPIO_BANK2, IH_GPIO_BASE + 32,
+               METHOD_GPIO_7XX },
+       { OMAP7XX_GPIO3_BASE, NULL, INT_7XX_GPIO_BANK3, IH_GPIO_BASE + 64,
+               METHOD_GPIO_7XX },
+       { OMAP7XX_GPIO4_BASE, NULL, INT_7XX_GPIO_BANK4,  IH_GPIO_BASE + 96,
+               METHOD_GPIO_7XX },
+       { OMAP7XX_GPIO5_BASE, NULL, INT_7XX_GPIO_BANK5,  IH_GPIO_BASE + 128,
+               METHOD_GPIO_7XX },
+       { OMAP7XX_GPIO6_BASE, NULL, INT_7XX_GPIO_BANK6,  IH_GPIO_BASE + 160,
+               METHOD_GPIO_7XX },
 };
 #endif
 
-
 #ifdef CONFIG_ARCH_OMAP24XX
 
 static struct gpio_bank gpio_bank_242x[4] = {
-       { OMAP242X_GPIO1_BASE, INT_24XX_GPIO_BANK1, IH_GPIO_BASE,       METHOD_GPIO_24XX },
-       { OMAP242X_GPIO2_BASE, INT_24XX_GPIO_BANK2, IH_GPIO_BASE + 32,  METHOD_GPIO_24XX },
-       { OMAP242X_GPIO3_BASE, INT_24XX_GPIO_BANK3, IH_GPIO_BASE + 64,  METHOD_GPIO_24XX },
-       { OMAP242X_GPIO4_BASE, INT_24XX_GPIO_BANK4, IH_GPIO_BASE + 96,  METHOD_GPIO_24XX },
+       { OMAP242X_GPIO1_BASE, NULL, INT_24XX_GPIO_BANK1, IH_GPIO_BASE,
+               METHOD_GPIO_24XX },
+       { OMAP242X_GPIO2_BASE, NULL, INT_24XX_GPIO_BANK2, IH_GPIO_BASE + 32,
+               METHOD_GPIO_24XX },
+       { OMAP242X_GPIO3_BASE, NULL, INT_24XX_GPIO_BANK3, IH_GPIO_BASE + 64,
+               METHOD_GPIO_24XX },
+       { OMAP242X_GPIO4_BASE, NULL, INT_24XX_GPIO_BANK4, IH_GPIO_BASE + 96,
+               METHOD_GPIO_24XX },
 };
 
 static struct gpio_bank gpio_bank_243x[5] = {
-       { OMAP243X_GPIO1_BASE, INT_24XX_GPIO_BANK1, IH_GPIO_BASE,       METHOD_GPIO_24XX },
-       { OMAP243X_GPIO2_BASE, INT_24XX_GPIO_BANK2, IH_GPIO_BASE + 32,  METHOD_GPIO_24XX },
-       { OMAP243X_GPIO3_BASE, INT_24XX_GPIO_BANK3, IH_GPIO_BASE + 64,  METHOD_GPIO_24XX },
-       { OMAP243X_GPIO4_BASE, INT_24XX_GPIO_BANK4, IH_GPIO_BASE + 96,  METHOD_GPIO_24XX },
-       { OMAP243X_GPIO5_BASE, INT_24XX_GPIO_BANK5, IH_GPIO_BASE + 128, METHOD_GPIO_24XX },
+       { OMAP243X_GPIO1_BASE, NULL, INT_24XX_GPIO_BANK1, IH_GPIO_BASE,
+               METHOD_GPIO_24XX },
+       { OMAP243X_GPIO2_BASE, NULL, INT_24XX_GPIO_BANK2, IH_GPIO_BASE + 32,
+               METHOD_GPIO_24XX },
+       { OMAP243X_GPIO3_BASE, NULL, INT_24XX_GPIO_BANK3, IH_GPIO_BASE + 64,
+               METHOD_GPIO_24XX },
+       { OMAP243X_GPIO4_BASE, NULL, INT_24XX_GPIO_BANK4, IH_GPIO_BASE + 96,
+               METHOD_GPIO_24XX },
+       { OMAP243X_GPIO5_BASE, NULL, INT_24XX_GPIO_BANK5, IH_GPIO_BASE + 128,
+               METHOD_GPIO_24XX },
 };
 
 #endif
 
 #ifdef CONFIG_ARCH_OMAP34XX
 static struct gpio_bank gpio_bank_34xx[6] = {
-       { OMAP34XX_GPIO1_BASE, INT_34XX_GPIO_BANK1, IH_GPIO_BASE,       METHOD_GPIO_24XX },
-       { OMAP34XX_GPIO2_BASE, INT_34XX_GPIO_BANK2, IH_GPIO_BASE + 32,  METHOD_GPIO_24XX },
-       { OMAP34XX_GPIO3_BASE, INT_34XX_GPIO_BANK3, IH_GPIO_BASE + 64,  METHOD_GPIO_24XX },
-       { OMAP34XX_GPIO4_BASE, INT_34XX_GPIO_BANK4, IH_GPIO_BASE + 96,  METHOD_GPIO_24XX },
-       { OMAP34XX_GPIO5_BASE, INT_34XX_GPIO_BANK5, IH_GPIO_BASE + 128, METHOD_GPIO_24XX },
-       { OMAP34XX_GPIO6_BASE, INT_34XX_GPIO_BANK6, IH_GPIO_BASE + 160, METHOD_GPIO_24XX },
+       { OMAP34XX_GPIO1_BASE, NULL, INT_34XX_GPIO_BANK1, IH_GPIO_BASE,
+               METHOD_GPIO_24XX },
+       { OMAP34XX_GPIO2_BASE, NULL, INT_34XX_GPIO_BANK2, IH_GPIO_BASE + 32,
+               METHOD_GPIO_24XX },
+       { OMAP34XX_GPIO3_BASE, NULL, INT_34XX_GPIO_BANK3, IH_GPIO_BASE + 64,
+               METHOD_GPIO_24XX },
+       { OMAP34XX_GPIO4_BASE, NULL, INT_34XX_GPIO_BANK4, IH_GPIO_BASE + 96,
+               METHOD_GPIO_24XX },
+       { OMAP34XX_GPIO5_BASE, NULL, INT_34XX_GPIO_BANK5, IH_GPIO_BASE + 128,
+               METHOD_GPIO_24XX },
+       { OMAP34XX_GPIO6_BASE, NULL, INT_34XX_GPIO_BANK6, IH_GPIO_BASE + 160,
+               METHOD_GPIO_24XX },
 };
 
+struct omap3_gpio_regs {
+       u32 sysconfig;
+       u32 irqenable1;
+       u32 irqenable2;
+       u32 wake_en;
+       u32 ctrl;
+       u32 oe;
+       u32 leveldetect0;
+       u32 leveldetect1;
+       u32 risingdetect;
+       u32 fallingdetect;
+       u32 dataout;
+       u32 setwkuena;
+       u32 setdataout;
+};
+
+static struct omap3_gpio_regs gpio_context[OMAP34XX_NR_GPIOS];
 #endif
 
 #ifdef CONFIG_ARCH_OMAP4
 static struct gpio_bank gpio_bank_44xx[6] = {
-       { OMAP44XX_GPIO1_BASE, INT_44XX_GPIO_BANK1, IH_GPIO_BASE,       \
+       { OMAP44XX_GPIO1_BASE, NULL, INT_44XX_GPIO_BANK1, IH_GPIO_BASE,
                METHOD_GPIO_24XX },
-       { OMAP44XX_GPIO2_BASE, INT_44XX_GPIO_BANK2, IH_GPIO_BASE + 32,  \
+       { OMAP44XX_GPIO2_BASE, NULL, INT_44XX_GPIO_BANK2, IH_GPIO_BASE + 32,
                METHOD_GPIO_24XX },
-       { OMAP44XX_GPIO3_BASE, INT_44XX_GPIO_BANK3, IH_GPIO_BASE + 64,  \
+       { OMAP44XX_GPIO3_BASE, NULL, INT_44XX_GPIO_BANK3, IH_GPIO_BASE + 64,
                METHOD_GPIO_24XX },
-       { OMAP44XX_GPIO4_BASE, INT_44XX_GPIO_BANK4, IH_GPIO_BASE + 96,  \
+       { OMAP44XX_GPIO4_BASE, NULL, INT_44XX_GPIO_BANK4, IH_GPIO_BASE + 96,
                METHOD_GPIO_24XX },
-       { OMAP44XX_GPIO5_BASE, INT_44XX_GPIO_BANK5, IH_GPIO_BASE + 128, \
+       { OMAP44XX_GPIO5_BASE, NULL, INT_44XX_GPIO_BANK5, IH_GPIO_BASE + 128,
                METHOD_GPIO_24XX },
-       { OMAP44XX_GPIO6_BASE, INT_44XX_GPIO_BANK6, IH_GPIO_BASE + 160, \
+       { OMAP44XX_GPIO6_BASE, NULL, INT_44XX_GPIO_BANK6, IH_GPIO_BASE + 160,
                METHOD_GPIO_24XX },
 };
 
@@ -402,14 +420,9 @@ static void _set_gpio_direction(struct gpio_bank *bank, int gpio, int is_input)
                reg += OMAP1610_GPIO_DIRECTION;
                break;
 #endif
-#ifdef CONFIG_ARCH_OMAP730
-       case METHOD_GPIO_730:
-               reg += OMAP730_GPIO_DIR_CONTROL;
-               break;
-#endif
-#ifdef CONFIG_ARCH_OMAP850
-       case METHOD_GPIO_850:
-               reg += OMAP850_GPIO_DIR_CONTROL;
+#if defined(CONFIG_ARCH_OMAP730) || defined(CONFIG_ARCH_OMAP850)
+       case METHOD_GPIO_7XX:
+               reg += OMAP7XX_GPIO_DIR_CONTROL;
                break;
 #endif
 #if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX)
@@ -469,19 +482,9 @@ static void _set_gpio_dataout(struct gpio_bank *bank, int gpio, int enable)
                l = 1 << gpio;
                break;
 #endif
-#ifdef CONFIG_ARCH_OMAP730
-       case METHOD_GPIO_730:
-               reg += OMAP730_GPIO_DATA_OUTPUT;
-               l = __raw_readl(reg);
-               if (enable)
-                       l |= 1 << gpio;
-               else
-                       l &= ~(1 << gpio);
-               break;
-#endif
-#ifdef CONFIG_ARCH_OMAP850
-       case METHOD_GPIO_850:
-               reg += OMAP850_GPIO_DATA_OUTPUT;
+#if defined(CONFIG_ARCH_OMAP730) || defined(CONFIG_ARCH_OMAP850)
+       case METHOD_GPIO_7XX:
+               reg += OMAP7XX_GPIO_DATA_OUTPUT;
                l = __raw_readl(reg);
                if (enable)
                        l |= 1 << gpio;
@@ -537,14 +540,9 @@ static int _get_gpio_datain(struct gpio_bank *bank, int gpio)
                reg += OMAP1610_GPIO_DATAIN;
                break;
 #endif
-#ifdef CONFIG_ARCH_OMAP730
-       case METHOD_GPIO_730:
-               reg += OMAP730_GPIO_DATA_INPUT;
-               break;
-#endif
-#ifdef CONFIG_ARCH_OMAP850
-       case METHOD_GPIO_850:
-               reg += OMAP850_GPIO_DATA_INPUT;
+#if defined(CONFIG_ARCH_OMAP730) || defined(CONFIG_ARCH_OMAP850)
+       case METHOD_GPIO_7XX:
+               reg += OMAP7XX_GPIO_DATA_INPUT;
                break;
 #endif
 #if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX)
@@ -588,14 +586,9 @@ static int _get_gpio_dataout(struct gpio_bank *bank, int gpio)
                reg += OMAP1610_GPIO_DATAOUT;
                break;
 #endif
-#ifdef CONFIG_ARCH_OMAP730
-       case METHOD_GPIO_730:
-               reg += OMAP730_GPIO_DATA_OUTPUT;
-               break;
-#endif
-#ifdef CONFIG_ARCH_OMAP850
-       case METHOD_GPIO_850:
-               reg += OMAP850_GPIO_DATA_OUTPUT;
+#if defined(CONFIG_ARCH_OMAP730) || defined(CONFIG_ARCH_OMAP850)
+       case METHOD_GPIO_7XX:
+               reg += OMAP7XX_GPIO_DATA_OUTPUT;
                break;
 #endif
 #if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX) || \
@@ -636,6 +629,10 @@ void omap_set_gpio_debounce(int gpio, int enable)
 #else
        reg += OMAP24XX_GPIO_DEBOUNCE_EN;
 #endif
+       if (!(bank->mod_usage & l)) {
+               printk(KERN_ERR "GPIO %d not requested\n", gpio);
+               return;
+       }
 
        spin_lock_irqsave(&bank->lock, flags);
        val = __raw_readl(reg);
@@ -671,6 +668,11 @@ void omap_set_gpio_debounce_time(int gpio, int enc_time)
        bank = get_gpio_bank(gpio);
        reg = bank->base;
 
+       if (!bank->mod_usage) {
+               printk(KERN_ERR "GPIO not requested\n");
+               return;
+       }
+
        enc_time &= 0xff;
 #ifdef CONFIG_ARCH_OMAP4
        reg += OMAP4_GPIO_DEBOUNCINGTIME;
@@ -797,21 +799,9 @@ static int _set_gpio_triggering(struct gpio_bank *bank, int gpio, int trigger)
                        __raw_writel(1 << gpio, bank->base + OMAP1610_GPIO_CLEAR_WAKEUPENA);
                break;
 #endif
-#ifdef CONFIG_ARCH_OMAP730
-       case METHOD_GPIO_730:
-               reg += OMAP730_GPIO_INT_CONTROL;
-               l = __raw_readl(reg);
-               if (trigger & IRQ_TYPE_EDGE_RISING)
-                       l |= 1 << gpio;
-               else if (trigger & IRQ_TYPE_EDGE_FALLING)
-                       l &= ~(1 << gpio);
-               else
-                       goto bad;
-               break;
-#endif
-#ifdef CONFIG_ARCH_OMAP850
-       case METHOD_GPIO_850:
-               reg += OMAP850_GPIO_INT_CONTROL;
+#if defined(CONFIG_ARCH_OMAP730) || defined(CONFIG_ARCH_OMAP850)
+       case METHOD_GPIO_7XX:
+               reg += OMAP7XX_GPIO_INT_CONTROL;
                l = __raw_readl(reg);
                if (trigger & IRQ_TYPE_EDGE_RISING)
                        l |= 1 << gpio;
@@ -897,14 +887,9 @@ static void _clear_gpio_irqbank(struct gpio_bank *bank, int gpio_mask)
                reg += OMAP1610_GPIO_IRQSTATUS1;
                break;
 #endif
-#ifdef CONFIG_ARCH_OMAP730
-       case METHOD_GPIO_730:
-               reg += OMAP730_GPIO_INT_STATUS;
-               break;
-#endif
-#ifdef CONFIG_ARCH_OMAP850
-       case METHOD_GPIO_850:
-               reg += OMAP850_GPIO_INT_STATUS;
+#if defined(CONFIG_ARCH_OMAP730) || defined(CONFIG_ARCH_OMAP850)
+       case METHOD_GPIO_7XX:
+               reg += OMAP7XX_GPIO_INT_STATUS;
                break;
 #endif
 #if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX)
@@ -971,16 +956,9 @@ static u32 _get_gpio_irqbank_mask(struct gpio_bank *bank)
                mask = 0xffff;
                break;
 #endif
-#ifdef CONFIG_ARCH_OMAP730
-       case METHOD_GPIO_730:
-               reg += OMAP730_GPIO_INT_MASK;
-               mask = 0xffffffff;
-               inv = 1;
-               break;
-#endif
-#ifdef CONFIG_ARCH_OMAP850
-       case METHOD_GPIO_850:
-               reg += OMAP850_GPIO_INT_MASK;
+#if defined(CONFIG_ARCH_OMAP730) || defined(CONFIG_ARCH_OMAP850)
+       case METHOD_GPIO_7XX:
+               reg += OMAP7XX_GPIO_INT_MASK;
                mask = 0xffffffff;
                inv = 1;
                break;
@@ -1044,19 +1022,9 @@ static void _enable_gpio_irqbank(struct gpio_bank *bank, int gpio_mask, int enab
                l = gpio_mask;
                break;
 #endif
-#ifdef CONFIG_ARCH_OMAP730
-       case METHOD_GPIO_730:
-               reg += OMAP730_GPIO_INT_MASK;
-               l = __raw_readl(reg);
-               if (enable)
-                       l &= ~(gpio_mask);
-               else
-                       l |= gpio_mask;
-               break;
-#endif
-#ifdef CONFIG_ARCH_OMAP850
-       case METHOD_GPIO_850:
-               reg += OMAP850_GPIO_INT_MASK;
+#if defined(CONFIG_ARCH_OMAP730) || defined(CONFIG_ARCH_OMAP850)
+       case METHOD_GPIO_7XX:
+               reg += OMAP7XX_GPIO_INT_MASK;
                l = __raw_readl(reg);
                if (enable)
                        l &= ~(gpio_mask);
@@ -1186,6 +1154,16 @@ static int omap_gpio_request(struct gpio_chip *chip, unsigned offset)
                __raw_writel(__raw_readl(reg) | (1 << offset), reg);
        }
 #endif
+       if (!cpu_class_is_omap1()) {
+               if (!bank->mod_usage) {
+                       u32 ctrl;
+                       ctrl = __raw_readl(bank->base + OMAP24XX_GPIO_CTRL);
+                       ctrl &= 0xFFFFFFFE;
+                       /* Module is enabled, clocks are not gated */
+                       __raw_writel(ctrl, bank->base + OMAP24XX_GPIO_CTRL);
+               }
+               bank->mod_usage |= 1 << offset;
+       }
        spin_unlock_irqrestore(&bank->lock, flags);
 
        return 0;
@@ -1212,6 +1190,16 @@ static void omap_gpio_free(struct gpio_chip *chip, unsigned offset)
                __raw_writel(1 << offset, reg);
        }
 #endif
+       if (!cpu_class_is_omap1()) {
+               bank->mod_usage &= ~(1 << offset);
+               if (!bank->mod_usage) {
+                       u32 ctrl;
+                       ctrl = __raw_readl(bank->base + OMAP24XX_GPIO_CTRL);
+                       /* Module is disabled, clocks are gated */
+                       ctrl |= 1;
+                       __raw_writel(ctrl, bank->base + OMAP24XX_GPIO_CTRL);
+               }
+       }
        _reset_gpio(bank, bank->chip.base + offset);
        spin_unlock_irqrestore(&bank->lock, flags);
 }
@@ -1249,13 +1237,9 @@ static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
        if (bank->method == METHOD_GPIO_1610)
                isr_reg = bank->base + OMAP1610_GPIO_IRQSTATUS1;
 #endif
-#ifdef CONFIG_ARCH_OMAP730
-       if (bank->method == METHOD_GPIO_730)
-               isr_reg = bank->base + OMAP730_GPIO_INT_STATUS;
-#endif
-#ifdef CONFIG_ARCH_OMAP850
-       if (bank->method == METHOD_GPIO_850)
-               isr_reg = bank->base + OMAP850_GPIO_INT_STATUS;
+#if defined(CONFIG_ARCH_OMAP730) || defined(CONFIG_ARCH_OMAP850)
+       if (bank->method == METHOD_GPIO_7XX)
+               isr_reg = bank->base + OMAP7XX_GPIO_INT_STATUS;
 #endif
 #if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX)
        if (bank->method == METHOD_GPIO_24XX)
@@ -1524,11 +1508,8 @@ static int gpio_is_input(struct gpio_bank *bank, int mask)
        case METHOD_GPIO_1610:
                reg += OMAP1610_GPIO_DIRECTION;
                break;
-       case METHOD_GPIO_730:
-               reg += OMAP730_GPIO_DIR_CONTROL;
-               break;
-       case METHOD_GPIO_850:
-               reg += OMAP850_GPIO_DIR_CONTROL;
+       case METHOD_GPIO_7XX:
+               reg += OMAP7XX_GPIO_DIR_CONTROL;
                break;
        case METHOD_GPIO_24XX:
                reg += OMAP24XX_GPIO_OE;
@@ -1607,6 +1588,23 @@ static struct clk * gpio5_fck;
 static struct clk *gpio_iclks[OMAP34XX_NR_GPIOS];
 #endif
 
+static void __init omap_gpio_show_rev(void)
+{
+       u32 rev;
+
+       if (cpu_is_omap16xx())
+               rev = __raw_readw(gpio_bank[1].base + OMAP1610_GPIO_REVISION);
+       else if (cpu_is_omap24xx() || cpu_is_omap34xx())
+               rev = __raw_readl(gpio_bank[0].base + OMAP24XX_GPIO_REVISION);
+       else if (cpu_is_omap44xx())
+               rev = __raw_readl(gpio_bank[0].base + OMAP4_GPIO_REVISION);
+       else
+               return;
+
+       printk(KERN_INFO "OMAP GPIO hardware version %d.%d\n",
+               (rev >> 4) & 0x0f, rev & 0x0f);
+}
+
 /* This lock class tells lockdep that GPIO irqs are in a different
  * category than their parents, so it won't report false recursion.
  */
@@ -1617,6 +1615,7 @@ static int __init _omap_gpio_init(void)
        int i;
        int gpio = 0;
        struct gpio_bank *bank;
+       int bank_size = SZ_8K;  /* Module 4KB + L4 4KB except on omap1 */
        char clk_name[11];
 
        initialized = 1;
@@ -1679,77 +1678,45 @@ static int __init _omap_gpio_init(void)
 
 #ifdef CONFIG_ARCH_OMAP15XX
        if (cpu_is_omap15xx()) {
-               printk(KERN_INFO "OMAP1510 GPIO hardware\n");
                gpio_bank_count = 2;
                gpio_bank = gpio_bank_1510;
+               bank_size = SZ_2K;
        }
 #endif
 #if defined(CONFIG_ARCH_OMAP16XX)
        if (cpu_is_omap16xx()) {
-               u32 rev;
-
                gpio_bank_count = 5;
                gpio_bank = gpio_bank_1610;
-               rev = __raw_readw(gpio_bank[1].base + OMAP1610_GPIO_REVISION);
-               printk(KERN_INFO "OMAP GPIO hardware version %d.%d\n",
-                      (rev >> 4) & 0x0f, rev & 0x0f);
+               bank_size = SZ_2K;
        }
 #endif
-#ifdef CONFIG_ARCH_OMAP730
-       if (cpu_is_omap730()) {
-               printk(KERN_INFO "OMAP730 GPIO hardware\n");
-               gpio_bank_count = 7;
-               gpio_bank = gpio_bank_730;
-       }
-#endif
-#ifdef CONFIG_ARCH_OMAP850
-       if (cpu_is_omap850()) {
-               printk(KERN_INFO "OMAP850 GPIO hardware\n");
+#if defined(CONFIG_ARCH_OMAP730) || defined(CONFIG_ARCH_OMAP850)
+       if (cpu_is_omap7xx()) {
                gpio_bank_count = 7;
-               gpio_bank = gpio_bank_850;
+               gpio_bank = gpio_bank_7xx;
+               bank_size = SZ_2K;
        }
 #endif
-
 #ifdef CONFIG_ARCH_OMAP24XX
        if (cpu_is_omap242x()) {
-               int rev;
-
                gpio_bank_count = 4;
                gpio_bank = gpio_bank_242x;
-               rev = __raw_readl(gpio_bank[0].base + OMAP24XX_GPIO_REVISION);
-               printk(KERN_INFO "OMAP242x GPIO hardware version %d.%d\n",
-                       (rev >> 4) & 0x0f, rev & 0x0f);
        }
        if (cpu_is_omap243x()) {
-               int rev;
-
                gpio_bank_count = 5;
                gpio_bank = gpio_bank_243x;
-               rev = __raw_readl(gpio_bank[0].base + OMAP24XX_GPIO_REVISION);
-               printk(KERN_INFO "OMAP243x GPIO hardware version %d.%d\n",
-                       (rev >> 4) & 0x0f, rev & 0x0f);
        }
 #endif
 #ifdef CONFIG_ARCH_OMAP34XX
        if (cpu_is_omap34xx()) {
-               int rev;
-
                gpio_bank_count = OMAP34XX_NR_GPIOS;
                gpio_bank = gpio_bank_34xx;
-               rev = __raw_readl(gpio_bank[0].base + OMAP24XX_GPIO_REVISION);
-               printk(KERN_INFO "OMAP34xx GPIO hardware version %d.%d\n",
-                       (rev >> 4) & 0x0f, rev & 0x0f);
        }
 #endif
 #ifdef CONFIG_ARCH_OMAP4
        if (cpu_is_omap44xx()) {
-               int rev;
-
                gpio_bank_count = OMAP34XX_NR_GPIOS;
                gpio_bank = gpio_bank_44xx;
-               rev = __raw_readl(gpio_bank[0].base + OMAP4_GPIO_REVISION);
-               printk(KERN_INFO "OMAP44xx GPIO hardware version %d.%d\n",
-                       (rev >> 4) & 0x0f, rev & 0x0f);
        }
 #endif
        for (i = 0; i < gpio_bank_count; i++) {
@@ -1757,6 +1724,14 @@ static int __init _omap_gpio_init(void)
 
                bank = &gpio_bank[i];
                spin_lock_init(&bank->lock);
+
+               /* Static mapping, never released */
+               bank->base = ioremap(bank->pbase, bank_size);
+               if (!bank->base) {
+                       printk(KERN_ERR "Could not ioremap gpio bank%i\n", i);
+                       continue;
+               }
+
                if (bank_is_mpuio(bank))
                        __raw_writew(0xffff, bank->base + OMAP_MPUIO_GPIO_MASKIT);
                if (cpu_is_omap15xx() && bank->method == METHOD_GPIO_1510) {
@@ -1768,11 +1743,11 @@ static int __init _omap_gpio_init(void)
                        __raw_writew(0xffff, bank->base + OMAP1610_GPIO_IRQSTATUS1);
                        __raw_writew(0x0014, bank->base + OMAP1610_GPIO_SYSCONFIG);
                }
-               if (cpu_is_omap7xx() && bank->method == METHOD_GPIO_730) {
-                       __raw_writel(0xffffffff, bank->base + OMAP730_GPIO_INT_MASK);
-                       __raw_writel(0x00000000, bank->base + OMAP730_GPIO_INT_STATUS);
+               if (cpu_is_omap7xx() && bank->method == METHOD_GPIO_7XX) {
+                       __raw_writel(0xffffffff, bank->base + OMAP7XX_GPIO_INT_MASK);
+                       __raw_writel(0x00000000, bank->base + OMAP7XX_GPIO_INT_STATUS);
 
-                       gpio_count = 32; /* 730 has 32-bit GPIOs */
+                       gpio_count = 32; /* 7xx has 32-bit GPIOs */
                }
 
 #if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX) || \
@@ -1804,6 +1779,8 @@ static int __init _omap_gpio_init(void)
                        gpio_count = 32;
                }
 #endif
+
+               bank->mod_usage = 0;
                /* REVISIT eventually switch from OMAP-specific gpio structs
                 * over to the generic ones
                 */
@@ -1862,6 +1839,8 @@ static int __init _omap_gpio_init(void)
        if (cpu_is_omap34xx())
                omap_writel(1 << 0, 0x48306814);
 
+       omap_gpio_show_rev();
+
        return 0;
 }
 
@@ -2106,6 +2085,81 @@ void omap2_gpio_resume_after_retention(void)
 
 #endif
 
+#ifdef CONFIG_ARCH_OMAP34XX
+/* save the registers of bank 2-6 */
+void omap_gpio_save_context(void)
+{
+       int i;
+
+       /* saving banks from 2-6 only since GPIO1 is in WKUP */
+       for (i = 1; i < gpio_bank_count; i++) {
+               struct gpio_bank *bank = &gpio_bank[i];
+               gpio_context[i].sysconfig =
+                       __raw_readl(bank->base + OMAP24XX_GPIO_SYSCONFIG);
+               gpio_context[i].irqenable1 =
+                       __raw_readl(bank->base + OMAP24XX_GPIO_IRQENABLE1);
+               gpio_context[i].irqenable2 =
+                       __raw_readl(bank->base + OMAP24XX_GPIO_IRQENABLE2);
+               gpio_context[i].wake_en =
+                       __raw_readl(bank->base + OMAP24XX_GPIO_WAKE_EN);
+               gpio_context[i].ctrl =
+                       __raw_readl(bank->base + OMAP24XX_GPIO_CTRL);
+               gpio_context[i].oe =
+                       __raw_readl(bank->base + OMAP24XX_GPIO_OE);
+               gpio_context[i].leveldetect0 =
+                       __raw_readl(bank->base + OMAP24XX_GPIO_LEVELDETECT0);
+               gpio_context[i].leveldetect1 =
+                       __raw_readl(bank->base + OMAP24XX_GPIO_LEVELDETECT1);
+               gpio_context[i].risingdetect =
+                       __raw_readl(bank->base + OMAP24XX_GPIO_RISINGDETECT);
+               gpio_context[i].fallingdetect =
+                       __raw_readl(bank->base + OMAP24XX_GPIO_FALLINGDETECT);
+               gpio_context[i].dataout =
+                       __raw_readl(bank->base + OMAP24XX_GPIO_DATAOUT);
+               gpio_context[i].setwkuena =
+                       __raw_readl(bank->base + OMAP24XX_GPIO_SETWKUENA);
+               gpio_context[i].setdataout =
+                       __raw_readl(bank->base + OMAP24XX_GPIO_SETDATAOUT);
+       }
+}
+
+/* restore the required registers of bank 2-6 */
+void omap_gpio_restore_context(void)
+{
+       int i;
+
+       for (i = 1; i < gpio_bank_count; i++) {
+               struct gpio_bank *bank = &gpio_bank[i];
+               __raw_writel(gpio_context[i].sysconfig,
+                               bank->base + OMAP24XX_GPIO_SYSCONFIG);
+               __raw_writel(gpio_context[i].irqenable1,
+                               bank->base + OMAP24XX_GPIO_IRQENABLE1);
+               __raw_writel(gpio_context[i].irqenable2,
+                               bank->base + OMAP24XX_GPIO_IRQENABLE2);
+               __raw_writel(gpio_context[i].wake_en,
+                               bank->base + OMAP24XX_GPIO_WAKE_EN);
+               __raw_writel(gpio_context[i].ctrl,
+                               bank->base + OMAP24XX_GPIO_CTRL);
+               __raw_writel(gpio_context[i].oe,
+                               bank->base + OMAP24XX_GPIO_OE);
+               __raw_writel(gpio_context[i].leveldetect0,
+                               bank->base + OMAP24XX_GPIO_LEVELDETECT0);
+               __raw_writel(gpio_context[i].leveldetect1,
+                               bank->base + OMAP24XX_GPIO_LEVELDETECT1);
+               __raw_writel(gpio_context[i].risingdetect,
+                               bank->base + OMAP24XX_GPIO_RISINGDETECT);
+               __raw_writel(gpio_context[i].fallingdetect,
+                               bank->base + OMAP24XX_GPIO_FALLINGDETECT);
+               __raw_writel(gpio_context[i].dataout,
+                               bank->base + OMAP24XX_GPIO_DATAOUT);
+               __raw_writel(gpio_context[i].setwkuena,
+                               bank->base + OMAP24XX_GPIO_SETWKUENA);
+               __raw_writel(gpio_context[i].setdataout,
+                               bank->base + OMAP24XX_GPIO_SETDATAOUT);
+       }
+}
+#endif
+
 /*
  * This may get called early from board specific init
  * for boards that have interrupts routed via FPGA.
@@ -2160,8 +2214,7 @@ static int dbg_gpio_show(struct seq_file *s, void *unused)
 
                if (bank_is_mpuio(bank))
                        gpio = OMAP_MPUIO(0);
-               else if (cpu_class_is_omap2() || cpu_is_omap730() ||
-                               cpu_is_omap850())
+               else if (cpu_class_is_omap2() || cpu_is_omap7xx())
                        bankwidth = 32;
 
                for (j = 0; j < bankwidth; j++, gpio++, mask <<= 1) {
index 8b84839..c08362d 100644 (file)
@@ -27,7 +27,7 @@
 #include <linux/platform_device.h>
 #include <linux/i2c.h>
 #include <mach/irqs.h>
-#include <mach/mux.h>
+#include <plat/mux.h>
 
 #define OMAP_I2C_SIZE          0x3f
 #define OMAP1_I2C_BASE         0xfffb3800
similarity index 89%
rename from arch/arm/plat-omap/include/mach/board.h
rename to arch/arm/plat-omap/include/plat/board.h
index 8e913c3..abb17b6 100644 (file)
 
 #include <linux/types.h>
 
-#include <mach/gpio-switch.h>
+#include <plat/gpio-switch.h>
+
+/*
+ * OMAP35x EVM revision
+ * Run time detection of EVM revision is done by reading Ethernet
+ * PHY ID -
+ *     GEN_1   = 0x01150000
+ *     GEN_2   = 0x92200000
+ */
+enum {
+       OMAP3EVM_BOARD_GEN_1 = 0,       /* EVM Rev between  A - D */
+       OMAP3EVM_BOARD_GEN_2,           /* EVM Rev >= Rev E */
+};
 
 /* Different peripheral ids */
 #define OMAP_TAG_CLOCK         0x4f01
@@ -157,4 +169,10 @@ extern int omap_board_config_size;
 /* for TI reference platforms sharing the same debug card */
 extern int debug_card_init(u32 addr, unsigned gpio);
 
+/* OMAP3EVM revision */
+#if defined(CONFIG_MACH_OMAP3EVM)
+u8 get_omap3_evm_rev(void);
+#else
+#define get_omap3_evm_rev() (-EINVAL)
+#endif
 #endif
@@ -16,9 +16,9 @@
 #ifndef __ASM_ARM_ARCH_OMAP_CLOCKDOMAIN_H
 #define __ASM_ARM_ARCH_OMAP_CLOCKDOMAIN_H
 
-#include <mach/powerdomain.h>
-#include <mach/clock.h>
-#include <mach/cpu.h>
+#include <plat/powerdomain.h>
+#include <plat/clock.h>
+#include <plat/cpu.h>
 
 /* Clockdomain capability flags */
 #define CLKDM_CAN_FORCE_SLEEP                  (1 << 0)
similarity index 96%
rename from arch/arm/plat-omap/include/mach/common.h
rename to arch/arm/plat-omap/include/plat/common.h
index fdeab42..064f173 100644 (file)
@@ -31,6 +31,9 @@
 
 struct sys_timer;
 
+/* used by omap-smp.c and board-4430sdp.c */
+extern void __iomem *gic_cpu_base_addr;
+
 extern void omap_map_common_io(void);
 extern struct sys_timer omap_timer;
 #if defined(CONFIG_I2C_OMAP) || defined(CONFIG_I2C_OMAP_MODULE)
similarity index 70%
rename from arch/arm/plat-omap/include/mach/control.h
rename to arch/arm/plat-omap/include/plat/control.h
index 826d317..2ae8843 100644 (file)
 
 #ifndef __ASSEMBLY__
 #define OMAP242X_CTRL_REGADDR(reg)                                     \
-       OMAP2_IO_ADDRESS(OMAP242X_CTRL_BASE + (reg))
+               OMAP2_L4_IO_ADDRESS(OMAP242X_CTRL_BASE + (reg))
 #define OMAP243X_CTRL_REGADDR(reg)                                     \
-       OMAP2_IO_ADDRESS(OMAP243X_CTRL_BASE + (reg))
+               OMAP2_L4_IO_ADDRESS(OMAP243X_CTRL_BASE + (reg))
 #define OMAP343X_CTRL_REGADDR(reg)                                     \
-       OMAP2_IO_ADDRESS(OMAP343X_CTRL_BASE + (reg))
+               OMAP2_L4_IO_ADDRESS(OMAP343X_CTRL_BASE + (reg))
 #else
-#define OMAP242X_CTRL_REGADDR(reg)     OMAP2_IO_ADDRESS(OMAP242X_CTRL_BASE + (reg))
-#define OMAP243X_CTRL_REGADDR(reg)     OMAP2_IO_ADDRESS(OMAP243X_CTRL_BASE + (reg))
-#define OMAP343X_CTRL_REGADDR(reg)     OMAP2_IO_ADDRESS(OMAP343X_CTRL_BASE + (reg))
+#define OMAP242X_CTRL_REGADDR(reg)                                     \
+               OMAP2_L4_IO_ADDRESS(OMAP242X_CTRL_BASE + (reg))
+#define OMAP243X_CTRL_REGADDR(reg)                                     \
+               OMAP2_L4_IO_ADDRESS(OMAP243X_CTRL_BASE + (reg))
+#define OMAP343X_CTRL_REGADDR(reg)                                     \
+               OMAP2_L4_IO_ADDRESS(OMAP343X_CTRL_BASE + (reg))
 #endif /* __ASSEMBLY__ */
 
 /*
 #define OMAP24XX_CONTROL_TEST_KEY_8    (OMAP2_CONTROL_GENERAL + 0x00e0)
 #define OMAP24XX_CONTROL_TEST_KEY_9    (OMAP2_CONTROL_GENERAL + 0x00e4)
 
+#define OMAP343X_CONTROL_PADCONF_SYSNIRQ (OMAP2_CONTROL_INTERFACE + 0x01b0)
+
 /* 34xx-only CONTROL_GENERAL register offsets */
 #define OMAP343X_CONTROL_PADCONF_OFF   (OMAP2_CONTROL_GENERAL + 0x0000)
 #define OMAP343X_CONTROL_MEM_DFTRW0    (OMAP2_CONTROL_GENERAL + 0x0008)
 #define OMAP343X_CONTROL_TEST_KEY_13   (OMAP2_CONTROL_GENERAL + 0x00fc)
 #define OMAP343X_CONTROL_IVA2_BOOTADDR (OMAP2_CONTROL_GENERAL + 0x0190)
 #define OMAP343X_CONTROL_IVA2_BOOTMOD  (OMAP2_CONTROL_GENERAL + 0x0194)
-#define OMAP343X_CONTROL_PBIAS_LITE    (OMAP2_CONTROL_GENERAL + 0x02b0)
-#define OMAP343X_CONTROL_TEMP_SENSOR   (OMAP2_CONTROL_GENERAL + 0x02b4)
+#define OMAP343X_CONTROL_DEBOBS(i)     (OMAP2_CONTROL_GENERAL + 0x01B0 \
+                                       + ((i) >> 1) * 4 + (!(i) & 1) * 2)
+#define OMAP343X_CONTROL_PROG_IO0      (OMAP2_CONTROL_GENERAL + 0x01D4)
+#define OMAP343X_CONTROL_PROG_IO1      (OMAP2_CONTROL_GENERAL + 0x01D8)
+#define OMAP343X_CONTROL_DSS_DPLL_SPREADING    (OMAP2_CONTROL_GENERAL + 0x01E0)
+#define OMAP343X_CONTROL_CORE_DPLL_SPREADING   (OMAP2_CONTROL_GENERAL + 0x01E4)
+#define OMAP343X_CONTROL_PER_DPLL_SPREADING    (OMAP2_CONTROL_GENERAL + 0x01E8)
+#define OMAP343X_CONTROL_USBHOST_DPLL_SPREADING        (OMAP2_CONTROL_GENERAL + 0x01EC)
+#define OMAP343X_CONTROL_PBIAS_LITE    (OMAP2_CONTROL_GENERAL + 0x02B0)
+#define OMAP343X_CONTROL_TEMP_SENSOR   (OMAP2_CONTROL_GENERAL + 0x02B4)
+#define OMAP343X_CONTROL_SRAMLDO4      (OMAP2_CONTROL_GENERAL + 0x02B8)
+#define OMAP343X_CONTROL_SRAMLDO5      (OMAP2_CONTROL_GENERAL + 0x02C0)
+#define OMAP343X_CONTROL_CSI           (OMAP2_CONTROL_GENERAL + 0x02C4)
+
+
+/* 34xx PADCONF register offsets */
+#define OMAP343X_PADCONF_ETK(i)                (OMAP2_CONTROL_PADCONFS + 0x5a8 + \
+                                               (i)*2)
+#define OMAP343X_PADCONF_ETK_CLK       OMAP343X_PADCONF_ETK(0)
+#define OMAP343X_PADCONF_ETK_CTL       OMAP343X_PADCONF_ETK(1)
+#define OMAP343X_PADCONF_ETK_D0                OMAP343X_PADCONF_ETK(2)
+#define OMAP343X_PADCONF_ETK_D1                OMAP343X_PADCONF_ETK(3)
+#define OMAP343X_PADCONF_ETK_D2                OMAP343X_PADCONF_ETK(4)
+#define OMAP343X_PADCONF_ETK_D3                OMAP343X_PADCONF_ETK(5)
+#define OMAP343X_PADCONF_ETK_D4                OMAP343X_PADCONF_ETK(6)
+#define OMAP343X_PADCONF_ETK_D5                OMAP343X_PADCONF_ETK(7)
+#define OMAP343X_PADCONF_ETK_D6                OMAP343X_PADCONF_ETK(8)
+#define OMAP343X_PADCONF_ETK_D7                OMAP343X_PADCONF_ETK(9)
+#define OMAP343X_PADCONF_ETK_D8                OMAP343X_PADCONF_ETK(10)
+#define OMAP343X_PADCONF_ETK_D9                OMAP343X_PADCONF_ETK(11)
+#define OMAP343X_PADCONF_ETK_D10       OMAP343X_PADCONF_ETK(12)
+#define OMAP343X_PADCONF_ETK_D11       OMAP343X_PADCONF_ETK(13)
+#define OMAP343X_PADCONF_ETK_D12       OMAP343X_PADCONF_ETK(14)
+#define OMAP343X_PADCONF_ETK_D13       OMAP343X_PADCONF_ETK(15)
+#define OMAP343X_PADCONF_ETK_D14       OMAP343X_PADCONF_ETK(16)
+#define OMAP343X_PADCONF_ETK_D15       OMAP343X_PADCONF_ETK(17)
+
+/* 34xx GENERAL_WKUP regist offsets */
+#define OMAP343X_CONTROL_WKUP_DEBOBSMUX(i) (OMAP343X_CONTROL_GENERAL_WKUP + \
+                                               0x008 + (i))
+#define OMAP343X_CONTROL_WKUP_DEBOBS0 (OMAP343X_CONTROL_GENERAL_WKUP + 0x008)
+#define OMAP343X_CONTROL_WKUP_DEBOBS1 (OMAP343X_CONTROL_GENERAL_WKUP + 0x00C)
+#define OMAP343X_CONTROL_WKUP_DEBOBS2 (OMAP343X_CONTROL_GENERAL_WKUP + 0x010)
+#define OMAP343X_CONTROL_WKUP_DEBOBS3 (OMAP343X_CONTROL_GENERAL_WKUP + 0x014)
+#define OMAP343X_CONTROL_WKUP_DEBOBS4 (OMAP343X_CONTROL_GENERAL_WKUP + 0x018)
 
 /* 34xx D2D idle-related pins, handled by PM core */
 #define OMAP3_PADCONF_SAD2D_MSTANDBY   0x250
 #define OMAP2_PBIASLITEPWRDNZ0         (1 << 1)
 #define OMAP2_PBIASLITEVMODE0          (1 << 0)
 
+/* CONTROL_PROG_IO1 bits */
+#define OMAP3630_PRG_SDMMC1_SPEEDCTRL  (1 << 20)
+
 /* CONTROL_IVA2_BOOTMOD bits */
 #define OMAP3_IVA2_BOOTMOD_SHIFT       0
 #define OMAP3_IVA2_BOOTMOD_MASK                (0xf << 0)
 #define OMAP3_PADCONF_WAKEUPEVENT0     (1 << 15)
 #define OMAP3_PADCONF_WAKEUPENABLE0    (1 << 14)
 
+#define OMAP343X_SCRATCHPAD_ROM                (OMAP343X_CTRL_BASE + 0x860)
+#define OMAP343X_SCRATCHPAD            (OMAP343X_CTRL_BASE + 0x910)
+#define OMAP343X_SCRATCHPAD_ROM_OFFSET 0x19C
+
+/*
+ * CONTROL OMAP STATUS register to identify OMAP3 features
+ */
+#define OMAP3_CONTROL_OMAP_STATUS      0x044c
+
+#define OMAP3_SGX_SHIFT                        13
+#define OMAP3_SGX_MASK                 (3 << OMAP3_SGX_SHIFT)
+#define                FEAT_SGX_FULL           0
+#define                FEAT_SGX_HALF           1
+#define                FEAT_SGX_NONE           2
+
+#define OMAP3_IVA_SHIFT                        12
+#define OMAP3_IVA_MASK                 (1 << OMAP3_SGX_SHIFT)
+#define                FEAT_IVA                0
+#define                FEAT_IVA_NONE           1
+
+#define OMAP3_L2CACHE_SHIFT            10
+#define OMAP3_L2CACHE_MASK             (3 << OMAP3_L2CACHE_SHIFT)
+#define                FEAT_L2CACHE_NONE       0
+#define                FEAT_L2CACHE_64KB       1
+#define                FEAT_L2CACHE_128KB      2
+#define                FEAT_L2CACHE_256KB      3
+
+#define OMAP3_ISP_SHIFT                        5
+#define OMAP3_ISP_MASK                 (1<< OMAP3_ISP_SHIFT)
+#define                FEAT_ISP                0
+#define                FEAT_ISP_NONE           1
+
+#define OMAP3_NEON_SHIFT               4
+#define OMAP3_NEON_MASK                        (1<< OMAP3_NEON_SHIFT)
+#define                FEAT_NEON               0
+#define                FEAT_NEON_NONE          1
+
+
 #ifndef __ASSEMBLY__
 #if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3) || \
                defined(CONFIG_ARCH_OMAP4)
@@ -212,6 +301,15 @@ extern u32 omap_ctrl_readl(u16 offset);
 extern void omap_ctrl_writeb(u8 val, u16 offset);
 extern void omap_ctrl_writew(u16 val, u16 offset);
 extern void omap_ctrl_writel(u32 val, u16 offset);
+
+extern void omap3_save_scratchpad_contents(void);
+extern void omap3_clear_scratchpad_contents(void);
+extern u32 *get_restore_pointer(void);
+extern u32 *get_es3_restore_pointer(void);
+extern u32 omap3_arm_context[128];
+extern void omap3_control_save_context(void);
+extern void omap3_control_restore_context(void);
+
 #else
 #define omap_ctrl_base_get()           0
 #define omap_ctrl_readb(x)             0
similarity index 80%
rename from arch/arm/plat-omap/include/mach/cpu.h
rename to arch/arm/plat-omap/include/plat/cpu.h
index f129efb..2e17890 100644 (file)
@@ -30,6 +30,8 @@
 #ifndef __ASM_ARCH_OMAP_CPU_H
 #define __ASM_ARCH_OMAP_CPU_H
 
+#include <linux/bitops.h>
+
 /*
  * Omap device type i.e. EMU/HS/TST/GP/BAD
  */
@@ -57,6 +59,23 @@ struct omap_chip_id {
 unsigned int omap_rev(void);
 
 /*
+ * Define CPU revision bits
+ *
+ * Verbose meaning of the revision bits may be different for a silicon
+ * family. This difference can be handled separately.
+ */
+#define OMAP_REVBITS_00                0x00
+#define OMAP_REVBITS_10                0x10
+#define OMAP_REVBITS_20                0x20
+#define OMAP_REVBITS_30                0x30
+#define OMAP_REVBITS_40                0x40
+
+/*
+ * Get the CPU revision for OMAP devices
+ */
+#define GET_OMAP_REVISION()    ((omap_rev() >> 8) & 0xff)
+
+/*
  * Test if multicore OMAP support is needed
  */
 #undef MULTI_OMAP1
@@ -161,6 +180,7 @@ IS_OMAP_CLASS(34xx, 0x34)
 IS_OMAP_SUBCLASS(242x, 0x242)
 IS_OMAP_SUBCLASS(243x, 0x243)
 IS_OMAP_SUBCLASS(343x, 0x343)
+IS_OMAP_SUBCLASS(363x, 0x363)
 
 #define cpu_is_omap7xx()               0
 #define cpu_is_omap15xx()              0
@@ -264,6 +284,8 @@ IS_OMAP_SUBCLASS(343x, 0x343)
  * cpu_is_omap2423():  True for OMAP2423
  * cpu_is_omap2430():  True for OMAP2430
  * cpu_is_omap3430():  True for OMAP3430
+ * cpu_is_omap3505():  True for OMAP3505
+ * cpu_is_omap3517():  True for OMAP3517
  */
 #define GET_OMAP_TYPE  ((omap_rev() >> 16) & 0xffff)
 
@@ -287,6 +309,8 @@ IS_OMAP_TYPE(2422, 0x2422)
 IS_OMAP_TYPE(2423, 0x2423)
 IS_OMAP_TYPE(2430, 0x2430)
 IS_OMAP_TYPE(3430, 0x3430)
+IS_OMAP_TYPE(3505, 0x3505)
+IS_OMAP_TYPE(3517, 0x3517)
 
 #define cpu_is_omap310()               0
 #define cpu_is_omap730()               0
@@ -301,7 +325,14 @@ IS_OMAP_TYPE(3430, 0x3430)
 #define cpu_is_omap2422()              0
 #define cpu_is_omap2423()              0
 #define cpu_is_omap2430()              0
+#define cpu_is_omap3503()              0
+#define cpu_is_omap3515()              0
+#define cpu_is_omap3525()              0
+#define cpu_is_omap3530()              0
+#define cpu_is_omap3505()              0
+#define cpu_is_omap3517()              0
 #define cpu_is_omap3430()              0
+#define cpu_is_omap3630()              0
 
 /*
  * Whether we have MULTI_OMAP1 or not, we still need to distinguish
@@ -351,7 +382,27 @@ IS_OMAP_TYPE(3430, 0x3430)
 
 #if defined(CONFIG_ARCH_OMAP34XX)
 # undef cpu_is_omap3430
+# undef cpu_is_omap3503
+# undef cpu_is_omap3515
+# undef cpu_is_omap3525
+# undef cpu_is_omap3530
+# undef cpu_is_omap3505
+# undef cpu_is_omap3517
 # define cpu_is_omap3430()             is_omap3430()
+# define cpu_is_omap3503()             (cpu_is_omap3430() &&           \
+                                               (!omap3_has_iva()) &&   \
+                                               (!omap3_has_sgx()))
+# define cpu_is_omap3515()             (cpu_is_omap3430() &&           \
+                                               (omap3_has_iva()) &&    \
+                                               (!omap3_has_sgx()))
+# define cpu_is_omap3525()             (cpu_is_omap3430() &&           \
+                                               (omap3_has_sgx()) &&    \
+                                               (!omap3_has_iva()))
+# define cpu_is_omap3530()             (cpu_is_omap3430())
+# define cpu_is_omap3505()             is_omap3505()
+# define cpu_is_omap3517()             is_omap3517()
+# undef cpu_is_omap3630
+# define cpu_is_omap3630()             is_omap363x()
 #endif
 
 # if defined(CONFIG_ARCH_OMAP4)
@@ -382,6 +433,16 @@ IS_OMAP_TYPE(3430, 0x3430)
 #define OMAP3430_REV_ES3_0     0x34303034
 #define OMAP3430_REV_ES3_1     0x34304034
 
+#define OMAP3630_REV_ES1_0     0x36300034
+
+#define OMAP35XX_CLASS         0x35000034
+#define OMAP3503_REV(v)                (OMAP35XX_CLASS | (0x3503 << 16) | (v << 12))
+#define OMAP3515_REV(v)                (OMAP35XX_CLASS | (0x3515 << 16) | (v << 12))
+#define OMAP3525_REV(v)                (OMAP35XX_CLASS | (0x3525 << 16) | (v << 12))
+#define OMAP3530_REV(v)                (OMAP35XX_CLASS | (0x3530 << 16) | (v << 12))
+#define OMAP3505_REV(v)                (OMAP35XX_CLASS | (0x3505 << 16) | (v << 12))
+#define OMAP3517_REV(v)                (OMAP35XX_CLASS | (0x3517 << 16) | (v << 12))
+
 #define OMAP443X_CLASS         0x44300034
 
 /*
@@ -405,6 +466,7 @@ IS_OMAP_TYPE(3430, 0x3430)
 #define CHIP_IS_OMAP3430ES2            (1 << 4)
 #define CHIP_IS_OMAP3430ES3_0          (1 << 5)
 #define CHIP_IS_OMAP3430ES3_1          (1 << 6)
+#define CHIP_IS_OMAP3630ES1            (1 << 7)
 
 #define CHIP_IS_OMAP24XX               (CHIP_IS_OMAP2420 | CHIP_IS_OMAP2430)
 
@@ -416,11 +478,36 @@ IS_OMAP_TYPE(3430, 0x3430)
  */
 #define CHIP_GE_OMAP3430ES2            (CHIP_IS_OMAP3430ES2 | \
                                         CHIP_IS_OMAP3430ES3_0 | \
-                                        CHIP_IS_OMAP3430ES3_1)
-#define CHIP_GE_OMAP3430ES3_1          (CHIP_IS_OMAP3430ES3_1)
+                                        CHIP_IS_OMAP3430ES3_1 | \
+                                        CHIP_IS_OMAP3630ES1)
+#define CHIP_GE_OMAP3430ES3_1          (CHIP_IS_OMAP3430ES3_1 | \
+                                        CHIP_IS_OMAP3630ES1)
 
 
 int omap_chip_is(struct omap_chip_id oci);
 void omap2_check_revision(void);
 
+/*
+ * Runtime detection of OMAP3 features
+ */
+extern u32 omap3_features;
+
+#define OMAP3_HAS_L2CACHE              BIT(0)
+#define OMAP3_HAS_IVA                  BIT(1)
+#define OMAP3_HAS_SGX                  BIT(2)
+#define OMAP3_HAS_NEON                 BIT(3)
+#define OMAP3_HAS_ISP                  BIT(4)
+
+#define OMAP3_HAS_FEATURE(feat,flag)                   \
+static inline unsigned int omap3_has_ ##feat(void)     \
+{                                                      \
+       return (omap3_features & OMAP3_HAS_ ##flag);    \
+}                                                      \
+
+OMAP3_HAS_FEATURE(l2cache, L2CACHE)
+OMAP3_HAS_FEATURE(sgx, SGX)
+OMAP3_HAS_FEATURE(iva, IVA)
+OMAP3_HAS_FEATURE(neon, NEON)
+OMAP3_HAS_FEATURE(isp, ISP)
+
 #endif
similarity index 99%
rename from arch/arm/plat-omap/include/mach/dma.h
rename to arch/arm/plat-omap/include/plat/dma.h
index 72f680b..1c017b2 100644 (file)
@@ -633,6 +633,11 @@ extern void omap_set_dma_dst_endian_type(int lch, enum end_type etype);
 extern void omap_set_dma_src_endian_type(int lch, enum end_type etype);
 extern int omap_get_dma_index(int lch, int *ei, int *fi);
 
+void omap_dma_global_context_save(void);
+void omap_dma_global_context_restore(void);
+
+extern void omap_dma_disable_irq(int lch);
+
 /* Chaining APIs */
 #ifndef CONFIG_ARCH_OMAP1
 extern int omap_request_dma_chain(int dev_id, const char *dev_name,
similarity index 97%
rename from arch/arm/plat-omap/include/mach/gpio.h
rename to arch/arm/plat-omap/include/plat/gpio.h
index 633ff68..de7c547 100644 (file)
@@ -76,7 +76,8 @@ extern void omap2_gpio_prepare_for_retention(void);
 extern void omap2_gpio_resume_after_retention(void);
 extern void omap_set_gpio_debounce(int gpio, int enable);
 extern void omap_set_gpio_debounce_time(int gpio, int enable);
-
+extern void omap_gpio_save_context(void);
+extern void omap_gpio_restore_context(void);
 /*-------------------------------------------------------------------------*/
 
 /* Wrappers for "new style" GPIO calls, using the new infrastructure
similarity index 97%
rename from arch/arm/plat-omap/include/mach/gpmc.h
rename to arch/arm/plat-omap/include/plat/gpmc.h
index 9c99cda..696e0ca 100644 (file)
@@ -52,6 +52,7 @@
 #define GPMC_CONFIG1_FCLK_DIV2          (GPMC_CONFIG1_FCLK_DIV(1))
 #define GPMC_CONFIG1_FCLK_DIV3          (GPMC_CONFIG1_FCLK_DIV(2))
 #define GPMC_CONFIG1_FCLK_DIV4          (GPMC_CONFIG1_FCLK_DIV(3))
+#define GPMC_CONFIG7_CSVALID           (1 << 6)
 
 /*
  * Note that all values in this struct are in nanoseconds, while
@@ -107,6 +108,8 @@ extern int gpmc_prefetch_enable(int cs, int dma_mode,
                                        unsigned int u32_count, int is_write);
 extern void gpmc_prefetch_reset(void);
 extern int gpmc_prefetch_status(void);
+extern void omap3_gpmc_save_context(void);
+extern void omap3_gpmc_restore_context(void);
 extern void __init gpmc_init(void);
 
 #endif
similarity index 98%
rename from arch/arm/plat-omap/include/mach/hardware.h
rename to arch/arm/plat-omap/include/plat/hardware.h
index 26c1fbf..d5b26ad 100644 (file)
@@ -39,9 +39,9 @@
 #include <asm/sizes.h>
 #ifndef __ASSEMBLER__
 #include <asm/types.h>
-#include <mach/cpu.h>
+#include <plat/cpu.h>
 #endif
-#include <mach/serial.h>
+#include <plat/serial.h>
 
 /*
  * ---------------------------------------------------------------------------
  * ---------------------------------------------------------------------------
  */
 
-#include "omap730.h"
-#include "omap1510.h"
-#include "omap16xx.h"
-#include "omap24xx.h"
-#include "omap34xx.h"
-#include "omap44xx.h"
+#include <plat/omap7xx.h>
+#include <plat/omap1510.h>
+#include <plat/omap16xx.h>
+#include <plat/omap24xx.h>
+#include <plat/omap34xx.h>
+#include <plat/omap44xx.h>
 
 #endif /* __ASM_ARCH_OMAP_HARDWARE_H */
similarity index 60%
rename from arch/arm/plat-omap/include/mach/io.h
rename to arch/arm/plat-omap/include/plat/io.h
index 8d32df3..7e5319f 100644 (file)
 #define OMAP1_IO_OFFSET                0x01000000      /* Virtual IO = 0xfefb0000 */
 #define OMAP1_IO_ADDRESS(pa)   IOMEM((pa) - OMAP1_IO_OFFSET)
 
-#define OMAP2_IO_OFFSET                0x90000000
-#define OMAP2_IO_ADDRESS(pa)   IOMEM((pa) + OMAP2_IO_OFFSET) /* L3 and L4 */
+#define OMAP2_L3_IO_OFFSET     0x90000000
+#define OMAP2_L3_IO_ADDRESS(pa)        IOMEM((pa) + OMAP2_L3_IO_OFFSET) /* L3 */
+
+
+#define OMAP2_L4_IO_OFFSET     0xb2000000
+#define OMAP2_L4_IO_ADDRESS(pa)        IOMEM((pa) + OMAP2_L4_IO_OFFSET) /* L4 */
+
+#define OMAP4_L3_IO_OFFSET     0xb4000000
+#define OMAP4_L3_IO_ADDRESS(pa)        IOMEM((pa) + OMAP4_L3_IO_OFFSET) /* L3 */
+
+#define OMAP4_L3_PER_IO_OFFSET 0xb1100000
+#define OMAP4_L3_PER_IO_ADDRESS(pa)    IOMEM((pa) + OMAP4_L3_PER_IO_OFFSET)
+
+#define OMAP4_GPMC_IO_OFFSET           0xa9000000
+#define OMAP4_GPMC_IO_ADDRESS(pa)      IOMEM((pa) + OMAP4_GPMC_IO_OFFSET)
+
+#define OMAP2_EMU_IO_OFFSET            0xaa800000      /* Emulation */
+#define OMAP2_EMU_IO_ADDRESS(pa)       IOMEM((pa) + OMAP2_EMU_IO_OFFSET)
 
 /*
  * ----------------------------------------------------------------------------
  */
 
 /* We map both L3 and L4 on OMAP2 */
-#define L3_24XX_PHYS   L3_24XX_BASE    /* 0x68000000 */
-#define L3_24XX_VIRT   0xf8000000
+#define L3_24XX_PHYS   L3_24XX_BASE    /* 0x68000000 --> 0xf8000000*/
+#define L3_24XX_VIRT   (L3_24XX_PHYS + OMAP2_L3_IO_OFFSET)
 #define L3_24XX_SIZE   SZ_1M           /* 44kB of 128MB used, want 1MB sect */
-#define L4_24XX_PHYS   L4_24XX_BASE    /* 0x48000000 */
-#define L4_24XX_VIRT   0xd8000000
+#define L4_24XX_PHYS   L4_24XX_BASE    /* 0x48000000 --> 0xfa000000 */
+#define L4_24XX_VIRT   (L4_24XX_PHYS + OMAP2_L4_IO_OFFSET)
 #define L4_24XX_SIZE   SZ_1M           /* 1MB of 128MB used, want 1MB sect */
 
-#define L4_WK_243X_PHYS                L4_WK_243X_BASE         /* 0x49000000 */
-#define L4_WK_243X_VIRT                0xd9000000
+#define L4_WK_243X_PHYS                L4_WK_243X_BASE /* 0x49000000 --> 0xfb000000 */
+#define L4_WK_243X_VIRT                (L4_WK_243X_PHYS + OMAP2_L4_IO_OFFSET)
 #define L4_WK_243X_SIZE                SZ_1M
-#define OMAP243X_GPMC_PHYS     OMAP243X_GPMC_BASE      /* 0x49000000 */
-#define OMAP243X_GPMC_VIRT     0xFE000000
+#define OMAP243X_GPMC_PHYS     OMAP243X_GPMC_BASE
+#define OMAP243X_GPMC_VIRT     (OMAP243X_GPMC_PHYS + OMAP2_L3_IO_OFFSET)
+                                               /* 0x6e000000 --> 0xfe000000 */
 #define OMAP243X_GPMC_SIZE     SZ_1M
 #define OMAP243X_SDRC_PHYS     OMAP243X_SDRC_BASE
-#define OMAP243X_SDRC_VIRT     0xFD000000
+                                               /* 0x6D000000 --> 0xfd000000 */
+#define OMAP243X_SDRC_VIRT     (OMAP243X_SDRC_PHYS + OMAP2_L3_IO_OFFSET)
 #define OMAP243X_SDRC_SIZE     SZ_1M
 #define OMAP243X_SMS_PHYS      OMAP243X_SMS_BASE
-#define OMAP243X_SMS_VIRT      0xFC000000
+                                               /* 0x6c000000 --> 0xfc000000 */
+#define OMAP243X_SMS_VIRT      (OMAP243X_SMS_PHYS + OMAP2_L3_IO_OFFSET)
 #define OMAP243X_SMS_SIZE      SZ_1M
 
 /* DSP */
  */
 
 /* We map both L3 and L4 on OMAP3 */
-#define L3_34XX_PHYS           L3_34XX_BASE    /* 0x68000000 */
-#define L3_34XX_VIRT           0xf8000000
+#define L3_34XX_PHYS           L3_34XX_BASE    /* 0x68000000 --> 0xf8000000 */
+#define L3_34XX_VIRT           (L3_34XX_PHYS + OMAP2_L3_IO_OFFSET)
 #define L3_34XX_SIZE           SZ_1M   /* 44kB of 128MB used, want 1MB sect */
 
-#define L4_34XX_PHYS           L4_34XX_BASE    /* 0x48000000 */
-#define L4_34XX_VIRT           0xd8000000
+#define L4_34XX_PHYS           L4_34XX_BASE    /* 0x48000000 --> 0xfa000000 */
+#define L4_34XX_VIRT           (L4_34XX_PHYS + OMAP2_L4_IO_OFFSET)
 #define L4_34XX_SIZE           SZ_4M   /* 1MB of 128MB used, want 1MB sect */
 
 /*
  * VPOM3430 was not working for Int controller
  */
 
-#define L4_WK_34XX_PHYS                L4_WK_34XX_BASE /* 0x48300000 */
-#define L4_WK_34XX_VIRT                0xd8300000
+#define L4_WK_34XX_PHYS                L4_WK_34XX_BASE /* 0x48300000 --> 0xfa300000 */
+#define L4_WK_34XX_VIRT                (L4_WK_34XX_PHYS + OMAP2_L4_IO_OFFSET)
 #define L4_WK_34XX_SIZE                SZ_1M
 
-#define L4_PER_34XX_PHYS       L4_PER_34XX_BASE /* 0x49000000 */
-#define L4_PER_34XX_VIRT       0xd9000000
+#define L4_PER_34XX_PHYS       L4_PER_34XX_BASE
+                                               /* 0x49000000 --> 0xfb000000 */
+#define L4_PER_34XX_VIRT       (L4_PER_34XX_PHYS + OMAP2_L4_IO_OFFSET)
 #define L4_PER_34XX_SIZE       SZ_1M
 
-#define L4_EMU_34XX_PHYS       L4_EMU_34XX_BASE /* 0x54000000 */
-#define L4_EMU_34XX_VIRT       0xe4000000
-#define L4_EMU_34XX_SIZE       SZ_64M
+#define L4_EMU_34XX_PHYS       L4_EMU_34XX_BASE
+                                               /* 0x54000000 --> 0xfe800000 */
+#define L4_EMU_34XX_VIRT       (L4_EMU_34XX_PHYS + OMAP2_EMU_IO_OFFSET)
+#define L4_EMU_34XX_SIZE       SZ_8M
 
-#define OMAP34XX_GPMC_PHYS     OMAP34XX_GPMC_BASE /* 0x6E000000 */
-#define OMAP34XX_GPMC_VIRT     0xFE000000
+#define OMAP34XX_GPMC_PHYS     OMAP34XX_GPMC_BASE
+                                               /* 0x6e000000 --> 0xfe000000 */
+#define OMAP34XX_GPMC_VIRT     (OMAP34XX_GPMC_PHYS + OMAP2_L3_IO_OFFSET)
 #define OMAP34XX_GPMC_SIZE     SZ_1M
 
-#define OMAP343X_SMS_PHYS      OMAP343X_SMS_BASE /* 0x6C000000 */
-#define OMAP343X_SMS_VIRT      0xFC000000
+#define OMAP343X_SMS_PHYS      OMAP343X_SMS_BASE
+                                               /* 0x6c000000 --> 0xfc000000 */
+#define OMAP343X_SMS_VIRT      (OMAP343X_SMS_PHYS + OMAP2_L3_IO_OFFSET)
 #define OMAP343X_SMS_SIZE      SZ_1M
 
-#define OMAP343X_SDRC_PHYS     OMAP343X_SDRC_BASE /* 0x6D000000 */
-#define OMAP343X_SDRC_VIRT     0xFD000000
+#define OMAP343X_SDRC_PHYS     OMAP343X_SDRC_BASE
+                                               /* 0x6D000000 --> 0xfd000000 */
+#define OMAP343X_SDRC_VIRT     (OMAP343X_SDRC_PHYS + OMAP2_L3_IO_OFFSET)
 #define OMAP343X_SDRC_SIZE     SZ_1M
 
 /* DSP */
  */
 
 /* We map both L3 and L4 on OMAP4 */
-#define L3_44XX_PHYS           L3_44XX_BASE
-#define L3_44XX_VIRT           0xd4000000
+#define L3_44XX_PHYS           L3_44XX_BASE    /* 0x44000000 --> 0xf8000000 */
+#define L3_44XX_VIRT           (L3_44XX_PHYS + OMAP4_L3_IO_OFFSET)
 #define L3_44XX_SIZE           SZ_1M
 
-#define L4_44XX_PHYS           L4_44XX_BASE
-#define L4_44XX_VIRT           0xda000000
+#define L4_44XX_PHYS           L4_44XX_BASE    /* 0x4a000000 --> 0xfc000000 */
+#define L4_44XX_VIRT           (L4_44XX_PHYS + OMAP2_L4_IO_OFFSET)
 #define L4_44XX_SIZE           SZ_4M
 
 
-#define L4_WK_44XX_PHYS                L4_WK_44XX_BASE
-#define L4_WK_44XX_VIRT                0xda300000
+#define L4_WK_44XX_PHYS                L4_WK_44XX_BASE /* 0x4a300000 --> 0xfc300000 */
+#define L4_WK_44XX_VIRT                (L4_WK_44XX_PHYS + OMAP2_L4_IO_OFFSET)
 #define L4_WK_44XX_SIZE                SZ_1M
 
 #define L4_PER_44XX_PHYS       L4_PER_44XX_BASE
-#define L4_PER_44XX_VIRT       0xd8000000
+                                               /* 0x48000000 --> 0xfa000000 */
+#define L4_PER_44XX_VIRT       (L4_PER_44XX_PHYS + OMAP2_L4_IO_OFFSET)
 #define L4_PER_44XX_SIZE       SZ_4M
 
+#define L4_ABE_44XX_PHYS       L4_ABE_44XX_BASE
+                                               /* 0x49000000 --> 0xfb000000 */
+#define L4_ABE_44XX_VIRT       (L4_ABE_44XX_PHYS + OMAP2_L4_IO_OFFSET)
+#define L4_ABE_44XX_SIZE       SZ_1M
+
 #define L4_EMU_44XX_PHYS       L4_EMU_44XX_BASE
-#define L4_EMU_44XX_VIRT       0xe4000000
-#define L4_EMU_44XX_SIZE       SZ_64M
+                                               /* 0x54000000 --> 0xfe800000 */
+#define L4_EMU_44XX_VIRT       (L4_EMU_44XX_PHYS + OMAP2_EMU_IO_OFFSET)
+#define L4_EMU_44XX_SIZE       SZ_8M
 
 #define OMAP44XX_GPMC_PHYS     OMAP44XX_GPMC_BASE
-#define OMAP44XX_GPMC_VIRT     0xe0000000
+                                               /* 0x50000000 --> 0xf9000000 */
+#define OMAP44XX_GPMC_VIRT     (OMAP44XX_GPMC_PHYS + OMAP4_GPMC_IO_OFFSET)
 #define OMAP44XX_GPMC_SIZE     SZ_1M
 
 
+#define OMAP44XX_EMIF1_PHYS    OMAP44XX_EMIF1_BASE
+                                               /* 0x4c000000 --> 0xfd100000 */
+#define OMAP44XX_EMIF1_VIRT    (OMAP44XX_EMIF1_PHYS + OMAP4_L3_PER_IO_OFFSET)
+#define OMAP44XX_EMIF1_SIZE    SZ_1M
+
+#define OMAP44XX_EMIF2_PHYS    OMAP44XX_EMIF2_BASE
+                                               /* 0x4d000000 --> 0xfd200000 */
+#define OMAP44XX_EMIF2_VIRT    (OMAP44XX_EMIF2_PHYS + OMAP4_L3_PER_IO_OFFSET)
+#define OMAP44XX_EMIF2_SIZE    SZ_1M
+
+#define OMAP44XX_DMM_PHYS      OMAP44XX_DMM_BASE
+                                               /* 0x4e000000 --> 0xfd300000 */
+#define OMAP44XX_DMM_VIRT      (OMAP44XX_DMM_PHYS + OMAP4_L3_PER_IO_OFFSET)
+#define OMAP44XX_DMM_SIZE      SZ_1M
 /*
  * ----------------------------------------------------------------------------
  * Omap specific register access
similarity index 99%
rename from arch/arm/plat-omap/include/mach/iommu.h
rename to arch/arm/plat-omap/include/plat/iommu.h
index 46d41ac..0752af9 100644 (file)
@@ -107,7 +107,7 @@ struct iommu_platform_data {
 #if defined(CONFIG_ARCH_OMAP1)
 #error "iommu for this processor not implemented yet"
 #else
-#include <mach/iommu2.h>
+#include <plat/iommu2.h>
 #endif
 
 /*
similarity index 70%
rename from arch/arm/plat-omap/include/mach/irqs.h
rename to arch/arm/plat-omap/include/plat/irqs.h
index 28a1650..ce5dd2d 100644 (file)
 #define INT_1610_SSR_FIFO_0    29
 
 /*
- * OMAP-730 specific IRQ numbers for interrupt handler 1
+ * OMAP-7xx specific IRQ numbers for interrupt handler 1
  */
-#define INT_730_IH2_FIQ                0
-#define INT_730_IH2_IRQ                1
-#define INT_730_USB_NON_ISO    2
-#define INT_730_USB_ISO                3
-#define INT_730_ICR            4
-#define INT_730_EAC            5
-#define INT_730_GPIO_BANK1     6
-#define INT_730_GPIO_BANK2     7
-#define INT_730_GPIO_BANK3     8
-#define INT_730_McBSP2TX       10
-#define INT_730_McBSP2RX       11
-#define INT_730_McBSP2RX_OVF   12
-#define INT_730_LCD_LINE       14
-#define INT_730_GSM_PROTECT    15
-#define INT_730_TIMER3         16
-#define INT_730_GPIO_BANK5     17
-#define INT_730_GPIO_BANK6     18
-#define INT_730_SPGIO_WR       29
-
-/*
- * OMAP-850 specific IRQ numbers for interrupt handler 1
- */
-#define INT_850_IH2_FIQ                0
-#define INT_850_IH2_IRQ                1
-#define INT_850_USB_NON_ISO    2
-#define INT_850_USB_ISO                3
-#define INT_850_ICR            4
-#define INT_850_EAC            5
-#define INT_850_GPIO_BANK1     6
-#define INT_850_GPIO_BANK2     7
-#define INT_850_GPIO_BANK3     8
-#define INT_850_McBSP2TX       10
-#define INT_850_McBSP2RX       11
-#define INT_850_McBSP2RX_OVF   12
-#define INT_850_LCD_LINE       14
-#define INT_850_GSM_PROTECT    15
-#define INT_850_TIMER3         16
-#define INT_850_GPIO_BANK5     17
-#define INT_850_GPIO_BANK6     18
-#define INT_850_SPGIO_WR       29
-
+#define INT_7XX_IH2_FIQ                0
+#define INT_7XX_IH2_IRQ                1
+#define INT_7XX_USB_NON_ISO    2
+#define INT_7XX_USB_ISO                3
+#define INT_7XX_ICR            4
+#define INT_7XX_EAC            5
+#define INT_7XX_GPIO_BANK1     6
+#define INT_7XX_GPIO_BANK2     7
+#define INT_7XX_GPIO_BANK3     8
+#define INT_7XX_McBSP2TX       10
+#define INT_7XX_McBSP2RX       11
+#define INT_7XX_McBSP2RX_OVF   12
+#define INT_7XX_LCD_LINE       14
+#define INT_7XX_GSM_PROTECT    15
+#define INT_7XX_TIMER3         16
+#define INT_7XX_GPIO_BANK5     17
+#define INT_7XX_GPIO_BANK6     18
+#define INT_7XX_SPGIO_WR       29
 
 /*
  * IRQ numbers for interrupt handler 2
 #define INT_1610_SHA1MD5       (91 + IH2_BASE)
 
 /*
- * OMAP-730 specific IRQ numbers for interrupt handler 2
+ * OMAP-7xx specific IRQ numbers for interrupt handler 2
  */
-#define INT_730_HW_ERRORS      (0 + IH2_BASE)
-#define INT_730_NFIQ_PWR_FAIL  (1 + IH2_BASE)
-#define INT_730_CFCD           (2 + IH2_BASE)
-#define INT_730_CFIREQ         (3 + IH2_BASE)
-#define INT_730_I2C            (4 + IH2_BASE)
-#define INT_730_PCC            (5 + IH2_BASE)
-#define INT_730_MPU_EXT_NIRQ   (6 + IH2_BASE)
-#define INT_730_SPI_100K_1     (7 + IH2_BASE)
-#define INT_730_SYREN_SPI      (8 + IH2_BASE)
-#define INT_730_VLYNQ          (9 + IH2_BASE)
-#define INT_730_GPIO_BANK4     (10 + IH2_BASE)
-#define INT_730_McBSP1TX       (11 + IH2_BASE)
-#define INT_730_McBSP1RX       (12 + IH2_BASE)
-#define INT_730_McBSP1RX_OF    (13 + IH2_BASE)
-#define INT_730_UART_MODEM_IRDA_2 (14 + IH2_BASE)
-#define INT_730_UART_MODEM_1   (15 + IH2_BASE)
-#define INT_730_MCSI           (16 + IH2_BASE)
-#define INT_730_uWireTX                (17 + IH2_BASE)
-#define INT_730_uWireRX                (18 + IH2_BASE)
-#define INT_730_SMC_CD         (19 + IH2_BASE)
-#define INT_730_SMC_IREQ       (20 + IH2_BASE)
-#define INT_730_HDQ_1WIRE      (21 + IH2_BASE)
-#define INT_730_TIMER32K       (22 + IH2_BASE)
-#define INT_730_MMC_SDIO       (23 + IH2_BASE)
-#define INT_730_UPLD           (24 + IH2_BASE)
-#define INT_730_USB_HHC_1      (27 + IH2_BASE)
-#define INT_730_USB_HHC_2      (28 + IH2_BASE)
-#define INT_730_USB_GENI       (29 + IH2_BASE)
-#define INT_730_USB_OTG                (30 + IH2_BASE)
-#define INT_730_CAMERA_IF      (31 + IH2_BASE)
-#define INT_730_RNG            (32 + IH2_BASE)
-#define INT_730_DUAL_MODE_TIMER (33 + IH2_BASE)
-#define INT_730_DBB_RF_EN      (34 + IH2_BASE)
-#define INT_730_MPUIO_KEYPAD   (35 + IH2_BASE)
-#define INT_730_SHA1_MD5       (36 + IH2_BASE)
-#define INT_730_SPI_100K_2     (37 + IH2_BASE)
-#define INT_730_RNG_IDLE       (38 + IH2_BASE)
-#define INT_730_MPUIO          (39 + IH2_BASE)
-#define INT_730_LLPC_LCD_CTRL_CAN_BE_OFF       (40 + IH2_BASE)
-#define INT_730_LLPC_OE_FALLING (41 + IH2_BASE)
-#define INT_730_LLPC_OE_RISING (42 + IH2_BASE)
-#define INT_730_LLPC_VSYNC     (43 + IH2_BASE)
-#define INT_730_WAKE_UP_REQ    (46 + IH2_BASE)
-#define INT_730_DMA_CH6                (53 + IH2_BASE)
-#define INT_730_DMA_CH7                (54 + IH2_BASE)
-#define INT_730_DMA_CH8                (55 + IH2_BASE)
-#define INT_730_DMA_CH9                (56 + IH2_BASE)
-#define INT_730_DMA_CH10       (57 + IH2_BASE)
-#define INT_730_DMA_CH11       (58 + IH2_BASE)
-#define INT_730_DMA_CH12       (59 + IH2_BASE)
-#define INT_730_DMA_CH13       (60 + IH2_BASE)
-#define INT_730_DMA_CH14       (61 + IH2_BASE)
-#define INT_730_DMA_CH15       (62 + IH2_BASE)
-#define INT_730_NAND           (63 + IH2_BASE)
-
-/*
- * OMAP-850 specific IRQ numbers for interrupt handler 2
- */
-#define INT_850_HW_ERRORS      (0 + IH2_BASE)
-#define INT_850_NFIQ_PWR_FAIL  (1 + IH2_BASE)
-#define INT_850_CFCD           (2 + IH2_BASE)
-#define INT_850_CFIREQ         (3 + IH2_BASE)
-#define INT_850_I2C            (4 + IH2_BASE)
-#define INT_850_PCC            (5 + IH2_BASE)
-#define INT_850_MPU_EXT_NIRQ   (6 + IH2_BASE)
-#define INT_850_SPI_100K_1     (7 + IH2_BASE)
-#define INT_850_SYREN_SPI      (8 + IH2_BASE)
-#define INT_850_VLYNQ          (9 + IH2_BASE)
-#define INT_850_GPIO_BANK4     (10 + IH2_BASE)
-#define INT_850_McBSP1TX       (11 + IH2_BASE)
-#define INT_850_McBSP1RX       (12 + IH2_BASE)
-#define INT_850_McBSP1RX_OF    (13 + IH2_BASE)
-#define INT_850_UART_MODEM_IRDA_2 (14 + IH2_BASE)
-#define INT_850_UART_MODEM_1   (15 + IH2_BASE)
-#define INT_850_MCSI           (16 + IH2_BASE)
-#define INT_850_uWireTX                (17 + IH2_BASE)
-#define INT_850_uWireRX                (18 + IH2_BASE)
-#define INT_850_SMC_CD         (19 + IH2_BASE)
-#define INT_850_SMC_IREQ       (20 + IH2_BASE)
-#define INT_850_HDQ_1WIRE      (21 + IH2_BASE)
-#define INT_850_TIMER32K       (22 + IH2_BASE)
-#define INT_850_MMC_SDIO       (23 + IH2_BASE)
-#define INT_850_UPLD           (24 + IH2_BASE)
-#define INT_850_USB_HHC_1      (27 + IH2_BASE)
-#define INT_850_USB_HHC_2      (28 + IH2_BASE)
-#define INT_850_USB_GENI       (29 + IH2_BASE)
-#define INT_850_USB_OTG                (30 + IH2_BASE)
-#define INT_850_CAMERA_IF      (31 + IH2_BASE)
-#define INT_850_RNG            (32 + IH2_BASE)
-#define INT_850_DUAL_MODE_TIMER (33 + IH2_BASE)
-#define INT_850_DBB_RF_EN      (34 + IH2_BASE)
-#define INT_850_MPUIO_KEYPAD   (35 + IH2_BASE)
-#define INT_850_SHA1_MD5       (36 + IH2_BASE)
-#define INT_850_SPI_100K_2     (37 + IH2_BASE)
-#define INT_850_RNG_IDLE       (38 + IH2_BASE)
-#define INT_850_MPUIO          (39 + IH2_BASE)
-#define INT_850_LLPC_LCD_CTRL_CAN_BE_OFF       (40 + IH2_BASE)
-#define INT_850_LLPC_OE_FALLING (41 + IH2_BASE)
-#define INT_850_LLPC_OE_RISING (42 + IH2_BASE)
-#define INT_850_LLPC_VSYNC     (43 + IH2_BASE)
-#define INT_850_WAKE_UP_REQ    (46 + IH2_BASE)
-#define INT_850_DMA_CH6                (53 + IH2_BASE)
-#define INT_850_DMA_CH7                (54 + IH2_BASE)
-#define INT_850_DMA_CH8                (55 + IH2_BASE)
-#define INT_850_DMA_CH9                (56 + IH2_BASE)
-#define INT_850_DMA_CH10       (57 + IH2_BASE)
-#define INT_850_DMA_CH11       (58 + IH2_BASE)
-#define INT_850_DMA_CH12       (59 + IH2_BASE)
-#define INT_850_DMA_CH13       (60 + IH2_BASE)
-#define INT_850_DMA_CH14       (61 + IH2_BASE)
-#define INT_850_DMA_CH15       (62 + IH2_BASE)
-#define INT_850_NAND           (63 + IH2_BASE)
+#define INT_7XX_HW_ERRORS      (0 + IH2_BASE)
+#define INT_7XX_NFIQ_PWR_FAIL  (1 + IH2_BASE)
+#define INT_7XX_CFCD           (2 + IH2_BASE)
+#define INT_7XX_CFIREQ         (3 + IH2_BASE)
+#define INT_7XX_I2C            (4 + IH2_BASE)
+#define INT_7XX_PCC            (5 + IH2_BASE)
+#define INT_7XX_MPU_EXT_NIRQ   (6 + IH2_BASE)
+#define INT_7XX_SPI_100K_1     (7 + IH2_BASE)
+#define INT_7XX_SYREN_SPI      (8 + IH2_BASE)
+#define INT_7XX_VLYNQ          (9 + IH2_BASE)
+#define INT_7XX_GPIO_BANK4     (10 + IH2_BASE)
+#define INT_7XX_McBSP1TX       (11 + IH2_BASE)
+#define INT_7XX_McBSP1RX       (12 + IH2_BASE)
+#define INT_7XX_McBSP1RX_OF    (13 + IH2_BASE)
+#define INT_7XX_UART_MODEM_IRDA_2 (14 + IH2_BASE)
+#define INT_7XX_UART_MODEM_1   (15 + IH2_BASE)
+#define INT_7XX_MCSI           (16 + IH2_BASE)
+#define INT_7XX_uWireTX                (17 + IH2_BASE)
+#define INT_7XX_uWireRX                (18 + IH2_BASE)
+#define INT_7XX_SMC_CD         (19 + IH2_BASE)
+#define INT_7XX_SMC_IREQ       (20 + IH2_BASE)
+#define INT_7XX_HDQ_1WIRE      (21 + IH2_BASE)
+#define INT_7XX_TIMER32K       (22 + IH2_BASE)
+#define INT_7XX_MMC_SDIO       (23 + IH2_BASE)
+#define INT_7XX_UPLD           (24 + IH2_BASE)
+#define INT_7XX_USB_HHC_1      (27 + IH2_BASE)
+#define INT_7XX_USB_HHC_2      (28 + IH2_BASE)
+#define INT_7XX_USB_GENI       (29 + IH2_BASE)
+#define INT_7XX_USB_OTG                (30 + IH2_BASE)
+#define INT_7XX_CAMERA_IF      (31 + IH2_BASE)
+#define INT_7XX_RNG            (32 + IH2_BASE)
+#define INT_7XX_DUAL_MODE_TIMER (33 + IH2_BASE)
+#define INT_7XX_DBB_RF_EN      (34 + IH2_BASE)
+#define INT_7XX_MPUIO_KEYPAD   (35 + IH2_BASE)
+#define INT_7XX_SHA1_MD5       (36 + IH2_BASE)
+#define INT_7XX_SPI_100K_2     (37 + IH2_BASE)
+#define INT_7XX_RNG_IDLE       (38 + IH2_BASE)
+#define INT_7XX_MPUIO          (39 + IH2_BASE)
+#define INT_7XX_LLPC_LCD_CTRL_CAN_BE_OFF       (40 + IH2_BASE)
+#define INT_7XX_LLPC_OE_FALLING (41 + IH2_BASE)
+#define INT_7XX_LLPC_OE_RISING (42 + IH2_BASE)
+#define INT_7XX_LLPC_VSYNC     (43 + IH2_BASE)
+#define INT_7XX_WAKE_UP_REQ    (46 + IH2_BASE)
+#define INT_7XX_DMA_CH6                (53 + IH2_BASE)
+#define INT_7XX_DMA_CH7                (54 + IH2_BASE)
+#define INT_7XX_DMA_CH8                (55 + IH2_BASE)
+#define INT_7XX_DMA_CH9                (56 + IH2_BASE)
+#define INT_7XX_DMA_CH10       (57 + IH2_BASE)
+#define INT_7XX_DMA_CH11       (58 + IH2_BASE)
+#define INT_7XX_DMA_CH12       (59 + IH2_BASE)
+#define INT_7XX_DMA_CH13       (60 + IH2_BASE)
+#define INT_7XX_DMA_CH14       (61 + IH2_BASE)
+#define INT_7XX_DMA_CH15       (62 + IH2_BASE)
+#define INT_7XX_NAND           (63 + IH2_BASE)
 
 #define INT_24XX_SYS_NIRQ      7
 #define INT_24XX_SDMA_IRQ0     12
 
 #define OMAP_IRQ_BIT(irq)      (1 << ((irq) % 32))
 
+#define INTCPS_NR_MIR_REGS     3
+#define INTCPS_NR_IRQS         96
+
 #ifndef __ASSEMBLY__
 extern void omap_init_irq(void);
 extern int omap_irq_pending(void);
+void omap_intc_save_context(void);
+void omap_intc_restore_context(void);
 #endif
 
 #include <mach/hardware.h>
similarity index 79%
rename from arch/arm/plat-omap/include/mach/mailbox.h
rename to arch/arm/plat-omap/include/plat/mailbox.h
index b7a6991..729166b 100644 (file)
@@ -6,9 +6,9 @@
 #include <linux/wait.h>
 #include <linux/workqueue.h>
 #include <linux/blkdev.h>
+#include <linux/interrupt.h>
 
 typedef u32 mbox_msg_t;
-typedef void (mbox_receiver_t)(mbox_msg_t msg);
 struct omap_mbox;
 
 typedef int __bitwise omap_mbox_irq_t;
@@ -29,8 +29,10 @@ struct omap_mbox_ops {
        int             (*fifo_empty)(struct omap_mbox *mbox);
        int             (*fifo_full)(struct omap_mbox *mbox);
        /* irq */
-       void            (*enable_irq)(struct omap_mbox *mbox, omap_mbox_irq_t irq);
-       void            (*disable_irq)(struct omap_mbox *mbox, omap_mbox_irq_t irq);
+       void            (*enable_irq)(struct omap_mbox *mbox,
+                                               omap_mbox_irq_t irq);
+       void            (*disable_irq)(struct omap_mbox *mbox,
+                                               omap_mbox_irq_t irq);
        void            (*ack_irq)(struct omap_mbox *mbox, omap_mbox_irq_t irq);
        int             (*is_irq)(struct omap_mbox *mbox, omap_mbox_irq_t irq);
        /* ctx */
@@ -42,6 +44,7 @@ struct omap_mbox_queue {
        spinlock_t              lock;
        struct request_queue    *queue;
        struct work_struct      work;
+       struct tasklet_struct   tasklet;
        int     (*callback)(void *);
        struct omap_mbox        *mbox;
 };
@@ -64,7 +67,7 @@ struct omap_mbox {
        void                    (*err_notify)(void);
 };
 
-int omap_mbox_msg_send(struct omap_mbox *, mbox_msg_t msg, void *);
+int omap_mbox_msg_send(struct omap_mbox *, mbox_msg_t msg);
 void omap_mbox_init_seq(struct omap_mbox *);
 
 struct omap_mbox *omap_mbox_get(const char *);
@@ -93,4 +96,16 @@ static inline void omap_mbox_restore_ctx(struct omap_mbox *mbox)
        mbox->ops->restore_ctx(mbox);
 }
 
+static inline void omap_mbox_enable_irq(struct omap_mbox *mbox,
+                                       omap_mbox_irq_t irq)
+{
+       mbox->ops->enable_irq(mbox, irq);
+}
+
+static inline void omap_mbox_disable_irq(struct omap_mbox *mbox,
+                                        omap_mbox_irq_t irq)
+{
+       mbox->ops->disable_irq(mbox, irq);
+}
+
 #endif /* MAILBOX_H */
similarity index 98%
rename from arch/arm/plat-omap/include/mach/mcbsp.h
rename to arch/arm/plat-omap/include/plat/mcbsp.h
index e0d6eca..4f22e5b 100644 (file)
 #include <linux/spinlock.h>
 
 #include <mach/hardware.h>
-#include <mach/clock.h>
+#include <plat/clock.h>
 
-#define OMAP730_MCBSP1_BASE    0xfffb1000
-#define OMAP730_MCBSP2_BASE    0xfffb1800
+#define OMAP7XX_MCBSP1_BASE    0xfffb1000
+#define OMAP7XX_MCBSP2_BASE    0xfffb1800
 
 #define OMAP1510_MCBSP1_BASE   0xe1011800
 #define OMAP1510_MCBSP2_BASE   0xfffb1000
@@ -58,7 +58,7 @@
 #define OMAP44XX_MCBSP3_BASE   0x49026000
 #define OMAP44XX_MCBSP4_BASE   0x48074000
 
-#if defined(CONFIG_ARCH_OMAP15XX) || defined(CONFIG_ARCH_OMAP16XX) || defined(CONFIG_ARCH_OMAP730)
+#if defined(CONFIG_ARCH_OMAP15XX) || defined(CONFIG_ARCH_OMAP16XX) || defined(CONFIG_ARCH_OMAP730) || defined(CONFIG_ARCH_OMAP850)
 
 #define OMAP_MCBSP_REG_DRR2    0x00
 #define OMAP_MCBSP_REG_DRR1    0x02
similarity index 94%
rename from arch/arm/plat-omap/include/mach/memory.h
rename to arch/arm/plat-omap/include/plat/memory.h
index 9ad41dc..3325f7b 100644 (file)
                __dma = __dma - PHYS_OFFSET + OMAP1510_LB_OFFSET; \
           __dma; })
 
+#define __arch_dma_to_page(dev, addr)  \
+       ({ dma_addr_t __dma = addr;                             \
+          if (is_lbus_device(dev))                             \
+               __dma += PHYS_OFFSET - OMAP1510_LB_OFFSET;      \
+          phys_to_page(__dma);                                 \
+       })
+
 #define __arch_dma_to_virt(dev, addr)  ({ (void *) (is_lbus_device(dev) ? \
                                                lbus_to_virt(addr) : \
                                                __phys_to_virt(addr)); })
similarity index 99%
rename from arch/arm/plat-omap/include/mach/mmc.h
rename to arch/arm/plat-omap/include/plat/mmc.h
index 7229b95..2993713 100644 (file)
@@ -15,7 +15,7 @@
 #include <linux/device.h>
 #include <linux/mmc/host.h>
 
-#include <mach/board.h>
+#include <plat/board.h>
 
 #define OMAP15XX_NR_MMC                1
 #define OMAP16XX_NR_MMC                2
similarity index 90%
rename from arch/arm/plat-omap/include/mach/mux.h
rename to arch/arm/plat-omap/include/plat/mux.h
index 0f49d2d..ba77de6 100644 (file)
                                        .pu_pd_reg = PU_PD_SEL_##reg, \
                                        .pu_pd_val = status,
 
-#define MUX_REG_730(reg, mode_offset, mode) .mux_reg_name = "OMAP730_IO_CONF_"#reg, \
-                                       .mux_reg = OMAP730_IO_CONF_##reg, \
+#define MUX_REG_7XX(reg, mode_offset, mode) .mux_reg_name = "OMAP7XX_IO_CONF_"#reg, \
+                                       .mux_reg = OMAP7XX_IO_CONF_##reg, \
                                        .mask_offset = mode_offset, \
                                        .mask = mode,
 
-#define PULL_REG_730(reg, bit, status) .pull_name = "OMAP730_IO_CONF_"#reg, \
-                                       .pull_reg = OMAP730_IO_CONF_##reg, \
-                                       .pull_bit = bit, \
-                                       .pull_val = status,
-
-#define MUX_REG_850(reg, mode_offset, mode) .mux_reg_name = "OMAP850_IO_CONF_"#reg, \
-                                       .mux_reg = OMAP850_IO_CONF_##reg, \
-                                       .mask_offset = mode_offset, \
-                                       .mask = mode,
-
-#define PULL_REG_850(reg, bit, status) .pull_name = "OMAP850_IO_CONF_"#reg, \
-                                       .pull_reg = OMAP850_IO_CONF_##reg, \
+#define PULL_REG_7XX(reg, bit, status) .pull_name = "OMAP7XX_IO_CONF_"#reg, \
+                                       .pull_reg = OMAP7XX_IO_CONF_##reg, \
                                        .pull_bit = bit, \
                                        .pull_val = status,
 
 #define PU_PD_REG(reg, status)         .pu_pd_reg = PU_PD_SEL_##reg, \
                                        .pu_pd_val = status,
 
-#define MUX_REG_730(reg, mode_offset, mode) \
-                                       .mux_reg = OMAP730_IO_CONF_##reg, \
+#define MUX_REG_7XX(reg, mode_offset, mode) \
+                                       .mux_reg = OMAP7XX_IO_CONF_##reg, \
                                        .mask_offset = mode_offset, \
                                        .mask = mode,
 
-#define PULL_REG_730(reg, bit, status) .pull_reg = OMAP730_IO_CONF_##reg, \
-                                       .pull_bit = bit, \
-                                       .pull_val = status,
-
-#define MUX_REG_850(reg, mode_offset, mode) \
-                                       .mux_reg = OMAP850_IO_CONF_##reg, \
-                                       .mask_offset = mode_offset, \
-                                       .mask = mode,
-
-#define PULL_REG_850(reg, bit, status) .pull_reg = OMAP850_IO_CONF_##reg, \
+#define PULL_REG_7XX(reg, bit, status) .pull_reg = OMAP7XX_IO_CONF_##reg, \
                                        .pull_bit = bit, \
                                        .pull_val = status,
 
 
 /*
  * OMAP730/850 has a slightly different config for the pin mux.
- * - config regs are the OMAP730_IO_CONF_x regs (see omap730.h) regs and
+ * - config regs are the OMAP7XX_IO_CONF_x regs (see omap730.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
  */
-#define MUX_CFG_730(desc, mux_reg, mode_offset, mode,  \
-                  pull_bit, pull_status, debug_status)\
-{                                                      \
-       .name =  desc,                                  \
-       .debug = debug_status,                          \
-       MUX_REG_730(mux_reg, mode_offset, mode)         \
-       PULL_REG_730(mux_reg, pull_bit, pull_status)    \
-       PU_PD_REG(NA, 0)                \
-},
-
-#define MUX_CFG_850(desc, mux_reg, mode_offset, mode,  \
+#define MUX_CFG_7XX(desc, mux_reg, mode_offset, mode,  \
                   pull_bit, pull_status, debug_status)\
 {                                                      \
        .name =  desc,                                  \
        .debug = debug_status,                          \
-       MUX_REG_850(mux_reg, mode_offset, mode)         \
-       PULL_REG_850(mux_reg, pull_bit, pull_status)    \
+       MUX_REG_7XX(mux_reg, mode_offset, mode)         \
+       PULL_REG_7XX(mux_reg, pull_bit, pull_status)    \
        PU_PD_REG(NA, 0)                \
 },
 
-
 #define MUX_CFG_24XX(desc, reg_offset, mode,                   \
                                pull_en, pull_mode, dbg)        \
 {                                                              \
@@ -232,45 +202,30 @@ struct pin_config {
 
 };
 
-enum omap730_index {
+enum omap7xx_index {
        /* OMAP 730 keyboard */
-       E2_730_KBR0,
-       J7_730_KBR1,
-       E1_730_KBR2,
-       F3_730_KBR3,
-       D2_730_KBR4,
-       C2_730_KBC0,
-       D3_730_KBC1,
-       E4_730_KBC2,
-       F4_730_KBC3,
-       E3_730_KBC4,
+       E2_7XX_KBR0,
+       J7_7XX_KBR1,
+       E1_7XX_KBR2,
+       F3_7XX_KBR3,
+       D2_7XX_KBR4,
+       C2_7XX_KBC0,
+       D3_7XX_KBC1,
+       E4_7XX_KBC2,
+       F4_7XX_KBC3,
+       E3_7XX_KBC4,
 
        /* USB */
-       AA17_730_USB_DM,
-       W16_730_USB_PU_EN,
-       W17_730_USB_VBUSI,
+       AA17_7XX_USB_DM,
+       W16_7XX_USB_PU_EN,
+       W17_7XX_USB_VBUSI,
+
+       /* MMC */
+       MMC_7XX_CMD,
+       MMC_7XX_CLK,
+       MMC_7XX_DAT0,
 };
 
-enum omap850_index {
-       /* OMAP 850 keyboard */
-       E2_850_KBR0,
-       J7_850_KBR1,
-       E1_850_KBR2,
-       F3_850_KBR3,
-       D2_850_KBR4,
-       C2_850_KBC0,
-       D3_850_KBC1,
-       E4_850_KBC2,
-       F4_850_KBC3,
-       E3_850_KBC4,
-
-       /* USB */
-       AA17_850_USB_DM,
-       W16_850_USB_PU_EN,
-       W17_850_USB_VBUSI,
-};
-
-
 enum omap1xxx_index {
        /* UART1 (BT_UART_GATING)*/
        UART1_TX = 0,
@@ -879,6 +834,10 @@ enum omap34xx_index {
        AH4_3430_MMC2_DAT1,
        AG4_3430_MMC2_DAT2,
        AF4_3430_MMC2_DAT3,
+       AE4_3430_MMC2_DAT4,
+       AH3_3430_MMC2_DAT5,
+       AF3_3430_MMC2_DAT6,
+       AE3_3430_MMC2_DAT7,
 
        /* MMC3 */
        AF10_3430_MMC3_CLK,
@@ -890,6 +849,11 @@ enum omap34xx_index {
 
        /* SYS_NIRQ T2 INT1 */
        AF26_34XX_SYS_NIRQ,
+
+       /* EHCI GPIO's for OMAP3EVM (Rev >= E) */
+       AH14_34XX_GPIO21,
+       AF9_34XX_GPIO22,
+       U3_34XX_GPIO61,
 };
 
 struct omap_mux_cfg {
similarity index 98%
rename from arch/arm/plat-omap/include/mach/omap-alsa.h
rename to arch/arm/plat-omap/include/plat/omap-alsa.h
index bdf30a0..b53055b 100644 (file)
 #ifndef __OMAP_ALSA_H
 #define __OMAP_ALSA_H
 
-#include <mach/dma.h>
+#include <plat/dma.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
-#include <mach/mcbsp.h>
+#include <plat/mcbsp.h>
 #include <linux/platform_device.h>
 
 #define DMA_BUF_SIZE   (1024 * 8)
similarity index 91%
rename from arch/arm/plat-omap/include/mach/omap34xx.h
rename to arch/arm/plat-omap/include/plat/omap34xx.h
index f8d186a..077f059 100644 (file)
 #define OMAP3430_ISP_CSI2A_END         (OMAP3430_ISP_CSI2A_BASE   + 0x16F)
 #define OMAP3430_ISP_CSI2PHY_END       (OMAP3430_ISP_CSI2PHY_BASE + 0x007)
 
-#define OMAP34XX_IVA_INTC_BASE 0x40000000
 #define OMAP34XX_HSUSB_OTG_BASE        (L4_34XX_BASE + 0xAB000)
-#define OMAP34XX_HSUSB_HOST_BASE       (L4_34XX_BASE + 0x64000)
 #define OMAP34XX_USBTLL_BASE   (L4_34XX_BASE + 0x62000)
+#define OMAP34XX_UHH_CONFIG_BASE       (L4_34XX_BASE + 0x64000)
+#define OMAP34XX_OHCI_BASE     (L4_34XX_BASE + 0x64400)
+#define OMAP34XX_EHCI_BASE     (L4_34XX_BASE + 0x64800)
+#define OMAP34XX_SR1_BASE      0x480C9000
+#define OMAP34XX_SR2_BASE      0x480CB000
 
 #define OMAP34XX_MAILBOX_BASE          (L4_34XX_BASE + 0x94000)
 
-#define OMAP34XX_DSP_BASE      0x58000000
-#define OMAP34XX_DSP_MEM_BASE  (OMAP34XX_DSP_BASE + 0x0)
-#define OMAP34XX_DSP_IPI_BASE  (OMAP34XX_DSP_BASE + 0x1000000)
-#define OMAP34XX_DSP_MMU_BASE  (OMAP34XX_DSP_BASE + 0x2000000)
 #endif /* __ASM_ARCH_OMAP34XX_H */
 
similarity index 79%
rename from arch/arm/plat-omap/include/mach/omap44xx.h
rename to arch/arm/plat-omap/include/plat/omap44xx.h
index b3ba5ac..e52902a 100644 (file)
@@ -22,6 +22,9 @@
 #define L4_PER_44XX_BASE               0x48000000
 #define L4_EMU_44XX_BASE               0x54000000
 #define L3_44XX_BASE                   0x44000000
+#define OMAP44XX_EMIF1_BASE            0x4c000000
+#define OMAP44XX_EMIF2_BASE            0x4d000000
+#define OMAP44XX_DMM_BASE              0x4e000000
 #define OMAP4430_32KSYNCT_BASE         0x4a304000
 #define OMAP4430_CM_BASE               0x4a004000
 #define OMAP4430_PRM_BASE              0x48306000
 #define IRQ_SIR_IRQ                    0x0040
 #define OMAP44XX_GIC_DIST_BASE         0x48241000
 #define OMAP44XX_GIC_CPU_BASE          0x48240100
-#define OMAP44XX_VA_GIC_CPU_BASE       OMAP2_IO_ADDRESS(OMAP44XX_GIC_CPU_BASE)
 #define OMAP44XX_SCU_BASE              0x48240000
-#define OMAP44XX_VA_SCU_BASE           OMAP2_IO_ADDRESS(OMAP44XX_SCU_BASE)
 #define OMAP44XX_LOCAL_TWD_BASE                0x48240600
-#define OMAP44XX_VA_LOCAL_TWD_BASE     OMAP2_IO_ADDRESS(OMAP44XX_LOCAL_TWD_BASE)
-#define OMAP44XX_LOCAL_TWD_SIZE                0x00000100
 #define OMAP44XX_WKUPGEN_BASE          0x48281000
-#define OMAP44XX_VA_WKUPGEN_BASE       OMAP2_IO_ADDRESS(OMAP44XX_WKUPGEN_BASE)
+
+#define OMAP44XX_MAILBOX_BASE          (L4_44XX_BASE + 0xF4000)
 
 #endif /* __ASM_ARCH_OMAP44XX_H */
 
diff --git a/arch/arm/plat-omap/include/plat/omap7xx.h b/arch/arm/plat-omap/include/plat/omap7xx.h
new file mode 100644 (file)
index 0000000..53f5241
--- /dev/null
@@ -0,0 +1,104 @@
+/* arch/arm/plat-omap/include/mach/omap7xx.h
+ *
+ * Hardware definitions for TI OMAP7XX processor.
+ *
+ * Cleanup for Linux-2.6 by Dirk Behme <dirk.behme@de.bosch.com>
+ * Adapted for omap850 by Zebediah C. McClure <zmc@lurian.net>
+ * Adapted for omap7xx by Alistair Buxton <a.j.buxton@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * 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_OMAP7XX_H
+#define __ASM_ARCH_OMAP7XX_H
+
+/*
+ * ----------------------------------------------------------------------------
+ * Base addresses
+ * ----------------------------------------------------------------------------
+ */
+
+/* Syntax: XX_BASE = Virtual base address, XX_START = Physical base address */
+
+#define OMAP7XX_DSP_BASE       0xE0000000
+#define OMAP7XX_DSP_SIZE       0x50000
+#define OMAP7XX_DSP_START      0xE0000000
+
+#define OMAP7XX_DSPREG_BASE    0xE1000000
+#define OMAP7XX_DSPREG_SIZE    SZ_128K
+#define OMAP7XX_DSPREG_START   0xE1000000
+
+/*
+ * ----------------------------------------------------------------------------
+ * OMAP7XX specific configuration registers
+ * ----------------------------------------------------------------------------
+ */
+#define OMAP7XX_CONFIG_BASE    0xfffe1000
+#define OMAP7XX_IO_CONF_0      0xfffe1070
+#define OMAP7XX_IO_CONF_1      0xfffe1074
+#define OMAP7XX_IO_CONF_2      0xfffe1078
+#define OMAP7XX_IO_CONF_3      0xfffe107c
+#define OMAP7XX_IO_CONF_4      0xfffe1080
+#define OMAP7XX_IO_CONF_5      0xfffe1084
+#define OMAP7XX_IO_CONF_6      0xfffe1088
+#define OMAP7XX_IO_CONF_7      0xfffe108c
+#define OMAP7XX_IO_CONF_8      0xfffe1090
+#define OMAP7XX_IO_CONF_9      0xfffe1094
+#define OMAP7XX_IO_CONF_10     0xfffe1098
+#define OMAP7XX_IO_CONF_11     0xfffe109c
+#define OMAP7XX_IO_CONF_12     0xfffe10a0
+#define OMAP7XX_IO_CONF_13     0xfffe10a4
+
+#define OMAP7XX_MODE_1         0xfffe1010
+#define OMAP7XX_MODE_2         0xfffe1014
+
+/* CSMI specials: in terms of base + offset */
+#define OMAP7XX_MODE2_OFFSET   0x14
+
+/*
+ * ----------------------------------------------------------------------------
+ * OMAP7XX traffic controller configuration registers
+ * ----------------------------------------------------------------------------
+ */
+#define OMAP7XX_FLASH_CFG_0    0xfffecc10
+#define OMAP7XX_FLASH_ACFG_0   0xfffecc50
+#define OMAP7XX_FLASH_CFG_1    0xfffecc14
+#define OMAP7XX_FLASH_ACFG_1   0xfffecc54
+
+/*
+ * ----------------------------------------------------------------------------
+ * OMAP7XX DSP control registers
+ * ----------------------------------------------------------------------------
+ */
+#define OMAP7XX_ICR_BASE       0xfffbb800
+#define OMAP7XX_DSP_M_CTL      0xfffbb804
+#define OMAP7XX_DSP_MMU_BASE   0xfffed200
+
+/*
+ * ----------------------------------------------------------------------------
+ * OMAP7XX PCC_UPLD configuration registers
+ * ----------------------------------------------------------------------------
+ */
+#define OMAP7XX_PCC_UPLD_CTRL_BASE     (0xfffe0900)
+#define OMAP7XX_PCC_UPLD_CTRL          (OMAP7XX_PCC_UPLD_CTRL_BASE + 0x00)
+
+#endif /*  __ASM_ARCH_OMAP7XX_H */
+
@@ -34,7 +34,7 @@
 #include <linux/kernel.h>
 #include <linux/platform_device.h>
 
-#include <mach/omap_hwmod.h>
+#include <plat/omap_hwmod.h>
 
 /* omap_device._state values */
 #define OMAP_DEVICE_STATE_UNKNOWN      0
similarity index 99%
rename from arch/arm/plat-omap/include/mach/omap_hwmod.h
rename to arch/arm/plat-omap/include/plat/omap_hwmod.h
index 1f79c20..dbdd123 100644 (file)
@@ -35,7 +35,7 @@
 #include <linux/kernel.h>
 #include <linux/ioport.h>
 
-#include <mach/cpu.h>
+#include <plat/cpu.h>
 
 struct omap_device;
 
similarity index 99%
rename from arch/arm/plat-omap/include/mach/omapfb.h
rename to arch/arm/plat-omap/include/plat/omapfb.h
index b226bdf..bfef7ab 100644 (file)
@@ -168,7 +168,7 @@ enum omapfb_update_mode {
 #include <linux/fb.h>
 #include <linux/mutex.h>
 
-#include <mach/board.h>
+#include <plat/board.h>
 
 #define OMAP_LCDC_INV_VSYNC             0x0001
 #define OMAP_LCDC_INV_HSYNC             0x0002
@@ -19,7 +19,7 @@
 
 #include <asm/atomic.h>
 
-#include <mach/cpu.h>
+#include <plat/cpu.h>
 
 
 /* Powerdomain basic power states */
similarity index 89%
rename from arch/arm/plat-omap/include/mach/prcm.h
rename to arch/arm/plat-omap/include/plat/prcm.h
index cda2a70..e63e94e 100644 (file)
@@ -27,9 +27,13 @@ u32 omap_prcm_get_reset_sources(void);
 void omap_prcm_arch_reset(char mode);
 int omap2_cm_wait_idlest(void __iomem *reg, u32 mask, const char *name);
 
-#endif
+#define START_PADCONF_SAVE 0x2
+#define PADCONF_SAVE_DONE  0x1
 
+void omap3_prcm_save_context(void);
+void omap3_prcm_restore_context(void);
 
+#endif
 
 
 
similarity index 89%
rename from arch/arm/plat-omap/include/mach/sdrc.h
rename to arch/arm/plat-omap/include/plat/sdrc.h
index 1c09c78..f704030 100644 (file)
 #define SDRC_RFR_CTRL_1                0x0D4
 #define SDRC_MANUAL_1          0x0D8
 
+#define SDRC_POWER_AUTOCOUNT_SHIFT     8
+#define SDRC_POWER_AUTOCOUNT_MASK      (0xffff << SDRC_POWER_AUTOCOUNT_SHIFT)
+#define SDRC_POWER_CLKCTRL_SHIFT       4
+#define SDRC_POWER_CLKCTRL_MASK                (0x3 << SDRC_POWER_CLKCTRL_SHIFT)
+#define SDRC_SELF_REFRESH_ON_AUTOCOUNT (0x2 << SDRC_POWER_CLKCTRL_SHIFT)
+
 /*
  * These values represent the number of memory clock cycles between
  * autorefresh initiation.  They assume 1 refresh per 64 ms (JEDEC), 8192
  */
 
 #define OMAP242X_SMS_REGADDR(reg)                                      \
-                       (void __iomem *)OMAP2_IO_ADDRESS(OMAP2420_SMS_BASE + reg)
+               (void __iomem *)OMAP2_L3_IO_ADDRESS(OMAP2420_SMS_BASE + reg)
 #define OMAP243X_SMS_REGADDR(reg)                                      \
-                       (void __iomem *)OMAP2_IO_ADDRESS(OMAP243X_SMS_BASE + reg)
+               (void __iomem *)OMAP2_L3_IO_ADDRESS(OMAP243X_SMS_BASE + reg)
 #define OMAP343X_SMS_REGADDR(reg)                                      \
-                       (void __iomem *)OMAP2_IO_ADDRESS(OMAP343X_SMS_BASE + reg)
+               (void __iomem *)OMAP2_L3_IO_ADDRESS(OMAP343X_SMS_BASE + reg)
 
 /* SMS register offsets - read/write with sms_{read,write}_reg() */
 
@@ -120,6 +126,8 @@ void __init omap2_sdrc_init(struct omap_sdrc_params *sdrc_cs0,
 int omap2_sdrc_get_params(unsigned long r,
                          struct omap_sdrc_params **sdrc_cs0,
                          struct omap_sdrc_params **sdrc_cs1);
+void omap2_sms_save_context(void);
+void omap2_sms_restore_context(void);
 
 #ifdef CONFIG_ARCH_OMAP2
 
similarity index 94%
rename from arch/arm/plat-omap/include/mach/serial.h
rename to arch/arm/plat-omap/include/plat/serial.h
index e249186..9951345 100644 (file)
 #define OMAP_UART1_BASE                0xfffb0000
 #define OMAP_UART2_BASE                0xfffb0800
 #define OMAP_UART3_BASE                0xfffb9800
-#define OMAP_MAX_NR_PORTS      3
 #elif defined(CONFIG_ARCH_OMAP2)
 /* OMAP2 serial ports */
 #define OMAP_UART1_BASE                0x4806a000
 #define OMAP_UART2_BASE                0x4806c000
 #define OMAP_UART3_BASE                0x4806e000
-#define OMAP_MAX_NR_PORTS      3
 #elif defined(CONFIG_ARCH_OMAP3)
 /* OMAP3 serial ports */
 #define OMAP_UART1_BASE                0x4806a000
 #define OMAP_UART2_BASE                0x4806c000
 #define OMAP_UART3_BASE                0x49020000
-#define OMAP_MAX_NR_PORTS      3
 #elif defined(CONFIG_ARCH_OMAP4)
 /* OMAP4 serial ports */
 #define OMAP_UART1_BASE                0x4806a000
 #define OMAP_UART2_BASE                0x4806c000
 #define OMAP_UART3_BASE                0x48020000
 #define OMAP_UART4_BASE                0x4806e000
-#define OMAP_MAX_NR_PORTS      4
 #endif
 
 #define OMAP1510_BASE_BAUD     (12000000/16)
similarity index 93%
rename from arch/arm/plat-omap/include/mach/sram.h
rename to arch/arm/plat-omap/include/plat/sram.h
index 8974e3f..16a1b45 100644 (file)
@@ -27,6 +27,7 @@ extern u32 omap3_configure_core_dpll(
                        u32 sdrc_actim_ctrl_b_0, u32 sdrc_mr_0,
                        u32 sdrc_rfr_ctrl_1, u32 sdrc_actim_ctrl_a_1,
                        u32 sdrc_actim_ctrl_b_1, u32 sdrc_mr_1);
+extern void omap3_sram_restore_context(void);
 
 /* Do not use these */
 extern void omap1_sram_reprogram_clock(u32 ckctl, u32 dpllctl);
@@ -68,4 +69,10 @@ extern u32 omap3_sram_configure_core_dpll(
                        u32 sdrc_actim_ctrl_b_1, u32 sdrc_mr_1);
 extern unsigned long omap3_sram_configure_core_dpll_sz;
 
+#ifdef CONFIG_PM
+extern void omap_push_sram_idle(void);
+#else
+static inline void omap_push_sram_idle(void) {}
+#endif /* CONFIG_PM */
+
 #endif
similarity index 97%
rename from arch/arm/plat-omap/include/mach/system.h
rename to arch/arm/plat-omap/include/plat/system.h
index ed8ec74..c58a4ef 100644 (file)
@@ -9,7 +9,7 @@
 #include <asm/mach-types.h>
 #include <mach/hardware.h>
 
-#include <mach/prcm.h>
+#include <plat/prcm.h>
 
 #ifndef CONFIG_MACH_VOICEBLUE
 #define voiceblue_reset()              do {} while (0)
similarity index 90%
rename from arch/arm/plat-omap/include/mach/uncompress.h
rename to arch/arm/plat-omap/include/plat/uncompress.h
index 0814c5f..13c305d 100644 (file)
 
 #include <linux/types.h>
 #include <linux/serial_reg.h>
-#include <mach/serial.h>
+#include <plat/serial.h>
 
 unsigned int system_rev;
 
 #define UART_OMAP_MDR1         0x08    /* mode definition register */
 #define OMAP_ID_730            0x355F
+#define OMAP_ID_850            0x362C
 #define ID_MASK                        0x7fff
 #define check_port(base, shift) ((base[UART_OMAP_MDR1 << shift] & 7) == 0)
 #define omap_get_id() ((*(volatile unsigned int *)(0xfffed404)) >> 12) & ID_MASK
@@ -43,8 +44,12 @@ static void putc(int c)
        uart = (volatile u8 *)(OMAP_UART3_BASE);
 #elif defined(CONFIG_OMAP_LL_DEBUG_UART2)
        uart = (volatile u8 *)(OMAP_UART2_BASE);
-#else
+#elif defined(CONFIG_OMAP_LL_DEBUG_UART1)
        uart = (volatile u8 *)(OMAP_UART1_BASE);
+#elif defined(CONFIG_OMAP_LL_DEBUG_NONE)
+       return;
+#else
+       return;
 #endif
 
 #ifdef CONFIG_ARCH_OMAP1
@@ -53,7 +58,7 @@ static void putc(int c)
                /* MMU is not on, so cpu_is_omapXXXX() won't work here */
                unsigned int omap_id = omap_get_id();
 
-               if (omap_id == OMAP_ID_730)
+               if (omap_id == OMAP_ID_730 || omap_id == OMAP_ID_850)
                        shift = 0;
 
                if (check_port(uart, shift))
similarity index 90%
rename from arch/arm/plat-omap/include/mach/usb.h
rename to arch/arm/plat-omap/include/plat/usb.h
index f337e17..33a500e 100644 (file)
@@ -3,7 +3,22 @@
 #ifndef        __ASM_ARCH_OMAP_USB_H
 #define        __ASM_ARCH_OMAP_USB_H
 
-#include <mach/board.h>
+#include <plat/board.h>
+
+#define OMAP3_HS_USB_PORTS     3
+enum ehci_hcd_omap_mode {
+       EHCI_HCD_OMAP_MODE_UNKNOWN,
+       EHCI_HCD_OMAP_MODE_PHY,
+       EHCI_HCD_OMAP_MODE_TLL,
+};
+
+struct ehci_hcd_omap_platform_data {
+       enum ehci_hcd_omap_mode         port_mode[OMAP3_HS_USB_PORTS];
+       unsigned                        phy_reset:1;
+
+       /* have to be valid if phy_reset is true and portx is in phy mode */
+       int     reset_gpio_port[OMAP3_HS_USB_PORTS];
+};
 
 /*-------------------------------------------------------------------------*/
 
@@ -29,6 +44,8 @@
 
 extern void usb_musb_init(void);
 
+extern void usb_ehci_init(struct ehci_hcd_omap_platform_data *pdata);
+
 #endif
 
 void omap_usb_init(struct omap_usb_config *pdata);
index b6defa2..11f5d79 100644 (file)
 #include <linux/io.h>
 #include <linux/mm.h>
 
-#include <mach/omap730.h>
-#include <mach/omap1510.h>
-#include <mach/omap16xx.h>
-#include <mach/omap24xx.h>
-#include <mach/omap34xx.h>
-#include <mach/omap44xx.h>
+#include <plat/omap7xx.h>
+#include <plat/omap1510.h>
+#include <plat/omap16xx.h>
+#include <plat/omap24xx.h>
+#include <plat/omap34xx.h>
+#include <plat/omap44xx.h>
 
 #define BETWEEN(p,st,sz)       ((p) >= (st) && (p) < ((st) + (sz)))
 #define XLATE(p,pst,vst)       ((void __iomem *)((p) - (pst) + (vst)))
@@ -33,13 +33,13 @@ void __iomem *omap_ioremap(unsigned long p, size_t size, unsigned int type)
                if (BETWEEN(p, OMAP1_IO_PHYS, OMAP1_IO_SIZE))
                        return XLATE(p, OMAP1_IO_PHYS, OMAP1_IO_VIRT);
        }
-       if (cpu_is_omap730()) {
-               if (BETWEEN(p, OMAP730_DSP_BASE, OMAP730_DSP_SIZE))
-                       return XLATE(p, OMAP730_DSP_BASE, OMAP730_DSP_START);
+       if (cpu_is_omap7xx()) {
+               if (BETWEEN(p, OMAP7XX_DSP_BASE, OMAP7XX_DSP_SIZE))
+                       return XLATE(p, OMAP7XX_DSP_BASE, OMAP7XX_DSP_START);
 
-               if (BETWEEN(p, OMAP730_DSPREG_BASE, OMAP730_DSPREG_SIZE))
-                       return XLATE(p, OMAP730_DSPREG_BASE,
-                                       OMAP730_DSPREG_START);
+               if (BETWEEN(p, OMAP7XX_DSPREG_BASE, OMAP7XX_DSPREG_SIZE))
+                       return XLATE(p, OMAP7XX_DSPREG_BASE,
+                                       OMAP7XX_DSPREG_START);
        }
        if (cpu_is_omap15xx()) {
                if (BETWEEN(p, OMAP1510_DSP_BASE, OMAP1510_DSP_SIZE))
@@ -114,6 +114,14 @@ void __iomem *omap_ioremap(unsigned long p, size_t size, unsigned int type)
                        return XLATE(p, L4_WK_44XX_PHYS, L4_WK_44XX_VIRT);
                if (BETWEEN(p, OMAP44XX_GPMC_PHYS, OMAP44XX_GPMC_SIZE))
                        return XLATE(p, OMAP44XX_GPMC_PHYS, OMAP44XX_GPMC_VIRT);
+               if (BETWEEN(p, OMAP44XX_EMIF1_PHYS, OMAP44XX_EMIF1_SIZE))
+                       return XLATE(p, OMAP44XX_EMIF1_PHYS,            \
+                                                       OMAP44XX_EMIF1_VIRT);
+               if (BETWEEN(p, OMAP44XX_EMIF2_PHYS, OMAP44XX_EMIF2_SIZE))
+                       return XLATE(p, OMAP44XX_EMIF2_PHYS,            \
+                                                       OMAP44XX_EMIF2_VIRT);
+               if (BETWEEN(p, OMAP44XX_DMM_PHYS, OMAP44XX_DMM_SIZE))
+                       return XLATE(p, OMAP44XX_DMM_PHYS, OMAP44XX_DMM_VIRT);
                if (BETWEEN(p, L4_PER_44XX_PHYS, L4_PER_44XX_SIZE))
                        return XLATE(p, L4_PER_44XX_PHYS, L4_PER_44XX_VIRT);
                if (BETWEEN(p, L4_EMU_44XX_PHYS, L4_EMU_44XX_SIZE))
@@ -142,7 +150,7 @@ u8 omap_readb(u32 pa)
        if (cpu_class_is_omap1())
                return __raw_readb(OMAP1_IO_ADDRESS(pa));
        else
-               return __raw_readb(OMAP2_IO_ADDRESS(pa));
+               return __raw_readb(OMAP2_L4_IO_ADDRESS(pa));
 }
 EXPORT_SYMBOL(omap_readb);
 
@@ -151,7 +159,7 @@ u16 omap_readw(u32 pa)
        if (cpu_class_is_omap1())
                return __raw_readw(OMAP1_IO_ADDRESS(pa));
        else
-               return __raw_readw(OMAP2_IO_ADDRESS(pa));
+               return __raw_readw(OMAP2_L4_IO_ADDRESS(pa));
 }
 EXPORT_SYMBOL(omap_readw);
 
@@ -160,7 +168,7 @@ u32 omap_readl(u32 pa)
        if (cpu_class_is_omap1())
                return __raw_readl(OMAP1_IO_ADDRESS(pa));
        else
-               return __raw_readl(OMAP2_IO_ADDRESS(pa));
+               return __raw_readl(OMAP2_L4_IO_ADDRESS(pa));
 }
 EXPORT_SYMBOL(omap_readl);
 
@@ -169,7 +177,7 @@ void omap_writeb(u8 v, u32 pa)
        if (cpu_class_is_omap1())
                __raw_writeb(v, OMAP1_IO_ADDRESS(pa));
        else
-               __raw_writeb(v, OMAP2_IO_ADDRESS(pa));
+               __raw_writeb(v, OMAP2_L4_IO_ADDRESS(pa));
 }
 EXPORT_SYMBOL(omap_writeb);
 
@@ -178,7 +186,7 @@ void omap_writew(u16 v, u32 pa)
        if (cpu_class_is_omap1())
                __raw_writew(v, OMAP1_IO_ADDRESS(pa));
        else
-               __raw_writew(v, OMAP2_IO_ADDRESS(pa));
+               __raw_writew(v, OMAP2_L4_IO_ADDRESS(pa));
 }
 EXPORT_SYMBOL(omap_writew);
 
@@ -187,6 +195,6 @@ void omap_writel(u32 v, u32 pa)
        if (cpu_class_is_omap1())
                __raw_writel(v, OMAP1_IO_ADDRESS(pa));
        else
-               __raw_writel(v, OMAP2_IO_ADDRESS(pa));
+               __raw_writel(v, OMAP2_L4_IO_ADDRESS(pa));
 }
 EXPORT_SYMBOL(omap_writel);
index c799b3b..afd1c27 100644 (file)
@@ -17,8 +17,8 @@
 #include <linux/platform_device.h>
 #include <linux/debugfs.h>
 
-#include <mach/iommu.h>
-#include <mach/iovmm.h>
+#include <plat/iommu.h>
+#include <plat/iovmm.h>
 
 #include "iopgtable.h"
 
index 94584f1..c0ff1e3 100644 (file)
@@ -20,7 +20,7 @@
 
 #include <asm/cacheflush.h>
 
-#include <mach/iommu.h>
+#include <plat/iommu.h>
 
 #include "iopgtable.h"
 
index dc3fac3..936aef1 100644 (file)
@@ -18,8 +18,8 @@
 #include <asm/cacheflush.h>
 #include <asm/mach/map.h>
 
-#include <mach/iommu.h>
-#include <mach/iovmm.h>
+#include <plat/iommu.h>
+#include <plat/iovmm.h>
 
 #include "iopgtable.h"
 
@@ -392,7 +392,6 @@ static void sgtable_fill_vmalloc(struct sg_table *sgt, void *_va)
        }
 
        va_end = _va + PAGE_SIZE * i;
-       flush_cache_vmap((unsigned long)_va, (unsigned long)va_end);
 }
 
 static inline void sgtable_drain_vmalloc(struct sg_table *sgt)
@@ -427,8 +426,6 @@ static void sgtable_fill_kmalloc(struct sg_table *sgt, u32 pa, size_t len)
                len -= bytes;
        }
        BUG_ON(len);
-
-       clean_dcache_area(va, len);
 }
 
 static inline void sgtable_drain_kmalloc(struct sg_table *sgt)
@@ -449,7 +446,7 @@ static int map_iovm_area(struct iommu *obj, struct iovm_struct *new,
        struct scatterlist *sg;
        u32 da = new->da_start;
 
-       if (!obj || !new || !sgt)
+       if (!obj || !sgt)
                return -EINVAL;
 
        BUG_ON(!sgtable_ok(sgt));
@@ -617,7 +614,7 @@ u32 iommu_vmap(struct iommu *obj, u32 da, const struct sg_table *sgt,
                 u32 flags)
 {
        size_t bytes;
-       void *va;
+       void *va = NULL;
 
        if (!obj || !obj->dev || !sgt)
                return -EINVAL;
@@ -627,9 +624,11 @@ u32 iommu_vmap(struct iommu *obj, u32 da, const struct sg_table *sgt,
                return -EINVAL;
        bytes = PAGE_ALIGN(bytes);
 
-       va = vmap_sg(sgt);
-       if (IS_ERR(va))
-               return PTR_ERR(va);
+       if (flags & IOVMF_MMIO) {
+               va = vmap_sg(sgt);
+               if (IS_ERR(va))
+                       return PTR_ERR(va);
+       }
 
        flags &= IOVMF_HW_MASK;
        flags |= IOVMF_DISCONT;
index 40424ed..8e90633 100644 (file)
 #include <linux/device.h>
 #include <linux/delay.h>
 
-#include <mach/mailbox.h>
-
-static int enable_seq_bit;
-module_param(enable_seq_bit, bool, 0);
-MODULE_PARM_DESC(enable_seq_bit, "Enable sequence bit checking.");
+#include <plat/mailbox.h>
 
 static struct omap_mbox *mboxes;
 static DEFINE_RWLOCK(mboxes_lock);
 
-/*
- * Mailbox sequence bit API
- */
-
-/* seq_rcv should be initialized with any value other than
- * 0 and 1 << 31, to allow either value for the first
- * message.  */
-static inline void mbox_seq_init(struct omap_mbox *mbox)
-{
-       if (!enable_seq_bit)
-               return;
-
-       /* any value other than 0 and 1 << 31 */
-       mbox->seq_rcv = 0xffffffff;
-}
-
-static inline void mbox_seq_toggle(struct omap_mbox *mbox, mbox_msg_t * msg)
-{
-       if (!enable_seq_bit)
-               return;
-
-       /* add seq_snd to msg */
-       *msg = (*msg & 0x7fffffff) | mbox->seq_snd;
-       /* flip seq_snd */
-       mbox->seq_snd ^= 1 << 31;
-}
-
-static inline int mbox_seq_test(struct omap_mbox *mbox, mbox_msg_t msg)
-{
-       mbox_msg_t seq;
-
-       if (!enable_seq_bit)
-               return 0;
-
-       seq = msg & (1 << 31);
-       if (seq == mbox->seq_rcv)
-               return -1;
-       mbox->seq_rcv = seq;
-       return 0;
-}
+static int mbox_configured;
 
 /* Mailbox FIFO handle functions */
 static inline mbox_msg_t mbox_fifo_read(struct omap_mbox *mbox)
@@ -95,14 +52,6 @@ static inline int mbox_fifo_full(struct omap_mbox *mbox)
 }
 
 /* Mailbox IRQ handle functions */
-static inline void enable_mbox_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq)
-{
-       mbox->ops->enable_irq(mbox, irq);
-}
-static inline void disable_mbox_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq)
-{
-       mbox->ops->disable_irq(mbox, irq);
-}
 static inline void ack_mbox_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq)
 {
        if (mbox->ops->ack_irq)
@@ -113,17 +62,10 @@ static inline int is_mbox_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq)
        return mbox->ops->is_irq(mbox, irq);
 }
 
-/* Mailbox Sequence Bit function */
-void omap_mbox_init_seq(struct omap_mbox *mbox)
-{
-       mbox_seq_init(mbox);
-}
-EXPORT_SYMBOL(omap_mbox_init_seq);
-
 /*
  * message sender
  */
-static int __mbox_msg_send(struct omap_mbox *mbox, mbox_msg_t msg, void *arg)
+static int __mbox_msg_send(struct omap_mbox *mbox, mbox_msg_t msg)
 {
        int ret = 0, i = 1000;
 
@@ -134,89 +76,49 @@ static int __mbox_msg_send(struct omap_mbox *mbox, mbox_msg_t msg, void *arg)
                        return -1;
                udelay(1);
        }
-
-       if (arg && mbox->txq->callback) {
-               ret = mbox->txq->callback(arg);
-               if (ret)
-                       goto out;
-       }
-
-       mbox_seq_toggle(mbox, &msg);
        mbox_fifo_write(mbox, msg);
- out:
        return ret;
 }
 
-struct omap_msg_tx_data {
-       mbox_msg_t      msg;
-       void            *arg;
-};
 
-static void omap_msg_tx_end_io(struct request *rq, int error)
+int omap_mbox_msg_send(struct omap_mbox *mbox, mbox_msg_t msg)
 {
-       kfree(rq->special);
-       __blk_put_request(rq->q, rq);
-}
 
-int omap_mbox_msg_send(struct omap_mbox *mbox, mbox_msg_t msg, void* arg)
-{
-       struct omap_msg_tx_data *tx_data;
        struct request *rq;
        struct request_queue *q = mbox->txq->queue;
 
-       tx_data = kmalloc(sizeof(*tx_data), GFP_ATOMIC);
-       if (unlikely(!tx_data))
-               return -ENOMEM;
-
        rq = blk_get_request(q, WRITE, GFP_ATOMIC);
-       if (unlikely(!rq)) {
-               kfree(tx_data);
+       if (unlikely(!rq))
                return -ENOMEM;
-       }
 
-       tx_data->msg = msg;
-       tx_data->arg = arg;
-       rq->end_io = omap_msg_tx_end_io;
-       blk_insert_request(q, rq, 0, tx_data);
+       blk_insert_request(q, rq, 0, (void *) msg);
+       tasklet_schedule(&mbox->txq->tasklet);
 
-       schedule_work(&mbox->txq->work);
        return 0;
 }
 EXPORT_SYMBOL(omap_mbox_msg_send);
 
-static void mbox_tx_work(struct work_struct *work)
+static void mbox_tx_tasklet(unsigned long tx_data)
 {
        int ret;
        struct request *rq;
-       struct omap_mbox_queue *mq = container_of(work,
-                               struct omap_mbox_queue, work);
-       struct omap_mbox *mbox = mq->queue->queuedata;
+       struct omap_mbox *mbox = (struct omap_mbox *)tx_data;
        struct request_queue *q = mbox->txq->queue;
 
        while (1) {
-               struct omap_msg_tx_data *tx_data;
 
-               spin_lock(q->queue_lock);
                rq = blk_fetch_request(q);
-               spin_unlock(q->queue_lock);
 
                if (!rq)
                        break;
 
-               tx_data = rq->special;
-
-               ret = __mbox_msg_send(mbox, tx_data->msg, tx_data->arg);
+               ret = __mbox_msg_send(mbox, (mbox_msg_t)rq->special);
                if (ret) {
-                       enable_mbox_irq(mbox, IRQ_TX);
-                       spin_lock(q->queue_lock);
+                       omap_mbox_enable_irq(mbox, IRQ_TX);
                        blk_requeue_request(q, rq);
-                       spin_unlock(q->queue_lock);
                        return;
                }
-
-               spin_lock(q->queue_lock);
-               __blk_end_request_all(rq, 0);
-               spin_unlock(q->queue_lock);
+               blk_end_request_all(rq, 0);
        }
 }
 
@@ -233,11 +135,6 @@ static void mbox_rx_work(struct work_struct *work)
        mbox_msg_t msg;
        unsigned long flags;
 
-       if (mbox->rxq->callback == NULL) {
-               sysfs_notify(&mbox->dev->kobj, NULL, "mbox");
-               return;
-       }
-
        while (1) {
                spin_lock_irqsave(q->queue_lock, flags);
                rq = blk_fetch_request(q);
@@ -254,19 +151,19 @@ static void mbox_rx_work(struct work_struct *work)
 /*
  * Mailbox interrupt handler
  */
-static void mbox_txq_fn(struct request_queue * q)
+static void mbox_txq_fn(struct request_queue *q)
 {
 }
 
-static void mbox_rxq_fn(struct request_queue * q)
+static void mbox_rxq_fn(struct request_queue *q)
 {
 }
 
 static void __mbox_tx_interrupt(struct omap_mbox *mbox)
 {
-       disable_mbox_irq(mbox, IRQ_TX);
+       omap_mbox_disable_irq(mbox, IRQ_TX);
        ack_mbox_irq(mbox, IRQ_TX);
-       schedule_work(&mbox->txq->work);
+       tasklet_schedule(&mbox->txq->tasklet);
 }
 
 static void __mbox_rx_interrupt(struct omap_mbox *mbox)
@@ -275,8 +172,6 @@ static void __mbox_rx_interrupt(struct omap_mbox *mbox)
        mbox_msg_t msg;
        struct request_queue *q = mbox->rxq->queue;
 
-       disable_mbox_irq(mbox, IRQ_RX);
-
        while (!mbox_fifo_empty(mbox)) {
                rq = blk_get_request(q, WRITE, GFP_ATOMIC);
                if (unlikely(!rq))
@@ -284,11 +179,6 @@ static void __mbox_rx_interrupt(struct omap_mbox *mbox)
 
                msg = mbox_fifo_read(mbox);
 
-               if (unlikely(mbox_seq_test(mbox, msg))) {
-                       pr_info("mbox: Illegal seq bit!(%08x)\n", msg);
-                       if (mbox->err_notify)
-                               mbox->err_notify();
-               }
 
                blk_insert_request(q, rq, 0, (void *)msg);
                if (mbox->ops->type == OMAP_MBOX_TYPE1)
@@ -297,7 +187,6 @@ static void __mbox_rx_interrupt(struct omap_mbox *mbox)
 
        /* no more messages in the fifo. clear IRQ source. */
        ack_mbox_irq(mbox, IRQ_RX);
-       enable_mbox_irq(mbox, IRQ_RX);
 nomem:
        schedule_work(&mbox->rxq->work);
 }
@@ -315,76 +204,10 @@ static irqreturn_t mbox_interrupt(int irq, void *p)
        return IRQ_HANDLED;
 }
 
-/*
- * sysfs files
- */
-static ssize_t
-omap_mbox_write(struct device *dev, struct device_attribute *attr,
-               const char * buf, size_t count)
-{
-       int ret;
-       mbox_msg_t *p = (mbox_msg_t *)buf;
-       struct omap_mbox *mbox = dev_get_drvdata(dev);
-
-       for (; count >= sizeof(mbox_msg_t); count -= sizeof(mbox_msg_t)) {
-               ret = omap_mbox_msg_send(mbox, be32_to_cpu(*p), NULL);
-               if (ret)
-                       return -EAGAIN;
-               p++;
-       }
-
-       return (size_t)((char *)p - buf);
-}
-
-static ssize_t
-omap_mbox_read(struct device *dev, struct device_attribute *attr, char *buf)
-{
-       unsigned long flags;
-       struct request *rq;
-       mbox_msg_t *p = (mbox_msg_t *) buf;
-       struct omap_mbox *mbox = dev_get_drvdata(dev);
-       struct request_queue *q = mbox->rxq->queue;
-
-       while (1) {
-               spin_lock_irqsave(q->queue_lock, flags);
-               rq = blk_fetch_request(q);
-               spin_unlock_irqrestore(q->queue_lock, flags);
-
-               if (!rq)
-                       break;
-
-               *p = (mbox_msg_t)rq->special;
-
-               blk_end_request_all(rq, 0);
-
-               if (unlikely(mbox_seq_test(mbox, *p))) {
-                       pr_info("mbox: Illegal seq bit!(%08x) ignored\n", *p);
-                       continue;
-               }
-               p++;
-       }
-
-       pr_debug("%02x %02x %02x %02x\n", buf[0], buf[1], buf[2], buf[3]);
-
-       return (size_t) ((char *)p - buf);
-}
-
-static DEVICE_ATTR(mbox, S_IRUGO | S_IWUSR, omap_mbox_read, omap_mbox_write);
-
-static ssize_t mbox_show(struct class *class, char *buf)
-{
-       return sprintf(buf, "mbox");
-}
-
-static CLASS_ATTR(mbox, S_IRUGO, mbox_show, NULL);
-
-static struct class omap_mbox_class = {
-       .name = "omap-mailbox",
-};
-
 static struct omap_mbox_queue *mbox_queue_alloc(struct omap_mbox *mbox,
-                                       request_fn_proc * proc,
-                                       void (*work) (struct work_struct *))
+                                       request_fn_proc *proc,
+                                       void (*work) (struct work_struct *),
+                                       void (*tasklet)(unsigned long))
 {
        struct request_queue *q;
        struct omap_mbox_queue *mq;
@@ -401,8 +224,11 @@ static struct omap_mbox_queue *mbox_queue_alloc(struct omap_mbox *mbox,
        q->queuedata = mbox;
        mq->queue = q;
 
-       INIT_WORK(&mq->work, work);
+       if (work)
+               INIT_WORK(&mq->work, work);
 
+       if (tasklet)
+               tasklet_init(&mq->tasklet, tasklet, (unsigned long)mbox);
        return mq;
 error:
        kfree(mq);
@@ -415,18 +241,25 @@ static void mbox_queue_free(struct omap_mbox_queue *q)
        kfree(q);
 }
 
-static int omap_mbox_init(struct omap_mbox *mbox)
+static int omap_mbox_startup(struct omap_mbox *mbox)
 {
-       int ret;
+       int ret = 0;
        struct omap_mbox_queue *mq;
 
        if (likely(mbox->ops->startup)) {
-               ret = mbox->ops->startup(mbox);
-               if (unlikely(ret))
+               write_lock(&mboxes_lock);
+               if (!mbox_configured)
+                       ret = mbox->ops->startup(mbox);
+
+               if (unlikely(ret)) {
+                       write_unlock(&mboxes_lock);
                        return ret;
+               }
+               mbox_configured++;
+               write_unlock(&mboxes_lock);
        }
 
-       ret = request_irq(mbox->irq, mbox_interrupt, IRQF_DISABLED,
+       ret = request_irq(mbox->irq, mbox_interrupt, IRQF_SHARED,
                                mbox->name, mbox);
        if (unlikely(ret)) {
                printk(KERN_ERR
@@ -434,14 +267,14 @@ static int omap_mbox_init(struct omap_mbox *mbox)
                goto fail_request_irq;
        }
 
-       mq = mbox_queue_alloc(mbox, mbox_txq_fn, mbox_tx_work);
+       mq = mbox_queue_alloc(mbox, mbox_txq_fn, NULL, mbox_tx_tasklet);
        if (!mq) {
                ret = -ENOMEM;
                goto fail_alloc_txq;
        }
        mbox->txq = mq;
 
-       mq = mbox_queue_alloc(mbox, mbox_rxq_fn, mbox_rx_work);
+       mq = mbox_queue_alloc(mbox, mbox_rxq_fn, mbox_rx_work, NULL);
        if (!mq) {
                ret = -ENOMEM;
                goto fail_alloc_rxq;
@@ -468,8 +301,14 @@ static void omap_mbox_fini(struct omap_mbox *mbox)
 
        free_irq(mbox->irq, mbox);
 
-       if (unlikely(mbox->ops->shutdown))
-               mbox->ops->shutdown(mbox);
+       if (unlikely(mbox->ops->shutdown)) {
+               write_lock(&mboxes_lock);
+               if (mbox_configured > 0)
+                       mbox_configured--;
+               if (!mbox_configured)
+                       mbox->ops->shutdown(mbox);
+               write_unlock(&mboxes_lock);
+       }
 }
 
 static struct omap_mbox **find_mboxes(const char *name)
@@ -498,7 +337,7 @@ struct omap_mbox *omap_mbox_get(const char *name)
 
        read_unlock(&mboxes_lock);
 
-       ret = omap_mbox_init(mbox);
+       ret = omap_mbox_startup(mbox);
        if (ret)
                return ERR_PTR(-ENODEV);
 
@@ -522,15 +361,6 @@ int omap_mbox_register(struct device *parent, struct omap_mbox *mbox)
        if (mbox->next)
                return -EBUSY;
 
-       mbox->dev = device_create(&omap_mbox_class,
-                                 parent, 0, mbox, "%s", mbox->name);
-       if (IS_ERR(mbox->dev))
-               return PTR_ERR(mbox->dev);
-
-       ret = device_create_file(mbox->dev, &dev_attr_mbox);
-       if (ret)
-               goto err_sysfs;
-
        write_lock(&mboxes_lock);
        tmp = find_mboxes(mbox->name);
        if (*tmp) {
@@ -544,9 +374,6 @@ int omap_mbox_register(struct device *parent, struct omap_mbox *mbox)
        return 0;
 
 err_find:
-       device_remove_file(mbox->dev, &dev_attr_mbox);
-err_sysfs:
-       device_unregister(mbox->dev);
        return ret;
 }
 EXPORT_SYMBOL(omap_mbox_register);
@@ -562,8 +389,6 @@ int omap_mbox_unregister(struct omap_mbox *mbox)
                        *tmp = mbox->next;
                        mbox->next = NULL;
                        write_unlock(&mboxes_lock);
-                       device_remove_file(mbox->dev, &dev_attr_mbox);
-                       device_unregister(mbox->dev);
                        return 0;
                }
                tmp = &(*tmp)->next;
@@ -574,23 +399,16 @@ int omap_mbox_unregister(struct omap_mbox *mbox)
 }
 EXPORT_SYMBOL(omap_mbox_unregister);
 
-static int __init omap_mbox_class_init(void)
+static int __init omap_mbox_init(void)
 {
-       int ret = class_register(&omap_mbox_class);
-       if (!ret)
-               ret = class_create_file(&omap_mbox_class, &class_attr_mbox);
-
-       return ret;
+       return 0;
 }
+module_init(omap_mbox_init);
 
-static void __exit omap_mbox_class_exit(void)
+static void __exit omap_mbox_exit(void)
 {
-       class_remove_file(&omap_mbox_class, &class_attr_mbox);
-       class_unregister(&omap_mbox_class);
 }
-
-subsys_initcall(omap_mbox_class_init);
-module_exit(omap_mbox_class_exit);
+module_exit(omap_mbox_exit);
 
 MODULE_LICENSE("GPL v2");
 MODULE_DESCRIPTION("omap mailbox: interrupt driven messaging");
index e664b91..2cc1cc3 100644 (file)
@@ -24,8 +24,8 @@
 #include <linux/delay.h>
 #include <linux/io.h>
 
-#include <mach/dma.h>
-#include <mach/mcbsp.h>
+#include <plat/dma.h>
+#include <plat/mcbsp.h>
 
 struct omap_mcbsp **mcbsp_ptr;
 int omap_mcbsp_count;
@@ -298,9 +298,7 @@ int omap_mcbsp_get_dma_op_mode(unsigned int id)
        }
        mcbsp = id_to_mcbsp_ptr(id);
 
-       spin_lock_irq(&mcbsp->lock);
        dma_op_mode = mcbsp->dma_op_mode;
-       spin_unlock_irq(&mcbsp->lock);
 
        return dma_op_mode;
 }
@@ -318,7 +316,6 @@ static inline void omap34xx_mcbsp_request(struct omap_mcbsp *mcbsp)
                syscon = OMAP_MCBSP_READ(mcbsp->io_base, SYSCON);
                syscon &= ~(ENAWAKEUP | SIDLEMODE(0x03) | CLOCKACTIVITY(0x03));
 
-               spin_lock_irq(&mcbsp->lock);
                if (mcbsp->dma_op_mode == MCBSP_DMA_MODE_THRESHOLD) {
                        syscon |= (ENAWAKEUP | SIDLEMODE(0x02) |
                                        CLOCKACTIVITY(0x02));
@@ -327,7 +324,6 @@ static inline void omap34xx_mcbsp_request(struct omap_mcbsp *mcbsp)
                } else {
                        syscon |= SIDLEMODE(0x01);
                }
-               spin_unlock_irq(&mcbsp->lock);
 
                OMAP_MCBSP_WRITE(mcbsp->io_base, SYSCON, syscon);
        }
@@ -1145,9 +1141,7 @@ static ssize_t dma_op_mode_show(struct device *dev,
        ssize_t len = 0;
        const char * const *s;
 
-       spin_lock_irq(&mcbsp->lock);
        dma_op_mode = mcbsp->dma_op_mode;
-       spin_unlock_irq(&mcbsp->lock);
 
        for (s = &dma_op_modes[i]; i < ARRAY_SIZE(dma_op_modes); s++, i++) {
                if (dma_op_mode == i)
index 8d329fb..05aebca 100644 (file)
@@ -28,7 +28,7 @@
 #include <linux/io.h>
 #include <asm/system.h>
 #include <linux/spinlock.h>
-#include <mach/mux.h>
+#include <plat/mux.h>
 
 #ifdef CONFIG_OMAP_MUX
 
index e98f0a2..186bca8 100644 (file)
@@ -22,9 +22,9 @@
 #include <linux/device.h>
 
 /* Interface documentation is in mach/omap-pm.h */
-#include <mach/omap-pm.h>
+#include <plat/omap-pm.h>
 
-#include <mach/powerdomain.h>
+#include <plat/powerdomain.h>
 
 struct omap_opp *dsp_opps;
 struct omap_opp *mpu_opps;
index 2c409fc..bb16e62 100644 (file)
@@ -82,8 +82,8 @@
 #include <linux/err.h>
 #include <linux/io.h>
 
-#include <mach/omap_device.h>
-#include <mach/omap_hwmod.h>
+#include <plat/omap_device.h>
+#include <plat/omap_hwmod.h>
 
 /* These parameters are passed to _omap_device_{de,}activate() */
 #define USE_WAKEUP_LAT                 0
 /* Private functions */
 
 /**
- * _read_32ksynct - read the OMAP 32K sync timer
- *
- * Returns the current value of the 32KiHz synchronization counter.
- * XXX this should be generalized to simply read the system clocksource.
- * XXX this should be moved to a separate synctimer32k.c file
- */
-static u32 _read_32ksynct(void)
-{
-       if (!cpu_class_is_omap2())
-               BUG();
-
-       return __raw_readl(OMAP2_IO_ADDRESS(OMAP_32KSYNCT_BASE + 0x010));
-}
-
-/**
  * _omap_device_activate - increase device readiness
  * @od: struct omap_device *
  * @ignore_lat: increase to latency target (0) or full readiness (1)?
@@ -133,13 +118,13 @@ static u32 _read_32ksynct(void)
  */
 static int _omap_device_activate(struct omap_device *od, u8 ignore_lat)
 {
-       u32 a, b;
+       struct timespec a, b, c;
 
        pr_debug("omap_device: %s: activating\n", od->pdev.name);
 
        while (od->pm_lat_level > 0) {
                struct omap_device_pm_latency *odpl;
-               int act_lat = 0;
+               unsigned long long act_lat = 0;
 
                od->pm_lat_level--;
 
@@ -149,20 +134,22 @@ static int _omap_device_activate(struct omap_device *od, u8 ignore_lat)
                    (od->dev_wakeup_lat <= od->_dev_wakeup_lat_limit))
                        break;
 
-               a = _read_32ksynct();
+               getnstimeofday(&a);
 
                /* XXX check return code */
                odpl->activate_func(od);
 
-               b = _read_32ksynct();
+               getnstimeofday(&b);
 
-               act_lat = (b - a) >> 15; /* 32KiHz cycles to microseconds */
+               c = timespec_sub(b, a);
+               act_lat = timespec_to_ns(&c) * NSEC_PER_USEC;
 
                pr_debug("omap_device: %s: pm_lat %d: activate: elapsed time "
-                        "%d usec\n", od->pdev.name, od->pm_lat_level, act_lat);
+                        "%llu usec\n", od->pdev.name, od->pm_lat_level,
+                        act_lat);
 
                WARN(act_lat > odpl->activate_lat, "omap_device: %s.%d: "
-                    "activate step %d took longer than expected (%d > %d)\n",
+                    "activate step %d took longer than expected (%llu > %d)\n",
                     od->pdev.name, od->pdev.id, od->pm_lat_level,
                     act_lat, odpl->activate_lat);
 
@@ -188,13 +175,13 @@ static int _omap_device_activate(struct omap_device *od, u8 ignore_lat)
  */
 static int _omap_device_deactivate(struct omap_device *od, u8 ignore_lat)
 {
-       u32 a, b;
+       struct timespec a, b, c;
 
        pr_debug("omap_device: %s: deactivating\n", od->pdev.name);
 
        while (od->pm_lat_level < od->pm_lats_cnt) {
                struct omap_device_pm_latency *odpl;
-               int deact_lat = 0;
+               unsigned long long deact_lat = 0;
 
                odpl = od->pm_lats + od->pm_lat_level;
 
@@ -203,23 +190,24 @@ static int _omap_device_deactivate(struct omap_device *od, u8 ignore_lat)
                     od->_dev_wakeup_lat_limit))
                        break;
 
-               a = _read_32ksynct();
+               getnstimeofday(&a);
 
                /* XXX check return code */
                odpl->deactivate_func(od);
 
-               b = _read_32ksynct();
+               getnstimeofday(&b);
 
-               deact_lat = (b - a) >> 15; /* 32KiHz cycles to microseconds */
+               c = timespec_sub(b, a);
+               deact_lat = timespec_to_ns(&c) * NSEC_PER_USEC;
 
                pr_debug("omap_device: %s: pm_lat %d: deactivate: elapsed time "
-                        "%d usec\n", od->pdev.name, od->pm_lat_level,
+                        "%llu usec\n", od->pdev.name, od->pm_lat_level,
                         deact_lat);
 
                WARN(deact_lat > odpl->deactivate_lat, "omap_device: %s.%d: "
-                    "deactivate step %d took longer than expected (%d > %d)\n",
-                    od->pdev.name, od->pdev.id, od->pm_lat_level,
-                    deact_lat, odpl->deactivate_lat);
+                    "deactivate step %d took longer than expected "
+                    "(%llu > %d)\n", od->pdev.name, od->pdev.id,
+                    od->pm_lat_level, deact_lat, odpl->deactivate_lat);
 
                od->dev_wakeup_lat += odpl->activate_lat;
 
index 75d1f26..3e92366 100644 (file)
 
 #include <asm/mach/map.h>
 
-#include <mach/sram.h>
-#include <mach/board.h>
-#include <mach/cpu.h>
+#include <plat/sram.h>
+#include <plat/board.h>
+#include <plat/cpu.h>
 
-#include <mach/control.h>
+#include <plat/control.h>
 
 #if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3)
 # include "../mach-omap2/prm.h"
 #define OMAP1_SRAM_VA          VMALLOC_END
 #define OMAP2_SRAM_PA          0x40200000
 #define OMAP2_SRAM_PUB_PA      0x4020f800
-#define OMAP2_SRAM_VA          0xe3000000
+#define OMAP2_SRAM_VA          0xfe400000
 #define OMAP2_SRAM_PUB_VA      (OMAP2_SRAM_VA + 0x800)
 #define OMAP3_SRAM_PA           0x40200000
-#define OMAP3_SRAM_VA           0xe3000000
+#define OMAP3_SRAM_VA           0xfe400000
 #define OMAP3_SRAM_PUB_PA       0x40208000
 #define OMAP3_SRAM_PUB_VA       (OMAP3_SRAM_VA + 0x8000)
 #define OMAP4_SRAM_PA          0x40200000              /*0x402f0000*/
-#define OMAP4_SRAM_VA          0xd7000000              /*0xd70f0000*/
+#define OMAP4_SRAM_VA          0xfe400000              /*0xfe4f0000*/
 
 #if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX)
 #define SRAM_BOOTLOADER_SZ     0x00
 #define SRAM_BOOTLOADER_SZ     0x80
 #endif
 
-#define OMAP24XX_VA_REQINFOPERM0       OMAP2_IO_ADDRESS(0x68005048)
-#define OMAP24XX_VA_READPERM0          OMAP2_IO_ADDRESS(0x68005050)
-#define OMAP24XX_VA_WRITEPERM0         OMAP2_IO_ADDRESS(0x68005058)
+#define OMAP24XX_VA_REQINFOPERM0       OMAP2_L3_IO_ADDRESS(0x68005048)
+#define OMAP24XX_VA_READPERM0          OMAP2_L3_IO_ADDRESS(0x68005050)
+#define OMAP24XX_VA_WRITEPERM0         OMAP2_L3_IO_ADDRESS(0x68005058)
 
-#define OMAP34XX_VA_REQINFOPERM0       OMAP2_IO_ADDRESS(0x68012848)
-#define OMAP34XX_VA_READPERM0          OMAP2_IO_ADDRESS(0x68012850)
-#define OMAP34XX_VA_WRITEPERM0         OMAP2_IO_ADDRESS(0x68012858)
-#define OMAP34XX_VA_ADDR_MATCH2                OMAP2_IO_ADDRESS(0x68012880)
-#define OMAP34XX_VA_SMS_RG_ATT0                OMAP2_IO_ADDRESS(0x6C000048)
-#define OMAP34XX_VA_CONTROL_STAT       OMAP2_IO_ADDRESS(0x480022F0)
+#define OMAP34XX_VA_REQINFOPERM0       OMAP2_L3_IO_ADDRESS(0x68012848)
+#define OMAP34XX_VA_READPERM0          OMAP2_L3_IO_ADDRESS(0x68012850)
+#define OMAP34XX_VA_WRITEPERM0         OMAP2_L3_IO_ADDRESS(0x68012858)
+#define OMAP34XX_VA_ADDR_MATCH2                OMAP2_L3_IO_ADDRESS(0x68012880)
+#define OMAP34XX_VA_SMS_RG_ATT0                OMAP2_L3_IO_ADDRESS(0x6C000048)
+#define OMAP34XX_VA_CONTROL_STAT       OMAP2_L4_IO_ADDRESS(0x480022F0)
 
 #define GP_DEVICE              0x300
 
@@ -396,22 +396,24 @@ u32 omap3_configure_core_dpll(u32 m2, u32 unlock_dll, u32 f, u32 inc,
                        sdrc_actim_ctrl_b_1, sdrc_mr_1);
 }
 
-/* REVISIT: Should this be same as omap34xx_sram_init() after off-idle? */
-void restore_sram_functions(void)
+#ifdef CONFIG_PM
+void omap3_sram_restore_context(void)
 {
        omap_sram_ceil = omap_sram_base + omap_sram_size;
 
        _omap3_sram_configure_core_dpll =
                omap_sram_push(omap3_sram_configure_core_dpll,
                               omap3_sram_configure_core_dpll_sz);
+       omap_push_sram_idle();
 }
+#endif /* CONFIG_PM */
 
 int __init omap34xx_sram_init(void)
 {
        _omap3_sram_configure_core_dpll =
                omap_sram_push(omap3_sram_configure_core_dpll,
                               omap3_sram_configure_core_dpll_sz);
-
+       omap_push_sram_idle();
        return 0;
 }
 #else
index 509f2ed..51033a4 100644 (file)
 #include <asm/system.h>
 #include <mach/hardware.h>
 
-#include <mach/control.h>
-#include <mach/mux.h>
-#include <mach/usb.h>
-#include <mach/board.h>
+#include <plat/control.h>
+#include <plat/mux.h>
+#include <plat/usb.h>
+#include <plat/board.h>
 
 #ifdef CONFIG_ARCH_OMAP1
 
@@ -159,11 +159,14 @@ static u32 __init omap_usb0_init(unsigned nwires, unsigned is_device)
                 *  - OTG support on this port not yet written
                 */
 
-               l = omap_readl(USB_TRANSCEIVER_CTRL);
-               l &= ~(7 << 4);
-               if (!is_device)
-                       l |= (3 << 1);
-               omap_writel(l, USB_TRANSCEIVER_CTRL);
+               /* Don't do this for omap7xx -- it causes USB to not work correctly */
+               if (!cpu_is_omap7xx()) {
+                       l = omap_readl(USB_TRANSCEIVER_CTRL);
+                       l &= ~(7 << 4);
+                       if (!is_device)
+                               l |= (3 << 1);
+                       omap_writel(l, USB_TRANSCEIVER_CTRL);
+               }
 
                return 3 << 16;
        }
@@ -603,7 +606,12 @@ omap_otg_init(struct omap_usb_config *config)
        if (config->otg || config->register_dev) {
                syscon &= ~DEV_IDLE_EN;
                udc_device.dev.platform_data = config;
-               /* FIXME patch IRQ numbers for omap730 */
+               /* IRQ numbers for omap7xx */
+               if(cpu_is_omap7xx()) {
+                       udc_resources[1].start = INT_7XX_USB_GENI;
+                       udc_resources[2].start = INT_7XX_USB_NON_ISO;
+                       udc_resources[3].start = INT_7XX_USB_ISO;
+               }
                status = platform_device_register(&udc_device);
                if (status)
                        pr_debug("can't register UDC device, %d\n", status);
@@ -614,8 +622,8 @@ omap_otg_init(struct omap_usb_config *config)
        if (config->otg || config->register_host) {
                syscon &= ~HST_IDLE_EN;
                ohci_device.dev.platform_data = config;
-               if (cpu_is_omap730())
-                       ohci_resources[1].start = INT_730_USB_HHC_1;
+               if (cpu_is_omap7xx())
+                       ohci_resources[1].start = INT_7XX_USB_HHC_1;
                status = platform_device_register(&ohci_device);
                if (status)
                        pr_debug("can't register OHCI device, %d\n", status);
@@ -626,8 +634,8 @@ omap_otg_init(struct omap_usb_config *config)
        if (config->otg) {
                syscon &= ~OTG_IDLE_EN;
                otg_device.dev.platform_data = config;
-               if (cpu_is_omap730())
-                       otg_resources[1].start = INT_730_USB_OTG;
+               if (cpu_is_omap7xx())
+                       otg_resources[1].start = INT_7XX_USB_OTG;
                status = platform_device_register(&otg_device);
                if (status)
                        pr_debug("can't register OTG device, %d\n", status);
@@ -731,7 +739,7 @@ static inline void omap_1510_usb_init(struct omap_usb_config *config) {}
 
 void __init omap_usb_init(struct omap_usb_config *pdata)
 {
-       if (cpu_is_omap730() || cpu_is_omap16xx() || cpu_is_omap24xx())
+       if (cpu_is_omap7xx() || cpu_is_omap16xx() || cpu_is_omap24xx())
                omap_otg_init(pdata);
        else if (cpu_is_omap15xx())
                omap_1510_usb_init(pdata);
index 8931c5f..e139a72 100644 (file)
@@ -159,6 +159,12 @@ config S3C_GPIO_CFG_S3C64XX
          Internal configuration to enable S3C64XX style GPIO configuration
          functions.
 
+config S5P_GPIO_CFG_S5PC1XX
+       bool
+       help
+         Internal configuration to enable S5PC1XX style GPIO configuration
+         functions.
+
 # DMA
 
 config S3C_DMA
@@ -178,6 +184,11 @@ config S3C_DEV_HSMMC1
        help
          Compile in platform device definitions for HSMMC channel 1
 
+config S3C_DEV_HSMMC2
+       bool
+       help
+         Compile in platform device definitions for HSMMC channel 2
+
 config S3C_DEV_I2C1
        bool
        help
index 3c09109..50444da 100644 (file)
@@ -36,6 +36,7 @@ obj-$(CONFIG_HAVE_PWM)                += pwm.o
 
 obj-$(CONFIG_S3C_DEV_HSMMC)    += dev-hsmmc.o
 obj-$(CONFIG_S3C_DEV_HSMMC1)   += dev-hsmmc1.o
+obj-$(CONFIG_S3C_DEV_HSMMC2)   += dev-hsmmc2.o
 obj-y                          += dev-i2c0.o
 obj-$(CONFIG_S3C_DEV_I2C1)     += dev-i2c1.o
 obj-$(CONFIG_S3C_DEV_FB)       += dev-fb.o
index 4d01ef1..619cfa8 100644 (file)
@@ -1,6 +1,6 @@
 /* linux/arch/arm/plat-s3c24xx/clock.c
  *
- * Copyright (c) 2004-2005 Simtec Electronics
+ * Copyright 2004-2005 Simtec Electronics
  *     Ben Dooks <ben@simtec.co.uk>
  *
  * S3C24XX Core clock control support
@@ -337,7 +337,7 @@ int s3c24xx_register_clocks(struct clk **clks, int nr_clks)
 
 int __init s3c24xx_register_baseclocks(unsigned long xtal)
 {
-       printk(KERN_INFO "S3C24XX Clocks, (c) 2004 Simtec Electronics\n");
+       printk(KERN_INFO "S3C24XX Clocks, Copyright 2004 Simtec Electronics\n");
 
        clk_xtal.rate = xtal;
 
diff --git a/arch/arm/plat-s3c/dev-hsmmc2.c b/arch/arm/plat-s3c/dev-hsmmc2.c
new file mode 100644 (file)
index 0000000..824580b
--- /dev/null
@@ -0,0 +1,69 @@
+/* linux/arch/arm/plat-s3c/dev-hsmmc2.c
+ *
+ * Copyright (c) 2009 Samsung Electronics
+ * Copyright (c) 2009 Maurus Cuelenaere
+ *
+ * Based on arch/arm/plat-s3c/dev-hsmmc1.c
+ * original file Copyright (c) 2008 Simtec Electronics
+ *
+ * S3C series device definition for hsmmc device 2
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/mmc/host.h>
+
+#include <mach/map.h>
+#include <plat/sdhci.h>
+#include <plat/devs.h>
+
+#define S3C_SZ_HSMMC   (0x1000)
+
+static struct resource s3c_hsmmc2_resource[] = {
+       [0] = {
+               .start = S3C_PA_HSMMC2,
+               .end   = S3C_PA_HSMMC2 + S3C_SZ_HSMMC - 1,
+               .flags = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start = IRQ_HSMMC2,
+               .end   = IRQ_HSMMC2,
+               .flags = IORESOURCE_IRQ,
+       }
+};
+
+static u64 s3c_device_hsmmc2_dmamask = 0xffffffffUL;
+
+struct s3c_sdhci_platdata s3c_hsmmc2_def_platdata = {
+       .max_width      = 4,
+       .host_caps      = (MMC_CAP_4_BIT_DATA |
+                          MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED),
+};
+
+struct platform_device s3c_device_hsmmc2 = {
+       .name           = "s3c-sdhci",
+       .id             = 2,
+       .num_resources  = ARRAY_SIZE(s3c_hsmmc2_resource),
+       .resource       = s3c_hsmmc2_resource,
+       .dev            = {
+               .dma_mask               = &s3c_device_hsmmc2_dmamask,
+               .coherent_dma_mask      = 0xffffffffUL,
+               .platform_data          = &s3c_hsmmc2_def_platdata,
+       },
+};
+
+void s3c_sdhci2_set_platdata(struct s3c_sdhci_platdata *pd)
+{
+       struct s3c_sdhci_platdata *set = &s3c_hsmmc2_def_platdata;
+
+       set->max_width = pd->max_width;
+
+       if (pd->cfg_gpio)
+               set->cfg_gpio = pd->cfg_gpio;
+       if (pd->cfg_card)
+               set->cfg_card = pd->cfg_card;
+}
index 4283728..4c76152 100644 (file)
@@ -1,6 +1,6 @@
 /* linux/arch/arm/plat-s3c/dev-i2c0.c
  *
- * Copyright 2008,2009 Simtec Electronics
+ * Copyright 2008-2009 Simtec Electronics
  *     Ben Dooks <ben@simtec.co.uk>
  *     http://armlinux.simtec.co.uk/
  *
index 8349c46..d44f791 100644 (file)
@@ -1,6 +1,6 @@
 /* linux/arch/arm/plat-s3c/dev-i2c1.c
  *
- * Copyright 2008,2009 Simtec Electronics
+ * Copyright 2008-2009 Simtec Electronics
  *     Ben Dooks <ben@simtec.co.uk>
  *     http://armlinux.simtec.co.uk/
  *
index 4e53237..e771e77 100644 (file)
@@ -9,8 +9,12 @@
 #include <linux/kernel.h>
 #include <linux/platform_device.h>
 
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+
 #include <mach/map.h>
 #include <plat/devs.h>
+#include <plat/nand.h>
 
 static struct resource s3c_nand_resource[] = {
        [0] = {
@@ -28,3 +32,96 @@ struct platform_device s3c_device_nand = {
 };
 
 EXPORT_SYMBOL(s3c_device_nand);
+
+/**
+ * s3c_nand_copy_set() - copy nand set data
+ * @set: The new structure, directly copied from the old.
+ *
+ * Copy all the fields from the NAND set field from what is probably __initdata
+ * to new kernel memory. The code returns 0 if the copy happened correctly or
+ * an error code for the calling function to display.
+ *
+ * Note, we currently do not try and look to see if we've already copied the
+ * data in a previous set.
+ */
+static int __init s3c_nand_copy_set(struct s3c2410_nand_set *set)
+{
+       void *ptr;
+       int size;
+
+       size = sizeof(struct mtd_partition) * set->nr_partitions;
+       if (size) {
+               ptr = kmemdup(set->partitions, size, GFP_KERNEL);
+               set->partitions = ptr;
+
+               if (!ptr)
+                       return -ENOMEM;
+       }
+       
+       size = sizeof(int) * set->nr_chips;
+       if (size) {
+               ptr = kmemdup(set->nr_map, size, GFP_KERNEL);
+               set->nr_map = ptr;
+
+               if (!ptr)
+                       return -ENOMEM;
+       }
+
+       if (set->ecc_layout) {
+               ptr = kmemdup(set->ecc_layout,
+                             sizeof(struct nand_ecclayout), GFP_KERNEL);
+               set->ecc_layout = ptr;
+
+               if (!ptr)
+                       return -ENOMEM;
+       }
+       
+       return 0;
+}
+
+void __init s3c_nand_set_platdata(struct s3c2410_platform_nand *nand)
+{
+       struct s3c2410_platform_nand *npd;
+       int size;
+       int ret;
+
+       /* note, if we get a failure in allocation, we simply drop out of the
+        * function. If there is so little memory available at initialisation
+        * time then there is little chance the system is going to run.
+        */ 
+
+       npd = kmemdup(nand, sizeof(struct s3c2410_platform_nand), GFP_KERNEL);
+       if (!npd) {
+               printk(KERN_ERR "%s: failed copying platform data\n", __func__);
+               return;
+       }
+
+       /* now see if we need to copy any of the nand set data */
+
+       size = sizeof(struct s3c2410_nand_set) * npd->nr_sets;
+       if (size) {
+               struct s3c2410_nand_set *from = npd->sets;
+               struct s3c2410_nand_set *to;
+               int i;
+
+               to = kmemdup(from, size, GFP_KERNEL);
+               npd->sets = to; /* set, even if we failed */
+
+               if (!to) {
+                       printk(KERN_ERR "%s: no memory for sets\n", __func__);
+                       return;
+               }
+               
+               for (i = 0; i < npd->nr_sets; i++) {
+                       ret = s3c_nand_copy_set(to);
+                       if (!ret) {
+                               printk(KERN_ERR "%s: failed to copy set %d\n",
+                               __func__, i);
+                               return;
+                       }
+                       to++;
+               }
+       }
+}
+
+EXPORT_SYMBOL_GPL(s3c_nand_set_platdata);
index c9db75c..a995850 100644 (file)
@@ -1,6 +1,6 @@
 /* linux/arch/arm/plat-s3c/dma.c
  *
- * Copyright (c) 2003-2005,2006,2009 Simtec Electronics
+ * Copyright (c) 2003-2009 Simtec Electronics
  *     Ben Dooks <ben@simtec.co.uk>
  *     http://armlinux.simtec.co.uk/
  *
index 0f440b9..53a9365 100644 (file)
@@ -33,5 +33,5 @@ struct s3c24xx_audio_simtec_pdata {
        void    (*startup)(void);
 };
 
-extern int simtec_audio_add(const char *codec_name,
+extern int simtec_audio_add(const char *codec_name, bool has_lr_routing,
                            struct s3c24xx_audio_simtec_pdata *pdata);
index de0e8da..f22d23b 100644 (file)
@@ -1,45 +1,17 @@
-/* arch/arm/mach-s3c2410/include/mach/audio.h
+/* arch/arm/plat-s3c/include/plat/audio.h
  *
- * Copyright (c) 2004-2005 Simtec Electronics
- *     http://www.simtec.co.uk/products/SWLINUX/
- *     Ben Dooks <ben@simtec.co.uk>
- *
- * S3C24XX - Audio platfrom_device info
+ * Copyright (c) 2009 Samsung Electronics Co. Ltd
+ * Author: 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_AUDIO_H
-#define __ASM_ARCH_AUDIO_H __FILE__
-
-/* struct s3c24xx_iis_ops
- *
- * called from the s3c24xx audio core to deal with the architecture
- * or the codec's setup and control.
- *
- * the pointer to itself is passed through in case the caller wants to
- * embed this in an larger structure for easy reference to it's context.
-*/
+ */
 
-struct s3c24xx_iis_ops {
-       struct module *owner;
-
-       int     (*startup)(struct s3c24xx_iis_ops *me);
-       void    (*shutdown)(struct s3c24xx_iis_ops *me);
-       int     (*suspend)(struct s3c24xx_iis_ops *me);
-       int     (*resume)(struct s3c24xx_iis_ops *me);
-
-       int     (*open)(struct s3c24xx_iis_ops *me, struct snd_pcm_substream *strm);
-       int     (*close)(struct s3c24xx_iis_ops *me, struct snd_pcm_substream *strm);
-       int     (*prepare)(struct s3c24xx_iis_ops *me, struct snd_pcm_substream *strm, struct snd_pcm_runtime *rt);
+/**
+ * struct s3c_audio_pdata - common platform data for audio device drivers
+ * @cfg_gpio: Callback function to setup mux'ed pins in I2S/PCM/AC97 mode
+ */
+struct s3c_audio_pdata {
+       int (*cfg_gpio)(struct platform_device *);
 };
-
-struct s3c24xx_platdata_iis {
-       const char              *codec_clk;
-       struct s3c24xx_iis_ops  *ops;
-       int                     (*match_dev)(struct device *dev);
-};
-
-#endif /* __ASM_ARCH_AUDIO_H */
index 7b982b7..94eb06a 100644 (file)
@@ -1,6 +1,6 @@
 /* arch/arm/plat-s3c/include/plat/cpu-freq.h
  *
- * Copyright (c) 2006,2007 Simtec Electronics
+ * Copyright (c) 2006-2007 Simtec Electronics
  *     http://armlinux.simtec.co.uk/
  *     Ben Dooks <ben@simtec.co.uk>
  *
index fbc3d49..d1131ca 100644 (file)
@@ -12,6 +12,9 @@
 
 /* todo - fix when rmk changes iodescs to use `void __iomem *` */
 
+#ifndef __SAMSUNG_PLAT_CPU_H
+#define __SAMSUNG_PLAT_CPU_H
+
 #define IODESC_ENT(x) { (unsigned long)S3C24XX_VA_##x, __phys_to_pfn(S3C24XX_PA_##x), S3C24XX_SZ_##x, MT_DEVICE }
 
 #ifndef MHZ
@@ -73,3 +76,6 @@ extern struct sysdev_class s3c2443_sysclass;
 extern struct sysdev_class s3c6410_sysclass;
 extern struct sysdev_class s3c64xx_sysclass;
 
+extern void (*s5pc1xx_idle)(void);
+
+#endif
index 0f540ea..932cbbb 100644 (file)
@@ -28,6 +28,9 @@ extern struct platform_device s3c64xx_device_iis0;
 extern struct platform_device s3c64xx_device_iis1;
 extern struct platform_device s3c64xx_device_iisv4;
 
+extern struct platform_device s3c64xx_device_pcm0;
+extern struct platform_device s3c64xx_device_pcm1;
+
 extern struct platform_device s3c_device_fb;
 extern struct platform_device s3c_device_usb;
 extern struct platform_device s3c_device_lcd;
index 34dba98..e429d10 100644 (file)
@@ -1,6 +1,6 @@
 /* arch/arm/plat-s3c/include/plat/dma.h
  *
- * Copyright (C) 2003,2004,2006 Simtec Electronics
+ * Copyright (C) 2003-2006 Simtec Electronics
  *     Ben Dooks <ben@simtec.co.uk>
  *
  * Samsung S3C DMA support
index 214ff56..f8db879 100644 (file)
@@ -70,4 +70,11 @@ extern void s3c_fb_set_platdata(struct s3c_fb_platdata *pd);
  */
 extern void s3c64xx_fb_gpio_setup_24bpp(void);
 
+/**
+ * s5pc100_fb_gpio_setup_24bpp() - S5PC100 setup function for 24bpp LCD
+ *
+ * Initialise the GPIO for an 24bpp LCD display on the RGB interface.
+ */
+extern void s5pc100_fb_gpio_setup_24bpp(void);
+
 #endif /* __PLAT_S3C_FB_H */
index 67450f1..3083df0 100644 (file)
@@ -1,6 +1,6 @@
 /* arch/arm/plat-s3c/include/plat/iic.h
  *
- * Copyright 2004,2009 Simtec Electronics
+ * Copyright 2004-2009 Simtec Electronics
  *     Ben Dooks <ben@simtec.co.uk>
  *
  * S3C - I2C Controller platform_device info
index 18f9588..0659859 100644 (file)
@@ -55,3 +55,11 @@ struct s3c2410_platform_nand {
                                               int chip);
 };
 
+/**
+ * s3c_nand_set_platdata() - register NAND platform data.
+ * @nand: The NAND platform data to register with s3c_device_nand.
+ *
+ * This function copies the given NAND platform data, @nand and registers
+ * it with the s3c_device_nand. This allows @nand to be __initdata.
+*/
+extern void s3c_nand_set_platdata(struct s3c2410_platform_nand *nand);
diff --git a/arch/arm/plat-s3c/include/plat/regs-fb-v4.h b/arch/arm/plat-s3c/include/plat/regs-fb-v4.h
new file mode 100644 (file)
index 0000000..a60ed0d
--- /dev/null
@@ -0,0 +1,235 @@
+/* arch/arm/plat-s3c/include/plat/regs-fb-v4.h
+ *
+ * Copyright 2008 Openmoko, Inc.
+ * Copyright 2008 Simtec Electronics
+ *      http://armlinux.simtec.co.uk/
+ *      Ben Dooks <ben@simtec.co.uk>
+ *
+ * S3C64XX - new-style framebuffer register definitions
+ *
+ * This is the register set for the new style framebuffer interface
+ * found from the S3C2443 onwards and specifically the S3C64XX series
+ * S3C6400 and S3C6410.
+ *
+ * The file contains the cpu specific items which change between whichever
+ * architecture is selected. See <plat/regs-fb.h> for the core definitions
+ * that are the same.
+ *
+ * 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 the core definitions here, in case we really do need to
+ * override them at a later date.
+*/
+
+#include <plat/regs-fb.h>
+
+#define S3C_FB_MAX_WIN (5)  /* number of hardware windows available. */
+#define VIDCON1_FSTATUS_EVEN   (1 << 15)
+
+/* Video timing controls */
+#define VIDTCON0                               (0x10)
+#define VIDTCON1                               (0x14)
+#define VIDTCON2                               (0x18)
+
+/* Window position controls */
+
+#define WINCON(_win)                           (0x20 + ((_win) * 4))
+
+/* OSD1 and OSD4 do not have register D */
+
+#define VIDOSD_A(_win)                         (0x40 + ((_win) * 16))
+#define VIDOSD_B(_win)                         (0x44 + ((_win) * 16))
+#define VIDOSD_C(_win)                         (0x48 + ((_win) * 16))
+#define VIDOSD_D(_win)                         (0x4C + ((_win) * 16))
+
+
+#define VIDINTCON0                             (0x130)
+
+#define WxKEYCONy(_win, _con)                  ((0x140 + ((_win) * 8)) + ((_con) * 4))
+
+/* WINCONx */
+
+#define WINCONx_CSCWIDTH_MASK                  (0x3 << 26)
+#define WINCONx_CSCWIDTH_SHIFT                 (26)
+#define WINCONx_CSCWIDTH_WIDE                  (0x0 << 26)
+#define WINCONx_CSCWIDTH_NARROW                        (0x3 << 26)
+
+#define WINCONx_ENLOCAL                                (1 << 22)
+#define WINCONx_BUFSTATUS                      (1 << 21)
+#define WINCONx_BUFSEL                         (1 << 20)
+#define WINCONx_BUFAUTOEN                      (1 << 19)
+#define WINCONx_YCbCr                          (1 << 13)
+
+#define WINCON1_LOCALSEL_CAMIF                 (1 << 23)
+
+#define WINCON2_LOCALSEL_CAMIF                 (1 << 23)
+#define WINCON2_BLD_PIX                                (1 << 6)
+
+#define WINCON2_ALPHA_SEL                      (1 << 1)
+#define WINCON2_BPPMODE_MASK                   (0xf << 2)
+#define WINCON2_BPPMODE_SHIFT                  (2)
+#define WINCON2_BPPMODE_1BPP                   (0x0 << 2)
+#define WINCON2_BPPMODE_2BPP                   (0x1 << 2)
+#define WINCON2_BPPMODE_4BPP                   (0x2 << 2)
+#define WINCON2_BPPMODE_8BPP_1232              (0x4 << 2)
+#define WINCON2_BPPMODE_16BPP_565              (0x5 << 2)
+#define WINCON2_BPPMODE_16BPP_A1555            (0x6 << 2)
+#define WINCON2_BPPMODE_16BPP_I1555            (0x7 << 2)
+#define WINCON2_BPPMODE_18BPP_666              (0x8 << 2)
+#define WINCON2_BPPMODE_18BPP_A1665            (0x9 << 2)
+#define WINCON2_BPPMODE_19BPP_A1666            (0xa << 2)
+#define WINCON2_BPPMODE_24BPP_888              (0xb << 2)
+#define WINCON2_BPPMODE_24BPP_A1887            (0xc << 2)
+#define WINCON2_BPPMODE_25BPP_A1888            (0xd << 2)
+#define WINCON2_BPPMODE_28BPP_A4888            (0xd << 2)
+
+#define WINCON3_BLD_PIX                                (1 << 6)
+
+#define WINCON3_ALPHA_SEL                      (1 << 1)
+#define WINCON3_BPPMODE_MASK                   (0xf << 2)
+#define WINCON3_BPPMODE_SHIFT                  (2)
+#define WINCON3_BPPMODE_1BPP                   (0x0 << 2)
+#define WINCON3_BPPMODE_2BPP                   (0x1 << 2)
+#define WINCON3_BPPMODE_4BPP                   (0x2 << 2)
+#define WINCON3_BPPMODE_16BPP_565              (0x5 << 2)
+#define WINCON3_BPPMODE_16BPP_A1555            (0x6 << 2)
+#define WINCON3_BPPMODE_16BPP_I1555            (0x7 << 2)
+#define WINCON3_BPPMODE_18BPP_666              (0x8 << 2)
+#define WINCON3_BPPMODE_18BPP_A1665            (0x9 << 2)
+#define WINCON3_BPPMODE_19BPP_A1666            (0xa << 2)
+#define WINCON3_BPPMODE_24BPP_888              (0xb << 2)
+#define WINCON3_BPPMODE_24BPP_A1887            (0xc << 2)
+#define WINCON3_BPPMODE_25BPP_A1888            (0xd << 2)
+#define WINCON3_BPPMODE_28BPP_A4888            (0xd << 2)
+
+#define VIDINTCON0_FIFIOSEL_WINDOW2            (0x10 << 5)
+#define VIDINTCON0_FIFIOSEL_WINDOW3            (0x20 << 5)
+#define VIDINTCON0_FIFIOSEL_WINDOW4            (0x40 << 5)
+
+#define DITHMODE                               (0x170)
+#define WINxMAP(_win)                          (0x180 + ((_win) * 4))
+
+
+#define DITHMODE_R_POS_MASK                    (0x3 << 5)
+#define DITHMODE_R_POS_SHIFT                   (5)
+#define DITHMODE_R_POS_8BIT                    (0x0 << 5)
+#define DITHMODE_R_POS_6BIT                    (0x1 << 5)
+#define DITHMODE_R_POS_5BIT                    (0x2 << 5)
+
+#define DITHMODE_G_POS_MASK                    (0x3 << 3)
+#define DITHMODE_G_POS_SHIFT                   (3)
+#define DITHMODE_G_POS_8BIT                    (0x0 << 3)
+#define DITHMODE_G_POS_6BIT                    (0x1 << 3)
+#define DITHMODE_G_POS_5BIT                    (0x2 << 3)
+
+#define DITHMODE_B_POS_MASK                    (0x3 << 1)
+#define DITHMODE_B_POS_SHIFT                   (1)
+#define DITHMODE_B_POS_8BIT                    (0x0 << 1)
+#define DITHMODE_B_POS_6BIT                    (0x1 << 1)
+#define DITHMODE_B_POS_5BIT                    (0x2 << 1)
+
+#define DITHMODE_DITH_EN                       (1 << 0)
+
+#define WPALCON                                        (0x1A0)
+
+/* Palette control */
+/* Note for S5PC100: you can still use those macros on WPALCON (aka WPALCON_L),
+ * but make sure that WPALCON_H W2PAL-W4PAL entries are zeroed out */
+#define WPALCON_W4PAL_16BPP_A555               (1 << 8)
+#define WPALCON_W3PAL_16BPP_A555               (1 << 7)
+#define WPALCON_W2PAL_16BPP_A555               (1 << 6)
+
+
+/* system specific implementation code for palette sizes, and other
+ * information that changes depending on which architecture is being
+ * compiled.
+*/
+
+/* return true if window _win has OSD register D */
+#define s3c_fb_has_osd_d(_win) ((_win) != 4 && (_win) != 0)
+
+static inline unsigned int s3c_fb_win_pal_size(unsigned int win)
+{
+       if (win < 2)
+               return 256;
+       if (win < 4)
+               return 16;
+       if (win == 4)
+               return 4;
+
+       BUG();  /* shouldn't get here */
+}
+
+static inline int s3c_fb_validate_win_bpp(unsigned int win, unsigned int bpp)
+{
+       /* all windows can do 1/2 bpp */
+
+       if ((bpp == 25 || bpp == 19) && win == 0)
+               return 0;       /* win 0 does not have 19 or 25bpp modes */
+
+       if (bpp == 4 && win == 4)
+               return 0;
+
+       if (bpp == 8 && (win >= 3))
+               return 0;       /* win 3/4 cannot do 8bpp in any mode */
+
+       return 1;
+}
+
+static inline int s3c_fb_pal_is16(unsigned int window)
+{
+       return window > 1;
+}
+
+struct s3c_fb_palette {
+       struct fb_bitfield      r;
+       struct fb_bitfield      g;
+       struct fb_bitfield      b;
+       struct fb_bitfield      a;
+};
+
+static inline void s3c_fb_init_palette(unsigned int window,
+                                      struct s3c_fb_palette *palette)
+{
+       if (window < 2) {
+               /* Windows 0/1 are 8/8/8 or A/8/8/8 */
+               palette->r.offset = 16;
+               palette->r.length = 8;
+               palette->g.offset = 8;
+               palette->g.length = 8;
+               palette->b.offset = 0;
+               palette->b.length = 8;
+       } else {
+               /* currently we assume RGB 5/6/5 */
+               palette->r.offset = 11;
+               palette->r.length = 5;
+               palette->g.offset = 5;
+               palette->g.length = 6;
+               palette->b.offset = 0;
+               palette->b.length = 5;
+       }
+}
+
+/* Notes on per-window bpp settings
+ *
+ * Value       Win0     Win1     Win2     Win3     Win 4
+ * 0000                1(P)     1(P)     1(P)     1(P)     1(P)
+ * 0001                2(P)     2(P)     2(P)     2(P)     2(P)
+ * 0010                4(P)     4(P)     4(P)     4(P)     -none-
+ * 0011                8(P)     8(P)     -none-   -none-   -none-
+ * 0100                -none-   8(A232)  8(A232)  -none-   -none-
+ * 0101                16(565)  16(565)  16(565)  16(565)   16(565)
+ * 0110                -none-   16(A555) 16(A555) 16(A555)  16(A555)
+ * 0111                16(I555) 16(I565) 16(I555) 16(I555)  16(I555)
+ * 1000                18(666)  18(666)  18(666)  18(666)   18(666)
+ * 1001                -none-   18(A665) 18(A665) 18(A665)  16(A665)
+ * 1010                -none-   19(A666) 19(A666) 19(A666)  19(A666)
+ * 1011                24(888)  24(888)  24(888)  24(888)   24(888)
+ * 1100                -none-   24(A887) 24(A887) 24(A887)  24(A887)
+ * 1101                -none-   25(A888) 25(A888) 25(A888)  25(A888)
+ * 1110                -none-   -none-   -none-   -none-    -none-
+ * 1111                -none-   -none-   -none-   -none-    -none-
+*/
index b2caa4b..238efea 100644 (file)
@@ -1,7 +1,7 @@
 /* arch/arm/mach-s3c2410/include/mach/regs-nand.h
  *
- * Copyright (c) 2004,2005 Simtec Electronics <linux@simtec.co.uk>
- *                   http://www.simtec.co.uk/products/SWLINUX/
+ * Copyright (c) 2004-2005 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
index 07659da..abf2fbc 100644 (file)
@@ -67,6 +67,8 @@
 #define S3C2412_IISMOD_BCLK_MASK       (3 << 1)
 #define S3C2412_IISMOD_8BIT            (1 << 0)
 
+#define S3C64XX_IISMOD_CDCLKCON                (1 << 12)
+
 #define S3C2412_IISPSR_PSREN           (1 << 15)
 
 #define S3C2412_IISFIC_TXFLUSH         (1 << 15)
index 66af75a..85d8904 100644 (file)
@@ -6,7 +6,7 @@
  *
  *  Copyright (C) 2002 Shane Nay (shane@minirl.com)
  *
- *  Additional defines, (c) 2003 Simtec Electronics (linux@simtec.co.uk)
+ *  Additional defines, Copyright 2003 Simtec Electronics (linux@simtec.co.uk)
  *
  *  Adapted from:
  *
index f615308..5319867 100644 (file)
@@ -57,6 +57,7 @@ struct s3c_sdhci_platdata {
  */
 extern void s3c_sdhci0_set_platdata(struct s3c_sdhci_platdata *pd);
 extern void s3c_sdhci1_set_platdata(struct s3c_sdhci_platdata *pd);
+extern void s3c_sdhci2_set_platdata(struct s3c_sdhci_platdata *pd);
 
 /* Default platform data, exported so that per-cpu initialisation can
  * set the correct one when there are more than one cpu type selected.
@@ -64,11 +65,16 @@ extern void s3c_sdhci1_set_platdata(struct s3c_sdhci_platdata *pd);
 
 extern struct s3c_sdhci_platdata s3c_hsmmc0_def_platdata;
 extern struct s3c_sdhci_platdata s3c_hsmmc1_def_platdata;
+extern struct s3c_sdhci_platdata s3c_hsmmc2_def_platdata;
 
 /* Helper function availablity */
 
 extern void s3c64xx_setup_sdhci0_cfg_gpio(struct platform_device *, int w);
 extern void s3c64xx_setup_sdhci1_cfg_gpio(struct platform_device *, int w);
+extern void s5pc100_setup_sdhci0_cfg_gpio(struct platform_device *, int w);
+extern void s5pc100_setup_sdhci1_cfg_gpio(struct platform_device *, int w);
+extern void s5pc100_setup_sdhci2_cfg_gpio(struct platform_device *, int w);
+extern void s3c64xx_setup_sdhci2_cfg_gpio(struct platform_device *, int w);
 
 /* S3C6400 SDHCI setup */
 
@@ -103,6 +109,17 @@ static inline void s3c6400_default_sdhci1(void)
 static inline void s3c6400_default_sdhci1(void) { }
 #endif /* CONFIG_S3C_DEV_HSMMC1 */
 
+#ifdef CONFIG_S3C_DEV_HSMMC2
+static inline void s3c6400_default_sdhci2(void)
+{
+       s3c_hsmmc2_def_platdata.clocks = s3c6400_hsmmc_clksrcs;
+       s3c_hsmmc2_def_platdata.cfg_gpio = s3c64xx_setup_sdhci2_cfg_gpio;
+       s3c_hsmmc2_def_platdata.cfg_card = s3c6400_setup_sdhci_cfg_card;
+}
+#else
+static inline void s3c6400_default_sdhci2(void) { }
+#endif /* CONFIG_S3C_DEV_HSMMC2 */
+
 #else
 static inline void s3c6400_default_sdhci0(void) { }
 static inline void s3c6400_default_sdhci1(void) { }
@@ -140,9 +157,70 @@ static inline void s3c6410_default_sdhci1(void)
 static inline void s3c6410_default_sdhci1(void) { }
 #endif /* CONFIG_S3C_DEV_HSMMC1 */
 
+#ifdef CONFIG_S3C_DEV_HSMMC2
+static inline void s3c6410_default_sdhci2(void)
+{
+       s3c_hsmmc2_def_platdata.clocks = s3c6410_hsmmc_clksrcs;
+       s3c_hsmmc2_def_platdata.cfg_gpio = s3c64xx_setup_sdhci2_cfg_gpio;
+       s3c_hsmmc2_def_platdata.cfg_card = s3c6410_setup_sdhci0_cfg_card;
+}
+#else
+static inline void s3c6410_default_sdhci2(void) { }
+#endif /* CONFIG_S3C_DEV_HSMMC2 */
+
 #else
 static inline void s3c6410_default_sdhci0(void) { }
 static inline void s3c6410_default_sdhci1(void) { }
 #endif /* CONFIG_S3C6410_SETUP_SDHCI */
 
+/* S5PC100 SDHCI setup */
+
+#ifdef CONFIG_S5PC100_SETUP_SDHCI
+extern char *s5pc100_hsmmc_clksrcs[4];
+
+extern void s5pc100_setup_sdhci0_cfg_card(struct platform_device *dev,
+                                          void __iomem *r,
+                                          struct mmc_ios *ios,
+                                          struct mmc_card *card);
+
+#ifdef CONFIG_S3C_DEV_HSMMC
+static inline void s5pc100_default_sdhci0(void)
+{
+       s3c_hsmmc0_def_platdata.clocks = s5pc100_hsmmc_clksrcs;
+       s3c_hsmmc0_def_platdata.cfg_gpio = s5pc100_setup_sdhci0_cfg_gpio;
+       s3c_hsmmc0_def_platdata.cfg_card = s5pc100_setup_sdhci0_cfg_card;
+}
+#else
+static inline void s5pc100_default_sdhci0(void) { }
+#endif /* CONFIG_S3C_DEV_HSMMC */
+
+#ifdef CONFIG_S3C_DEV_HSMMC1
+static inline void s5pc100_default_sdhci1(void)
+{
+       s3c_hsmmc1_def_platdata.clocks = s5pc100_hsmmc_clksrcs;
+       s3c_hsmmc1_def_platdata.cfg_gpio = s5pc100_setup_sdhci1_cfg_gpio;
+       s3c_hsmmc1_def_platdata.cfg_card = s5pc100_setup_sdhci0_cfg_card;
+}
+#else
+static inline void s5pc100_default_sdhci1(void) { }
+#endif /* CONFIG_S3C_DEV_HSMMC1 */
+
+#ifdef CONFIG_S3C_DEV_HSMMC2
+static inline void s5pc100_default_sdhci2(void)
+{
+       s3c_hsmmc2_def_platdata.clocks = s5pc100_hsmmc_clksrcs;
+       s3c_hsmmc2_def_platdata.cfg_gpio = s5pc100_setup_sdhci2_cfg_gpio;
+       s3c_hsmmc2_def_platdata.cfg_card = s5pc100_setup_sdhci0_cfg_card;
+}
+#else
+static inline void s5pc100_default_sdhci2(void) { }
+#endif /* CONFIG_S3C_DEV_HSMMC1 */
+
+
+#else
+static inline void s5pc100_default_sdhci0(void) { }
+static inline void s5pc100_default_sdhci1(void) { }
+static inline void s5pc100_default_sdhci2(void) { }
+#endif /* CONFIG_S5PC100_SETUP_SDHCI */
+
 #endif /* __PLAT_S3C_SDHCI_H */
index 39f2555..8eb1f43 100644 (file)
@@ -1,7 +1,7 @@
 /* linux/arch/arm/plat-s3c/pm-check.c
  *  originally in linux/arch/arm/plat-s3c24xx/pm.c
  *
- * Copyright (c) 2004,2006,2008 Simtec Electronics
+ * Copyright (c) 2004-2008 Simtec Electronics
  *     http://armlinux.simtec.co.uk
  *     Ben Dooks <ben@simtec.co.uk>
  *
index 8d97db2..7674706 100644 (file)
@@ -1,7 +1,7 @@
 /* linux/arch/arm/plat-s3c/pm.c
  *
  * Copyright 2008 Openmoko, Inc.
- * Copyright 2004,2006,2008 Simtec Electronics
+ * Copyright 2004-2008 Simtec Electronics
  *     Ben Dooks <ben@simtec.co.uk>
  *     http://armlinux.simtec.co.uk/
  *
index 9c7aca4..20fbf93 100644 (file)
@@ -178,4 +178,11 @@ config MACH_SMDK
        help
          Common machine code for SMDK2410 and SMDK2440
 
+config S3C24XX_SIMTEC_AUDIO
+       bool
+       depends on (ARCH_BAST || MACH_VR1000 || MACH_OSIRIS || MACH_ANUBIS)
+       default y
+       help
+         Add audio devices for common Simtec S3C24XX boards
+
 endif
index 7780d2d..5dee8c1 100644 (file)
@@ -55,3 +55,4 @@ obj-$(CONFIG_S3C24XX_SPI_BUS1_GPD8_GPD9_GPD10)         += spi-bus1-gpd8_9_10.o
 # machine common support
 
 obj-$(CONFIG_MACH_SMDK)                += common-smdk.o
+obj-$(CONFIG_S3C24XX_SIMTEC_AUDIO)     += simtec-audio.o
index 0afb217..ac061a1 100644 (file)
@@ -1,6 +1,6 @@
 /* linux/arch/arm/plat-s3c24xx/clock-dclk.c
  *
- * Copyright (c) 2004,2008 Simtec Electronics
+ * Copyright (c) 2004-2008 Simtec Electronics
  *     Ben Dooks <ben@simtec.co.uk>
  *     http://armlinux.simtec.co.uk/
  *
index aa11986..9e0e20a 100644 (file)
@@ -198,7 +198,7 @@ void __init smdk_machine_init(void)
        if (machine_is_smdk2443())
                smdk_nand_info.twrph0 = 50;
 
-       s3c_device_nand.dev.platform_data = &smdk_nand_info;
+       s3c_nand_set_platdata(&smdk_nand_info);
 
        platform_add_devices(smdk_devs, ARRAY_SIZE(smdk_devs));
 
index 4f1b789..2d42efb 100644 (file)
@@ -1,6 +1,6 @@
 /* linux/arch/arm/plat-s3c24xx/cpu-freq.c
  *
- * Copyright (c) 2006,2007,2008 Simtec Electronics
+ * Copyright (c) 2006-2008 Simtec Electronics
  *     http://armlinux.simtec.co.uk/
  *     Ben Dooks <ben@simtec.co.uk>
  *
index f046f8c..f65192d 100644 (file)
@@ -1,6 +1,6 @@
 /* linux/arch/arm/plat-s3c24xx/dma.c
  *
- * Copyright (c) 2003-2005,2006 Simtec Electronics
+ * Copyright 2003-2006 Simtec Electronics
  *     Ben Dooks <ben@simtec.co.uk>
  *
  * S3C2410 DMA core
@@ -1310,7 +1310,7 @@ int __init s3c24xx_dma_init(unsigned int channels, unsigned int irq,
        int channel;
        int ret;
 
-       printk("S3C24XX DMA Driver, (c) 2003-2004,2006 Simtec Electronics\n");
+       printk("S3C24XX DMA Driver, Copyright 2003-2006 Simtec Electronics\n");
 
        dma_channels = channels;
 
index c776120..33d421d 100644 (file)
@@ -1,6 +1,6 @@
 /* arch/arm/plat-s3c/include/plat/cpu-freq.h
  *
- * Copyright (c) 2006,2007,2009 Simtec Electronics
+ * Copyright (c) 2006-2009 Simtec Electronics
  *     http://armlinux.simtec.co.uk/
  *     Ben Dooks <ben@simtec.co.uk>
  *
index c2cef61..36aaa10 100644 (file)
@@ -1,6 +1,31 @@
 #ifndef _ARCH_MCI_H
 #define _ARCH_MCI_H
 
+/**
+ * struct s3c24xx_mci_pdata - sd/mmc controller platform data
+ * @no_wprotect: Set this to indicate there is no write-protect switch.
+ * @no_detect: Set this if there is no detect switch.
+ * @wprotect_invert: Invert the default sense of the write protect switch.
+ * @detect_invert: Invert the default sense of the write protect switch.
+ * @use_dma: Set to allow the use of DMA.
+ * @gpio_detect: GPIO number for the card detect line.
+ * @gpio_wprotect: GPIO number for the write protect line.
+ * @ocr_avail: The mask of the available power states, non-zero to use.
+ * @set_power: Callback to control the power mode.
+ *
+ * The @gpio_detect is used for card detection when @no_wprotect is unset,
+ * and the default sense is that 0 returned from gpio_get_value() means
+ * that a card is inserted. If @detect_invert is set, then the value from
+ * gpio_get_value() is inverted, which makes 1 mean card inserted.
+ *
+ * The driver will use @gpio_wprotect to signal whether the card is write
+ * protected if @no_wprotect is not set. A 0 returned from gpio_get_value()
+ * means the card is read/write, and 1 means read-only. The @wprotect_invert
+ * will invert the value returned from gpio_get_value().
+ *
+ * Card power is set by @ocr_availa, using MCC_VDD_ constants if it is set
+ * to a non-zero value, otherwise the default of 3.2-3.4V is used.
+ */
 struct s3c24xx_mci_pdata {
        unsigned int    no_wprotect : 1;
        unsigned int    no_detect : 1;
index 3bc0a21..1b0f4c3 100644 (file)
@@ -1,6 +1,6 @@
 /* arch/arm/mach-s3c2410/include/mach/dma.h
  *
- * Copyright (C) 2003,2004,2006 Simtec Electronics
+ * Copyright (C) 2003-2006 Simtec Electronics
  *     Ben Dooks <ben@simtec.co.uk>
  *
  * Samsung S3C24XX DMA support
index b7acf1a..ea8dea3 100644 (file)
@@ -1,6 +1,6 @@
 /* linux/arch/arm/plat-s3c24xx/irq-om.c
  *
- * Copyright (c) 2003,2004 Simtec Electronics
+ * Copyright (c) 2003-2004 Simtec Electronics
  *     Ben Dooks <ben@simtec.co.uk>
  *     http://armlinux.simtec.co.uk/
  *
index d02f5f0..ef0f521 100644 (file)
@@ -1,6 +1,6 @@
 /* linux/arch/arm/plat-s3c24xx/irq.c
  *
- * Copyright (c) 2003,2004 Simtec Electronics 
+ * Copyright (c) 2003-2004 Simtec Electronics
  *     Ben Dooks <ben@simtec.co.uk>
  *
  * This program is free software; you can redistribute it and/or modify
index da0d321..663b280 100644 (file)
@@ -1,6 +1,6 @@
 /* linux/arch/arm/plat-s3c24xx/pm-simtec.c
  *
- * Copyright (c) 2004 Simtec Electronics
+ * Copyright 2004 Simtec Electronics
  *     Ben Dooks <ben@simtec.co.uk>
  *
  * http://armlinux.simtec.co.uk/
@@ -35,7 +35,7 @@
 
 #include <plat/pm.h>
 
-#define COPYRIGHT ", (c) 2005 Simtec Electronics"
+#define COPYRIGHT ", Copyright 2005 Simtec Electronics"
 
 /* pm_simtec_init
  *
index 56e5253..3620dd2 100644 (file)
@@ -1,6 +1,6 @@
 /* linux/arch/arm/plat-s3c24xx/pm.c
  *
- * Copyright (c) 2004,2006 Simtec Electronics
+ * Copyright (c) 2004-2006 Simtec Electronics
  *     Ben Dooks <ben@simtec.co.uk>
  *
  * S3C24XX Power Manager (Suspend-To-RAM) support
index d0a3a14..963fb0b 100644 (file)
@@ -1,6 +1,6 @@
 /* linux/arch/arm/plat-s3c24xx/s3c2410-iotiming.c
  *
- * Copyright (c) 2006,2008,2009 Simtec Electronics
+ * Copyright (c) 2006-2009 Simtec Electronics
  *     http://armlinux.simtec.co.uk/
  *     Ben Dooks <ben@simtec.co.uk>
  *
index fd45e47..24993dc 100644 (file)
@@ -1,6 +1,6 @@
 /* linux/arch/arm/plat-s3c24xx/s3c2412-iotiming.c
  *
- * Copyright (c) 2006,2008 Simtec Electronics
+ * Copyright (c) 2006-2008 Simtec Electronics
  *     http://armlinux.simtec.co.uk/
  *     Ben Dooks <ben@simtec.co.uk>
  *
index ae2e6c6..976002f 100644 (file)
@@ -1,6 +1,6 @@
 /* linux/arch/arm/plat-s3c24xx/s3c2440-cpufreq.c
  *
- * Copyright (c) 2006,2008,2009 Simtec Electronics
+ * Copyright (c) 2006-2009 Simtec Electronics
  *     http://armlinux.simtec.co.uk/
  *     Ben Dooks <ben@simtec.co.uk>
  *     Vincent Sanders <vince@simtec.co.uk>
index ff9443b..49f6503 100644 (file)
@@ -1,6 +1,6 @@
 /* arch/arm/plat-s3c24xx/s3c2440-pll-12000000.c
  *
- * Copyright (c) 2006,2007 Simtec Electronics
+ * Copyright (c) 2006-2007 Simtec Electronics
  *     http://armlinux.simtec.co.uk/
  *     Ben Dooks <ben@simtec.co.uk>
  *     Vincent Sanders <vince@arm.linux.org.uk>
index dde41f1..7937109 100644 (file)
@@ -1,6 +1,6 @@
 /* linux/arch/arm/plat-s3c24xx/s3c24xx-clock.c
  *
- * Copyright (c) 2004-2005,2008 Simtec Electronics
+ * Copyright (c) 2004-2008 Simtec Electronics
  *     http://armlinux.simtec.co.uk/
  *     Ben Dooks <ben@simtec.co.uk>
  *
index 0902afd..a75c0c2 100644 (file)
@@ -1,6 +1,6 @@
 /* linux/arch/arm/plat-s3c24xx/s3c244x-irq.c
  *
- * Copyright (c) 2003,2004 Simtec Electronics
+ * Copyright (c) 2003-2004 Simtec Electronics
  *     Ben Dooks <ben@simtec.co.uk>
  *
  * This program is free software; you can redistribute it and/or modify
diff --git a/arch/arm/plat-s3c24xx/simtec-audio.c b/arch/arm/plat-s3c24xx/simtec-audio.c
new file mode 100644 (file)
index 0000000..6bc832e
--- /dev/null
@@ -0,0 +1,77 @@
+/* linux/arch/arm/plat-s3c24xx/simtec-audio.c
+ *
+ * Copyright (c) 2009 Simtec Electronics
+ *     http://armlinux.simtec.co.uk/
+ *     Ben Dooks <ben@simtec.co.uk>
+ *
+ * Audio setup for various Simtec S3C24XX implementations
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/io.h>
+
+#include <mach/bast-map.h>
+#include <mach/bast-irq.h>
+#include <mach/bast-cpld.h>
+
+#include <mach/hardware.h>
+#include <mach/regs-gpio.h>
+
+#include <plat/audio-simtec.h>
+#include <plat/devs.h>
+
+/* platform ops for audio */
+
+static void simtec_audio_startup_lrroute(void)
+{
+       unsigned int tmp;
+       unsigned long flags;
+
+       local_irq_save(flags);
+
+       tmp = __raw_readb(BAST_VA_CTRL1);
+       tmp &= ~BAST_CPLD_CTRL1_LRMASK;
+       tmp |= BAST_CPLD_CTRL1_LRCDAC;
+       __raw_writeb(tmp, BAST_VA_CTRL1);
+
+       local_irq_restore(flags);
+}
+
+static struct s3c24xx_audio_simtec_pdata simtec_audio_platdata;
+static char our_name[32];
+
+static struct platform_device simtec_audio_dev = {
+       .name   = our_name,
+       .id     = -1,
+       .dev    = {
+               .parent         = &s3c_device_iis.dev,
+               .platform_data  = &simtec_audio_platdata,
+       },
+};
+
+int __init simtec_audio_add(const char *name, bool has_lr_routing,
+                           struct s3c24xx_audio_simtec_pdata *spd)
+{
+       if (!name)
+               name = "tlv320aic23";
+
+       snprintf(our_name, sizeof(our_name)-1, "s3c24xx-simtec-%s", name);
+
+       /* copy platform data so the source can be __initdata */
+       if (spd)
+               simtec_audio_platdata = *spd;
+
+       if (has_lr_routing)
+               simtec_audio_platdata.startup = simtec_audio_startup_lrroute;
+
+       platform_device_register(&s3c_device_iis);
+       platform_device_register(&simtec_audio_dev);
+       return 0;
+}
index b1fdd83..49796d2 100644 (file)
@@ -107,6 +107,11 @@ static struct map_desc s3c_iodesc[] __initdata = {
                .pfn            = __phys_to_pfn(S3C64XX_PA_WATCHDOG),
                .length         = SZ_4K,
                .type           = MT_DEVICE,
+       }, {
+               .virtual        = (unsigned long)S3C_VA_USB_HSPHY,
+               .pfn            = __phys_to_pfn(S3C64XX_PA_USB_HSPHY),
+               .length         = SZ_1K,
+               .type           = MT_DEVICE,
        },
 };
 
index e6e0843..74c0e83 100644 (file)
@@ -19,6 +19,7 @@
 
 static struct clk *armclk;
 static struct regulator *vddarm;
+static unsigned long regulator_latency;
 
 #ifdef CONFIG_CPU_S3C6410
 struct s3c64xx_dvfs {
@@ -27,11 +28,10 @@ struct s3c64xx_dvfs {
 };
 
 static struct s3c64xx_dvfs s3c64xx_dvfs_table[] = {
-       [0] = { 1000000, 1000000 },
-       [1] = { 1000000, 1050000 },
-       [2] = { 1050000, 1100000 },
-       [3] = { 1050000, 1150000 },
-       [4] = { 1250000, 1350000 },
+       [0] = { 1000000, 1150000 },
+       [1] = { 1050000, 1150000 },
+       [2] = { 1100000, 1150000 },
+       [3] = { 1200000, 1350000 },
 };
 
 static struct cpufreq_frequency_table s3c64xx_freq_table[] = {
@@ -41,9 +41,9 @@ static struct cpufreq_frequency_table s3c64xx_freq_table[] = {
        { 1, 266000 },
        { 2, 333000 },
        { 2, 400000 },
-       { 3, 532000 },
-       { 3, 533000 },
-       { 4, 667000 },
+       { 2, 532000 },
+       { 2, 533000 },
+       { 3, 667000 },
        { 0, CPUFREQ_TABLE_END },
 };
 #endif
@@ -141,7 +141,7 @@ err:
 }
 
 #ifdef CONFIG_REGULATOR
-static void __init s3c64xx_cpufreq_constrain_voltages(void)
+static void __init s3c64xx_cpufreq_config_regulator(void)
 {
        int count, v, i, found;
        struct cpufreq_frequency_table *freq;
@@ -150,11 +150,10 @@ static void __init s3c64xx_cpufreq_constrain_voltages(void)
        count = regulator_count_voltages(vddarm);
        if (count < 0) {
                pr_err("cpufreq: Unable to check supported voltages\n");
-               return;
        }
 
        freq = s3c64xx_freq_table;
-       while (freq->frequency != CPUFREQ_TABLE_END) {
+       while (count > 0 && freq->frequency != CPUFREQ_TABLE_END) {
                if (freq->frequency == CPUFREQ_ENTRY_INVALID)
                        continue;
 
@@ -175,6 +174,10 @@ static void __init s3c64xx_cpufreq_constrain_voltages(void)
 
                freq++;
        }
+
+       /* Guess based on having to do an I2C/SPI write; in future we
+        * will be able to query the regulator performance here. */
+       regulator_latency = 1 * 1000 * 1000;
 }
 #endif
 
@@ -206,7 +209,7 @@ static int __init s3c64xx_cpufreq_driver_init(struct cpufreq_policy *policy)
                pr_err("cpufreq: Only frequency scaling available\n");
                vddarm = NULL;
        } else {
-               s3c64xx_cpufreq_constrain_voltages();
+               s3c64xx_cpufreq_config_regulator();
        }
 #endif
 
@@ -217,8 +220,11 @@ static int __init s3c64xx_cpufreq_driver_init(struct cpufreq_policy *policy)
                /* Check for frequencies we can generate */
                r = clk_round_rate(armclk, freq->frequency * 1000);
                r /= 1000;
-               if (r != freq->frequency)
+               if (r != freq->frequency) {
+                       pr_debug("cpufreq: %dkHz unsupported by clock\n",
+                                freq->frequency);
                        freq->frequency = CPUFREQ_ENTRY_INVALID;
+               }
 
                /* If we have no regulator then assume startup
                 * frequency is the maximum we can support. */
@@ -230,9 +236,11 @@ static int __init s3c64xx_cpufreq_driver_init(struct cpufreq_policy *policy)
 
        policy->cur = clk_get_rate(armclk) / 1000;
 
-       /* Pick a conservative guess in ns: we'll need ~1 I2C/SPI
-        * write plus clock reprogramming. */
-       policy->cpuinfo.transition_latency = 2 * 1000 * 1000;
+       /* Datasheet says PLL stabalisation time (if we were to use
+        * the PLLs, which we don't currently) is ~300us worst case,
+        * but add some fudge.
+        */
+       policy->cpuinfo.transition_latency = (500 * 1000) + regulator_latency;
 
        ret = cpufreq_frequency_table_cpuinfo(policy, s3c64xx_freq_table);
        if (ret != 0) {
index 1322beb..a21a88f 100644 (file)
 
 #include <mach/irqs.h>
 #include <mach/map.h>
+#include <mach/dma.h>
+#include <mach/gpio.h>
 
 #include <plat/devs.h>
-
+#include <plat/audio.h>
+#include <plat/gpio-bank-d.h>
+#include <plat/gpio-bank-e.h>
+#include <plat/gpio-cfg.h>
 
 static struct resource s3c64xx_iis0_resource[] = {
        [0] = {
@@ -66,3 +71,97 @@ struct platform_device s3c64xx_device_iisv4 = {
        .resource         = s3c64xx_iisv4_resource,
 };
 EXPORT_SYMBOL(s3c64xx_device_iisv4);
+
+
+/* PCM Controller platform_devices */
+
+static int s3c64xx_pcm_cfg_gpio(struct platform_device *pdev)
+{
+       switch (pdev->id) {
+       case 0:
+               s3c_gpio_cfgpin(S3C64XX_GPD(0), S3C64XX_GPD0_PCM0_SCLK);
+               s3c_gpio_cfgpin(S3C64XX_GPD(1), S3C64XX_GPD1_PCM0_EXTCLK);
+               s3c_gpio_cfgpin(S3C64XX_GPD(2), S3C64XX_GPD2_PCM0_FSYNC);
+               s3c_gpio_cfgpin(S3C64XX_GPD(3), S3C64XX_GPD3_PCM0_SIN);
+               s3c_gpio_cfgpin(S3C64XX_GPD(4), S3C64XX_GPD4_PCM0_SOUT);
+               break;
+       case 1:
+               s3c_gpio_cfgpin(S3C64XX_GPE(0), S3C64XX_GPE0_PCM1_SCLK);
+               s3c_gpio_cfgpin(S3C64XX_GPE(1), S3C64XX_GPE1_PCM1_EXTCLK);
+               s3c_gpio_cfgpin(S3C64XX_GPE(2), S3C64XX_GPE2_PCM1_FSYNC);
+               s3c_gpio_cfgpin(S3C64XX_GPE(3), S3C64XX_GPE3_PCM1_SIN);
+               s3c_gpio_cfgpin(S3C64XX_GPE(4), S3C64XX_GPE4_PCM1_SOUT);
+               break;
+       default:
+               printk(KERN_DEBUG "Invalid PCM Controller number!");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static struct resource s3c64xx_pcm0_resource[] = {
+       [0] = {
+               .start = S3C64XX_PA_PCM0,
+               .end   = S3C64XX_PA_PCM0 + 0x100 - 1,
+               .flags = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start = DMACH_PCM0_TX,
+               .end   = DMACH_PCM0_TX,
+               .flags = IORESOURCE_DMA,
+       },
+       [2] = {
+               .start = DMACH_PCM0_RX,
+               .end   = DMACH_PCM0_RX,
+               .flags = IORESOURCE_DMA,
+       },
+};
+
+static struct s3c_audio_pdata s3c_pcm0_pdata = {
+       .cfg_gpio = s3c64xx_pcm_cfg_gpio,
+};
+
+struct platform_device s3c64xx_device_pcm0 = {
+       .name             = "samsung-pcm",
+       .id               = 0,
+       .num_resources    = ARRAY_SIZE(s3c64xx_pcm0_resource),
+       .resource         = s3c64xx_pcm0_resource,
+       .dev = {
+               .platform_data = &s3c_pcm0_pdata,
+       },
+};
+EXPORT_SYMBOL(s3c64xx_device_pcm0);
+
+static struct resource s3c64xx_pcm1_resource[] = {
+       [0] = {
+               .start = S3C64XX_PA_PCM1,
+               .end   = S3C64XX_PA_PCM1 + 0x100 - 1,
+               .flags = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start = DMACH_PCM1_TX,
+               .end   = DMACH_PCM1_TX,
+               .flags = IORESOURCE_DMA,
+       },
+       [2] = {
+               .start = DMACH_PCM1_RX,
+               .end   = DMACH_PCM1_RX,
+               .flags = IORESOURCE_DMA,
+       },
+};
+
+static struct s3c_audio_pdata s3c_pcm1_pdata = {
+       .cfg_gpio = s3c64xx_pcm_cfg_gpio,
+};
+
+struct platform_device s3c64xx_device_pcm1 = {
+       .name             = "samsung-pcm",
+       .id               = 1,
+       .num_resources    = ARRAY_SIZE(s3c64xx_pcm1_resource),
+       .resource         = s3c64xx_pcm1_resource,
+       .dev = {
+               .platform_data = &s3c_pcm1_pdata,
+       },
+};
+EXPORT_SYMBOL(s3c64xx_device_pcm1);
index 9285929..7785604 100644 (file)
@@ -213,6 +213,11 @@ static struct s3c_gpio_cfg gpio_4bit_cfg_eint0011 = {
        .get_pull       = s3c_gpio_getpull_updown,
 };
 
+int s3c64xx_gpio2int_gpm(struct gpio_chip *chip, unsigned pin)
+{
+       return pin < 5 ? IRQ_EINT(23) + pin : -ENXIO;
+}
+
 static struct s3c_gpio_chip gpio_4bit[] = {
        {
                .base   = S3C64XX_GPA_BASE,
@@ -269,10 +274,16 @@ static struct s3c_gpio_chip gpio_4bit[] = {
                        .base   = S3C64XX_GPM(0),
                        .ngpio  = S3C64XX_GPIO_M_NR,
                        .label  = "GPM",
+                       .to_irq = s3c64xx_gpio2int_gpm,
                },
        },
 };
 
+int s3c64xx_gpio2int_gpl(struct gpio_chip *chip, unsigned pin)
+{
+       return pin >= 8 ? IRQ_EINT(16) + pin - 8 : -ENXIO;
+}
+
 static struct s3c_gpio_chip gpio_4bit2[] = {
        {
                .base   = S3C64XX_GPH_BASE + 0x4,
@@ -297,6 +308,7 @@ static struct s3c_gpio_chip gpio_4bit2[] = {
                        .base   = S3C64XX_GPL(0),
                        .ngpio  = S3C64XX_GPIO_L_NR,
                        .label  = "GPL",
+                       .to_irq = s3c64xx_gpio2int_gpl,
                },
        },
 };
index c47daf7..e22b49f 100644 (file)
 
 #define S3C64XX_GPC4_SPI_MISO1         (0x02 << 16)
 #define S3C64XX_GPC4_MMC2_CMD          (0x03 << 16)
-#define S3C64XX_GPC4_I2S0_V40_DO       (0x05 << 16)
+#define S3C64XX_GPC4_I2S_V40_DO0       (0x05 << 16)
 #define S3C64XX_GPC4_EINT_G2_4         (0x07 << 16)
 
 #define S3C64XX_GPC5_SPI_CLK1          (0x02 << 20)
 #define S3C64XX_GPC5_MMC2_CLK          (0x03 << 20)
-#define S3C64XX_GPC5_I2S1_V40_DO       (0x05 << 20)
+#define S3C64XX_GPC5_I2S_V40_DO1       (0x05 << 20)
 #define S3C64XX_GPC5_EINT_G2_5         (0x07 << 20)
 
 #define S3C64XX_GPC6_SPI_MOSI1         (0x02 << 24)
 #define S3C64XX_GPC6_EINT_G2_6         (0x07 << 24)
 
 #define S3C64XX_GPC7_SPI_nCS1          (0x02 << 28)
-#define S3C64XX_GPC7_I2S2_V40_DO       (0x05 << 28)
+#define S3C64XX_GPC7_I2S_V40_DO2       (0x05 << 28)
 #define S3C64XX_GPC7_EINT_G2_7         (0x07 << 28)
 
index f81b7b8..ebdf183 100644 (file)
@@ -65,7 +65,7 @@ static void s3c_irq_eint_maskack(unsigned int irq)
 static int s3c_irq_eint_set_type(unsigned int irq, unsigned int type)
 {
        int offs = eint_offset(irq);
-       int pin;
+       int pin, pin_val;
        int shift;
        u32 ctrl, mask;
        u32 newvalue = 0;
@@ -109,7 +109,10 @@ static int s3c_irq_eint_set_type(unsigned int irq, unsigned int type)
                return -1;
        }
 
-       shift = (offs / 2) * 4;
+       if (offs <= 15)
+               shift = (offs / 2) * 4;
+       else
+               shift = ((offs - 16) / 2) * 4;
        mask = 0x7 << shift;
 
        ctrl = __raw_readl(reg);
@@ -119,12 +122,18 @@ static int s3c_irq_eint_set_type(unsigned int irq, unsigned int type)
 
        /* set the GPIO pin appropriately */
 
-       if (offs < 23)
+       if (offs < 16) {
                pin = S3C64XX_GPN(offs);
-       else
+               pin_val = S3C_GPIO_SFN(2);
+       } else if (offs < 23) {
+               pin = S3C64XX_GPL(offs + 8 - 16);
+               pin_val = S3C_GPIO_SFN(3);
+       } else {
                pin = S3C64XX_GPM(offs - 23);
+               pin_val = S3C_GPIO_SFN(3);
+       }
 
-       s3c_gpio_cfgpin(pin, S3C_GPIO_SFN(2));
+       s3c_gpio_cfgpin(pin, pin_val);
 
        return 0;
 }
index 5417123..a58c0cc 100644 (file)
@@ -53,3 +53,23 @@ void s3c64xx_setup_sdhci1_cfg_gpio(struct platform_device *dev, int width)
        s3c_gpio_setpull(S3C64XX_GPG(6), S3C_GPIO_PULL_UP);
        s3c_gpio_cfgpin(S3C64XX_GPG(6), S3C_GPIO_SFN(3));
 }
+
+void s3c64xx_setup_sdhci2_cfg_gpio(struct platform_device *dev, int width)
+{
+       unsigned int gpio;
+       unsigned int end;
+
+       end = S3C64XX_GPH(6 + width);
+
+       /* Set all the necessary GPH pins to special-function 1 */
+       for (gpio = S3C64XX_GPH(6); gpio < end; gpio++) {
+               s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(3));
+               s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE);
+       }
+
+       /* Set all the necessary GPC pins to special-function 1 */
+       for (gpio = S3C64XX_GPC(4); gpio < S3C64XX_GPC(6); gpio++) {
+               s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(3));
+               s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE);
+       }
+}
index a8a711c..1608e62 100644 (file)
@@ -15,6 +15,9 @@ config PLAT_S5PC1XX
        select ARCH_REQUIRE_GPIOLIB
        select S3C_GPIO_TRACK
        select S3C_GPIO_PULL_UPDOWN
+       select S3C_GPIO_CFG_S3C24XX
+       select S3C_GPIO_CFG_S3C64XX
+       select S5P_GPIO_CFG_S5PC1XX
        help
          Base platform code for any Samsung S5PC1XX device
 
@@ -34,7 +37,12 @@ config CPU_S5PC100_CLOCK
 
 # platform specific device setup
 
-config S5PC100_SETUP_I2C0
+config S5PC1XX_SETUP_FB_24BPP
+       bool
+       help
+          Common setup code for S5PC1XX with an 24bpp RGB display helper.
+
+config S5PC1XX_SETUP_I2C0
        bool
        default y
        help
@@ -43,8 +51,14 @@ config S5PC100_SETUP_I2C0
          Note, currently since i2c0 is always compiled, this setup helper
          is always compiled with it.
 
-config S5PC100_SETUP_I2C1
+config S5PC1XX_SETUP_I2C1
        bool
        help
          Common setup code for i2c bus 1.
+
+config S5PC1XX_SETUP_SDHCI_GPIO
+       bool
+       help
+         Common setup code for SDHCI gpio.
+
 endif
index f1ecb2c..278f268 100644 (file)
@@ -13,7 +13,9 @@ obj-                          :=
 
 obj-y                          += dev-uart.o
 obj-y                          += cpu.o
-obj-y                          += irq.o
+obj-y                          += irq.o irq-gpio.o irq-eint.o
+obj-y                          += clock.o
+obj-y                          += gpiolib.o
 
 # CPU support
 
@@ -22,5 +24,8 @@ obj-$(CONFIG_CPU_S5PC100_CLOCK)       += s5pc100-clock.o
 
 # Device setup
 
-obj-$(CONFIG_S5PC100_SETUP_I2C0) += setup-i2c0.o
-obj-$(CONFIG_S5PC100_SETUP_I2C1) += setup-i2c1.o
+obj-$(CONFIG_S5P_GPIO_CFG_S5PC1XX) += gpio-config.o
+obj-$(CONFIG_S5PC1XX_SETUP_FB_24BPP) += setup-fb-24bpp.o
+obj-$(CONFIG_S5PC1XX_SETUP_I2C0) += setup-i2c0.o
+obj-$(CONFIG_S5PC1XX_SETUP_I2C1) += setup-i2c1.o
+obj-$(CONFIG_S5PC1XX_SETUP_SDHCI_GPIO) += setup-sdhci-gpio.o
diff --git a/arch/arm/plat-s5pc1xx/clock.c b/arch/arm/plat-s5pc1xx/clock.c
new file mode 100644 (file)
index 0000000..26c21d8
--- /dev/null
@@ -0,0 +1,728 @@
+/* linux/arch/arm/plat-s5pc1xx/clock.c
+ *
+ * Copyright 2009 Samsung Electronics Co.
+ *
+ * S5PC1XX Base clock support
+ *
+ * Based on plat-s3c64xx/clock.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.
+*/
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+
+#include <mach/hardware.h>
+#include <mach/map.h>
+
+#include <plat/regs-clock.h>
+#include <plat/devs.h>
+#include <plat/clock.h>
+
+struct clk clk_27m = {
+       .name           = "clk_27m",
+       .id             = -1,
+       .rate           = 27000000,
+};
+
+static int clk_48m_ctrl(struct clk *clk, int enable)
+{
+       unsigned long flags;
+       u32 val;
+
+       /* can't rely on clock lock, this register has other usages */
+       local_irq_save(flags);
+
+       val = __raw_readl(S5PC100_CLKSRC1);
+       if (enable)
+               val |= S5PC100_CLKSRC1_CLK48M_MASK;
+       else
+               val &= ~S5PC100_CLKSRC1_CLK48M_MASK;
+
+       __raw_writel(val, S5PC100_CLKSRC1);
+       local_irq_restore(flags);
+
+       return 0;
+}
+
+struct clk clk_48m = {
+       .name           = "clk_48m",
+       .id             = -1,
+       .rate           = 48000000,
+       .enable         = clk_48m_ctrl,
+};
+
+struct clk clk_54m = {
+       .name           = "clk_54m",
+       .id             = -1,
+       .rate           = 54000000,
+};
+
+static int clk_default_setrate(struct clk *clk, unsigned long rate)
+{
+       clk->rate = rate;
+       return 0;
+}
+
+static int clk_dummy_enable(struct clk *clk, int enable)
+{
+       return 0;
+}
+
+struct clk clk_hd0 = {
+       .name           = "hclkd0",
+       .id             = -1,
+       .rate           = 0,
+       .parent         = NULL,
+       .ctrlbit        = 0,
+       .set_rate       = clk_default_setrate,
+       .enable         = clk_dummy_enable,
+};
+
+struct clk clk_pd0 = {
+       .name           = "pclkd0",
+       .id             = -1,
+       .rate           = 0,
+       .parent         = NULL,
+       .ctrlbit        = 0,
+       .set_rate       = clk_default_setrate,
+       .enable         = clk_dummy_enable,
+};
+
+static int s5pc1xx_clk_gate(void __iomem *reg, struct clk *clk, int enable)
+{
+       unsigned int ctrlbit = clk->ctrlbit;
+       u32 con;
+
+       con = __raw_readl(reg);
+       if (enable)
+               con |= ctrlbit;
+       else
+               con &= ~ctrlbit;
+       __raw_writel(con, reg);
+
+       return 0;
+}
+
+static int s5pc100_clk_d00_ctrl(struct clk *clk, int enable)
+{
+       return s5pc1xx_clk_gate(S5PC100_CLKGATE_D00, clk, enable);
+}
+
+static int s5pc100_clk_d01_ctrl(struct clk *clk, int enable)
+{
+       return s5pc1xx_clk_gate(S5PC100_CLKGATE_D01, clk, enable);
+}
+
+static int s5pc100_clk_d02_ctrl(struct clk *clk, int enable)
+{
+       return s5pc1xx_clk_gate(S5PC100_CLKGATE_D02, clk, enable);
+}
+
+static int s5pc100_clk_d10_ctrl(struct clk *clk, int enable)
+{
+       return s5pc1xx_clk_gate(S5PC100_CLKGATE_D10, clk, enable);
+}
+
+static int s5pc100_clk_d11_ctrl(struct clk *clk, int enable)
+{
+       return s5pc1xx_clk_gate(S5PC100_CLKGATE_D11, clk, enable);
+}
+
+static int s5pc100_clk_d12_ctrl(struct clk *clk, int enable)
+{
+       return s5pc1xx_clk_gate(S5PC100_CLKGATE_D12, clk, enable);
+}
+
+static int s5pc100_clk_d13_ctrl(struct clk *clk, int enable)
+{
+       return s5pc1xx_clk_gate(S5PC100_CLKGATE_D13, clk, enable);
+}
+
+static int s5pc100_clk_d14_ctrl(struct clk *clk, int enable)
+{
+       return s5pc1xx_clk_gate(S5PC100_CLKGATE_D14, clk, enable);
+}
+
+static int s5pc100_clk_d15_ctrl(struct clk *clk, int enable)
+{
+       return s5pc1xx_clk_gate(S5PC100_CLKGATE_D15, clk, enable);
+}
+
+static int s5pc100_clk_d20_ctrl(struct clk *clk, int enable)
+{
+       return s5pc1xx_clk_gate(S5PC100_CLKGATE_D20, clk, enable);
+}
+
+int s5pc100_sclk0_ctrl(struct clk *clk, int enable)
+{
+       return s5pc1xx_clk_gate(S5PC100_SCLKGATE0, clk, enable);
+}
+
+int s5pc100_sclk1_ctrl(struct clk *clk, int enable)
+{
+       return s5pc1xx_clk_gate(S5PC100_SCLKGATE1, clk, enable);
+}
+
+static struct clk s5pc100_init_clocks_disable[] = {
+       {
+               .name           = "dsi",
+               .id             = -1,
+               .parent         = &clk_p,
+               .enable         = s5pc100_clk_d11_ctrl,
+               .ctrlbit        = S5PC100_CLKGATE_D11_DSI,
+       }, {
+               .name           = "csi",
+               .id             = -1,
+               .parent         = &clk_h,
+               .enable         = s5pc100_clk_d11_ctrl,
+               .ctrlbit        = S5PC100_CLKGATE_D11_CSI,
+       }, {
+               .name           = "ccan",
+               .id             = 0,
+               .parent         = &clk_p,
+               .enable         = s5pc100_clk_d14_ctrl,
+               .ctrlbit        = S5PC100_CLKGATE_D14_CCAN0,
+       }, {
+               .name           = "ccan",
+               .id             = 1,
+               .parent         = &clk_p,
+               .enable         = s5pc100_clk_d14_ctrl,
+               .ctrlbit        = S5PC100_CLKGATE_D14_CCAN1,
+       }, {
+               .name           = "keypad",
+               .id             = -1,
+               .parent         = &clk_p,
+               .enable         = s5pc100_clk_d15_ctrl,
+               .ctrlbit        = S5PC100_CLKGATE_D15_KEYIF,
+       }, {
+               .name           = "hclkd2",
+               .id             = -1,
+               .parent         = NULL,
+               .enable         = s5pc100_clk_d20_ctrl,
+               .ctrlbit        = S5PC100_CLKGATE_D20_HCLKD2,
+       }, {
+               .name           = "iis-d2",
+               .id             = -1,
+               .parent         = NULL,
+               .enable         = s5pc100_clk_d20_ctrl,
+               .ctrlbit        = S5PC100_CLKGATE_D20_I2SD2,
+       },
+};
+
+static struct clk s5pc100_init_clocks[] = {
+       /* System1 (D0_0) devices */
+       {
+               .name           = "intc",
+               .id             = -1,
+               .parent         = &clk_hd0,
+               .enable         = s5pc100_clk_d00_ctrl,
+               .ctrlbit        = S5PC100_CLKGATE_D00_INTC,
+       }, {
+               .name           = "tzic",
+               .id             = -1,
+               .parent         = &clk_hd0,
+               .enable         = s5pc100_clk_d00_ctrl,
+               .ctrlbit        = S5PC100_CLKGATE_D00_TZIC,
+       }, {
+               .name           = "cf-ata",
+               .id             = -1,
+               .parent         = &clk_hd0,
+               .enable         = s5pc100_clk_d00_ctrl,
+               .ctrlbit        = S5PC100_CLKGATE_D00_CFCON,
+       }, {
+               .name           = "mdma",
+               .id             = -1,
+               .parent         = &clk_hd0,
+               .enable         = s5pc100_clk_d00_ctrl,
+               .ctrlbit        = S5PC100_CLKGATE_D00_MDMA,
+       }, {
+               .name           = "g2d",
+               .id             = -1,
+               .parent         = &clk_hd0,
+               .enable         = s5pc100_clk_d00_ctrl,
+               .ctrlbit        = S5PC100_CLKGATE_D00_G2D,
+       }, {
+               .name           = "secss",
+               .id             = -1,
+               .parent         = &clk_hd0,
+               .enable         = s5pc100_clk_d00_ctrl,
+               .ctrlbit        = S5PC100_CLKGATE_D00_SECSS,
+       }, {
+               .name           = "cssys",
+               .id             = -1,
+               .parent         = &clk_hd0,
+               .enable         = s5pc100_clk_d00_ctrl,
+               .ctrlbit        = S5PC100_CLKGATE_D00_CSSYS,
+       },
+
+       /* Memory (D0_1) devices */
+       {
+               .name           = "dmc",
+               .id             = -1,
+               .parent         = &clk_hd0,
+               .enable         = s5pc100_clk_d01_ctrl,
+               .ctrlbit        = S5PC100_CLKGATE_D01_DMC,
+       }, {
+               .name           = "sromc",
+               .id             = -1,
+               .parent         = &clk_hd0,
+               .enable         = s5pc100_clk_d01_ctrl,
+               .ctrlbit        = S5PC100_CLKGATE_D01_SROMC,
+       }, {
+               .name           = "onenand",
+               .id             = -1,
+               .parent         = &clk_hd0,
+               .enable         = s5pc100_clk_d01_ctrl,
+               .ctrlbit        = S5PC100_CLKGATE_D01_ONENAND,
+       }, {
+               .name           = "nand",
+               .id             = -1,
+               .parent         = &clk_hd0,
+               .enable         = s5pc100_clk_d01_ctrl,
+               .ctrlbit        = S5PC100_CLKGATE_D01_NFCON,
+       }, {
+               .name           = "intmem",
+               .id             = -1,
+               .parent         = &clk_hd0,
+               .enable         = s5pc100_clk_d01_ctrl,
+               .ctrlbit        = S5PC100_CLKGATE_D01_INTMEM,
+       }, {
+               .name           = "ebi",
+               .id             = -1,
+               .parent         = &clk_hd0,
+               .enable         = s5pc100_clk_d01_ctrl,
+               .ctrlbit        = S5PC100_CLKGATE_D01_EBI,
+       },
+
+       /* System2 (D0_2) devices */
+       {
+               .name           = "seckey",
+               .id             = -1,
+               .parent         = &clk_pd0,
+               .enable         = s5pc100_clk_d02_ctrl,
+               .ctrlbit        = S5PC100_CLKGATE_D02_SECKEY,
+       }, {
+               .name           = "sdm",
+               .id             = -1,
+               .parent         = &clk_hd0,
+               .enable         = s5pc100_clk_d02_ctrl,
+               .ctrlbit        = S5PC100_CLKGATE_D02_SDM,
+       },
+
+       /* File (D1_0) devices */
+       {
+               .name           = "pdma",
+               .id             = 0,
+               .parent         = &clk_h,
+               .enable         = s5pc100_clk_d10_ctrl,
+               .ctrlbit        = S5PC100_CLKGATE_D10_PDMA0,
+       }, {
+               .name           = "pdma",
+               .id             = 1,
+               .parent         = &clk_h,
+               .enable         = s5pc100_clk_d10_ctrl,
+               .ctrlbit        = S5PC100_CLKGATE_D10_PDMA1,
+       }, {
+               .name           = "usb-host",
+               .id             = -1,
+               .parent         = &clk_h,
+               .enable         = s5pc100_clk_d10_ctrl,
+               .ctrlbit        = S5PC100_CLKGATE_D10_USBHOST,
+       }, {
+               .name           = "otg",
+               .id             = -1,
+               .parent         = &clk_h,
+               .enable         = s5pc100_clk_d10_ctrl,
+               .ctrlbit        = S5PC100_CLKGATE_D10_USBOTG,
+       }, {
+               .name           = "modem",
+               .id             = -1,
+               .parent         = &clk_h,
+               .enable         = s5pc100_clk_d10_ctrl,
+               .ctrlbit        = S5PC100_CLKGATE_D10_MODEMIF,
+       }, {
+               .name           = "hsmmc",
+               .id             = 0,
+               .parent         = &clk_48m,
+               .enable         = s5pc100_clk_d10_ctrl,
+               .ctrlbit        = S5PC100_CLKGATE_D10_HSMMC0,
+       }, {
+               .name           = "hsmmc",
+               .id             = 1,
+               .parent         = &clk_48m,
+               .enable         = s5pc100_clk_d10_ctrl,
+               .ctrlbit        = S5PC100_CLKGATE_D10_HSMMC1,
+       }, {
+               .name           = "hsmmc",
+               .id             = 2,
+               .parent         = &clk_48m,
+               .enable         = s5pc100_clk_d10_ctrl,
+               .ctrlbit        = S5PC100_CLKGATE_D10_HSMMC2,
+       },
+
+       /* Multimedia1 (D1_1) devices */
+       {
+               .name           = "lcd",
+               .id             = -1,
+               .parent         = &clk_p,
+               .enable         = s5pc100_clk_d11_ctrl,
+               .ctrlbit        = S5PC100_CLKGATE_D11_LCD,
+       }, {
+               .name           = "rotator",
+               .id             = -1,
+               .parent         = &clk_p,
+               .enable         = s5pc100_clk_d11_ctrl,
+               .ctrlbit        = S5PC100_CLKGATE_D11_ROTATOR,
+       }, {
+               .name           = "fimc",
+               .id             = -1,
+               .parent         = &clk_p,
+               .enable         = s5pc100_clk_d11_ctrl,
+               .ctrlbit        = S5PC100_CLKGATE_D11_FIMC0,
+       }, {
+               .name           = "fimc",
+               .id             = -1,
+               .parent         = &clk_p,
+               .enable         = s5pc100_clk_d11_ctrl,
+               .ctrlbit        = S5PC100_CLKGATE_D11_FIMC1,
+       }, {
+               .name           = "fimc",
+               .id             = -1,
+               .parent         = &clk_p,
+               .enable         = s5pc100_clk_d11_ctrl,
+               .ctrlbit        = S5PC100_CLKGATE_D11_FIMC2,
+       }, {
+               .name           = "jpeg",
+               .id             = -1,
+               .parent         = &clk_p,
+               .enable         = s5pc100_clk_d11_ctrl,
+               .ctrlbit        = S5PC100_CLKGATE_D11_JPEG,
+       }, {
+               .name           = "g3d",
+               .id             = -1,
+               .parent         = &clk_p,
+               .enable         = s5pc100_clk_d11_ctrl,
+               .ctrlbit        = S5PC100_CLKGATE_D11_G3D,
+       },
+
+       /* Multimedia2 (D1_2) devices */
+       {
+               .name           = "tv",
+               .id             = -1,
+               .parent         = &clk_p,
+               .enable         = s5pc100_clk_d12_ctrl,
+               .ctrlbit        = S5PC100_CLKGATE_D12_TV,
+       }, {
+               .name           = "vp",
+               .id             = -1,
+               .parent         = &clk_p,
+               .enable         = s5pc100_clk_d12_ctrl,
+               .ctrlbit        = S5PC100_CLKGATE_D12_VP,
+       }, {
+               .name           = "mixer",
+               .id             = -1,
+               .parent         = &clk_p,
+               .enable         = s5pc100_clk_d12_ctrl,
+               .ctrlbit        = S5PC100_CLKGATE_D12_MIXER,
+       }, {
+               .name           = "hdmi",
+               .id             = -1,
+               .parent         = &clk_p,
+               .enable         = s5pc100_clk_d12_ctrl,
+               .ctrlbit        = S5PC100_CLKGATE_D12_HDMI,
+       }, {
+               .name           = "mfc",
+               .id             = -1,
+               .parent         = &clk_p,
+               .enable         = s5pc100_clk_d12_ctrl,
+               .ctrlbit        = S5PC100_CLKGATE_D12_MFC,
+       },
+
+       /* System (D1_3) devices */
+       {
+               .name           = "chipid",
+               .id             = -1,
+               .parent         = &clk_p,
+               .enable         = s5pc100_clk_d13_ctrl,
+               .ctrlbit        = S5PC100_CLKGATE_D13_CHIPID,
+       }, {
+               .name           = "gpio",
+               .id             = -1,
+               .parent         = &clk_p,
+               .enable         = s5pc100_clk_d13_ctrl,
+               .ctrlbit        = S5PC100_CLKGATE_D13_GPIO,
+       }, {
+               .name           = "apc",
+               .id             = -1,
+               .parent         = &clk_p,
+               .enable         = s5pc100_clk_d13_ctrl,
+               .ctrlbit        = S5PC100_CLKGATE_D13_APC,
+       }, {
+               .name           = "iec",
+               .id             = -1,
+               .parent         = &clk_p,
+               .enable         = s5pc100_clk_d13_ctrl,
+               .ctrlbit        = S5PC100_CLKGATE_D13_IEC,
+       }, {
+               .name           = "timers",
+               .id             = -1,
+               .parent         = &clk_p,
+               .enable         = s5pc100_clk_d13_ctrl,
+               .ctrlbit        = S5PC100_CLKGATE_D13_PWM,
+       }, {
+               .name           = "systimer",
+               .id             = -1,
+               .parent         = &clk_p,
+               .enable         = s5pc100_clk_d13_ctrl,
+               .ctrlbit        = S5PC100_CLKGATE_D13_SYSTIMER,
+       }, {
+               .name           = "watchdog",
+               .id             = -1,
+               .parent         = &clk_p,
+               .enable         = s5pc100_clk_d13_ctrl,
+               .ctrlbit        = S5PC100_CLKGATE_D13_WDT,
+       }, {
+               .name           = "rtc",
+               .id             = -1,
+               .parent         = &clk_p,
+               .enable         = s5pc100_clk_d13_ctrl,
+               .ctrlbit        = S5PC100_CLKGATE_D13_RTC,
+       },
+
+       /* Connectivity (D1_4) devices */
+       {
+               .name           = "uart",
+               .id             = 0,
+               .parent         = &clk_p,
+               .enable         = s5pc100_clk_d14_ctrl,
+               .ctrlbit        = S5PC100_CLKGATE_D14_UART0,
+       }, {
+               .name           = "uart",
+               .id             = 1,
+               .parent         = &clk_p,
+               .enable         = s5pc100_clk_d14_ctrl,
+               .ctrlbit        = S5PC100_CLKGATE_D14_UART1,
+       }, {
+               .name           = "uart",
+               .id             = 2,
+               .parent         = &clk_p,
+               .enable         = s5pc100_clk_d14_ctrl,
+               .ctrlbit        = S5PC100_CLKGATE_D14_UART2,
+       }, {
+               .name           = "uart",
+               .id             = 3,
+               .parent         = &clk_p,
+               .enable         = s5pc100_clk_d14_ctrl,
+               .ctrlbit        = S5PC100_CLKGATE_D14_UART3,
+       }, {
+               .name           = "i2c",
+               .id             = -1,
+               .parent         = &clk_p,
+               .enable         = s5pc100_clk_d14_ctrl,
+               .ctrlbit        = S5PC100_CLKGATE_D14_IIC,
+       }, {
+               .name           = "hdmi-i2c",
+               .id             = -1,
+               .parent         = &clk_p,
+               .enable         = s5pc100_clk_d14_ctrl,
+               .ctrlbit        = S5PC100_CLKGATE_D14_HDMI_IIC,
+       }, {
+               .name           = "spi",
+               .id             = 0,
+               .parent         = &clk_p,
+               .enable         = s5pc100_clk_d14_ctrl,
+               .ctrlbit        = S5PC100_CLKGATE_D14_SPI0,
+       }, {
+               .name           = "spi",
+               .id             = 1,
+               .parent         = &clk_p,
+               .enable         = s5pc100_clk_d14_ctrl,
+               .ctrlbit        = S5PC100_CLKGATE_D14_SPI1,
+       }, {
+               .name           = "spi",
+               .id             = 2,
+               .parent         = &clk_p,
+               .enable         = s5pc100_clk_d14_ctrl,
+               .ctrlbit        = S5PC100_CLKGATE_D14_SPI2,
+       }, {
+               .name           = "irda",
+               .id             = -1,
+               .parent         = &clk_p,
+               .enable         = s5pc100_clk_d14_ctrl,
+               .ctrlbit        = S5PC100_CLKGATE_D14_IRDA,
+       }, {
+               .name           = "hsitx",
+               .id             = -1,
+               .parent         = &clk_p,
+               .enable         = s5pc100_clk_d14_ctrl,
+               .ctrlbit        = S5PC100_CLKGATE_D14_HSITX,
+       }, {
+               .name           = "hsirx",
+               .id             = -1,
+               .parent         = &clk_p,
+               .enable         = s5pc100_clk_d14_ctrl,
+               .ctrlbit        = S5PC100_CLKGATE_D14_HSIRX,
+       },
+
+       /* Audio (D1_5) devices */
+       {
+               .name           = "iis",
+               .id             = 0,
+               .parent         = &clk_p,
+               .enable         = s5pc100_clk_d15_ctrl,
+               .ctrlbit        = S5PC100_CLKGATE_D15_IIS0,
+       }, {
+               .name           = "iis",
+               .id             = 1,
+               .parent         = &clk_p,
+               .enable         = s5pc100_clk_d15_ctrl,
+               .ctrlbit        = S5PC100_CLKGATE_D15_IIS1,
+       }, {
+               .name           = "iis",
+               .id             = 2,
+               .parent         = &clk_p,
+               .enable         = s5pc100_clk_d15_ctrl,
+               .ctrlbit        = S5PC100_CLKGATE_D15_IIS2,
+       }, {
+               .name           = "ac97",
+               .id             = -1,
+               .parent         = &clk_p,
+               .enable         = s5pc100_clk_d15_ctrl,
+               .ctrlbit        = S5PC100_CLKGATE_D15_AC97,
+       }, {
+               .name           = "pcm",
+               .id             = 0,
+               .parent         = &clk_p,
+               .enable         = s5pc100_clk_d15_ctrl,
+               .ctrlbit        = S5PC100_CLKGATE_D15_PCM0,
+       }, {
+               .name           = "pcm",
+               .id             = 1,
+               .parent         = &clk_p,
+               .enable         = s5pc100_clk_d15_ctrl,
+               .ctrlbit        = S5PC100_CLKGATE_D15_PCM1,
+       }, {
+               .name           = "spdif",
+               .id             = -1,
+               .parent         = &clk_p,
+               .enable         = s5pc100_clk_d15_ctrl,
+               .ctrlbit        = S5PC100_CLKGATE_D15_SPDIF,
+       }, {
+               .name           = "adc",
+               .id             = -1,
+               .parent         = &clk_p,
+               .enable         = s5pc100_clk_d15_ctrl,
+               .ctrlbit        = S5PC100_CLKGATE_D15_TSADC,
+       }, {
+               .name           = "cg",
+               .id             = -1,
+               .parent         = &clk_p,
+               .enable         = s5pc100_clk_d15_ctrl,
+               .ctrlbit        = S5PC100_CLKGATE_D15_CG,
+       },
+
+       /* Audio (D2_0) devices: all disabled */
+
+       /* Special Clocks 0 */
+       {
+               .name           = "sclk_hpm",
+               .id             = -1,
+               .parent         = NULL,
+               .enable         = s5pc100_sclk0_ctrl,
+               .ctrlbit        = S5PC100_CLKGATE_SCLK0_HPM,
+       }, {
+               .name           = "sclk_onenand",
+               .id             = -1,
+               .parent         = NULL,
+               .enable         = s5pc100_sclk0_ctrl,
+               .ctrlbit        = S5PC100_CLKGATE_SCLK0_ONENAND,
+       }, {
+               .name           = "spi_48",
+               .id             = 0,
+               .parent         = &clk_48m,
+               .enable         = s5pc100_sclk0_ctrl,
+               .ctrlbit        = S5PC100_CLKGATE_SCLK0_SPI0_48,
+       }, {
+               .name           = "spi_48",
+               .id             = 1,
+               .parent         = &clk_48m,
+               .enable         = s5pc100_sclk0_ctrl,
+               .ctrlbit        = S5PC100_CLKGATE_SCLK0_SPI1_48,
+       }, {
+               .name           = "spi_48",
+               .id             = 2,
+               .parent         = &clk_48m,
+               .enable         = s5pc100_sclk0_ctrl,
+               .ctrlbit        = S5PC100_CLKGATE_SCLK0_SPI2_48,
+       }, {
+               .name           = "mmc_48",
+               .id             = 0,
+               .parent         = &clk_48m,
+               .enable         = s5pc100_sclk0_ctrl,
+               .ctrlbit        = S5PC100_CLKGATE_SCLK0_MMC0_48,
+       }, {
+               .name           = "mmc_48",
+               .id             = 1,
+               .parent         = &clk_48m,
+               .enable         = s5pc100_sclk0_ctrl,
+               .ctrlbit        = S5PC100_CLKGATE_SCLK0_MMC1_48,
+       }, {
+               .name           = "mmc_48",
+               .id             = 2,
+               .parent         = &clk_48m,
+               .enable         = s5pc100_sclk0_ctrl,
+               .ctrlbit        = S5PC100_CLKGATE_SCLK0_MMC2_48,
+       },
+       /* Special Clocks 1 */
+};
+
+static struct clk *clks[] __initdata = {
+       &clk_ext,
+       &clk_epll,
+       &clk_27m,
+       &clk_48m,
+       &clk_54m,
+};
+
+void __init s5pc1xx_register_clocks(void)
+{
+       struct clk *clkp;
+       int ret;
+       int ptr;
+       int size;
+
+       s3c24xx_register_clocks(clks, ARRAY_SIZE(clks));
+
+       clkp = s5pc100_init_clocks;
+       size = ARRAY_SIZE(s5pc100_init_clocks);
+
+       for (ptr = 0; ptr < size; ptr++, clkp++) {
+               ret = s3c24xx_register_clock(clkp);
+               if (ret < 0) {
+                       printk(KERN_ERR "Failed to register clock %s (%d)\n",
+                              clkp->name, ret);
+               }
+       }
+
+       clkp = s5pc100_init_clocks_disable;
+       size = ARRAY_SIZE(s5pc100_init_clocks_disable);
+
+       for (ptr = 0; ptr < size; ptr++, clkp++) {
+               ret = s3c24xx_register_clock(clkp);
+               if (ret < 0) {
+                       printk(KERN_ERR "Failed to register clock %s (%d)\n",
+                              clkp->name, ret);
+               }
+
+               (clkp->enable)(clkp, 0);
+       }
+
+       s3c_pwmclk_init();
+}
index 715a733..02baeaa 100644 (file)
@@ -55,6 +55,16 @@ static struct cpu_table cpu_ids[] __initdata = {
 
 static struct map_desc s5pc1xx_iodesc[] __initdata = {
        {
+               .virtual        = (unsigned long)S5PC1XX_VA_CLK_OTHER,
+               .pfn            = __phys_to_pfn(S5PC1XX_PA_CLK_OTHER),
+               .length         = SZ_4K,
+               .type           = MT_DEVICE,
+       }, {
+               .virtual        = (unsigned long)S5PC1XX_VA_GPIO,
+               .pfn            = __phys_to_pfn(S5PC100_PA_GPIO),
+               .length         = SZ_4K,
+               .type           = MT_DEVICE,
+       }, {
                .virtual        = (unsigned long)S5PC1XX_VA_CHIPID,
                .pfn            = __phys_to_pfn(S5PC1XX_PA_CHIPID),
                .length         = SZ_16,
diff --git a/arch/arm/plat-s5pc1xx/gpio-config.c b/arch/arm/plat-s5pc1xx/gpio-config.c
new file mode 100644 (file)
index 0000000..bba675d
--- /dev/null
@@ -0,0 +1,62 @@
+/* linux/arch/arm/plat-s5pc1xx/gpio-config.c
+ *
+ * Copyright 2009 Samsung Electronics
+ *
+ * S5PC1XX GPIO Configuration.
+ *
+ * Based on plat-s3c64xx/gpio-config.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.
+*/
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/gpio.h>
+#include <linux/io.h>
+
+#include <mach/gpio-core.h>
+#include <plat/gpio-cfg-s5pc1xx.h>
+
+s5p_gpio_drvstr_t s5p_gpio_get_drvstr(unsigned int pin, unsigned int off)
+{
+       struct s3c_gpio_chip *chip = s3c_gpiolib_getchip(pin);
+       void __iomem *reg;
+       int shift = off * 2;
+       u32 drvstr;
+
+       if (!chip)
+               return -EINVAL;
+
+       reg = chip->base + 0x0C;
+
+       drvstr = __raw_readl(reg);
+       drvstr = 0xffff & (0x3 << shift);
+       drvstr = drvstr >> shift;
+
+       return (__force s5p_gpio_drvstr_t)drvstr;
+}
+EXPORT_SYMBOL(s5p_gpio_get_drvstr);
+
+int s5p_gpio_set_drvstr(unsigned int pin, unsigned int off,
+                       s5p_gpio_drvstr_t drvstr)
+{
+       struct s3c_gpio_chip *chip = s3c_gpiolib_getchip(pin);
+       void __iomem *reg;
+       int shift = off * 2;
+       u32 tmp;
+
+       if (!chip)
+               return -EINVAL;
+
+       reg = chip->base + 0x0C;
+
+       tmp = __raw_readl(reg);
+       tmp |= drvstr << shift;
+
+       __raw_writel(tmp, reg);
+
+       return 0;
+}
+EXPORT_SYMBOL(s5p_gpio_set_drvstr);
diff --git a/arch/arm/plat-s5pc1xx/gpiolib.c b/arch/arm/plat-s5pc1xx/gpiolib.c
new file mode 100644 (file)
index 0000000..facb410
--- /dev/null
@@ -0,0 +1,503 @@
+/*
+ * arch/arm/plat-s5pc1xx/gpiolib.c
+ *
+ *  Copyright 2009 Samsung Electronics Co
+ *  Kyungmin Park <kyungmin.park@samsung.com>
+ *
+ * S5PC1XX - GPIOlib support
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/irq.h>
+#include <linux/io.h>
+#include <linux/gpio.h>
+
+#include <mach/map.h>
+#include <mach/gpio-core.h>
+
+#include <plat/gpio-cfg.h>
+#include <plat/gpio-cfg-helpers.h>
+#include <plat/regs-gpio.h>
+
+/* S5PC100 GPIO bank summary:
+ *
+ * Bank        GPIOs   Style   INT Type
+ * A0  8       4Bit    GPIO_INT0
+ * A1  5       4Bit    GPIO_INT1
+ * B   8       4Bit    GPIO_INT2
+ * C   5       4Bit    GPIO_INT3
+ * D   7       4Bit    GPIO_INT4
+ * E0  8       4Bit    GPIO_INT5
+ * E1  6       4Bit    GPIO_INT6
+ * F0  8       4Bit    GPIO_INT7
+ * F1  8       4Bit    GPIO_INT8
+ * F2  8       4Bit    GPIO_INT9
+ * F3  4       4Bit    GPIO_INT10
+ * G0  8       4Bit    GPIO_INT11
+ * G1  3       4Bit    GPIO_INT12
+ * G2  7       4Bit    GPIO_INT13
+ * G3  7       4Bit    GPIO_INT14
+ * H0  8       4Bit    WKUP_INT
+ * H1  8       4Bit    WKUP_INT
+ * H2  8       4Bit    WKUP_INT
+ * H3  8       4Bit    WKUP_INT
+ * I   8       4Bit    GPIO_INT15
+ * J0  8       4Bit    GPIO_INT16
+ * J1  5       4Bit    GPIO_INT17
+ * J2  8       4Bit    GPIO_INT18
+ * J3  8       4Bit    GPIO_INT19
+ * J4  4       4Bit    GPIO_INT20
+ * K0  8       4Bit    None
+ * K1  6       4Bit    None
+ * K2  8       4Bit    None
+ * K3  8       4Bit    None
+ * L0  8       4Bit    None
+ * L1  8       4Bit    None
+ * L2  8       4Bit    None
+ * L3  8       4Bit    None
+ */
+
+#define OFF_GPCON      (0x00)
+#define OFF_GPDAT      (0x04)
+
+#define con_4bit_shift(__off) ((__off) * 4)
+
+#if 1
+#define gpio_dbg(x...) do { } while (0)
+#else
+#define gpio_dbg(x...) printk(KERN_DEBUG x)
+#endif
+
+/* The s5pc1xx_gpiolib routines are to control the gpio banks where
+ * the gpio configuration register (GPxCON) has 4 bits per GPIO, as the
+ * following example:
+ *
+ * base + 0x00: Control register, 4 bits per gpio
+ *             gpio n: 4 bits starting at (4*n)
+ *             0000 = input, 0001 = output, others mean special-function
+ * base + 0x04: Data register, 1 bit per gpio
+ *             bit n: data bit n
+ *
+ * Note, since the data register is one bit per gpio and is at base + 0x4
+ * we can use s3c_gpiolib_get and s3c_gpiolib_set to change the state of
+ * the output.
+ */
+
+static int s5pc1xx_gpiolib_input(struct gpio_chip *chip, unsigned offset)
+{
+       struct s3c_gpio_chip *ourchip = to_s3c_gpio(chip);
+       void __iomem *base = ourchip->base;
+       unsigned long con;
+
+       con = __raw_readl(base + OFF_GPCON);
+       con &= ~(0xf << con_4bit_shift(offset));
+       __raw_writel(con, base + OFF_GPCON);
+
+       gpio_dbg("%s: %p: CON now %08lx\n", __func__, base, con);
+
+       return 0;
+}
+
+static int s5pc1xx_gpiolib_output(struct gpio_chip *chip,
+                                      unsigned offset, int value)
+{
+       struct s3c_gpio_chip *ourchip = to_s3c_gpio(chip);
+       void __iomem *base = ourchip->base;
+       unsigned long con;
+       unsigned long dat;
+
+       con = __raw_readl(base + OFF_GPCON);
+       con &= ~(0xf << con_4bit_shift(offset));
+       con |= 0x1 << con_4bit_shift(offset);
+
+       dat = __raw_readl(base + OFF_GPDAT);
+       if (value)
+               dat |= 1 << offset;
+       else
+               dat &= ~(1 << offset);
+
+       __raw_writel(dat, base + OFF_GPDAT);
+       __raw_writel(con, base + OFF_GPCON);
+       __raw_writel(dat, base + OFF_GPDAT);
+
+       gpio_dbg("%s: %p: CON %08lx, DAT %08lx\n", __func__, base, con, dat);
+
+       return 0;
+}
+
+static int s5pc1xx_gpiolib_to_irq(struct gpio_chip *chip, unsigned int offset)
+{
+       return S3C_IRQ_GPIO(chip->base + offset);
+}
+
+static int s5pc1xx_gpiolib_to_eint(struct gpio_chip *chip, unsigned int offset)
+{
+       int base;
+
+       base = chip->base - S5PC100_GPH0(0);
+       if (base == 0)
+               return IRQ_EINT(offset);
+       base = chip->base - S5PC100_GPH1(0);
+       if (base == 0)
+               return IRQ_EINT(8 + offset);
+       base = chip->base - S5PC100_GPH2(0);
+       if (base == 0)
+               return IRQ_EINT(16 + offset);
+       base = chip->base - S5PC100_GPH3(0);
+       if (base == 0)
+               return IRQ_EINT(24 + offset);
+       return -EINVAL;
+}
+
+static struct s3c_gpio_cfg gpio_cfg = {
+       .set_config     = s3c_gpio_setcfg_s3c64xx_4bit,
+       .set_pull       = s3c_gpio_setpull_updown,
+       .get_pull       = s3c_gpio_getpull_updown,
+};
+
+static struct s3c_gpio_cfg gpio_cfg_eint = {
+       .cfg_eint       = 0xf,
+       .set_config     = s3c_gpio_setcfg_s3c64xx_4bit,
+       .set_pull       = s3c_gpio_setpull_updown,
+       .get_pull       = s3c_gpio_getpull_updown,
+};
+
+static struct s3c_gpio_cfg gpio_cfg_noint = {
+       .set_config     = s3c_gpio_setcfg_s3c64xx_4bit,
+       .set_pull       = s3c_gpio_setpull_updown,
+       .get_pull       = s3c_gpio_getpull_updown,
+};
+
+static struct s3c_gpio_chip s5pc100_gpio_chips[] = {
+       {
+               .base   = S5PC100_GPA0_BASE,
+               .config = &gpio_cfg,
+               .chip   = {
+                       .base   = S5PC100_GPA0(0),
+                       .ngpio  = S5PC100_GPIO_A0_NR,
+                       .label  = "GPA0",
+               },
+       }, {
+               .base   = S5PC100_GPA1_BASE,
+               .config = &gpio_cfg,
+               .chip   = {
+                       .base   = S5PC100_GPA1(0),
+                       .ngpio  = S5PC100_GPIO_A1_NR,
+                       .label  = "GPA1",
+               },
+       }, {
+               .base   = S5PC100_GPB_BASE,
+               .config = &gpio_cfg,
+               .chip   = {
+                       .base   = S5PC100_GPB(0),
+                       .ngpio  = S5PC100_GPIO_B_NR,
+                       .label  = "GPB",
+               },
+       }, {
+               .base   = S5PC100_GPC_BASE,
+               .config = &gpio_cfg,
+               .chip   = {
+                       .base   = S5PC100_GPC(0),
+                       .ngpio  = S5PC100_GPIO_C_NR,
+                       .label  = "GPC",
+               },
+       }, {
+               .base   = S5PC100_GPD_BASE,
+               .config = &gpio_cfg,
+               .chip   = {
+                       .base   = S5PC100_GPD(0),
+                       .ngpio  = S5PC100_GPIO_D_NR,
+                       .label  = "GPD",
+               },
+       }, {
+               .base   = S5PC100_GPE0_BASE,
+               .config = &gpio_cfg,
+               .chip   = {
+                       .base   = S5PC100_GPE0(0),
+                       .ngpio  = S5PC100_GPIO_E0_NR,
+                       .label  = "GPE0",
+               },
+       }, {
+               .base   = S5PC100_GPE1_BASE,
+               .config = &gpio_cfg,
+               .chip   = {
+                       .base   = S5PC100_GPE1(0),
+                       .ngpio  = S5PC100_GPIO_E1_NR,
+                       .label  = "GPE1",
+               },
+       }, {
+               .base   = S5PC100_GPF0_BASE,
+               .config = &gpio_cfg,
+               .chip   = {
+                       .base   = S5PC100_GPF0(0),
+                       .ngpio  = S5PC100_GPIO_F0_NR,
+                       .label  = "GPF0",
+               },
+       }, {
+               .base   = S5PC100_GPF1_BASE,
+               .config = &gpio_cfg,
+               .chip   = {
+                       .base   = S5PC100_GPF1(0),
+                       .ngpio  = S5PC100_GPIO_F1_NR,
+                       .label  = "GPF1",
+               },
+       }, {
+               .base   = S5PC100_GPF2_BASE,
+               .config = &gpio_cfg,
+               .chip   = {
+                       .base   = S5PC100_GPF2(0),
+                       .ngpio  = S5PC100_GPIO_F2_NR,
+                       .label  = "GPF2",
+               },
+       }, {
+               .base   = S5PC100_GPF3_BASE,
+               .config = &gpio_cfg,
+               .chip   = {
+                       .base   = S5PC100_GPF3(0),
+                       .ngpio  = S5PC100_GPIO_F3_NR,
+                       .label  = "GPF3",
+               },
+       }, {
+               .base   = S5PC100_GPG0_BASE,
+               .config = &gpio_cfg,
+               .chip   = {
+                       .base   = S5PC100_GPG0(0),
+                       .ngpio  = S5PC100_GPIO_G0_NR,
+                       .label  = "GPG0",
+               },
+       }, {
+               .base   = S5PC100_GPG1_BASE,
+               .config = &gpio_cfg,
+               .chip   = {
+                       .base   = S5PC100_GPG1(0),
+                       .ngpio  = S5PC100_GPIO_G1_NR,
+                       .label  = "GPG1",
+               },
+       }, {
+               .base   = S5PC100_GPG2_BASE,
+               .config = &gpio_cfg,
+               .chip   = {
+                       .base   = S5PC100_GPG2(0),
+                       .ngpio  = S5PC100_GPIO_G2_NR,
+                       .label  = "GPG2",
+               },
+       }, {
+               .base   = S5PC100_GPG3_BASE,
+               .config = &gpio_cfg,
+               .chip   = {
+                       .base   = S5PC100_GPG3(0),
+                       .ngpio  = S5PC100_GPIO_G3_NR,
+                       .label  = "GPG3",
+               },
+       }, {
+               .base   = S5PC100_GPH0_BASE,
+               .config = &gpio_cfg_eint,
+               .chip   = {
+                       .base   = S5PC100_GPH0(0),
+                       .ngpio  = S5PC100_GPIO_H0_NR,
+                       .label  = "GPH0",
+               },
+       }, {
+               .base   = S5PC100_GPH1_BASE,
+               .config = &gpio_cfg_eint,
+               .chip   = {
+                       .base   = S5PC100_GPH1(0),
+                       .ngpio  = S5PC100_GPIO_H1_NR,
+                       .label  = "GPH1",
+               },
+       }, {
+               .base   = S5PC100_GPH2_BASE,
+               .config = &gpio_cfg_eint,
+               .chip   = {
+                       .base   = S5PC100_GPH2(0),
+                       .ngpio  = S5PC100_GPIO_H2_NR,
+                       .label  = "GPH2",
+               },
+       }, {
+               .base   = S5PC100_GPH3_BASE,
+               .config = &gpio_cfg_eint,
+               .chip   = {
+                       .base   = S5PC100_GPH3(0),
+                       .ngpio  = S5PC100_GPIO_H3_NR,
+                       .label  = "GPH3",
+               },
+       }, {
+               .base   = S5PC100_GPI_BASE,
+               .config = &gpio_cfg,
+               .chip   = {
+                       .base   = S5PC100_GPI(0),
+                       .ngpio  = S5PC100_GPIO_I_NR,
+                       .label  = "GPI",
+               },
+       }, {
+               .base   = S5PC100_GPJ0_BASE,
+               .config = &gpio_cfg,
+               .chip   = {
+                       .base   = S5PC100_GPJ0(0),
+                       .ngpio  = S5PC100_GPIO_J0_NR,
+                       .label  = "GPJ0",
+               },
+       }, {
+               .base   = S5PC100_GPJ1_BASE,
+               .config = &gpio_cfg,
+               .chip   = {
+                       .base   = S5PC100_GPJ1(0),
+                       .ngpio  = S5PC100_GPIO_J1_NR,
+                       .label  = "GPJ1",
+               },
+       }, {
+               .base   = S5PC100_GPJ2_BASE,
+               .config = &gpio_cfg,
+               .chip   = {
+                       .base   = S5PC100_GPJ2(0),
+                       .ngpio  = S5PC100_GPIO_J2_NR,
+                       .label  = "GPJ2",
+               },
+       }, {
+               .base   = S5PC100_GPJ3_BASE,
+               .config = &gpio_cfg,
+               .chip   = {
+                       .base   = S5PC100_GPJ3(0),
+                       .ngpio  = S5PC100_GPIO_J3_NR,
+                       .label  = "GPJ3",
+               },
+       }, {
+               .base   = S5PC100_GPJ4_BASE,
+               .config = &gpio_cfg,
+               .chip   = {
+                       .base   = S5PC100_GPJ4(0),
+                       .ngpio  = S5PC100_GPIO_J4_NR,
+                       .label  = "GPJ4",
+               },
+       }, {
+               .base   = S5PC100_GPK0_BASE,
+               .config = &gpio_cfg_noint,
+               .chip   = {
+                       .base   = S5PC100_GPK0(0),
+                       .ngpio  = S5PC100_GPIO_K0_NR,
+                       .label  = "GPK0",
+               },
+       }, {
+               .base   = S5PC100_GPK1_BASE,
+               .config = &gpio_cfg_noint,
+               .chip   = {
+                       .base   = S5PC100_GPK1(0),
+                       .ngpio  = S5PC100_GPIO_K1_NR,
+                       .label  = "GPK1",
+               },
+       }, {
+               .base   = S5PC100_GPK2_BASE,
+               .config = &gpio_cfg_noint,
+               .chip   = {
+                       .base   = S5PC100_GPK2(0),
+                       .ngpio  = S5PC100_GPIO_K2_NR,
+                       .label  = "GPK2",
+               },
+       }, {
+               .base   = S5PC100_GPK3_BASE,
+               .config = &gpio_cfg_noint,
+               .chip   = {
+                       .base   = S5PC100_GPK3(0),
+                       .ngpio  = S5PC100_GPIO_K3_NR,
+                       .label  = "GPK3",
+               },
+       }, {
+               .base   = S5PC100_GPL0_BASE,
+               .config = &gpio_cfg_noint,
+               .chip   = {
+                       .base   = S5PC100_GPL0(0),
+                       .ngpio  = S5PC100_GPIO_L0_NR,
+                       .label  = "GPL0",
+               },
+       }, {
+               .base   = S5PC100_GPL1_BASE,
+               .config = &gpio_cfg_noint,
+               .chip   = {
+                       .base   = S5PC100_GPL1(0),
+                       .ngpio  = S5PC100_GPIO_L1_NR,
+                       .label  = "GPL1",
+               },
+       }, {
+               .base   = S5PC100_GPL2_BASE,
+               .config = &gpio_cfg_noint,
+               .chip   = {
+                       .base   = S5PC100_GPL2(0),
+                       .ngpio  = S5PC100_GPIO_L2_NR,
+                       .label  = "GPL2",
+               },
+       }, {
+               .base   = S5PC100_GPL3_BASE,
+               .config = &gpio_cfg_noint,
+               .chip   = {
+                       .base   = S5PC100_GPL3(0),
+                       .ngpio  = S5PC100_GPIO_L3_NR,
+                       .label  = "GPL3",
+               },
+       }, {
+               .base   = S5PC100_GPL4_BASE,
+               .config = &gpio_cfg_noint,
+               .chip   = {
+                       .base   = S5PC100_GPL4(0),
+                       .ngpio  = S5PC100_GPIO_L4_NR,
+                       .label  = "GPL4",
+               },
+       },
+};
+
+/* FIXME move from irq-gpio.c */
+extern struct irq_chip s5pc1xx_gpioint;
+extern void s5pc1xx_irq_gpioint_handler(unsigned int irq, struct irq_desc *desc);
+
+static __init void s5pc1xx_gpiolib_link(struct s3c_gpio_chip *chip)
+{
+       chip->chip.direction_input = s5pc1xx_gpiolib_input;
+       chip->chip.direction_output = s5pc1xx_gpiolib_output;
+       chip->pm = __gpio_pm(&s3c_gpio_pm_4bit);
+
+       /* Interrupt */
+       if (chip->config == &gpio_cfg) {
+               int i, irq;
+
+               chip->chip.to_irq = s5pc1xx_gpiolib_to_irq;
+
+               for (i = 0;  i < chip->chip.ngpio; i++) {
+                       irq = S3C_IRQ_GPIO_BASE + chip->chip.base + i;
+                       set_irq_chip(irq, &s5pc1xx_gpioint);
+                       set_irq_data(irq, &chip->chip);
+                       set_irq_handler(irq, handle_level_irq);
+                       set_irq_flags(irq, IRQF_VALID);
+               }
+       } else if (chip->config == &gpio_cfg_eint)
+               chip->chip.to_irq = s5pc1xx_gpiolib_to_eint;
+}
+
+static __init void s5pc1xx_gpiolib_add(struct s3c_gpio_chip *chips,
+                                      int nr_chips,
+                                      void (*fn)(struct s3c_gpio_chip *))
+{
+       for (; nr_chips > 0; nr_chips--, chips++) {
+               if (fn)
+                       (fn)(chips);
+               s3c_gpiolib_add(chips);
+       }
+}
+
+static __init int s5pc1xx_gpiolib_init(void)
+{
+       struct s3c_gpio_chip *chips;
+       int nr_chips;
+
+               chips = s5pc100_gpio_chips;
+               nr_chips = ARRAY_SIZE(s5pc100_gpio_chips);
+
+       s5pc1xx_gpiolib_add(chips, nr_chips, s5pc1xx_gpiolib_link);
+       /* Interrupt */
+       set_irq_chained_handler(IRQ_GPIOINT, s5pc1xx_irq_gpioint_handler);
+
+       return 0;
+}
+core_initcall(s5pc1xx_gpiolib_init);
diff --git a/arch/arm/plat-s5pc1xx/include/plat/gpio-cfg-s5pc1xx.h b/arch/arm/plat-s5pc1xx/include/plat/gpio-cfg-s5pc1xx.h
new file mode 100644 (file)
index 0000000..72ad59f
--- /dev/null
@@ -0,0 +1,32 @@
+/* linux/arch/arm/plat-s5pc1xx/include/plat/gpio-cfg.h
+ *
+ * Copyright 2009 Samsung Electronic
+ *
+ * S5PC1XX Platform - GPIO pin configuration
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+/* This file contains the necessary definitions to get the basic gpio
+ * pin configuration done such as setting a pin to input or output or
+ * changing the pull-{up,down} configurations.
+ */
+
+#ifndef __GPIO_CFG_S5PC1XX_H
+#define __GPIO_CFG_S5PC1XX_H __FILE__
+
+typedef unsigned int __bitwise__ s5p_gpio_drvstr_t;
+
+#define S5P_GPIO_DRVSTR_LV1    0x00
+#define S5P_GPIO_DRVSTR_LV2    0x01
+#define S5P_GPIO_DRVSTR_LV3    0x10
+#define S5P_GPIO_DRVSTR_LV4    0x11
+
+extern s5p_gpio_drvstr_t s5p_gpio_get_drvstr(unsigned int pin, unsigned int off);
+
+extern int s5p_gpio_set_drvstr(unsigned int pin, unsigned int off,
+                       s5p_gpio_drvstr_t drvstr);
+
+#endif /* __GPIO_CFG_S5PC1XX_H */
diff --git a/arch/arm/plat-s5pc1xx/include/plat/gpio-ext.h b/arch/arm/plat-s5pc1xx/include/plat/gpio-ext.h
new file mode 100644 (file)
index 0000000..33ad267
--- /dev/null
@@ -0,0 +1,44 @@
+/* linux/arch/arm/plat-s5pc1xx/include/plat/gpio-eint.h
+ *
+ * Copyright 2009 Samsung Electronics Co.
+ *
+ * External Interrupt (GPH0 ~ GPH3) control register definitions
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#define S5PC1XX_WKUP_INT_CON0_7                (S5PC1XX_EINT_BASE + 0x0)
+#define S5PC1XX_WKUP_INT_CON8_15       (S5PC1XX_EINT_BASE + 0x4)
+#define S5PC1XX_WKUP_INT_CON16_23      (S5PC1XX_EINT_BASE + 0x8)
+#define S5PC1XX_WKUP_INT_CON24_31      (S5PC1XX_EINT_BASE + 0xC)
+#define S5PC1XX_WKUP_INT_CON(x)                (S5PC1XX_WKUP_INT_CON0_7 + (x * 0x4))
+
+#define S5PC1XX_WKUP_INT_FLTCON0_3     (S5PC1XX_EINT_BASE + 0x80)
+#define S5PC1XX_WKUP_INT_FLTCON4_7     (S5PC1XX_EINT_BASE + 0x84)
+#define S5PC1XX_WKUP_INT_FLTCON8_11    (S5PC1XX_EINT_BASE + 0x88)
+#define S5PC1XX_WKUP_INT_FLTCON12_15   (S5PC1XX_EINT_BASE + 0x8C)
+#define S5PC1XX_WKUP_INT_FLTCON16_19   (S5PC1XX_EINT_BASE + 0x90)
+#define S5PC1XX_WKUP_INT_FLTCON20_23   (S5PC1XX_EINT_BASE + 0x94)
+#define S5PC1XX_WKUP_INT_FLTCON24_27   (S5PC1XX_EINT_BASE + 0x98)
+#define S5PC1XX_WKUP_INT_FLTCON28_31   (S5PC1XX_EINT_BASE + 0x9C)
+#define S5PC1XX_WKUP_INT_FLTCON(x)     (S5PC1XX_WKUP_INT_FLTCON0_3 + (x * 0x4))
+
+#define S5PC1XX_WKUP_INT_MASK0_7       (S5PC1XX_EINT_BASE + 0x100)
+#define S5PC1XX_WKUP_INT_MASK8_15      (S5PC1XX_EINT_BASE + 0x104)
+#define S5PC1XX_WKUP_INT_MASK16_23     (S5PC1XX_EINT_BASE + 0x108)
+#define S5PC1XX_WKUP_INT_MASK24_31     (S5PC1XX_EINT_BASE + 0x10C)
+#define S5PC1XX_WKUP_INT_MASK(x)       (S5PC1XX_WKUP_INT_MASK0_7 + (x * 0x4))
+
+#define S5PC1XX_WKUP_INT_PEND0_7       (S5PC1XX_EINT_BASE + 0x140)
+#define S5PC1XX_WKUP_INT_PEND8_15      (S5PC1XX_EINT_BASE + 0x144)
+#define S5PC1XX_WKUP_INT_PEND16_23     (S5PC1XX_EINT_BASE + 0x148)
+#define S5PC1XX_WKUP_INT_PEND24_31     (S5PC1XX_EINT_BASE + 0x14C)
+#define S5PC1XX_WKUP_INT_PEND(x)       (S5PC1XX_WKUP_INT_PEND0_7 + (x * 0x4))
+
+#define S5PC1XX_WKUP_INT_LOWLEV                (0x00)
+#define S5PC1XX_WKUP_INT_HILEV         (0x01)
+#define S5PC1XX_WKUP_INT_FALLEDGE      (0x02)
+#define S5PC1XX_WKUP_INT_RISEEDGE      (0x03)
+#define S5PC1XX_WKUP_INT_BOTHEDGE      (0x04)
index f07d8c3..ef87363 100644 (file)
 #define IRQ_SDMIRQ             S5PC1XX_IRQ_VIC2(30)
 #define IRQ_SDMFIQ             S5PC1XX_IRQ_VIC2(31)
 
+/* External interrupt */
 #define S3C_IRQ_EINT_BASE      (IRQ_SDMFIQ + 1)
 
-#define S3C_EINT(x)            ((x) + S3C_IRQ_EINT_BASE)
-#define IRQ_EINT(x)            S3C_EINT(x)
+#define S3C_EINT(x)            (S3C_IRQ_EINT_BASE + (x - 16))
+#define IRQ_EINT(x)            (x < 16 ? IRQ_EINT0 + x : S3C_EINT(x))
+#define IRQ_EINT_BIT(x)                (x < IRQ_EINT16_31 ? x - IRQ_EINT0 : x - S3C_EINT(0))
 
-#define NR_IRQS                (IRQ_EINT(31)+1)
+/* GPIO interrupt */
+#define S3C_IRQ_GPIO_BASE      (IRQ_EINT(31) + 1)
+#define S3C_IRQ_GPIO(x)                (S3C_IRQ_GPIO_BASE + (x))
+
+/*
+ * Until MP04 Groups -> 40 (exactly 39) Groups * 8 ~= 320 GPIOs
+ */
+#define NR_IRQS                        (S3C_IRQ_GPIO(320) + 1)
 
 #endif /* __ASM_PLAT_S5PC1XX_IRQS_H */
 
index 75c8390..c5cc86e 100644 (file)
 #ifndef __PLAT_REGS_CLOCK_H
 #define __PLAT_REGS_CLOCK_H __FILE__
 
-#define S5PC1XX_CLKREG(x)              (S5PC1XX_VA_CLK + (x))
-
-#define S5PC1XX_APLL_LOCK              S5PC1XX_CLKREG(0x00)
-#define S5PC1XX_MPLL_LOCK              S5PC1XX_CLKREG(0x04)
-#define S5PC1XX_EPLL_LOCK              S5PC1XX_CLKREG(0x08)
-#define S5PC100_HPLL_LOCK              S5PC1XX_CLKREG(0x0C)
-
-#define S5PC1XX_APLL_CON               S5PC1XX_CLKREG(0x100)
-#define S5PC1XX_MPLL_CON               S5PC1XX_CLKREG(0x104)
-#define S5PC1XX_EPLL_CON               S5PC1XX_CLKREG(0x108)
-#define S5PC100_HPLL_CON               S5PC1XX_CLKREG(0x10C)
-
-#define S5PC1XX_CLK_SRC0               S5PC1XX_CLKREG(0x200)
-#define S5PC1XX_CLK_SRC1               S5PC1XX_CLKREG(0x204)
-#define S5PC1XX_CLK_SRC2               S5PC1XX_CLKREG(0x208)
-#define S5PC1XX_CLK_SRC3               S5PC1XX_CLKREG(0x20C)
-
-#define S5PC1XX_CLK_DIV0               S5PC1XX_CLKREG(0x300)
-#define S5PC1XX_CLK_DIV1               S5PC1XX_CLKREG(0x304)
-#define S5PC1XX_CLK_DIV2               S5PC1XX_CLKREG(0x308)
-#define S5PC1XX_CLK_DIV3               S5PC1XX_CLKREG(0x30C)
-#define S5PC1XX_CLK_DIV4               S5PC1XX_CLKREG(0x310)
-
-#define S5PC100_CLK_OUT                        S5PC1XX_CLKREG(0x400)
-
-#define S5PC100_CLKGATE_D00            S5PC1XX_CLKREG(0x500)
-#define S5PC100_CLKGATE_D01            S5PC1XX_CLKREG(0x504)
-#define S5PC100_CLKGATE_D02            S5PC1XX_CLKREG(0x508)
-
-#define S5PC100_CLKGATE_D10            S5PC1XX_CLKREG(0x520)
-#define S5PC100_CLKGATE_D11            S5PC1XX_CLKREG(0x524)
-#define S5PC100_CLKGATE_D12            S5PC1XX_CLKREG(0x528)
-#define S5PC100_CLKGATE_D13            S5PC1XX_CLKREG(0x52C)
-#define S5PC100_CLKGATE_D14            S5PC1XX_CLKREG(0x530)
-#define S5PC100_CLKGATE_D15            S5PC1XX_CLKREG(0x534)
-
-#define S5PC100_CLKGATE_D20            S5PC1XX_CLKREG(0x540)
-
-#define S5PC100_SCLKGATE0              S5PC1XX_CLKREG(0x560)
-#define S5PC100_SCLKGATE1              S5PC1XX_CLKREG(0x564)
-
-#define S5PC100_OTHERS          S5PC1XX_CLKREG(0x8200)
-
-#define S5PC1XX_EPLL_EN     (1<<31)
-#define S5PC1XX_EPLL_MASK   0xffffffff
-#define S5PC1XX_EPLLVAL(_m, _p, _s)   ((_m) << 16 | ((_p) << 8) | ((_s)))
+#define S5PC100_CLKREG(x)              (S5PC1XX_VA_CLK + (x))
+#define S5PC100_CLKREG_OTHER(x)                (S5PC1XX_VA_CLK_OTHER + (x))
+
+/* s5pc100 register for clock */
+#define S5PC100_APLL_LOCK              S5PC100_CLKREG(0x00)
+#define S5PC100_MPLL_LOCK              S5PC100_CLKREG(0x04)
+#define S5PC100_EPLL_LOCK              S5PC100_CLKREG(0x08)
+#define S5PC100_HPLL_LOCK              S5PC100_CLKREG(0x0C)
+
+#define S5PC100_APLL_CON               S5PC100_CLKREG(0x100)
+#define S5PC100_MPLL_CON               S5PC100_CLKREG(0x104)
+#define S5PC100_EPLL_CON               S5PC100_CLKREG(0x108)
+#define S5PC100_HPLL_CON               S5PC100_CLKREG(0x10C)
+
+#define S5PC100_CLKSRC0                        S5PC100_CLKREG(0x200)
+#define S5PC100_CLKSRC1                        S5PC100_CLKREG(0x204)
+#define S5PC100_CLKSRC2                        S5PC100_CLKREG(0x208)
+#define S5PC100_CLKSRC3                        S5PC100_CLKREG(0x20C)
+
+#define S5PC100_CLKDIV0                        S5PC100_CLKREG(0x300)
+#define S5PC100_CLKDIV1                        S5PC100_CLKREG(0x304)
+#define S5PC100_CLKDIV2                        S5PC100_CLKREG(0x308)
+#define S5PC100_CLKDIV3                        S5PC100_CLKREG(0x30C)
+#define S5PC100_CLKDIV4                        S5PC100_CLKREG(0x310)
+
+#define S5PC100_CLK_OUT                        S5PC100_CLKREG(0x400)
+
+#define S5PC100_CLKGATE_D00            S5PC100_CLKREG(0x500)
+#define S5PC100_CLKGATE_D01            S5PC100_CLKREG(0x504)
+#define S5PC100_CLKGATE_D02            S5PC100_CLKREG(0x508)
+
+#define S5PC100_CLKGATE_D10            S5PC100_CLKREG(0x520)
+#define S5PC100_CLKGATE_D11            S5PC100_CLKREG(0x524)
+#define S5PC100_CLKGATE_D12            S5PC100_CLKREG(0x528)
+#define S5PC100_CLKGATE_D13            S5PC100_CLKREG(0x52C)
+#define S5PC100_CLKGATE_D14            S5PC100_CLKREG(0x530)
+#define S5PC100_CLKGATE_D15            S5PC100_CLKREG(0x534)
+
+#define S5PC100_CLKGATE_D20            S5PC100_CLKREG(0x540)
+
+#define S5PC100_SCLKGATE0              S5PC100_CLKREG(0x560)
+#define S5PC100_SCLKGATE1              S5PC100_CLKREG(0x564)
+
+/* EPLL_CON */
+#define S5PC100_EPLL_EN                        (1<<31)
+#define S5PC100_EPLL_MASK              0xffffffff
+#define S5PC100_EPLLVAL(_m, _p, _s)    ((_m) << 16 | ((_p) << 8) | ((_s)))
 
 /* CLKSRC0 */
-#define S5PC1XX_CLKSRC0_APLL_MASK              (0x1<<0)
-#define S5PC1XX_CLKSRC0_APLL_SHIFT             (0)
-#define S5PC1XX_CLKSRC0_MPLL_MASK              (0x1<<4)
-#define S5PC1XX_CLKSRC0_MPLL_SHIFT             (4)
-#define S5PC1XX_CLKSRC0_EPLL_MASK              (0x1<<8)
-#define S5PC1XX_CLKSRC0_EPLL_SHIFT             (8)
+#define S5PC100_CLKSRC0_APLL_MASK              (0x1<<0)
+#define S5PC100_CLKSRC0_APLL_SHIFT             (0)
+#define S5PC100_CLKSRC0_MPLL_MASK              (0x1<<4)
+#define S5PC100_CLKSRC0_MPLL_SHIFT             (4)
+#define S5PC100_CLKSRC0_EPLL_MASK              (0x1<<8)
+#define S5PC100_CLKSRC0_EPLL_SHIFT             (8)
 #define S5PC100_CLKSRC0_HPLL_MASK              (0x1<<12)
 #define S5PC100_CLKSRC0_HPLL_SHIFT             (12)
 #define S5PC100_CLKSRC0_AMMUX_MASK             (0x1<<16)
 #define S5PC100_CLKSRC0_AMMUX_SHIFT            (16)
 #define S5PC100_CLKSRC0_HREF_MASK              (0x1<<20)
 #define S5PC100_CLKSRC0_HREF_SHIFT             (20)
-#define S5PC1XX_CLKSRC0_ONENAND_MASK   (0x1<<24)
-#define S5PC1XX_CLKSRC0_ONENAND_SHIFT  (24)
+#define S5PC100_CLKSRC0_ONENAND_MASK   (0x1<<24)
+#define S5PC100_CLKSRC0_ONENAND_SHIFT  (24)
 
 
 /* CLKSRC1 */
 #define S5PC100_CLKSRC3_SPDIF_MASK             (0x3<<24)
 #define S5PC100_CLKSRC3_SPDIF_SHIFT            (24)
 
-
 /* CLKDIV0 */
-#define S5PC1XX_CLKDIV0_APLL_MASK              (0x1<<0)
-#define S5PC1XX_CLKDIV0_APLL_SHIFT             (0)
+#define S5PC100_CLKDIV0_APLL_MASK              (0x1<<0)
+#define S5PC100_CLKDIV0_APLL_SHIFT             (0)
 #define S5PC100_CLKDIV0_ARM_MASK               (0x7<<4)
 #define S5PC100_CLKDIV0_ARM_SHIFT              (4)
 #define S5PC100_CLKDIV0_D0_MASK                (0x7<<8)
 #define S5PC100_CLKDIV0_SECSS_SHIFT            (16)
 
 /* CLKDIV1 */
-#define S5PC100_CLKDIV1_AM_MASK                (0x7<<0)
-#define S5PC100_CLKDIV1_AM_SHIFT               (0)
+#define S5PC100_CLKDIV1_APLL2_MASK             (0x7<<0)
+#define S5PC100_CLKDIV1_APLL2_SHIFT            (0)
 #define S5PC100_CLKDIV1_MPLL_MASK              (0x3<<4)
 #define S5PC100_CLKDIV1_MPLL_SHIFT             (4)
 #define S5PC100_CLKDIV1_MPLL2_MASK             (0x1<<8)
 #define S5PC100_CLKDIV4_AUDIO2_MASK            (0xf<<20)
 #define S5PC100_CLKDIV4_AUDIO2_SHIFT   (20)
 
-
 /* HCLKD0/PCLKD0 Clock Gate 0 Registers */
 #define S5PC100_CLKGATE_D00_INTC               (1<<0)
 #define S5PC100_CLKGATE_D00_TZIC               (1<<1)
 #define S5PC100_CLKGATE_D20_I2SD2              (1<<1)
 
 /* Special Clock Gate 0 Registers */
-#define        S5PC1XX_CLKGATE_SCLK0_HPM               (1<<0)
-#define        S5PC1XX_CLKGATE_SCLK0_PWI               (1<<1)
+#define        S5PC100_CLKGATE_SCLK0_HPM               (1<<0)
+#define        S5PC100_CLKGATE_SCLK0_PWI               (1<<1)
 #define        S5PC100_CLKGATE_SCLK0_ONENAND   (1<<2)
 #define        S5PC100_CLKGATE_SCLK0_UART              (1<<3)
 #define        S5PC100_CLKGATE_SCLK0_SPI0              (1<<4)
 #define        S5PC100_CLKGATE_SCLK1_SPDIF             (1<<11)
 #define        S5PC100_CLKGATE_SCLK1_CAM               (1<<12)
 
-/* register for power management */
-#define S5PC100_PWR_CFG                S5PC1XX_CLKREG(0x8000)
-#define S5PC100_EINT_WAKEUP_MASK       S5PC1XX_CLKREG(0x8004)
-#define S5PC100_NORMAL_CFG             S5PC1XX_CLKREG(0x8010)
-#define S5PC100_STOP_CFG               S5PC1XX_CLKREG(0x8014)
-#define S5PC100_SLEEP_CFG              S5PC1XX_CLKREG(0x8018)
-#define S5PC100_STOP_MEM_CFG   S5PC1XX_CLKREG(0x801C)
-#define S5PC100_OSC_FREQ               S5PC1XX_CLKREG(0x8100)
-#define S5PC100_OSC_STABLE             S5PC1XX_CLKREG(0x8104)
-#define S5PC100_PWR_STABLE             S5PC1XX_CLKREG(0x8108)
-#define S5PC100_MTC_STABLE             S5PC1XX_CLKREG(0x8110)
-#define S5PC100_CLAMP_STABLE   S5PC1XX_CLKREG(0x8114)
-#define S5PC100_OTHERS                 S5PC1XX_CLKREG(0x8200)
-#define S5PC100_RST_STAT               S5PC1XX_CLKREG(0x8300)
-#define S5PC100_WAKEUP_STAT    S5PC1XX_CLKREG(0x8304)
-#define S5PC100_BLK_PWR_STAT   S5PC1XX_CLKREG(0x8308)
-#define S5PC100_INFORM0                S5PC1XX_CLKREG(0x8400)
-#define S5PC100_INFORM1                S5PC1XX_CLKREG(0x8404)
-#define S5PC100_INFORM2                S5PC1XX_CLKREG(0x8408)
-#define S5PC100_INFORM3                S5PC1XX_CLKREG(0x840C)
-#define S5PC100_INFORM4                S5PC1XX_CLKREG(0x8410)
-#define S5PC100_INFORM5                S5PC1XX_CLKREG(0x8414)
-#define S5PC100_INFORM6                S5PC1XX_CLKREG(0x8418)
-#define S5PC100_INFORM7                S5PC1XX_CLKREG(0x841C)
-#define S5PC100_DCGIDX_MAP0    S5PC1XX_CLKREG(0x8500)
-#define S5PC100_DCGIDX_MAP1    S5PC1XX_CLKREG(0x8504)
-#define S5PC100_DCGIDX_MAP2    S5PC1XX_CLKREG(0x8508)
-#define S5PC100_DCGPERF_MAP0   S5PC1XX_CLKREG(0x850C)
-#define S5PC100_DCGPERF_MAP1   S5PC1XX_CLKREG(0x8510)
-#define S5PC100_DVCIDX_MAP             S5PC1XX_CLKREG(0x8514)
-#define S5PC100_FREQ_CPU               S5PC1XX_CLKREG(0x8518)
-#define S5PC100_FREQ_DPM               S5PC1XX_CLKREG(0x851C)
-#define S5PC100_DVSEMCLK_EN    S5PC1XX_CLKREG(0x8520)
-#define S5PC100_APLL_CON_L8    S5PC1XX_CLKREG(0x8600)
-#define S5PC100_APLL_CON_L7    S5PC1XX_CLKREG(0x8604)
-#define S5PC100_APLL_CON_L6    S5PC1XX_CLKREG(0x8608)
-#define S5PC100_APLL_CON_L5    S5PC1XX_CLKREG(0x860C)
-#define S5PC100_APLL_CON_L4    S5PC1XX_CLKREG(0x8610)
-#define S5PC100_APLL_CON_L3    S5PC1XX_CLKREG(0x8614)
-#define S5PC100_APLL_CON_L2    S5PC1XX_CLKREG(0x8618)
-#define S5PC100_APLL_CON_L1    S5PC1XX_CLKREG(0x861C)
-#define S5PC100_IEM_CONTROL    S5PC1XX_CLKREG(0x8620)
-#define S5PC100_CLKDIV_IEM_L8  S5PC1XX_CLKREG(0x8700)
-#define S5PC100_CLKDIV_IEM_L7  S5PC1XX_CLKREG(0x8704)
-#define S5PC100_CLKDIV_IEM_L6  S5PC1XX_CLKREG(0x8708)
-#define S5PC100_CLKDIV_IEM_L5  S5PC1XX_CLKREG(0x870C)
-#define S5PC100_CLKDIV_IEM_L4  S5PC1XX_CLKREG(0x8710)
-#define S5PC100_CLKDIV_IEM_L3  S5PC1XX_CLKREG(0x8714)
-#define S5PC100_CLKDIV_IEM_L2  S5PC1XX_CLKREG(0x8718)
-#define S5PC100_CLKDIV_IEM_L1  S5PC1XX_CLKREG(0x871C)
-#define S5PC100_IEM_HPMCLK_DIV         S5PC1XX_CLKREG(0x8724)
-
-#define S5PC100_SWRESET                S5PC1XX_CLKREG(0x100000)
-#define S5PC100_OND_SWRESET            S5PC1XX_CLKREG(0x100008)
-#define S5PC100_GEN_CTRL               S5PC1XX_CLKREG(0x100100)
-#define S5PC100_GEN_STATUS             S5PC1XX_CLKREG(0x100104)
-#define S5PC100_MEM_SYS_CFG            S5PC1XX_CLKREG(0x100200)
-#define S5PC100_CAM_MUX_SEL            S5PC1XX_CLKREG(0x100300)
-#define S5PC100_MIXER_OUT_SEL  S5PC1XX_CLKREG(0x100304)
-#define S5PC100_LPMP_MODE_SEL  S5PC1XX_CLKREG(0x100308)
-#define S5PC100_MIPI_PHY_CON0  S5PC1XX_CLKREG(0x100400)
-#define S5PC100_MIPI_PHY_CON1  S5PC1XX_CLKREG(0x100414)
-#define S5PC100_HDMI_PHY_CON0  S5PC1XX_CLKREG(0x100420)
-
-#define S5PC100_CFG_WFI_CLEAN  (~(3<<5))
-#define S5PC100_CFG_WFI_IDLE   (1<<5)
-#define S5PC100_CFG_WFI_STOP   (2<<5)
-#define S5PC100_CFG_WFI_SLEEP  (3<<5)
-
+#define S5PC100_SWRESET                S5PC100_CLKREG_OTHER(0x000)
+#define S5PC100_OND_SWRESET    S5PC100_CLKREG_OTHER(0x008)
+#define S5PC100_GEN_CTRL       S5PC100_CLKREG_OTHER(0x100)
+#define S5PC100_GEN_STATUS     S5PC100_CLKREG_OTHER(0x104)
+#define S5PC100_MEM_SYS_CFG    S5PC100_CLKREG_OTHER(0x200)
+#define S5PC100_CAM_MUX_SEL    S5PC100_CLKREG_OTHER(0x300)
+#define S5PC100_MIXER_OUT_SEL  S5PC100_CLKREG_OTHER(0x304)
+#define S5PC100_LPMP_MODE_SEL  S5PC100_CLKREG_OTHER(0x308)
+#define S5PC100_MIPI_PHY_CON0  S5PC100_CLKREG_OTHER(0x400)
+#define S5PC100_MIPI_PHY_CON1  S5PC100_CLKREG_OTHER(0x414)
+#define S5PC100_HDMI_PHY_CON0  S5PC100_CLKREG_OTHER(0x420)
+
+#define S5PC100_SWRESET_RESETVAL       0xc100
 #define S5PC100_OTHER_SYS_INT  24
 #define S5PC100_OTHER_STA_TYPE 23
 #define STA_TYPE_EXPON         0
 #define STA_TYPE_SFR           1
 
-#define S5PC100_PWR_STA_EXP_SCALE      0
-#define S5PC100_PWR_STA_CNT            4
-
-#define S5PC100_PWR_STABLE_COUNT       85500
-
 #define S5PC100_SLEEP_CFG_OSC_EN       0
 
 /* OTHERS Resgister */
-#define S5PC100_OTHERS_USB_SIG_MASK    (1 << 16)
+#define S5PC100_OTHERS_USB_SIG_MASK    (1 << 16)
 #define S5PC100_OTHERS_MIPI_DPHY_EN            (1 << 28)
 
 /* MIPI D-PHY Control Register 0 */
diff --git a/arch/arm/plat-s5pc1xx/include/plat/regs-gpio.h b/arch/arm/plat-s5pc1xx/include/plat/regs-gpio.h
new file mode 100644 (file)
index 0000000..43c7bc8
--- /dev/null
@@ -0,0 +1,70 @@
+/* linux/arch/arm/plat-s5pc1xx/include/plat/regs-gpio.h
+ *
+ * Copyright 2009 Samsung Electronics Co.
+ *      Byungho Min <bhmin@samsung.com>
+ *
+ * S5PC1XX - GPIO register definitions
+ */
+
+#ifndef __ASM_PLAT_S5PC1XX_REGS_GPIO_H
+#define __ASM_PLAT_S5PC1XX_REGS_GPIO_H __FILE__
+
+#include <mach/map.h>
+
+/* S5PC100 */
+#define S5PC100_GPIO_BASE      S5PC1XX_VA_GPIO
+#define S5PC100_GPA0_BASE      (S5PC100_GPIO_BASE + 0x0000)
+#define S5PC100_GPA1_BASE      (S5PC100_GPIO_BASE + 0x0020)
+#define S5PC100_GPB_BASE       (S5PC100_GPIO_BASE + 0x0040)
+#define S5PC100_GPC_BASE       (S5PC100_GPIO_BASE + 0x0060)
+#define S5PC100_GPD_BASE       (S5PC100_GPIO_BASE + 0x0080)
+#define S5PC100_GPE0_BASE      (S5PC100_GPIO_BASE + 0x00A0)
+#define S5PC100_GPE1_BASE      (S5PC100_GPIO_BASE + 0x00C0)
+#define S5PC100_GPF0_BASE      (S5PC100_GPIO_BASE + 0x00E0)
+#define S5PC100_GPF1_BASE      (S5PC100_GPIO_BASE + 0x0100)
+#define S5PC100_GPF2_BASE      (S5PC100_GPIO_BASE + 0x0120)
+#define S5PC100_GPF3_BASE      (S5PC100_GPIO_BASE + 0x0140)
+#define S5PC100_GPG0_BASE      (S5PC100_GPIO_BASE + 0x0160)
+#define S5PC100_GPG1_BASE      (S5PC100_GPIO_BASE + 0x0180)
+#define S5PC100_GPG2_BASE      (S5PC100_GPIO_BASE + 0x01A0)
+#define S5PC100_GPG3_BASE      (S5PC100_GPIO_BASE + 0x01C0)
+#define S5PC100_GPH0_BASE      (S5PC100_GPIO_BASE + 0x0C00)
+#define S5PC100_GPH1_BASE      (S5PC100_GPIO_BASE + 0x0C20)
+#define S5PC100_GPH2_BASE      (S5PC100_GPIO_BASE + 0x0C40)
+#define S5PC100_GPH3_BASE      (S5PC100_GPIO_BASE + 0x0C60)
+#define S5PC100_GPI_BASE       (S5PC100_GPIO_BASE + 0x01E0)
+#define S5PC100_GPJ0_BASE      (S5PC100_GPIO_BASE + 0x0200)
+#define S5PC100_GPJ1_BASE      (S5PC100_GPIO_BASE + 0x0220)
+#define S5PC100_GPJ2_BASE      (S5PC100_GPIO_BASE + 0x0240)
+#define S5PC100_GPJ3_BASE      (S5PC100_GPIO_BASE + 0x0260)
+#define S5PC100_GPJ4_BASE      (S5PC100_GPIO_BASE + 0x0280)
+#define S5PC100_GPK0_BASE      (S5PC100_GPIO_BASE + 0x02A0)
+#define S5PC100_GPK1_BASE      (S5PC100_GPIO_BASE + 0x02C0)
+#define S5PC100_GPK2_BASE      (S5PC100_GPIO_BASE + 0x02E0)
+#define S5PC100_GPK3_BASE      (S5PC100_GPIO_BASE + 0x0300)
+#define S5PC100_GPL0_BASE      (S5PC100_GPIO_BASE + 0x0320)
+#define S5PC100_GPL1_BASE      (S5PC100_GPIO_BASE + 0x0340)
+#define S5PC100_GPL2_BASE      (S5PC100_GPIO_BASE + 0x0360)
+#define S5PC100_GPL3_BASE      (S5PC100_GPIO_BASE + 0x0380)
+#define S5PC100_GPL4_BASE      (S5PC100_GPIO_BASE + 0x03A0)
+#define S5PC100_EINT_BASE      (S5PC100_GPIO_BASE + 0x0E00)
+
+#define S5PC100_UHOST          (S5PC100_GPIO_BASE + 0x0B68)
+#define S5PC100_PDNEN          (S5PC100_GPIO_BASE + 0x0F80)
+
+/* PDNEN */
+#define S5PC100_PDNEN_CFG_PDNEN        (1 << 1)
+#define S5PC100_PDNEN_CFG_AUTO (0 << 1)
+#define S5PC100_PDNEN_POWERDOWN        (1 << 0)
+#define S5PC100_PDNEN_NORMAL   (0 << 0)
+
+/* Common part */
+/* External interrupt base is same at both s5pc100 and s5pc110 */
+#define S5PC1XX_EINT_BASE      (S5PC100_EINT_BASE)
+
+#define S5PC100_GPx_INPUT(__gpio)      (0x0 << ((__gpio) * 4))
+#define S5PC100_GPx_OUTPUT(__gpio)     (0x1 << ((__gpio) * 4))
+#define S5PC100_GPx_CONMASK(__gpio)    (0xf << ((__gpio) * 4))
+
+#endif /* __ASM_PLAT_S5PC1XX_REGS_GPIO_H */
+
diff --git a/arch/arm/plat-s5pc1xx/include/plat/regs-power.h b/arch/arm/plat-s5pc1xx/include/plat/regs-power.h
new file mode 100644 (file)
index 0000000..02ffa49
--- /dev/null
@@ -0,0 +1,84 @@
+/* arch/arm/plat-s5pc1xx/include/plat/regs-clock.h
+ *
+ * Copyright 2009 Samsung Electronics Co.
+ *     Jongse Won <jongse.won@samsung.com>
+ *
+ * S5PC1XX clock register definitions
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#ifndef __ASM_ARM_REGS_PWR
+#define __ASM_ARM_REGS_PWR __FILE__
+
+#define S5PC1XX_PWRREG(x)                      (S5PC1XX_VA_PWR + (x))
+
+/* s5pc100 (0xE0108000) register for power management */
+#define S5PC100_PWR_CFG                                S5PC1XX_PWRREG(0x0)
+#define S5PC100_EINT_WAKEUP_MASK               S5PC1XX_PWRREG(0x4)
+#define S5PC100_NORMAL_CFG                     S5PC1XX_PWRREG(0x10)
+#define S5PC100_STOP_CFG                       S5PC1XX_PWRREG(0x14)
+#define S5PC100_SLEEP_CFG                      S5PC1XX_PWRREG(0x18)
+#define S5PC100_STOP_MEM_CFG                   S5PC1XX_PWRREG(0x1C)
+#define S5PC100_OSC_FREQ                       S5PC1XX_PWRREG(0x100)
+#define S5PC100_OSC_STABLE                     S5PC1XX_PWRREG(0x104)
+#define S5PC100_PWR_STABLE                     S5PC1XX_PWRREG(0x108)
+#define S5PC100_MTC_STABLE                     S5PC1XX_PWRREG(0x110)
+#define S5PC100_CLAMP_STABLE                   S5PC1XX_PWRREG(0x114)
+#define S5PC100_OTHERS                         S5PC1XX_PWRREG(0x200)
+#define S5PC100_RST_STAT                       S5PC1XX_PWRREG(0x300)
+#define S5PC100_WAKEUP_STAT                    S5PC1XX_PWRREG(0x304)
+#define S5PC100_BLK_PWR_STAT                   S5PC1XX_PWRREG(0x308)
+#define S5PC100_INFORM0                                S5PC1XX_PWRREG(0x400)
+#define S5PC100_INFORM1                                S5PC1XX_PWRREG(0x404)
+#define S5PC100_INFORM2                                S5PC1XX_PWRREG(0x408)
+#define S5PC100_INFORM3                                S5PC1XX_PWRREG(0x40C)
+#define S5PC100_INFORM4                                S5PC1XX_PWRREG(0x410)
+#define S5PC100_INFORM5                                S5PC1XX_PWRREG(0x414)
+#define S5PC100_INFORM6                                S5PC1XX_PWRREG(0x418)
+#define S5PC100_INFORM7                                S5PC1XX_PWRREG(0x41C)
+#define S5PC100_DCGIDX_MAP0                    S5PC1XX_PWRREG(0x500)
+#define S5PC100_DCGIDX_MAP1                    S5PC1XX_PWRREG(0x504)
+#define S5PC100_DCGIDX_MAP2                    S5PC1XX_PWRREG(0x508)
+#define S5PC100_DCGPERF_MAP0                   S5PC1XX_PWRREG(0x50C)
+#define S5PC100_DCGPERF_MAP1                   S5PC1XX_PWRREG(0x510)
+#define S5PC100_DVCIDX_MAP                     S5PC1XX_PWRREG(0x514)
+#define S5PC100_FREQ_CPU                       S5PC1XX_PWRREG(0x518)
+#define S5PC100_FREQ_DPM                       S5PC1XX_PWRREG(0x51C)
+#define S5PC100_DVSEMCLK_EN                    S5PC1XX_PWRREG(0x520)
+#define S5PC100_APLL_CON_L8                    S5PC1XX_PWRREG(0x600)
+#define S5PC100_APLL_CON_L7                    S5PC1XX_PWRREG(0x604)
+#define S5PC100_APLL_CON_L6                    S5PC1XX_PWRREG(0x608)
+#define S5PC100_APLL_CON_L5                    S5PC1XX_PWRREG(0x60C)
+#define S5PC100_APLL_CON_L4                    S5PC1XX_PWRREG(0x610)
+#define S5PC100_APLL_CON_L3                    S5PC1XX_PWRREG(0x614)
+#define S5PC100_APLL_CON_L2                    S5PC1XX_PWRREG(0x618)
+#define S5PC100_APLL_CON_L1                    S5PC1XX_PWRREG(0x61C)
+#define S5PC100_IEM_CONTROL                    S5PC1XX_PWRREG(0x620)
+#define S5PC100_CLKDIV_IEM_L8                  S5PC1XX_PWRREG(0x700)
+#define S5PC100_CLKDIV_IEM_L7                  S5PC1XX_PWRREG(0x704)
+#define S5PC100_CLKDIV_IEM_L6                  S5PC1XX_PWRREG(0x708)
+#define S5PC100_CLKDIV_IEM_L5                  S5PC1XX_PWRREG(0x70C)
+#define S5PC100_CLKDIV_IEM_L4                  S5PC1XX_PWRREG(0x710)
+#define S5PC100_CLKDIV_IEM_L3                  S5PC1XX_PWRREG(0x714)
+#define S5PC100_CLKDIV_IEM_L2                  S5PC1XX_PWRREG(0x718)
+#define S5PC100_CLKDIV_IEM_L1                  S5PC1XX_PWRREG(0x71C)
+#define S5PC100_IEM_HPMCLK_DIV                 S5PC1XX_PWRREG(0x724)
+
+/* PWR_CFG */
+#define S5PC100_PWRCFG_CFG_DEEP_IDLE           (1 << 31)
+#define S5PC100_PWRCFG_CFG_WFI_MASK            (3 << 5)
+#define S5PC100_PWRCFG_CFG_WFI_IDLE            (0 << 5)
+#define S5PC100_PWRCFG_CFG_WFI_DEEP_IDLE       (1 << 5)
+#define S5PC100_PWRCFG_CFG_WFI_STOP            (2 << 5)
+#define S5PC100_PWRCFG_CFG_WFI_SLEEP           (3 << 5)
+
+/* SLEEP_CFG */
+#define S5PC100_SLEEP_OSC_EN_SLEEP             (1 << 0)
+
+/* OTHERS */
+#define S5PC100_PMU_INT_DISABLE                        (1 << 24)
+
+#endif /* __ASM_ARM_REGS_PWR */
index 45e2751..2531f34 100644 (file)
@@ -35,10 +35,9 @@ extern struct clk clk_hpll;
 extern struct clk clk_hd0;
 extern struct clk clk_pd0;
 extern struct clk clk_54m;
-extern struct clk clk_dout_mpll2;
 extern void s5pc1xx_register_clocks(void);
-extern int s5pc1xx_sclk0_ctrl(struct clk *clk, int enable);
-extern int s5pc1xx_sclk1_ctrl(struct clk *clk, int enable);
+extern int s5pc100_sclk0_ctrl(struct clk *clk, int enable);
+extern int s5pc100_sclk1_ctrl(struct clk *clk, int enable);
 
 /* Some day, belows will be moved to plat-s5pc/include/plat/devs.h */
 extern struct s3c24xx_uart_resources s5pc1xx_uart_resources[];
diff --git a/arch/arm/plat-s5pc1xx/irq-eint.c b/arch/arm/plat-s5pc1xx/irq-eint.c
new file mode 100644 (file)
index 0000000..373122f
--- /dev/null
@@ -0,0 +1,281 @@
+/*
+ * linux/arch/arm/plat-s5pc1xx/irq-eint.c
+ *
+ *  Copyright 2009 Samsung Electronics Co.
+ *  Byungho Min <bhmin@samsung.com>
+ *  Kyungin Park <kyungmin.park@samsung.com>
+ *
+ * Based on plat-s3c64xx/irq-eint.c
+ *
+ * S5PC1XX - Interrupt handling for IRQ_EINT(x)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/io.h>
+#include <linux/sysdev.h>
+#include <linux/pm.h>
+#include <linux/gpio.h>
+
+#include <asm/hardware/vic.h>
+
+#include <mach/map.h>
+
+#include <plat/gpio-cfg.h>
+#include <plat/gpio-ext.h>
+#include <plat/pm.h>
+#include <plat/regs-gpio.h>
+#include <plat/regs-irqtype.h>
+
+/*
+ * bank is a group of external interrupt
+ * bank0 means EINT0 ... EINT7
+ * bank1 means EINT8 ... EINT15
+ * bank2 means EINT16 ... EINT23
+ * bank3 means EINT24 ... EINT31
+ */
+
+static inline int s3c_get_eint(unsigned int irq)
+{
+       int real;
+
+       if (irq < IRQ_EINT16_31)
+               real = (irq - IRQ_EINT0);
+       else
+               real = (irq - S3C_IRQ_EINT_BASE) + IRQ_EINT16_31 - IRQ_EINT0;
+
+       return real;
+}
+
+static inline int s3c_get_bank(unsigned int irq)
+{
+       return s3c_get_eint(irq) >> 3;
+}
+
+static inline int s3c_eint_to_bit(unsigned int irq)
+{
+       int real, bit;
+
+       real = s3c_get_eint(irq);
+       bit = 1 << (real & (8 - 1));
+
+       return bit;
+}
+
+static inline void s3c_irq_eint_mask(unsigned int irq)
+{
+       u32 mask;
+       u32 bank = s3c_get_bank(irq);
+
+       mask = __raw_readl(S5PC1XX_WKUP_INT_MASK(bank));
+       mask |= s3c_eint_to_bit(irq);
+       __raw_writel(mask, S5PC1XX_WKUP_INT_MASK(bank));
+}
+
+static void s3c_irq_eint_unmask(unsigned int irq)
+{
+       u32 mask;
+       u32 bank = s3c_get_bank(irq);
+
+       mask = __raw_readl(S5PC1XX_WKUP_INT_MASK(bank));
+       mask &= ~(s3c_eint_to_bit(irq));
+       __raw_writel(mask, S5PC1XX_WKUP_INT_MASK(bank));
+}
+
+static inline void s3c_irq_eint_ack(unsigned int irq)
+{
+       u32 bank = s3c_get_bank(irq);
+
+       __raw_writel(s3c_eint_to_bit(irq), S5PC1XX_WKUP_INT_PEND(bank));
+}
+
+static void s3c_irq_eint_maskack(unsigned int irq)
+{
+       /* compiler should in-line these */
+       s3c_irq_eint_mask(irq);
+       s3c_irq_eint_ack(irq);
+}
+
+static int s3c_irq_eint_set_type(unsigned int irq, unsigned int type)
+{
+       u32 bank = s3c_get_bank(irq);
+       int real = s3c_get_eint(irq);
+       int gpio, shift, sfn;
+       u32 ctrl, con = 0;
+
+       switch (type) {
+       case IRQ_TYPE_NONE:
+               printk(KERN_WARNING "No edge setting!\n");
+               break;
+
+       case IRQ_TYPE_EDGE_RISING:
+               con = S5PC1XX_WKUP_INT_RISEEDGE;
+               break;
+
+       case IRQ_TYPE_EDGE_FALLING:
+               con = S5PC1XX_WKUP_INT_FALLEDGE;
+               break;
+
+       case IRQ_TYPE_EDGE_BOTH:
+               con = S5PC1XX_WKUP_INT_BOTHEDGE;
+               break;
+
+       case IRQ_TYPE_LEVEL_LOW:
+               con = S5PC1XX_WKUP_INT_LOWLEV;
+               break;
+
+       case IRQ_TYPE_LEVEL_HIGH:
+               con = S5PC1XX_WKUP_INT_HILEV;
+               break;
+
+       default:
+               printk(KERN_ERR "No such irq type %d", type);
+               return -EINVAL;
+       }
+
+       gpio = real & (8 - 1);
+       shift = gpio << 2;
+
+       ctrl = __raw_readl(S5PC1XX_WKUP_INT_CON(bank));
+       ctrl &= ~(0x7 << shift);
+       ctrl |= con << shift;
+       __raw_writel(ctrl, S5PC1XX_WKUP_INT_CON(bank));
+
+       switch (real) {
+       case 0 ... 7:
+                       gpio = S5PC100_GPH0(gpio);
+               break;
+       case 8 ... 15:
+                       gpio = S5PC100_GPH1(gpio);
+               break;
+       case 16 ... 23:
+                       gpio = S5PC100_GPH2(gpio);
+               break;
+       case 24 ... 31:
+                       gpio = S5PC100_GPH3(gpio);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       sfn = S3C_GPIO_SFN(0x2);
+       s3c_gpio_cfgpin(gpio, sfn);
+
+       return 0;
+}
+
+static struct irq_chip s3c_irq_eint = {
+       .name           = "EINT",
+       .mask           = s3c_irq_eint_mask,
+       .unmask         = s3c_irq_eint_unmask,
+       .mask_ack       = s3c_irq_eint_maskack,
+       .ack            = s3c_irq_eint_ack,
+       .set_type       = s3c_irq_eint_set_type,
+       .set_wake       = s3c_irqext_wake,
+};
+
+/* s3c_irq_demux_eint
+ *
+ * This function demuxes the IRQ from external interrupts,
+ * from IRQ_EINT(16) to IRQ_EINT(31). It is designed to be inlined into
+ * the specific handlers s3c_irq_demux_eintX_Y.
+ */
+static inline void s3c_irq_demux_eint(unsigned int start, unsigned int end)
+{
+       u32 status = __raw_readl(S5PC1XX_WKUP_INT_PEND((start >> 3)));
+       u32 mask = __raw_readl(S5PC1XX_WKUP_INT_MASK((start >> 3)));
+       unsigned int irq;
+
+       status &= ~mask;
+       status &= (1 << (end - start + 1)) - 1;
+
+       for (irq = IRQ_EINT(start); irq <= IRQ_EINT(end); irq++) {
+               if (status & 1)
+                       generic_handle_irq(irq);
+
+               status >>= 1;
+       }
+}
+
+static void s3c_irq_demux_eint16_31(unsigned int irq, struct irq_desc *desc)
+{
+       s3c_irq_demux_eint(16, 23);
+       s3c_irq_demux_eint(24, 31);
+}
+
+/*
+ * Handle EINT0 ... EINT15 at VIC directly
+ */
+static void s3c_irq_vic_eint_mask(unsigned int irq)
+{
+       void __iomem *base = get_irq_chip_data(irq);
+       unsigned int real;
+
+       s3c_irq_eint_mask(irq);
+       real = s3c_get_eint(irq);
+       writel(1 << real, base + VIC_INT_ENABLE_CLEAR);
+}
+
+static void s3c_irq_vic_eint_unmask(unsigned int irq)
+{
+       void __iomem *base = get_irq_chip_data(irq);
+       unsigned int real;
+
+       s3c_irq_eint_unmask(irq);
+       real = s3c_get_eint(irq);
+       writel(1 << real, base + VIC_INT_ENABLE);
+}
+
+static inline void s3c_irq_vic_eint_ack(unsigned int irq)
+{
+       u32 bit;
+       u32 bank = s3c_get_bank(irq);
+
+       bit = s3c_eint_to_bit(irq);
+       __raw_writel(bit, S5PC1XX_WKUP_INT_PEND(bank));
+}
+
+static void s3c_irq_vic_eint_maskack(unsigned int irq)
+{
+       /* compiler should in-line these */
+       s3c_irq_vic_eint_mask(irq);
+       s3c_irq_vic_eint_ack(irq);
+}
+
+static struct irq_chip s3c_irq_vic_eint = {
+       .name           = "EINT",
+       .mask           = s3c_irq_vic_eint_mask,
+       .unmask         = s3c_irq_vic_eint_unmask,
+       .mask_ack       = s3c_irq_vic_eint_maskack,
+       .ack            = s3c_irq_vic_eint_ack,
+       .set_type       = s3c_irq_eint_set_type,
+       .set_wake       = s3c_irqext_wake,
+};
+
+static int __init s5pc1xx_init_irq_eint(void)
+{
+       int irq;
+
+       for (irq = IRQ_EINT0; irq <= IRQ_EINT15; irq++) {
+               set_irq_chip(irq, &s3c_irq_vic_eint);
+               set_irq_handler(irq, handle_level_irq);
+               set_irq_flags(irq, IRQF_VALID);
+       }
+
+       for (irq = IRQ_EINT(16); irq <= IRQ_EINT(31); irq++) {
+               set_irq_chip(irq, &s3c_irq_eint);
+               set_irq_handler(irq, handle_level_irq);
+               set_irq_flags(irq, IRQF_VALID);
+       }
+
+       set_irq_chained_handler(IRQ_EINT16_31, s3c_irq_demux_eint16_31);
+
+       return 0;
+}
+
+arch_initcall(s5pc1xx_init_irq_eint);
diff --git a/arch/arm/plat-s5pc1xx/irq-gpio.c b/arch/arm/plat-s5pc1xx/irq-gpio.c
new file mode 100644 (file)
index 0000000..fecca7a
--- /dev/null
@@ -0,0 +1,266 @@
+/*
+ * arch/arm/plat-s5pc1xx/irq-gpio.c
+ *
+ * Copyright (C) 2009 Samsung Electronics
+ *
+ * S5PC1XX - Interrupt handling for IRQ_GPIO${group}(x)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/io.h>
+#include <linux/gpio.h>
+
+#include <mach/map.h>
+#include <plat/gpio-cfg.h>
+
+#define S5PC1XX_GPIOREG(x)             (S5PC1XX_VA_GPIO + (x))
+
+#define CON_OFFSET                     0x700
+#define MASK_OFFSET                    0x900
+#define PEND_OFFSET                    0xA00
+#define CON_OFFSET_2                   0xE00
+#define MASK_OFFSET_2                  0xF00
+#define PEND_OFFSET_2                  0xF40
+
+#define GPIOINT_LEVEL_LOW              0x0
+#define GPIOINT_LEVEL_HIGH             0x1
+#define GPIOINT_EDGE_FALLING           0x2
+#define GPIOINT_EDGE_RISING            0x3
+#define GPIOINT_EDGE_BOTH              0x4
+
+static int group_to_con_offset(int group)
+{
+       return group << 2;
+}
+
+static int group_to_mask_offset(int group)
+{
+       return group << 2;
+}
+
+static int group_to_pend_offset(int group)
+{
+       return group << 2;
+}
+
+static int s5pc1xx_get_start(unsigned int group)
+{
+       switch (group) {
+       case 0: return S5PC100_GPIO_A0_START;
+       case 1: return S5PC100_GPIO_A1_START;
+       case 2: return S5PC100_GPIO_B_START;
+       case 3: return S5PC100_GPIO_C_START;
+       case 4: return S5PC100_GPIO_D_START;
+       case 5: return S5PC100_GPIO_E0_START;
+       case 6: return S5PC100_GPIO_E1_START;
+       case 7: return S5PC100_GPIO_F0_START;
+       case 8: return S5PC100_GPIO_F1_START;
+       case 9: return S5PC100_GPIO_F2_START;
+       case 10: return S5PC100_GPIO_F3_START;
+       case 11: return S5PC100_GPIO_G0_START;
+       case 12: return S5PC100_GPIO_G1_START;
+       case 13: return S5PC100_GPIO_G2_START;
+       case 14: return S5PC100_GPIO_G3_START;
+       case 15: return S5PC100_GPIO_I_START;
+       case 16: return S5PC100_GPIO_J0_START;
+       case 17: return S5PC100_GPIO_J1_START;
+       case 18: return S5PC100_GPIO_J2_START;
+       case 19: return S5PC100_GPIO_J3_START;
+       case 20: return S5PC100_GPIO_J4_START;
+       default:
+               BUG();
+       }
+
+       return -EINVAL;
+}
+
+static int s5pc1xx_get_group(unsigned int irq)
+{
+       irq -= S3C_IRQ_GPIO(0);
+
+       switch (irq) {
+       case S5PC100_GPIO_A0_START ... S5PC100_GPIO_A1_START - 1:
+               return 0;
+       case S5PC100_GPIO_A1_START ... S5PC100_GPIO_B_START - 1:
+               return 1;
+       case S5PC100_GPIO_B_START ... S5PC100_GPIO_C_START - 1:
+               return 2;
+       case S5PC100_GPIO_C_START ... S5PC100_GPIO_D_START - 1:
+               return 3;
+       case S5PC100_GPIO_D_START ... S5PC100_GPIO_E0_START - 1:
+               return 4;
+       case S5PC100_GPIO_E0_START ... S5PC100_GPIO_E1_START - 1:
+               return 5;
+       case S5PC100_GPIO_E1_START ... S5PC100_GPIO_F0_START - 1:
+               return 6;
+       case S5PC100_GPIO_F0_START ... S5PC100_GPIO_F1_START - 1:
+               return 7;
+       case S5PC100_GPIO_F1_START ... S5PC100_GPIO_F2_START - 1:
+               return 8;
+       case S5PC100_GPIO_F2_START ... S5PC100_GPIO_F3_START - 1:
+               return 9;
+       case S5PC100_GPIO_F3_START ... S5PC100_GPIO_G0_START - 1:
+               return 10;
+       case S5PC100_GPIO_G0_START ... S5PC100_GPIO_G1_START - 1:
+               return 11;
+       case S5PC100_GPIO_G1_START ... S5PC100_GPIO_G2_START - 1:
+               return 12;
+       case S5PC100_GPIO_G2_START ... S5PC100_GPIO_G3_START - 1:
+               return 13;
+       case S5PC100_GPIO_G3_START ... S5PC100_GPIO_H0_START - 1:
+               return 14;
+       case S5PC100_GPIO_I_START ... S5PC100_GPIO_J0_START - 1:
+               return 15;
+       case S5PC100_GPIO_J0_START ... S5PC100_GPIO_J1_START - 1:
+               return 16;
+       case S5PC100_GPIO_J1_START ... S5PC100_GPIO_J2_START - 1:
+               return 17;
+       case S5PC100_GPIO_J2_START ... S5PC100_GPIO_J3_START - 1:
+               return 18;
+       case S5PC100_GPIO_J3_START ... S5PC100_GPIO_J4_START - 1:
+               return 19;
+       case S5PC100_GPIO_J4_START ... S5PC100_GPIO_K0_START - 1:
+               return 20;
+       default:
+               BUG();
+       }
+
+       return -EINVAL;
+}
+
+static int s5pc1xx_get_offset(unsigned int irq)
+{
+       struct gpio_chip *chip = get_irq_data(irq);
+       return irq - S3C_IRQ_GPIO(chip->base);
+}
+
+static void s5pc1xx_gpioint_ack(unsigned int irq)
+{
+       int group, offset, pend_offset;
+       unsigned int value;
+
+       group = s5pc1xx_get_group(irq);
+       offset = s5pc1xx_get_offset(irq);
+       pend_offset = group_to_pend_offset(group);
+
+       value = __raw_readl(S5PC1XX_GPIOREG(PEND_OFFSET) + pend_offset);
+       value |= 1 << offset;
+       __raw_writel(value, S5PC1XX_GPIOREG(PEND_OFFSET) + pend_offset);
+}
+
+static void s5pc1xx_gpioint_mask(unsigned int irq)
+{
+       int group, offset, mask_offset;
+       unsigned int value;
+
+       group = s5pc1xx_get_group(irq);
+       offset = s5pc1xx_get_offset(irq);
+       mask_offset = group_to_mask_offset(group);
+
+       value = __raw_readl(S5PC1XX_GPIOREG(MASK_OFFSET) + mask_offset);
+       value |= 1 << offset;
+       __raw_writel(value, S5PC1XX_GPIOREG(MASK_OFFSET) + mask_offset);
+}
+
+static void s5pc1xx_gpioint_unmask(unsigned int irq)
+{
+       int group, offset, mask_offset;
+       unsigned int value;
+
+       group = s5pc1xx_get_group(irq);
+       offset = s5pc1xx_get_offset(irq);
+       mask_offset = group_to_mask_offset(group);
+
+       value = __raw_readl(S5PC1XX_GPIOREG(MASK_OFFSET) + mask_offset);
+       value &= ~(1 << offset);
+       __raw_writel(value, S5PC1XX_GPIOREG(MASK_OFFSET) + mask_offset);
+}
+
+static void s5pc1xx_gpioint_mask_ack(unsigned int irq)
+{
+       s5pc1xx_gpioint_mask(irq);
+       s5pc1xx_gpioint_ack(irq);
+}
+
+static int s5pc1xx_gpioint_set_type(unsigned int irq, unsigned int type)
+{
+       int group, offset, con_offset;
+       unsigned int value;
+
+       group = s5pc1xx_get_group(irq);
+       offset = s5pc1xx_get_offset(irq);
+       con_offset = group_to_con_offset(group);
+
+       switch (type) {
+       case IRQ_TYPE_NONE:
+               printk(KERN_WARNING "No irq type\n");
+               return -EINVAL;
+       case IRQ_TYPE_EDGE_RISING:
+               type = GPIOINT_EDGE_RISING;
+               break;
+       case IRQ_TYPE_EDGE_FALLING:
+               type = GPIOINT_EDGE_FALLING;
+               break;
+       case IRQ_TYPE_EDGE_BOTH:
+               type = GPIOINT_EDGE_BOTH;
+               break;
+       case IRQ_TYPE_LEVEL_HIGH:
+               type = GPIOINT_LEVEL_HIGH;
+               break;
+       case IRQ_TYPE_LEVEL_LOW:
+               type = GPIOINT_LEVEL_LOW;
+               break;
+       default:
+               BUG();
+       }
+
+
+       value = __raw_readl(S5PC1XX_GPIOREG(CON_OFFSET) + con_offset);
+       value &= ~(0xf << (offset * 0x4));
+       value |= (type << (offset * 0x4));
+       __raw_writel(value, S5PC1XX_GPIOREG(CON_OFFSET) + con_offset);
+
+       return 0;
+}
+
+struct irq_chip s5pc1xx_gpioint = {
+       .name           = "GPIO",
+       .ack            = s5pc1xx_gpioint_ack,
+       .mask           = s5pc1xx_gpioint_mask,
+       .mask_ack       = s5pc1xx_gpioint_mask_ack,
+       .unmask         = s5pc1xx_gpioint_unmask,
+       .set_type       = s5pc1xx_gpioint_set_type,
+};
+
+void s5pc1xx_irq_gpioint_handler(unsigned int irq, struct irq_desc *desc)
+{
+       int group, offset, pend_offset, mask_offset;
+       int real_irq, group_end;
+       unsigned int pend, mask;
+
+       group_end = 21;
+
+       for (group = 0; group < group_end; group++) {
+               pend_offset = group_to_pend_offset(group);
+               pend = __raw_readl(S5PC1XX_GPIOREG(PEND_OFFSET) + pend_offset);
+               if (!pend)
+                       continue;
+
+               mask_offset = group_to_mask_offset(group);
+               mask = __raw_readl(S5PC1XX_GPIOREG(MASK_OFFSET) + mask_offset);
+               pend &= ~mask;
+
+               for (offset = 0; offset < 8; offset++) {
+                       if (pend & (1 << offset)) {
+                               real_irq = s5pc1xx_get_start(group) + offset;
+                               generic_handle_irq(S3C_IRQ_GPIO(real_irq));
+                       }
+               }
+       }
+}
index 80d6dd9..e44fd04 100644 (file)
@@ -79,7 +79,7 @@ static void s3c_irq_timer_ack(unsigned int irq)
 {
        u32 reg = __raw_readl(S3C64XX_TINT_CSTAT);
 
-       reg &= 0x1f;
+       reg &= 0x1f;  /* mask out pending interrupts */
        reg |= (1 << 5) << (irq - IRQ_TIMER0);
        __raw_writel(reg, S3C64XX_TINT_CSTAT);
 }
index 6b24035..b436d44 100644 (file)
@@ -49,6 +49,7 @@ static struct clk clk_ext_xtal_mux = {
 #define clk_fin_hpll clk_ext_xtal_mux
 
 #define clk_fout_mpll  clk_mpll
+#define clk_vclk_54m   clk_54m
 
 struct clk_sources {
        unsigned int    nr_sources;
@@ -67,746 +68,327 @@ struct clksrc_clk {
        void __iomem            *reg_source;
 };
 
-static int clk_default_setrate(struct clk *clk, unsigned long rate)
-{
-       clk->rate = rate;
-       return 1;
-}
-
-struct clk clk_27m = {
-       .name           = "clk_27m",
+/* APLL */
+static struct clk clk_fout_apll = {
+       .name           = "fout_apll",
        .id             = -1,
        .rate           = 27000000,
 };
 
-static int clk_48m_ctrl(struct clk *clk, int enable)
-{
-       unsigned long flags;
-       u32 val;
+static struct clk *clk_src_apll_list[] = {
+       [0] = &clk_fin_apll,
+       [1] = &clk_fout_apll,
+};
+
+static struct clk_sources clk_src_apll = {
+       .sources        = clk_src_apll_list,
+       .nr_sources     = ARRAY_SIZE(clk_src_apll_list),
+};
 
-       /* can't rely on clock lock, this register has other usages */
-       local_irq_save(flags);
+static struct clksrc_clk clk_mout_apll = {
+       .clk    = {
+               .name           = "mout_apll",
+               .id             = -1,
+       },
+       .shift          = S5PC100_CLKSRC0_APLL_SHIFT,
+       .mask           = S5PC100_CLKSRC0_APLL_MASK,
+       .sources        = &clk_src_apll,
+       .reg_source     = S5PC100_CLKSRC0,
+};
 
-       val = __raw_readl(S5PC1XX_CLK_SRC1);
-       if (enable)
-               val |= S5PC100_CLKSRC1_CLK48M_MASK;
-       else
-               val &= ~S5PC100_CLKSRC1_CLK48M_MASK;
+static unsigned long s5pc100_clk_dout_apll_get_rate(struct clk *clk)
+{
+       unsigned long rate = clk_get_rate(clk->parent);
+       unsigned int ratio;
 
-       __raw_writel(val, S5PC1XX_CLK_SRC1);
-       local_irq_restore(flags);
+       ratio = __raw_readl(S5PC100_CLKDIV0) & S5PC100_CLKDIV0_APLL_MASK;
+       ratio >>= S5PC100_CLKDIV0_APLL_SHIFT;
 
-       return 0;
+       return rate / (ratio + 1);
 }
 
-struct clk clk_48m = {
-       .name           = "clk_48m",
+static struct clk clk_dout_apll = {
+       .name           = "dout_apll",
        .id             = -1,
-       .rate           = 48000000,
-       .enable         = clk_48m_ctrl,
+       .parent         = &clk_mout_apll.clk,
+       .get_rate       = s5pc100_clk_dout_apll_get_rate,
 };
 
-struct clk clk_54m = {
-       .name           = "clk_54m",
-       .id             = -1,
-       .rate           = 54000000,
-};
-
-struct clk clk_hpll = {
-       .name           = "hpll",
-       .id             = -1,
-};
+static unsigned long s5pc100_clk_arm_get_rate(struct clk *clk)
+{
+       unsigned long rate = clk_get_rate(clk->parent);
+       unsigned int ratio;
 
-struct clk clk_hd0 = {
-       .name           = "hclkd0",
-       .id             = -1,
-       .rate           = 0,
-       .parent         = NULL,
-       .ctrlbit        = 0,
-       .set_rate       = clk_default_setrate,
-};
+       ratio = __raw_readl(S5PC100_CLKDIV0) & S5PC100_CLKDIV0_ARM_MASK;
+       ratio >>= S5PC100_CLKDIV0_ARM_SHIFT;
 
-struct clk clk_pd0 = {
-       .name           = "pclkd0",
-       .id             = -1,
-       .rate           = 0,
-       .parent         = NULL,
-       .ctrlbit        = 0,
-       .set_rate       = clk_default_setrate,
-};
+       return rate / (ratio + 1);
+}
 
-static int s5pc1xx_clk_gate(void __iomem *reg,
-                               struct clk *clk,
-                               int enable)
+static unsigned long s5pc100_clk_arm_round_rate(struct clk *clk,
+                                               unsigned long rate)
 {
-       unsigned int ctrlbit = clk->ctrlbit;
-       u32 con;
+       unsigned long parent = clk_get_rate(clk->parent);
+       u32 div;
 
-       con = __raw_readl(reg);
+       if (parent < rate)
+               return rate;
 
-       if (enable)
-               con |= ctrlbit;
-       else
-               con &= ~ctrlbit;
+       div = (parent / rate) - 1;
+       if (div > S5PC100_CLKDIV0_ARM_MASK)
+               div = S5PC100_CLKDIV0_ARM_MASK;
 
-       __raw_writel(con, reg);
-       return 0;
+       return parent / (div + 1);
 }
 
-static int s5pc1xx_clk_d00_ctrl(struct clk *clk, int enable)
+static int s5pc100_clk_arm_set_rate(struct clk *clk, unsigned long rate)
 {
-       return s5pc1xx_clk_gate(S5PC100_CLKGATE_D00, clk, enable);
-}
+       unsigned long parent = clk_get_rate(clk->parent);
+       u32 div;
+       u32 val;
 
-static int s5pc1xx_clk_d01_ctrl(struct clk *clk, int enable)
-{
-       return s5pc1xx_clk_gate(S5PC100_CLKGATE_D01, clk, enable);
-}
+       if (rate < parent / (S5PC100_CLKDIV0_ARM_MASK + 1))
+               return -EINVAL;
 
-static int s5pc1xx_clk_d02_ctrl(struct clk *clk, int enable)
-{
-       return s5pc1xx_clk_gate(S5PC100_CLKGATE_D02, clk, enable);
-}
+       rate = clk_round_rate(clk, rate);
+       div = clk_get_rate(clk->parent) / rate;
 
-static int s5pc1xx_clk_d10_ctrl(struct clk *clk, int enable)
-{
-       return s5pc1xx_clk_gate(S5PC100_CLKGATE_D10, clk, enable);
-}
+       val = __raw_readl(S5PC100_CLKDIV0);
+       val &= S5PC100_CLKDIV0_ARM_MASK;
+       val |= (div - 1);
+       __raw_writel(val, S5PC100_CLKDIV0);
 
-static int s5pc1xx_clk_d11_ctrl(struct clk *clk, int enable)
-{
-       return s5pc1xx_clk_gate(S5PC100_CLKGATE_D11, clk, enable);
+       return 0;
 }
 
-static int s5pc1xx_clk_d12_ctrl(struct clk *clk, int enable)
-{
-       return s5pc1xx_clk_gate(S5PC100_CLKGATE_D12, clk, enable);
-}
+static struct clk clk_arm = {
+       .name           = "armclk",
+       .id             = -1,
+       .parent         = &clk_dout_apll,
+       .get_rate       = s5pc100_clk_arm_get_rate,
+       .set_rate       = s5pc100_clk_arm_set_rate,
+       .round_rate     = s5pc100_clk_arm_round_rate,
+};
 
-static int s5pc1xx_clk_d13_ctrl(struct clk *clk, int enable)
+static unsigned long s5pc100_clk_dout_d0_bus_get_rate(struct clk *clk)
 {
-       return s5pc1xx_clk_gate(S5PC100_CLKGATE_D13, clk, enable);
-}
+       unsigned long rate = clk_get_rate(clk->parent);
+       unsigned int ratio;
 
-static int s5pc1xx_clk_d14_ctrl(struct clk *clk, int enable)
-{
-       return s5pc1xx_clk_gate(S5PC100_CLKGATE_D14, clk, enable);
-}
+       ratio = __raw_readl(S5PC100_CLKDIV0) & S5PC100_CLKDIV0_D0_MASK;
+       ratio >>= S5PC100_CLKDIV0_D0_SHIFT;
 
-static int s5pc1xx_clk_d15_ctrl(struct clk *clk, int enable)
-{
-       return s5pc1xx_clk_gate(S5PC100_CLKGATE_D15, clk, enable);
+       return rate / (ratio + 1);
 }
 
-static int s5pc1xx_clk_d20_ctrl(struct clk *clk, int enable)
-{
-       return s5pc1xx_clk_gate(S5PC100_CLKGATE_D20, clk, enable);
-}
+static struct clk clk_dout_d0_bus = {
+       .name           = "dout_d0_bus",
+       .id             = -1,
+       .parent         = &clk_arm,
+       .get_rate       = s5pc100_clk_dout_d0_bus_get_rate,
+};
 
-int s5pc1xx_sclk0_ctrl(struct clk *clk, int enable)
+static unsigned long s5pc100_clk_dout_pclkd0_get_rate(struct clk *clk)
 {
-       return s5pc1xx_clk_gate(S5PC100_SCLKGATE0, clk, enable);
+       unsigned long rate = clk_get_rate(clk->parent);
+       unsigned int ratio;
+
+       ratio = __raw_readl(S5PC100_CLKDIV0) & S5PC100_CLKDIV0_PCLKD0_MASK;
+       ratio >>= S5PC100_CLKDIV0_PCLKD0_SHIFT;
+
+       return rate / (ratio + 1);
 }
 
-int s5pc1xx_sclk1_ctrl(struct clk *clk, int enable)
+static struct clk clk_dout_pclkd0 = {
+       .name           = "dout_pclkd0",
+       .id             = -1,
+       .parent         = &clk_dout_d0_bus,
+       .get_rate       = s5pc100_clk_dout_pclkd0_get_rate,
+};
+
+static unsigned long s5pc100_clk_dout_apll2_get_rate(struct clk *clk)
 {
-       return s5pc1xx_clk_gate(S5PC100_SCLKGATE1, clk, enable);
+       unsigned long rate = clk_get_rate(clk->parent);
+       unsigned int ratio;
+
+       ratio = __raw_readl(S5PC100_CLKDIV1) & S5PC100_CLKDIV1_APLL2_MASK;
+       ratio >>= S5PC100_CLKDIV1_APLL2_SHIFT;
+
+       return rate / (ratio + 1);
 }
 
-static struct clk init_clocks_disable[] = {
-       {
-               .name           = "dsi",
-               .id             = -1,
-               .parent         = &clk_p,
-               .enable         = s5pc1xx_clk_d11_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D11_DSI,
-       }, {
-               .name           = "csi",
-               .id             = -1,
-               .parent         = &clk_h,
-               .enable         = s5pc1xx_clk_d11_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D11_CSI,
-       }, {
-               .name           = "ccan0",
-               .id             = 0,
-               .parent         = &clk_p,
-               .enable         = s5pc1xx_clk_d14_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D14_CCAN0,
-       }, {
-               .name           = "ccan1",
-               .id             = 1,
-               .parent         = &clk_p,
-               .enable         = s5pc1xx_clk_d14_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D14_CCAN1,
-       }, {
-               .name           = "keypad",
-               .id             = -1,
-               .parent         = &clk_p,
-               .enable         = s5pc1xx_clk_d15_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D15_KEYIF,
-       }, {
-               .name           = "hclkd2",
-               .id             = -1,
-               .parent         = NULL,
-               .enable         = s5pc1xx_clk_d20_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D20_HCLKD2,
-       }, {
-               .name           = "iis-d2",
-               .id             = -1,
-               .parent         = NULL,
-               .enable         = s5pc1xx_clk_d20_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D20_I2SD2,
-       }, {
-               .name           = "otg",
-               .id             = -1,
-               .parent         = &clk_h,
-               .enable         = s5pc1xx_clk_d10_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D10_USBOTG,
-       },
+static struct clk clk_dout_apll2 = {
+       .name           = "dout_apll2",
+       .id             = -1,
+       .parent         = &clk_mout_apll.clk,
+       .get_rate       = s5pc100_clk_dout_apll2_get_rate,
 };
 
-static struct clk init_clocks[] = {
-       /* System1 (D0_0) devices */
-       {
-               .name           = "intc",
-               .id             = -1,
-               .parent         = &clk_hd0,
-               .enable         = s5pc1xx_clk_d00_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D00_INTC,
-       }, {
-               .name           = "tzic",
-               .id             = -1,
-               .parent         = &clk_hd0,
-               .enable         = s5pc1xx_clk_d00_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D00_TZIC,
-       }, {
-               .name           = "cf-ata",
-               .id             = -1,
-               .parent         = &clk_hd0,
-               .enable         = s5pc1xx_clk_d00_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D00_CFCON,
-       }, {
-               .name           = "mdma",
-               .id             = -1,
-               .parent         = &clk_hd0,
-               .enable         = s5pc1xx_clk_d00_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D00_MDMA,
-       }, {
-               .name           = "g2d",
-               .id             = -1,
-               .parent         = &clk_hd0,
-               .enable         = s5pc1xx_clk_d00_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D00_G2D,
-       }, {
-               .name           = "secss",
-               .id             = -1,
-               .parent         = &clk_hd0,
-               .enable         = s5pc1xx_clk_d00_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D00_SECSS,
-       }, {
-               .name           = "cssys",
-               .id             = -1,
-               .parent         = &clk_hd0,
-               .enable         = s5pc1xx_clk_d00_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D00_CSSYS,
-       },
+/* MPLL */
+static struct clk *clk_src_mpll_list[] = {
+       [0] = &clk_fin_mpll,
+       [1] = &clk_fout_mpll,
+};
 
-       /* Memory (D0_1) devices */
-       {
-               .name           = "dmc",
-               .id             = -1,
-               .parent         = &clk_hd0,
-               .enable         = s5pc1xx_clk_d01_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D01_DMC,
-       }, {
-               .name           = "sromc",
-               .id             = -1,
-               .parent         = &clk_hd0,
-               .enable         = s5pc1xx_clk_d01_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D01_SROMC,
-       }, {
-               .name           = "onenand",
-               .id             = -1,
-               .parent         = &clk_hd0,
-               .enable         = s5pc1xx_clk_d01_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D01_ONENAND,
-       }, {
-               .name           = "nand",
-               .id             = -1,
-               .parent         = &clk_hd0,
-               .enable         = s5pc1xx_clk_d01_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D01_NFCON,
-       }, {
-               .name           = "intmem",
-               .id             = -1,
-               .parent         = &clk_hd0,
-               .enable         = s5pc1xx_clk_d01_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D01_INTMEM,
-       }, {
-               .name           = "ebi",
-               .id             = -1,
-               .parent         = &clk_hd0,
-               .enable         = s5pc1xx_clk_d01_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D01_EBI,
-       },
+static struct clk_sources clk_src_mpll = {
+       .sources        = clk_src_mpll_list,
+       .nr_sources     = ARRAY_SIZE(clk_src_mpll_list),
+};
 
-       /* System2 (D0_2) devices */
-       {
-               .name           = "seckey",
-               .id             = -1,
-               .parent         = &clk_pd0,
-               .enable         = s5pc1xx_clk_d02_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D02_SECKEY,
-       }, {
-               .name           = "sdm",
+static struct clksrc_clk clk_mout_mpll = {
+       .clk = {
+               .name           = "mout_mpll",
                .id             = -1,
-               .parent         = &clk_hd0,
-               .enable         = s5pc1xx_clk_d02_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D02_SDM,
        },
+       .shift          = S5PC100_CLKSRC0_MPLL_SHIFT,
+       .mask           = S5PC100_CLKSRC0_MPLL_MASK,
+       .sources        = &clk_src_mpll,
+       .reg_source     = S5PC100_CLKSRC0,
+};
 
-       /* File (D1_0) devices */
-       {
-               .name           = "pdma0",
-               .id             = -1,
-               .parent         = &clk_h,
-               .enable         = s5pc1xx_clk_d10_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D10_PDMA0,
-       }, {
-               .name           = "pdma1",
-               .id             = -1,
-               .parent         = &clk_h,
-               .enable         = s5pc1xx_clk_d10_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D10_PDMA1,
-       }, {
-               .name           = "usb-host",
-               .id             = -1,
-               .parent         = &clk_h,
-               .enable         = s5pc1xx_clk_d10_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D10_USBHOST,
-       }, {
-               .name           = "modem",
-               .id             = -1,
-               .parent         = &clk_h,
-               .enable         = s5pc1xx_clk_d10_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D10_MODEMIF,
-       }, {
-               .name           = "hsmmc",
-               .id             = 0,
-               .parent         = &clk_h,
-               .enable         = s5pc1xx_clk_d10_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D10_HSMMC0,
-       }, {
-               .name           = "hsmmc",
-               .id             = 1,
-               .parent         = &clk_h,
-               .enable         = s5pc1xx_clk_d10_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D10_HSMMC1,
-       }, {
-               .name           = "hsmmc",
-               .id             = 2,
-               .parent         = &clk_h,
-               .enable         = s5pc1xx_clk_d10_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D10_HSMMC2,
-       },
+static struct clk *clkset_am_list[] = {
+       [0] = &clk_mout_mpll.clk,
+       [1] = &clk_dout_apll2,
+};
 
-       /* Multimedia1 (D1_1) devices */
-       {
-               .name           = "lcd",
-               .id             = -1,
-               .parent         = &clk_h,
-               .enable         = s5pc1xx_clk_d11_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D11_LCD,
-       }, {
-               .name           = "rotator",
-               .id             = -1,
-               .parent         = &clk_h,
-               .enable         = s5pc1xx_clk_d11_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D11_ROTATOR,
-       }, {
-               .name           = "fimc",
-               .id             = 0,
-               .parent         = &clk_h,
-               .enable         = s5pc1xx_clk_d11_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D11_FIMC0,
-       }, {
-               .name           = "fimc",
-               .id             = 1,
-               .parent         = &clk_h,
-               .enable         = s5pc1xx_clk_d11_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D11_FIMC1,
-       }, {
-               .name           = "fimc",
-               .id             = 2,
-               .parent         = &clk_h,
-               .enable         = s5pc1xx_clk_d11_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D11_FIMC2,
-       }, {
-               .name           = "jpeg",
-               .id             = -1,
-               .parent         = &clk_h,
-               .enable         = s5pc1xx_clk_d11_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D11_JPEG,
-       }, {
-               .name           = "g3d",
-               .id             = -1,
-               .parent         = &clk_h,
-               .enable         = s5pc1xx_clk_d11_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D11_G3D,
-       },
+static struct clk_sources clk_src_am = {
+       .sources        = clkset_am_list,
+       .nr_sources     = ARRAY_SIZE(clkset_am_list),
+};
 
-       /* Multimedia2 (D1_2) devices */
-       {
-               .name           = "tv",
-               .id             = -1,
-               .parent         = &clk_h,
-               .enable         = s5pc1xx_clk_d12_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D12_TV,
-       }, {
-               .name           = "vp",
-               .id             = -1,
-               .parent         = &clk_h,
-               .enable         = s5pc1xx_clk_d12_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D12_VP,
-       }, {
-               .name           = "mixer",
-               .id             = -1,
-               .parent         = &clk_h,
-               .enable         = s5pc1xx_clk_d12_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D12_MIXER,
-       }, {
-               .name           = "hdmi",
-               .id             = -1,
-               .parent         = &clk_h,
-               .enable         = s5pc1xx_clk_d12_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D12_HDMI,
-       }, {
-               .name           = "mfc",
+static struct clksrc_clk clk_mout_am = {
+       .clk = {
+               .name           = "mout_am",
                .id             = -1,
-               .parent         = &clk_h,
-               .enable         = s5pc1xx_clk_d12_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D12_MFC,
        },
+       .shift          = S5PC100_CLKSRC0_AMMUX_SHIFT,
+       .mask           = S5PC100_CLKSRC0_AMMUX_MASK,
+       .sources        = &clk_src_am,
+       .reg_source     = S5PC100_CLKSRC0,
+};
 
-       /* System (D1_3) devices */
-       {
-               .name           = "chipid",
-               .id             = -1,
-               .parent         = &clk_p,
-               .enable         = s5pc1xx_clk_d13_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D13_CHIPID,
-       }, {
-               .name           = "gpio",
-               .id             = -1,
-               .parent         = &clk_p,
-               .enable         = s5pc1xx_clk_d13_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D13_GPIO,
-       }, {
-               .name           = "apc",
-               .id             = -1,
-               .parent         = &clk_p,
-               .enable         = s5pc1xx_clk_d13_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D13_APC,
-       }, {
-               .name           = "iec",
-               .id             = -1,
-               .parent         = &clk_p,
-               .enable         = s5pc1xx_clk_d13_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D13_IEC,
-       }, {
-               .name           = "timers",
-               .id             = -1,
-               .parent         = &clk_p,
-               .enable         = s5pc1xx_clk_d13_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D13_PWM,
-       }, {
-               .name           = "systimer",
-               .id             = -1,
-               .parent         = &clk_p,
-               .enable         = s5pc1xx_clk_d13_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D13_SYSTIMER,
-       }, {
-               .name           = "watchdog",
-               .id             = -1,
-               .parent         = &clk_p,
-               .enable         = s5pc1xx_clk_d13_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D13_WDT,
-       }, {
-               .name           = "rtc",
-               .id             = -1,
-               .parent         = &clk_p,
-               .enable         = s5pc1xx_clk_d13_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D13_RTC,
-       },
+static unsigned long s5pc100_clk_dout_d1_bus_get_rate(struct clk *clk)
+{
+       unsigned long rate = clk_get_rate(clk->parent);
+       unsigned int ratio;
 
-       /* Connectivity (D1_4) devices */
-       {
-               .name           = "uart",
-               .id             = 0,
-               .parent         = &clk_p,
-               .enable         = s5pc1xx_clk_d14_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D14_UART0,
-       }, {
-               .name           = "uart",
-               .id             = 1,
-               .parent         = &clk_p,
-               .enable         = s5pc1xx_clk_d14_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D14_UART1,
-       }, {
-               .name           = "uart",
-               .id             = 2,
-               .parent         = &clk_p,
-               .enable         = s5pc1xx_clk_d14_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D14_UART2,
-       }, {
-               .name           = "uart",
-               .id             = 3,
-               .parent         = &clk_p,
-               .enable         = s5pc1xx_clk_d14_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D14_UART3,
-       }, {
-               .name           = "i2c",
-               .id             = -1,
-               .parent         = &clk_p,
-               .enable         = s5pc1xx_clk_d14_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D14_IIC,
-       }, {
-               .name           = "hdmi-i2c",
-               .id             = -1,
-               .parent         = &clk_p,
-               .enable         = s5pc1xx_clk_d14_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D14_HDMI_IIC,
-       }, {
-               .name           = "spi",
-               .id             = 0,
-               .parent         = &clk_p,
-               .enable         = s5pc1xx_clk_d14_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D14_SPI0,
-       }, {
-               .name           = "spi",
-               .id             = 1,
-               .parent         = &clk_p,
-               .enable         = s5pc1xx_clk_d14_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D14_SPI1,
-       }, {
-               .name           = "spi",
-               .id             = 2,
-               .parent         = &clk_p,
-               .enable         = s5pc1xx_clk_d14_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D14_SPI2,
-       }, {
-               .name           = "irda",
-               .id             = -1,
-               .parent         = &clk_p,
-               .enable         = s5pc1xx_clk_d14_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D14_IRDA,
-       }, {
-               .name           = "hsitx",
-               .id             = -1,
-               .parent         = &clk_p,
-               .enable         = s5pc1xx_clk_d14_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D14_HSITX,
-       }, {
-               .name           = "hsirx",
-               .id             = -1,
-               .parent         = &clk_p,
-               .enable         = s5pc1xx_clk_d14_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D14_HSIRX,
-       },
+       printk(KERN_DEBUG "%s: parent is %ld\n", __func__, rate);
 
-       /* Audio (D1_5) devices */
-       {
-               .name           = "iis",
-               .id             = 0,
-               .parent         = &clk_p,
-               .enable         = s5pc1xx_clk_d15_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D15_IIS0,
-       }, {
-               .name           = "iis",
-               .id             = 1,
-               .parent         = &clk_p,
-               .enable         = s5pc1xx_clk_d15_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D15_IIS1,
-       }, {
-               .name           = "iis",
-               .id             = 2,
-               .parent         = &clk_p,
-               .enable         = s5pc1xx_clk_d15_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D15_IIS2,
-       }, {
-               .name           = "ac97",
-               .id             = -1,
-               .parent         = &clk_p,
-               .enable         = s5pc1xx_clk_d15_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D15_AC97,
-       }, {
-               .name           = "pcm",
-               .id             = 0,
-               .parent         = &clk_p,
-               .enable         = s5pc1xx_clk_d15_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D15_PCM0,
-       }, {
-               .name           = "pcm",
-               .id             = 1,
-               .parent         = &clk_p,
-               .enable         = s5pc1xx_clk_d15_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D15_PCM1,
-       }, {
-               .name           = "spdif",
-               .id             = -1,
-               .parent         = &clk_p,
-               .enable         = s5pc1xx_clk_d15_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D15_SPDIF,
-       }, {
-               .name           = "adc",
-               .id             = -1,
-               .parent         = &clk_p,
-               .enable         = s5pc1xx_clk_d15_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D15_TSADC,
-       }, {
-               .name           = "keyif",
-               .id             = -1,
-               .parent         = &clk_p,
-               .enable         = s5pc1xx_clk_d15_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D15_KEYIF,
-       }, {
-               .name           = "cg",
-               .id             = -1,
-               .parent         = &clk_p,
-               .enable         = s5pc1xx_clk_d15_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D15_CG,
-       },
+       ratio = __raw_readl(S5PC100_CLKDIV1) & S5PC100_CLKDIV1_D1_MASK;
+       ratio >>= S5PC100_CLKDIV1_D1_SHIFT;
 
-       /* Audio (D2_0) devices: all disabled */
+       return rate / (ratio + 1);
+}
 
-       /* Special Clocks 1 */
-       {
-               .name           = "sclk_hpm",
-               .id             = -1,
-               .parent         = NULL,
-               .enable         = s5pc1xx_sclk0_ctrl,
-               .ctrlbit        = S5PC1XX_CLKGATE_SCLK0_HPM,
-       }, {
-               .name           = "sclk_onenand",
-               .id             = -1,
-               .parent         = NULL,
-               .enable         = s5pc1xx_sclk0_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_SCLK0_ONENAND,
-       }, {
-               .name           = "sclk_spi_48",
-               .id             = 0,
-               .parent         = &clk_48m,
-               .enable         = s5pc1xx_sclk0_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_SCLK0_SPI0_48,
-       }, {
-               .name           = "sclk_spi_48",
-               .id             = 1,
-               .parent         = &clk_48m,
-               .enable         = s5pc1xx_sclk0_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_SCLK0_SPI1_48,
-       }, {
-               .name           = "sclk_spi_48",
-               .id             = 2,
-               .parent         = &clk_48m,
-               .enable         = s5pc1xx_sclk0_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_SCLK0_SPI2_48,
-       }, {
-               .name           = "sclk_mmc_48",
-               .id             = 0,
-               .parent         = &clk_48m,
-               .enable         = s5pc1xx_sclk0_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_SCLK0_MMC0_48,
-       }, {
-               .name           = "sclk_mmc_48",
-               .id             = 1,
-               .parent         = &clk_48m,
-               .enable         = s5pc1xx_sclk0_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_SCLK0_MMC1_48,
-       }, {
-               .name           = "sclk_mmc_48",
-               .id             = 2,
-               .parent         = &clk_48m,
-               .enable         = s5pc1xx_sclk0_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_SCLK0_MMC2_48,
-       },
+static struct clk clk_dout_d1_bus = {
+       .name           = "dout_d1_bus",
+       .id             = -1,
+       .parent         = &clk_mout_am.clk,
+       .get_rate       = s5pc100_clk_dout_d1_bus_get_rate,
+};
 
-       /* Special Clocks 2 */
-       {
-               .name           = "sclk_tv_54",
-               .id             = -1,
-               .parent         = &clk_54m,
-               .enable         = s5pc1xx_sclk1_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_SCLK1_TV54,
-       }, {
-               .name           = "sclk_vdac_54",
-               .id             = -1,
-               .parent         = &clk_54m,
-               .enable         = s5pc1xx_sclk1_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_SCLK1_VDAC54,
-       }, {
-               .name           = "sclk_spdif",
+static struct clk *clkset_onenand_list[] = {
+       [0] = &clk_dout_d0_bus,
+       [1] = &clk_dout_d1_bus,
+};
+
+static struct clk_sources clk_src_onenand = {
+       .sources        = clkset_onenand_list,
+       .nr_sources     = ARRAY_SIZE(clkset_onenand_list),
+};
+
+static struct clksrc_clk clk_mout_onenand = {
+       .clk = {
+               .name           = "mout_onenand",
                .id             = -1,
-               .parent         = NULL,
-               .enable         = s5pc1xx_sclk1_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_SCLK1_SPDIF,
        },
+       .shift          = S5PC100_CLKSRC0_ONENAND_SHIFT,
+       .mask           = S5PC100_CLKSRC0_ONENAND_MASK,
+       .sources        = &clk_src_onenand,
+       .reg_source     = S5PC100_CLKSRC0,
 };
 
-void __init s5pc1xx_register_clocks(void)
+static unsigned long s5pc100_clk_dout_pclkd1_get_rate(struct clk *clk)
 {
-       struct clk *clkp;
-       int ret;
-       int ptr;
+       unsigned long rate = clk_get_rate(clk->parent);
+       unsigned int ratio;
 
-       clkp = init_clocks;
-       for (ptr = 0; ptr < ARRAY_SIZE(init_clocks); ptr++, clkp++) {
-               ret = s3c24xx_register_clock(clkp);
-               if (ret < 0) {
-                       printk(KERN_ERR "Failed to register clock %s (%d)\n",
-                              clkp->name, ret);
-               }
-       }
+       printk(KERN_DEBUG "%s: parent is %ld\n", __func__, rate);
 
-       clkp = init_clocks_disable;
-       for (ptr = 0; ptr < ARRAY_SIZE(init_clocks_disable); ptr++, clkp++) {
+       ratio = __raw_readl(S5PC100_CLKDIV1) & S5PC100_CLKDIV1_PCLKD1_MASK;
+       ratio >>= S5PC100_CLKDIV1_PCLKD1_SHIFT;
 
-               ret = s3c24xx_register_clock(clkp);
-               if (ret < 0) {
-                       printk(KERN_ERR "Failed to register clock %s (%d)\n",
-                              clkp->name, ret);
-               }
+       return rate / (ratio + 1);
+}
 
-               (clkp->enable)(clkp, 0);
-       }
+static struct clk clk_dout_pclkd1 = {
+       .name           = "dout_pclkd1",
+       .id             = -1,
+       .parent         = &clk_dout_d1_bus,
+       .get_rate       = s5pc100_clk_dout_pclkd1_get_rate,
+};
+
+static unsigned long s5pc100_clk_dout_mpll2_get_rate(struct clk *clk)
+{
+       unsigned long rate = clk_get_rate(clk->parent);
+       unsigned int ratio;
+
+       printk(KERN_DEBUG "%s: parent is %ld\n", __func__, rate);
+
+       ratio = __raw_readl(S5PC100_CLKDIV1) & S5PC100_CLKDIV1_MPLL2_MASK;
+       ratio >>= S5PC100_CLKDIV1_MPLL2_SHIFT;
 
-       s3c_pwmclk_init();
+       return rate / (ratio + 1);
 }
-static struct clk clk_fout_apll = {
-       .name           = "fout_apll",
+
+static struct clk clk_dout_mpll2 = {
+       .name           = "dout_mpll2",
        .id             = -1,
+       .parent         = &clk_mout_am.clk,
+       .get_rate       = s5pc100_clk_dout_mpll2_get_rate,
 };
 
-static struct clk *clk_src_apll_list[] = {
-       [0] = &clk_fin_apll,
-       [1] = &clk_fout_apll,
-};
+static unsigned long s5pc100_clk_dout_cam_get_rate(struct clk *clk)
+{
+       unsigned long rate = clk_get_rate(clk->parent);
+       unsigned int ratio;
 
-static struct clk_sources clk_src_apll = {
-       .sources        = clk_src_apll_list,
-       .nr_sources     = ARRAY_SIZE(clk_src_apll_list),
+       printk(KERN_DEBUG "%s: parent is %ld\n", __func__, rate);
+
+       ratio = __raw_readl(S5PC100_CLKDIV1) & S5PC100_CLKDIV1_CAM_MASK;
+       ratio >>= S5PC100_CLKDIV1_CAM_SHIFT;
+
+       return rate / (ratio + 1);
+}
+
+static struct clk clk_dout_cam = {
+       .name           = "dout_cam",
+       .id             = -1,
+       .parent         = &clk_dout_mpll2,
+       .get_rate       = s5pc100_clk_dout_cam_get_rate,
 };
 
-static struct clksrc_clk clk_mout_apll = {
-       .clk    = {
-               .name           = "mout_apll",
-               .id             = -1,
-       },
-       .shift          = S5PC1XX_CLKSRC0_APLL_SHIFT,
-       .mask           = S5PC1XX_CLKSRC0_APLL_MASK,
-       .sources        = &clk_src_apll,
-       .reg_source     = S5PC1XX_CLK_SRC0,
+static unsigned long s5pc100_clk_dout_mpll_get_rate(struct clk *clk)
+{
+       unsigned long rate = clk_get_rate(clk->parent);
+       unsigned int ratio;
+
+       printk(KERN_DEBUG "%s: parent is %ld\n", __func__, rate);
+
+       ratio = __raw_readl(S5PC100_CLKDIV1) & S5PC100_CLKDIV1_MPLL_MASK;
+       ratio >>= S5PC100_CLKDIV1_MPLL_SHIFT;
+
+       return rate / (ratio + 1);
+}
+
+static struct clk clk_dout_mpll = {
+       .name           = "dout_mpll",
+       .id             = -1,
+       .parent         = &clk_mout_am.clk,
+       .get_rate       = s5pc100_clk_dout_mpll_get_rate,
 };
 
+/* EPLL */
 static struct clk clk_fout_epll = {
        .name           = "fout_epll",
        .id             = -1,
@@ -827,91 +409,57 @@ static struct clksrc_clk clk_mout_epll = {
                .name           = "mout_epll",
                .id             = -1,
        },
-       .shift          = S5PC1XX_CLKSRC0_EPLL_SHIFT,
-       .mask           = S5PC1XX_CLKSRC0_EPLL_MASK,
+       .shift          = S5PC100_CLKSRC0_EPLL_SHIFT,
+       .mask           = S5PC100_CLKSRC0_EPLL_MASK,
        .sources        = &clk_src_epll,
-       .reg_source     = S5PC1XX_CLK_SRC0,
+       .reg_source     = S5PC100_CLKSRC0,
 };
 
-static struct clk *clk_src_mpll_list[] = {
-       [0] = &clk_fin_mpll,
-       [1] = &clk_fout_mpll,
-};
-
-static struct clk_sources clk_src_mpll = {
-       .sources        = clk_src_mpll_list,
-       .nr_sources     = ARRAY_SIZE(clk_src_mpll_list),
-};
-
-static struct clksrc_clk clk_mout_mpll = {
-       .clk = {
-               .name           = "mout_mpll",
-               .id             = -1,
-       },
-       .shift          = S5PC1XX_CLKSRC0_MPLL_SHIFT,
-       .mask           = S5PC1XX_CLKSRC0_MPLL_MASK,
-       .sources        = &clk_src_mpll,
-       .reg_source     = S5PC1XX_CLK_SRC0,
-};
-
-static unsigned long s5pc1xx_clk_doutmpll_get_rate(struct clk *clk)
-{
-       unsigned long rate = clk_get_rate(clk->parent);
-       unsigned long clkdiv;
-
-       printk(KERN_DEBUG "%s: parent is %ld\n", __func__, rate);
-
-       clkdiv = __raw_readl(S5PC1XX_CLK_DIV1) & S5PC100_CLKDIV1_MPLL_MASK;
-       rate /= (clkdiv >> S5PC100_CLKDIV1_MPLL_SHIFT) + 1;
-
-       return rate;
-}
-
-static struct clk clk_dout_mpll = {
-       .name           = "dout_mpll",
+/* HPLL */
+static struct clk clk_fout_hpll = {
+       .name           = "fout_hpll",
        .id             = -1,
-       .parent         = &clk_mout_mpll.clk,
-       .get_rate       = s5pc1xx_clk_doutmpll_get_rate,
 };
 
-static unsigned long s5pc1xx_clk_doutmpll2_get_rate(struct clk *clk)
-{
-       unsigned long rate = clk_get_rate(clk->parent);
-       unsigned long clkdiv;
-
-       printk(KERN_DEBUG "%s: parent is %ld\n", __func__, rate);
-
-       clkdiv = __raw_readl(S5PC1XX_CLK_DIV1) & S5PC100_CLKDIV1_MPLL2_MASK;
-       rate /= (clkdiv >> S5PC100_CLKDIV1_MPLL2_SHIFT) + 1;
-
-       return rate;
-}
-
-struct clk clk_dout_mpll2 = {
-       .name           = "dout_mpll2",
-       .id             = -1,
-       .parent         = &clk_mout_mpll.clk,
-       .get_rate       = s5pc1xx_clk_doutmpll2_get_rate,
+static struct clk *clk_src_hpll_list[] = {
+       [0] = &clk_27m,
+       [1] = &clk_fout_hpll,
 };
 
-static struct clk *clkset_uart_list[] = {
-       &clk_mout_epll.clk,
-       &clk_dout_mpll,
-       NULL,
-       NULL
+static struct clk_sources clk_src_hpll = {
+       .sources        = clk_src_hpll_list,
+       .nr_sources     = ARRAY_SIZE(clk_src_hpll_list),
 };
 
-static struct clk_sources clkset_uart = {
-       .sources        = clkset_uart_list,
-       .nr_sources     = ARRAY_SIZE(clkset_uart_list),
+static struct clksrc_clk clk_mout_hpll = {
+       .clk    = {
+               .name           = "mout_hpll",
+               .id             = -1,
+       },
+       .shift          = S5PC100_CLKSRC0_HPLL_SHIFT,
+       .mask           = S5PC100_CLKSRC0_HPLL_MASK,
+       .sources        = &clk_src_hpll,
+       .reg_source     = S5PC100_CLKSRC0,
 };
 
+/* Peripherals */
+/*
+ * The peripheral clocks are all controlled via clocksource followed
+ * by an optional divider and gate stage. We currently roll this into
+ * one clock which hides the intermediate clock from the mux.
+ *
+ * Note, the JPEG clock can only be an even divider...
+ *
+ * The scaler and LCD clocks depend on the S5PC100 version, and also
+ * have a common parent divisor so are not included here.
+ */
+
 static inline struct clksrc_clk *to_clksrc(struct clk *clk)
 {
        return container_of(clk, struct clksrc_clk, clk);
 }
 
-static unsigned long s5pc1xx_getrate_clksrc(struct clk *clk)
+static unsigned long s5pc100_getrate_clksrc(struct clk *clk)
 {
        struct clksrc_clk *sclk = to_clksrc(clk);
        unsigned long rate = clk_get_rate(clk->parent);
@@ -925,7 +473,7 @@ static unsigned long s5pc1xx_getrate_clksrc(struct clk *clk)
        return rate;
 }
 
-static int s5pc1xx_setrate_clksrc(struct clk *clk, unsigned long rate)
+static int s5pc100_setrate_clksrc(struct clk *clk, unsigned long rate)
 {
        struct clksrc_clk *sclk = to_clksrc(clk);
        void __iomem *reg = sclk->reg_divider;
@@ -938,14 +486,14 @@ static int s5pc1xx_setrate_clksrc(struct clk *clk, unsigned long rate)
                return -EINVAL;
 
        val = __raw_readl(reg);
-       val &= ~(0xf << sclk->shift);
-       val |= (div - 1) << sclk->shift;
+       val &= ~(0xf << sclk->divider_shift);
+       val |= (div - 1) << sclk->divider_shift;
        __raw_writel(val, reg);
 
        return 0;
 }
 
-static int s5pc1xx_setparent_clksrc(struct clk *clk, struct clk *parent)
+static int s5pc100_setparent_clksrc(struct clk *clk, struct clk *parent)
 {
        struct clksrc_clk *sclk = to_clksrc(clk);
        struct clk_sources *srcs = sclk->sources;
@@ -970,7 +518,7 @@ static int s5pc1xx_setparent_clksrc(struct clk *clk, struct clk *parent)
        return -EINVAL;
 }
 
-static unsigned long s5pc1xx_roundrate_clksrc(struct clk *clk,
+static unsigned long s5pc100_roundrate_clksrc(struct clk *clk,
                                              unsigned long rate)
 {
        unsigned long parent_rate = clk_get_rate(clk->parent);
@@ -992,35 +540,466 @@ static unsigned long s5pc1xx_roundrate_clksrc(struct clk *clk,
        return rate;
 }
 
+static struct clk *clkset_spi_list[] = {
+       &clk_mout_epll.clk,
+       &clk_dout_mpll2,
+       &clk_fin_epll,
+       &clk_mout_hpll.clk,
+};
+
+static struct clk_sources clkset_spi = {
+       .sources        = clkset_spi_list,
+       .nr_sources     = ARRAY_SIZE(clkset_spi_list),
+};
+
+static struct clksrc_clk clk_spi0 = {
+       .clk    = {
+               .name           = "spi_bus",
+               .id             = 0,
+               .ctrlbit        = S5PC100_CLKGATE_SCLK0_SPI0,
+               .enable         = s5pc100_sclk0_ctrl,
+               .set_parent     = s5pc100_setparent_clksrc,
+               .get_rate       = s5pc100_getrate_clksrc,
+               .set_rate       = s5pc100_setrate_clksrc,
+               .round_rate     = s5pc100_roundrate_clksrc,
+       },
+       .shift          = S5PC100_CLKSRC1_SPI0_SHIFT,
+       .mask           = S5PC100_CLKSRC1_SPI0_MASK,
+       .sources        = &clkset_spi,
+       .divider_shift  = S5PC100_CLKDIV2_SPI0_SHIFT,
+       .reg_divider    = S5PC100_CLKDIV2,
+       .reg_source     = S5PC100_CLKSRC1,
+};
+
+static struct clksrc_clk clk_spi1 = {
+       .clk    = {
+               .name           = "spi_bus",
+               .id             = 1,
+               .ctrlbit        = S5PC100_CLKGATE_SCLK0_SPI1,
+               .enable         = s5pc100_sclk0_ctrl,
+               .set_parent     = s5pc100_setparent_clksrc,
+               .get_rate       = s5pc100_getrate_clksrc,
+               .set_rate       = s5pc100_setrate_clksrc,
+               .round_rate     = s5pc100_roundrate_clksrc,
+       },
+       .shift          = S5PC100_CLKSRC1_SPI1_SHIFT,
+       .mask           = S5PC100_CLKSRC1_SPI1_MASK,
+       .sources        = &clkset_spi,
+       .divider_shift  = S5PC100_CLKDIV2_SPI1_SHIFT,
+       .reg_divider    = S5PC100_CLKDIV2,
+       .reg_source     = S5PC100_CLKSRC1,
+};
+
+static struct clksrc_clk clk_spi2 = {
+       .clk    = {
+               .name           = "spi_bus",
+               .id             = 2,
+               .ctrlbit        = S5PC100_CLKGATE_SCLK0_SPI2,
+               .enable         = s5pc100_sclk0_ctrl,
+               .set_parent     = s5pc100_setparent_clksrc,
+               .get_rate       = s5pc100_getrate_clksrc,
+               .set_rate       = s5pc100_setrate_clksrc,
+               .round_rate     = s5pc100_roundrate_clksrc,
+       },
+       .shift          = S5PC100_CLKSRC1_SPI2_SHIFT,
+       .mask           = S5PC100_CLKSRC1_SPI2_MASK,
+       .sources        = &clkset_spi,
+       .divider_shift  = S5PC100_CLKDIV2_SPI2_SHIFT,
+       .reg_divider    = S5PC100_CLKDIV2,
+       .reg_source     = S5PC100_CLKSRC1,
+};
+
+static struct clk *clkset_uart_list[] = {
+       &clk_mout_epll.clk,
+       &clk_dout_mpll,
+};
+
+static struct clk_sources clkset_uart = {
+       .sources        = clkset_uart_list,
+       .nr_sources     = ARRAY_SIZE(clkset_uart_list),
+};
+
 static struct clksrc_clk clk_uart_uclk1 = {
        .clk    = {
                .name           = "uclk1",
                .id             = -1,
                .ctrlbit        = S5PC100_CLKGATE_SCLK0_UART,
-               .enable         = s5pc1xx_sclk0_ctrl,
-               .set_parent     = s5pc1xx_setparent_clksrc,
-               .get_rate       = s5pc1xx_getrate_clksrc,
-               .set_rate       = s5pc1xx_setrate_clksrc,
-               .round_rate     = s5pc1xx_roundrate_clksrc,
+               .enable         = s5pc100_sclk0_ctrl,
+               .set_parent     = s5pc100_setparent_clksrc,
+               .get_rate       = s5pc100_getrate_clksrc,
+               .set_rate       = s5pc100_setrate_clksrc,
+               .round_rate     = s5pc100_roundrate_clksrc,
        },
        .shift          = S5PC100_CLKSRC1_UART_SHIFT,
        .mask           = S5PC100_CLKSRC1_UART_MASK,
        .sources        = &clkset_uart,
        .divider_shift  = S5PC100_CLKDIV2_UART_SHIFT,
-       .reg_divider    = S5PC1XX_CLK_DIV2,
-       .reg_source     = S5PC1XX_CLK_SRC1,
+       .reg_divider    = S5PC100_CLKDIV2,
+       .reg_source     = S5PC100_CLKSRC1,
+};
+
+static struct clk clk_iis_cd0 = {
+       .name           = "iis_cdclk0",
+       .id             = -1,
+};
+
+static struct clk clk_iis_cd1 = {
+       .name           = "iis_cdclk1",
+       .id             = -1,
+};
+
+static struct clk clk_iis_cd2 = {
+       .name           = "iis_cdclk2",
+       .id             = -1,
+};
+
+static struct clk clk_pcm_cd0 = {
+       .name           = "pcm_cdclk0",
+       .id             = -1,
+};
+
+static struct clk clk_pcm_cd1 = {
+       .name           = "pcm_cdclk1",
+       .id             = -1,
+};
+
+static struct clk *clkset_audio0_list[] = {
+       &clk_mout_epll.clk,
+       &clk_dout_mpll,
+       &clk_fin_epll,
+       &clk_iis_cd0,
+       &clk_pcm_cd0,
+       &clk_mout_hpll.clk,
+};
+
+static struct clk_sources clkset_audio0 = {
+       .sources        = clkset_audio0_list,
+       .nr_sources     = ARRAY_SIZE(clkset_audio0_list),
+};
+
+static struct clksrc_clk clk_audio0 = {
+       .clk    = {
+               .name           = "audio-bus",
+               .id             = 0,
+               .ctrlbit        = S5PC100_CLKGATE_SCLK1_AUDIO0,
+               .enable         = s5pc100_sclk1_ctrl,
+               .set_parent     = s5pc100_setparent_clksrc,
+               .get_rate       = s5pc100_getrate_clksrc,
+               .set_rate       = s5pc100_setrate_clksrc,
+               .round_rate     = s5pc100_roundrate_clksrc,
+       },
+       .shift          = S5PC100_CLKSRC3_AUDIO0_SHIFT,
+       .mask           = S5PC100_CLKSRC3_AUDIO0_MASK,
+       .sources        = &clkset_audio0,
+       .divider_shift  = S5PC100_CLKDIV4_AUDIO0_SHIFT,
+       .reg_divider    = S5PC100_CLKDIV4,
+       .reg_source     = S5PC100_CLKSRC3,
+};
+
+static struct clk *clkset_audio1_list[] = {
+       &clk_mout_epll.clk,
+       &clk_dout_mpll,
+       &clk_fin_epll,
+       &clk_iis_cd1,
+       &clk_pcm_cd1,
+       &clk_mout_hpll.clk,
+};
+
+static struct clk_sources clkset_audio1 = {
+       .sources        = clkset_audio1_list,
+       .nr_sources     = ARRAY_SIZE(clkset_audio1_list),
+};
+
+static struct clksrc_clk clk_audio1 = {
+       .clk    = {
+               .name           = "audio-bus",
+               .id             = 1,
+               .ctrlbit        = S5PC100_CLKGATE_SCLK1_AUDIO1,
+               .enable         = s5pc100_sclk1_ctrl,
+               .set_parent     = s5pc100_setparent_clksrc,
+               .get_rate       = s5pc100_getrate_clksrc,
+               .set_rate       = s5pc100_setrate_clksrc,
+               .round_rate     = s5pc100_roundrate_clksrc,
+       },
+       .shift          = S5PC100_CLKSRC3_AUDIO1_SHIFT,
+       .mask           = S5PC100_CLKSRC3_AUDIO1_MASK,
+       .sources        = &clkset_audio1,
+       .divider_shift  = S5PC100_CLKDIV4_AUDIO1_SHIFT,
+       .reg_divider    = S5PC100_CLKDIV4,
+       .reg_source     = S5PC100_CLKSRC3,
+};
+
+static struct clk *clkset_audio2_list[] = {
+       &clk_mout_epll.clk,
+       &clk_dout_mpll,
+       &clk_fin_epll,
+       &clk_iis_cd2,
+       &clk_mout_hpll.clk,
+};
+
+static struct clk_sources clkset_audio2 = {
+       .sources        = clkset_audio2_list,
+       .nr_sources     = ARRAY_SIZE(clkset_audio2_list),
+};
+
+static struct clksrc_clk clk_audio2 = {
+       .clk    = {
+               .name           = "audio-bus",
+               .id             = 2,
+               .ctrlbit        = S5PC100_CLKGATE_SCLK1_AUDIO2,
+               .enable         = s5pc100_sclk1_ctrl,
+               .set_parent     = s5pc100_setparent_clksrc,
+               .get_rate       = s5pc100_getrate_clksrc,
+               .set_rate       = s5pc100_setrate_clksrc,
+               .round_rate     = s5pc100_roundrate_clksrc,
+       },
+       .shift          = S5PC100_CLKSRC3_AUDIO2_SHIFT,
+       .mask           = S5PC100_CLKSRC3_AUDIO2_MASK,
+       .sources        = &clkset_audio2,
+       .divider_shift  = S5PC100_CLKDIV4_AUDIO2_SHIFT,
+       .reg_divider    = S5PC100_CLKDIV4,
+       .reg_source     = S5PC100_CLKSRC3,
+};
+
+static struct clk *clkset_spdif_list[] = {
+       &clk_audio0.clk,
+       &clk_audio1.clk,
+       &clk_audio2.clk,
+};
+
+static struct clk_sources clkset_spdif = {
+       .sources        = clkset_spdif_list,
+       .nr_sources     = ARRAY_SIZE(clkset_spdif_list),
+};
+
+static struct clksrc_clk clk_spdif = {
+       .clk    = {
+               .name           = "spdif",
+               .id             = -1,
+       },
+       .shift          = S5PC100_CLKSRC3_SPDIF_SHIFT,
+       .mask           = S5PC100_CLKSRC3_SPDIF_MASK,
+       .sources        = &clkset_spdif,
+       .reg_source     = S5PC100_CLKSRC3,
+};
+
+static struct clk *clkset_lcd_fimc_list[] = {
+       &clk_mout_epll.clk,
+       &clk_dout_mpll,
+       &clk_mout_hpll.clk,
+       &clk_vclk_54m,
+};
+
+static struct clk_sources clkset_lcd_fimc = {
+       .sources        = clkset_lcd_fimc_list,
+       .nr_sources     = ARRAY_SIZE(clkset_lcd_fimc_list),
+};
+
+static struct clksrc_clk clk_lcd = {
+       .clk    = {
+               .name           = "lcd",
+               .id             = -1,
+               .ctrlbit        = S5PC100_CLKGATE_SCLK1_LCD,
+               .enable         = s5pc100_sclk1_ctrl,
+               .set_parent     = s5pc100_setparent_clksrc,
+               .get_rate       = s5pc100_getrate_clksrc,
+               .set_rate       = s5pc100_setrate_clksrc,
+               .round_rate     = s5pc100_roundrate_clksrc,
+       },
+       .shift          = S5PC100_CLKSRC2_LCD_SHIFT,
+       .mask           = S5PC100_CLKSRC2_LCD_MASK,
+       .sources        = &clkset_lcd_fimc,
+       .divider_shift  = S5PC100_CLKDIV3_LCD_SHIFT,
+       .reg_divider    = S5PC100_CLKDIV3,
+       .reg_source     = S5PC100_CLKSRC2,
+};
+
+static struct clksrc_clk clk_fimc0 = {
+       .clk    = {
+               .name           = "fimc",
+               .id             = 0,
+               .ctrlbit        = S5PC100_CLKGATE_SCLK1_FIMC0,
+               .enable         = s5pc100_sclk1_ctrl,
+               .set_parent     = s5pc100_setparent_clksrc,
+               .get_rate       = s5pc100_getrate_clksrc,
+               .set_rate       = s5pc100_setrate_clksrc,
+               .round_rate     = s5pc100_roundrate_clksrc,
+       },
+       .shift          = S5PC100_CLKSRC2_FIMC0_SHIFT,
+       .mask           = S5PC100_CLKSRC2_FIMC0_MASK,
+       .sources        = &clkset_lcd_fimc,
+       .divider_shift  = S5PC100_CLKDIV3_FIMC0_SHIFT,
+       .reg_divider    = S5PC100_CLKDIV3,
+       .reg_source     = S5PC100_CLKSRC2,
+};
+
+static struct clksrc_clk clk_fimc1 = {
+       .clk    = {
+               .name           = "fimc",
+               .id             = 1,
+               .ctrlbit        = S5PC100_CLKGATE_SCLK1_FIMC1,
+               .enable         = s5pc100_sclk1_ctrl,
+               .set_parent     = s5pc100_setparent_clksrc,
+               .get_rate       = s5pc100_getrate_clksrc,
+               .set_rate       = s5pc100_setrate_clksrc,
+               .round_rate     = s5pc100_roundrate_clksrc,
+       },
+       .shift          = S5PC100_CLKSRC2_FIMC1_SHIFT,
+       .mask           = S5PC100_CLKSRC2_FIMC1_MASK,
+       .sources        = &clkset_lcd_fimc,
+       .divider_shift  = S5PC100_CLKDIV3_FIMC1_SHIFT,
+       .reg_divider    = S5PC100_CLKDIV3,
+       .reg_source     = S5PC100_CLKSRC2,
+};
+
+static struct clksrc_clk clk_fimc2 = {
+       .clk    = {
+               .name           = "fimc",
+               .id             = 2,
+               .ctrlbit        = S5PC100_CLKGATE_SCLK1_FIMC2,
+               .enable         = s5pc100_sclk1_ctrl,
+               .set_parent     = s5pc100_setparent_clksrc,
+               .get_rate       = s5pc100_getrate_clksrc,
+               .set_rate       = s5pc100_setrate_clksrc,
+               .round_rate     = s5pc100_roundrate_clksrc,
+       },
+       .shift          = S5PC100_CLKSRC2_FIMC2_SHIFT,
+       .mask           = S5PC100_CLKSRC2_FIMC2_MASK,
+       .sources        = &clkset_lcd_fimc,
+       .divider_shift  = S5PC100_CLKDIV3_FIMC2_SHIFT,
+       .reg_divider    = S5PC100_CLKDIV3,
+       .reg_source     = S5PC100_CLKSRC2,
+};
+
+static struct clk *clkset_mmc_list[] = {
+       &clk_mout_epll.clk,
+       &clk_dout_mpll,
+       &clk_fin_epll,
+       &clk_mout_hpll.clk ,
+};
+
+static struct clk_sources clkset_mmc = {
+       .sources        = clkset_mmc_list,
+       .nr_sources     = ARRAY_SIZE(clkset_mmc_list),
+};
+
+static struct clksrc_clk clk_mmc0 = {
+       .clk    = {
+               .name           = "mmc_bus",
+               .id             = 0,
+               .ctrlbit        = S5PC100_CLKGATE_SCLK0_MMC0,
+               .enable         = s5pc100_sclk0_ctrl,
+               .set_parent     = s5pc100_setparent_clksrc,
+               .get_rate       = s5pc100_getrate_clksrc,
+               .set_rate       = s5pc100_setrate_clksrc,
+               .round_rate     = s5pc100_roundrate_clksrc,
+       },
+       .shift          = S5PC100_CLKSRC2_MMC0_SHIFT,
+       .mask           = S5PC100_CLKSRC2_MMC0_MASK,
+       .sources        = &clkset_mmc,
+       .divider_shift  = S5PC100_CLKDIV3_MMC0_SHIFT,
+       .reg_divider    = S5PC100_CLKDIV3,
+       .reg_source     = S5PC100_CLKSRC2,
+};
+
+static struct clksrc_clk clk_mmc1 = {
+       .clk    = {
+               .name           = "mmc_bus",
+               .id             = 1,
+               .ctrlbit        = S5PC100_CLKGATE_SCLK0_MMC1,
+               .enable         = s5pc100_sclk0_ctrl,
+               .set_parent     = s5pc100_setparent_clksrc,
+               .get_rate       = s5pc100_getrate_clksrc,
+               .set_rate       = s5pc100_setrate_clksrc,
+               .round_rate     = s5pc100_roundrate_clksrc,
+       },
+       .shift          = S5PC100_CLKSRC2_MMC1_SHIFT,
+       .mask           = S5PC100_CLKSRC2_MMC1_MASK,
+       .sources        = &clkset_mmc,
+       .divider_shift  = S5PC100_CLKDIV3_MMC1_SHIFT,
+       .reg_divider    = S5PC100_CLKDIV3,
+       .reg_source     = S5PC100_CLKSRC2,
+};
+
+static struct clksrc_clk clk_mmc2 = {
+       .clk    = {
+               .name           = "mmc_bus",
+               .id             = 2,
+               .ctrlbit        = S5PC100_CLKGATE_SCLK0_MMC2,
+               .enable         = s5pc100_sclk0_ctrl,
+               .set_parent     = s5pc100_setparent_clksrc,
+               .get_rate       = s5pc100_getrate_clksrc,
+               .set_rate       = s5pc100_setrate_clksrc,
+               .round_rate     = s5pc100_roundrate_clksrc,
+       },
+       .shift          = S5PC100_CLKSRC2_MMC2_SHIFT,
+       .mask           = S5PC100_CLKSRC2_MMC2_MASK,
+       .sources        = &clkset_mmc,
+       .divider_shift  = S5PC100_CLKDIV3_MMC2_SHIFT,
+       .reg_divider    = S5PC100_CLKDIV3,
+       .reg_source     = S5PC100_CLKSRC2,
+};
+
+
+static struct clk *clkset_usbhost_list[] = {
+       &clk_mout_epll.clk,
+       &clk_dout_mpll,
+       &clk_mout_hpll.clk,
+       &clk_48m,
+};
+
+static struct clk_sources clkset_usbhost = {
+       .sources        = clkset_usbhost_list,
+       .nr_sources     = ARRAY_SIZE(clkset_usbhost_list),
+};
+
+static struct clksrc_clk clk_usbhost = {
+       .clk    = {
+               .name           = "usbhost",
+               .id             = -1,
+               .ctrlbit        = S5PC100_CLKGATE_SCLK0_USBHOST,
+               .enable         = s5pc100_sclk0_ctrl,
+               .set_parent     = s5pc100_setparent_clksrc,
+               .get_rate       = s5pc100_getrate_clksrc,
+               .set_rate       = s5pc100_setrate_clksrc,
+               .round_rate     = s5pc100_roundrate_clksrc,
+       },
+       .shift          = S5PC100_CLKSRC1_UHOST_SHIFT,
+       .mask           = S5PC100_CLKSRC1_UHOST_MASK,
+       .sources        = &clkset_usbhost,
+       .divider_shift  = S5PC100_CLKDIV2_UHOST_SHIFT,
+       .reg_divider    = S5PC100_CLKDIV2,
+       .reg_source     = S5PC100_CLKSRC1,
 };
 
 /* Clock initialisation code */
 
 static struct clksrc_clk *init_parents[] = {
        &clk_mout_apll,
-       &clk_mout_epll,
        &clk_mout_mpll,
+       &clk_mout_am,
+       &clk_mout_onenand,
+       &clk_mout_epll,
+       &clk_mout_hpll,
+       &clk_spi0,
+       &clk_spi1,
+       &clk_spi2,
        &clk_uart_uclk1,
+       &clk_audio0,
+       &clk_audio1,
+       &clk_audio2,
+       &clk_spdif,
+       &clk_lcd,
+       &clk_fimc0,
+       &clk_fimc1,
+       &clk_fimc2,
+       &clk_mmc0,
+       &clk_mmc1,
+       &clk_mmc2,
+       &clk_usbhost,
 };
 
-static void __init_or_cpufreq s5pc1xx_set_clksrc(struct clksrc_clk *clk)
+static void __init_or_cpufreq s5pc100_set_clksrc(struct clksrc_clk *clk)
 {
        struct clk_sources *srcs = clk->sources;
        u32 clksrc = __raw_readl(clk->reg_source);
@@ -1036,9 +1015,9 @@ static void __init_or_cpufreq s5pc1xx_set_clksrc(struct clksrc_clk *clk)
 
        clk->clk.parent = srcs->sources[clksrc];
 
-       printk(KERN_INFO "%s: source is %s (%d), rate is %ld\n",
-              clk->clk.name, clk->clk.parent->name, clksrc,
-              clk_get_rate(&clk->clk));
+       printk(KERN_INFO "%s: source is %s (%d), rate is %ld.%03ld MHz\n",
+               clk->clk.name, clk->clk.parent->name, clksrc,
+               print_mhz(clk_get_rate(&clk->clk)));
 }
 
 #define GET_DIV(clk, field) ((((clk) & field##_MASK) >> field##_SHIFT) + 1)
@@ -1052,20 +1031,16 @@ void __init_or_cpufreq s5pc100_setup_clocks(void)
        unsigned long hclk;
        unsigned long pclkd0;
        unsigned long pclk;
-       unsigned long apll;
-       unsigned long mpll;
-       unsigned long hpll;
-       unsigned long epll;
+       unsigned long apll, mpll, epll, hpll;
        unsigned int ptr;
        u32 clkdiv0, clkdiv1;
 
        printk(KERN_DEBUG "%s: registering clocks\n", __func__);
 
-       clkdiv0 = __raw_readl(S5PC1XX_CLK_DIV0);
-       clkdiv1 = __raw_readl(S5PC1XX_CLK_DIV1);
+       clkdiv0 = __raw_readl(S5PC100_CLKDIV0);
+       clkdiv1 = __raw_readl(S5PC100_CLKDIV1);
 
-       printk(KERN_DEBUG "%s: clkdiv0 = %08x, clkdiv1 = %08x\n",
-                       __func__, clkdiv0, clkdiv1);
+       printk(KERN_DEBUG "%s: clkdiv0 = %08x, clkdiv1 = %08x\n", __func__, clkdiv0, clkdiv1);
 
        xtal_clk = clk_get(NULL, "xtal");
        BUG_ON(IS_ERR(xtal_clk));
@@ -1075,48 +1050,81 @@ void __init_or_cpufreq s5pc100_setup_clocks(void)
 
        printk(KERN_DEBUG "%s: xtal is %ld\n", __func__, xtal);
 
-       apll = s5pc1xx_get_pll(xtal, __raw_readl(S5PC1XX_APLL_CON));
-       mpll = s5pc1xx_get_pll(xtal, __raw_readl(S5PC1XX_MPLL_CON));
-       epll = s5pc1xx_get_pll(xtal, __raw_readl(S5PC1XX_EPLL_CON));
+       apll = s5pc1xx_get_pll(xtal, __raw_readl(S5PC100_APLL_CON));
+       mpll = s5pc1xx_get_pll(xtal, __raw_readl(S5PC100_MPLL_CON));
+       epll = s5pc1xx_get_pll(xtal, __raw_readl(S5PC100_EPLL_CON));
        hpll = s5pc1xx_get_pll(xtal, __raw_readl(S5PC100_HPLL_CON));
 
-       printk(KERN_INFO "S5PC100: PLL settings, A=%ld, M=%ld, E=%ld, H=%ld\n",
-              apll, mpll, epll, hpll);
+       printk(KERN_INFO "S5PC100: Apll=%ld.%03ld Mhz, Mpll=%ld.%03ld Mhz"
+               ", Epll=%ld.%03ld Mhz, Hpll=%ld.%03ld Mhz\n",
+               print_mhz(apll), print_mhz(mpll),
+               print_mhz(epll), print_mhz(hpll));
 
-       armclk = apll / GET_DIV(clkdiv0, S5PC1XX_CLKDIV0_APLL);
+       armclk = apll / GET_DIV(clkdiv0, S5PC100_CLKDIV0_APLL);
        armclk = armclk / GET_DIV(clkdiv0, S5PC100_CLKDIV0_ARM);
        hclkd0 = armclk / GET_DIV(clkdiv0, S5PC100_CLKDIV0_D0);
        pclkd0 = hclkd0 / GET_DIV(clkdiv0, S5PC100_CLKDIV0_PCLKD0);
        hclk = mpll / GET_DIV(clkdiv1, S5PC100_CLKDIV1_D1);
        pclk = hclk / GET_DIV(clkdiv1, S5PC100_CLKDIV1_PCLKD1);
 
-       printk(KERN_INFO "S5PC100: ARMCLK=%ld, HCLKD0=%ld, PCLKD0=%ld, HCLK=%ld, PCLK=%ld\n",
-              armclk, hclkd0, pclkd0, hclk, pclk);
+       printk(KERN_INFO "S5PC100: ARMCLK=%ld.%03ld MHz, HCLKD0=%ld.%03ld MHz,"
+               " PCLKD0=%ld.%03ld MHz\n, HCLK=%ld.%03ld MHz,"
+               " PCLK=%ld.%03ld MHz\n",
+               print_mhz(armclk), print_mhz(hclkd0),
+               print_mhz(pclkd0), print_mhz(hclk), print_mhz(pclk));
 
        clk_fout_apll.rate = apll;
        clk_fout_mpll.rate = mpll;
        clk_fout_epll.rate = epll;
-       clk_fout_apll.rate = apll;
+       clk_fout_hpll.rate = hpll;
 
        clk_h.rate = hclk;
        clk_p.rate = pclk;
+       clk_f.rate = armclk;
 
        for (ptr = 0; ptr < ARRAY_SIZE(init_parents); ptr++)
-               s5pc1xx_set_clksrc(init_parents[ptr]);
+               s5pc100_set_clksrc(init_parents[ptr]);
 }
 
 static struct clk *clks[] __initdata = {
        &clk_ext_xtal_mux,
-       &clk_mout_epll.clk,
-       &clk_fout_epll,
+       &clk_mout_apll.clk,
+       &clk_dout_apll,
+       &clk_dout_d0_bus,
+       &clk_dout_pclkd0,
+       &clk_dout_apll2,
        &clk_mout_mpll.clk,
+       &clk_mout_am.clk,
+       &clk_dout_d1_bus,
+       &clk_mout_onenand.clk,
+       &clk_dout_pclkd1,
+       &clk_dout_mpll2,
+       &clk_dout_cam,
        &clk_dout_mpll,
+       &clk_mout_epll.clk,
+       &clk_fout_epll,
+       &clk_iis_cd0,
+       &clk_iis_cd1,
+       &clk_iis_cd2,
+       &clk_pcm_cd0,
+       &clk_pcm_cd1,
+       &clk_spi0.clk,
+       &clk_spi1.clk,
+       &clk_spi2.clk,
        &clk_uart_uclk1.clk,
-       &clk_ext,
-       &clk_epll,
-       &clk_27m,
-       &clk_48m,
-       &clk_54m,
+       &clk_audio0.clk,
+       &clk_audio1.clk,
+       &clk_audio2.clk,
+       &clk_spdif.clk,
+       &clk_lcd.clk,
+       &clk_fimc0.clk,
+       &clk_fimc1.clk,
+       &clk_fimc2.clk,
+       &clk_mmc0.clk,
+       &clk_mmc1.clk,
+       &clk_mmc2.clk,
+       &clk_usbhost.clk,
+       &clk_arm,
 };
 
 void __init s5pc100_register_clocks(void)
@@ -1133,7 +1141,4 @@ void __init s5pc100_register_clocks(void)
                               clkp->name, ret);
                }
        }
-
-       clk_mpll.parent = &clk_mout_mpll.clk;
-       clk_epll.parent = &clk_mout_epll.clk;
 }
diff --git a/arch/arm/plat-s5pc1xx/setup-fb-24bpp.c b/arch/arm/plat-s5pc1xx/setup-fb-24bpp.c
new file mode 100644 (file)
index 0000000..1a63768
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * linux/arch/arm/plat-s5pc100/setup-fb-24bpp.c
+ *
+ * Copyright 2009 Samsung Electronics
+ *
+ * Base S5PC1XX setup information for 24bpp LCD framebuffer
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/fb.h>
+#include <linux/gpio.h>
+
+#include <mach/regs-fb.h>
+#include <mach/map.h>
+#include <plat/fb.h>
+#include <plat/gpio-cfg.h>
+#include <plat/gpio-cfg-s5pc1xx.h>
+
+#define DISR_OFFSET    0x7008
+
+void s5pc100_fb_gpio_setup_24bpp(void)
+{
+       unsigned int gpio = 0;
+
+       for (gpio = S5PC100_GPF0(0); gpio <= S5PC100_GPF0(7); gpio++) {
+               s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2));
+               s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE);
+       }
+
+       for (gpio = S5PC100_GPF1(0); gpio <= S5PC100_GPF1(7); gpio++) {
+               s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2));
+               s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE);
+       }
+
+       for (gpio = S5PC100_GPF2(0); gpio <= S5PC100_GPF2(7); gpio++) {
+               s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2));
+               s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE);
+       }
+
+       for (gpio = S5PC100_GPF3(0); gpio <= S5PC100_GPF3(3); gpio++) {
+               s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2));
+               s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE);
+       }
+}
index 3d00c02..5e4a7c3 100644 (file)
 
 struct platform_device; /* don't need the contents */
 
+#include <linux/gpio.h>
 #include <plat/iic.h>
+#include <plat/gpio-cfg.h>
 
 void s3c_i2c0_cfg_gpio(struct platform_device *dev)
 {
-       /* Pin configuration would be needed */
+       s3c_gpio_cfgpin(S5PC100_GPD(3), S3C_GPIO_SFN(2));
+       s3c_gpio_setpull(S5PC100_GPD(3), S3C_GPIO_PULL_UP);
+       s3c_gpio_cfgpin(S5PC100_GPD(4), S3C_GPIO_SFN(2));
+       s3c_gpio_setpull(S5PC100_GPD(4), S3C_GPIO_PULL_UP);
 }
index c8f3ca4..a0a8b4a 100644 (file)
 
 struct platform_device; /* don't need the contents */
 
+#include <linux/gpio.h>
 #include <plat/iic.h>
+#include <plat/gpio-cfg.h>
 
 void s3c_i2c1_cfg_gpio(struct platform_device *dev)
 {
-       /* Pin configuration would be needed */
+       s3c_gpio_cfgpin(S5PC100_GPD(5), S3C_GPIO_SFN(2));
+       s3c_gpio_setpull(S5PC100_GPD(5), S3C_GPIO_PULL_UP);
+       s3c_gpio_cfgpin(S5PC100_GPD(6), S3C_GPIO_SFN(2));
+       s3c_gpio_setpull(S5PC100_GPD(6), S3C_GPIO_PULL_UP);
 }
diff --git a/arch/arm/plat-s5pc1xx/setup-sdhci-gpio.c b/arch/arm/plat-s5pc1xx/setup-sdhci-gpio.c
new file mode 100644 (file)
index 0000000..185c894
--- /dev/null
@@ -0,0 +1,86 @@
+/* linux/arch/arm/plat-s5pc1xx/setup-sdhci-gpio.c
+ *
+ * Copyright 2009 Samsung Eletronics
+ *
+ * S5PC1XX - Helper functions for setting up SDHCI device(s) GPIO (HSMMC)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/gpio.h>
+#include <linux/mmc/host.h>
+#include <linux/mmc/card.h>
+
+#include <plat/gpio-cfg.h>
+#include <plat/regs-sdhci.h>
+
+void s5pc100_setup_sdhci0_cfg_gpio(struct platform_device *dev, int width)
+{
+       unsigned int gpio;
+       unsigned int end;
+       unsigned int num;
+
+       num = width;
+       /* In case of 8 width, we should decrease the 2 */
+       if (width == 8)
+               num = width - 2;
+
+       end = S5PC100_GPG0(2 + num);
+
+       /* Set all the necessary GPG0/GPG1 pins to special-function 0 */
+       for (gpio = S5PC100_GPG0(0); gpio < end; gpio++) {
+               s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2));
+               s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE);
+       }
+
+       if (width == 8) {
+               for (gpio = S5PC100_GPG1(0); gpio <= S5PC100_GPG1(1); gpio++) {
+                       s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2));
+                       s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE);
+               }
+       }
+
+       s3c_gpio_setpull(S5PC100_GPG1(2), S3C_GPIO_PULL_UP);
+       s3c_gpio_cfgpin(S5PC100_GPG1(2), S3C_GPIO_SFN(2));
+}
+
+void s5pc100_setup_sdhci1_cfg_gpio(struct platform_device *dev, int width)
+{
+       unsigned int gpio;
+       unsigned int end;
+
+       end = S5PC100_GPG2(2 + width);
+
+       /* Set all the necessary GPG2 pins to special-function 2 */
+       for (gpio = S5PC100_GPG2(0); gpio < end; gpio++) {
+               s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2));
+               s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE);
+       }
+
+       s3c_gpio_setpull(S5PC100_GPG2(6), S3C_GPIO_PULL_UP);
+       s3c_gpio_cfgpin(S5PC100_GPG2(6), S3C_GPIO_SFN(2));
+}
+
+void s5pc100_setup_sdhci2_cfg_gpio(struct platform_device *dev, int width)
+{
+       unsigned int gpio;
+       unsigned int end;
+
+       end = S5PC100_GPG3(2 + width);
+
+       /* Set all the necessary GPG3 pins to special-function 2 */
+       for (gpio = S5PC100_GPG3(0); gpio < end; gpio++) {
+               s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2));
+               s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE);
+       }
+
+       s3c_gpio_setpull(S5PC100_GPG3(6), S3C_GPIO_PULL_UP);
+       s3c_gpio_cfgpin(S5PC100_GPG3(6), S3C_GPIO_SFN(2));
+}
diff --git a/arch/arm/plat-samsung/Kconfig b/arch/arm/plat-samsung/Kconfig
new file mode 100644 (file)
index 0000000..486a0d6
--- /dev/null
@@ -0,0 +1,17 @@
+# arch/arm/plat-samsung/Kconfig
+#
+# Copyright 2009 Simtec Electronics
+#
+# Licensed under GPLv2
+
+config PLAT_SAMSUNG
+       bool
+       depends on ARCH_S3C2410 || ARCH_S3C24A0 || ARCH_S3C64XX || ARCH_S5PC1XX
+       default y
+       help
+         Base platform code for all Samsung SoC based systems
+
+if PLAT_SAMSUNG
+
+
+endif
diff --git a/arch/arm/plat-samsung/Makefile b/arch/arm/plat-samsung/Makefile
new file mode 100644 (file)
index 0000000..4478b9f
--- /dev/null
@@ -0,0 +1,11 @@
+# arch/arm/plat-s3c64xx/Makefile
+#
+# Copyright 2009 Simtec Electronics
+#
+# Licensed under GPLv2
+
+obj-y                          :=
+obj-m                          :=
+obj-n                          := dummy.o
+obj-                           :=
+
index 35e3bd9..d856354 100644 (file)
@@ -92,6 +92,7 @@ config PLATFORM_AT32AP
        select PERFORMANCE_COUNTERS
        select ARCH_REQUIRE_GPIOLIB
        select GENERIC_ALLOCATOR
+       select HAVE_FB_ATMEL
 
 #
 # CPU types
index 6706747..96e5382 100644 (file)
@@ -107,6 +107,7 @@ extern void flush_icache_page(struct vm_area_struct *vma, struct page *page);
  * do something here, but only for certain configurations.  No such
  * configurations exist at this time.
  */
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 0
 #define flush_dcache_page(page)                        do { } while (0)
 #define flush_dcache_mmap_lock(page)           do { } while (0)
 #define flush_dcache_mmap_unlock(page)         do { } while (0)
index af03a36..417eaac 100644 (file)
@@ -68,9 +68,11 @@ do { memcpy(dst, src, len);                                          \
 #endif
 #if defined(CONFIG_BFIN_EXTMEM_WRITEBACK) || defined(CONFIG_BFIN_L2_WRITEBACK)
 # define flush_dcache_range(start,end)         blackfin_dcache_flush_range((start), (end))
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 1
 # define flush_dcache_page(page)               blackfin_dflush_page(page_address(page))
 #else
 # define flush_dcache_range(start,end)         do { } while (0)
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 0
 # define flush_dcache_page(page)               do { } while (0)
 #endif
 
index cf60e3f..36795bc 100644 (file)
@@ -12,6 +12,7 @@
 #define flush_cache_dup_mm(mm)                 do { } while (0)
 #define flush_cache_range(vma, start, end)     do { } while (0)
 #define flush_cache_page(vma, vmaddr, pfn)     do { } while (0)
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 0
 #define flush_dcache_page(page)                        do { } while (0)
 #define flush_dcache_mmap_lock(mapping)                do { } while (0)
 #define flush_dcache_mmap_unlock(mapping)      do { } while (0)
index 432a69e..edbac54 100644 (file)
@@ -47,6 +47,7 @@ static inline void __flush_cache_all(void)
 }
 
 /* dcache/icache coherency... */
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 1
 #ifdef CONFIG_MMU
 extern void flush_dcache_page(struct page *page);
 #else
index 0d4d3e3..5fa3889 100644 (file)
@@ -211,37 +211,6 @@ static int cmode_procctl(ctl_table *ctl, int write,
        return try_set_cmode(new_cmode)?:*lenp;
 }
 
-static int cmode_sysctl(ctl_table *table,
-                       void __user *oldval, size_t __user *oldlenp,
-                       void __user *newval, size_t newlen)
-{
-       if (oldval && oldlenp) {
-               size_t oldlen;
-
-               if (get_user(oldlen, oldlenp))
-                       return -EFAULT;
-
-               if (oldlen != sizeof(int))
-                       return -EINVAL;
-
-               if (put_user(clock_cmode_current, (unsigned __user *)oldval) ||
-                   put_user(sizeof(int), oldlenp))
-                       return -EFAULT;
-       }
-       if (newval && newlen) {
-               int new_cmode;
-
-               if (newlen != sizeof(int))
-                       return -EINVAL;
-
-               if (get_user(new_cmode, (int __user *)newval))
-                       return -EFAULT;
-
-               return try_set_cmode(new_cmode)?:1;
-       }
-       return 1;
-}
-
 static int try_set_p0(int new_p0)
 {
        unsigned long flags, clkc;
@@ -314,37 +283,6 @@ static int p0_procctl(ctl_table *ctl, int write,
        return try_set_p0(new_p0)?:*lenp;
 }
 
-static int p0_sysctl(ctl_table *table,
-                    void __user *oldval, size_t __user *oldlenp,
-                    void __user *newval, size_t newlen)
-{
-       if (oldval && oldlenp) {
-               size_t oldlen;
-
-               if (get_user(oldlen, oldlenp))
-                       return -EFAULT;
-
-               if (oldlen != sizeof(int))
-                       return -EINVAL;
-
-               if (put_user(clock_p0_current, (unsigned __user *)oldval) ||
-                   put_user(sizeof(int), oldlenp))
-                       return -EFAULT;
-       }
-       if (newval && newlen) {
-               int new_p0;
-
-               if (newlen != sizeof(int))
-                       return -EINVAL;
-
-               if (get_user(new_p0, (int __user *)newval))
-                       return -EFAULT;
-
-               return try_set_p0(new_p0)?:1;
-       }
-       return 1;
-}
-
 static int cm_procctl(ctl_table *ctl, int write,
                      void __user *buffer, size_t *lenp, loff_t *fpos)
 {
@@ -358,87 +296,47 @@ static int cm_procctl(ctl_table *ctl, int write,
        return try_set_cm(new_cm)?:*lenp;
 }
 
-static int cm_sysctl(ctl_table *table,
-                    void __user *oldval, size_t __user *oldlenp,
-                    void __user *newval, size_t newlen)
-{
-       if (oldval && oldlenp) {
-               size_t oldlen;
-
-               if (get_user(oldlen, oldlenp))
-                       return -EFAULT;
-
-               if (oldlen != sizeof(int))
-                       return -EINVAL;
-
-               if (put_user(clock_cm_current, (unsigned __user *)oldval) ||
-                   put_user(sizeof(int), oldlenp))
-                       return -EFAULT;
-       }
-       if (newval && newlen) {
-               int new_cm;
-
-               if (newlen != sizeof(int))
-                       return -EINVAL;
-
-               if (get_user(new_cm, (int __user *)newval))
-                       return -EFAULT;
-
-               return try_set_cm(new_cm)?:1;
-       }
-       return 1;
-}
-
-
 static struct ctl_table pm_table[] =
 {
        {
-               .ctl_name       = CTL_PM_SUSPEND,
                .procname       = "suspend",
                .data           = NULL,
                .maxlen         = 0,
                .mode           = 0200,
-               .proc_handler   = &sysctl_pm_do_suspend,
+               .proc_handler   = sysctl_pm_do_suspend,
        },
        {
-               .ctl_name       = CTL_PM_CMODE,
                .procname       = "cmode",
                .data           = &clock_cmode_current,
                .maxlen         = sizeof(int),
                .mode           = 0644,
-               .proc_handler   = &cmode_procctl,
-               .strategy       = &cmode_sysctl,
+               .proc_handler   = cmode_procctl,
        },
        {
-               .ctl_name       = CTL_PM_P0,
                .procname       = "p0",
                .data           = &clock_p0_current,
                .maxlen         = sizeof(int),
                .mode           = 0644,
-               .proc_handler   = &p0_procctl,
-               .strategy       = &p0_sysctl,
+               .proc_handler   = p0_procctl,
        },
        {
-               .ctl_name       = CTL_PM_CM,
                .procname       = "cm",
                .data           = &clock_cm_current,
                .maxlen         = sizeof(int),
                .mode           = 0644,
-               .proc_handler   = &cm_procctl,
-               .strategy       = &cm_sysctl,
+               .proc_handler   = cm_procctl,
        },
-       { .ctl_name = 0}
+       { }
 };
 
 static struct ctl_table pm_dir_table[] =
 {
        {
-               .ctl_name       = CTL_PM,
                .procname       = "pm",
                .mode           = 0555,
                .child          = pm_table,
        },
-       { .ctl_name = 0}
+       { }
 };
 
 /*
index 3e9d7e0..035516c 100644 (file)
@@ -176,21 +176,19 @@ static int procctl_frv_pin_cxnr(ctl_table *table, int write, struct file *filp,
 static struct ctl_table frv_table[] =
 {
        {
-               .ctl_name       = 1,
                .procname       = "cache-mode",
                .data           = NULL,
                .maxlen         = 0,
                .mode           = 0644,
-               .proc_handler   = &procctl_frv_cachemode,
+               .proc_handler   = procctl_frv_cachemode,
        },
 #ifdef CONFIG_MMU
        {
-               .ctl_name       = 2,
                .procname       = "pin-cxnr",
                .data           = NULL,
                .maxlen         = 0,
                .mode           = 0644,
-               .proc_handler   = &procctl_frv_pin_cxnr
+               .proc_handler   = procctl_frv_pin_cxnr
        },
 #endif
        {}
@@ -203,7 +201,6 @@ static struct ctl_table frv_table[] =
 static struct ctl_table frv_dir_table[] =
 {
        {
-               .ctl_name       = CTL_FRV,
                .procname       = "frv",
                .mode           = 0555,
                .child          = frv_table
index 5ffdca2..4cf2df2 100644 (file)
@@ -15,6 +15,7 @@
 #define        flush_cache_dup_mm(mm)          do { } while (0)
 #define        flush_cache_range(vma,a,b)
 #define        flush_cache_page(vma,p,pfn)
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 0
 #define        flush_dcache_page(page)
 #define        flush_dcache_mmap_lock(mapping)
 #define        flush_dcache_mmap_unlock(mapping)
index af9405c..10c3751 100644 (file)
@@ -327,7 +327,7 @@ ia32_syscall_table:
        data8 compat_sys_writev
        data8 sys_getsid
        data8 sys_fdatasync
-       data8 sys32_sysctl
+       data8 compat_sys_sysctl
        data8 sys_mlock           /* 150 */
        data8 sys_munlock
        data8 sys_mlockall
index 625ed8f..429ec96 100644 (file)
@@ -1628,61 +1628,6 @@ sys32_msync (unsigned int start, unsigned int len, int flags)
        return sys_msync(addr, len + (start - addr), flags);
 }
 
-struct sysctl32 {
-       unsigned int    name;
-       int             nlen;
-       unsigned int    oldval;
-       unsigned int    oldlenp;
-       unsigned int    newval;
-       unsigned int    newlen;
-       unsigned int    __unused[4];
-};
-
-#ifdef CONFIG_SYSCTL_SYSCALL
-asmlinkage long
-sys32_sysctl (struct sysctl32 __user *args)
-{
-       struct sysctl32 a32;
-       mm_segment_t old_fs = get_fs ();
-       void __user *oldvalp, *newvalp;
-       size_t oldlen;
-       int __user *namep;
-       long ret;
-
-       if (copy_from_user(&a32, args, sizeof(a32)))
-               return -EFAULT;
-
-       /*
-        * We need to pre-validate these because we have to disable address checking
-        * before calling do_sysctl() because of OLDLEN but we can't run the risk of the
-        * user specifying bad addresses here.  Well, since we're dealing with 32 bit
-        * addresses, we KNOW that access_ok() will always succeed, so this is an
-        * expensive NOP, but so what...
-        */
-       namep = (int __user *) compat_ptr(a32.name);
-       oldvalp = compat_ptr(a32.oldval);
-       newvalp = compat_ptr(a32.newval);
-
-       if ((oldvalp && get_user(oldlen, (int __user *) compat_ptr(a32.oldlenp)))
-           || !access_ok(VERIFY_WRITE, namep, 0)
-           || !access_ok(VERIFY_WRITE, oldvalp, 0)
-           || !access_ok(VERIFY_WRITE, newvalp, 0))
-               return -EFAULT;
-
-       set_fs(KERNEL_DS);
-       lock_kernel();
-       ret = do_sysctl(namep, a32.nlen, oldvalp, (size_t __user *) &oldlen,
-                       newvalp, (size_t) a32.newlen);
-       unlock_kernel();
-       set_fs(old_fs);
-
-       if (oldvalp && put_user (oldlen, (int __user *) compat_ptr(a32.oldlenp)))
-               return -EFAULT;
-
-       return ret;
-}
-#endif
-
 asmlinkage long
 sys32_newuname (struct new_utsname __user *name)
 {
index c8ce271..429eefc 100644 (file)
@@ -25,6 +25,7 @@
 #define flush_cache_vmap(start, end)           do { } while (0)
 #define flush_cache_vunmap(start, end)         do { } while (0)
 
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 1
 #define flush_dcache_page(page)                        \
 do {                                           \
        clear_bit(PG_arch_1, &(page)->flags);   \
index 18a7e49..bc90c75 100644 (file)
@@ -60,6 +60,7 @@ struct kvm_ioapic_state {
 #define KVM_IRQCHIP_PIC_MASTER   0
 #define KVM_IRQCHIP_PIC_SLAVE    1
 #define KVM_IRQCHIP_IOAPIC       2
+#define KVM_NR_IRQCHIPS          3
 
 #define KVM_CONTEXT_SIZE       8*1024
 
index d9b6325..a362e67 100644 (file)
@@ -475,7 +475,6 @@ struct kvm_arch {
        struct list_head assigned_dev_head;
        struct iommu_domain *iommu_domain;
        int iommu_flags;
-       struct hlist_head irq_ack_notifier_list;
 
        unsigned long irq_sources_bitmap;
        unsigned long irq_states[KVM_IOAPIC_NUM_PINS];
index 6631a9d..b942f40 100644 (file)
@@ -239,32 +239,29 @@ kdump_init_notifier(struct notifier_block *self, unsigned long val, void *data)
 #ifdef CONFIG_SYSCTL
 static ctl_table kdump_ctl_table[] = {
        {
-               .ctl_name = CTL_UNNUMBERED,
                .procname = "kdump_on_init",
                .data = &kdump_on_init,
                .maxlen = sizeof(int),
                .mode = 0644,
-               .proc_handler = &proc_dointvec,
+               .proc_handler = proc_dointvec,
        },
        {
-               .ctl_name = CTL_UNNUMBERED,
                .procname = "kdump_on_fatal_mca",
                .data = &kdump_on_fatal_mca,
                .maxlen = sizeof(int),
                .mode = 0644,
-               .proc_handler = &proc_dointvec,
+               .proc_handler = proc_dointvec,
        },
-       { .ctl_name = 0 }
+       { }
 };
 
 static ctl_table sys_table[] = {
        {
-         .ctl_name = CTL_KERN,
          .procname = "kernel",
          .mode = 0555,
          .child = kdump_ctl_table,
        },
-       { .ctl_name = 0 }
+       { }
 };
 #endif
 
index f178270..402698b 100644 (file)
@@ -522,42 +522,37 @@ EXPORT_SYMBOL(pfm_sysctl);
 
 static ctl_table pfm_ctl_table[]={
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "debug",
                .data           = &pfm_sysctl.debug,
                .maxlen         = sizeof(int),
                .mode           = 0666,
-               .proc_handler   = &proc_dointvec,
+               .proc_handler   = proc_dointvec,
        },
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "debug_ovfl",
                .data           = &pfm_sysctl.debug_ovfl,
                .maxlen         = sizeof(int),
                .mode           = 0666,
-               .proc_handler   = &proc_dointvec,
+               .proc_handler   = proc_dointvec,
        },
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "fastctxsw",
                .data           = &pfm_sysctl.fastctxsw,
                .maxlen         = sizeof(int),
                .mode           = 0600,
-               .proc_handler   =  &proc_dointvec,
+               .proc_handler   = proc_dointvec,
        },
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "expert_mode",
                .data           = &pfm_sysctl.expert_mode,
                .maxlen         = sizeof(int),
                .mode           = 0600,
-               .proc_handler   = &proc_dointvec,
+               .proc_handler   = proc_dointvec,
        },
        {}
 };
 static ctl_table pfm_sysctl_dir[] = {
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "perfmon",
                .mode           = 0555,
                .child          = pfm_ctl_table,
@@ -566,7 +561,6 @@ static ctl_table pfm_sysctl_dir[] = {
 };
 static ctl_table pfm_sysctl_root[] = {
        {
-               .ctl_name       = CTL_KERN,
                .procname       = "kernel",
                .mode           = 0555,
                .child          = pfm_sysctl_dir,
index 0bb99b7..1089b3e 100644 (file)
@@ -49,7 +49,7 @@ EXTRA_CFLAGS += -Ivirt/kvm -Iarch/ia64/kvm/
 EXTRA_AFLAGS += -Ivirt/kvm -Iarch/ia64/kvm/
 
 common-objs = $(addprefix ../../../virt/kvm/, kvm_main.o ioapic.o \
-               coalesced_mmio.o irq_comm.o)
+               coalesced_mmio.o irq_comm.o assigned-dev.o)
 
 ifeq ($(CONFIG_IOMMU_API),y)
 common-objs += $(addprefix ../../../virt/kvm/, iommu.o)
index 0ad09f0..5fdeec5 100644 (file)
@@ -124,7 +124,7 @@ long ia64_pal_vp_create(u64 *vpd, u64 *host_iva, u64 *opt_handler)
 
 static  DEFINE_SPINLOCK(vp_lock);
 
-void kvm_arch_hardware_enable(void *garbage)
+int kvm_arch_hardware_enable(void *garbage)
 {
        long  status;
        long  tmp_base;
@@ -137,7 +137,7 @@ void kvm_arch_hardware_enable(void *garbage)
        slot = ia64_itr_entry(0x3, KVM_VMM_BASE, pte, KVM_VMM_SHIFT);
        local_irq_restore(saved_psr);
        if (slot < 0)
-               return;
+               return -EINVAL;
 
        spin_lock(&vp_lock);
        status = ia64_pal_vp_init_env(kvm_vsa_base ?
@@ -145,7 +145,7 @@ void kvm_arch_hardware_enable(void *garbage)
                        __pa(kvm_vm_buffer), KVM_VM_BUFFER_BASE, &tmp_base);
        if (status != 0) {
                printk(KERN_WARNING"kvm: Failed to Enable VT Support!!!!\n");
-               return ;
+               return -EINVAL;
        }
 
        if (!kvm_vsa_base) {
@@ -154,6 +154,8 @@ void kvm_arch_hardware_enable(void *garbage)
        }
        spin_unlock(&vp_lock);
        ia64_ptr_entry(0x3, slot);
+
+       return 0;
 }
 
 void kvm_arch_hardware_disable(void *garbage)
@@ -851,8 +853,7 @@ static int kvm_vm_ioctl_get_irqchip(struct kvm *kvm,
        r = 0;
        switch (chip->chip_id) {
        case KVM_IRQCHIP_IOAPIC:
-               memcpy(&chip->chip.ioapic, ioapic_irqchip(kvm),
-                               sizeof(struct kvm_ioapic_state));
+               r = kvm_get_ioapic(kvm, &chip->chip.ioapic);
                break;
        default:
                r = -EINVAL;
@@ -868,9 +869,7 @@ static int kvm_vm_ioctl_set_irqchip(struct kvm *kvm, struct kvm_irqchip *chip)
        r = 0;
        switch (chip->chip_id) {
        case KVM_IRQCHIP_IOAPIC:
-               memcpy(ioapic_irqchip(kvm),
-                               &chip->chip.ioapic,
-                               sizeof(struct kvm_ioapic_state));
+               r = kvm_set_ioapic(kvm, &chip->chip.ioapic);
                break;
        default:
                r = -EINVAL;
@@ -944,7 +943,7 @@ long kvm_arch_vm_ioctl(struct file *filp,
 {
        struct kvm *kvm = filp->private_data;
        void __user *argp = (void __user *)arg;
-       int r = -EINVAL;
+       int r = -ENOTTY;
 
        switch (ioctl) {
        case KVM_SET_MEMORY_REGION: {
@@ -985,10 +984,8 @@ long kvm_arch_vm_ioctl(struct file *filp,
                        goto out;
                if (irqchip_in_kernel(kvm)) {
                        __s32 status;
-                       mutex_lock(&kvm->irq_lock);
                        status = kvm_set_irq(kvm, KVM_USERSPACE_IRQ_SOURCE_ID,
                                    irq_event.irq, irq_event.level);
-                       mutex_unlock(&kvm->irq_lock);
                        if (ioctl == KVM_IRQ_LINE_STATUS) {
                                irq_event.status = status;
                                if (copy_to_user(argp, &irq_event,
index 78587c9..8e8e045 100644 (file)
@@ -12,6 +12,7 @@ extern void _flush_cache_copyback_all(void);
 #define flush_cache_dup_mm(mm)                 do { } while (0)
 #define flush_cache_range(vma, start, end)     do { } while (0)
 #define flush_cache_page(vma, vmaddr, pfn)     do { } while (0)
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 0
 #define flush_dcache_page(page)                        do { } while (0)
 #define flush_dcache_mmap_lock(mapping)                do { } while (0)
 #define flush_dcache_mmap_unlock(mapping)      do { } while (0)
@@ -33,6 +34,7 @@ extern void smp_flush_cache_all(void);
 #define flush_cache_dup_mm(mm)                 do { } while (0)
 #define flush_cache_range(vma, start, end)     do { } while (0)
 #define flush_cache_page(vma, vmaddr, pfn)     do { } while (0)
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 0
 #define flush_dcache_page(page)                        do { } while (0)
 #define flush_dcache_mmap_lock(mapping)                do { } while (0)
 #define flush_dcache_mmap_unlock(mapping)      do { } while (0)
@@ -46,6 +48,7 @@ extern void smp_flush_cache_all(void);
 #define flush_cache_dup_mm(mm)                 do { } while (0)
 #define flush_cache_range(vma, start, end)     do { } while (0)
 #define flush_cache_page(vma, vmaddr, pfn)     do { } while (0)
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 0
 #define flush_dcache_page(page)                        do { } while (0)
 #define flush_dcache_mmap_lock(mapping)                do { } while (0)
 #define flush_dcache_mmap_unlock(mapping)      do { } while (0)
index 16bf375..73de7c8 100644 (file)
@@ -128,6 +128,7 @@ static inline void __flush_page_to_ram(void *vaddr)
        }
 }
 
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 1
 #define flush_dcache_page(page)                __flush_page_to_ram(page_address(page))
 #define flush_dcache_mmap_lock(mapping)                do { } while (0)
 #define flush_dcache_mmap_unlock(mapping)      do { } while (0)
index c65f00a..89f1956 100644 (file)
@@ -12,6 +12,7 @@
 #define flush_cache_range(vma, start, end)     __flush_cache_all()
 #define flush_cache_page(vma, vmaddr)          do { } while (0)
 #define flush_dcache_range(start,len)          __flush_cache_all()
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 0
 #define flush_dcache_page(page)                        do { } while (0)
 #define flush_dcache_mmap_lock(mapping)                do { } while (0)
 #define flush_dcache_mmap_unlock(mapping)      do { } while (0)
index 8c9194b..a6ab663 100644 (file)
@@ -71,6 +71,8 @@ struct switch_stack {
 #define PTRACE_GETFPREGS          14
 #define PTRACE_SETFPREGS          15
 
+#define PTRACE_SINGLEBLOCK     33      /* resume execution until next branch */
+
 #ifdef __KERNEL__
 
 #ifndef PS_S
@@ -82,6 +84,21 @@ struct switch_stack {
 #define instruction_pointer(regs) ((regs)->pc)
 #define profile_pc(regs) instruction_pointer(regs)
 extern void show_regs(struct pt_regs *);
+
+/*
+ * These are defined as per linux/ptrace.h, which see.
+ */
+struct task_struct;
+
+#define arch_has_single_step() (1)
+extern void user_enable_single_step(struct task_struct *);
+extern void user_disable_single_step(struct task_struct *);
+
+#ifdef CONFIG_MMU
+#define arch_has_block_step()  (1)
+extern void user_enable_block_step(struct task_struct *);
+#endif
+
 #endif /* __KERNEL__ */
 #endif /* __ASSEMBLY__ */
 #endif /* _M68K_PTRACE_H */
index b6da388..167e518 100644 (file)
@@ -4,10 +4,12 @@
 #ifndef ASM_OFFSETS_C
 #include <asm/asm-offsets.h>
 #endif
-#include <asm/current.h>
 #include <asm/types.h>
 #include <asm/page.h>
 
+#ifndef __ASSEMBLY__
+#include <asm/current.h>
+
 struct thread_info {
        struct task_struct      *task;          /* main task structure */
        unsigned long           flags;
@@ -16,6 +18,7 @@ struct thread_info {
        __u32 cpu; /* should always be 0 on m68k */
        struct restart_block    restart_block;
 };
+#endif /* __ASSEMBLY__ */
 
 #define PREEMPT_ACTIVE         0x4000000
 
index c5b3363..77fc7c1 100644 (file)
@@ -179,7 +179,11 @@ do_signal_return:
        addql   #8,%sp
        RESTORE_SWITCH_STACK
        addql   #4,%sp
-       jbra    resume_userspace
+       tstl    %d0
+       jeq     resume_userspace
+       | when single stepping into handler stop at the first insn
+       btst    #6,%curptr@(TASK_INFO+TINFO_FLAGS+2)
+       jeq     resume_userspace
 
 do_delayed_trace:
        bclr    #7,%sp@(PT_OFF_SR)      | clear trace bit in SR
index 41230c5..0529659 100644 (file)
@@ -317,15 +317,12 @@ asmlinkage int sys_execve(char __user *name, char __user * __user *argv, char __
        char * filename;
        struct pt_regs *regs = (struct pt_regs *) &name;
 
-       lock_kernel();
        filename = getname(name);
        error = PTR_ERR(filename);
        if (IS_ERR(filename))
-               goto out;
+               return error;
        error = do_execve(filename, argv, envp, regs);
        putname(filename);
-out:
-       unlock_kernel();
        return error;
 }
 
index 2075543..1fc217e 100644 (file)
@@ -35,7 +35,9 @@
 #define SR_MASK 0x001f
 
 /* sets the trace bits. */
-#define TRACE_BITS 0x8000
+#define TRACE_BITS 0xC000
+#define T1_BIT 0x8000
+#define T0_BIT 0x4000
 
 /* Find the stack offset for a register, relative to thread.esp0. */
 #define PT_REG(reg)    ((long)&((struct pt_regs *)0)->reg)
@@ -44,7 +46,7 @@
 /* Mapping from PT_xxx to the stack offset at which the register is
    saved.  Notice that usp has no stack-slot and needs to be treated
    specially (see get_reg/put_reg below). */
-static int regoff[] = {
+static const int regoff[] = {
        [0]     = PT_REG(d1),
        [1]     = PT_REG(d2),
        [2]     = PT_REG(d3),
@@ -79,6 +81,14 @@ static inline long get_reg(struct task_struct *task, int regno)
                addr = (unsigned long *)(task->thread.esp0 + regoff[regno]);
        else
                return 0;
+       /* Need to take stkadj into account. */
+       if (regno == PT_SR || regno == PT_PC) {
+               long stkadj = *(long *)(task->thread.esp0 + PT_REG(stkadj));
+               addr = (unsigned long *) ((unsigned long)addr + stkadj);
+               /* The sr is actually a 16 bit register.  */
+               if (regno == PT_SR)
+                       return *(unsigned short *)addr;
+       }
        return *addr;
 }
 
@@ -96,6 +106,16 @@ static inline int put_reg(struct task_struct *task, int regno,
                addr = (unsigned long *)(task->thread.esp0 + regoff[regno]);
        else
                return -1;
+       /* Need to take stkadj into account. */
+       if (regno == PT_SR || regno == PT_PC) {
+               long stkadj = *(long *)(task->thread.esp0 + PT_REG(stkadj));
+               addr = (unsigned long *) ((unsigned long)addr + stkadj);
+               /* The sr is actually a 16 bit register.  */
+               if (regno == PT_SR) {
+                       *(unsigned short *)addr = data;
+                       return 0;
+               }
+       }
        *addr = data;
        return 0;
 }
@@ -105,7 +125,7 @@ static inline int put_reg(struct task_struct *task, int regno,
  */
 static inline void singlestep_disable(struct task_struct *child)
 {
-       unsigned long tmp = get_reg(child, PT_SR) & ~(TRACE_BITS << 16);
+       unsigned long tmp = get_reg(child, PT_SR) & ~TRACE_BITS;
        put_reg(child, PT_SR, tmp);
        clear_tsk_thread_flag(child, TIF_DELAYED_TRACE);
 }
@@ -118,18 +138,30 @@ void ptrace_disable(struct task_struct *child)
        singlestep_disable(child);
 }
 
+void user_enable_single_step(struct task_struct *child)
+{
+       unsigned long tmp = get_reg(child, PT_SR) & ~TRACE_BITS;
+       put_reg(child, PT_SR, tmp | T1_BIT);
+       set_tsk_thread_flag(child, TIF_DELAYED_TRACE);
+}
+
+void user_enable_block_step(struct task_struct *child)
+{
+       unsigned long tmp = get_reg(child, PT_SR) & ~TRACE_BITS;
+       put_reg(child, PT_SR, tmp | T0_BIT);
+}
+
+void user_disable_single_step(struct task_struct *child)
+{
+       singlestep_disable(child);
+}
+
 long arch_ptrace(struct task_struct *child, long request, long addr, long data)
 {
        unsigned long tmp;
        int i, ret = 0;
 
        switch (request) {
-       /* when I and D space are separate, these will need to be fixed. */
-       case PTRACE_PEEKTEXT:   /* read word at location addr. */
-       case PTRACE_PEEKDATA:
-               ret = generic_ptrace_peekdata(child, addr, data);
-               break;
-
        /* read the word at location addr in the USER area. */
        case PTRACE_PEEKUSR:
                if (addr & 3)
@@ -138,8 +170,6 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
 
                if (addr >= 0 && addr < 19) {
                        tmp = get_reg(child, addr);
-                       if (addr == PT_SR)
-                               tmp >>= 16;
                } else if (addr >= 21 && addr < 49) {
                        tmp = child->thread.fp[addr - 21];
                        /* Convert internal fpu reg representation
@@ -149,16 +179,10 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
                                tmp = ((tmp & 0xffff0000) << 15) |
                                      ((tmp & 0x0000ffff) << 16);
                } else
-                       break;
+                       goto out_eio;
                ret = put_user(tmp, (unsigned long *)data);
                break;
 
-       /* when I and D space are separate, this will have to be fixed. */
-       case PTRACE_POKETEXT:   /* write the word at location addr. */
-       case PTRACE_POKEDATA:
-               ret = generic_ptrace_pokedata(child, addr, data);
-               break;
-
        case PTRACE_POKEUSR:    /* write the word at location addr in the USER area */
                if (addr & 3)
                        goto out_eio;
@@ -166,9 +190,9 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
 
                if (addr == PT_SR) {
                        data &= SR_MASK;
-                       data <<= 16;
-                       data |= get_reg(child, PT_SR) & ~(SR_MASK << 16);
-               } else if (addr >= 0 && addr < 19) {
+                       data |= get_reg(child, PT_SR) & ~SR_MASK;
+               }
+               if (addr >= 0 && addr < 19) {
                        if (put_reg(child, addr, data))
                                goto out_eio;
                } else if (addr >= 21 && addr < 48) {
@@ -185,52 +209,9 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
                        goto out_eio;
                break;
 
-       case PTRACE_SYSCALL:    /* continue and stop at next (return from) syscall */
-       case PTRACE_CONT:       /* restart after signal. */
-               if (!valid_signal(data))
-                       goto out_eio;
-
-               if (request == PTRACE_SYSCALL)
-                       set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
-               else
-                       clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
-               child->exit_code = data;
-               singlestep_disable(child);
-               wake_up_process(child);
-               break;
-
-       /*
-        * make the child exit.  Best I can do is send it a sigkill.
-        * perhaps it should be put in the status that it wants to
-        * exit.
-        */
-       case PTRACE_KILL:
-               if (child->exit_state == EXIT_ZOMBIE) /* already dead */
-                       break;
-               child->exit_code = SIGKILL;
-               singlestep_disable(child);
-               wake_up_process(child);
-               break;
-
-       case PTRACE_SINGLESTEP: /* set the trap flag. */
-               if (!valid_signal(data))
-                       goto out_eio;
-
-               clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
-               tmp = get_reg(child, PT_SR) | (TRACE_BITS << 16);
-               put_reg(child, PT_SR, tmp);
-               set_tsk_thread_flag(child, TIF_DELAYED_TRACE);
-
-               child->exit_code = data;
-               /* give it a chance to run. */
-               wake_up_process(child);
-               break;
-
        case PTRACE_GETREGS:    /* Get all gp regs from the child. */
                for (i = 0; i < 19; i++) {
                        tmp = get_reg(child, i);
-                       if (i == PT_SR)
-                               tmp >>= 16;
                        ret = put_user(tmp, (unsigned long *)data);
                        if (ret)
                                break;
@@ -245,8 +226,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
                                break;
                        if (i == PT_SR) {
                                tmp &= SR_MASK;
-                               tmp <<= 16;
-                               tmp |= get_reg(child, PT_SR) & ~(SR_MASK << 16);
+                               tmp |= get_reg(child, PT_SR) & ~SR_MASK;
                        }
                        put_reg(child, i, tmp);
                        data += sizeof(long);
index 47eac19..878be5f 100644 (file)
@@ -2,6 +2,7 @@
 
 #include <asm-generic/vmlinux.lds.h>
 #include <asm/page.h>
+#include <asm/thread_info.h>
 
 OUTPUT_FORMAT("elf32-m68k", "elf32-m68k", "elf32-m68k")
 OUTPUT_ARCH(m68k)
@@ -22,73 +23,37 @@ SECTIONS
 
   _etext = .;                  /* End of text section */
 
-  . = ALIGN(16);               /* Exception table */
-  __start___ex_table = .;
-  __ex_table : { *(__ex_table) }
-  __stop___ex_table = .;
+  EXCEPTION_TABLE(16)
 
   RODATA
 
-  .data : {                    /* Data */
-       DATA_DATA
-       CONSTRUCTORS
-       }
+  RW_DATA_SECTION(16, PAGE_SIZE, THREAD_SIZE)
 
-  . = ALIGN(16);
-  .data.cacheline_aligned : { *(.data.cacheline_aligned) }
-
-  .bss : { *(.bss) }           /* BSS */
+  BSS_SECTION(0, 0, 0)
 
   _edata = .;                  /* End of data section */
 
   /* will be freed after init */
   . = ALIGN(PAGE_SIZE);                /* Init code and data */
   __init_begin = .;
-  .init.text : {
-       _sinittext = .;
-       INIT_TEXT
-       _einittext = .;
-  } :data
-  .init.data : { INIT_DATA }
-  . = ALIGN(16);
-  __setup_start = .;
-  .init.setup : { *(.init.setup) }
-  __setup_end = .;
-  __initcall_start = .;
-  .initcall.init : {
-       INITCALLS
-  }
-  __initcall_end = .;
-  __con_initcall_start = .;
-  .con_initcall.init : { *(.con_initcall.init) }
-  __con_initcall_end = .;
+  INIT_TEXT_SECTION(PAGE_SIZE) :data
+  INIT_DATA_SECTION(16)
   .m68k_fixup : {
        __start_fixup = .;
        *(.m68k_fixup)
        __stop_fixup = .;
   }
-  SECURITY_INIT
-#ifdef CONFIG_BLK_DEV_INITRD
-  . = ALIGN(8192);
-  __initramfs_start = .;
-  .init.ramfs : { *(.init.ramfs) }
-  __initramfs_end = .;
-#endif
   NOTES
-  . = ALIGN(8192);
-  __init_end = .;
-
-  .data.init_task : { *(.data.init_task) }     /* The initial task and kernel stack */
+  .init_end : {
+       /* This ALIGN be in a section so that _end is at the end of the
+          load segment. */
+       . = ALIGN(PAGE_SIZE);
+       __init_end = .;
+  }
 
   _end = . ;
 
-  /* Stabs debugging sections.  */
-  .stab 0 : { *(.stab) }
-  .stabstr 0 : { *(.stabstr) }
-  .stab.excl 0 : { *(.stab.excl) }
-  .stab.exclstr 0 : { *(.stab.exclstr) }
-  .stab.index 0 : { *(.stab.index) }
-  .stab.indexstr 0 : { *(.stab.indexstr) }
+  STABS_DEBUG
   .comment 0 : { *(.comment) }
 
   /* Sections to be discarded */
index 03efaf0..1ad6b7a 100644 (file)
@@ -2,6 +2,7 @@
 
 #include <asm-generic/vmlinux.lds.h>
 #include <asm/page.h>
+#include <asm/thread_info.h>
 
 OUTPUT_FORMAT("elf32-m68k", "elf32-m68k", "elf32-m68k")
 OUTPUT_ARCH(m68k)
@@ -23,14 +24,8 @@ SECTIONS
 
   _etext = .;                  /* End of text section */
 
-  .data : {                    /* Data */
-       DATA_DATA
-       CONSTRUCTORS
-       . = ALIGN(16);          /* Exception table */
-       __start___ex_table = .;
-       *(__ex_table)
-       __stop___ex_table = .;
-       } :data
+  EXCEPTION_TABLE(16) :data
+  RW_DATA_SECTION(16, PAGE_SIZE, THREAD_SIZE) :data
   /* End of data goes *here* so that freeing init code works properly. */
   _edata = .;
   NOTES
@@ -38,56 +33,21 @@ SECTIONS
   /* will be freed after init */
   . = ALIGN(PAGE_SIZE);        /* Init code and data */
 __init_begin = .;
-       .init.text : {
-               _sinittext = .;
-               INIT_TEXT
-               _einittext = .;
-       }
-       .init.data : { INIT_DATA }
-       . = ALIGN(16);
-       __setup_start = .;
-       .init.setup : { *(.init.setup) }
-       __setup_end = .;
-       __initcall_start = .;
-       .initcall.init : {
-               INITCALLS
-       }
-       __initcall_end = .;
-       __con_initcall_start = .;
-       .con_initcall.init : { *(.con_initcall.init) }
-       __con_initcall_end = .;
+       INIT_TEXT_SECTION(PAGE_SIZE)
+       INIT_DATA_SECTION(16)
        .m68k_fixup : {
                __start_fixup = .;
                *(.m68k_fixup)
                __stop_fixup = .;
        }
-       SECURITY_INIT
-#ifdef CONFIG_BLK_DEV_INITRD
-       . = ALIGN(PAGE_SIZE);
-       __initramfs_start = .;
-       .init.ramfs : { *(.init.ramfs) }
-       __initramfs_end = .;
-#endif
        . = ALIGN(PAGE_SIZE);
        __init_end = .;
-       .data.init.task : { *(.data.init_task) }
-
 
-  .bss : { *(.bss) }           /* BSS */
+  BSS_SECTION(0, 0, 0)
 
   _end = . ;
 
-  .crap : {
-       /* Stabs debugging sections.  */
-       *(.stab)
-       *(.stabstr)
-       *(.stab.excl)
-       *(.stab.exclstr)
-       *(.stab.index)
-       *(.stab.indexstr)
-       *(.comment)
-       *(.note)
-  }
+  STABS_DEBUG
 
   /* Sections to be discarded */
   DISCARDS
index ef70ca0..4d38289 100644 (file)
@@ -86,6 +86,20 @@ static inline int put_reg(struct task_struct *task, int regno,
        return 0;
 }
 
+void user_enable_single_step(struct task_struct *task)
+{
+       unsigned long srflags;
+       srflags = get_reg(task, PT_SR) | (TRACE_BITS << 16);
+       put_reg(task, PT_SR, srflags);
+}
+
+void user_disable_single_step(struct task_struct *task)
+{
+       unsigned long srflags;
+       srflags = get_reg(task, PT_SR) & ~(TRACE_BITS << 16);
+       put_reg(task, PT_SR, srflags);
+}
+
 /*
  * Called by kernel/ptrace.c when detaching..
  *
@@ -93,10 +107,8 @@ static inline int put_reg(struct task_struct *task, int regno,
  */
 void ptrace_disable(struct task_struct *child)
 {
-       unsigned long tmp;
        /* make sure the single step bit is not set. */
-       tmp = get_reg(child, PT_SR) & ~(TRACE_BITS << 16);
-       put_reg(child, PT_SR, tmp);
+       user_disable_single_step(child);
 }
 
 long arch_ptrace(struct task_struct *child, long request, long addr, long data)
index f989d6a..088076e 100644 (file)
@@ -37,6 +37,7 @@
 #define flush_cache_page(vma, vmaddr, pfn)     do { } while (0)
 
 #define flush_dcache_range(start, end) __invalidate_dcache_range(start, end)
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 0
 #define flush_dcache_page(page)                        do { } while (0)
 #define flush_dcache_mmap_lock(mapping)                do { } while (0)
 #define flush_dcache_mmap_unlock(mapping)      do { } while (0)
index 37e6f30..ef3ec1d 100644 (file)
  * 2 of the License, or (at your option) any later version.
  */
 
+#include <linux/of.h>  /* linux/of.h gets to determine #include ordering */
+
 #ifndef _ASM_MICROBLAZE_PROM_H
 #define _ASM_MICROBLAZE_PROM_H
 #ifdef __KERNEL__
-
-/* Definitions used by the flattened device tree */
-#define OF_DT_HEADER           0xd00dfeed /* marker */
-#define OF_DT_BEGIN_NODE       0x1 /* Start of node, full name */
-#define OF_DT_END_NODE         0x2 /* End node */
-#define OF_DT_PROP             0x3 /* Property: name off, size, content */
-#define OF_DT_NOP              0x4 /* nop */
-#define OF_DT_END              0x9
-
-#define OF_DT_VERSION          0x10
-
 #ifndef __ASSEMBLY__
 
 #include <linux/types.h>
+#include <linux/of_fdt.h>
 #include <linux/proc_fs.h>
 #include <linux/platform_device.h>
 #include <asm/irq.h>
 #define of_prop_cmp(s1, s2)            strcmp((s1), (s2))
 #define of_node_cmp(s1, s2)            strcasecmp((s1), (s2))
 
-/*
- * This is what gets passed to the kernel by prom_init or kexec
- *
- * The dt struct contains the device tree structure, full pathes and
- * property contents. The dt strings contain a separate block with just
- * the strings for the property names, and is fully page aligned and
- * self contained in a page, so that it can be kept around by the kernel,
- * each property name appears only once in this page (cheap compression)
- *
- * the mem_rsvmap contains a map of reserved ranges of physical memory,
- * passing it here instead of in the device-tree itself greatly simplifies
- * the job of everybody. It's just a list of u64 pairs (base/size) that
- * ends when size is 0
- */
-struct boot_param_header {
-       u32     magic; /* magic word OF_DT_HEADER */
-       u32     totalsize; /* total size of DT block */
-       u32     off_dt_struct; /* offset to structure */
-       u32     off_dt_strings; /* offset to strings */
-       u32     off_mem_rsvmap; /* offset to memory reserve map */
-       u32     version; /* format version */
-       u32     last_comp_version; /* last compatible version */
-       /* version 2 fields below */
-       u32     boot_cpuid_phys; /* Physical CPU id we're booting on */
-       /* version 3 fields below */
-       u32     dt_strings_size; /* size of the DT strings block */
-       /* version 17 fields below */
-       u32     dt_struct_size; /* size of the DT structure block */
-};
-
-typedef u32 phandle;
-typedef u32 ihandle;
-
-struct property {
-       char    *name;
-       int     length;
-       void    *value;
-       struct property *next;
-};
-
-struct device_node {
-       const char *name;
-       const char *type;
-       phandle node;
-       phandle linux_phandle;
-       char    *full_name;
-
-       struct  property *properties;
-       struct  property *deadprops; /* removed properties */
-       struct  device_node *parent;
-       struct  device_node *child;
-       struct  device_node *sibling;
-       struct  device_node *next; /* next device of same type */
-       struct  device_node *allnext; /* next in list of all nodes */
-       struct  proc_dir_entry *pde; /* this node's proc directory */
-       struct  kref kref;
-       unsigned long _flags;
-       void    *data;
-};
-
 extern struct device_node *of_chosen;
 
-static inline int of_node_check_flag(struct device_node *n, unsigned long flag)
-{
-       return test_bit(flag, &n->_flags);
-}
-
-static inline void of_node_set_flag(struct device_node *n, unsigned long flag)
-{
-       set_bit(flag, &n->_flags);
-}
-
 #define HAVE_ARCH_DEVTREE_FIXUPS
 
-static inline void set_node_proc_entry(struct device_node *dn,
-                                       struct proc_dir_entry *de)
-{
-       dn->pde = de;
-}
-
 extern struct device_node *allnodes;   /* temporary while merging */
 extern rwlock_t devtree_lock;  /* temporary while merging */
 
-extern struct device_node *of_find_all_nodes(struct device_node *prev);
-extern struct device_node *of_node_get(struct device_node *node);
-extern void of_node_put(struct device_node *node);
-
-/* For scanning the flat device-tree at boot time */
-extern int __init of_scan_flat_dt(int (*it)(unsigned long node,
-                                       const char *uname, int depth,
-                                       void *data),
-                               void *data);
-extern void *__init of_get_flat_dt_prop(unsigned long node, const char *name,
-                                       unsigned long *size);
-extern int __init
-               of_flat_dt_is_compatible(unsigned long node, const char *name);
-extern unsigned long __init of_get_flat_dt_root(void);
-
 /* For updating the device tree at runtime */
 extern void of_attach_node(struct device_node *);
 extern void of_detach_node(struct device_node *);
 
 /* Other Prototypes */
-extern void finish_device_tree(void);
-extern void unflatten_device_tree(void);
 extern int early_uartlite_console(void);
-extern void early_init_devtree(void *);
-extern int machine_is_compatible(const char *compat);
-extern void print_properties(struct device_node *node);
-extern int prom_n_intr_cells(struct device_node *np);
-extern void prom_get_irq_senses(unsigned char *senses, int off, int max);
-extern int prom_add_property(struct device_node *np, struct property *prop);
-extern int prom_remove_property(struct device_node *np, struct property *prop);
-extern int prom_update_property(struct device_node *np,
-                               struct property *newprop,
-                               struct property *oldprop);
 
 extern struct resource *request_OF_resource(struct device_node *node,
                                int index, const char *name_postfix);
@@ -166,18 +55,6 @@ extern int release_OF_resource(struct device_node *node, int index);
  * OF address retreival & translation
  */
 
-/* Helper to read a big number; size is in cells (not bytes) */
-static inline u64 of_read_number(const u32 *cell, int size)
-{
-       u64 r = 0;
-       while (size--)
-               r = (r << 32) | *(cell++);
-       return r;
-}
-
-/* Like of_read_number, but we want an unsigned long result */
-#define of_read_ulong(cell, size)      of_read_number(cell, size)
-
 /* Translate an OF address block into a CPU physical address
  */
 extern u64 of_translate_address(struct device_node *np, const u32 *addr);
@@ -305,12 +182,6 @@ extern int of_irq_to_resource(struct device_node *dev, int index,
  */
 extern void __iomem *of_iomap(struct device_node *device, int index);
 
-/*
- * NB: This is here while we transition from using asm/prom.h
- * to linux/of.h
- */
-#include <linux/of.h>
-
 #endif /* __ASSEMBLY__ */
 #endif /* __KERNEL__ */
 #endif /* _ASM_MICROBLAZE_PROM_H */
index 697ce30..3091619 100644 (file)
@@ -31,7 +31,7 @@
 #include <linux/linkage.h>
 #include <asm/thread_info.h>
 #include <asm/page.h>
-#include <asm/prom.h>          /* for OF_DT_HEADER */
+#include <linux/of_fdt.h>              /* for OF_DT_HEADER */
 
 #ifdef CONFIG_MMU
 #include <asm/setup.h> /* COMMAND_LINE_SIZE */
index c005cc6..b817df1 100644 (file)
@@ -860,29 +860,6 @@ struct device_node *of_find_node_by_phandle(phandle handle)
 EXPORT_SYMBOL(of_find_node_by_phandle);
 
 /**
- *     of_find_all_nodes - Get next node in global list
- *     @prev:  Previous node or NULL to start iteration
- *             of_node_put() will be called on it
- *
- *     Returns a node pointer with refcount incremented, use
- *     of_node_put() on it when done.
- */
-struct device_node *of_find_all_nodes(struct device_node *prev)
-{
-       struct device_node *np;
-
-       read_lock(&devtree_lock);
-       np = prev ? prev->allnext : allnodes;
-       for (; np != NULL; np = np->allnext)
-               if (of_node_get(np))
-                       break;
-       of_node_put(prev);
-       read_unlock(&devtree_lock);
-       return np;
-}
-EXPORT_SYMBOL(of_find_all_nodes);
-
-/**
  *     of_node_get - Increment refcount of a node
  *     @node:  Node to inc refcount, NULL is supported to
  *             simplify writing of callers
index 03b1d69..40bb9fd 100644 (file)
@@ -38,6 +38,7 @@ extern void (*flush_cache_range)(struct vm_area_struct *vma,
 extern void (*flush_cache_page)(struct vm_area_struct *vma, unsigned long page, unsigned long pfn);
 extern void __flush_dcache_page(struct page *page);
 
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 1
 static inline void flush_dcache_page(struct page *page)
 {
        if (cpu_has_dc_aliases || !cpu_has_ic_fills_f_dc)
index b77fefa..1a2793e 100644 (file)
@@ -265,67 +265,6 @@ SYSCALL_DEFINE5(n32_msgrcv, int, msqid, u32, msgp, size_t, msgsz,
 }
 #endif
 
-struct sysctl_args32
-{
-       compat_caddr_t name;
-       int nlen;
-       compat_caddr_t oldval;
-       compat_caddr_t oldlenp;
-       compat_caddr_t newval;
-       compat_size_t newlen;
-       unsigned int __unused[4];
-};
-
-#ifdef CONFIG_SYSCTL_SYSCALL
-
-SYSCALL_DEFINE1(32_sysctl, struct sysctl_args32 __user *, args)
-{
-       struct sysctl_args32 tmp;
-       int error;
-       size_t oldlen;
-       size_t __user *oldlenp = NULL;
-       unsigned long addr = (((unsigned long)&args->__unused[0]) + 7) & ~7;
-
-       if (copy_from_user(&tmp, args, sizeof(tmp)))
-               return -EFAULT;
-
-       if (tmp.oldval && tmp.oldlenp) {
-               /* Duh, this is ugly and might not work if sysctl_args
-                  is in read-only memory, but do_sysctl does indirectly
-                  a lot of uaccess in both directions and we'd have to
-                  basically copy the whole sysctl.c here, and
-                  glibc's __sysctl uses rw memory for the structure
-                  anyway.  */
-               if (get_user(oldlen, (u32 __user *)A(tmp.oldlenp)) ||
-                   put_user(oldlen, (size_t __user *)addr))
-                       return -EFAULT;
-               oldlenp = (size_t __user *)addr;
-       }
-
-       lock_kernel();
-       error = do_sysctl((int __user *)A(tmp.name), tmp.nlen, (void __user *)A(tmp.oldval),
-                         oldlenp, (void __user *)A(tmp.newval), tmp.newlen);
-       unlock_kernel();
-       if (oldlenp) {
-               if (!error) {
-                       if (get_user(oldlen, (size_t __user *)addr) ||
-                           put_user(oldlen, (u32 __user *)A(tmp.oldlenp)))
-                               error = -EFAULT;
-               }
-               copy_to_user(args->__unused, tmp.__unused, sizeof(tmp.__unused));
-       }
-       return error;
-}
-
-#else
-
-SYSCALL_DEFINE1(32_sysctl, struct sysctl_args32 __user *, args)
-{
-       return -ENOSYS;
-}
-
-#endif /* CONFIG_SYSCTL_SYSCALL */
-
 SYSCALL_DEFINE1(32_newuname, struct new_utsname __user *, name)
 {
        int ret = 0;
index 5154e64..66b5a48 100644 (file)
@@ -272,7 +272,7 @@ EXPORT(sysn32_call_table)
        PTR     sys_munlockall
        PTR     sys_vhangup                     /* 6150 */
        PTR     sys_pivot_root
-       PTR     sys_32_sysctl
+       PTR     compat_sys_sysctl
        PTR     sys_prctl
        PTR     compat_sys_adjtimex
        PTR     compat_sys_setrlimit            /* 6155 */
index 23b842b..515f9ea 100644 (file)
@@ -356,7 +356,7 @@ sys_call_table:
        PTR     sys_ni_syscall                  /* 4150 */
        PTR     sys_getsid
        PTR     sys_fdatasync
-       PTR     sys_32_sysctl
+       PTR     compat_sys_sysctl
        PTR     sys_mlock
        PTR     sys_munlock                     /* 4155 */
        PTR     sys_mlockall
index b3deed8..14b9a28 100644 (file)
 #include "ds1603.h"
 #endif
 
-/* Strategy function to write EEPROM after changing string entry */
-int sysctl_lasatstring(ctl_table *table,
-               void *oldval, size_t *oldlenp,
-               void *newval, size_t newlen)
-{
-       int r;
-
-       r = sysctl_string(table, oldval, oldlenp, newval, newlen);
-       if (r < 0)
-               return r;
-
-       if (newval && newlen)
-               lasat_write_eeprom_info();
-
-       return 0;
-}
-
 
 /* And the same for proc */
 int proc_dolasatstring(ctl_table *table, int write,
@@ -113,46 +96,6 @@ int proc_dolasatrtc(ctl_table *table, int write,
 }
 #endif
 
-/* Sysctl for setting the IP addresses */
-int sysctl_lasat_intvec(ctl_table *table,
-                   void *oldval, size_t *oldlenp,
-                   void *newval, size_t newlen)
-{
-       int r;
-
-       r = sysctl_intvec(table, oldval, oldlenp, newval, newlen);
-       if (r < 0)
-               return r;
-
-       if (newval && newlen)
-               lasat_write_eeprom_info();
-
-       return 0;
-}
-
-#ifdef CONFIG_DS1603
-/* Same for RTC */
-int sysctl_lasat_rtc(ctl_table *table,
-                   void *oldval, size_t *oldlenp,
-                   void *newval, size_t newlen)
-{
-       struct timespec ts;
-       int r;
-
-       read_persistent_clock(&ts);
-       rtctmp = ts.tv_sec;
-       if (rtctmp < 0)
-               rtctmp = 0;
-       r = sysctl_intvec(table, oldval, oldlenp, newval, newlen);
-       if (r < 0)
-               return r;
-       if (newval && newlen)
-               rtc_mips_set_mmss(rtctmp);
-
-       return r;
-}
-#endif
-
 #ifdef CONFIG_INET
 int proc_lasat_ip(ctl_table *table, int write,
                       void *buffer, size_t *lenp, loff_t *ppos)
@@ -214,23 +157,6 @@ int proc_lasat_ip(ctl_table *table, int write,
 }
 #endif
 
-static int sysctl_lasat_prid(ctl_table *table,
-                                    void *oldval, size_t *oldlenp,
-                                    void *newval, size_t newlen)
-{
-       int r;
-
-       r = sysctl_intvec(table, oldval, oldlenp, newval, newlen);
-       if (r < 0)
-               return r;
-       if (newval && newlen) {
-               lasat_board_info.li_eeprom_info.prid = *(int *)newval;
-               lasat_write_eeprom_info();
-               lasat_init_board_info();
-       }
-       return 0;
-}
-
 int proc_lasat_prid(ctl_table *table, int write,
                       void *buffer, size_t *lenp, loff_t *ppos)
 {
@@ -252,115 +178,92 @@ extern int lasat_boot_to_service;
 
 static ctl_table lasat_table[] = {
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "cpu-hz",
                .data           = &lasat_board_info.li_cpu_hz,
                .maxlen         = sizeof(int),
                .mode           = 0444,
-               .proc_handler   = &proc_dointvec,
-               .strategy       = &sysctl_intvec
+               .proc_handler   = proc_dointvec,
        },
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "bus-hz",
                .data           = &lasat_board_info.li_bus_hz,
                .maxlen         = sizeof(int),
                .mode           = 0444,
-               .proc_handler   = &proc_dointvec,
-               .strategy       = &sysctl_intvec
+               .proc_handler   = proc_dointvec,
        },
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "bmid",
                .data           = &lasat_board_info.li_bmid,
                .maxlen         = sizeof(int),
                .mode           = 0444,
-               .proc_handler   = &proc_dointvec,
-               .strategy       = &sysctl_intvec
+               .proc_handler   = proc_dointvec,
        },
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "prid",
                .data           = &lasat_board_info.li_prid,
                .maxlen         = sizeof(int),
                .mode           = 0644,
-               .proc_handler   = &proc_lasat_prid,
-               .strategy       = &sysctl_lasat_prid
-       },
+               .proc_handler   = proc_lasat_prid,
+.      },
 #ifdef CONFIG_INET
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "ipaddr",
                .data           = &lasat_board_info.li_eeprom_info.ipaddr,
                .maxlen         = sizeof(int),
                .mode           = 0644,
-               .proc_handler   = &proc_lasat_ip,
-               .strategy       = &sysctl_lasat_intvec
+               .proc_handler   = proc_lasat_ip,
        },
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "netmask",
                .data           = &lasat_board_info.li_eeprom_info.netmask,
                .maxlen         = sizeof(int),
                .mode           = 0644,
-               .proc_handler   = &proc_lasat_ip,
-               .strategy       = &sysctl_lasat_intvec
+               .proc_handler   = proc_lasat_ip,
        },
 #endif
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "passwd_hash",
                .data           = &lasat_board_info.li_eeprom_info.passwd_hash,
                .maxlen         =
                        sizeof(lasat_board_info.li_eeprom_info.passwd_hash),
                .mode           = 0600,
-               .proc_handler   = &proc_dolasatstring,
-               .strategy       = &sysctl_lasatstring
+               .proc_handler   = proc_dolasatstring,
        },
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "boot-service",
                .data           = &lasat_boot_to_service,
                .maxlen         = sizeof(int),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec,
-               .strategy       = &sysctl_intvec
+               .proc_handler   = proc_dointvec,
        },
 #ifdef CONFIG_DS1603
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "rtc",
                .data           = &rtctmp,
                .maxlen         = sizeof(int),
                .mode           = 0644,
-               .proc_handler   = &proc_dolasatrtc,
-               .strategy       = &sysctl_lasat_rtc
+               .proc_handler   = proc_dolasatrtc,
        },
 #endif
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "namestr",
                .data           = &lasat_board_info.li_namestr,
                .maxlen         = sizeof(lasat_board_info.li_namestr),
                .mode           = 0444,
-               .proc_handler   = &proc_dostring,
-               .strategy       = &sysctl_string
+               .proc_handler   = proc_dostring,
        },
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "typestr",
                .data           = &lasat_board_info.li_typestr,
                .maxlen         = sizeof(lasat_board_info.li_typestr),
                .mode           = 0444,
-               .proc_handler   = &proc_dostring,
-               .strategy       = &sysctl_string
+               .proc_handler   = proc_dostring,
        },
        {}
 };
 
 static ctl_table lasat_root_table[] = {
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "lasat",
                .mode           =  0555,
                .child          = lasat_table
index 1a55d61..29e692f 100644 (file)
@@ -26,6 +26,7 @@
 #define flush_cache_page(vma, vmaddr, pfn)     do {} while (0)
 #define flush_cache_vmap(start, end)           do {} while (0)
 #define flush_cache_vunmap(start, end)         do {} while (0)
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 0
 #define flush_dcache_page(page)                        do {} while (0)
 #define flush_dcache_mmap_lock(mapping)                do {} while (0)
 #define flush_dcache_mmap_unlock(mapping)      do {} while (0)
index 7243951..7a73b61 100644 (file)
@@ -42,6 +42,7 @@ void flush_cache_mm(struct mm_struct *mm);
 #define flush_cache_vmap(start, end)           flush_cache_all()
 #define flush_cache_vunmap(start, end)         flush_cache_all()
 
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 1
 extern void flush_dcache_page(struct page *page);
 
 #define flush_dcache_mmap_lock(mapping) \
index 561388b..76d23ec 100644 (file)
@@ -90,77 +90,6 @@ asmlinkage long sys32_unimplemented(int r26, int r25, int r24, int r23,
     return -ENOSYS;
 }
 
-#ifdef CONFIG_SYSCTL
-
-struct __sysctl_args32 {
-       u32 name;
-       int nlen;
-       u32 oldval;
-       u32 oldlenp;
-       u32 newval;
-       u32 newlen;
-       u32 __unused[4];
-};
-
-asmlinkage long sys32_sysctl(struct __sysctl_args32 __user *args)
-{
-#ifndef CONFIG_SYSCTL_SYSCALL
-       return -ENOSYS;
-#else
-       struct __sysctl_args32 tmp;
-       int error;
-       unsigned int oldlen32;
-       size_t oldlen, __user *oldlenp = NULL;
-       unsigned long addr = (((long __force)&args->__unused[0]) + 7) & ~7;
-
-       DBG(("sysctl32(%p)\n", args));
-
-       if (copy_from_user(&tmp, args, sizeof(tmp)))
-               return -EFAULT;
-
-       if (tmp.oldval && tmp.oldlenp) {
-               /* Duh, this is ugly and might not work if sysctl_args
-                  is in read-only memory, but do_sysctl does indirectly
-                  a lot of uaccess in both directions and we'd have to
-                  basically copy the whole sysctl.c here, and
-                  glibc's __sysctl uses rw memory for the structure
-                  anyway.  */
-               /* a possibly better hack than this, which will avoid the
-                * problem if the struct is read only, is to push the
-                * 'oldlen' value out to the user's stack instead. -PB
-                */
-               if (get_user(oldlen32, (u32 *)(u64)tmp.oldlenp))
-                       return -EFAULT;
-               oldlen = oldlen32;
-               if (put_user(oldlen, (size_t *)addr))
-                       return -EFAULT;
-               oldlenp = (size_t *)addr;
-       }
-
-       lock_kernel();
-       error = do_sysctl((int __user *)(u64)tmp.name, tmp.nlen,
-                         (void __user *)(u64)tmp.oldval, oldlenp,
-                         (void __user *)(u64)tmp.newval, tmp.newlen);
-       unlock_kernel();
-       if (oldlenp) {
-               if (!error) {
-                       if (get_user(oldlen, (size_t *)addr)) {
-                               error = -EFAULT;
-                       } else {
-                               oldlen32 = oldlen;
-                               if (put_user(oldlen32, (u32 *)(u64)tmp.oldlenp))
-                                       error = -EFAULT;
-                       }
-               }
-               if (copy_to_user(args->__unused, tmp.__unused, sizeof(tmp.__unused)))
-                       error = -EFAULT;
-       }
-       return error;
-#endif
-}
-
-#endif /* CONFIG_SYSCTL */
-
 asmlinkage long sys32_sched_rr_get_interval(pid_t pid,
        struct compat_timespec __user *interval)
 {
index 843f423..01c4fcf 100644 (file)
        ENTRY_SAME(getsid)
        ENTRY_SAME(fdatasync)
        /* struct __sysctl_args is a mess */
-       ENTRY_DIFF(sysctl)
+       ENTRY_COMP(sysctl)
        ENTRY_SAME(mlock)               /* 150 */
        ENTRY_SAME(munlock)
        ENTRY_SAME(mlockall)
index 3b10051..bf3382f 100644 (file)
@@ -46,7 +46,7 @@ config DEBUG_STACK_USAGE
 
 config HCALL_STATS
        bool "Hypervisor call instrumentation"
-       depends on PPC_PSERIES && DEBUG_FS
+       depends on PPC_PSERIES && DEBUG_FS && TRACEPOINTS
        help
          Adds code to keep track of the number of hypervisor calls made and
          the amount of time spent in hypervisor calls.  Wall time spent in
index f1889ab..c568329 100644 (file)
@@ -1683,7 +1683,7 @@ CONFIG_HAVE_ARCH_KGDB=y
 CONFIG_DEBUG_STACKOVERFLOW=y
 # CONFIG_DEBUG_STACK_USAGE is not set
 # CONFIG_DEBUG_PAGEALLOC is not set
-CONFIG_HCALL_STATS=y
+# CONFIG_HCALL_STATS is not set
 # CONFIG_CODE_PATCHING_SELFTEST is not set
 # CONFIG_FTR_FIXUP_SELFTEST is not set
 # CONFIG_MSI_BITMAP_SELFTEST is not set
index ba667a3..ab9e402 100644 (file)
@@ -25,6 +25,7 @@
 #define flush_cache_vmap(start, end)           do { } while (0)
 #define flush_cache_vunmap(start, end)         do { } while (0)
 
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 1
 extern void flush_dcache_page(struct page *page);
 #define flush_dcache_mmap_lock(mapping)                do { } while (0)
 #define flush_dcache_mmap_unlock(mapping)      do { } while (0)
index 9154e85..f0fb4fc 100644 (file)
@@ -19,6 +19,7 @@
 #define _ASM_POWERPC_EMULATED_OPS_H
 
 #include <asm/atomic.h>
+#include <linux/perf_event.h>
 
 
 #ifdef CONFIG_PPC_EMULATED_STATS
@@ -57,7 +58,7 @@ extern u32 ppc_warn_emulated;
 
 extern void ppc_warn_emulated_print(const char *type);
 
-#define PPC_WARN_EMULATED(type)                                                 \
+#define __PPC_WARN_EMULATED(type)                                       \
        do {                                                             \
                atomic_inc(&ppc_emulated.type.val);                      \
                if (ppc_warn_emulated)                                   \
@@ -66,8 +67,22 @@ extern void ppc_warn_emulated_print(const char *type);
 
 #else /* !CONFIG_PPC_EMULATED_STATS */
 
-#define PPC_WARN_EMULATED(type)        do { } while (0)
+#define __PPC_WARN_EMULATED(type)      do { } while (0)
 
 #endif /* !CONFIG_PPC_EMULATED_STATS */
 
+#define PPC_WARN_EMULATED(type, regs)                                  \
+       do {                                                            \
+               perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS,           \
+                       1, 0, regs, 0);                                 \
+               __PPC_WARN_EMULATED(type);                              \
+       } while (0)
+
+#define PPC_WARN_ALIGNMENT(type, regs)                                 \
+       do {                                                            \
+               perf_sw_event(PERF_COUNT_SW_ALIGNMENT_FAULTS,           \
+                       1, 0, regs, regs->dar);                         \
+               __PPC_WARN_EMULATED(type);                              \
+       } while (0)
+
 #endif /* _ASM_POWERPC_EMULATED_OPS_H */
index 6251a4b..c27caac 100644 (file)
@@ -274,6 +274,8 @@ struct hcall_stats {
        unsigned long   num_calls;      /* number of calls (on this CPU) */
        unsigned long   tb_total;       /* total wall time (mftb) of calls. */
        unsigned long   purr_total;     /* total cpu time (PURR) of calls. */
+       unsigned long   tb_start;
+       unsigned long   purr_start;
 };
 #define HCALL_STAT_ARRAY_SIZE  ((MAX_HCALL_OPCODE >> 2) + 1)
 
index 131011b..01d7182 100644 (file)
@@ -72,11 +72,7 @@ extern int pmac_i2c_get_type(struct pmac_i2c_bus *bus);
 extern int pmac_i2c_get_flags(struct pmac_i2c_bus *bus);
 extern int pmac_i2c_get_channel(struct pmac_i2c_bus *bus);
 
-/* i2c layer adapter attach/detach */
-extern void pmac_i2c_attach_adapter(struct pmac_i2c_bus *bus,
-                                   struct i2c_adapter *adapter);
-extern void pmac_i2c_detach_adapter(struct pmac_i2c_bus *bus,
-                                   struct i2c_adapter *adapter);
+/* i2c layer adapter helpers */
 extern struct i2c_adapter *pmac_i2c_get_adapter(struct pmac_i2c_bus *bus);
 extern struct pmac_i2c_bus *pmac_i2c_adapter_to_bus(struct i2c_adapter *adapter);
 
index 6ff0418..2ab9cbd 100644 (file)
@@ -1,3 +1,4 @@
+#include <linux/of.h>  /* linux/of.h gets to determine #include ordering */
 #ifndef _POWERPC_PROM_H
 #define _POWERPC_PROM_H
 #ifdef __KERNEL__
@@ -16,6 +17,7 @@
  * 2 of the License, or (at your option) any later version.
  */
 #include <linux/types.h>
+#include <linux/of_fdt.h>
 #include <linux/proc_fs.h>
 #include <linux/platform_device.h>
 #include <asm/irq.h>
 #define of_prop_cmp(s1, s2)            strcmp((s1), (s2))
 #define of_node_cmp(s1, s2)            strcasecmp((s1), (s2))
 
-/* Definitions used by the flattened device tree */
-#define OF_DT_HEADER           0xd00dfeed      /* marker */
-#define OF_DT_BEGIN_NODE       0x1             /* Start of node, full name */
-#define OF_DT_END_NODE         0x2             /* End node */
-#define OF_DT_PROP             0x3             /* Property: name off, size,
-                                                * content */
-#define OF_DT_NOP              0x4             /* nop */
-#define OF_DT_END              0x9
-
-#define OF_DT_VERSION          0x10
-
-/*
- * This is what gets passed to the kernel by prom_init or kexec
- *
- * The dt struct contains the device tree structure, full pathes and
- * property contents. The dt strings contain a separate block with just
- * the strings for the property names, and is fully page aligned and
- * self contained in a page, so that it can be kept around by the kernel,
- * each property name appears only once in this page (cheap compression)
- *
- * the mem_rsvmap contains a map of reserved ranges of physical memory,
- * passing it here instead of in the device-tree itself greatly simplifies
- * the job of everybody. It's just a list of u64 pairs (base/size) that
- * ends when size is 0
- */
-struct boot_param_header
-{
-       u32     magic;                  /* magic word OF_DT_HEADER */
-       u32     totalsize;              /* total size of DT block */
-       u32     off_dt_struct;          /* offset to structure */
-       u32     off_dt_strings;         /* offset to strings */
-       u32     off_mem_rsvmap;         /* offset to memory reserve map */
-       u32     version;                /* format version */
-       u32     last_comp_version;      /* last compatible version */
-       /* version 2 fields below */
-       u32     boot_cpuid_phys;        /* Physical CPU id we're booting on */
-       /* version 3 fields below */
-       u32     dt_strings_size;        /* size of the DT strings block */
-       /* version 17 fields below */
-       u32     dt_struct_size;         /* size of the DT structure block */
-};
-
-
-
-typedef u32 phandle;
-typedef u32 ihandle;
-
-struct property {
-       char    *name;
-       int     length;
-       void    *value;
-       struct property *next;
-};
-
-struct device_node {
-       const char *name;
-       const char *type;
-       phandle node;
-       phandle linux_phandle;
-       char    *full_name;
-
-       struct  property *properties;
-       struct  property *deadprops; /* removed properties */
-       struct  device_node *parent;
-       struct  device_node *child;
-       struct  device_node *sibling;
-       struct  device_node *next;      /* next device of same type */
-       struct  device_node *allnext;   /* next in list of all nodes */
-       struct  proc_dir_entry *pde;    /* this node's proc directory */
-       struct  kref kref;
-       unsigned long _flags;
-       void    *data;
-};
-
 extern struct device_node *of_chosen;
 
-static inline int of_node_check_flag(struct device_node *n, unsigned long flag)
-{
-       return test_bit(flag, &n->_flags);
-}
-
-static inline void of_node_set_flag(struct device_node *n, unsigned long flag)
-{
-       set_bit(flag, &n->_flags);
-}
-
-
 #define HAVE_ARCH_DEVTREE_FIXUPS
 
-static inline void set_node_proc_entry(struct device_node *dn, struct proc_dir_entry *de)
-{
-       dn->pde = de;
-}
-
-
-extern struct device_node *of_find_all_nodes(struct device_node *prev);
-extern struct device_node *of_node_get(struct device_node *node);
-extern void of_node_put(struct device_node *node);
-
-/* For scanning the flat device-tree at boot time */
-extern int __init of_scan_flat_dt(int (*it)(unsigned long node,
-                                           const char *uname, int depth,
-                                           void *data),
-                                 void *data);
-extern void* __init of_get_flat_dt_prop(unsigned long node, const char *name,
-                                       unsigned long *size);
-extern int __init of_flat_dt_is_compatible(unsigned long node, const char *name);
-extern unsigned long __init of_get_flat_dt_root(void);
-
 /* For updating the device tree at runtime */
 extern void of_attach_node(struct device_node *);
 extern void of_detach_node(struct device_node *);
 
-/* Other Prototypes */
-extern void finish_device_tree(void);
-extern void unflatten_device_tree(void);
-extern void early_init_devtree(void *);
-extern int machine_is_compatible(const char *compat);
-extern void print_properties(struct device_node *node);
-extern int prom_n_intr_cells(struct device_node* np);
-extern void prom_get_irq_senses(unsigned char *senses, int off, int max);
-extern int prom_add_property(struct device_node* np, struct property* prop);
-extern int prom_remove_property(struct device_node *np, struct property *prop);
-extern int prom_update_property(struct device_node *np,
-                               struct property *newprop,
-                               struct property *oldprop);
-
 #ifdef CONFIG_PPC32
 /*
  * PCI <-> OF matching functions
@@ -178,26 +61,6 @@ extern int release_OF_resource(struct device_node* node, int index);
  * OF address retreival & translation
  */
 
-
-/* Helper to read a big number; size is in cells (not bytes) */
-static inline u64 of_read_number(const u32 *cell, int size)
-{
-       u64 r = 0;
-       while (size--)
-               r = (r << 32) | *(cell++);
-       return r;
-}
-
-/* Like of_read_number, but we want an unsigned long result */
-#ifdef CONFIG_PPC32
-static inline unsigned long of_read_ulong(const u32 *cell, int size)
-{
-       return cell[size-1];
-}
-#else
-#define of_read_ulong(cell, size)      of_read_number(cell, size)
-#endif
-
 /* Translate an OF address block into a CPU physical address
  */
 extern u64 of_translate_address(struct device_node *np, const u32 *addr);
@@ -349,11 +212,5 @@ extern int of_irq_to_resource(struct device_node *dev, int index,
  */
 extern void __iomem *of_iomap(struct device_node *device, int index);
 
-/*
- * NB:  This is here while we transition from using asm/prom.h
- * to linux/of.h
- */
-#include <linux/of.h>
-
 #endif /* __KERNEL__ */
 #endif /* _POWERPC_PROM_H */
index 6315edc..bc8dd53 100644 (file)
 #define SPRN_MMCR1     798
 #define SPRN_MMCRA     0x312
 #define   MMCRA_SDSYNC 0x80000000UL /* SDAR synced with SIAR */
+#define   MMCRA_SDAR_DCACHE_MISS 0x40000000UL
+#define   MMCRA_SDAR_ERAT_MISS   0x20000000UL
 #define   MMCRA_SIHV   0x10000000UL /* state of MSR HV when SIAR set */
 #define   MMCRA_SIPR   0x08000000UL /* state of MSR PR when SIAR set */
 #define   MMCRA_SLOT   0x07000000UL /* SLOT bits (37-39) */
diff --git a/arch/powerpc/include/asm/trace.h b/arch/powerpc/include/asm/trace.h
new file mode 100644 (file)
index 0000000..cbe2297
--- /dev/null
@@ -0,0 +1,133 @@
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM powerpc
+
+#if !defined(_TRACE_POWERPC_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_POWERPC_H
+
+#include <linux/tracepoint.h>
+
+struct pt_regs;
+
+TRACE_EVENT(irq_entry,
+
+       TP_PROTO(struct pt_regs *regs),
+
+       TP_ARGS(regs),
+
+       TP_STRUCT__entry(
+               __field(struct pt_regs *, regs)
+       ),
+
+       TP_fast_assign(
+               __entry->regs = regs;
+       ),
+
+       TP_printk("pt_regs=%p", __entry->regs)
+);
+
+TRACE_EVENT(irq_exit,
+
+       TP_PROTO(struct pt_regs *regs),
+
+       TP_ARGS(regs),
+
+       TP_STRUCT__entry(
+               __field(struct pt_regs *, regs)
+       ),
+
+       TP_fast_assign(
+               __entry->regs = regs;
+       ),
+
+       TP_printk("pt_regs=%p", __entry->regs)
+);
+
+TRACE_EVENT(timer_interrupt_entry,
+
+       TP_PROTO(struct pt_regs *regs),
+
+       TP_ARGS(regs),
+
+       TP_STRUCT__entry(
+               __field(struct pt_regs *, regs)
+       ),
+
+       TP_fast_assign(
+               __entry->regs = regs;
+       ),
+
+       TP_printk("pt_regs=%p", __entry->regs)
+);
+
+TRACE_EVENT(timer_interrupt_exit,
+
+       TP_PROTO(struct pt_regs *regs),
+
+       TP_ARGS(regs),
+
+       TP_STRUCT__entry(
+               __field(struct pt_regs *, regs)
+       ),
+
+       TP_fast_assign(
+               __entry->regs = regs;
+       ),
+
+       TP_printk("pt_regs=%p", __entry->regs)
+);
+
+#ifdef CONFIG_PPC_PSERIES
+extern void hcall_tracepoint_regfunc(void);
+extern void hcall_tracepoint_unregfunc(void);
+
+TRACE_EVENT_FN(hcall_entry,
+
+       TP_PROTO(unsigned long opcode, unsigned long *args),
+
+       TP_ARGS(opcode, args),
+
+       TP_STRUCT__entry(
+               __field(unsigned long, opcode)
+       ),
+
+       TP_fast_assign(
+               __entry->opcode = opcode;
+       ),
+
+       TP_printk("opcode=%lu", __entry->opcode),
+
+       hcall_tracepoint_regfunc, hcall_tracepoint_unregfunc
+);
+
+TRACE_EVENT_FN(hcall_exit,
+
+       TP_PROTO(unsigned long opcode, unsigned long retval,
+               unsigned long *retbuf),
+
+       TP_ARGS(opcode, retval, retbuf),
+
+       TP_STRUCT__entry(
+               __field(unsigned long, opcode)
+               __field(unsigned long, retval)
+       ),
+
+       TP_fast_assign(
+               __entry->opcode = opcode;
+               __entry->retval = retval;
+       ),
+
+       TP_printk("opcode=%lu retval=%lu", __entry->opcode, __entry->retval),
+
+       hcall_tracepoint_regfunc, hcall_tracepoint_unregfunc
+);
+#endif
+
+#endif /* _TRACE_POWERPC_H */
+
+#undef TRACE_INCLUDE_PATH
+#undef TRACE_INCLUDE_FILE
+
+#define TRACE_INCLUDE_PATH asm
+#define TRACE_INCLUDE_FILE trace
+
+#include <trace/define_trace.h>
index a5b632e..3839839 100644 (file)
@@ -732,7 +732,7 @@ int fix_alignment(struct pt_regs *regs)
 
 #ifdef CONFIG_SPE
        if ((instr >> 26) == 0x4) {
-               PPC_WARN_EMULATED(spe);
+               PPC_WARN_ALIGNMENT(spe, regs);
                return emulate_spe(regs, reg, instr);
        }
 #endif
@@ -786,7 +786,7 @@ int fix_alignment(struct pt_regs *regs)
                        flags |= SPLT;
                        nb = 8;
                }
-               PPC_WARN_EMULATED(vsx);
+               PPC_WARN_ALIGNMENT(vsx, regs);
                return emulate_vsx(addr, reg, areg, regs, flags, nb);
        }
 #endif
@@ -794,7 +794,7 @@ int fix_alignment(struct pt_regs *regs)
         * the exception of DCBZ which is handled as a special case here
         */
        if (instr == DCBZ) {
-               PPC_WARN_EMULATED(dcbz);
+               PPC_WARN_ALIGNMENT(dcbz, regs);
                return emulate_dcbz(regs, addr);
        }
        if (unlikely(nb == 0))
@@ -804,7 +804,7 @@ int fix_alignment(struct pt_regs *regs)
         * function
         */
        if (flags & M) {
-               PPC_WARN_EMULATED(multiple);
+               PPC_WARN_ALIGNMENT(multiple, regs);
                return emulate_multiple(regs, addr, reg, nb,
                                        flags, instr, swiz);
        }
@@ -825,11 +825,11 @@ int fix_alignment(struct pt_regs *regs)
 
        /* Special case for 16-byte FP loads and stores */
        if (nb == 16) {
-               PPC_WARN_EMULATED(fp_pair);
+               PPC_WARN_ALIGNMENT(fp_pair, regs);
                return emulate_fp_pair(addr, reg, flags);
        }
 
-       PPC_WARN_EMULATED(unaligned);
+       PPC_WARN_ALIGNMENT(unaligned, regs);
 
        /* If we are loading, get the data from user space, else
         * get it from register values
index 9763267..bdcb557 100644 (file)
@@ -551,7 +551,7 @@ restore:
 BEGIN_FW_FTR_SECTION
        ld      r5,SOFTE(r1)
 FW_FTR_SECTION_ELSE
-       b       iseries_check_pending_irqs
+       b       .Liseries_check_pending_irqs
 ALT_FW_FTR_SECTION_END_IFCLR(FW_FEATURE_ISERIES)
 2:
        TRACE_AND_RESTORE_IRQ(r5);
@@ -623,7 +623,7 @@ ALT_FW_FTR_SECTION_END_IFCLR(FW_FEATURE_ISERIES)
 
 #endif /* CONFIG_PPC_BOOK3E */
 
-iseries_check_pending_irqs:
+.Liseries_check_pending_irqs:
 #ifdef CONFIG_PPC_ISERIES
        ld      r5,SOFTE(r1)
        cmpdi   0,r5,0
index 1808876..c7eb4e0 100644 (file)
@@ -185,12 +185,15 @@ END_FTR_SECTION_IFSET(CPU_FTR_REAL_LE)
         * prolog code of the PerformanceMonitor one. A little
         * trickery is thus necessary
         */
+performance_monitor_pSeries_1:
        . = 0xf00
        b       performance_monitor_pSeries
 
+altivec_unavailable_pSeries_1:
        . = 0xf20
        b       altivec_unavailable_pSeries
 
+vsx_unavailable_pSeries_1:
        . = 0xf40
        b       vsx_unavailable_pSeries
 
index 88d9c1d..049dda6 100644 (file)
@@ -110,18 +110,16 @@ int powersave_nap;
  */
 static ctl_table powersave_nap_ctl_table[]={
        {
-               .ctl_name       = KERN_PPC_POWERSAVE_NAP,
                .procname       = "powersave-nap",
                .data           = &powersave_nap,
                .maxlen         = sizeof(int),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec,
+               .proc_handler   = proc_dointvec,
        },
        {}
 };
 static ctl_table powersave_nap_sysctl_root[] = {
        {
-               .ctl_name       = CTL_KERN,
                .procname       = "kernel",
                .mode           = 0555,
                .child          = powersave_nap_ctl_table,
index e5d1211..02a3346 100644 (file)
@@ -70,6 +70,8 @@
 #include <asm/firmware.h>
 #include <asm/lv1call.h>
 #endif
+#define CREATE_TRACE_POINTS
+#include <asm/trace.h>
 
 int __irq_offset_value;
 static int ppc_spurious_interrupts;
@@ -325,6 +327,8 @@ void do_IRQ(struct pt_regs *regs)
        struct pt_regs *old_regs = set_irq_regs(regs);
        unsigned int irq;
 
+       trace_irq_entry(regs);
+
        irq_enter();
 
        check_stack_overflow();
@@ -348,6 +352,8 @@ void do_IRQ(struct pt_regs *regs)
                timer_interrupt(regs);
        }
 #endif
+
+       trace_irq_exit(regs);
 }
 
 void __init init_IRQ(void)
index 87f1663..1eb85fb 100644 (file)
@@ -1165,7 +1165,7 @@ static void record_and_restart(struct perf_event *event, unsigned long val,
         */
        if (record) {
                struct perf_sample_data data = {
-                       .addr   = 0,
+                       .addr   = ~0ULL,
                        .period = event->hw.last_period,
                };
 
index 0f4c1c7..199de52 100644 (file)
 #define MMCR1_PMCSEL_MSK       0x7f
 
 /*
- * Bits in MMCRA
- */
-
-/*
  * Layout of constraint bits:
  * 6666555555555544444444443333333333222222222211111111110000000000
  * 3210987654321098765432109876543210987654321098765432109876543210
index c351b3a..98b6a72 100644 (file)
 #define MMCR1_PMCSEL_MSK       0x7f
 
 /*
- * Bits in MMCRA
- */
-
-/*
  * Layout of constraint bits:
  * 6666555555555544444444443333333333222222222211111111110000000000
  * 3210987654321098765432109876543210987654321098765432109876543210
@@ -390,7 +386,7 @@ static int power5_compute_mmcr(u64 event[], int n_ev,
                               unsigned int hwc[], unsigned long mmcr[])
 {
        unsigned long mmcr1 = 0;
-       unsigned long mmcra = 0;
+       unsigned long mmcra = MMCRA_SDAR_DCACHE_MISS | MMCRA_SDAR_ERAT_MISS;
        unsigned int pmc, unit, byte, psel;
        unsigned int ttm, grp;
        int i, isbus, bit, grsel;
index ca399ba..84a607b 100644 (file)
@@ -178,7 +178,7 @@ static int p6_compute_mmcr(u64 event[], int n_ev,
                           unsigned int hwc[], unsigned long mmcr[])
 {
        unsigned long mmcr1 = 0;
-       unsigned long mmcra = 0;
+       unsigned long mmcra = MMCRA_SDAR_DCACHE_MISS | MMCRA_SDAR_ERAT_MISS;
        int i;
        unsigned int pmc, ev, b, u, s, psel;
        unsigned int ttmset = 0;
index 28a4daa..852f7b7 100644 (file)
 #define MMCR1_PMCSEL_MSK       0xff
 
 /*
- * Bits in MMCRA
- */
-
-/*
  * Layout of constraint bits:
  * 6666555555555544444444443333333333222222222211111111110000000000
  * 3210987654321098765432109876543210987654321098765432109876543210
@@ -230,7 +226,7 @@ static int power7_compute_mmcr(u64 event[], int n_ev,
                               unsigned int hwc[], unsigned long mmcr[])
 {
        unsigned long mmcr1 = 0;
-       unsigned long mmcra = 0;
+       unsigned long mmcra = MMCRA_SDAR_DCACHE_MISS | MMCRA_SDAR_ERAT_MISS;
        unsigned int pmc, unit, combine, l2sel, psel;
        unsigned int pmc_inuse = 0;
        int i;
index 4795744..8eff48e 100644 (file)
@@ -84,10 +84,6 @@ static short mmcr1_adder_bits[8] = {
 };
 
 /*
- * Bits in MMCRA
- */
-
-/*
  * Layout of constraint bits:
  * 6666555555555544444444443333333333222222222211111111110000000000
  * 3210987654321098765432109876543210987654321098765432109876543210
index d4405b9..4ec3008 100644 (file)
@@ -1317,29 +1317,6 @@ struct device_node *of_find_next_cache_node(struct device_node *np)
 }
 
 /**
- *     of_find_all_nodes - Get next node in global list
- *     @prev:  Previous node or NULL to start iteration
- *             of_node_put() will be called on it
- *
- *     Returns a node pointer with refcount incremented, use
- *     of_node_put() on it when done.
- */
-struct device_node *of_find_all_nodes(struct device_node *prev)
-{
-       struct device_node *np;
-
-       read_lock(&devtree_lock);
-       np = prev ? prev->allnext : allnodes;
-       for (; np != 0; np = np->allnext)
-               if (of_node_get(np))
-                       break;
-       of_node_put(prev);
-       read_unlock(&devtree_lock);
-       return np;
-}
-EXPORT_SYMBOL(of_find_all_nodes);
-
-/**
  *     of_node_get - Increment refcount of a node
  *     @node:  Node to inc refcount, NULL is supported to
  *             simplify writing of callers
index 4271f7a..845c72a 100644 (file)
@@ -660,6 +660,7 @@ late_initcall(check_cache_coherency);
 
 #ifdef CONFIG_DEBUG_FS
 struct dentry *powerpc_debugfs_root;
+EXPORT_SYMBOL(powerpc_debugfs_root);
 
 static int powerpc_debugfs_init(void)
 {
index b97c2d6..c5a4732 100644 (file)
@@ -520,58 +520,6 @@ asmlinkage long compat_sys_umask(u32 mask)
        return sys_umask((int)mask);
 }
 
-#ifdef CONFIG_SYSCTL_SYSCALL
-struct __sysctl_args32 {
-       u32 name;
-       int nlen;
-       u32 oldval;
-       u32 oldlenp;
-       u32 newval;
-       u32 newlen;
-       u32 __unused[4];
-};
-
-asmlinkage long compat_sys_sysctl(struct __sysctl_args32 __user *args)
-{
-       struct __sysctl_args32 tmp;
-       int error;
-       size_t oldlen;
-       size_t __user *oldlenp = NULL;
-       unsigned long addr = (((unsigned long)&args->__unused[0]) + 7) & ~7;
-
-       if (copy_from_user(&tmp, args, sizeof(tmp)))
-               return -EFAULT;
-
-       if (tmp.oldval && tmp.oldlenp) {
-               /* Duh, this is ugly and might not work if sysctl_args
-                  is in read-only memory, but do_sysctl does indirectly
-                  a lot of uaccess in both directions and we'd have to
-                  basically copy the whole sysctl.c here, and
-                  glibc's __sysctl uses rw memory for the structure
-                  anyway.  */
-               oldlenp = (size_t __user *)addr;
-               if (get_user(oldlen, (compat_size_t __user *)compat_ptr(tmp.oldlenp)) ||
-                   put_user(oldlen, oldlenp))
-                       return -EFAULT;
-       }
-
-       lock_kernel();
-       error = do_sysctl(compat_ptr(tmp.name), tmp.nlen,
-                         compat_ptr(tmp.oldval), oldlenp,
-                         compat_ptr(tmp.newval), tmp.newlen);
-       unlock_kernel();
-       if (oldlenp) {
-               if (!error) {
-                       if (get_user(oldlen, oldlenp) ||
-                           put_user(oldlen, (compat_size_t __user *)compat_ptr(tmp.oldlenp)))
-                               error = -EFAULT;
-               }
-               copy_to_user(args->__unused, tmp.__unused, sizeof(tmp.__unused));
-       }
-       return error;
-}
-#endif
-
 unsigned long compat_sys_mmap2(unsigned long addr, size_t len,
                          unsigned long prot, unsigned long flags,
                          unsigned long fd, unsigned long pgoff)
index a136a11..36707de 100644 (file)
@@ -54,6 +54,7 @@
 #include <linux/irq.h>
 #include <linux/delay.h>
 #include <linux/perf_event.h>
+#include <asm/trace.h>
 
 #include <asm/io.h>
 #include <asm/processor.h>
@@ -571,6 +572,8 @@ void timer_interrupt(struct pt_regs * regs)
        struct clock_event_device *evt = &decrementer->event;
        u64 now;
 
+       trace_timer_interrupt_entry(regs);
+
        /* Ensure a positive value is written to the decrementer, or else
         * some CPUs will continuue to take decrementer exceptions */
        set_dec(DECREMENTER_MAX);
@@ -590,6 +593,7 @@ void timer_interrupt(struct pt_regs * regs)
                now = decrementer->next_tb - now;
                if (now <= DECREMENTER_MAX)
                        set_dec((int)now);
+               trace_timer_interrupt_exit(regs);
                return;
        }
        old_regs = set_irq_regs(regs);
@@ -620,6 +624,8 @@ void timer_interrupt(struct pt_regs * regs)
 
        irq_exit();
        set_irq_regs(old_regs);
+
+       trace_timer_interrupt_exit(regs);
 }
 
 void wakeup_decrementer(void)
index 6f0ae1a..9d1f935 100644 (file)
@@ -759,7 +759,7 @@ static int emulate_instruction(struct pt_regs *regs)
 
        /* Emulate the mfspr rD, PVR. */
        if ((instword & PPC_INST_MFSPR_PVR_MASK) == PPC_INST_MFSPR_PVR) {
-               PPC_WARN_EMULATED(mfpvr);
+               PPC_WARN_EMULATED(mfpvr, regs);
                rd = (instword >> 21) & 0x1f;
                regs->gpr[rd] = mfspr(SPRN_PVR);
                return 0;
@@ -767,7 +767,7 @@ static int emulate_instruction(struct pt_regs *regs)
 
        /* Emulating the dcba insn is just a no-op.  */
        if ((instword & PPC_INST_DCBA_MASK) == PPC_INST_DCBA) {
-               PPC_WARN_EMULATED(dcba);
+               PPC_WARN_EMULATED(dcba, regs);
                return 0;
        }
 
@@ -776,7 +776,7 @@ static int emulate_instruction(struct pt_regs *regs)
                int shift = (instword >> 21) & 0x1c;
                unsigned long msk = 0xf0000000UL >> shift;
 
-               PPC_WARN_EMULATED(mcrxr);
+               PPC_WARN_EMULATED(mcrxr, regs);
                regs->ccr = (regs->ccr & ~msk) | ((regs->xer >> shift) & msk);
                regs->xer &= ~0xf0000000UL;
                return 0;
@@ -784,19 +784,19 @@ static int emulate_instruction(struct pt_regs *regs)
 
        /* Emulate load/store string insn. */
        if ((instword & PPC_INST_STRING_GEN_MASK) == PPC_INST_STRING) {
-               PPC_WARN_EMULATED(string);
+               PPC_WARN_EMULATED(string, regs);
                return emulate_string_inst(regs, instword);
        }
 
        /* Emulate the popcntb (Population Count Bytes) instruction. */
        if ((instword & PPC_INST_POPCNTB_MASK) == PPC_INST_POPCNTB) {
-               PPC_WARN_EMULATED(popcntb);
+               PPC_WARN_EMULATED(popcntb, regs);
                return emulate_popcntb_inst(regs, instword);
        }
 
        /* Emulate isel (Integer Select) instruction */
        if ((instword & PPC_INST_ISEL_MASK) == PPC_INST_ISEL) {
-               PPC_WARN_EMULATED(isel);
+               PPC_WARN_EMULATED(isel, regs);
                return emulate_isel(regs, instword);
        }
 
@@ -995,7 +995,7 @@ void SoftwareEmulation(struct pt_regs *regs)
 #ifdef CONFIG_MATH_EMULATION
        errcode = do_mathemu(regs);
        if (errcode >= 0)
-               PPC_WARN_EMULATED(math);
+               PPC_WARN_EMULATED(math, regs);
 
        switch (errcode) {
        case 0:
@@ -1018,7 +1018,7 @@ void SoftwareEmulation(struct pt_regs *regs)
 #elif defined(CONFIG_8XX_MINIMAL_FPEMU)
        errcode = Soft_emulate_8xx(regs);
        if (errcode >= 0)
-               PPC_WARN_EMULATED(8xx);
+               PPC_WARN_EMULATED(8xx, regs);
 
        switch (errcode) {
        case 0:
@@ -1129,7 +1129,7 @@ void altivec_assist_exception(struct pt_regs *regs)
 
        flush_altivec_to_thread(current);
 
-       PPC_WARN_EMULATED(altivec);
+       PPC_WARN_EMULATED(altivec, regs);
        err = emulate_altivec(regs);
        if (err == 0) {
                regs->nip += 4;         /* skip emulated instruction */
index 2a4551f..5902bbc 100644 (file)
@@ -78,8 +78,9 @@ int kvmppc_emulate_mmio(struct kvm_run *run, struct kvm_vcpu *vcpu)
        return r;
 }
 
-void kvm_arch_hardware_enable(void *garbage)
+int kvm_arch_hardware_enable(void *garbage)
 {
+       return 0;
 }
 
 void kvm_arch_hardware_disable(void *garbage)
@@ -421,7 +422,7 @@ long kvm_arch_vm_ioctl(struct file *filp,
 
        switch (ioctl) {
        default:
-               r = -EINVAL;
+               r = -ENOTTY;
        }
 
        return r;
index 806ef67..8167d42 100644 (file)
@@ -51,7 +51,7 @@ static inline void kvmppc_account_exit_stat(struct kvm_vcpu *vcpu, int type)
 
        /* The BUILD_BUG_ON below breaks in funny ways, commented out
         * for now ... -BenH
-       BUILD_BUG_ON(__builtin_constant_p(type));
+       BUILD_BUG_ON(!__builtin_constant_p(type));
        */
        switch (type) {
        case EXT_INTR_EXITS:
index 75f3267..e68beac 100644 (file)
@@ -26,11 +26,11 @@ BEGIN_FTR_SECTION
        srd     r8,r5,r11
 
        mtctr   r8
-setup:
+.Lsetup:
        dcbt    r9,r4
        dcbz    r9,r3
        add     r9,r9,r12
-       bdnz    setup
+       bdnz    .Lsetup
 END_FTR_SECTION_IFSET(CPU_FTR_CP_USE_DCBTZ)
        addi    r3,r3,-8
        srdi    r8,r5,7         /* page is copied in 128 byte strides */
index 414ca98..345e2da 100644 (file)
@@ -42,6 +42,7 @@
 #include <linux/interrupt.h>
 #include <linux/timer.h>
 #include <linux/mutex.h>
+#include <linux/i2c.h>
 #include <asm/keylargo.h>
 #include <asm/uninorth.h>
 #include <asm/io.h>
@@ -80,7 +81,7 @@ struct pmac_i2c_bus
        struct device_node      *busnode;
        int                     type;
        int                     flags;
-       struct i2c_adapter      *adapter;
+       struct i2c_adapter      adapter;
        void                    *hostdata;
        int                     channel;        /* some hosts have multiple */
        int                     mode;           /* current mode */
@@ -1014,25 +1015,9 @@ int pmac_i2c_get_channel(struct pmac_i2c_bus *bus)
 EXPORT_SYMBOL_GPL(pmac_i2c_get_channel);
 
 
-void pmac_i2c_attach_adapter(struct pmac_i2c_bus *bus,
-                            struct i2c_adapter *adapter)
-{
-       WARN_ON(bus->adapter != NULL);
-       bus->adapter = adapter;
-}
-EXPORT_SYMBOL_GPL(pmac_i2c_attach_adapter);
-
-void pmac_i2c_detach_adapter(struct pmac_i2c_bus *bus,
-                            struct i2c_adapter *adapter)
-{
-       WARN_ON(bus->adapter != adapter);
-       bus->adapter = NULL;
-}
-EXPORT_SYMBOL_GPL(pmac_i2c_detach_adapter);
-
 struct i2c_adapter *pmac_i2c_get_adapter(struct pmac_i2c_bus *bus)
 {
-       return bus->adapter;
+       return &bus->adapter;
 }
 EXPORT_SYMBOL_GPL(pmac_i2c_get_adapter);
 
@@ -1041,7 +1026,7 @@ struct pmac_i2c_bus *pmac_i2c_adapter_to_bus(struct i2c_adapter *adapter)
        struct pmac_i2c_bus *bus;
 
        list_for_each_entry(bus, &pmac_i2c_busses, link)
-               if (bus->adapter == adapter)
+               if (&bus->adapter == adapter)
                        return bus;
        return NULL;
 }
@@ -1053,7 +1038,7 @@ int pmac_i2c_match_adapter(struct device_node *dev, struct i2c_adapter *adapter)
 
        if (bus == NULL)
                return 0;
-       return (bus->adapter == adapter);
+       return (&bus->adapter == adapter);
 }
 EXPORT_SYMBOL_GPL(pmac_i2c_match_adapter);
 
index c1427b3..383a5d0 100644 (file)
        
 #define STK_PARM(i)     (48 + ((i)-3)*8)
 
-#ifdef CONFIG_HCALL_STATS
+#ifdef CONFIG_TRACEPOINTS
+
+       .section        ".toc","aw"
+
+       .globl hcall_tracepoint_refcount
+hcall_tracepoint_refcount:
+       .llong  0
+
+       .section        ".text"
+
 /*
  * precall must preserve all registers.  use unused STK_PARM()
- * areas to save snapshots and opcode.
+ * areas to save snapshots and opcode. We branch around this
+ * in early init (eg when populating the MMU hashtable) by using an
+ * unconditional cpu feature.
  */
-#define HCALL_INST_PRECALL                                     \
-       std     r3,STK_PARM(r3)(r1);    /* save opcode */       \
-       mftb    r0;                     /* get timebase and */  \
-       std     r0,STK_PARM(r5)(r1);    /* save for later */    \
+#define HCALL_INST_PRECALL(FIRST_REG)                          \
 BEGIN_FTR_SECTION;                                             \
-       mfspr   r0,SPRN_PURR;           /* get PURR and */      \
-       std     r0,STK_PARM(r6)(r1);    /* save for later */    \
-END_FTR_SECTION_IFSET(CPU_FTR_PURR);
-       
+       b       1f;                                             \
+END_FTR_SECTION(0, 1);                                         \
+       ld      r12,hcall_tracepoint_refcount@toc(r2);          \
+       cmpdi   r12,0;                                          \
+       beq+    1f;                                             \
+       mflr    r0;                                             \
+       std     r3,STK_PARM(r3)(r1);                            \
+       std     r4,STK_PARM(r4)(r1);                            \
+       std     r5,STK_PARM(r5)(r1);                            \
+       std     r6,STK_PARM(r6)(r1);                            \
+       std     r7,STK_PARM(r7)(r1);                            \
+       std     r8,STK_PARM(r8)(r1);                            \
+       std     r9,STK_PARM(r9)(r1);                            \
+       std     r10,STK_PARM(r10)(r1);                          \
+       std     r0,16(r1);                                      \
+       addi    r4,r1,STK_PARM(FIRST_REG);                      \
+       stdu    r1,-STACK_FRAME_OVERHEAD(r1);                   \
+       bl      .__trace_hcall_entry;                           \
+       addi    r1,r1,STACK_FRAME_OVERHEAD;                     \
+       ld      r0,16(r1);                                      \
+       ld      r3,STK_PARM(r3)(r1);                            \
+       ld      r4,STK_PARM(r4)(r1);                            \
+       ld      r5,STK_PARM(r5)(r1);                            \
+       ld      r6,STK_PARM(r6)(r1);                            \
+       ld      r7,STK_PARM(r7)(r1);                            \
+       ld      r8,STK_PARM(r8)(r1);                            \
+       ld      r9,STK_PARM(r9)(r1);                            \
+       ld      r10,STK_PARM(r10)(r1);                          \
+       mtlr    r0;                                             \
+1:
+
 /*
  * postcall is performed immediately before function return which
  * allows liberal use of volatile registers.  We branch around this
  * in early init (eg when populating the MMU hashtable) by using an
  * unconditional cpu feature.
  */
-#define HCALL_INST_POSTCALL                                    \
+#define __HCALL_INST_POSTCALL                                  \
 BEGIN_FTR_SECTION;                                             \
        b       1f;                                             \
 END_FTR_SECTION(0, 1);                                         \
-       ld      r4,STK_PARM(r3)(r1);    /* validate opcode */   \
-       cmpldi  cr7,r4,MAX_HCALL_OPCODE;                        \
-       bgt-    cr7,1f;                                         \
-                                                               \
-       /* get time and PURR snapshots after hcall */           \
-       mftb    r7;                     /* timebase after */    \
-BEGIN_FTR_SECTION;                                             \
-       mfspr   r8,SPRN_PURR;           /* PURR after */        \
-       ld      r6,STK_PARM(r6)(r1);    /* PURR before */       \
-       subf    r6,r6,r8;               /* delta */             \
-END_FTR_SECTION_IFSET(CPU_FTR_PURR);                           \
-       ld      r5,STK_PARM(r5)(r1);    /* timebase before */   \
-       subf    r5,r5,r7;               /* time delta */        \
-                                                               \
-       /* calculate address of stat structure r4 = opcode */   \
-       srdi    r4,r4,2;                /* index into array */  \
-       mulli   r4,r4,HCALL_STAT_SIZE;                          \
-       LOAD_REG_ADDR(r7, per_cpu__hcall_stats);                \
-       add     r4,r4,r7;                                       \
-       ld      r7,PACA_DATA_OFFSET(r13); /* per cpu offset */  \
-       add     r4,r4,r7;                                       \
-                                                               \
-       /* update stats */                                      \
-       ld      r7,HCALL_STAT_CALLS(r4); /* count */            \
-       addi    r7,r7,1;                                        \
-       std     r7,HCALL_STAT_CALLS(r4);                        \
-       ld      r7,HCALL_STAT_TB(r4);   /* timebase */          \
-       add     r7,r7,r5;                                       \
-       std     r7,HCALL_STAT_TB(r4);                           \
-BEGIN_FTR_SECTION;                                             \
-       ld      r7,HCALL_STAT_PURR(r4); /* PURR */              \
-       add     r7,r7,r6;                                       \
-       std     r7,HCALL_STAT_PURR(r4);                         \
-END_FTR_SECTION_IFSET(CPU_FTR_PURR);                           \
+       ld      r12,hcall_tracepoint_refcount@toc(r2);          \
+       cmpdi   r12,0;                                          \
+       beq+    1f;                                             \
+       mflr    r0;                                             \
+       ld      r6,STK_PARM(r3)(r1);                            \
+       std     r3,STK_PARM(r3)(r1);                            \
+       mr      r4,r3;                                          \
+       mr      r3,r6;                                          \
+       std     r0,16(r1);                                      \
+       stdu    r1,-STACK_FRAME_OVERHEAD(r1);                   \
+       bl      .__trace_hcall_exit;                            \
+       addi    r1,r1,STACK_FRAME_OVERHEAD;                     \
+       ld      r0,16(r1);                                      \
+       ld      r3,STK_PARM(r3)(r1);                            \
+       mtlr    r0;                                             \
 1:
+
+#define HCALL_INST_POSTCALL_NORETS                             \
+       li      r5,0;                                           \
+       __HCALL_INST_POSTCALL
+
+#define HCALL_INST_POSTCALL(BUFREG)                            \
+       mr      r5,BUFREG;                                      \
+       __HCALL_INST_POSTCALL
+
 #else
-#define HCALL_INST_PRECALL
-#define HCALL_INST_POSTCALL
+#define HCALL_INST_PRECALL(FIRST_ARG)
+#define HCALL_INST_POSTCALL_NORETS
+#define HCALL_INST_POSTCALL(BUFREG)
 #endif
 
        .text
@@ -86,11 +112,11 @@ _GLOBAL(plpar_hcall_norets)
        mfcr    r0
        stw     r0,8(r1)
 
-       HCALL_INST_PRECALL
+       HCALL_INST_PRECALL(r4)
 
        HVSC                            /* invoke the hypervisor */
 
-       HCALL_INST_POSTCALL
+       HCALL_INST_POSTCALL_NORETS
 
        lwz     r0,8(r1)
        mtcrf   0xff,r0
@@ -102,7 +128,7 @@ _GLOBAL(plpar_hcall)
        mfcr    r0
        stw     r0,8(r1)
 
-       HCALL_INST_PRECALL
+       HCALL_INST_PRECALL(r5)
 
        std     r4,STK_PARM(r4)(r1)     /* Save ret buffer */
 
@@ -121,7 +147,7 @@ _GLOBAL(plpar_hcall)
        std     r6, 16(r12)
        std     r7, 24(r12)
 
-       HCALL_INST_POSTCALL
+       HCALL_INST_POSTCALL(r12)
 
        lwz     r0,8(r1)
        mtcrf   0xff,r0
@@ -168,7 +194,7 @@ _GLOBAL(plpar_hcall9)
        mfcr    r0
        stw     r0,8(r1)
 
-       HCALL_INST_PRECALL
+       HCALL_INST_PRECALL(r5)
 
        std     r4,STK_PARM(r4)(r1)     /* Save ret buffer */
 
@@ -196,7 +222,7 @@ _GLOBAL(plpar_hcall9)
        std     r11,56(r12)
        std     r0, 64(r12)
 
-       HCALL_INST_POSTCALL
+       HCALL_INST_POSTCALL(r12)
 
        lwz     r0,8(r1)
        mtcrf   0xff,r0
index 3631a4f..2f58c71 100644 (file)
@@ -26,6 +26,7 @@
 #include <asm/hvcall.h>
 #include <asm/firmware.h>
 #include <asm/cputable.h>
+#include <asm/trace.h>
 
 DEFINE_PER_CPU(struct hcall_stats[HCALL_STAT_ARRAY_SIZE], hcall_stats);
 
@@ -100,6 +101,35 @@ static const struct file_operations hcall_inst_seq_fops = {
 #define        HCALL_ROOT_DIR          "hcall_inst"
 #define CPU_NAME_BUF_SIZE      32
 
+
+static void probe_hcall_entry(unsigned long opcode, unsigned long *args)
+{
+       struct hcall_stats *h;
+
+       if (opcode > MAX_HCALL_OPCODE)
+               return;
+
+       h = &get_cpu_var(hcall_stats)[opcode / 4];
+       h->tb_start = mftb();
+       h->purr_start = mfspr(SPRN_PURR);
+}
+
+static void probe_hcall_exit(unsigned long opcode, unsigned long retval,
+                            unsigned long *retbuf)
+{
+       struct hcall_stats *h;
+
+       if (opcode > MAX_HCALL_OPCODE)
+               return;
+
+       h = &__get_cpu_var(hcall_stats)[opcode / 4];
+       h->num_calls++;
+       h->tb_total = mftb() - h->tb_start;
+       h->purr_total = mfspr(SPRN_PURR) - h->purr_start;
+
+       put_cpu_var(hcall_stats);
+}
+
 static int __init hcall_inst_init(void)
 {
        struct dentry *hcall_root;
@@ -110,6 +140,14 @@ static int __init hcall_inst_init(void)
        if (!firmware_has_feature(FW_FEATURE_LPAR))
                return 0;
 
+       if (register_trace_hcall_entry(probe_hcall_entry))
+               return -EINVAL;
+
+       if (register_trace_hcall_exit(probe_hcall_exit)) {
+               unregister_trace_hcall_entry(probe_hcall_entry);
+               return -EINVAL;
+       }
+
        hcall_root = debugfs_create_dir(HCALL_ROOT_DIR, NULL);
        if (!hcall_root)
                return -ENOMEM;
index 903eb9e..0707653 100644 (file)
@@ -39,6 +39,7 @@
 #include <asm/cputable.h>
 #include <asm/udbg.h>
 #include <asm/smp.h>
+#include <asm/trace.h>
 
 #include "plpar_wrappers.h"
 #include "pseries.h"
@@ -661,3 +662,35 @@ void arch_free_page(struct page *page, int order)
 EXPORT_SYMBOL(arch_free_page);
 
 #endif
+
+#ifdef CONFIG_TRACEPOINTS
+/*
+ * We optimise our hcall path by placing hcall_tracepoint_refcount
+ * directly in the TOC so we can check if the hcall tracepoints are
+ * enabled via a single load.
+ */
+
+/* NB: reg/unreg are called while guarded with the tracepoints_mutex */
+extern long hcall_tracepoint_refcount;
+
+void hcall_tracepoint_regfunc(void)
+{
+       hcall_tracepoint_refcount++;
+}
+
+void hcall_tracepoint_unregfunc(void)
+{
+       hcall_tracepoint_refcount--;
+}
+
+void __trace_hcall_entry(unsigned long opcode, unsigned long *args)
+{
+       trace_hcall_entry(opcode, args);
+}
+
+void __trace_hcall_exit(long opcode, unsigned long retval,
+                       unsigned long *retbuf)
+{
+       trace_hcall_exit(opcode, retval, retbuf);
+}
+#endif
index b55fd7e..4955899 100644 (file)
@@ -61,12 +61,12 @@ static struct ctl_table appldata_table[] = {
        {
                .procname       = "timer",
                .mode           = S_IRUGO | S_IWUSR,
-               .proc_handler   = &appldata_timer_handler,
+               .proc_handler   = appldata_timer_handler,
        },
        {
                .procname       = "interval",
                .mode           = S_IRUGO | S_IWUSR,
-               .proc_handler   = &appldata_interval_handler,
+               .proc_handler   = appldata_interval_handler,
        },
        { },
 };
index 49d5af9..405cc97 100644 (file)
@@ -10,6 +10,7 @@
 #define flush_cache_dup_mm(mm)                 do { } while (0)
 #define flush_cache_range(vma, start, end)     do { } while (0)
 #define flush_cache_page(vma, vmaddr, pfn)     do { } while (0)
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 0
 #define flush_dcache_page(page)                        do { } while (0)
 #define flush_dcache_mmap_lock(mapping)                do { } while (0)
 #define flush_dcache_mmap_unlock(mapping)      do { } while (0)
index 3dfcaeb..82b32a1 100644 (file)
@@ -1,6 +1,5 @@
 #ifndef __LINUX_KVM_S390_H
 #define __LINUX_KVM_S390_H
-
 /*
  * asm-s390/kvm.h - KVM s390 specific structures and definitions
  *
@@ -15,6 +14,8 @@
  */
 #include <linux/types.h>
 
+#define __KVM_S390
+
 /* for KVM_GET_REGS and KVM_SET_REGS */
 struct kvm_regs {
        /* general purpose regs for s390 */
index 0debcec..fda1a81 100644 (file)
@@ -527,59 +527,6 @@ asmlinkage long sys32_sendfile64(int out_fd, int in_fd,
        return ret;
 }
 
-#ifdef CONFIG_SYSCTL_SYSCALL
-struct __sysctl_args32 {
-       u32 name;
-       int nlen;
-       u32 oldval;
-       u32 oldlenp;
-       u32 newval;
-       u32 newlen;
-       u32 __unused[4];
-};
-
-asmlinkage long sys32_sysctl(struct __sysctl_args32 __user *args)
-{
-       struct __sysctl_args32 tmp;
-       int error;
-       size_t oldlen;
-       size_t __user *oldlenp = NULL;
-       unsigned long addr = (((unsigned long)&args->__unused[0]) + 7) & ~7;
-
-       if (copy_from_user(&tmp, args, sizeof(tmp)))
-               return -EFAULT;
-
-       if (tmp.oldval && tmp.oldlenp) {
-               /* Duh, this is ugly and might not work if sysctl_args
-                  is in read-only memory, but do_sysctl does indirectly
-                  a lot of uaccess in both directions and we'd have to
-                  basically copy the whole sysctl.c here, and
-                  glibc's __sysctl uses rw memory for the structure
-                  anyway.  */
-               if (get_user(oldlen, (u32 __user *)compat_ptr(tmp.oldlenp)) ||
-                   put_user(oldlen, (size_t __user *)addr))
-                       return -EFAULT;
-               oldlenp = (size_t __user *)addr;
-       }
-
-       lock_kernel();
-       error = do_sysctl(compat_ptr(tmp.name), tmp.nlen, compat_ptr(tmp.oldval),
-                         oldlenp, compat_ptr(tmp.newval), tmp.newlen);
-       unlock_kernel();
-       if (oldlenp) {
-               if (!error) {
-                       if (get_user(oldlen, (size_t __user *)addr) ||
-                           put_user(oldlen, (u32 __user *)compat_ptr(tmp.oldlenp)))
-                               error = -EFAULT;
-               }
-               if (copy_to_user(args->__unused, tmp.__unused,
-                                sizeof(tmp.__unused)))
-                       error = -EFAULT;
-       }
-       return error;
-}
-#endif
-
 struct stat64_emu31 {
        unsigned long long  st_dev;
        unsigned int    __pad1;
index c07f9ca..45e9092 100644 (file)
@@ -162,7 +162,6 @@ struct ucontext32 {
        compat_sigset_t         uc_sigmask;     /* mask last for extensibility */
 };
 
-struct __sysctl_args32;
 struct stat64_emu31;
 struct mmap_arg_struct_emu31;
 struct fadvise64_64_args;
@@ -212,7 +211,6 @@ long sys32_sendfile(int out_fd, int in_fd, compat_off_t __user *offset,
                    size_t count);
 long sys32_sendfile64(int out_fd, int in_fd, compat_loff_t __user *offset,
                      s32 count);
-long sys32_sysctl(struct __sysctl_args32 __user *args);
 long sys32_stat64(char __user * filename, struct stat64_emu31 __user * statbuf);
 long sys32_lstat64(char __user * filename,
                   struct stat64_emu31 __user * statbuf);
index cbd9901..30de2d0 100644 (file)
@@ -689,8 +689,6 @@ sys32_fdatasync_wrapper:
        llgfr   %r2,%r2                 # unsigned int
        jg      sys_fdatasync           # branch to system call
 
-#sys32_sysctl_wrapper                  # tbd
-
        .globl  sys32_mlock_wrapper
 sys32_mlock_wrapper:
        llgfr   %r2,%r2                 # unsigned long
@@ -1087,8 +1085,8 @@ sys32_stime_wrapper:
 
        .globl  sys32_sysctl_wrapper
 sys32_sysctl_wrapper:
-       llgtr   %r2,%r2                 # struct __sysctl_args32 *
-       jg      sys32_sysctl
+       llgtr   %r2,%r2                 # struct compat_sysctl_args *
+       jg      compat_sys_sysctl
 
        .globl  sys32_fstat64_wrapper
 sys32_fstat64_wrapper:
index 20f282c..071c81f 100644 (file)
@@ -893,35 +893,30 @@ s390dbf_procactive(ctl_table *table, int write,
 
 static struct ctl_table s390dbf_table[] = {
        {
-               .ctl_name       = CTL_S390DBF_STOPPABLE,
                .procname       = "debug_stoppable",
                .data           = &debug_stoppable,
                .maxlen         = sizeof(int),
                .mode           = S_IRUGO | S_IWUSR,
-               .proc_handler   = &proc_dointvec,
-               .strategy       = &sysctl_intvec,
+               .proc_handler   = proc_dointvec,
        },
         {
-               .ctl_name       = CTL_S390DBF_ACTIVE,
                .procname       = "debug_active",
                .data           = &debug_active,
                .maxlen         = sizeof(int),
                .mode           = S_IRUGO | S_IWUSR,
-               .proc_handler   = &s390dbf_procactive,
-               .strategy       = &sysctl_intvec,
+               .proc_handler   = s390dbf_procactive,
        },
-       { .ctl_name = 0 }
+       { }
 };
 
 static struct ctl_table s390dbf_dir_table[] = {
        {
-               .ctl_name       = CTL_S390DBF,
                .procname       = "s390dbf",
                .maxlen         = 0,
                .mode           = S_IRUGO | S_IXUGO,
                .child          = s390dbf_table,
        },
-       { .ctl_name = 0 }
+       { }
 };
 
 static struct ctl_table_header *s390dbf_sysctl_header;
index 07ced89..f8bcaef 100644 (file)
@@ -74,9 +74,10 @@ struct kvm_stats_debugfs_item debugfs_entries[] = {
 static unsigned long long *facilities;
 
 /* Section: not file related */
-void kvm_arch_hardware_enable(void *garbage)
+int kvm_arch_hardware_enable(void *garbage)
 {
        /* every s390 is virtualization enabled ;-) */
+       return 0;
 }
 
 void kvm_arch_hardware_disable(void *garbage)
@@ -116,10 +117,16 @@ long kvm_arch_dev_ioctl(struct file *filp,
 
 int kvm_dev_ioctl_check_extension(long ext)
 {
+       int r;
+
        switch (ext) {
+       case KVM_CAP_S390_PSW:
+               r = 1;
+               break;
        default:
-               return 0;
+               r = 0;
        }
+       return r;
 }
 
 /* Section: vm related */
@@ -150,7 +157,7 @@ long kvm_arch_vm_ioctl(struct file *filp,
                break;
        }
        default:
-               r = -EINVAL;
+               r = -ENOTTY;
        }
 
        return r;
@@ -419,8 +426,10 @@ static int kvm_arch_vcpu_ioctl_set_initial_psw(struct kvm_vcpu *vcpu, psw_t psw)
        vcpu_load(vcpu);
        if (atomic_read(&vcpu->arch.sie_block->cpuflags) & CPUSTAT_RUNNING)
                rc = -EBUSY;
-       else
-               vcpu->arch.sie_block->gpsw = psw;
+       else {
+               vcpu->run->psw_mask = psw.mask;
+               vcpu->run->psw_addr = psw.addr;
+       }
        vcpu_put(vcpu);
        return rc;
 }
@@ -508,9 +517,6 @@ rerun_vcpu:
 
        switch (kvm_run->exit_reason) {
        case KVM_EXIT_S390_SIEIC:
-               vcpu->arch.sie_block->gpsw.mask = kvm_run->s390_sieic.mask;
-               vcpu->arch.sie_block->gpsw.addr = kvm_run->s390_sieic.addr;
-               break;
        case KVM_EXIT_UNKNOWN:
        case KVM_EXIT_INTR:
        case KVM_EXIT_S390_RESET:
@@ -519,6 +525,9 @@ rerun_vcpu:
                BUG();
        }
 
+       vcpu->arch.sie_block->gpsw.mask = kvm_run->psw_mask;
+       vcpu->arch.sie_block->gpsw.addr = kvm_run->psw_addr;
+
        might_fault();
 
        do {
@@ -538,8 +547,6 @@ rerun_vcpu:
                /* intercept cannot be handled in-kernel, prepare kvm-run */
                kvm_run->exit_reason         = KVM_EXIT_S390_SIEIC;
                kvm_run->s390_sieic.icptcode = vcpu->arch.sie_block->icptcode;
-               kvm_run->s390_sieic.mask     = vcpu->arch.sie_block->gpsw.mask;
-               kvm_run->s390_sieic.addr     = vcpu->arch.sie_block->gpsw.addr;
                kvm_run->s390_sieic.ipa      = vcpu->arch.sie_block->ipa;
                kvm_run->s390_sieic.ipb      = vcpu->arch.sie_block->ipb;
                rc = 0;
@@ -551,6 +558,9 @@ rerun_vcpu:
                rc = 0;
        }
 
+       kvm_run->psw_mask     = vcpu->arch.sie_block->gpsw.mask;
+       kvm_run->psw_addr     = vcpu->arch.sie_block->gpsw.addr;
+
        if (vcpu->sigset_active)
                sigprocmask(SIG_SETMASK, &sigsaved, NULL);
 
index 40c8c67..15ee111 100644 (file)
@@ -188,9 +188,9 @@ static int __sigp_set_prefix(struct kvm_vcpu *vcpu, u16 cpu_addr, u32 address,
 
        /* make sure that the new value is valid memory */
        address = address & 0x7fffe000u;
-       if ((copy_from_guest(vcpu, &tmp,
-               (u64) (address + vcpu->arch.sie_block->gmsor) , 1)) ||
-          (copy_from_guest(vcpu, &tmp, (u64) (address +
+       if ((copy_from_user(&tmp, (void __user *)
+               (address + vcpu->arch.sie_block->gmsor) , 1)) ||
+          (copy_from_user(&tmp, (void __user *)(address +
                        vcpu->arch.sie_block->gmsor + PAGE_SIZE), 1))) {
                *reg |= SIGP_STAT_INVALID_PARAMETER;
                return 1; /* invalid parameter */
index b201135..ff58779 100644 (file)
@@ -343,30 +343,29 @@ static struct ctl_table cmm_table[] = {
        {
                .procname       = "cmm_pages",
                .mode           = 0644,
-               .proc_handler   = &cmm_pages_handler,
+               .proc_handler   = cmm_pages_handler,
        },
        {
                .procname       = "cmm_timed_pages",
                .mode           = 0644,
-               .proc_handler   = &cmm_pages_handler,
+               .proc_handler   = cmm_pages_handler,
        },
        {
                .procname       = "cmm_timeout",
                .mode           = 0644,
-               .proc_handler   = &cmm_timeout_handler,
+               .proc_handler   = cmm_timeout_handler,
        },
-       { .ctl_name = 0 }
+       { }
 };
 
 static struct ctl_table cmm_dir_table[] = {
        {
-               .ctl_name       = CTL_VM,
                .procname       = "vm",
                .maxlen         = 0,
                .mode           = 0555,
                .child          = cmm_table,
        },
-       { .ctl_name = 0 }
+       { }
 };
 #endif
 
index 07cc8fc..caaba24 100644 (file)
@@ -16,6 +16,7 @@ extern void flush_icache_range(unsigned long start, unsigned long end);
 extern void flush_dcache_range(unsigned long start, unsigned long end);
 
 #define flush_cache_dup_mm(mm)                 do {} while (0)
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 0
 #define flush_dcache_page(page)                        do {} while (0)
 #define flush_dcache_mmap_lock(mapping)                do {} while (0)
 #define flush_dcache_mmap_unlock(mapping)      do {} while (0)
index 8f305b3..e6dd5e9 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/init.h>
 #include <linux/platform_device.h>
 #include <linux/irq.h>
+#include <sound/sh_dac_audio.h>
 #include <asm/hd64461.h>
 #include <asm/io.h>
 #include <mach/hp6xx.h>
@@ -51,9 +52,63 @@ static struct platform_device jornadakbd_device = {
        .id             = -1,
 };
 
+static void dac_audio_start(struct dac_audio_pdata *pdata)
+{
+       u16 v;
+       u8 v8;
+
+       /* HP Jornada 680/690 speaker on */
+       v = inw(HD64461_GPADR);
+       v &= ~HD64461_GPADR_SPEAKER;
+       outw(v, HD64461_GPADR);
+
+       /* HP Palmtop 620lx/660lx speaker on */
+       v8 = inb(PKDR);
+       v8 &= ~PKDR_SPEAKER;
+       outb(v8, PKDR);
+
+       sh_dac_enable(pdata->channel);
+}
+
+static void dac_audio_stop(struct dac_audio_pdata *pdata)
+{
+       u16 v;
+       u8 v8;
+
+       /* HP Jornada 680/690 speaker off */
+       v = inw(HD64461_GPADR);
+       v |= HD64461_GPADR_SPEAKER;
+       outw(v, HD64461_GPADR);
+
+       /* HP Palmtop 620lx/660lx speaker off */
+       v8 = inb(PKDR);
+       v8 |= PKDR_SPEAKER;
+       outb(v8, PKDR);
+
+       sh_dac_output(0, pdata->channel);
+       sh_dac_disable(pdata->channel);
+}
+
+static struct dac_audio_pdata dac_audio_platform_data = {
+       .buffer_size            = 64000,
+       .channel                = 1,
+       .start                  = dac_audio_start,
+       .stop                   = dac_audio_stop,
+};
+
+static struct platform_device dac_audio_device = {
+       .name           = "dac_audio",
+       .id             = -1,
+       .dev            = {
+               .platform_data  = &dac_audio_platform_data,
+       }
+
+};
+
 static struct platform_device *hp6xx_devices[] __initdata = {
        &cf_ide_device,
        &jornadakbd_device,
+       &dac_audio_device,
 };
 
 static void __init hp6xx_init_irq(void)
index e78c3be..0894bba 100644 (file)
@@ -313,6 +313,9 @@ static struct platform_device fsi_device = {
        .dev    = {
                .platform_data  = &fsi_info,
        },
+       .archdata = {
+               .hwblk_id = HWBLK_SPU, /* FSI needs SPU hwblk */
+       },
 };
 
 /* KEYSC in SoC (Needs SW33-2 set to ON) */
index c29918f..dda96eb 100644 (file)
@@ -42,6 +42,7 @@ extern void flush_cache_page(struct vm_area_struct *vma,
                                unsigned long addr, unsigned long pfn);
 extern void flush_cache_range(struct vm_area_struct *vma,
                                 unsigned long start, unsigned long end);
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 1
 extern void flush_dcache_page(struct page *page);
 extern void flush_icache_range(unsigned long start, unsigned long end);
 extern void flush_icache_page(struct vm_area_struct *vma,
index 0d4165a..bcc301a 100644 (file)
@@ -29,6 +29,9 @@
 
 #define PKDR_LED_GREEN         0x10
 
+/* HP Palmtop 620lx/660lx speaker on/off */
+#define PKDR_SPEAKER           0x20
+
 #define SCPDR_TS_SCAN_ENABLE   0x20
 #define SCPDR_TS_SCAN_Y                0x02
 #define SCPDR_TS_SCAN_X                0x01
@@ -42,6 +45,7 @@
 #define ADC_CHANNEL_BACKUP     4
 #define ADC_CHANNEL_CHARGE     5
 
+/* HP Jornada 680/690 speaker on/off */
 #define HD64461_GPADR_SPEAKER  0x01
 #define HD64461_GPADR_PCMCIA0  (0x02|0x08)
 
index 267e5eb..75c0cbe 100644 (file)
@@ -877,44 +877,39 @@ static int misaligned_fixup(struct pt_regs *regs)
 
 static ctl_table unaligned_table[] = {
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "kernel_reports",
                .data           = &kernel_mode_unaligned_fixup_count,
                .maxlen         = sizeof(int),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec
+               .proc_handler   = proc_dointvec
        },
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "user_reports",
                .data           = &user_mode_unaligned_fixup_count,
                .maxlen         = sizeof(int),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec
+               .proc_handler   = proc_dointvec
        },
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "user_enable",
                .data           = &user_mode_unaligned_fixup_enable,
                .maxlen         = sizeof(int),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec},
+               .proc_handler   = proc_dointvec},
        {}
 };
 
 static ctl_table unaligned_root[] = {
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "unaligned_fixup",
                .mode           = 0555,
-               unaligned_table
+               .child          = unaligned_table
        },
        {}
 };
 
 static ctl_table sh64_root[] = {
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "sh64",
                .mode           = 0555,
                .child          = unaligned_root
index 05ef538..33ac1a9 100644 (file)
@@ -221,6 +221,13 @@ config SPARC64_SMP
        default y
        depends on SPARC64 && SMP
 
+config EARLYFB
+       bool "Support for early boot text console"
+       default y
+       depends on SPARC64
+       help
+         Say Y here to enable a faster early framebuffer boot console.
+
 choice
        prompt "Kernel page size" if SPARC64
        default SPARC64_PAGE_SIZE_8KB
index dfe272d..113225b 100644 (file)
@@ -27,6 +27,7 @@ AS             := $(AS) -32
 LDFLAGS        := -m elf32_sparc
 CHECKFLAGS     += -D__sparc__
 export BITS    := 32
+UTS_MACHINE    := sparc
 
 #KBUILD_CFLAGS += -g -pipe -fcall-used-g5 -fcall-used-g7
 KBUILD_CFLAGS += -m32 -pipe -mno-fpu -fcall-used-g5 -fcall-used-g7
@@ -46,6 +47,7 @@ CHECKFLAGS      += -D__sparc__ -D__sparc_v9__ -D__arch64__ -m64
 
 LDFLAGS              := -m elf64_sparc
 export BITS          := 64
+UTS_MACHINE          := sparc64
 
 KBUILD_CFLAGS += -m64 -pipe -mno-fpu -mcpu=ultrasparc -mcmodel=medlow   \
                  -ffixed-g4 -ffixed-g5 -fcall-used-g7 -Wno-sign-compare \
diff --git a/arch/sparc/include/asm/btext.h b/arch/sparc/include/asm/btext.h
new file mode 100644 (file)
index 0000000..9b2bc6b
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef _SPARC_BTEXT_H
+#define _SPARC_BTEXT_H
+
+extern int btext_find_display(void);
+
+#endif /* _SPARC_BTEXT_H */
index 68ac109..2e46877 100644 (file)
@@ -75,6 +75,7 @@ BTFIXUPDEF_CALL(void, flush_sig_insns, struct mm_struct *, unsigned long)
 
 extern void sparc_flush_page_to_ram(struct page *page);
 
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 1
 #define flush_dcache_page(page)                        sparc_flush_page_to_ram(page)
 #define flush_dcache_mmap_lock(mapping)                do { } while (0)
 #define flush_dcache_mmap_unlock(mapping)      do { } while (0)
index c433217..b953840 100644 (file)
@@ -37,6 +37,7 @@ extern void flush_dcache_page_all(struct mm_struct *mm, struct page *page);
 #endif
 
 extern void __flush_dcache_range(unsigned long start, unsigned long end);
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 1
 extern void flush_dcache_page(struct page *page);
 
 #define flush_icache_page(vma, pg)     do { } while(0)
index 28a42b7..3ea5964 100644 (file)
@@ -148,7 +148,7 @@ static inline unsigned long leon_load_reg(unsigned long paddr)
        return retval;
 }
 
-extern inline void leon_srmmu_disabletlb(void)
+static inline void leon_srmmu_disabletlb(void)
 {
        unsigned int retval;
        __asm__ __volatile__("lda [%%g0] %2, %0\n\t" : "=r"(retval) : "r"(0),
@@ -158,7 +158,7 @@ extern inline void leon_srmmu_disabletlb(void)
                             "i"(ASI_LEON_MMUREGS) : "memory");
 }
 
-extern inline void leon_srmmu_enabletlb(void)
+static inline void leon_srmmu_enabletlb(void)
 {
        unsigned int retval;
        __asm__ __volatile__("lda [%%g0] %2, %0\n\t" : "=r"(retval) : "r"(0),
@@ -190,7 +190,7 @@ extern void leon_init_IRQ(void);
 
 extern unsigned long last_valid_pfn;
 
-extern inline unsigned long sparc_leon3_get_dcachecfg(void)
+static inline unsigned long sparc_leon3_get_dcachecfg(void)
 {
        unsigned int retval;
        __asm__ __volatile__("lda [%1] %2, %0\n\t" :
@@ -201,7 +201,7 @@ extern inline unsigned long sparc_leon3_get_dcachecfg(void)
 }
 
 /* enable snooping */
-extern inline void sparc_leon3_enable_snooping(void)
+static inline void sparc_leon3_enable_snooping(void)
 {
        __asm__ __volatile__ ("lda [%%g0] 2, %%l1\n\t"
                          "set 0x800000, %%l2\n\t"
@@ -209,7 +209,14 @@ extern inline void sparc_leon3_enable_snooping(void)
                          "sta %%l2, [%%g0] 2\n\t" : : : "l1", "l2");
 };
 
-extern inline void sparc_leon3_disable_cache(void)
+static inline int sparc_leon3_snooping_enabled(void)
+{
+       u32 cctrl;
+       __asm__ __volatile__("lda [%%g0] 2, %0\n\t" : "=r"(cctrl));
+        return (cctrl >> 23) & 1;
+};
+
+static inline void sparc_leon3_disable_cache(void)
 {
        __asm__ __volatile__ ("lda [%%g0] 2, %%l1\n\t"
                          "set 0x00000f, %%l2\n\t"
@@ -340,6 +347,30 @@ extern int leon_flush_needed(void);
 extern void leon_switch_mm(void);
 extern int srmmu_swprobe_trace;
 
+#ifdef CONFIG_SMP
+extern int leon_smp_nrcpus(void);
+extern void leon_clear_profile_irq(int cpu);
+extern void leon_smp_done(void);
+extern void leon_boot_cpus(void);
+extern int leon_boot_one_cpu(int i);
+void leon_init_smp(void);
+extern void cpu_probe(void);
+extern void cpu_idle(void);
+extern void init_IRQ(void);
+extern void cpu_panic(void);
+extern int __leon_processor_id(void);
+void leon_enable_irq_cpu(unsigned int irq_nr, unsigned int cpu);
+
+extern unsigned int real_irq_entry[], smpleon_ticker[];
+extern unsigned int patchme_maybe_smp_msg[];
+extern unsigned long trapbase_cpu1[];
+extern unsigned long trapbase_cpu2[];
+extern unsigned long trapbase_cpu3[];
+extern unsigned int t_nmi[], linux_trap_ipi15_leon[];
+extern unsigned int linux_trap_ipi15_sun4m[];
+
+#endif /* CONFIG_SMP */
+
 #endif /* __KERNEL__ */
 
 #endif /* __ASSEMBLY__ */
@@ -356,6 +387,10 @@ extern int srmmu_swprobe_trace;
 #define leon_switch_mm() do {} while (0)
 #define leon_init_IRQ() do {} while (0)
 #define init_leon() do {} while (0)
+#define leon_smp_done() do {} while (0)
+#define leon_boot_cpus() do {} while (0)
+#define leon_boot_one_cpu(i) 1
+#define leon_init_smp() do {} while (0)
 
 #endif /* !defined(CONFIG_SPARC_LEON) */
 
index 82a190d..f845828 100644 (file)
@@ -1,3 +1,4 @@
+#include <linux/of.h>  /* linux/of.h gets to determine #include ordering */
 #ifndef _SPARC_PROM_H
 #define _SPARC_PROM_H
 #ifdef __KERNEL__
 #define of_prop_cmp(s1, s2)            strcasecmp((s1), (s2))
 #define of_node_cmp(s1, s2)            strcmp((s1), (s2))
 
-typedef u32 phandle;
-typedef u32 ihandle;
-
-struct property {
-       char    *name;
-       int     length;
-       void    *value;
-       struct property *next;
-       unsigned long _flags;
-       unsigned int unique_id;
-};
-
-struct of_irq_controller;
-struct device_node {
-       const char      *name;
-       const char      *type;
-       phandle node;
-       char    *path_component_name;
-       char    *full_name;
-
-       struct  property *properties;
-       struct  property *deadprops; /* removed properties */
-       struct  device_node *parent;
-       struct  device_node *child;
-       struct  device_node *sibling;
-       struct  device_node *next;      /* next device of same type */
-       struct  device_node *allnext;   /* next in list of all nodes */
-       struct  proc_dir_entry *pde;    /* this node's proc directory */
-       struct  kref kref;
-       unsigned long _flags;
-       void    *data;
-       unsigned int unique_id;
-
-       struct of_irq_controller *irq_trans;
-};
-
 struct of_irq_controller {
        unsigned int    (*irq_build)(struct device_node *, unsigned int, void *);
        void            *data;
 };
 
-#define OF_IS_DYNAMIC(x) test_bit(OF_DYNAMIC, &x->_flags)
-#define OF_MARK_DYNAMIC(x) set_bit(OF_DYNAMIC, &x->_flags)
-
 extern struct device_node *of_find_node_by_cpuid(int cpuid);
 extern int of_set_property(struct device_node *node, const char *name, void *val, int len);
 extern struct mutex of_set_property_mutex;
@@ -89,15 +51,6 @@ extern void prom_build_devicetree(void);
 extern void of_populate_present_mask(void);
 extern void of_fill_in_cpu_data(void);
 
-/* Dummy ref counting routines - to be implemented later */
-static inline struct device_node *of_node_get(struct device_node *node)
-{
-       return node;
-}
-static inline void of_node_put(struct device_node *node)
-{
-}
-
 /* These routines are here to provide compatibility with how powerpc
  * handles IRQ mapping for OF device nodes.  We precompute and permanently
  * register them in the of_device objects, whereas powerpc computes them
@@ -108,12 +61,6 @@ static inline void irq_dispose_mapping(unsigned int virq)
 {
 }
 
-/*
- * NB:  This is here while we transition from using asm/prom.h
- * to linux/of.h
- */
-#include <linux/of.h>
-
 extern struct device_node *of_console_device;
 extern char *of_console_path;
 extern char *of_console_options;
index 1dc129a..6e56210 100644 (file)
@@ -35,8 +35,8 @@ struct rw_semaphore {
 #endif
 
 #define __RWSEM_INITIALIZER(name) \
-{ RWSEM_UNLOCKED_VALUE, SPIN_LOCK_UNLOCKED, LIST_HEAD_INIT((name).wait_list) \
-  __RWSEM_DEP_MAP_INIT(name) }
+{ RWSEM_UNLOCKED_VALUE, __SPIN_LOCK_UNLOCKED((name).wait_lock), \
+  LIST_HEAD_INIT((name).wait_list) __RWSEM_DEP_MAP_INIT(name) }
 
 #define DECLARE_RWSEM(name) \
        struct rw_semaphore name = __RWSEM_INITIALIZER(name)
index 58101dc..841905c 100644 (file)
@@ -106,6 +106,15 @@ static inline int hard_smp4d_processor_id(void)
        return cpuid;
 }
 
+extern inline int hard_smpleon_processor_id(void)
+{
+       int cpuid;
+       __asm__ __volatile__("rd     %%asr17,%0\n\t"
+                            "srl    %0,28,%0" :
+                            "=&r" (cpuid) : );
+       return cpuid;
+}
+
 #ifndef MODULE
 static inline int hard_smp_processor_id(void)
 {
index 5b47fab..c631614 100644 (file)
@@ -72,7 +72,7 @@ obj-y                     += dma.o
 obj-$(CONFIG_SPARC32_PCI) += pcic.o
 
 obj-$(CONFIG_SMP)         += trampoline_$(BITS).o smp_$(BITS).o
-obj-$(CONFIG_SPARC32_SMP) += sun4m_smp.o sun4d_smp.o
+obj-$(CONFIG_SPARC32_SMP) += sun4m_smp.o sun4d_smp.o leon_smp.o
 obj-$(CONFIG_SPARC64_SMP) += hvtramp.o
 
 obj-y                     += auxio_$(BITS).o
@@ -87,6 +87,7 @@ obj-$(CONFIG_KGDB)        += kgdb_$(BITS).o
 obj-$(CONFIG_DYNAMIC_FTRACE) += ftrace.o
 CFLAGS_REMOVE_ftrace.o := -pg
 
+obj-$(CONFIG_EARLYFB) += btext.o
 obj-$(CONFIG_STACKTRACE)     += stacktrace.o
 # sparc64 PCI
 obj-$(CONFIG_SPARC64_PCI)    += pci.o pci_common.o psycho_common.o
index 9c11582..71ec90b 100644 (file)
@@ -10,7 +10,6 @@
 #include <linux/errno.h>
 #include <linux/init.h>
 #include <linux/miscdevice.h>
-#include <linux/smp_lock.h>
 #include <linux/pm.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
@@ -76,7 +75,6 @@ static inline void apc_free(struct of_device *op)
 
 static int apc_open(struct inode *inode, struct file *f)
 {
-       cycle_kernel_lock();
        return 0;
 }
 
@@ -87,61 +85,46 @@ static int apc_release(struct inode *inode, struct file *f)
 
 static long apc_ioctl(struct file *f, unsigned int cmd, unsigned long __arg)
 {
-       __u8 inarg, __user *arg;
-
-       arg = (__u8 __user *) __arg;
-
-       lock_kernel();
+       __u8 inarg, __user *arg = (__u8 __user *) __arg;
 
        switch (cmd) {
        case APCIOCGFANCTL:
-               if (put_user(apc_readb(APC_FANCTL_REG) & APC_REGMASK, arg)) {
-                       unlock_kernel();
+               if (put_user(apc_readb(APC_FANCTL_REG) & APC_REGMASK, arg))
                        return -EFAULT;
-               }
                break;
 
        case APCIOCGCPWR:
-               if (put_user(apc_readb(APC_CPOWER_REG) & APC_REGMASK, arg)) {
-                       unlock_kernel();
+               if (put_user(apc_readb(APC_CPOWER_REG) & APC_REGMASK, arg))
                        return -EFAULT;
-               }
                break;
 
        case APCIOCGBPORT:
-               if (put_user(apc_readb(APC_BPORT_REG) & APC_BPMASK, arg)) {
-                       unlock_kernel();
+               if (put_user(apc_readb(APC_BPORT_REG) & APC_BPMASK, arg))
                        return -EFAULT;
-               }
                break;
 
        case APCIOCSFANCTL:
-               if (get_user(inarg, arg)) {
-                       unlock_kernel();
+               if (get_user(inarg, arg))
                        return -EFAULT;
-               }
                apc_writeb(inarg & APC_REGMASK, APC_FANCTL_REG);
                break;
+
        case APCIOCSCPWR:
-               if (get_user(inarg, arg)) {
-                       unlock_kernel();
+               if (get_user(inarg, arg))
                        return -EFAULT;
-               }
                apc_writeb(inarg & APC_REGMASK, APC_CPOWER_REG);
                break;
+
        case APCIOCSBPORT:
-               if (get_user(inarg, arg)) {
-                       unlock_kernel();
+               if (get_user(inarg, arg))
                        return -EFAULT;
-               }
                apc_writeb(inarg & APC_BPMASK, APC_BPORT_REG);
                break;
+
        default:
-               unlock_kernel();
                return -EINVAL;
        };
 
-       unlock_kernel();
        return 0;
 }
 
index 45c4123..ee8d214 100644 (file)
@@ -28,6 +28,7 @@ void __init auxio_probe(void)
        struct resource r;
 
        switch (sparc_cpu_model) {
+       case sparc_leon:
        case sun4d:
        case sun4:
                return;
diff --git a/arch/sparc/kernel/btext.c b/arch/sparc/kernel/btext.c
new file mode 100644 (file)
index 0000000..8cc2d56
--- /dev/null
@@ -0,0 +1,673 @@
+/*
+ * Procedures for drawing on the screen early on in the boot process.
+ *
+ * Benjamin Herrenschmidt <benh@kernel.crashing.org>
+ */
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/console.h>
+
+#include <asm/btext.h>
+#include <asm/oplib.h>
+#include <asm/io.h>
+
+#define NO_SCROLL
+
+#ifndef NO_SCROLL
+static void scrollscreen(void);
+#endif
+
+static void draw_byte(unsigned char c, long locX, long locY);
+static void draw_byte_32(unsigned char *bits, unsigned int *base, int rb);
+static void draw_byte_16(unsigned char *bits, unsigned int *base, int rb);
+static void draw_byte_8(unsigned char *bits, unsigned int *base, int rb);
+
+#define __force_data __attribute__((__section__(".data")))
+
+static int g_loc_X __force_data;
+static int g_loc_Y __force_data;
+static int g_max_loc_X __force_data;
+static int g_max_loc_Y __force_data;
+
+static int dispDeviceRowBytes __force_data;
+static int dispDeviceDepth  __force_data;
+static int dispDeviceRect[4] __force_data;
+static unsigned char *dispDeviceBase __force_data;
+
+#define cmapsz (16*256)
+
+static unsigned char vga_font[cmapsz];
+
+static int __init btext_initialize(unsigned int node)
+{
+       unsigned int width, height, depth, pitch;
+       unsigned long address = 0;
+       u32 prop;
+
+       if (prom_getproperty(node, "width", (char *)&width, 4) < 0)
+               return -EINVAL;
+       if (prom_getproperty(node, "height", (char *)&height, 4) < 0)
+               return -EINVAL;
+       if (prom_getproperty(node, "depth", (char *)&depth, 4) < 0)
+               return -EINVAL;
+       pitch = width * ((depth + 7) / 8);
+
+       if (prom_getproperty(node, "linebytes", (char *)&prop, 4) >= 0 &&
+           prop != 0xffffffffu)
+               pitch = prop;
+
+       if (pitch == 1)
+               pitch = 0x1000;
+
+       if (prom_getproperty(node, "address", (char *)&prop, 4) >= 0)
+               address = prop;
+
+       /* FIXME: Add support for PCI reg properties. Right now, only
+        * reliable on macs
+        */
+       if (address == 0)
+               return -EINVAL;
+
+       g_loc_X = 0;
+       g_loc_Y = 0;
+       g_max_loc_X = width / 8;
+       g_max_loc_Y = height / 16;
+       dispDeviceBase = (unsigned char *)address;
+       dispDeviceRowBytes = pitch;
+       dispDeviceDepth = depth == 15 ? 16 : depth;
+       dispDeviceRect[0] = dispDeviceRect[1] = 0;
+       dispDeviceRect[2] = width;
+       dispDeviceRect[3] = height;
+
+       return 0;
+}
+
+/* Calc the base address of a given point (x,y) */
+static unsigned char * calc_base(int x, int y)
+{
+       unsigned char *base = dispDeviceBase;
+
+       base += (x + dispDeviceRect[0]) * (dispDeviceDepth >> 3);
+       base += (y + dispDeviceRect[1]) * dispDeviceRowBytes;
+       return base;
+}
+
+static void btext_clearscreen(void)
+{
+       unsigned int *base      = (unsigned int *)calc_base(0, 0);
+       unsigned long width     = ((dispDeviceRect[2] - dispDeviceRect[0]) *
+                                       (dispDeviceDepth >> 3)) >> 2;
+       int i,j;
+
+       for (i=0; i<(dispDeviceRect[3] - dispDeviceRect[1]); i++)
+       {
+               unsigned int *ptr = base;
+               for(j=width; j; --j)
+                       *(ptr++) = 0;
+               base += (dispDeviceRowBytes >> 2);
+       }
+}
+
+#ifndef NO_SCROLL
+static void scrollscreen(void)
+{
+       unsigned int *src       = (unsigned int *)calc_base(0,16);
+       unsigned int *dst       = (unsigned int *)calc_base(0,0);
+       unsigned long width     = ((dispDeviceRect[2] - dispDeviceRect[0]) *
+                                  (dispDeviceDepth >> 3)) >> 2;
+       int i,j;
+
+       for (i=0; i<(dispDeviceRect[3] - dispDeviceRect[1] - 16); i++)
+       {
+               unsigned int *src_ptr = src;
+               unsigned int *dst_ptr = dst;
+               for(j=width; j; --j)
+                       *(dst_ptr++) = *(src_ptr++);
+               src += (dispDeviceRowBytes >> 2);
+               dst += (dispDeviceRowBytes >> 2);
+       }
+       for (i=0; i<16; i++)
+       {
+               unsigned int *dst_ptr = dst;
+               for(j=width; j; --j)
+                       *(dst_ptr++) = 0;
+               dst += (dispDeviceRowBytes >> 2);
+       }
+}
+#endif /* ndef NO_SCROLL */
+
+void btext_drawchar(char c)
+{
+       int cline = 0;
+#ifdef NO_SCROLL
+       int x;
+#endif
+       switch (c) {
+       case '\b':
+               if (g_loc_X > 0)
+                       --g_loc_X;
+               break;
+       case '\t':
+               g_loc_X = (g_loc_X & -8) + 8;
+               break;
+       case '\r':
+               g_loc_X = 0;
+               break;
+       case '\n':
+               g_loc_X = 0;
+               g_loc_Y++;
+               cline = 1;
+               break;
+       default:
+               draw_byte(c, g_loc_X++, g_loc_Y);
+       }
+       if (g_loc_X >= g_max_loc_X) {
+               g_loc_X = 0;
+               g_loc_Y++;
+               cline = 1;
+       }
+#ifndef NO_SCROLL
+       while (g_loc_Y >= g_max_loc_Y) {
+               scrollscreen();
+               g_loc_Y--;
+       }
+#else
+       /* wrap around from bottom to top of screen so we don't
+          waste time scrolling each line.  -- paulus. */
+       if (g_loc_Y >= g_max_loc_Y)
+               g_loc_Y = 0;
+       if (cline) {
+               for (x = 0; x < g_max_loc_X; ++x)
+                       draw_byte(' ', x, g_loc_Y);
+       }
+#endif
+}
+
+static void btext_drawtext(const char *c, unsigned int len)
+{
+       while (len--)
+               btext_drawchar(*c++);
+}
+
+static void draw_byte(unsigned char c, long locX, long locY)
+{
+       unsigned char *base     = calc_base(locX << 3, locY << 4);
+       unsigned char *font     = &vga_font[((unsigned int)c) * 16];
+       int rb                  = dispDeviceRowBytes;
+
+       switch(dispDeviceDepth) {
+       case 24:
+       case 32:
+               draw_byte_32(font, (unsigned int *)base, rb);
+               break;
+       case 15:
+       case 16:
+               draw_byte_16(font, (unsigned int *)base, rb);
+               break;
+       case 8:
+               draw_byte_8(font, (unsigned int *)base, rb);
+               break;
+       }
+}
+
+static unsigned int expand_bits_8[16] = {
+       0x00000000,
+       0x000000ff,
+       0x0000ff00,
+       0x0000ffff,
+       0x00ff0000,
+       0x00ff00ff,
+       0x00ffff00,
+       0x00ffffff,
+       0xff000000,
+       0xff0000ff,
+       0xff00ff00,
+       0xff00ffff,
+       0xffff0000,
+       0xffff00ff,
+       0xffffff00,
+       0xffffffff
+};
+
+static unsigned int expand_bits_16[4] = {
+       0x00000000,
+       0x0000ffff,
+       0xffff0000,
+       0xffffffff
+};
+
+
+static void draw_byte_32(unsigned char *font, unsigned int *base, int rb)
+{
+       int l, bits;
+       int fg = 0xFFFFFFFFUL;
+       int bg = 0x00000000UL;
+
+       for (l = 0; l < 16; ++l)
+       {
+               bits = *font++;
+               base[0] = (-(bits >> 7) & fg) ^ bg;
+               base[1] = (-((bits >> 6) & 1) & fg) ^ bg;
+               base[2] = (-((bits >> 5) & 1) & fg) ^ bg;
+               base[3] = (-((bits >> 4) & 1) & fg) ^ bg;
+               base[4] = (-((bits >> 3) & 1) & fg) ^ bg;
+               base[5] = (-((bits >> 2) & 1) & fg) ^ bg;
+               base[6] = (-((bits >> 1) & 1) & fg) ^ bg;
+               base[7] = (-(bits & 1) & fg) ^ bg;
+               base = (unsigned int *) ((char *)base + rb);
+       }
+}
+
+static void draw_byte_16(unsigned char *font, unsigned int *base, int rb)
+{
+       int l, bits;
+       int fg = 0xFFFFFFFFUL;
+       int bg = 0x00000000UL;
+       unsigned int *eb = (int *)expand_bits_16;
+
+       for (l = 0; l < 16; ++l)
+       {
+               bits = *font++;
+               base[0] = (eb[bits >> 6] & fg) ^ bg;
+               base[1] = (eb[(bits >> 4) & 3] & fg) ^ bg;
+               base[2] = (eb[(bits >> 2) & 3] & fg) ^ bg;
+               base[3] = (eb[bits & 3] & fg) ^ bg;
+               base = (unsigned int *) ((char *)base + rb);
+       }
+}
+
+static void draw_byte_8(unsigned char *font, unsigned int *base, int rb)
+{
+       int l, bits;
+       int fg = 0x0F0F0F0FUL;
+       int bg = 0x00000000UL;
+       unsigned int *eb = (int *)expand_bits_8;
+
+       for (l = 0; l < 16; ++l)
+       {
+               bits = *font++;
+               base[0] = (eb[bits >> 4] & fg) ^ bg;
+               base[1] = (eb[bits & 0xf] & fg) ^ bg;
+               base = (unsigned int *) ((char *)base + rb);
+       }
+}
+
+static void btext_console_write(struct console *con, const char *s,
+                               unsigned int n)
+{
+       btext_drawtext(s, n);
+}
+
+static struct console btext_console = {
+       .name   = "btext",
+       .write  = btext_console_write,
+       .flags  = CON_PRINTBUFFER | CON_ENABLED | CON_BOOT | CON_ANYTIME,
+       .index  = 0,
+};
+
+int __init btext_find_display(void)
+{
+       unsigned int node;
+       char type[32];
+       int ret;
+
+       node = prom_inst2pkg(prom_stdout);
+       if (prom_getproperty(node, "device_type", type, 32) < 0)
+               return -ENODEV;
+       if (strcmp(type, "display"))
+               return -ENODEV;
+
+       ret = btext_initialize(node);
+       if (!ret) {
+               btext_clearscreen();
+               register_console(&btext_console);
+       }
+       return ret;
+}
+
+static unsigned char vga_font[cmapsz] = {
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x81, 0xa5, 0x81, 0x81, 0xbd,
+0x99, 0x81, 0x81, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xff,
+0xdb, 0xff, 0xff, 0xc3, 0xe7, 0xff, 0xff, 0x7e, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x6c, 0xfe, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x7c, 0xfe,
+0x7c, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18,
+0x3c, 0x3c, 0xe7, 0xe7, 0xe7, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x7e, 0x18, 0x18, 0x3c,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c,
+0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00,
+0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc3, 0x99, 0xbd,
+0xbd, 0x99, 0xc3, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x1e, 0x0e,
+0x1a, 0x32, 0x78, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x3c, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18, 0x18,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x33, 0x3f, 0x30, 0x30, 0x30,
+0x30, 0x70, 0xf0, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x63,
+0x7f, 0x63, 0x63, 0x63, 0x63, 0x67, 0xe7, 0xe6, 0xc0, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x18, 0x18, 0xdb, 0x3c, 0xe7, 0x3c, 0xdb, 0x18, 0x18,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfe, 0xf8,
+0xf0, 0xe0, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x06, 0x0e,
+0x1e, 0x3e, 0xfe, 0x3e, 0x1e, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
+0x66, 0x00, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xdb,
+0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x7c, 0xc6, 0x60, 0x38, 0x6c, 0xc6, 0xc6, 0x6c, 0x38, 0x0c, 0xc6,
+0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0xfe, 0xfe, 0xfe, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c,
+0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+0x18, 0x7e, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc0,
+0xc0, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x24, 0x66, 0xff, 0x66, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x38, 0x7c, 0x7c, 0xfe, 0xfe, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0x7c, 0x7c,
+0x38, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x24, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6c,
+0x6c, 0xfe, 0x6c, 0x6c, 0x6c, 0xfe, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00,
+0x18, 0x18, 0x7c, 0xc6, 0xc2, 0xc0, 0x7c, 0x06, 0x06, 0x86, 0xc6, 0x7c,
+0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc2, 0xc6, 0x0c, 0x18,
+0x30, 0x60, 0xc6, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c,
+0x6c, 0x38, 0x76, 0xdc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x30, 0x30, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x30,
+0x30, 0x30, 0x18, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x18,
+0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e,
+0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x02, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xce, 0xde, 0xf6, 0xe6, 0xc6, 0xc6, 0x7c,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x38, 0x78, 0x18, 0x18, 0x18,
+0x18, 0x18, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6,
+0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x7c, 0xc6, 0x06, 0x06, 0x3c, 0x06, 0x06, 0x06, 0xc6, 0x7c,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x1c, 0x3c, 0x6c, 0xcc, 0xfe,
+0x0c, 0x0c, 0x0c, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc0,
+0xc0, 0xc0, 0xfc, 0x06, 0x06, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x38, 0x60, 0xc0, 0xc0, 0xfc, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc6, 0x06, 0x06, 0x0c, 0x18,
+0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6,
+0xc6, 0xc6, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x06, 0x06, 0x0c, 0x78,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00,
+0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x06,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00,
+0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60,
+0x30, 0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x7c, 0xc6, 0xc6, 0x0c, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xde, 0xde,
+0xde, 0xdc, 0xc0, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38,
+0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x66, 0x66, 0x66, 0x66, 0xfc,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xc0,
+0xc0, 0xc2, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x6c,
+0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68, 0x60, 0x62, 0x66, 0xfe,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68,
+0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66,
+0xc2, 0xc0, 0xc0, 0xde, 0xc6, 0xc6, 0x66, 0x3a, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x18,
+0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x0c,
+0x0c, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0xe6, 0x66, 0x66, 0x6c, 0x78, 0x78, 0x6c, 0x66, 0x66, 0xe6,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x60, 0x60, 0x60, 0x60, 0x60,
+0x60, 0x62, 0x66, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xe7,
+0xff, 0xff, 0xdb, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6, 0xc6, 0xc6,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
+0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x66,
+0x66, 0x66, 0x7c, 0x60, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xd6, 0xde, 0x7c,
+0x0c, 0x0e, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x6c,
+0x66, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6,
+0xc6, 0x60, 0x38, 0x0c, 0x06, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0xff, 0xdb, 0x99, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
+0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3,
+0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xdb, 0xdb, 0xff, 0x66, 0x66,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x18,
+0x3c, 0x66, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3,
+0xc3, 0x66, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0xff, 0xc3, 0x86, 0x0c, 0x18, 0x30, 0x60, 0xc1, 0xc3, 0xff,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x30, 0x30, 0x30, 0x30, 0x30,
+0x30, 0x30, 0x30, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
+0xc0, 0xe0, 0x70, 0x38, 0x1c, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x3c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x3c,
+0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x0c, 0x7c,
+0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x60,
+0x60, 0x78, 0x6c, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc0, 0xc0, 0xc0, 0xc6, 0x7c,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x0c, 0x0c, 0x3c, 0x6c, 0xcc,
+0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60, 0x60, 0x60, 0x60, 0xf0,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xcc, 0xcc,
+0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xcc, 0x78, 0x00, 0x00, 0x00, 0xe0, 0x60,
+0x60, 0x6c, 0x76, 0x66, 0x66, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x18, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x00, 0x0e, 0x06, 0x06,
+0x06, 0x06, 0x06, 0x06, 0x66, 0x66, 0x3c, 0x00, 0x00, 0x00, 0xe0, 0x60,
+0x60, 0x66, 0x6c, 0x78, 0x78, 0x6c, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe6, 0xff, 0xdb,
+0xdb, 0xdb, 0xdb, 0xdb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x66, 0x66,
+0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x76, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0x0c, 0x1e, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0x60, 0x60, 0xf0,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0x60,
+0x38, 0x0c, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x30,
+0x30, 0xfc, 0x30, 0x30, 0x30, 0x30, 0x36, 0x1c, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, 0xc3,
+0xc3, 0x66, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0xc3, 0xc3, 0xc3, 0xdb, 0xdb, 0xff, 0x66, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18, 0x3c, 0x66, 0xc3,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6,
+0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0xfe, 0xcc, 0x18, 0x30, 0x60, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x0e, 0x18, 0x18, 0x18, 0x70, 0x18, 0x18, 0x18, 0x18, 0x0e,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00, 0x18,
+0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x18,
+0x18, 0x18, 0x0e, 0x18, 0x18, 0x18, 0x18, 0x70, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6,
+0xc6, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66,
+0xc2, 0xc0, 0xc0, 0xc0, 0xc2, 0x66, 0x3c, 0x0c, 0x06, 0x7c, 0x00, 0x00,
+0x00, 0x00, 0xcc, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x00, 0x7c, 0xc6, 0xfe,
+0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c,
+0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0xcc, 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x00, 0x78, 0x0c, 0x7c,
+0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x38,
+0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x60, 0x60, 0x66, 0x3c, 0x0c, 0x06,
+0x3c, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xfe,
+0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00,
+0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x60, 0x30, 0x18, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x38, 0x18, 0x18,
+0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 0x66,
+0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x60, 0x30, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c,
+0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6,
+0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x38, 0x00,
+0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
+0x18, 0x30, 0x60, 0x00, 0xfe, 0x66, 0x60, 0x7c, 0x60, 0x60, 0x66, 0xfe,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6e, 0x3b, 0x1b,
+0x7e, 0xd8, 0xdc, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x6c,
+0xcc, 0xcc, 0xfe, 0xcc, 0xcc, 0xcc, 0xcc, 0xce, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, 0x00, 0x7c, 0xc6, 0xc6,
+0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18,
+0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x30, 0x78, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x00, 0xcc, 0xcc, 0xcc,
+0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00,
+0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0x78, 0x00,
+0x00, 0xc6, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c,
+0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
+0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e,
+0xc3, 0xc0, 0xc0, 0xc0, 0xc3, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60, 0x60, 0x60, 0x60, 0xe6, 0xfc,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18, 0xff, 0x18,
+0xff, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x66, 0x66,
+0x7c, 0x62, 0x66, 0x6f, 0x66, 0x66, 0x66, 0xf3, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x0e, 0x1b, 0x18, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18,
+0xd8, 0x70, 0x00, 0x00, 0x00, 0x18, 0x30, 0x60, 0x00, 0x78, 0x0c, 0x7c,
+0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30,
+0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x18, 0x30, 0x60, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x30, 0x60, 0x00, 0xcc, 0xcc, 0xcc,
+0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc,
+0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00,
+0x76, 0xdc, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6, 0xc6,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x6c, 0x6c, 0x3e, 0x00, 0x7e, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x6c,
+0x38, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x30, 0x30, 0x00, 0x30, 0x30, 0x60, 0xc0, 0xc6, 0xc6, 0x7c,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc0,
+0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0xfe, 0x06, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0xc0, 0xc0, 0xc2, 0xc6, 0xcc, 0x18, 0x30, 0x60, 0xce, 0x9b, 0x06,
+0x0c, 0x1f, 0x00, 0x00, 0x00, 0xc0, 0xc0, 0xc2, 0xc6, 0xcc, 0x18, 0x30,
+0x66, 0xce, 0x96, 0x3e, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18,
+0x00, 0x18, 0x18, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x6c, 0xd8, 0x6c, 0x36, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x6c, 0x36,
+0x6c, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x44, 0x11, 0x44,
+0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44,
+0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa,
+0x55, 0xaa, 0x55, 0xaa, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77,
+0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0x18, 0x18, 0x18, 0x18,
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18,
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8,
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36,
+0x36, 0x36, 0x36, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x36, 0x36, 0x36, 0x36,
+0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0xf8,
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36,
+0x36, 0xf6, 0x06, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x06, 0xf6,
+0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+0x36, 0xf6, 0x06, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xfe, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18,
+0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18,
+0x18, 0x18, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18,
+0x18, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x37,
+0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+0x36, 0x37, 0x30, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36,
+0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xf7, 0x00, 0xff,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0xff, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36,
+0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x36, 0x36, 0x36,
+0x36, 0xf7, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xff,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0xff, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x36, 0x36, 0x36, 0x36,
+0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x3f,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18,
+0x18, 0x1f, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18,
+0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f,
+0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+0x36, 0x36, 0x36, 0xff, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18,
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xf0, 0xf0, 0xf0,
+0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0,
+0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
+0x0f, 0x0f, 0x0f, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x76, 0xdc, 0xd8, 0xd8, 0xd8, 0xdc, 0x76, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0xd8, 0xcc, 0xc6, 0xc6, 0xc6, 0xcc,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc6, 0xc6, 0xc0, 0xc0, 0xc0,
+0xc0, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0xfe, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0xfe, 0xc6, 0x60, 0x30, 0x18, 0x30, 0x60, 0xc6, 0xfe,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xd8, 0xd8,
+0xd8, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x66, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xc0, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x18, 0x3c, 0x66, 0x66,
+0x66, 0x3c, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38,
+0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x6c, 0x6c, 0x6c, 0xee,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x30, 0x18, 0x0c, 0x3e, 0x66,
+0x66, 0x66, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x7e, 0xdb, 0xdb, 0xdb, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x03, 0x06, 0x7e, 0xdb, 0xdb, 0xf3, 0x7e, 0x60, 0xc0,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x30, 0x60, 0x60, 0x7c, 0x60,
+0x60, 0x60, 0x30, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c,
+0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18,
+0x18, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30,
+0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x00, 0x7e,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x1b, 0x1b, 0x1b, 0x18, 0x18,
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+0x18, 0x18, 0x18, 0x18, 0xd8, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x7e, 0x00, 0x18, 0x18, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x00,
+0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x6c,
+0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x0c, 0x0c,
+0x0c, 0x0c, 0x0c, 0xec, 0x6c, 0x6c, 0x3c, 0x1c, 0x00, 0x00, 0x00, 0x00,
+0x00, 0xd8, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0xd8, 0x30, 0x60, 0xc8, 0xf8, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00,
+};
index 1446df9..e447938 100644 (file)
@@ -185,6 +185,17 @@ static const struct manufacturer_info __initconst manufacturer_info[] = {
                FPU(-1, NULL)
        }
 },{
+       0xF,            /* Aeroflex Gaisler */
+       .cpu_info = {
+               CPU(3, "LEON"),
+               CPU(-1, NULL)
+       },
+       .fpu_info = {
+               FPU(2, "GRFPU"),
+               FPU(3, "GRFPU-Lite"),
+               FPU(-1, NULL)
+       }
+},{
        0x17,
        .cpu_info = {
                CPU_PMU(0x10, "TI UltraSparc I   (SpitFire)", "ultra12"),
index f41ecc5..ec9c7bc 100644 (file)
@@ -400,6 +400,39 @@ linux_trap_ipi15_sun4d:
        /* FIXME */
 1:     b,a     1b
 
+#ifdef CONFIG_SPARC_LEON
+
+       .globl  smpleon_ticker
+       /* SMP per-cpu ticker interrupts are handled specially. */
+smpleon_ticker:
+        SAVE_ALL
+       or      %l0, PSR_PIL, %g2
+       wr      %g2, 0x0, %psr
+       WRITE_PAUSE
+       wr      %g2, PSR_ET, %psr
+       WRITE_PAUSE
+       call    leon_percpu_timer_interrupt
+        add    %sp, STACKFRAME_SZ, %o0
+       wr      %l0, PSR_ET, %psr
+       WRITE_PAUSE
+       RESTORE_ALL
+
+       .align  4
+       .globl  linux_trap_ipi15_leon
+linux_trap_ipi15_leon:
+       SAVE_ALL
+       or      %l0, PSR_PIL, %l4
+       wr      %l4, 0x0, %psr
+       WRITE_PAUSE
+       wr      %l4, PSR_ET, %psr
+       WRITE_PAUSE
+       call    leon_cross_call_irq
+        nop
+       b       ret_trap_lockless_ipi
+        clr    %l6
+
+#endif /* CONFIG_SPARC_LEON */
+
 #endif /* CONFIG_SMP */
 
        /* This routine handles illegal instructions and privileged
index 439d82a..21bb259 100644 (file)
@@ -811,9 +811,31 @@ found_version:
 got_prop:
 #ifdef CONFIG_SPARC_LEON
                /* no cpu-type check is needed, it is a SPARC-LEON */
+#ifdef CONFIG_SMP
+               ba leon_smp_init
+                nop
+
+               .global leon_smp_init
+leon_smp_init:
+               sethi   %hi(boot_cpu_id), %g1    ! master always 0
+               stb     %g0, [%g1 + %lo(boot_cpu_id)]
+               sethi   %hi(boot_cpu_id4), %g1   ! master always 0
+               stb     %g0, [%g1 + %lo(boot_cpu_id4)]
+
+               rd     %asr17,%g1
+               srl    %g1,28,%g1
+
+               cmp %g0,%g1
+                beq sun4c_continue_boot         !continue with master
+               nop
+
+               ba leon_smp_cpu_startup
+                nop
+#else
                ba sun4c_continue_boot
                 nop
 #endif
+#endif
                set     cputypval, %o2
                ldub    [%o2 + 0x4], %l1
 
index 9f61fd8..3c8c44f 100644 (file)
 #include <asm/dma.h>
 #include <asm/iommu.h>
 #include <asm/io-unit.h>
+#include <asm/leon.h>
 
+#ifdef CONFIG_SPARC_LEON
+#define mmu_inval_dma_area(p, l) leon_flush_dcache_all()
+#else
 #define mmu_inval_dma_area(p, l)       /* Anton pulled it out for 2.4.0-xx */
+#endif
 
 static struct resource *_sparc_find_resource(struct resource *r,
                                             unsigned long);
index 8ab1d47..ce996f9 100644 (file)
@@ -187,7 +187,7 @@ int show_interrupts(struct seq_file *p, void *v)
                for_each_online_cpu(j)
                        seq_printf(p, "%10u ", kstat_irqs_cpu(i, j));
 #endif
-               seq_printf(p, " %9s", irq_desc[i].chip->typename);
+               seq_printf(p, " %9s", irq_desc[i].chip->name);
                seq_printf(p, "  %s", action->name);
 
                for (action=action->next; action; action = action->next)
@@ -484,7 +484,7 @@ static void sun4v_virq_eoi(unsigned int virt_irq)
 }
 
 static struct irq_chip sun4u_irq = {
-       .typename       = "sun4u",
+       .name           = "sun4u",
        .enable         = sun4u_irq_enable,
        .disable        = sun4u_irq_disable,
        .eoi            = sun4u_irq_eoi,
@@ -492,7 +492,7 @@ static struct irq_chip sun4u_irq = {
 };
 
 static struct irq_chip sun4v_irq = {
-       .typename       = "sun4v",
+       .name           = "sun4v",
        .enable         = sun4v_irq_enable,
        .disable        = sun4v_irq_disable,
        .eoi            = sun4v_irq_eoi,
@@ -500,7 +500,7 @@ static struct irq_chip sun4v_irq = {
 };
 
 static struct irq_chip sun4v_virq = {
-       .typename       = "vsun4v",
+       .name           = "vsun4v",
        .enable         = sun4v_virq_enable,
        .disable        = sun4v_virq_disable,
        .eoi            = sun4v_virq_eoi,
index 54d8a5b..87f1760 100644 (file)
 #include <linux/of_platform.h>
 #include <linux/interrupt.h>
 #include <linux/of_device.h>
+
 #include <asm/oplib.h>
 #include <asm/timer.h>
 #include <asm/prom.h>
 #include <asm/leon.h>
 #include <asm/leon_amba.h>
+#include <asm/traps.h>
+#include <asm/cacheflush.h>
 
 #include "prom.h"
 #include "irq.h"
@@ -115,6 +118,21 @@ void __init leon_init_timers(irq_handler_t counter_fn)
                                      (((1000000 / 100) - 1)));
                LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[0].ctrl, 0);
 
+#ifdef CONFIG_SMP
+               leon_percpu_timer_dev[0].start = (int)leon3_gptimer_regs;
+               leon_percpu_timer_dev[0].irq = leon3_gptimer_irq+1;
+
+               if (!(LEON3_BYPASS_LOAD_PA(&leon3_gptimer_regs->config) &
+                     (1<<LEON3_GPTIMER_SEPIRQ))) {
+                       prom_printf("irq timer not configured with seperate irqs \n");
+                       BUG();
+               }
+
+               LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[1].val, 0);
+               LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[1].rld, (((1000000/100) - 1)));
+               LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[1].ctrl, 0);
+# endif
+
        } else {
                printk(KERN_ERR "No Timer/irqctrl found\n");
                BUG();
@@ -130,11 +148,41 @@ void __init leon_init_timers(irq_handler_t counter_fn)
                prom_halt();
        }
 
+# ifdef CONFIG_SMP
+       {
+               unsigned long flags;
+               struct tt_entry *trap_table = &sparc_ttable[SP_TRAP_IRQ1 + (leon_percpu_timer_dev[0].irq - 1)];
+
+               /* For SMP we use the level 14 ticker, however the bootup code
+                * has copied the firmwares level 14 vector into boot cpu's
+                * trap table, we must fix this now or we get squashed.
+                */
+               local_irq_save(flags);
+
+               patchme_maybe_smp_msg[0] = 0x01000000; /* NOP out the branch */
+
+               /* Adjust so that we jump directly to smpleon_ticker */
+               trap_table->inst_three += smpleon_ticker - real_irq_entry;
+
+               local_flush_cache_all();
+               local_irq_restore(flags);
+       }
+# endif
+
        if (leon3_gptimer_regs) {
                LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[0].ctrl,
                                      LEON3_GPTIMER_EN |
                                      LEON3_GPTIMER_RL |
                                      LEON3_GPTIMER_LD | LEON3_GPTIMER_IRQEN);
+
+#ifdef CONFIG_SMP
+               LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[1].ctrl,
+                                     LEON3_GPTIMER_EN |
+                                     LEON3_GPTIMER_RL |
+                                     LEON3_GPTIMER_LD |
+                                     LEON3_GPTIMER_IRQEN);
+#endif
+
        }
 }
 
@@ -175,6 +223,42 @@ void __init leon_node_init(struct device_node *dp, struct device_node ***nextp)
        }
 }
 
+#ifdef CONFIG_SMP
+
+void leon_set_cpu_int(int cpu, int level)
+{
+       unsigned long mask;
+       mask = get_irqmask(level);
+       LEON3_BYPASS_STORE_PA(&leon3_irqctrl_regs->force[cpu], mask);
+}
+
+static void leon_clear_ipi(int cpu, int level)
+{
+       unsigned long mask;
+       mask = get_irqmask(level);
+       LEON3_BYPASS_STORE_PA(&leon3_irqctrl_regs->force[cpu], mask<<16);
+}
+
+static void leon_set_udt(int cpu)
+{
+}
+
+void leon_clear_profile_irq(int cpu)
+{
+}
+
+void leon_enable_irq_cpu(unsigned int irq_nr, unsigned int cpu)
+{
+       unsigned long mask, flags, *addr;
+       mask = get_irqmask(irq_nr);
+       local_irq_save(flags);
+       addr = (unsigned long *)&(leon3_irqctrl_regs->mask[cpu]);
+       LEON3_BYPASS_STORE_PA(addr, (LEON3_BYPASS_LOAD_PA(addr) | (mask)));
+       local_irq_restore(flags);
+}
+
+#endif
+
 void __init leon_init_IRQ(void)
 {
        sparc_init_timers = leon_init_timers;
diff --git a/arch/sparc/kernel/leon_smp.c b/arch/sparc/kernel/leon_smp.c
new file mode 100644 (file)
index 0000000..05c0dad
--- /dev/null
@@ -0,0 +1,468 @@
+/* leon_smp.c: Sparc-Leon SMP support.
+ *
+ * based on sun4m_smp.c
+ * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 2009 Daniel Hellstrom (daniel@gaisler.com) Aeroflex Gaisler AB
+ * Copyright (C) 2009 Konrad Eisele (konrad@gaisler.com) Aeroflex Gaisler AB
+ */
+
+#include <asm/head.h>
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/threads.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/interrupt.h>
+#include <linux/kernel_stat.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <linux/mm.h>
+#include <linux/swap.h>
+#include <linux/profile.h>
+#include <linux/pm.h>
+#include <linux/delay.h>
+
+#include <asm/cacheflush.h>
+#include <asm/tlbflush.h>
+
+#include <asm/ptrace.h>
+#include <asm/atomic.h>
+#include <asm/irq_regs.h>
+
+#include <asm/delay.h>
+#include <asm/irq.h>
+#include <asm/page.h>
+#include <asm/pgalloc.h>
+#include <asm/pgtable.h>
+#include <asm/oplib.h>
+#include <asm/cpudata.h>
+#include <asm/asi.h>
+#include <asm/leon.h>
+#include <asm/leon_amba.h>
+
+#ifdef CONFIG_SPARC_LEON
+
+#include "irq.h"
+
+extern ctxd_t *srmmu_ctx_table_phys;
+static int smp_processors_ready;
+extern volatile unsigned long cpu_callin_map[NR_CPUS];
+extern unsigned char boot_cpu_id;
+extern cpumask_t smp_commenced_mask;
+void __init leon_configure_cache_smp(void);
+
+static inline unsigned long do_swap(volatile unsigned long *ptr,
+                                   unsigned long val)
+{
+       __asm__ __volatile__("swapa [%1] %2, %0\n\t" : "=&r"(val)
+                            : "r"(ptr), "i"(ASI_LEON_DCACHE_MISS)
+                            : "memory");
+       return val;
+}
+
+static void smp_setup_percpu_timer(void);
+
+void __cpuinit leon_callin(void)
+{
+       int cpuid = hard_smpleon_processor_id();
+
+       local_flush_cache_all();
+       local_flush_tlb_all();
+       leon_configure_cache_smp();
+
+       /* Get our local ticker going. */
+       smp_setup_percpu_timer();
+
+       calibrate_delay();
+       smp_store_cpu_info(cpuid);
+
+       local_flush_cache_all();
+       local_flush_tlb_all();
+
+       /*
+        * Unblock the master CPU _only_ when the scheduler state
+        * of all secondary CPUs will be up-to-date, so after
+        * the SMP initialization the master will be just allowed
+        * to call the scheduler code.
+        * Allow master to continue.
+        */
+       do_swap(&cpu_callin_map[cpuid], 1);
+
+       local_flush_cache_all();
+       local_flush_tlb_all();
+
+       cpu_probe();
+
+       /* Fix idle thread fields. */
+       __asm__ __volatile__("ld [%0], %%g6\n\t" : : "r"(&current_set[cpuid])
+                            : "memory" /* paranoid */);
+
+       /* Attach to the address space of init_task. */
+       atomic_inc(&init_mm.mm_count);
+       current->active_mm = &init_mm;
+
+       while (!cpu_isset(cpuid, smp_commenced_mask))
+               mb();
+
+       local_irq_enable();
+       cpu_set(cpuid, cpu_online_map);
+}
+
+/*
+ *     Cycle through the processors asking the PROM to start each one.
+ */
+
+extern struct linux_prom_registers smp_penguin_ctable;
+
+void __init leon_configure_cache_smp(void)
+{
+       unsigned long cfg = sparc_leon3_get_dcachecfg();
+       int me = smp_processor_id();
+
+       if (ASI_LEON3_SYSCTRL_CFG_SSIZE(cfg) > 4) {
+               printk(KERN_INFO "Note: SMP with snooping only works on 4k cache, found %dk(0x%x) on cpu %d, disabling caches\n",
+                    (unsigned int)ASI_LEON3_SYSCTRL_CFG_SSIZE(cfg),
+                    (unsigned int)cfg, (unsigned int)me);
+               sparc_leon3_disable_cache();
+       } else {
+               if (cfg & ASI_LEON3_SYSCTRL_CFG_SNOOPING) {
+                       sparc_leon3_enable_snooping();
+               } else {
+                       printk(KERN_INFO "Note: You have to enable snooping in the vhdl model cpu %d, disabling caches\n",
+                            me);
+                       sparc_leon3_disable_cache();
+               }
+       }
+
+       local_flush_cache_all();
+       local_flush_tlb_all();
+}
+
+void leon_smp_setbroadcast(unsigned int mask)
+{
+       int broadcast =
+           ((LEON3_BYPASS_LOAD_PA(&(leon3_irqctrl_regs->mpstatus)) >>
+             LEON3_IRQMPSTATUS_BROADCAST) & 1);
+       if (!broadcast) {
+               prom_printf("######## !!!! The irqmp-ctrl must have broadcast enabled, smp wont work !!!!! ####### nr cpus: %d\n",
+                    leon_smp_nrcpus());
+               if (leon_smp_nrcpus() > 1) {
+                       BUG();
+               } else {
+                       prom_printf("continue anyway\n");
+                       return;
+               }
+       }
+       LEON_BYPASS_STORE_PA(&(leon3_irqctrl_regs->mpbroadcast), mask);
+}
+
+unsigned int leon_smp_getbroadcast(void)
+{
+       unsigned int mask;
+       mask = LEON_BYPASS_LOAD_PA(&(leon3_irqctrl_regs->mpbroadcast));
+       return mask;
+}
+
+int leon_smp_nrcpus(void)
+{
+       int nrcpu =
+           ((LEON3_BYPASS_LOAD_PA(&(leon3_irqctrl_regs->mpstatus)) >>
+             LEON3_IRQMPSTATUS_CPUNR) & 0xf) + 1;
+       return nrcpu;
+}
+
+void __init leon_boot_cpus(void)
+{
+       int nrcpu = leon_smp_nrcpus();
+       int me = smp_processor_id();
+
+       printk(KERN_INFO "%d:(%d:%d) cpus mpirq at 0x%x \n", (unsigned int)me,
+              (unsigned int)nrcpu, (unsigned int)NR_CPUS,
+              (unsigned int)&(leon3_irqctrl_regs->mpstatus));
+
+       leon_enable_irq_cpu(LEON3_IRQ_CROSS_CALL, me);
+       leon_enable_irq_cpu(LEON3_IRQ_TICKER, me);
+       leon_enable_irq_cpu(LEON3_IRQ_RESCHEDULE, me);
+
+       leon_smp_setbroadcast(1 << LEON3_IRQ_TICKER);
+
+       leon_configure_cache_smp();
+       smp_setup_percpu_timer();
+       local_flush_cache_all();
+
+}
+
+int __cpuinit leon_boot_one_cpu(int i)
+{
+
+       struct task_struct *p;
+       int timeout;
+
+       /* Cook up an idler for this guy. */
+       p = fork_idle(i);
+
+       current_set[i] = task_thread_info(p);
+
+       /* See trampoline.S:leon_smp_cpu_startup for details...
+        * Initialize the contexts table
+        * Since the call to prom_startcpu() trashes the structure,
+        * we need to re-initialize it for each cpu
+        */
+       smp_penguin_ctable.which_io = 0;
+       smp_penguin_ctable.phys_addr = (unsigned int)srmmu_ctx_table_phys;
+       smp_penguin_ctable.reg_size = 0;
+
+       /* whirrr, whirrr, whirrrrrrrrr... */
+       printk(KERN_INFO "Starting CPU %d : (irqmp: 0x%x)\n", (unsigned int)i,
+              (unsigned int)&leon3_irqctrl_regs->mpstatus);
+       local_flush_cache_all();
+
+       LEON_BYPASS_STORE_PA(&(leon3_irqctrl_regs->mpstatus), 1 << i);
+
+       /* wheee... it's going... */
+       for (timeout = 0; timeout < 10000; timeout++) {
+               if (cpu_callin_map[i])
+                       break;
+               udelay(200);
+       }
+       printk(KERN_INFO "Started CPU %d \n", (unsigned int)i);
+
+       if (!(cpu_callin_map[i])) {
+               printk(KERN_ERR "Processor %d is stuck.\n", i);
+               return -ENODEV;
+       } else {
+               leon_enable_irq_cpu(LEON3_IRQ_CROSS_CALL, i);
+               leon_enable_irq_cpu(LEON3_IRQ_TICKER, i);
+               leon_enable_irq_cpu(LEON3_IRQ_RESCHEDULE, i);
+       }
+
+       local_flush_cache_all();
+       return 0;
+}
+
+void __init leon_smp_done(void)
+{
+
+       int i, first;
+       int *prev;
+
+       /* setup cpu list for irq rotation */
+       first = 0;
+       prev = &first;
+       for (i = 0; i < NR_CPUS; i++) {
+               if (cpu_online(i)) {
+                       *prev = i;
+                       prev = &cpu_data(i).next;
+               }
+       }
+       *prev = first;
+       local_flush_cache_all();
+
+       /* Free unneeded trap tables */
+       if (!cpu_isset(1, cpu_present_map)) {
+               ClearPageReserved(virt_to_page(trapbase_cpu1));
+               init_page_count(virt_to_page(trapbase_cpu1));
+               free_page((unsigned long)trapbase_cpu1);
+               totalram_pages++;
+               num_physpages++;
+       }
+       if (!cpu_isset(2, cpu_present_map)) {
+               ClearPageReserved(virt_to_page(trapbase_cpu2));
+               init_page_count(virt_to_page(trapbase_cpu2));
+               free_page((unsigned long)trapbase_cpu2);
+               totalram_pages++;
+               num_physpages++;
+       }
+       if (!cpu_isset(3, cpu_present_map)) {
+               ClearPageReserved(virt_to_page(trapbase_cpu3));
+               init_page_count(virt_to_page(trapbase_cpu3));
+               free_page((unsigned long)trapbase_cpu3);
+               totalram_pages++;
+               num_physpages++;
+       }
+       /* Ok, they are spinning and ready to go. */
+       smp_processors_ready = 1;
+
+}
+
+void leon_irq_rotate(int cpu)
+{
+}
+
+static struct smp_funcall {
+       smpfunc_t func;
+       unsigned long arg1;
+       unsigned long arg2;
+       unsigned long arg3;
+       unsigned long arg4;
+       unsigned long arg5;
+       unsigned long processors_in[NR_CPUS];   /* Set when ipi entered. */
+       unsigned long processors_out[NR_CPUS];  /* Set when ipi exited. */
+} ccall_info;
+
+static DEFINE_SPINLOCK(cross_call_lock);
+
+/* Cross calls must be serialized, at least currently. */
+static void leon_cross_call(smpfunc_t func, cpumask_t mask, unsigned long arg1,
+                           unsigned long arg2, unsigned long arg3,
+                           unsigned long arg4)
+{
+       if (smp_processors_ready) {
+               register int high = NR_CPUS - 1;
+               unsigned long flags;
+
+               spin_lock_irqsave(&cross_call_lock, flags);
+
+               {
+                       /* If you make changes here, make sure gcc generates proper code... */
+                       register smpfunc_t f asm("i0") = func;
+                       register unsigned long a1 asm("i1") = arg1;
+                       register unsigned long a2 asm("i2") = arg2;
+                       register unsigned long a3 asm("i3") = arg3;
+                       register unsigned long a4 asm("i4") = arg4;
+                       register unsigned long a5 asm("i5") = 0;
+
+                       __asm__ __volatile__("std %0, [%6]\n\t"
+                                            "std %2, [%6 + 8]\n\t"
+                                            "std %4, [%6 + 16]\n\t" : :
+                                            "r"(f), "r"(a1), "r"(a2), "r"(a3),
+                                            "r"(a4), "r"(a5),
+                                            "r"(&ccall_info.func));
+               }
+
+               /* Init receive/complete mapping, plus fire the IPI's off. */
+               {
+                       register int i;
+
+                       cpu_clear(smp_processor_id(), mask);
+                       cpus_and(mask, cpu_online_map, mask);
+                       for (i = 0; i <= high; i++) {
+                               if (cpu_isset(i, mask)) {
+                                       ccall_info.processors_in[i] = 0;
+                                       ccall_info.processors_out[i] = 0;
+                                       set_cpu_int(i, LEON3_IRQ_CROSS_CALL);
+
+                               }
+                       }
+               }
+
+               {
+                       register int i;
+
+                       i = 0;
+                       do {
+                               if (!cpu_isset(i, mask))
+                                       continue;
+
+                               while (!ccall_info.processors_in[i])
+                                       barrier();
+                       } while (++i <= high);
+
+                       i = 0;
+                       do {
+                               if (!cpu_isset(i, mask))
+                                       continue;
+
+                               while (!ccall_info.processors_out[i])
+                                       barrier();
+                       } while (++i <= high);
+               }
+
+               spin_unlock_irqrestore(&cross_call_lock, flags);
+       }
+}
+
+/* Running cross calls. */
+void leon_cross_call_irq(void)
+{
+       int i = smp_processor_id();
+
+       ccall_info.processors_in[i] = 1;
+       ccall_info.func(ccall_info.arg1, ccall_info.arg2, ccall_info.arg3,
+                       ccall_info.arg4, ccall_info.arg5);
+       ccall_info.processors_out[i] = 1;
+}
+
+void leon_percpu_timer_interrupt(struct pt_regs *regs)
+{
+       struct pt_regs *old_regs;
+       int cpu = smp_processor_id();
+
+       old_regs = set_irq_regs(regs);
+
+       leon_clear_profile_irq(cpu);
+
+       profile_tick(CPU_PROFILING);
+
+       if (!--prof_counter(cpu)) {
+               int user = user_mode(regs);
+
+               irq_enter();
+               update_process_times(user);
+               irq_exit();
+
+               prof_counter(cpu) = prof_multiplier(cpu);
+       }
+       set_irq_regs(old_regs);
+}
+
+static void __init smp_setup_percpu_timer(void)
+{
+       int cpu = smp_processor_id();
+
+       prof_counter(cpu) = prof_multiplier(cpu) = 1;
+}
+
+void __init leon_blackbox_id(unsigned *addr)
+{
+       int rd = *addr & 0x3e000000;
+       int rs1 = rd >> 11;
+
+       /* patch places where ___b_hard_smp_processor_id appears */
+       addr[0] = 0x81444000 | rd;      /* rd %asr17, reg */
+       addr[1] = 0x8130201c | rd | rs1;        /* srl reg, 0x1c, reg */
+       addr[2] = 0x01000000;   /* nop */
+}
+
+void __init leon_blackbox_current(unsigned *addr)
+{
+       int rd = *addr & 0x3e000000;
+       int rs1 = rd >> 11;
+
+       /* patch LOAD_CURRENT macro where ___b_load_current appears */
+       addr[0] = 0x81444000 | rd;      /* rd %asr17, reg */
+       addr[2] = 0x8130201c | rd | rs1;        /* srl reg, 0x1c, reg */
+       addr[4] = 0x81282002 | rd | rs1;        /* sll reg, 0x2, reg */
+
+}
+
+/*
+ * CPU idle callback function
+ * See .../arch/sparc/kernel/process.c
+ */
+void pmc_leon_idle(void)
+{
+       __asm__ volatile ("mov %g0, %asr19");
+}
+
+void __init leon_init_smp(void)
+{
+       /* Patch ipi15 trap table */
+       t_nmi[1] = t_nmi[1] + (linux_trap_ipi15_leon - linux_trap_ipi15_sun4m);
+
+       BTFIXUPSET_BLACKBOX(hard_smp_processor_id, leon_blackbox_id);
+       BTFIXUPSET_BLACKBOX(load_current, leon_blackbox_current);
+       BTFIXUPSET_CALL(smp_cross_call, leon_cross_call, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(__hard_smp_processor_id, __leon_processor_id,
+                       BTFIXUPCALL_NORM);
+
+#ifndef PMC_NO_IDLE
+       /* Assign power management IDLE handler */
+       pm_idle = pmc_leon_idle;
+       printk(KERN_INFO "leon: power management initialized\n");
+#endif
+
+}
+
+#endif /* CONFIG_SPARC_LEON */
index f1be37a..e1b0541 100644 (file)
@@ -112,7 +112,7 @@ static void free_msi(struct pci_pbm_info *pbm, int msi_num)
 }
 
 static struct irq_chip msi_irq = {
-       .typename       = "PCI-MSI",
+       .name           = "PCI-MSI",
        .mask           = mask_msi_irq,
        .unmask         = unmask_msi_irq,
        .enable         = unmask_msi_irq,
index 2118033..a2a79e7 100644 (file)
@@ -46,6 +46,7 @@
 #include <asm/setup.h>
 #include <asm/mmu.h>
 #include <asm/ns87303.h>
+#include <asm/btext.h>
 
 #ifdef CONFIG_IP_PNP
 #include <net/ipconfig.h>
@@ -286,7 +287,10 @@ void __init setup_arch(char **cmdline_p)
        parse_early_param();
 
        boot_flags_init(*cmdline_p);
-       register_console(&prom_early_console);
+#ifdef CONFIG_EARLYFB
+       if (btext_find_display())
+#endif
+               register_console(&prom_early_console);
 
        if (tlb_type == hypervisor)
                printk("ARCH: SUN4V\n");
index 132d81f..91c10fb 100644 (file)
@@ -32,6 +32,7 @@
 #include <asm/cacheflush.h>
 #include <asm/tlbflush.h>
 #include <asm/cpudata.h>
+#include <asm/leon.h>
 
 #include "irq.h"
 
@@ -96,6 +97,9 @@ void __init smp_cpus_done(unsigned int max_cpus)
        case sun4d:
                smp4d_smp_done();
                break;
+       case sparc_leon:
+               leon_smp_done();
+               break;
        case sun4e:
                printk("SUN4E\n");
                BUG();
@@ -306,6 +310,9 @@ void __init smp_prepare_cpus(unsigned int max_cpus)
        case sun4d:
                smp4d_boot_cpus();
                break;
+       case sparc_leon:
+               leon_boot_cpus();
+               break;
        case sun4e:
                printk("SUN4E\n");
                BUG();
@@ -376,6 +383,9 @@ int __cpuinit __cpu_up(unsigned int cpu)
        case sun4d:
                ret = smp4d_boot_one_cpu(cpu);
                break;
+       case sparc_leon:
+               ret = leon_boot_one_cpu(cpu);
+               break;
        case sun4e:
                printk("SUN4E\n");
                BUG();
index 04e28b2..00abe87 100644 (file)
 #include <linux/nfs_fs.h>
 #include <linux/quota.h>
 #include <linux/module.h>
-#include <linux/sunrpc/svc.h>
-#include <linux/nfsd/nfsd.h>
-#include <linux/nfsd/cache.h>
-#include <linux/nfsd/xdr.h>
-#include <linux/nfsd/syscall.h>
 #include <linux/poll.h>
 #include <linux/personality.h>
 #include <linux/stat.h>
@@ -591,63 +586,6 @@ out:
        return ret;       
 }
 
-struct __sysctl_args32 {
-       u32 name;
-       int nlen;
-       u32 oldval;
-       u32 oldlenp;
-       u32 newval;
-       u32 newlen;
-       u32 __unused[4];
-};
-
-asmlinkage long sys32_sysctl(struct __sysctl_args32 __user *args)
-{
-#ifndef CONFIG_SYSCTL_SYSCALL
-       return -ENOSYS;
-#else
-       struct __sysctl_args32 tmp;
-       int error;
-       size_t oldlen, __user *oldlenp = NULL;
-       unsigned long addr = (((unsigned long)&args->__unused[0]) + 7UL) & ~7UL;
-
-       if (copy_from_user(&tmp, args, sizeof(tmp)))
-               return -EFAULT;
-
-       if (tmp.oldval && tmp.oldlenp) {
-               /* Duh, this is ugly and might not work if sysctl_args
-                  is in read-only memory, but do_sysctl does indirectly
-                  a lot of uaccess in both directions and we'd have to
-                  basically copy the whole sysctl.c here, and
-                  glibc's __sysctl uses rw memory for the structure
-                  anyway.  */
-               if (get_user(oldlen, (u32 __user *)(unsigned long)tmp.oldlenp) ||
-                   put_user(oldlen, (size_t __user *)addr))
-                       return -EFAULT;
-               oldlenp = (size_t __user *)addr;
-       }
-
-       lock_kernel();
-       error = do_sysctl((int __user *)(unsigned long) tmp.name,
-                         tmp.nlen,
-                         (void __user *)(unsigned long) tmp.oldval,
-                         oldlenp,
-                         (void __user *)(unsigned long) tmp.newval,
-                         tmp.newlen);
-       unlock_kernel();
-       if (oldlenp) {
-               if (!error) {
-                       if (get_user(oldlen, (size_t __user *)addr) ||
-                           put_user(oldlen, (u32 __user *)(unsigned long) tmp.oldlenp))
-                               error = -EFAULT;
-               }
-               if (copy_to_user(args->__unused, tmp.__unused, sizeof(tmp.__unused)))
-                       error = -EFAULT;
-       }
-       return error;
-#endif
-}
-
 long sys32_lookup_dcookie(unsigned long cookie_high,
                          unsigned long cookie_low,
                          char __user *buf, size_t len)
index f37bef7..cc8e786 100644 (file)
@@ -68,7 +68,7 @@ sys_call_table32:
        .word compat_sys_fstatfs64, sys_llseek, sys_mlock, sys_munlock, sys32_mlockall
 /*240*/        .word sys_munlockall, sys32_sched_setparam, sys32_sched_getparam, sys32_sched_setscheduler, sys32_sched_getscheduler
        .word sys_sched_yield, sys32_sched_get_priority_max, sys32_sched_get_priority_min, sys32_sched_rr_get_interval, compat_sys_nanosleep
-/*250*/        .word sys32_mremap, sys32_sysctl, sys32_getsid, sys_fdatasync, sys32_nfsservctl
+/*250*/        .word sys32_mremap, compat_sys_sysctl, sys32_getsid, sys_fdatasync, sys32_nfsservctl
        .word sys32_sync_file_range, compat_sys_clock_settime, compat_sys_clock_gettime, compat_sys_clock_getres, sys32_clock_nanosleep
 /*260*/        .word compat_sys_sched_getaffinity, compat_sys_sched_setaffinity, sys32_timer_settime, compat_sys_timer_gettime, sys_timer_getoverrun
        .word sys_timer_delete, compat_sys_timer_create, sys_ni_syscall, compat_sys_io_setup, sys_io_destroy
index 614ac7b..5b2f595 100644 (file)
@@ -210,9 +210,6 @@ static void __init sbus_time_init(void)
        btfixup();
 
        sparc_init_timers(timer_interrupt);
-       
-       /* Now that OBP ticker has been silenced, it is safe to enable IRQ. */
-       local_irq_enable();
 }
 
 void __init time_init(void)
index 5e235c5..691f484 100644 (file)
@@ -15,7 +15,7 @@
 #include <asm/contregs.h>
 #include <asm/thread_info.h>
 
-       .globl sun4m_cpu_startup, __smp4m_processor_id
+       .globl sun4m_cpu_startup, __smp4m_processor_id, __leon_processor_id
        .globl sun4d_cpu_startup, __smp4d_processor_id
 
        __CPUINIT
@@ -106,6 +106,12 @@ __smp4d_processor_id:
        retl
         mov    %g1, %o7
 
+__leon_processor_id:
+       rd     %asr17,%g2
+        srl    %g2,28,%g2
+       retl
+        mov    %g1, %o7
+
 /* CPUID in bootbus can be found at PA 0xff0140000 */
 #define SUN4D_BOOTBUS_CPUID    0xf0140000
 
@@ -160,3 +166,64 @@ sun4d_cpu_startup:
         nop
 
        b,a     smp_do_cpu_idle
+
+#ifdef CONFIG_SPARC_LEON
+
+       __CPUINIT
+       .align  4
+        .global leon_smp_cpu_startup, smp_penguin_ctable
+
+leon_smp_cpu_startup:
+
+        set smp_penguin_ctable,%g1
+        ld [%g1+4],%g1
+        srl %g1,4,%g1
+        set 0x00000100,%g5 /* SRMMU_CTXTBL_PTR */
+       sta %g1, [%g5] ASI_M_MMUREGS
+
+       /* Set up a sane %psr -- PIL<0xf> S<0x1> PS<0x1> CWP<0x0> */
+       set     (PSR_PIL | PSR_S | PSR_PS), %g1
+       wr      %g1, 0x0, %psr          ! traps off though
+       WRITE_PAUSE
+
+       /* Our %wim is one behind CWP */
+       mov     2, %g1
+       wr      %g1, 0x0, %wim
+       WRITE_PAUSE
+
+       /* Set tbr - we use just one trap table. */
+       set     trapbase, %g1
+       wr      %g1, 0x0, %tbr
+       WRITE_PAUSE
+
+       /* Get our CPU id */
+        rd     %asr17,%g3
+
+       /* Give ourselves a stack and curptr. */
+       set     current_set, %g5
+       srl     %g3, 28, %g4
+       sll     %g4, 2, %g4
+       ld      [%g5 + %g4], %g6
+
+       sethi   %hi(THREAD_SIZE - STACKFRAME_SZ), %sp
+       or      %sp, %lo(THREAD_SIZE - STACKFRAME_SZ), %sp
+       add     %g6, %sp, %sp
+
+       /* Turn on traps (PSR_ET). */
+       rd      %psr, %g1
+       wr      %g1, PSR_ET, %psr       ! traps on
+       WRITE_PAUSE
+
+       /* Init our caches, etc. */
+       set     poke_srmmu, %g5
+       ld      [%g5], %g5
+       call    %g5
+        nop
+
+       /* Start this processor. */
+       call    leon_callin
+        nop
+
+       b,a     smp_do_cpu_idle
+
+#endif
index 509b1ff..367321a 100644 (file)
@@ -1990,7 +1990,7 @@ void __init poke_leonsparc(void)
 void __init init_leon(void)
 {
 
-       srmmu_name = "Leon";
+       srmmu_name = "LEON";
 
        BTFIXUPSET_CALL(flush_cache_all, leon_flush_cache_all,
                        BTFIXUPCALL_NORM);
@@ -2037,8 +2037,6 @@ static void __init get_srmmu_type(void)
 
        /* First, check for sparc-leon. */
        if (sparc_cpu_model == sparc_leon) {
-               psr_typ = 0xf;  /* hardcoded ids for older models/simulators */
-               psr_vers = 2;
                init_leon();
                return;
        }
@@ -2301,7 +2299,8 @@ void __init ld_mmu_srmmu(void)
        BTFIXUPSET_CALL(flush_cache_mm, smp_flush_cache_mm, BTFIXUPCALL_NORM);
        BTFIXUPSET_CALL(flush_cache_range, smp_flush_cache_range, BTFIXUPCALL_NORM);
        BTFIXUPSET_CALL(flush_cache_page, smp_flush_cache_page, BTFIXUPCALL_NORM);
-       if (sparc_cpu_model != sun4d) {
+       if (sparc_cpu_model != sun4d &&
+           sparc_cpu_model != sparc_leon) {
                BTFIXUPSET_CALL(flush_tlb_all, smp_flush_tlb_all, BTFIXUPCALL_NORM);
                BTFIXUPSET_CALL(flush_tlb_mm, smp_flush_tlb_mm, BTFIXUPCALL_NORM);
                BTFIXUPSET_CALL(flush_tlb_range, smp_flush_tlb_range, BTFIXUPCALL_NORM);
@@ -2330,6 +2329,8 @@ void __init ld_mmu_srmmu(void)
 #ifdef CONFIG_SMP
        if (sparc_cpu_model == sun4d)
                sun4d_init_smp();
+       else if (sparc_cpu_model == sparc_leon)
+               leon_init_smp();
        else
                sun4m_init_smp();
 #endif
index 72ace95..1b2182b 100644 (file)
@@ -49,7 +49,9 @@ config X86
        select HAVE_KERNEL_GZIP
        select HAVE_KERNEL_BZIP2
        select HAVE_KERNEL_LZMA
+       select HAVE_HW_BREAKPOINT
        select HAVE_ARCH_KMEMCHECK
+       select HAVE_USER_RETURN_NOTIFIER
 
 config OUTPUT_FORMAT
        string
index 2649840..5e99762 100644 (file)
@@ -406,7 +406,7 @@ config X86_CMPXCHG64
 # generates cmov.
 config X86_CMOV
        def_bool y
-       depends on (MK8 || MK7 || MCORE2 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || MVIAC3_2 || MVIAC7 || MCRUSOE || MEFFICEON || X86_64 || MATOM)
+       depends on (MK8 || MK7 || MCORE2 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || MVIAC3_2 || MVIAC7 || MCRUSOE || MEFFICEON || X86_64 || MATOM || MGEODE_LX)
 
 config X86_MINIMUM_CPU_FAMILY
        int
index d105f29..731318e 100644 (file)
@@ -186,6 +186,15 @@ config X86_DS_SELFTEST
 config HAVE_MMIOTRACE_SUPPORT
        def_bool y
 
+config X86_DECODER_SELFTEST
+     bool "x86 instruction decoder selftest"
+     depends on DEBUG_KERNEL
+       ---help---
+        Perform x86 instruction decoder selftests at build time.
+        This option is useful for checking the sanity of x86 instruction
+        decoder code.
+        If unsure, say "N".
+
 #
 # IO delay types:
 #
@@ -287,4 +296,18 @@ config OPTIMIZE_INLINING
 
          If unsure, say N.
 
+config DEBUG_STRICT_USER_COPY_CHECKS
+       bool "Strict copy size checks"
+       depends on DEBUG_KERNEL && !TRACE_BRANCH_PROFILING
+       ---help---
+         Enabling this option turns a certain set of sanity checks for user
+         copy operations into compile time failures.
+
+         The copy_from_user() etc checks are there to help test if there
+         are sufficient security checks on the length argument of
+         the copy operation, by having gcc prove that the argument is
+         within bounds.
+
+         If unsure, or if you run an older (pre 4.4) gcc, say N.
+
 endmenu
index d2d24c9..78b32be 100644 (file)
@@ -155,6 +155,9 @@ all: bzImage
 KBUILD_IMAGE := $(boot)/bzImage
 
 bzImage: vmlinux
+ifeq ($(CONFIG_X86_DECODER_SELFTEST),y)
+       $(Q)$(MAKE) $(build)=arch/x86/tools posttest
+endif
        $(Q)$(MAKE) $(build)=$(boot) $(KBUILD_IMAGE)
        $(Q)mkdir -p $(objtree)/arch/$(UTS_MACHINE)/boot
        $(Q)ln -fsn ../../x86/boot/bzImage $(objtree)/arch/$(UTS_MACHINE)/boot/$@
index 30e9a26..cbf0776 100644 (file)
@@ -41,7 +41,7 @@ cflags-$(CONFIG_X86_ELAN)     += -march=i486
 
 # Geode GX1 support
 cflags-$(CONFIG_MGEODEGX1)     += -march=pentium-mmx
-
+cflags-$(CONFIG_MGEODE_LX)     += $(call cc-option,-march=geode,-march=pentium-mmx)
 # add at the end to overwrite eventual tuning options from earlier
 # cpu entries
 cflags-$(CONFIG_X86_GENERIC)   += $(call tune,generic,$(call tune,i686))
index d23b987..4eefdca 100644 (file)
@@ -653,7 +653,7 @@ ia32_sys_call_table:
        .quad compat_sys_writev
        .quad sys_getsid
        .quad sys_fdatasync
-       .quad sys32_sysctl      /* sysctl */
+       .quad compat_sys_sysctl /* sysctl */
        .quad sys_mlock         /* 150 */
        .quad sys_munlock
        .quad sys_mlockall
index 9f55271..df82c0e 100644 (file)
@@ -434,62 +434,6 @@ asmlinkage long sys32_rt_sigqueueinfo(int pid, int sig,
        return ret;
 }
 
-#ifdef CONFIG_SYSCTL_SYSCALL
-struct sysctl_ia32 {
-       unsigned int    name;
-       int             nlen;
-       unsigned int    oldval;
-       unsigned int    oldlenp;
-       unsigned int    newval;
-       unsigned int    newlen;
-       unsigned int    __unused[4];
-};
-
-
-asmlinkage long sys32_sysctl(struct sysctl_ia32 __user *args32)
-{
-       struct sysctl_ia32 a32;
-       mm_segment_t old_fs = get_fs();
-       void __user *oldvalp, *newvalp;
-       size_t oldlen;
-       int __user *namep;
-       long ret;
-
-       if (copy_from_user(&a32, args32, sizeof(a32)))
-               return -EFAULT;
-
-       /*
-        * We need to pre-validate these because we have to disable
-        * address checking before calling do_sysctl() because of
-        * OLDLEN but we can't run the risk of the user specifying bad
-        * addresses here.  Well, since we're dealing with 32 bit
-        * addresses, we KNOW that access_ok() will always succeed, so
-        * this is an expensive NOP, but so what...
-        */
-       namep = compat_ptr(a32.name);
-       oldvalp = compat_ptr(a32.oldval);
-       newvalp =  compat_ptr(a32.newval);
-
-       if ((oldvalp && get_user(oldlen, (int __user *)compat_ptr(a32.oldlenp)))
-           || !access_ok(VERIFY_WRITE, namep, 0)
-           || !access_ok(VERIFY_WRITE, oldvalp, 0)
-           || !access_ok(VERIFY_WRITE, newvalp, 0))
-               return -EFAULT;
-
-       set_fs(KERNEL_DS);
-       lock_kernel();
-       ret = do_sysctl(namep, a32.nlen, oldvalp, (size_t __user *)&oldlen,
-                       newvalp, (size_t) a32.newlen);
-       unlock_kernel();
-       set_fs(old_fs);
-
-       if (oldvalp && put_user(oldlen, (int __user *)compat_ptr(a32.oldlenp)))
-               return -EFAULT;
-
-       return ret;
-}
-#endif
-
 /* warning: next two assume little endian */
 asmlinkage long sys32_pread(unsigned int fd, char __user *ubuf, u32 count,
                            u32 poslo, u32 poshi)
index 4a8e80c..9f828f8 100644 (file)
@@ -10,6 +10,7 @@ header-y += ptrace-abi.h
 header-y += sigcontext32.h
 header-y += ucontext.h
 header-y += processor-flags.h
+header-y += hw_breakpoint.h
 
 unifdef-y += e820.h
 unifdef-y += ist.h
index bb70e39..7a15588 100644 (file)
@@ -17,6 +17,7 @@
 
 #include <linux/user.h>
 #include <linux/elfcore.h>
+#include <asm/debugreg.h>
 
 /*
  * fill in the user structure for an a.out core dump
@@ -32,14 +33,7 @@ static inline void aout_dump_thread(struct pt_regs *regs, struct user *dump)
                        >> PAGE_SHIFT;
        dump->u_dsize -= dump->u_tsize;
        dump->u_ssize = 0;
-       dump->u_debugreg[0] = current->thread.debugreg0;
-       dump->u_debugreg[1] = current->thread.debugreg1;
-       dump->u_debugreg[2] = current->thread.debugreg2;
-       dump->u_debugreg[3] = current->thread.debugreg3;
-       dump->u_debugreg[4] = 0;
-       dump->u_debugreg[5] = 0;
-       dump->u_debugreg[6] = current->thread.debugreg6;
-       dump->u_debugreg[7] = current->thread.debugreg7;
+       aout_dump_debugregs(dump);
 
        if (dump->start_stack < TASK_SIZE)
                dump->u_ssize = ((unsigned long)(TASK_SIZE - dump->start_stack))
index e2077d3..b97f786 100644 (file)
@@ -1,17 +1,13 @@
 #ifdef __ASSEMBLY__
 
-#ifdef CONFIG_X86_32
-# define X86_ALIGN .long
-#else
-# define X86_ALIGN .quad
-#endif
+#include <asm/asm.h>
 
 #ifdef CONFIG_SMP
        .macro LOCK_PREFIX
 1:     lock
        .section .smp_locks,"a"
-       .align 4
-       X86_ALIGN 1b
+       _ASM_ALIGN
+       _ASM_PTR 1b
        .previous
        .endm
 #else
index c240efc..69b74a7 100644 (file)
@@ -84,6 +84,7 @@ static inline void alternatives_smp_switch(int smp) {}
       "         .byte " __stringify(feature) "\n"      /* feature bit     */   \
       "         .byte 662b-661b\n"                     /* sourcelen       */   \
       "         .byte 664f-663f\n"                     /* replacementlen  */   \
+      "         .byte 0xff + (664f-663f) - (662b-661b)\n" /* rlen <= slen */   \
       ".previous\n"                                                    \
       ".section .altinstr_replacement, \"ax\"\n"                       \
       "663:\n\t" newinstr "\n664:\n"           /* replacement     */   \
index 474d80d..b4ac2cd 100644 (file)
@@ -297,20 +297,20 @@ struct apic {
        int disable_esr;
 
        int dest_logical;
-       unsigned long (*check_apicid_used)(physid_mask_t bitmap, int apicid);
+       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 (*init_apic_ldr)(void);
 
-       physid_mask_t (*ioapic_phys_id_map)(physid_mask_t map);
+       void (*ioapic_phys_id_map)(physid_mask_t *phys_map, physid_mask_t *retmap);
 
        void (*setup_apic_routing)(void);
        int (*multi_timer_check)(int apic, int irq);
        int (*apicid_to_node)(int logical_apicid);
        int (*cpu_to_logical_apicid)(int cpu);
        int (*cpu_present_to_apicid)(int mps_cpu);
-       physid_mask_t (*apicid_to_cpu_present)(int phys_apicid);
+       void (*apicid_to_cpu_present)(int phys_apicid, physid_mask_t *retmap);
        void (*setup_portio_remap)(void);
        int (*check_phys_apicid_present)(int phys_apicid);
        void (*enable_apic_mode)(void);
@@ -488,6 +488,8 @@ static inline unsigned int read_apic_id(void)
 
 extern void default_setup_apic_routing(void);
 
+extern struct apic apic_noop;
+
 #ifdef CONFIG_X86_32
 
 extern struct apic apic_default;
@@ -532,9 +534,9 @@ default_cpu_mask_to_apicid_and(const struct cpumask *cpumask,
        return (unsigned int)(mask1 & mask2 & mask3);
 }
 
-static inline unsigned long default_check_apicid_used(physid_mask_t bitmap, int apicid)
+static inline unsigned long default_check_apicid_used(physid_mask_t *map, int apicid)
 {
-       return physid_isset(apicid, bitmap);
+       return physid_isset(apicid, *map);
 }
 
 static inline unsigned long default_check_apicid_present(int bit)
@@ -542,9 +544,9 @@ static inline unsigned long default_check_apicid_present(int bit)
        return physid_isset(bit, phys_cpu_present_map);
 }
 
-static inline physid_mask_t default_ioapic_phys_id_map(physid_mask_t phys_map)
+static inline void default_ioapic_phys_id_map(physid_mask_t *phys_map, physid_mask_t *retmap)
 {
-       return phys_map;
+       *retmap = *phys_map;
 }
 
 /* Mapping from cpu number to logical apicid */
@@ -583,11 +585,6 @@ extern int default_cpu_present_to_apicid(int mps_cpu);
 extern int default_check_phys_apicid_present(int phys_apicid);
 #endif
 
-static inline physid_mask_t default_apicid_to_cpu_present(int phys_apicid)
-{
-       return physid_mask_of_physid(phys_apicid);
-}
-
 #endif /* CONFIG_X86_LOCAL_APIC */
 
 #ifdef CONFIG_X86_32
index 3b62da9..7fe3b30 100644 (file)
 #define IO_APIC_DEFAULT_PHYS_BASE      0xfec00000
 #define        APIC_DEFAULT_PHYS_BASE          0xfee00000
 
+/*
+ * This is the IO-APIC register space as specified
+ * by Intel docs:
+ */
+#define IO_APIC_SLOT_SIZE              1024
+
 #define        APIC_ID         0x20
 
 #define        APIC_LVR        0x30
diff --git a/arch/x86/include/asm/apicnum.h b/arch/x86/include/asm/apicnum.h
deleted file mode 100644 (file)
index 82f613c..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-#ifndef _ASM_X86_APICNUM_H
-#define _ASM_X86_APICNUM_H
-
-/* define MAX_IO_APICS */
-#ifdef CONFIG_X86_32
-# define MAX_IO_APICS 64
-#else
-# define MAX_IO_APICS 128
-# define MAX_LOCAL_APIC 32768
-#endif
-
-#endif /* _ASM_X86_APICNUM_H */
index b54f6af..9076add 100644 (file)
@@ -12,6 +12,7 @@ static inline void flush_cache_range(struct vm_area_struct *vma,
                                     unsigned long start, unsigned long end) { }
 static inline void flush_cache_page(struct vm_area_struct *vma,
                                    unsigned long vmaddr, unsigned long pfn) { }
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 0
 static inline void flush_dcache_page(struct page *page) { }
 static inline void flush_dcache_mmap_lock(struct address_space *mapping) { }
 static inline void flush_dcache_mmap_unlock(struct address_space *mapping) { }
index ee1931b..ffb9bb6 100644 (file)
@@ -8,14 +8,50 @@
  *       you need to test for the feature in boot_cpu_data.
  */
 
-#define xchg(ptr, v)                                                   \
-       ((__typeof__(*(ptr)))__xchg((unsigned long)(v), (ptr), sizeof(*(ptr))))
+extern void __xchg_wrong_size(void);
+
+/*
+ * Note: no "lock" prefix even on SMP: xchg always implies lock anyway
+ * Note 2: xchg has side effect, so that attribute volatile is necessary,
+ *       but generally the primitive is invalid, *ptr is output argument. --ANK
+ */
 
 struct __xchg_dummy {
        unsigned long a[100];
 };
 #define __xg(x) ((struct __xchg_dummy *)(x))
 
+#define __xchg(x, ptr, size)                                           \
+({                                                                     \
+       __typeof(*(ptr)) __x = (x);                                     \
+       switch (size) {                                                 \
+       case 1:                                                         \
+               asm volatile("xchgb %b0,%1"                             \
+                            : "=q" (__x)                               \
+                            : "m" (*__xg(ptr)), "0" (__x)              \
+                            : "memory");                               \
+               break;                                                  \
+       case 2:                                                         \
+               asm volatile("xchgw %w0,%1"                             \
+                            : "=r" (__x)                               \
+                            : "m" (*__xg(ptr)), "0" (__x)              \
+                            : "memory");                               \
+               break;                                                  \
+       case 4:                                                         \
+               asm volatile("xchgl %0,%1"                              \
+                            : "=r" (__x)                               \
+                            : "m" (*__xg(ptr)), "0" (__x)              \
+                            : "memory");                               \
+               break;                                                  \
+       default:                                                        \
+               __xchg_wrong_size();                                    \
+       }                                                               \
+       __x;                                                            \
+})
+
+#define xchg(ptr, v)                                                   \
+       __xchg((v), (ptr), sizeof(*ptr))
+
 /*
  * The semantics of XCHGCMP8B are a bit strange, this is why
  * there is a loop and the loading of %%eax and %%edx has to
@@ -71,57 +107,63 @@ static inline void __set_64bit_var(unsigned long long *ptr,
                       (unsigned int)((value) >> 32))                   \
         : __set_64bit(ptr, ll_low((value)), ll_high((value))))
 
-/*
- * Note: no "lock" prefix even on SMP: xchg always implies lock anyway
- * Note 2: xchg has side effect, so that attribute volatile is necessary,
- *       but generally the primitive is invalid, *ptr is output argument. --ANK
- */
-static inline unsigned long __xchg(unsigned long x, volatile void *ptr,
-                                  int size)
-{
-       switch (size) {
-       case 1:
-               asm volatile("xchgb %b0,%1"
-                            : "=q" (x)
-                            : "m" (*__xg(ptr)), "0" (x)
-                            : "memory");
-               break;
-       case 2:
-               asm volatile("xchgw %w0,%1"
-                            : "=r" (x)
-                            : "m" (*__xg(ptr)), "0" (x)
-                            : "memory");
-               break;
-       case 4:
-               asm volatile("xchgl %0,%1"
-                            : "=r" (x)
-                            : "m" (*__xg(ptr)), "0" (x)
-                            : "memory");
-               break;
-       }
-       return x;
-}
+extern void __cmpxchg_wrong_size(void);
 
 /*
  * Atomic compare and exchange.  Compare OLD with MEM, if identical,
  * store NEW in MEM.  Return the initial value in MEM.  Success is
  * indicated by comparing RETURN with OLD.
  */
+#define __raw_cmpxchg(ptr, old, new, size, lock)                       \
+({                                                                     \
+       __typeof__(*(ptr)) __ret;                                       \
+       __typeof__(*(ptr)) __old = (old);                               \
+       __typeof__(*(ptr)) __new = (new);                               \
+       switch (size) {                                                 \
+       case 1:                                                         \
+               asm volatile(lock "cmpxchgb %b1,%2"                     \
+                            : "=a"(__ret)                              \
+                            : "q"(__new), "m"(*__xg(ptr)), "0"(__old)  \
+                            : "memory");                               \
+               break;                                                  \
+       case 2:                                                         \
+               asm volatile(lock "cmpxchgw %w1,%2"                     \
+                            : "=a"(__ret)                              \
+                            : "r"(__new), "m"(*__xg(ptr)), "0"(__old)  \
+                            : "memory");                               \
+               break;                                                  \
+       case 4:                                                         \
+               asm volatile(lock "cmpxchgl %1,%2"                      \
+                            : "=a"(__ret)                              \
+                            : "r"(__new), "m"(*__xg(ptr)), "0"(__old)  \
+                            : "memory");                               \
+               break;                                                  \
+       default:                                                        \
+               __cmpxchg_wrong_size();                                 \
+       }                                                               \
+       __ret;                                                          \
+})
+
+#define __cmpxchg(ptr, old, new, size)                                 \
+       __raw_cmpxchg((ptr), (old), (new), (size), LOCK_PREFIX)
+
+#define __sync_cmpxchg(ptr, old, new, size)                            \
+       __raw_cmpxchg((ptr), (old), (new), (size), "lock; ")
+
+#define __cmpxchg_local(ptr, old, new, size)                           \
+       __raw_cmpxchg((ptr), (old), (new), (size), "")
 
 #ifdef CONFIG_X86_CMPXCHG
 #define __HAVE_ARCH_CMPXCHG 1
-#define cmpxchg(ptr, o, n)                                             \
-       ((__typeof__(*(ptr)))__cmpxchg((ptr), (unsigned long)(o),       \
-                                      (unsigned long)(n),              \
-                                      sizeof(*(ptr))))
-#define sync_cmpxchg(ptr, o, n)                                                \
-       ((__typeof__(*(ptr)))__sync_cmpxchg((ptr), (unsigned long)(o),  \
-                                           (unsigned long)(n),         \
-                                           sizeof(*(ptr))))
-#define cmpxchg_local(ptr, o, n)                                       \
-       ((__typeof__(*(ptr)))__cmpxchg_local((ptr), (unsigned long)(o), \
-                                            (unsigned long)(n),        \
-                                            sizeof(*(ptr))))
+
+#define cmpxchg(ptr, old, new)                                         \
+       __cmpxchg((ptr), (old), (new), sizeof(*ptr))
+
+#define sync_cmpxchg(ptr, old, new)                                    \
+       __sync_cmpxchg((ptr), (old), (new), sizeof(*ptr))
+
+#define cmpxchg_local(ptr, old, new)                                   \
+       __cmpxchg_local((ptr), (old), (new), sizeof(*ptr))
 #endif
 
 #ifdef CONFIG_X86_CMPXCHG64
@@ -133,94 +175,6 @@ static inline unsigned long __xchg(unsigned long x, volatile void *ptr,
                                               (unsigned long long)(n)))
 #endif
 
-static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
-                                     unsigned long new, int size)
-{
-       unsigned long prev;
-       switch (size) {
-       case 1:
-               asm volatile(LOCK_PREFIX "cmpxchgb %b1,%2"
-                            : "=a"(prev)
-                            : "q"(new), "m"(*__xg(ptr)), "0"(old)
-                            : "memory");
-               return prev;
-       case 2:
-               asm volatile(LOCK_PREFIX "cmpxchgw %w1,%2"
-                            : "=a"(prev)
-                            : "r"(new), "m"(*__xg(ptr)), "0"(old)
-                            : "memory");
-               return prev;
-       case 4:
-               asm volatile(LOCK_PREFIX "cmpxchgl %1,%2"
-                            : "=a"(prev)
-                            : "r"(new), "m"(*__xg(ptr)), "0"(old)
-                            : "memory");
-               return prev;
-       }
-       return old;
-}
-
-/*
- * Always use locked operations when touching memory shared with a
- * hypervisor, since the system may be SMP even if the guest kernel
- * isn't.
- */
-static inline unsigned long __sync_cmpxchg(volatile void *ptr,
-                                          unsigned long old,
-                                          unsigned long new, int size)
-{
-       unsigned long prev;
-       switch (size) {
-       case 1:
-               asm volatile("lock; cmpxchgb %b1,%2"
-                            : "=a"(prev)
-                            : "q"(new), "m"(*__xg(ptr)), "0"(old)
-                            : "memory");
-               return prev;
-       case 2:
-               asm volatile("lock; cmpxchgw %w1,%2"
-                            : "=a"(prev)
-                            : "r"(new), "m"(*__xg(ptr)), "0"(old)
-                            : "memory");
-               return prev;
-       case 4:
-               asm volatile("lock; cmpxchgl %1,%2"
-                            : "=a"(prev)
-                            : "r"(new), "m"(*__xg(ptr)), "0"(old)
-                            : "memory");
-               return prev;
-       }
-       return old;
-}
-
-static inline unsigned long __cmpxchg_local(volatile void *ptr,
-                                           unsigned long old,
-                                           unsigned long new, int size)
-{
-       unsigned long prev;
-       switch (size) {
-       case 1:
-               asm volatile("cmpxchgb %b1,%2"
-                            : "=a"(prev)
-                            : "q"(new), "m"(*__xg(ptr)), "0"(old)
-                            : "memory");
-               return prev;
-       case 2:
-               asm volatile("cmpxchgw %w1,%2"
-                            : "=a"(prev)
-                            : "r"(new), "m"(*__xg(ptr)), "0"(old)
-                            : "memory");
-               return prev;
-       case 4:
-               asm volatile("cmpxchgl %1,%2"
-                            : "=a"(prev)
-                            : "r"(new), "m"(*__xg(ptr)), "0"(old)
-                            : "memory");
-               return prev;
-       }
-       return old;
-}
-
 static inline unsigned long long __cmpxchg64(volatile void *ptr,
                                             unsigned long long old,
                                             unsigned long long new)
index 52de72e..485ae41 100644 (file)
@@ -3,9 +3,6 @@
 
 #include <asm/alternative.h> /* Provides LOCK_PREFIX */
 
-#define xchg(ptr, v) ((__typeof__(*(ptr)))__xchg((unsigned long)(v), \
-                                                (ptr), sizeof(*(ptr))))
-
 #define __xg(x) ((volatile long *)(x))
 
 static inline void set_64bit(volatile unsigned long *ptr, unsigned long val)
@@ -15,167 +12,118 @@ static inline void set_64bit(volatile unsigned long *ptr, unsigned long val)
 
 #define _set_64bit set_64bit
 
+extern void __xchg_wrong_size(void);
+extern void __cmpxchg_wrong_size(void);
+
 /*
  * Note: no "lock" prefix even on SMP: xchg always implies lock anyway
  * Note 2: xchg has side effect, so that attribute volatile is necessary,
  *       but generally the primitive is invalid, *ptr is output argument. --ANK
  */
-static inline unsigned long __xchg(unsigned long x, volatile void *ptr,
-                                  int size)
-{
-       switch (size) {
-       case 1:
-               asm volatile("xchgb %b0,%1"
-                            : "=q" (x)
-                            : "m" (*__xg(ptr)), "0" (x)
-                            : "memory");
-               break;
-       case 2:
-               asm volatile("xchgw %w0,%1"
-                            : "=r" (x)
-                            : "m" (*__xg(ptr)), "0" (x)
-                            : "memory");
-               break;
-       case 4:
-               asm volatile("xchgl %k0,%1"
-                            : "=r" (x)
-                            : "m" (*__xg(ptr)), "0" (x)
-                            : "memory");
-               break;
-       case 8:
-               asm volatile("xchgq %0,%1"
-                            : "=r" (x)
-                            : "m" (*__xg(ptr)), "0" (x)
-                            : "memory");
-               break;
-       }
-       return x;
-}
+#define __xchg(x, ptr, size)                                           \
+({                                                                     \
+       __typeof(*(ptr)) __x = (x);                                     \
+       switch (size) {                                                 \
+       case 1:                                                         \
+               asm volatile("xchgb %b0,%1"                             \
+                            : "=q" (__x)                               \
+                            : "m" (*__xg(ptr)), "0" (__x)              \
+                            : "memory");                               \
+               break;                                                  \
+       case 2:                                                         \
+               asm volatile("xchgw %w0,%1"                             \
+                            : "=r" (__x)                               \
+                            : "m" (*__xg(ptr)), "0" (__x)              \
+                            : "memory");                               \
+               break;                                                  \
+       case 4:                                                         \
+               asm volatile("xchgl %k0,%1"                             \
+                            : "=r" (__x)                               \
+                            : "m" (*__xg(ptr)), "0" (__x)              \
+                            : "memory");                               \
+               break;                                                  \
+       case 8:                                                         \
+               asm volatile("xchgq %0,%1"                              \
+                            : "=r" (__x)                               \
+                            : "m" (*__xg(ptr)), "0" (__x)              \
+                            : "memory");                               \
+               break;                                                  \
+       default:                                                        \
+               __xchg_wrong_size();                                    \
+       }                                                               \
+       __x;                                                            \
+})
+
+#define xchg(ptr, v)                                                   \
+       __xchg((v), (ptr), sizeof(*ptr))
+
+#define __HAVE_ARCH_CMPXCHG 1
 
 /*
  * Atomic compare and exchange.  Compare OLD with MEM, if identical,
  * store NEW in MEM.  Return the initial value in MEM.  Success is
  * indicated by comparing RETURN with OLD.
  */
+#define __raw_cmpxchg(ptr, old, new, size, lock)                       \
+({                                                                     \
+       __typeof__(*(ptr)) __ret;                                       \
+       __typeof__(*(ptr)) __old = (old);                               \
+       __typeof__(*(ptr)) __new = (new);                               \
+       switch (size) {                                                 \
+       case 1:                                                         \
+               asm volatile(lock "cmpxchgb %b1,%2"                     \
+                            : "=a"(__ret)                              \
+                            : "q"(__new), "m"(*__xg(ptr)), "0"(__old)  \
+                            : "memory");                               \
+               break;                                                  \
+       case 2:                                                         \
+               asm volatile(lock "cmpxchgw %w1,%2"                     \
+                            : "=a"(__ret)                              \
+                            : "r"(__new), "m"(*__xg(ptr)), "0"(__old)  \
+                            : "memory");                               \
+               break;                                                  \
+       case 4:                                                         \
+               asm volatile(lock "cmpxchgl %k1,%2"                     \
+                            : "=a"(__ret)                              \
+                            : "r"(__new), "m"(*__xg(ptr)), "0"(__old)  \
+                            : "memory");                               \
+               break;                                                  \
+       case 8:                                                         \
+               asm volatile(lock "cmpxchgq %1,%2"                      \
+                            : "=a"(__ret)                              \
+                            : "r"(__new), "m"(*__xg(ptr)), "0"(__old)  \
+                            : "memory");                               \
+               break;                                                  \
+       default:                                                        \
+               __cmpxchg_wrong_size();                                 \
+       }                                                               \
+       __ret;                                                          \
+})
 
-#define __HAVE_ARCH_CMPXCHG 1
+#define __cmpxchg(ptr, old, new, size)                                 \
+       __raw_cmpxchg((ptr), (old), (new), (size), LOCK_PREFIX)
 
-static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
-                                     unsigned long new, int size)
-{
-       unsigned long prev;
-       switch (size) {
-       case 1:
-               asm volatile(LOCK_PREFIX "cmpxchgb %b1,%2"
-                            : "=a"(prev)
-                            : "q"(new), "m"(*__xg(ptr)), "0"(old)
-                            : "memory");
-               return prev;
-       case 2:
-               asm volatile(LOCK_PREFIX "cmpxchgw %w1,%2"
-                            : "=a"(prev)
-                            : "r"(new), "m"(*__xg(ptr)), "0"(old)
-                            : "memory");
-               return prev;
-       case 4:
-               asm volatile(LOCK_PREFIX "cmpxchgl %k1,%2"
-                            : "=a"(prev)
-                            : "r"(new), "m"(*__xg(ptr)), "0"(old)
-                            : "memory");
-               return prev;
-       case 8:
-               asm volatile(LOCK_PREFIX "cmpxchgq %1,%2"
-                            : "=a"(prev)
-                            : "r"(new), "m"(*__xg(ptr)), "0"(old)
-                            : "memory");
-               return prev;
-       }
-       return old;
-}
+#define __sync_cmpxchg(ptr, old, new, size)                            \
+       __raw_cmpxchg((ptr), (old), (new), (size), "lock; ")
 
-/*
- * Always use locked operations when touching memory shared with a
- * hypervisor, since the system may be SMP even if the guest kernel
- * isn't.
- */
-static inline unsigned long __sync_cmpxchg(volatile void *ptr,
-                                          unsigned long old,
-                                          unsigned long new, int size)
-{
-       unsigned long prev;
-       switch (size) {
-       case 1:
-               asm volatile("lock; cmpxchgb %b1,%2"
-                            : "=a"(prev)
-                            : "q"(new), "m"(*__xg(ptr)), "0"(old)
-                            : "memory");
-               return prev;
-       case 2:
-               asm volatile("lock; cmpxchgw %w1,%2"
-                            : "=a"(prev)
-                            : "r"(new), "m"(*__xg(ptr)), "0"(old)
-                            : "memory");
-               return prev;
-       case 4:
-               asm volatile("lock; cmpxchgl %1,%2"
-                            : "=a"(prev)
-                            : "r"(new), "m"(*__xg(ptr)), "0"(old)
-                            : "memory");
-               return prev;
-       }
-       return old;
-}
+#define __cmpxchg_local(ptr, old, new, size)                           \
+       __raw_cmpxchg((ptr), (old), (new), (size), "")
 
-static inline unsigned long __cmpxchg_local(volatile void *ptr,
-                                           unsigned long old,
-                                           unsigned long new, int size)
-{
-       unsigned long prev;
-       switch (size) {
-       case 1:
-               asm volatile("cmpxchgb %b1,%2"
-                            : "=a"(prev)
-                            : "q"(new), "m"(*__xg(ptr)), "0"(old)
-                            : "memory");
-               return prev;
-       case 2:
-               asm volatile("cmpxchgw %w1,%2"
-                            : "=a"(prev)
-                            : "r"(new), "m"(*__xg(ptr)), "0"(old)
-                            : "memory");
-               return prev;
-       case 4:
-               asm volatile("cmpxchgl %k1,%2"
-                            : "=a"(prev)
-                            : "r"(new), "m"(*__xg(ptr)), "0"(old)
-                            : "memory");
-               return prev;
-       case 8:
-               asm volatile("cmpxchgq %1,%2"
-                            : "=a"(prev)
-                            : "r"(new), "m"(*__xg(ptr)), "0"(old)
-                            : "memory");
-               return prev;
-       }
-       return old;
-}
+#define cmpxchg(ptr, old, new)                                         \
+       __cmpxchg((ptr), (old), (new), sizeof(*ptr))
+
+#define sync_cmpxchg(ptr, old, new)                                    \
+       __sync_cmpxchg((ptr), (old), (new), sizeof(*ptr))
+
+#define cmpxchg_local(ptr, old, new)                                   \
+       __cmpxchg_local((ptr), (old), (new), sizeof(*ptr))
 
-#define cmpxchg(ptr, o, n)                                             \
-       ((__typeof__(*(ptr)))__cmpxchg((ptr), (unsigned long)(o),       \
-                                      (unsigned long)(n), sizeof(*(ptr))))
 #define cmpxchg64(ptr, o, n)                                           \
 ({                                                                     \
        BUILD_BUG_ON(sizeof(*(ptr)) != 8);                              \
        cmpxchg((ptr), (o), (n));                                       \
 })
-#define cmpxchg_local(ptr, o, n)                                       \
-       ((__typeof__(*(ptr)))__cmpxchg_local((ptr), (unsigned long)(o), \
-                                            (unsigned long)(n),        \
-                                            sizeof(*(ptr))))
-#define sync_cmpxchg(ptr, o, n)                                                \
-       ((__typeof__(*(ptr)))__sync_cmpxchg((ptr), (unsigned long)(o),  \
-                                           (unsigned long)(n),         \
-                                           sizeof(*(ptr))))
+
 #define cmpxchg64_local(ptr, o, n)                                     \
 ({                                                                     \
        BUILD_BUG_ON(sizeof(*(ptr)) != 8);                              \
index 3ea6f37..8240f76 100644 (file)
@@ -18,6 +18,7 @@
 #define DR_TRAP1       (0x2)           /* db1 */
 #define DR_TRAP2       (0x4)           /* db2 */
 #define DR_TRAP3       (0x8)           /* db3 */
+#define DR_TRAP_BITS   (DR_TRAP0|DR_TRAP1|DR_TRAP2|DR_TRAP3)
 
 #define DR_STEP                (0x4000)        /* single-step */
 #define DR_SWITCH      (0x8000)        /* task switch */
@@ -49,6 +50,8 @@
 
 #define DR_LOCAL_ENABLE_SHIFT 0    /* Extra shift to the local enable bit */
 #define DR_GLOBAL_ENABLE_SHIFT 1   /* Extra shift to the global enable bit */
+#define DR_LOCAL_ENABLE (0x1)      /* Local enable for reg 0 */
+#define DR_GLOBAL_ENABLE (0x2)     /* Global enable for reg 0 */
 #define DR_ENABLE_SIZE 2           /* 2 enable bits per register */
 
 #define DR_LOCAL_ENABLE_MASK (0x55)  /* Set  local bits for all 4 regs */
 #define DR_LOCAL_SLOWDOWN (0x100)   /* Local slow the pipeline */
 #define DR_GLOBAL_SLOWDOWN (0x200)  /* Global slow the pipeline */
 
+/*
+ * HW breakpoint additions
+ */
+#ifdef __KERNEL__
+
+DECLARE_PER_CPU(unsigned long, cpu_dr7);
+
+static inline void hw_breakpoint_disable(void)
+{
+       /* Zero the control register for HW Breakpoint */
+       set_debugreg(0UL, 7);
+
+       /* Zero-out the individual HW breakpoint address registers */
+       set_debugreg(0UL, 0);
+       set_debugreg(0UL, 1);
+       set_debugreg(0UL, 2);
+       set_debugreg(0UL, 3);
+}
+
+static inline int hw_breakpoint_active(void)
+{
+       return __get_cpu_var(cpu_dr7) & DR_GLOBAL_ENABLE_MASK;
+}
+
+extern void aout_dump_debugregs(struct user *dump);
+
+extern void hw_breakpoint_restore(void);
+
+#endif /* __KERNEL__ */
+
 #endif /* _ASM_X86_DEBUGREG_H */
index 82e3e8f..108eb6f 100644 (file)
@@ -20,11 +20,11 @@ typedef struct {
        unsigned int irq_call_count;
        unsigned int irq_tlb_count;
 #endif
-#ifdef CONFIG_X86_MCE
+#ifdef CONFIG_X86_THERMAL_VECTOR
        unsigned int irq_thermal_count;
-# ifdef CONFIG_X86_MCE_THRESHOLD
+#endif
+#ifdef CONFIG_X86_MCE_THRESHOLD
        unsigned int irq_threshold_count;
-# endif
 #endif
 } ____cacheline_aligned irq_cpustat_t;
 
diff --git a/arch/x86/include/asm/hw_breakpoint.h b/arch/x86/include/asm/hw_breakpoint.h
new file mode 100644 (file)
index 0000000..0675a7c
--- /dev/null
@@ -0,0 +1,73 @@
+#ifndef        _I386_HW_BREAKPOINT_H
+#define        _I386_HW_BREAKPOINT_H
+
+#ifdef __KERNEL__
+#define        __ARCH_HW_BREAKPOINT_H
+
+/*
+ * The name should probably be something dealt in
+ * a higher level. While dealing with the user
+ * (display/resolving)
+ */
+struct arch_hw_breakpoint {
+       char            *name; /* Contains name of the symbol to set bkpt */
+       unsigned long   address;
+       u8              len;
+       u8              type;
+};
+
+#include <linux/kdebug.h>
+#include <linux/percpu.h>
+#include <linux/list.h>
+
+/* Available HW breakpoint length encodings */
+#define X86_BREAKPOINT_LEN_1           0x40
+#define X86_BREAKPOINT_LEN_2           0x44
+#define X86_BREAKPOINT_LEN_4           0x4c
+#define X86_BREAKPOINT_LEN_EXECUTE     0x40
+
+#ifdef CONFIG_X86_64
+#define X86_BREAKPOINT_LEN_8           0x48
+#endif
+
+/* Available HW breakpoint type encodings */
+
+/* trigger on instruction execute */
+#define X86_BREAKPOINT_EXECUTE 0x80
+/* trigger on memory write */
+#define X86_BREAKPOINT_WRITE   0x81
+/* trigger on memory read or write */
+#define X86_BREAKPOINT_RW      0x83
+
+/* Total number of available HW breakpoint registers */
+#define HBP_NUM 4
+
+struct perf_event;
+struct pmu;
+
+extern int arch_check_va_in_userspace(unsigned long va, u8 hbp_len);
+extern int arch_validate_hwbkpt_settings(struct perf_event *bp,
+                                        struct task_struct *tsk);
+extern int hw_breakpoint_exceptions_notify(struct notifier_block *unused,
+                                          unsigned long val, void *data);
+
+
+int arch_install_hw_breakpoint(struct perf_event *bp);
+void arch_uninstall_hw_breakpoint(struct perf_event *bp);
+void hw_breakpoint_pmu_read(struct perf_event *bp);
+void hw_breakpoint_pmu_unthrottle(struct perf_event *bp);
+
+extern void
+arch_fill_perf_breakpoint(struct perf_event *bp);
+
+unsigned long encode_dr7(int drnum, unsigned int len, unsigned int type);
+int decode_dr7(unsigned long dr7, int bpnum, unsigned *len, unsigned *type);
+
+extern int arch_bp_generic_fields(int x86_len, int x86_type,
+                                 int *gen_len, int *gen_type);
+
+extern struct pmu perf_ops_bp;
+
+#endif /* __KERNEL__ */
+#endif /* _I386_HW_BREAKPOINT_H */
+
index ba180d9..6e12426 100644 (file)
@@ -79,14 +79,32 @@ static inline void set_io_apic_irq_attr(struct io_apic_irq_attr *irq_attr,
                                        int ioapic, int ioapic_pin,
                                        int trigger, int polarity)
 {
-       irq_attr->ioapic     = ioapic;
-       irq_attr->ioapic_pin = ioapic_pin;
-       irq_attr->trigger    = trigger;
-       irq_attr->polarity   = polarity;
+       irq_attr->ioapic        = ioapic;
+       irq_attr->ioapic_pin    = ioapic_pin;
+       irq_attr->trigger       = trigger;
+       irq_attr->polarity      = polarity;
 }
 
-extern int IO_APIC_get_PCI_irq_vector(int bus, int devfn, int pin,
-                                       struct io_apic_irq_attr *irq_attr);
+/*
+ * This is performance-critical, we want to do it O(1)
+ *
+ * Most irqs are mapped 1:1 with pins.
+ */
+struct irq_cfg {
+       struct irq_pin_list     *irq_2_pin;
+       cpumask_var_t           domain;
+       cpumask_var_t           old_domain;
+       u8                      vector;
+       u8                      move_in_progress : 1;
+};
+
+extern struct irq_cfg *irq_cfg(unsigned int);
+extern int assign_irq_vector(int, struct irq_cfg *, const struct cpumask *);
+extern void send_cleanup_vector(struct irq_cfg *);
+
+struct irq_desc;
+extern unsigned int set_desc_affinity(struct irq_desc *, const struct cpumask *);
+extern int IO_APIC_get_PCI_irq_vector(int bus, int devfn, int pin, struct io_apic_irq_attr *irq_attr);
 extern void setup_ioapic_dest(void);
 
 extern void enable_IO_APIC(void);
diff --git a/arch/x86/include/asm/inat.h b/arch/x86/include/asm/inat.h
new file mode 100644 (file)
index 0000000..205b063
--- /dev/null
@@ -0,0 +1,220 @@
+#ifndef _ASM_X86_INAT_H
+#define _ASM_X86_INAT_H
+/*
+ * x86 instruction attributes
+ *
+ * Written by Masami Hiramatsu <mhiramat@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 <asm/inat_types.h>
+
+/*
+ * Internal bits. Don't use bitmasks directly, because these bits are
+ * unstable. You should use checking functions.
+ */
+
+#define INAT_OPCODE_TABLE_SIZE 256
+#define INAT_GROUP_TABLE_SIZE 8
+
+/* Legacy last prefixes */
+#define INAT_PFX_OPNDSZ        1       /* 0x66 */ /* LPFX1 */
+#define INAT_PFX_REPE  2       /* 0xF3 */ /* LPFX2 */
+#define INAT_PFX_REPNE 3       /* 0xF2 */ /* LPFX3 */
+/* Other Legacy prefixes */
+#define INAT_PFX_LOCK  4       /* 0xF0 */
+#define INAT_PFX_CS    5       /* 0x2E */
+#define INAT_PFX_DS    6       /* 0x3E */
+#define INAT_PFX_ES    7       /* 0x26 */
+#define INAT_PFX_FS    8       /* 0x64 */
+#define INAT_PFX_GS    9       /* 0x65 */
+#define INAT_PFX_SS    10      /* 0x36 */
+#define INAT_PFX_ADDRSZ        11      /* 0x67 */
+/* x86-64 REX prefix */
+#define INAT_PFX_REX   12      /* 0x4X */
+/* AVX VEX prefixes */
+#define INAT_PFX_VEX2  13      /* 2-bytes VEX prefix */
+#define INAT_PFX_VEX3  14      /* 3-bytes VEX prefix */
+
+#define INAT_LSTPFX_MAX        3
+#define INAT_LGCPFX_MAX        11
+
+/* Immediate size */
+#define INAT_IMM_BYTE          1
+#define INAT_IMM_WORD          2
+#define INAT_IMM_DWORD         3
+#define INAT_IMM_QWORD         4
+#define INAT_IMM_PTR           5
+#define INAT_IMM_VWORD32       6
+#define INAT_IMM_VWORD         7
+
+/* Legacy prefix */
+#define INAT_PFX_OFFS  0
+#define INAT_PFX_BITS  4
+#define INAT_PFX_MAX    ((1 << INAT_PFX_BITS) - 1)
+#define INAT_PFX_MASK  (INAT_PFX_MAX << INAT_PFX_OFFS)
+/* Escape opcodes */
+#define INAT_ESC_OFFS  (INAT_PFX_OFFS + INAT_PFX_BITS)
+#define INAT_ESC_BITS  2
+#define INAT_ESC_MAX   ((1 << INAT_ESC_BITS) - 1)
+#define INAT_ESC_MASK  (INAT_ESC_MAX << INAT_ESC_OFFS)
+/* Group opcodes (1-16) */
+#define INAT_GRP_OFFS  (INAT_ESC_OFFS + INAT_ESC_BITS)
+#define INAT_GRP_BITS  5
+#define INAT_GRP_MAX   ((1 << INAT_GRP_BITS) - 1)
+#define INAT_GRP_MASK  (INAT_GRP_MAX << INAT_GRP_OFFS)
+/* Immediates */
+#define INAT_IMM_OFFS  (INAT_GRP_OFFS + INAT_GRP_BITS)
+#define INAT_IMM_BITS  3
+#define INAT_IMM_MASK  (((1 << INAT_IMM_BITS) - 1) << INAT_IMM_OFFS)
+/* Flags */
+#define INAT_FLAG_OFFS (INAT_IMM_OFFS + INAT_IMM_BITS)
+#define INAT_MODRM     (1 << (INAT_FLAG_OFFS))
+#define INAT_FORCE64   (1 << (INAT_FLAG_OFFS + 1))
+#define INAT_SCNDIMM   (1 << (INAT_FLAG_OFFS + 2))
+#define INAT_MOFFSET   (1 << (INAT_FLAG_OFFS + 3))
+#define INAT_VARIANT   (1 << (INAT_FLAG_OFFS + 4))
+#define INAT_VEXOK     (1 << (INAT_FLAG_OFFS + 5))
+#define INAT_VEXONLY   (1 << (INAT_FLAG_OFFS + 6))
+/* Attribute making macros for attribute tables */
+#define INAT_MAKE_PREFIX(pfx)  (pfx << INAT_PFX_OFFS)
+#define INAT_MAKE_ESCAPE(esc)  (esc << INAT_ESC_OFFS)
+#define INAT_MAKE_GROUP(grp)   ((grp << INAT_GRP_OFFS) | INAT_MODRM)
+#define INAT_MAKE_IMM(imm)     (imm << INAT_IMM_OFFS)
+
+/* Attribute search APIs */
+extern insn_attr_t inat_get_opcode_attribute(insn_byte_t opcode);
+extern insn_attr_t inat_get_escape_attribute(insn_byte_t opcode,
+                                            insn_byte_t last_pfx,
+                                            insn_attr_t esc_attr);
+extern insn_attr_t inat_get_group_attribute(insn_byte_t modrm,
+                                           insn_byte_t last_pfx,
+                                           insn_attr_t esc_attr);
+extern insn_attr_t inat_get_avx_attribute(insn_byte_t opcode,
+                                         insn_byte_t vex_m,
+                                         insn_byte_t vex_pp);
+
+/* Attribute checking functions */
+static inline int inat_is_legacy_prefix(insn_attr_t attr)
+{
+       attr &= INAT_PFX_MASK;
+       return attr && attr <= INAT_LGCPFX_MAX;
+}
+
+static inline int inat_is_address_size_prefix(insn_attr_t attr)
+{
+       return (attr & INAT_PFX_MASK) == INAT_PFX_ADDRSZ;
+}
+
+static inline int inat_is_operand_size_prefix(insn_attr_t attr)
+{
+       return (attr & INAT_PFX_MASK) == INAT_PFX_OPNDSZ;
+}
+
+static inline int inat_is_rex_prefix(insn_attr_t attr)
+{
+       return (attr & INAT_PFX_MASK) == INAT_PFX_REX;
+}
+
+static inline int inat_last_prefix_id(insn_attr_t attr)
+{
+       if ((attr & INAT_PFX_MASK) > INAT_LSTPFX_MAX)
+               return 0;
+       else
+               return attr & INAT_PFX_MASK;
+}
+
+static inline int inat_is_vex_prefix(insn_attr_t attr)
+{
+       attr &= INAT_PFX_MASK;
+       return attr == INAT_PFX_VEX2 || attr == INAT_PFX_VEX3;
+}
+
+static inline int inat_is_vex3_prefix(insn_attr_t attr)
+{
+       return (attr & INAT_PFX_MASK) == INAT_PFX_VEX3;
+}
+
+static inline int inat_is_escape(insn_attr_t attr)
+{
+       return attr & INAT_ESC_MASK;
+}
+
+static inline int inat_escape_id(insn_attr_t attr)
+{
+       return (attr & INAT_ESC_MASK) >> INAT_ESC_OFFS;
+}
+
+static inline int inat_is_group(insn_attr_t attr)
+{
+       return attr & INAT_GRP_MASK;
+}
+
+static inline int inat_group_id(insn_attr_t attr)
+{
+       return (attr & INAT_GRP_MASK) >> INAT_GRP_OFFS;
+}
+
+static inline int inat_group_common_attribute(insn_attr_t attr)
+{
+       return attr & ~INAT_GRP_MASK;
+}
+
+static inline int inat_has_immediate(insn_attr_t attr)
+{
+       return attr & INAT_IMM_MASK;
+}
+
+static inline int inat_immediate_size(insn_attr_t attr)
+{
+       return (attr & INAT_IMM_MASK) >> INAT_IMM_OFFS;
+}
+
+static inline int inat_has_modrm(insn_attr_t attr)
+{
+       return attr & INAT_MODRM;
+}
+
+static inline int inat_is_force64(insn_attr_t attr)
+{
+       return attr & INAT_FORCE64;
+}
+
+static inline int inat_has_second_immediate(insn_attr_t attr)
+{
+       return attr & INAT_SCNDIMM;
+}
+
+static inline int inat_has_moffset(insn_attr_t attr)
+{
+       return attr & INAT_MOFFSET;
+}
+
+static inline int inat_has_variant(insn_attr_t attr)
+{
+       return attr & INAT_VARIANT;
+}
+
+static inline int inat_accept_vex(insn_attr_t attr)
+{
+       return attr & INAT_VEXOK;
+}
+
+static inline int inat_must_vex(insn_attr_t attr)
+{
+       return attr & INAT_VEXONLY;
+}
+#endif
diff --git a/arch/x86/include/asm/inat_types.h b/arch/x86/include/asm/inat_types.h
new file mode 100644 (file)
index 0000000..cb3c20c
--- /dev/null
@@ -0,0 +1,29 @@
+#ifndef _ASM_X86_INAT_TYPES_H
+#define _ASM_X86_INAT_TYPES_H
+/*
+ * x86 instruction attributes
+ *
+ * Written by Masami Hiramatsu <mhiramat@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.
+ *
+ */
+
+/* Instruction attributes */
+typedef unsigned int insn_attr_t;
+typedef unsigned char insn_byte_t;
+typedef signed int insn_value_t;
+
+#endif
diff --git a/arch/x86/include/asm/insn.h b/arch/x86/include/asm/insn.h
new file mode 100644 (file)
index 0000000..96c2e0a
--- /dev/null
@@ -0,0 +1,184 @@
+#ifndef _ASM_X86_INSN_H
+#define _ASM_X86_INSN_H
+/*
+ * x86 instruction analysis
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Copyright (C) IBM Corporation, 2009
+ */
+
+/* insn_attr_t is defined in inat.h */
+#include <asm/inat.h>
+
+struct insn_field {
+       union {
+               insn_value_t value;
+               insn_byte_t bytes[4];
+       };
+       /* !0 if we've run insn_get_xxx() for this field */
+       unsigned char got;
+       unsigned char nbytes;
+};
+
+struct insn {
+       struct insn_field prefixes;     /*
+                                        * Prefixes
+                                        * prefixes.bytes[3]: last prefix
+                                        */
+       struct insn_field rex_prefix;   /* REX prefix */
+       struct insn_field vex_prefix;   /* VEX prefix */
+       struct insn_field opcode;       /*
+                                        * opcode.bytes[0]: opcode1
+                                        * opcode.bytes[1]: opcode2
+                                        * opcode.bytes[2]: opcode3
+                                        */
+       struct insn_field modrm;
+       struct insn_field sib;
+       struct insn_field displacement;
+       union {
+               struct insn_field immediate;
+               struct insn_field moffset1;     /* for 64bit MOV */
+               struct insn_field immediate1;   /* for 64bit imm or off16/32 */
+       };
+       union {
+               struct insn_field moffset2;     /* for 64bit MOV */
+               struct insn_field immediate2;   /* for 64bit imm or seg16 */
+       };
+
+       insn_attr_t attr;
+       unsigned char opnd_bytes;
+       unsigned char addr_bytes;
+       unsigned char length;
+       unsigned char x86_64;
+
+       const insn_byte_t *kaddr;       /* kernel address of insn to analyze */
+       const insn_byte_t *next_byte;
+};
+
+#define X86_MODRM_MOD(modrm) (((modrm) & 0xc0) >> 6)
+#define X86_MODRM_REG(modrm) (((modrm) & 0x38) >> 3)
+#define X86_MODRM_RM(modrm) ((modrm) & 0x07)
+
+#define X86_SIB_SCALE(sib) (((sib) & 0xc0) >> 6)
+#define X86_SIB_INDEX(sib) (((sib) & 0x38) >> 3)
+#define X86_SIB_BASE(sib) ((sib) & 0x07)
+
+#define X86_REX_W(rex) ((rex) & 8)
+#define X86_REX_R(rex) ((rex) & 4)
+#define X86_REX_X(rex) ((rex) & 2)
+#define X86_REX_B(rex) ((rex) & 1)
+
+/* VEX bit flags  */
+#define X86_VEX_W(vex) ((vex) & 0x80)  /* VEX3 Byte2 */
+#define X86_VEX_R(vex) ((vex) & 0x80)  /* VEX2/3 Byte1 */
+#define X86_VEX_X(vex) ((vex) & 0x40)  /* VEX3 Byte1 */
+#define X86_VEX_B(vex) ((vex) & 0x20)  /* VEX3 Byte1 */
+#define X86_VEX_L(vex) ((vex) & 0x04)  /* VEX3 Byte2, VEX2 Byte1 */
+/* VEX bit fields */
+#define X86_VEX3_M(vex)        ((vex) & 0x1f)          /* VEX3 Byte1 */
+#define X86_VEX2_M     1                       /* VEX2.M always 1 */
+#define X86_VEX_V(vex) (((vex) & 0x78) >> 3)   /* VEX3 Byte2, VEX2 Byte1 */
+#define X86_VEX_P(vex) ((vex) & 0x03)          /* VEX3 Byte2, VEX2 Byte1 */
+#define X86_VEX_M_MAX  0x1f                    /* VEX3.M Maximum value */
+
+/* The last prefix is needed for two-byte and three-byte opcodes */
+static inline insn_byte_t insn_last_prefix(struct insn *insn)
+{
+       return insn->prefixes.bytes[3];
+}
+
+extern void insn_init(struct insn *insn, const void *kaddr, int x86_64);
+extern void insn_get_prefixes(struct insn *insn);
+extern void insn_get_opcode(struct insn *insn);
+extern void insn_get_modrm(struct insn *insn);
+extern void insn_get_sib(struct insn *insn);
+extern void insn_get_displacement(struct insn *insn);
+extern void insn_get_immediate(struct insn *insn);
+extern void insn_get_length(struct insn *insn);
+
+/* Attribute will be determined after getting ModRM (for opcode groups) */
+static inline void insn_get_attribute(struct insn *insn)
+{
+       insn_get_modrm(insn);
+}
+
+/* Instruction uses RIP-relative addressing */
+extern int insn_rip_relative(struct insn *insn);
+
+/* Init insn for kernel text */
+static inline void kernel_insn_init(struct insn *insn, const void *kaddr)
+{
+#ifdef CONFIG_X86_64
+       insn_init(insn, kaddr, 1);
+#else /* CONFIG_X86_32 */
+       insn_init(insn, kaddr, 0);
+#endif
+}
+
+static inline int insn_is_avx(struct insn *insn)
+{
+       if (!insn->prefixes.got)
+               insn_get_prefixes(insn);
+       return (insn->vex_prefix.value != 0);
+}
+
+static inline insn_byte_t insn_vex_m_bits(struct insn *insn)
+{
+       if (insn->vex_prefix.nbytes == 2)       /* 2 bytes VEX */
+               return X86_VEX2_M;
+       else
+               return X86_VEX3_M(insn->vex_prefix.bytes[1]);
+}
+
+static inline insn_byte_t insn_vex_p_bits(struct insn *insn)
+{
+       if (insn->vex_prefix.nbytes == 2)       /* 2 bytes VEX */
+               return X86_VEX_P(insn->vex_prefix.bytes[1]);
+       else
+               return X86_VEX_P(insn->vex_prefix.bytes[2]);
+}
+
+/* Offset of each field from kaddr */
+static inline int insn_offset_rex_prefix(struct insn *insn)
+{
+       return insn->prefixes.nbytes;
+}
+static inline int insn_offset_vex_prefix(struct insn *insn)
+{
+       return insn_offset_rex_prefix(insn) + insn->rex_prefix.nbytes;
+}
+static inline int insn_offset_opcode(struct insn *insn)
+{
+       return insn_offset_vex_prefix(insn) + insn->vex_prefix.nbytes;
+}
+static inline int insn_offset_modrm(struct insn *insn)
+{
+       return insn_offset_opcode(insn) + insn->opcode.nbytes;
+}
+static inline int insn_offset_sib(struct insn *insn)
+{
+       return insn_offset_modrm(insn) + insn->modrm.nbytes;
+}
+static inline int insn_offset_displacement(struct insn *insn)
+{
+       return insn_offset_sib(insn) + insn->sib.nbytes;
+}
+static inline int insn_offset_immediate(struct insn *insn)
+{
+       return insn_offset_displacement(insn) + insn->displacement.nbytes;
+}
+
+#endif /* _ASM_X86_INSN_H */
index ddda6cb..ffd700f 100644 (file)
@@ -34,6 +34,7 @@ static inline int irq_canonicalize(int irq)
 #ifdef CONFIG_HOTPLUG_CPU
 #include <linux/cpumask.h>
 extern void fixup_irqs(void);
+extern void irq_force_complete_move(int);
 #endif
 
 extern void (*generic_interrupt_extension)(void);
index 4a5fe91..950df43 100644 (file)
@@ -19,6 +19,8 @@
 #define __KVM_HAVE_MSIX
 #define __KVM_HAVE_MCE
 #define __KVM_HAVE_PIT_STATE2
+#define __KVM_HAVE_XEN_HVM
+#define __KVM_HAVE_VCPU_EVENTS
 
 /* Architectural interrupt line count. */
 #define KVM_NR_INTERRUPTS 256
@@ -79,6 +81,7 @@ struct kvm_ioapic_state {
 #define KVM_IRQCHIP_PIC_MASTER   0
 #define KVM_IRQCHIP_PIC_SLAVE    1
 #define KVM_IRQCHIP_IOAPIC       2
+#define KVM_NR_IRQCHIPS          3
 
 /* for KVM_GET_REGS and KVM_SET_REGS */
 struct kvm_regs {
@@ -250,4 +253,31 @@ struct kvm_reinject_control {
        __u8 pit_reinject;
        __u8 reserved[31];
 };
+
+/* for KVM_GET/SET_VCPU_EVENTS */
+struct kvm_vcpu_events {
+       struct {
+               __u8 injected;
+               __u8 nr;
+               __u8 has_error_code;
+               __u8 pad;
+               __u32 error_code;
+       } exception;
+       struct {
+               __u8 injected;
+               __u8 nr;
+               __u8 soft;
+               __u8 pad;
+       } interrupt;
+       struct {
+               __u8 injected;
+               __u8 pending;
+               __u8 masked;
+               __u8 pad;
+       } nmi;
+       __u32 sipi_vector;
+       __u32 flags;
+       __u32 reserved[10];
+};
+
 #endif /* _ASM_X86_KVM_H */
index b7ed2c4..7c18e12 100644 (file)
@@ -129,7 +129,7 @@ struct decode_cache {
        u8 seg_override;
        unsigned int d;
        unsigned long regs[NR_VCPU_REGS];
-       unsigned long eip;
+       unsigned long eip, eip_orig;
        /* modrm */
        u8 modrm;
        u8 modrm_mod;
index d838922..4f865e8 100644 (file)
@@ -354,7 +354,6 @@ struct kvm_vcpu_arch {
        unsigned int time_offset;
        struct page *time_page;
 
-       bool singlestep; /* guest is single stepped by KVM */
        bool nmi_pending;
        bool nmi_injected;
 
@@ -371,6 +370,10 @@ struct kvm_vcpu_arch {
        u64 mcg_status;
        u64 mcg_ctl;
        u64 *mce_banks;
+
+       /* used for guest single stepping over the given code position */
+       u16 singlestep_cs;
+       unsigned long singlestep_rip;
 };
 
 struct kvm_mem_alias {
@@ -397,7 +400,6 @@ struct kvm_arch{
        struct kvm_pic *vpic;
        struct kvm_ioapic *vioapic;
        struct kvm_pit *vpit;
-       struct hlist_head irq_ack_notifier_list;
        int vapics_in_nmi_mode;
 
        unsigned int tss_addr;
@@ -410,8 +412,10 @@ struct kvm_arch{
        gpa_t ept_identity_map_addr;
 
        unsigned long irq_sources_bitmap;
-       unsigned long irq_states[KVM_IOAPIC_NUM_PINS];
        u64 vm_init_tsc;
+       s64 kvmclock_offset;
+
+       struct kvm_xen_hvm_config xen_hvm_config;
 };
 
 struct kvm_vm_stat {
@@ -461,7 +465,7 @@ struct descriptor_table {
 struct kvm_x86_ops {
        int (*cpu_has_kvm_support)(void);          /* __init */
        int (*disabled_by_bios)(void);             /* __init */
-       void (*hardware_enable)(void *dummy);      /* __init */
+       int (*hardware_enable)(void *dummy);
        void (*hardware_disable)(void *dummy);
        void (*check_processor_compatibility)(void *rtn);
        int (*hardware_setup)(void);               /* __init */
@@ -477,8 +481,8 @@ struct kvm_x86_ops {
        void (*vcpu_load)(struct kvm_vcpu *vcpu, int cpu);
        void (*vcpu_put)(struct kvm_vcpu *vcpu);
 
-       int (*set_guest_debug)(struct kvm_vcpu *vcpu,
-                              struct kvm_guest_debug *dbg);
+       void (*set_guest_debug)(struct kvm_vcpu *vcpu,
+                               struct kvm_guest_debug *dbg);
        int (*get_msr)(struct kvm_vcpu *vcpu, u32 msr_index, u64 *pdata);
        int (*set_msr)(struct kvm_vcpu *vcpu, u32 msr_index, u64 data);
        u64 (*get_segment_base)(struct kvm_vcpu *vcpu, int seg);
@@ -506,8 +510,8 @@ struct kvm_x86_ops {
 
        void (*tlb_flush)(struct kvm_vcpu *vcpu);
 
-       void (*run)(struct kvm_vcpu *vcpu, struct kvm_run *run);
-       int (*handle_exit)(struct kvm_run *run, struct kvm_vcpu *vcpu);
+       void (*run)(struct kvm_vcpu *vcpu);
+       int (*handle_exit)(struct kvm_vcpu *vcpu);
        void (*skip_emulated_instruction)(struct kvm_vcpu *vcpu);
        void (*set_interrupt_shadow)(struct kvm_vcpu *vcpu, int mask);
        u32 (*get_interrupt_shadow)(struct kvm_vcpu *vcpu, int mask);
@@ -519,6 +523,8 @@ struct kvm_x86_ops {
                                bool has_error_code, u32 error_code);
        int (*interrupt_allowed)(struct kvm_vcpu *vcpu);
        int (*nmi_allowed)(struct kvm_vcpu *vcpu);
+       bool (*get_nmi_mask)(struct kvm_vcpu *vcpu);
+       void (*set_nmi_mask)(struct kvm_vcpu *vcpu, bool masked);
        void (*enable_nmi_window)(struct kvm_vcpu *vcpu);
        void (*enable_irq_window)(struct kvm_vcpu *vcpu);
        void (*update_cr8_intercept)(struct kvm_vcpu *vcpu, int tpr, int irr);
@@ -568,7 +574,7 @@ enum emulation_result {
 #define EMULTYPE_NO_DECODE         (1 << 0)
 #define EMULTYPE_TRAP_UD           (1 << 1)
 #define EMULTYPE_SKIP              (1 << 2)
-int emulate_instruction(struct kvm_vcpu *vcpu, struct kvm_run *run,
+int emulate_instruction(struct kvm_vcpu *vcpu,
                        unsigned long cr2, u16 error_code, int emulation_type);
 void kvm_report_emulation_failure(struct kvm_vcpu *cvpu, const char *context);
 void realmode_lgdt(struct kvm_vcpu *vcpu, u16 size, unsigned long address);
@@ -585,9 +591,9 @@ int kvm_set_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 data);
 
 struct x86_emulate_ctxt;
 
-int kvm_emulate_pio(struct kvm_vcpu *vcpu, struct kvm_run *run, int in,
+int kvm_emulate_pio(struct kvm_vcpu *vcpu, int in,
                     int size, unsigned port);
-int kvm_emulate_pio_string(struct kvm_vcpu *vcpu, struct kvm_run *run, int in,
+int kvm_emulate_pio_string(struct kvm_vcpu *vcpu, int in,
                           int size, unsigned long count, int down,
                            gva_t address, int rep, unsigned port);
 void kvm_emulate_cpuid(struct kvm_vcpu *vcpu);
@@ -616,6 +622,9 @@ void kvm_get_cs_db_l_bits(struct kvm_vcpu *vcpu, int *db, int *l);
 int kvm_get_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata);
 int kvm_set_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 data);
 
+unsigned long kvm_get_rflags(struct kvm_vcpu *vcpu);
+void kvm_set_rflags(struct kvm_vcpu *vcpu, unsigned long rflags);
+
 void kvm_queue_exception(struct kvm_vcpu *vcpu, unsigned nr);
 void kvm_queue_exception_e(struct kvm_vcpu *vcpu, unsigned nr, u32 error_code);
 void kvm_inject_page_fault(struct kvm_vcpu *vcpu, unsigned long cr2,
@@ -802,4 +811,7 @@ int kvm_cpu_has_interrupt(struct kvm_vcpu *vcpu);
 int kvm_arch_interrupt_allowed(struct kvm_vcpu *vcpu);
 int kvm_cpu_get_interrupt(struct kvm_vcpu *v);
 
+void kvm_define_shared_msr(unsigned index, u32 msr);
+void kvm_set_shared_msr(unsigned index, u64 val, u64 mask);
+
 #endif /* _ASM_X86_KVM_HOST_H */
index f1363b7..858baa0 100644 (file)
@@ -108,6 +108,8 @@ struct mce_log {
 #define K8_MCE_THRESHOLD_BANK_5    (MCE_THRESHOLD_BASE + 5 * 9)
 #define K8_MCE_THRESHOLD_DRAM_ECC  (MCE_THRESHOLD_BANK_4 + 0)
 
+extern struct atomic_notifier_head x86_mce_decoder_chain;
+
 #ifdef __KERNEL__
 
 #include <linux/percpu.h>
@@ -118,9 +120,11 @@ extern int mce_disabled;
 extern int mce_p5_enabled;
 
 #ifdef CONFIG_X86_MCE
-void mcheck_init(struct cpuinfo_x86 *c);
+int mcheck_init(void);
+void mcheck_cpu_init(struct cpuinfo_x86 *c);
 #else
-static inline void mcheck_init(struct cpuinfo_x86 *c) {}
+static inline int mcheck_init(void) { return 0; }
+static inline void mcheck_cpu_init(struct cpuinfo_x86 *c) {}
 #endif
 
 #ifdef CONFIG_X86_ANCIENT_MCE
@@ -214,5 +218,11 @@ void intel_init_thermal(struct cpuinfo_x86 *c);
 
 void mce_log_therm_throt_event(__u64 status);
 
+#ifdef CONFIG_X86_THERMAL_VECTOR
+extern void mcheck_intel_therm_init(void);
+#else
+static inline void mcheck_intel_therm_init(void) { }
+#endif
+
 #endif /* __KERNEL__ */
 #endif /* _ASM_X86_MCE_H */
index 79c9450..61d90b1 100644 (file)
@@ -163,14 +163,16 @@ typedef struct physid_mask physid_mask_t;
 #define physids_shift_left(d, s, n)                            \
        bitmap_shift_left((d).mask, (s).mask, n, MAX_APICS)
 
-#define physids_coerce(map)                    ((map).mask[0])
+static inline unsigned long physids_coerce(physid_mask_t *map)
+{
+       return map->mask[0];
+}
 
-#define physids_promote(physids)                                       \
-       ({                                                              \
-               physid_mask_t __physid_mask = PHYSID_MASK_NONE;         \
-               __physid_mask.mask[0] = physids;                        \
-               __physid_mask;                                          \
-       })
+static inline void physids_promote(unsigned long physids, physid_mask_t *map)
+{
+       physids_clear(*map);
+       map->mask[0] = physids;
+}
 
 /* Note: will create very large stack frames if physid_mask_t is big */
 #define physid_mask_of_physid(physid)                                  \
index 7e2b6ba..5bef931 100644 (file)
@@ -247,8 +247,8 @@ do {                                                            \
 #ifdef CONFIG_SMP
 int rdmsr_on_cpu(unsigned int cpu, u32 msr_no, u32 *l, u32 *h);
 int wrmsr_on_cpu(unsigned int cpu, u32 msr_no, u32 l, u32 h);
-void rdmsr_on_cpus(const cpumask_t *mask, u32 msr_no, struct msr *msrs);
-void wrmsr_on_cpus(const cpumask_t *mask, u32 msr_no, struct msr *msrs);
+void rdmsr_on_cpus(const struct cpumask *mask, u32 msr_no, struct msr *msrs);
+void wrmsr_on_cpus(const struct cpumask *mask, u32 msr_no, struct msr *msrs);
 int rdmsr_safe_on_cpu(unsigned int cpu, u32 msr_no, u32 *l, u32 *h);
 int wrmsr_safe_on_cpu(unsigned int cpu, u32 msr_no, u32 l, u32 h);
 int rdmsr_safe_regs_on_cpu(unsigned int cpu, u32 regs[8]);
@@ -264,12 +264,12 @@ static inline int wrmsr_on_cpu(unsigned int cpu, u32 msr_no, u32 l, u32 h)
        wrmsr(msr_no, l, h);
        return 0;
 }
-static inline void rdmsr_on_cpus(const cpumask_t *m, u32 msr_no,
+static inline void rdmsr_on_cpus(const struct cpumask *m, u32 msr_no,
                                struct msr *msrs)
 {
        rdmsr_on_cpu(0, msr_no, &(msrs[0].l), &(msrs[0].h));
 }
-static inline void wrmsr_on_cpus(const cpumask_t *m, u32 msr_no,
+static inline void wrmsr_on_cpus(const struct cpumask *m, u32 msr_no,
                                struct msr *msrs)
 {
        wrmsr_on_cpu(0, msr_no, msrs[0].l, msrs[0].h);
index ad7ce3f..8d9f854 100644 (file)
  */
 #define ARCH_PERFMON_EVENT_MASK                                    0xffff
 
+/*
+ * filter mask to validate fixed counter events.
+ * the following filters disqualify for fixed counters:
+ *  - inv
+ *  - edge
+ *  - cnt-mask
+ *  The other filters are supported by fixed counters.
+ *  The any-thread option is supported starting with v3.
+ */
+#define ARCH_PERFMON_EVENT_FILTER_MASK                 0xff840000
+
 #define ARCH_PERFMON_UNHALTED_CORE_CYCLES_SEL                0x3c
 #define ARCH_PERFMON_UNHALTED_CORE_CYCLES_UMASK                (0x00 << 8)
-#define ARCH_PERFMON_UNHALTED_CORE_CYCLES_INDEX                 0
+#define ARCH_PERFMON_UNHALTED_CORE_CYCLES_INDEX                         0
 #define ARCH_PERFMON_UNHALTED_CORE_CYCLES_PRESENT \
                (1 << (ARCH_PERFMON_UNHALTED_CORE_CYCLES_INDEX))
 
index c978648..6f8ec1c 100644 (file)
@@ -30,6 +30,7 @@ struct mm_struct;
 #include <linux/math64.h>
 #include <linux/init.h>
 
+#define HBP_NUM 4
 /*
  * Default implementation of macro that returns current
  * instruction pointer ("program counter").
@@ -422,6 +423,8 @@ extern unsigned int xstate_size;
 extern void free_thread_xstate(struct task_struct *);
 extern struct kmem_cache *task_xstate_cachep;
 
+struct perf_event;
+
 struct thread_struct {
        /* Cached TLS descriptors: */
        struct desc_struct      tls_array[GDT_ENTRY_TLS_ENTRIES];
@@ -443,13 +446,10 @@ struct thread_struct {
        unsigned long           fs;
 #endif
        unsigned long           gs;
-       /* Hardware debugging registers: */
-       unsigned long           debugreg0;
-       unsigned long           debugreg1;
-       unsigned long           debugreg2;
-       unsigned long           debugreg3;
-       unsigned long           debugreg6;
-       unsigned long           debugreg7;
+       /* Save middle states of ptrace breakpoints */
+       struct perf_event       *ptrace_bps[HBP_NUM];
+       /* Debug status used for traps, single steps, etc... */
+       unsigned long           debugreg6;
        /* Fault info: */
        unsigned long           cr2;
        unsigned long           trap_no;
index 0f0d908..3d11fd0 100644 (file)
@@ -7,6 +7,7 @@
 
 #ifdef __KERNEL__
 #include <asm/segment.h>
+#include <asm/page_types.h>
 #endif
 
 #ifndef __ASSEMBLY__
@@ -216,6 +217,67 @@ static inline unsigned long user_stack_pointer(struct pt_regs *regs)
        return regs->sp;
 }
 
+/* Query offset/name of register from its name/offset */
+extern int regs_query_register_offset(const char *name);
+extern const char *regs_query_register_name(unsigned int offset);
+#define MAX_REG_OFFSET (offsetof(struct pt_regs, ss))
+
+/**
+ * regs_get_register() - get register value from its offset
+ * @regs:      pt_regs from which register value is gotten.
+ * @offset:    offset number of the register.
+ *
+ * regs_get_register returns the value of a register. The @offset is the
+ * offset of the register in struct pt_regs address which specified by @regs.
+ * If @offset is bigger than MAX_REG_OFFSET, this returns 0.
+ */
+static inline unsigned long regs_get_register(struct pt_regs *regs,
+                                             unsigned int offset)
+{
+       if (unlikely(offset > MAX_REG_OFFSET))
+               return 0;
+       return *(unsigned long *)((unsigned long)regs + offset);
+}
+
+/**
+ * regs_within_kernel_stack() - check the address in the stack
+ * @regs:      pt_regs which contains kernel stack pointer.
+ * @addr:      address which is checked.
+ *
+ * regs_within_kernel_stack() checks @addr is within the kernel stack page(s).
+ * If @addr is within the kernel stack, it returns true. If not, returns false.
+ */
+static inline int regs_within_kernel_stack(struct pt_regs *regs,
+                                          unsigned long addr)
+{
+       return ((addr & ~(THREAD_SIZE - 1))  ==
+               (kernel_stack_pointer(regs) & ~(THREAD_SIZE - 1)));
+}
+
+/**
+ * regs_get_kernel_stack_nth() - get Nth entry of the stack
+ * @regs:      pt_regs which contains kernel stack pointer.
+ * @n:         stack entry number.
+ *
+ * regs_get_kernel_stack_nth() returns @n th entry of the kernel stack which
+ * is specified by @regs. If the @n th entry is NOT in the kernel stack,
+ * this returns 0.
+ */
+static inline unsigned long regs_get_kernel_stack_nth(struct pt_regs *regs,
+                                                     unsigned int n)
+{
+       unsigned long *addr = (unsigned long *)kernel_stack_pointer(regs);
+       addr += n;
+       if (regs_within_kernel_stack(regs, (unsigned long)addr))
+               return *addr;
+       else
+               return 0;
+}
+
+/* Get Nth argument at function call */
+extern unsigned long regs_get_argument_nth(struct pt_regs *regs,
+                                          unsigned int n);
+
 /*
  * These are defined as per linux/ptrace.h, which see.
  */
index ae907e6..3d3e835 100644 (file)
@@ -177,10 +177,15 @@ static inline void *__memcpy3d(void *to, const void *from, size_t len)
  */
 
 #ifndef CONFIG_KMEMCHECK
+
+#if (__GNUC__ >= 4)
+#define memcpy(t, f, n) __builtin_memcpy(t, f, n)
+#else
 #define memcpy(t, f, n)                                \
        (__builtin_constant_p((n))              \
         ? __constant_memcpy((t), (f), (n))     \
         : __memcpy((t), (f), (n)))
+#endif
 #else
 /*
  * kmemcheck becomes very happy if we use the REP instructions unconditionally,
@@ -316,11 +321,15 @@ void *__constant_c_and_count_memset(void *s, unsigned long pattern,
         : __memset_generic((s), (c), (count)))
 
 #define __HAVE_ARCH_MEMSET
+#if (__GNUC__ >= 4)
+#define memset(s, c, count) __builtin_memset(s, c, count)
+#else
 #define memset(s, c, count)                                            \
        (__builtin_constant_p(c)                                        \
         ? __constant_c_x_memset((s), (0x01010101UL * (unsigned char)(c)), \
                                 (count))                               \
         : __memset((s), (c), (count)))
+#endif
 
 /*
  * find the first occurrence of byte 'c', or 1 past the area if none
index 85574b7..1fecb7e 100644 (file)
@@ -57,7 +57,8 @@ struct __attribute__ ((__packed__)) vmcb_control_area {
        u16 intercept_dr_write;
        u32 intercept_exceptions;
        u64 intercept;
-       u8 reserved_1[44];
+       u8 reserved_1[42];
+       u16 pause_filter_count;
        u64 iopm_base_pa;
        u64 msrpm_base_pa;
        u64 tsc_offset;
index 72a6dcd..9af9dec 100644 (file)
@@ -51,11 +51,6 @@ asmlinkage long sys32_sched_rr_get_interval(compat_pid_t,
 asmlinkage long sys32_rt_sigpending(compat_sigset_t __user *, compat_size_t);
 asmlinkage long sys32_rt_sigqueueinfo(int, int, compat_siginfo_t __user *);
 
-#ifdef CONFIG_SYSCTL_SYSCALL
-struct sysctl_ia32;
-asmlinkage long sys32_sysctl(struct sysctl_ia32 __user *);
-#endif
-
 asmlinkage long sys32_pread(unsigned int, char __user *, u32, u32, u32);
 asmlinkage long sys32_pwrite(unsigned int, char __user *, u32, u32, u32);
 
index f08f973..022a843 100644 (file)
@@ -128,8 +128,6 @@ do {                                                                        \
             "movq %%rsp,%P[threadrsp](%[prev])\n\t" /* save RSP */       \
             "movq %P[threadrsp](%[next]),%%rsp\n\t" /* restore RSP */    \
             "call __switch_to\n\t"                                       \
-            ".globl thread_return\n"                                     \
-            "thread_return:\n\t"                                         \
             "movq "__percpu_arg([current_task])",%%rsi\n\t"              \
             __switch_canary                                              \
             "movq %P[thread_info](%%rsi),%%r8\n\t"                       \
@@ -157,19 +155,22 @@ extern void native_load_gs_index(unsigned);
  * Load a segment. Fall back on loading the zero
  * segment if something goes wrong..
  */
-#define loadsegment(seg, value)                        \
-       asm volatile("\n"                       \
-                    "1:\t"                     \
-                    "movl %k0,%%" #seg "\n"    \
-                    "2:\n"                     \
-                    ".section .fixup,\"ax\"\n" \
-                    "3:\t"                     \
-                    "movl %k1, %%" #seg "\n\t" \
-                    "jmp 2b\n"                 \
-                    ".previous\n"              \
-                    _ASM_EXTABLE(1b,3b)        \
-                    : :"r" (value), "r" (0) : "memory")
-
+#define loadsegment(seg, value)                                                \
+do {                                                                   \
+       unsigned short __val = (value);                                 \
+                                                                       \
+       asm volatile("                                          \n"     \
+                    "1:        movl %k0,%%" #seg "             \n"     \
+                                                                       \
+                    ".section .fixup,\"ax\"                    \n"     \
+                    "2:        xorl %k0,%k0                    \n"     \
+                    "          jmp 1b                          \n"     \
+                    ".previous                                 \n"     \
+                                                                       \
+                    _ASM_EXTABLE(1b, 2b)                               \
+                                                                       \
+                    : "+r" (__val) : : "memory");                      \
+} while (0)
 
 /*
  * Save a segment register away
index d27d0a2..375c917 100644 (file)
@@ -83,6 +83,7 @@ struct thread_info {
 #define TIF_SYSCALL_AUDIT      7       /* syscall auditing active */
 #define TIF_SECCOMP            8       /* secure computing */
 #define TIF_MCE_NOTIFY         10      /* notify userspace of an MCE */
+#define TIF_USER_RETURN_NOTIFY 11      /* notify kernel of userspace return */
 #define TIF_NOTSC              16      /* TSC is not accessible in userland */
 #define TIF_IA32               17      /* 32bit process */
 #define TIF_FORK               18      /* ret_from_fork */
@@ -107,6 +108,7 @@ struct thread_info {
 #define _TIF_SYSCALL_AUDIT     (1 << TIF_SYSCALL_AUDIT)
 #define _TIF_SECCOMP           (1 << TIF_SECCOMP)
 #define _TIF_MCE_NOTIFY                (1 << TIF_MCE_NOTIFY)
+#define _TIF_USER_RETURN_NOTIFY        (1 << TIF_USER_RETURN_NOTIFY)
 #define _TIF_NOTSC             (1 << TIF_NOTSC)
 #define _TIF_IA32              (1 << TIF_IA32)
 #define _TIF_FORK              (1 << TIF_FORK)
@@ -142,13 +144,14 @@ struct thread_info {
 
 /* Only used for 64 bit */
 #define _TIF_DO_NOTIFY_MASK                                            \
-       (_TIF_SIGPENDING|_TIF_MCE_NOTIFY|_TIF_NOTIFY_RESUME)
+       (_TIF_SIGPENDING | _TIF_MCE_NOTIFY | _TIF_NOTIFY_RESUME |       \
+        _TIF_USER_RETURN_NOTIFY)
 
 /* flags to check in __switch_to() */
 #define _TIF_WORK_CTXSW                                                        \
        (_TIF_IO_BITMAP|_TIF_DEBUGCTLMSR|_TIF_DS_AREA_MSR|_TIF_NOTSC)
 
-#define _TIF_WORK_CTXSW_PREV _TIF_WORK_CTXSW
+#define _TIF_WORK_CTXSW_PREV (_TIF_WORK_CTXSW|_TIF_USER_RETURN_NOTIFY)
 #define _TIF_WORK_CTXSW_NEXT (_TIF_WORK_CTXSW|_TIF_DEBUG)
 
 #define PREEMPT_ACTIVE         0x10000000
index d2c6c93..abd3e0e 100644 (file)
@@ -570,7 +570,6 @@ extern struct movsl_mask {
 #ifdef CONFIG_X86_32
 # include "uaccess_32.h"
 #else
-# define ARCH_HAS_SEARCH_EXTABLE
 # include "uaccess_64.h"
 #endif
 
index 632fb44..0c9825e 100644 (file)
@@ -187,9 +187,34 @@ __copy_from_user_inatomic_nocache(void *to, const void __user *from,
 
 unsigned long __must_check copy_to_user(void __user *to,
                                        const void *from, unsigned long n);
-unsigned long __must_check copy_from_user(void *to,
+unsigned long __must_check _copy_from_user(void *to,
                                          const void __user *from,
                                          unsigned long n);
+
+
+extern void copy_from_user_overflow(void)
+#ifdef CONFIG_DEBUG_STRICT_USER_COPY_CHECKS
+       __compiletime_error("copy_from_user() buffer size is not provably correct")
+#else
+       __compiletime_warning("copy_from_user() buffer size is not provably correct")
+#endif
+;
+
+static inline unsigned long __must_check copy_from_user(void *to,
+                                         const void __user *from,
+                                         unsigned long n)
+{
+       int sz = __compiletime_object_size(to);
+       int ret = -EFAULT;
+
+       if (likely(sz == -1 || sz >= n))
+               ret = _copy_from_user(to, from, n);
+       else
+               copy_from_user_overflow();
+
+       return ret;
+}
+
 long __must_check strncpy_from_user(char *dst, const char __user *src,
                                    long count);
 long __must_check __strncpy_from_user(char *dst,
index db24b21..46324c6 100644 (file)
@@ -19,12 +19,37 @@ __must_check unsigned long
 copy_user_generic(void *to, const void *from, unsigned len);
 
 __must_check unsigned long
-copy_to_user(void __user *to, const void *from, unsigned len);
+_copy_to_user(void __user *to, const void *from, unsigned len);
 __must_check unsigned long
-copy_from_user(void *to, const void __user *from, unsigned len);
+_copy_from_user(void *to, const void __user *from, unsigned len);
 __must_check unsigned long
 copy_in_user(void __user *to, const void __user *from, unsigned len);
 
+static inline unsigned long __must_check copy_from_user(void *to,
+                                         const void __user *from,
+                                         unsigned long n)
+{
+       int sz = __compiletime_object_size(to);
+       int ret = -EFAULT;
+
+       might_fault();
+       if (likely(sz == -1 || sz >= n))
+               ret = _copy_from_user(to, from, n);
+#ifdef CONFIG_DEBUG_VM
+       else
+               WARN(1, "Buffer overflow detected!\n");
+#endif
+       return ret;
+}
+
+static __always_inline __must_check
+int copy_to_user(void __user *dst, const void *src, unsigned size)
+{
+       might_fault();
+
+       return _copy_to_user(dst, src, size);
+}
+
 static __always_inline __must_check
 int __copy_from_user(void *dst, const void __user *src, unsigned size)
 {
@@ -176,8 +201,11 @@ __must_check long strlen_user(const char __user *str);
 __must_check unsigned long clear_user(void __user *mem, unsigned long len);
 __must_check unsigned long __clear_user(void __user *mem, unsigned long len);
 
-__must_check long __copy_from_user_inatomic(void *dst, const void __user *src,
-                                           unsigned size);
+static __must_check __always_inline int
+__copy_from_user_inatomic(void *dst, const void __user *src, unsigned size)
+{
+       return copy_user_generic(dst, (__force const void *)src, size);
+}
 
 static __must_check __always_inline int
 __copy_to_user_inatomic(void __user *dst, const void *src, unsigned size)
index 9613c8c..d6b17c7 100644 (file)
@@ -25,12 +25,14 @@ struct uv_IO_APIC_route_entry {
                dest            : 32;
 };
 
-extern struct irq_chip uv_irq_chip;
-
-extern int arch_enable_uv_irq(char *, unsigned int, int, int, unsigned long);
-extern void arch_disable_uv_irq(int, unsigned long);
+enum {
+       UV_AFFINITY_ALL,
+       UV_AFFINITY_NODE,
+       UV_AFFINITY_CPU
+};
 
-extern int uv_setup_irq(char *, int, int, unsigned long);
-extern void uv_teardown_irq(unsigned int, int, unsigned long);
+extern int uv_irq_2_mmr_info(int, unsigned long *, int *);
+extern int uv_setup_irq(char *, int, int, unsigned long, int);
+extern void uv_teardown_irq(unsigned int);
 
 #endif /* _ASM_X86_UV_UV_IRQ_H */
index 272514c..2b49454 100644 (file)
@@ -56,6 +56,7 @@
 #define SECONDARY_EXEC_ENABLE_VPID              0x00000020
 #define SECONDARY_EXEC_WBINVD_EXITING          0x00000040
 #define SECONDARY_EXEC_UNRESTRICTED_GUEST      0x00000080
+#define SECONDARY_EXEC_PAUSE_LOOP_EXITING      0x00000400
 
 
 #define PIN_BASED_EXT_INTR_MASK                 0x00000001
@@ -144,6 +145,8 @@ enum vmcs_field {
        VM_ENTRY_INSTRUCTION_LEN        = 0x0000401a,
        TPR_THRESHOLD                   = 0x0000401c,
        SECONDARY_VM_EXEC_CONTROL       = 0x0000401e,
+       PLE_GAP                         = 0x00004020,
+       PLE_WINDOW                      = 0x00004022,
        VM_INSTRUCTION_ERROR            = 0x00004400,
        VM_EXIT_REASON                  = 0x00004402,
        VM_EXIT_INTR_INFO               = 0x00004404,
@@ -248,6 +251,7 @@ enum vmcs_field {
 #define EXIT_REASON_MSR_READ            31
 #define EXIT_REASON_MSR_WRITE           32
 #define EXIT_REASON_MWAIT_INSTRUCTION   36
+#define EXIT_REASON_PAUSE_INSTRUCTION   40
 #define EXIT_REASON_MCE_DURING_VMENTRY  41
 #define EXIT_REASON_TPR_BELOW_THRESHOLD 43
 #define EXIT_REASON_APIC_ACCESS         44
index d8e5d0c..4f2e66e 100644 (file)
@@ -40,7 +40,7 @@ obj-$(CONFIG_X86_64)  += sys_x86_64.o x8664_ksyms_64.o
 obj-$(CONFIG_X86_64)   += syscall_64.o vsyscall_64.o
 obj-y                  += bootflag.o e820.o
 obj-y                  += pci-dma.o quirks.o i8237.o topology.o kdebugfs.o
-obj-y                  += alternative.o i8253.o pci-nommu.o
+obj-y                  += alternative.o i8253.o pci-nommu.o hw_breakpoint.o
 obj-y                  += tsc.o io_delay.o rtc.o
 
 obj-$(CONFIG_X86_TRAMPOLINE)   += trampoline.o
index da7b7b9..565c1bf 100644 (file)
@@ -2,7 +2,7 @@
 # Makefile for local APIC drivers and for the IO-APIC code
 #
 
-obj-$(CONFIG_X86_LOCAL_APIC)   += apic.o probe_$(BITS).o ipi.o nmi.o
+obj-$(CONFIG_X86_LOCAL_APIC)   += apic.o apic_noop.o probe_$(BITS).o ipi.o nmi.o
 obj-$(CONFIG_X86_IO_APIC)      += io_apic.o
 obj-$(CONFIG_SMP)              += ipi.o
 
index 894aa97..ad8c75b 100644 (file)
@@ -241,28 +241,13 @@ static int modern_apic(void)
 }
 
 /*
- * bare function to substitute write operation
- * and it's _that_ fast :)
- */
-static void native_apic_write_dummy(u32 reg, u32 v)
-{
-       WARN_ON_ONCE((cpu_has_apic || !disable_apic));
-}
-
-static u32 native_apic_read_dummy(u32 reg)
-{
-       WARN_ON_ONCE((cpu_has_apic && !disable_apic));
-       return 0;
-}
-
-/*
- * right after this call apic->write/read doesn't do anything
- * note that there is no restore operation it works one way
+ * right after this call apic become NOOP driven
+ * so apic->write/read doesn't do anything
  */
 void apic_disable(void)
 {
-       apic->read = native_apic_read_dummy;
-       apic->write = native_apic_write_dummy;
+       pr_info("APIC: switched to apic NOOP\n");
+       apic = &apic_noop;
 }
 
 void native_apic_wait_icr_idle(void)
@@ -459,7 +444,7 @@ static void lapic_timer_setup(enum clock_event_mode mode,
                v = apic_read(APIC_LVTT);
                v |= (APIC_LVT_MASKED | LOCAL_TIMER_VECTOR);
                apic_write(APIC_LVTT, v);
-               apic_write(APIC_TMICT, 0xffffffff);
+               apic_write(APIC_TMICT, 0);
                break;
        case CLOCK_EVT_MODE_RESUME:
                /* Nothing to do here */
@@ -1392,14 +1377,11 @@ void __init enable_IR_x2apic(void)
        unsigned long flags;
        struct IO_APIC_route_entry **ioapic_entries = NULL;
        int ret, x2apic_enabled = 0;
-       int dmar_table_init_ret = 0;
+       int dmar_table_init_ret;
 
-#ifdef CONFIG_INTR_REMAP
        dmar_table_init_ret = dmar_table_init();
-       if (dmar_table_init_ret)
-               pr_debug("dmar_table_init() failed with %d:\n",
-                               dmar_table_init_ret);
-#endif
+       if (dmar_table_init_ret && !x2apic_supported())
+               return;
 
        ioapic_entries = alloc_ioapic_entries();
        if (!ioapic_entries) {
diff --git a/arch/x86/kernel/apic/apic_noop.c b/arch/x86/kernel/apic/apic_noop.c
new file mode 100644 (file)
index 0000000..d9acc3b
--- /dev/null
@@ -0,0 +1,200 @@
+/*
+ * NOOP APIC driver.
+ *
+ * Does almost nothing and should be substituted by a real apic driver via
+ * probe routine.
+ *
+ * Though in case if apic is disabled (for some reason) we try
+ * to not uglify the caller's code and allow to call (some) apic routines
+ * like self-ipi, etc...
+ */
+
+#include <linux/threads.h>
+#include <linux/cpumask.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/ctype.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <asm/fixmap.h>
+#include <asm/mpspec.h>
+#include <asm/apicdef.h>
+#include <asm/apic.h>
+#include <asm/setup.h>
+
+#include <linux/smp.h>
+#include <asm/ipi.h>
+
+#include <linux/interrupt.h>
+#include <asm/acpi.h>
+#include <asm/e820.h>
+
+static void noop_init_apic_ldr(void) { }
+static void noop_send_IPI_mask(const struct cpumask *cpumask, int vector) { }
+static void noop_send_IPI_mask_allbutself(const struct cpumask *cpumask, int vector) { }
+static void noop_send_IPI_allbutself(int vector) { }
+static void noop_send_IPI_all(int vector) { }
+static void noop_send_IPI_self(int vector) { }
+static void noop_apic_wait_icr_idle(void) { }
+static void noop_apic_icr_write(u32 low, u32 id) { }
+
+static int noop_wakeup_secondary_cpu(int apicid, unsigned long start_eip)
+{
+       return -1;
+}
+
+static u32 noop_safe_apic_wait_icr_idle(void)
+{
+       return 0;
+}
+
+static u64 noop_apic_icr_read(void)
+{
+       return 0;
+}
+
+static int noop_cpu_to_logical_apicid(int cpu)
+{
+       return 0;
+}
+
+static int noop_phys_pkg_id(int cpuid_apic, int index_msb)
+{
+       return 0;
+}
+
+static unsigned int noop_get_apic_id(unsigned long x)
+{
+       return 0;
+}
+
+static int noop_probe(void)
+{
+       /*
+        * NOOP apic should not ever be
+        * enabled via probe routine
+        */
+       return 0;
+}
+
+static int noop_apic_id_registered(void)
+{
+       /*
+        * if we would be really "pedantic"
+        * we should pass read_apic_id() here
+        * but since NOOP suppose APIC ID = 0
+        * lets save a few cycles
+        */
+       return physid_isset(0, phys_cpu_present_map);
+}
+
+static const struct cpumask *noop_target_cpus(void)
+{
+       /* only BSP here */
+       return cpumask_of(0);
+}
+
+static unsigned long noop_check_apicid_used(physid_mask_t *map, int apicid)
+{
+       return physid_isset(apicid, *map);
+}
+
+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)
+{
+       if (cpu != 0)
+               pr_warning("APIC: Vector allocated for non-BSP cpu\n");
+       cpumask_clear(retmask);
+       cpumask_set_cpu(cpu, retmask);
+}
+
+int noop_apicid_to_node(int logical_apicid)
+{
+       /* we're always on node 0 */
+       return 0;
+}
+
+static u32 noop_apic_read(u32 reg)
+{
+       WARN_ON_ONCE((cpu_has_apic && !disable_apic));
+       return 0;
+}
+
+static void noop_apic_write(u32 reg, u32 v)
+{
+       WARN_ON_ONCE((cpu_has_apic || !disable_apic));
+}
+
+struct apic apic_noop = {
+       .name                           = "noop",
+       .probe                          = noop_probe,
+       .acpi_madt_oem_check            = NULL,
+
+       .apic_id_registered             = noop_apic_id_registered,
+
+       .irq_delivery_mode              = dest_LowestPrio,
+       /* logical delivery broadcast to all CPUs: */
+       .irq_dest_mode                  = 1,
+
+       .target_cpus                    = noop_target_cpus,
+       .disable_esr                    = 0,
+       .dest_logical                   = APIC_DEST_LOGICAL,
+       .check_apicid_used              = noop_check_apicid_used,
+       .check_apicid_present           = noop_check_apicid_present,
+
+       .vector_allocation_domain       = noop_vector_allocation_domain,
+       .init_apic_ldr                  = noop_init_apic_ldr,
+
+       .ioapic_phys_id_map             = default_ioapic_phys_id_map,
+       .setup_apic_routing             = NULL,
+       .multi_timer_check              = NULL,
+       .apicid_to_node                 = noop_apicid_to_node,
+
+       .cpu_to_logical_apicid          = noop_cpu_to_logical_apicid,
+       .cpu_present_to_apicid          = default_cpu_present_to_apicid,
+       .apicid_to_cpu_present          = physid_set_mask_of_physid,
+
+       .setup_portio_remap             = NULL,
+       .check_phys_apicid_present      = default_check_phys_apicid_present,
+       .enable_apic_mode               = NULL,
+
+       .phys_pkg_id                    = noop_phys_pkg_id,
+
+       .mps_oem_check                  = NULL,
+
+       .get_apic_id                    = noop_get_apic_id,
+       .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,
+
+       .send_IPI_mask                  = noop_send_IPI_mask,
+       .send_IPI_mask_allbutself       = noop_send_IPI_mask_allbutself,
+       .send_IPI_allbutself            = noop_send_IPI_allbutself,
+       .send_IPI_all                   = noop_send_IPI_all,
+       .send_IPI_self                  = noop_send_IPI_self,
+
+       .wakeup_secondary_cpu           = noop_wakeup_secondary_cpu,
+
+       /* should be safe */
+       .trampoline_phys_low            = DEFAULT_TRAMPOLINE_PHYS_LOW,
+       .trampoline_phys_high           = DEFAULT_TRAMPOLINE_PHYS_HIGH,
+
+       .wait_for_init_deassert         = NULL,
+
+       .smp_callin_clear_local_apic    = NULL,
+       .inquire_remote_apic            = NULL,
+
+       .read                           = noop_apic_read,
+       .write                          = noop_apic_write,
+       .icr_read                       = noop_apic_icr_read,
+       .icr_write                      = noop_apic_icr_write,
+       .wait_icr_idle                  = noop_apic_wait_icr_idle,
+       .safe_wait_icr_idle             = noop_safe_apic_wait_icr_idle,
+};
index 77a0641..38dcecf 100644 (file)
@@ -35,7 +35,7 @@ static const struct cpumask *bigsmp_target_cpus(void)
 #endif
 }
 
-static unsigned long bigsmp_check_apicid_used(physid_mask_t bitmap, int apicid)
+static unsigned long bigsmp_check_apicid_used(physid_mask_t *map, int apicid)
 {
        return 0;
 }
@@ -93,11 +93,6 @@ static int bigsmp_cpu_present_to_apicid(int mps_cpu)
        return BAD_APICID;
 }
 
-static physid_mask_t bigsmp_apicid_to_cpu_present(int phys_apicid)
-{
-       return physid_mask_of_physid(phys_apicid);
-}
-
 /* Mapping from cpu number to logical apicid */
 static inline int bigsmp_cpu_to_logical_apicid(int cpu)
 {
@@ -106,10 +101,10 @@ static inline int bigsmp_cpu_to_logical_apicid(int cpu)
        return cpu_physical_id(cpu);
 }
 
-static physid_mask_t bigsmp_ioapic_phys_id_map(physid_mask_t phys_map)
+static void bigsmp_ioapic_phys_id_map(physid_mask_t *phys_map, physid_mask_t *retmap)
 {
        /* For clustered we don't have a good way to do this yet - hack */
-       return physids_promote(0xFFL);
+       physids_promote(0xFFL, retmap);
 }
 
 static int bigsmp_check_phys_apicid_present(int phys_apicid)
@@ -230,7 +225,7 @@ struct apic apic_bigsmp = {
        .apicid_to_node                 = bigsmp_apicid_to_node,
        .cpu_to_logical_apicid          = bigsmp_cpu_to_logical_apicid,
        .cpu_present_to_apicid          = bigsmp_cpu_present_to_apicid,
-       .apicid_to_cpu_present          = bigsmp_apicid_to_cpu_present,
+       .apicid_to_cpu_present          = physid_set_mask_of_physid,
        .setup_portio_remap             = NULL,
        .check_phys_apicid_present      = bigsmp_check_phys_apicid_present,
        .enable_apic_mode               = NULL,
index 89174f8..e85f8fb 100644 (file)
@@ -466,11 +466,11 @@ static const struct cpumask *es7000_target_cpus(void)
        return cpumask_of(smp_processor_id());
 }
 
-static unsigned long
-es7000_check_apicid_used(physid_mask_t bitmap, int apicid)
+static unsigned long es7000_check_apicid_used(physid_mask_t *map, int apicid)
 {
        return 0;
 }
+
 static unsigned long es7000_check_apicid_present(int bit)
 {
        return physid_isset(bit, phys_cpu_present_map);
@@ -539,14 +539,10 @@ static int es7000_cpu_present_to_apicid(int mps_cpu)
 
 static int cpu_id;
 
-static physid_mask_t es7000_apicid_to_cpu_present(int phys_apicid)
+static void es7000_apicid_to_cpu_present(int phys_apicid, physid_mask_t *retmap)
 {
-       physid_mask_t mask;
-
-       mask = physid_mask_of_physid(cpu_id);
+       physid_set_mask_of_physid(cpu_id, retmap);
        ++cpu_id;
-
-       return mask;
 }
 
 /* Mapping from cpu number to logical apicid */
@@ -561,10 +557,10 @@ static int es7000_cpu_to_logical_apicid(int cpu)
 #endif
 }
 
-static physid_mask_t es7000_ioapic_phys_id_map(physid_mask_t phys_map)
+static void es7000_ioapic_phys_id_map(physid_mask_t *phys_map, physid_mask_t *retmap)
 {
        /* For clustered we don't have a good way to do this yet - hack */
-       return physids_promote(0xff);
+       physids_promote(0xFFL, retmap);
 }
 
 static int es7000_check_phys_apicid_present(int cpu_physical_apicid)
index dc69f28..c0b4468 100644 (file)
@@ -60,8 +60,6 @@
 #include <asm/irq_remapping.h>
 #include <asm/hpet.h>
 #include <asm/hw_irq.h>
-#include <asm/uv/uv_hub.h>
-#include <asm/uv/uv_irq.h>
 
 #include <asm/apic.h>
 
@@ -140,20 +138,6 @@ static struct irq_pin_list *get_one_free_irq_2_pin(int node)
        return pin;
 }
 
-/*
- * This is performance-critical, we want to do it O(1)
- *
- * Most irqs are mapped 1:1 with pins.
- */
-struct irq_cfg {
-       struct irq_pin_list *irq_2_pin;
-       cpumask_var_t domain;
-       cpumask_var_t old_domain;
-       unsigned move_cleanup_count;
-       u8 vector;
-       u8 move_in_progress : 1;
-};
-
 /* irq_cfg is indexed by the sum of all RTEs in all I/O APICs. */
 #ifdef CONFIG_SPARSE_IRQ
 static struct irq_cfg irq_cfgx[] = {
@@ -209,7 +193,7 @@ int __init arch_early_irq_init(void)
 }
 
 #ifdef CONFIG_SPARSE_IRQ
-static struct irq_cfg *irq_cfg(unsigned int irq)
+struct irq_cfg *irq_cfg(unsigned int irq)
 {
        struct irq_cfg *cfg = NULL;
        struct irq_desc *desc;
@@ -361,7 +345,7 @@ void arch_free_chip_data(struct irq_desc *old_desc, struct irq_desc *desc)
 /* end for move_irq_desc */
 
 #else
-static struct irq_cfg *irq_cfg(unsigned int irq)
+struct irq_cfg *irq_cfg(unsigned int irq)
 {
        return irq < nr_irqs ? irq_cfgx + irq : NULL;
 }
@@ -555,23 +539,41 @@ static void __init replace_pin_at_irq_node(struct irq_cfg *cfg, int node,
        add_pin_to_irq_node(cfg, node, newapic, newpin);
 }
 
+static void __io_apic_modify_irq(struct irq_pin_list *entry,
+                                int mask_and, int mask_or,
+                                void (*final)(struct irq_pin_list *entry))
+{
+       unsigned int reg, pin;
+
+       pin = entry->pin;
+       reg = io_apic_read(entry->apic, 0x10 + pin * 2);
+       reg &= mask_and;
+       reg |= mask_or;
+       io_apic_modify(entry->apic, 0x10 + pin * 2, reg);
+       if (final)
+               final(entry);
+}
+
 static void io_apic_modify_irq(struct irq_cfg *cfg,
                               int mask_and, int mask_or,
                               void (*final)(struct irq_pin_list *entry))
 {
-       int pin;
        struct irq_pin_list *entry;
 
-       for_each_irq_pin(entry, cfg->irq_2_pin) {
-               unsigned int reg;
-               pin = entry->pin;
-               reg = io_apic_read(entry->apic, 0x10 + pin * 2);
-               reg &= mask_and;
-               reg |= mask_or;
-               io_apic_modify(entry->apic, 0x10 + pin * 2, reg);
-               if (final)
-                       final(entry);
-       }
+       for_each_irq_pin(entry, cfg->irq_2_pin)
+               __io_apic_modify_irq(entry, mask_and, mask_or, final);
+}
+
+static void __mask_and_edge_IO_APIC_irq(struct irq_pin_list *entry)
+{
+       __io_apic_modify_irq(entry, ~IO_APIC_REDIR_LEVEL_TRIGGER,
+                            IO_APIC_REDIR_MASKED, NULL);
+}
+
+static void __unmask_and_level_IO_APIC_irq(struct irq_pin_list *entry)
+{
+       __io_apic_modify_irq(entry, ~IO_APIC_REDIR_MASKED,
+                            IO_APIC_REDIR_LEVEL_TRIGGER, NULL);
 }
 
 static void __unmask_IO_APIC_irq(struct irq_cfg *cfg)
@@ -595,18 +597,6 @@ static void __mask_IO_APIC_irq(struct irq_cfg *cfg)
        io_apic_modify_irq(cfg, ~0, IO_APIC_REDIR_MASKED, &io_apic_sync);
 }
 
-static void __mask_and_edge_IO_APIC_irq(struct irq_cfg *cfg)
-{
-       io_apic_modify_irq(cfg, ~IO_APIC_REDIR_LEVEL_TRIGGER,
-                       IO_APIC_REDIR_MASKED, NULL);
-}
-
-static void __unmask_and_level_IO_APIC_irq(struct irq_cfg *cfg)
-{
-       io_apic_modify_irq(cfg, ~IO_APIC_REDIR_MASKED,
-                       IO_APIC_REDIR_LEVEL_TRIGGER, NULL);
-}
-
 static void mask_IO_APIC_irq_desc(struct irq_desc *desc)
 {
        struct irq_cfg *cfg = desc->chip_data;
@@ -1177,7 +1167,7 @@ __assign_irq_vector(int irq, struct irq_cfg *cfg, const struct cpumask *mask)
        int cpu, err;
        cpumask_var_t tmp_mask;
 
-       if ((cfg->move_in_progress) || cfg->move_cleanup_count)
+       if (cfg->move_in_progress)
                return -EBUSY;
 
        if (!alloc_cpumask_var(&tmp_mask, GFP_ATOMIC))
@@ -1237,8 +1227,7 @@ next:
        return err;
 }
 
-static int
-assign_irq_vector(int irq, struct irq_cfg *cfg, const struct cpumask *mask)
+int assign_irq_vector(int irq, struct irq_cfg *cfg, const struct cpumask *mask)
 {
        int err;
        unsigned long flags;
@@ -1599,9 +1588,6 @@ __apicdebuginit(void) print_IO_APIC(void)
        struct irq_desc *desc;
        unsigned int irq;
 
-       if (apic_verbosity == APIC_QUIET)
-               return;
-
        printk(KERN_DEBUG "number of MP IRQ sources: %d.\n", mp_irq_entries);
        for (i = 0; i < nr_ioapics; i++)
                printk(KERN_DEBUG "number of IO-APIC #%d registers: %d.\n",
@@ -1708,9 +1694,6 @@ __apicdebuginit(void) print_APIC_field(int base)
 {
        int i;
 
-       if (apic_verbosity == APIC_QUIET)
-               return;
-
        printk(KERN_DEBUG);
 
        for (i = 0; i < 8; i++)
@@ -1724,9 +1707,6 @@ __apicdebuginit(void) print_local_APIC(void *dummy)
        unsigned int i, v, ver, maxlvt;
        u64 icr;
 
-       if (apic_verbosity == APIC_QUIET)
-               return;
-
        printk(KERN_DEBUG "printing local APIC contents on CPU#%d/%d:\n",
                smp_processor_id(), hard_smp_processor_id());
        v = apic_read(APIC_ID);
@@ -1824,13 +1804,19 @@ __apicdebuginit(void) print_local_APIC(void *dummy)
        printk("\n");
 }
 
-__apicdebuginit(void) print_all_local_APICs(void)
+__apicdebuginit(void) print_local_APICs(int maxcpu)
 {
        int cpu;
 
+       if (!maxcpu)
+               return;
+
        preempt_disable();
-       for_each_online_cpu(cpu)
+       for_each_online_cpu(cpu) {
+               if (cpu >= maxcpu)
+                       break;
                smp_call_function_single(cpu, print_local_APIC, NULL, 1);
+       }
        preempt_enable();
 }
 
@@ -1839,7 +1825,7 @@ __apicdebuginit(void) print_PIC(void)
        unsigned int v;
        unsigned long flags;
 
-       if (apic_verbosity == APIC_QUIET || !nr_legacy_irqs)
+       if (!nr_legacy_irqs)
                return;
 
        printk(KERN_DEBUG "\nprinting PIC contents\n");
@@ -1866,21 +1852,41 @@ __apicdebuginit(void) print_PIC(void)
        printk(KERN_DEBUG "... PIC ELCR: %04x\n", v);
 }
 
-__apicdebuginit(int) print_all_ICs(void)
+static int __initdata show_lapic = 1;
+static __init int setup_show_lapic(char *arg)
 {
+       int num = -1;
+
+       if (strcmp(arg, "all") == 0) {
+               show_lapic = CONFIG_NR_CPUS;
+       } else {
+               get_option(&arg, &num);
+               if (num >= 0)
+                       show_lapic = num;
+       }
+
+       return 1;
+}
+__setup("show_lapic=", setup_show_lapic);
+
+__apicdebuginit(int) print_ICs(void)
+{
+       if (apic_verbosity == APIC_QUIET)
+               return 0;
+
        print_PIC();
 
        /* don't print out if apic is not there */
        if (!cpu_has_apic && !apic_from_smp_config())
                return 0;
 
-       print_all_local_APICs();
+       print_local_APICs(show_lapic);
        print_IO_APIC();
 
        return 0;
 }
 
-fs_initcall(print_all_ICs);
+fs_initcall(print_ICs);
 
 
 /* Where if anywhere is the i8259 connect in external int mode */
@@ -2031,7 +2037,7 @@ void __init setup_ioapic_ids_from_mpc(void)
         * This is broken; anything with a real cpu count has to
         * circumvent this idiocy regardless.
         */
-       phys_id_present_map = apic->ioapic_phys_id_map(phys_cpu_present_map);
+       apic->ioapic_phys_id_map(&phys_cpu_present_map, &phys_id_present_map);
 
        /*
         * Set the IOAPIC ID to the value stored in the MPC table.
@@ -2058,7 +2064,7 @@ void __init setup_ioapic_ids_from_mpc(void)
                 * system must have a unique ID or we get lots of nice
                 * 'stuck on smp_invalidate_needed IPI wait' messages.
                 */
-               if (apic->check_apicid_used(phys_id_present_map,
+               if (apic->check_apicid_used(&phys_id_present_map,
                                        mp_ioapics[apic_id].apicid)) {
                        printk(KERN_ERR "BIOS bug, IO-APIC#%d ID %d is already used!...\n",
                                apic_id, mp_ioapics[apic_id].apicid);
@@ -2073,7 +2079,7 @@ void __init setup_ioapic_ids_from_mpc(void)
                        mp_ioapics[apic_id].apicid = i;
                } else {
                        physid_mask_t tmp;
-                       tmp = apic->apicid_to_cpu_present(mp_ioapics[apic_id].apicid);
+                       apic->apicid_to_cpu_present(mp_ioapics[apic_id].apicid, &tmp);
                        apic_printk(APIC_VERBOSE, "Setting %d in the "
                                        "phys_id_present_map\n",
                                        mp_ioapics[apic_id].apicid);
@@ -2228,20 +2234,16 @@ static int ioapic_retrigger_irq(unsigned int irq)
  */
 
 #ifdef CONFIG_SMP
-static void send_cleanup_vector(struct irq_cfg *cfg)
+void send_cleanup_vector(struct irq_cfg *cfg)
 {
        cpumask_var_t cleanup_mask;
 
        if (unlikely(!alloc_cpumask_var(&cleanup_mask, GFP_ATOMIC))) {
                unsigned int i;
-               cfg->move_cleanup_count = 0;
-               for_each_cpu_and(i, cfg->old_domain, cpu_online_mask)
-                       cfg->move_cleanup_count++;
                for_each_cpu_and(i, cfg->old_domain, cpu_online_mask)
                        apic->send_IPI_mask(cpumask_of(i), IRQ_MOVE_CLEANUP_VECTOR);
        } else {
                cpumask_and(cleanup_mask, cfg->old_domain, cpu_online_mask);
-               cfg->move_cleanup_count = cpumask_weight(cleanup_mask);
                apic->send_IPI_mask(cleanup_mask, IRQ_MOVE_CLEANUP_VECTOR);
                free_cpumask_var(cleanup_mask);
        }
@@ -2272,15 +2274,12 @@ static void __target_IO_APIC_irq(unsigned int irq, unsigned int dest, struct irq
        }
 }
 
-static int
-assign_irq_vector(int irq, struct irq_cfg *cfg, const struct cpumask *mask);
-
 /*
  * Either sets desc->affinity to a valid value, and returns
  * ->cpu_mask_to_apicid of that, or returns BAD_APICID and
  * leaves desc->affinity untouched.
  */
-static unsigned int
+unsigned int
 set_desc_affinity(struct irq_desc *desc, const struct cpumask *mask)
 {
        struct irq_cfg *cfg;
@@ -2433,8 +2432,6 @@ asmlinkage void smp_irq_move_cleanup_interrupt(void)
 
                cfg = irq_cfg(irq);
                spin_lock(&desc->lock);
-               if (!cfg->move_cleanup_count)
-                       goto unlock;
 
                if (vector == cfg->vector && cpumask_test_cpu(me, cfg->domain))
                        goto unlock;
@@ -2452,7 +2449,6 @@ asmlinkage void smp_irq_move_cleanup_interrupt(void)
                        goto unlock;
                }
                __get_cpu_var(vector_irq)[vector] = -1;
-               cfg->move_cleanup_count--;
 unlock:
                spin_unlock(&desc->lock);
        }
@@ -2460,21 +2456,33 @@ unlock:
        irq_exit();
 }
 
-static void irq_complete_move(struct irq_desc **descp)
+static void __irq_complete_move(struct irq_desc **descp, unsigned vector)
 {
        struct irq_desc *desc = *descp;
        struct irq_cfg *cfg = desc->chip_data;
-       unsigned vector, me;
+       unsigned me;
 
        if (likely(!cfg->move_in_progress))
                return;
 
-       vector = ~get_irq_regs()->orig_ax;
        me = smp_processor_id();
 
        if (vector == cfg->vector && cpumask_test_cpu(me, cfg->domain))
                send_cleanup_vector(cfg);
 }
+
+static void irq_complete_move(struct irq_desc **descp)
+{
+       __irq_complete_move(descp, ~get_irq_regs()->orig_ax);
+}
+
+void irq_force_complete_move(int irq)
+{
+       struct irq_desc *desc = irq_to_desc(irq);
+       struct irq_cfg *cfg = desc->chip_data;
+
+       __irq_complete_move(&desc, cfg->vector);
+}
 #else
 static inline void irq_complete_move(struct irq_desc **descp) {}
 #endif
@@ -2490,6 +2498,59 @@ static void ack_apic_edge(unsigned int irq)
 
 atomic_t irq_mis_count;
 
+/*
+ * IO-APIC versions below 0x20 don't support EOI register.
+ * For the record, here is the information about various versions:
+ *     0Xh     82489DX
+ *     1Xh     I/OAPIC or I/O(x)APIC which are not PCI 2.2 Compliant
+ *     2Xh     I/O(x)APIC which is PCI 2.2 Compliant
+ *     30h-FFh Reserved
+ *
+ * Some of the Intel ICH Specs (ICH2 to ICH5) documents the io-apic
+ * version as 0x2. This is an error with documentation and these ICH chips
+ * use io-apic's of version 0x20.
+ *
+ * For IO-APIC's with EOI register, we use that to do an explicit EOI.
+ * Otherwise, we simulate the EOI message manually by changing the trigger
+ * mode to edge and then back to level, with RTE being masked during this.
+*/
+static void __eoi_ioapic_irq(unsigned int irq, struct irq_cfg *cfg)
+{
+       struct irq_pin_list *entry;
+
+       for_each_irq_pin(entry, cfg->irq_2_pin) {
+               if (mp_ioapics[entry->apic].apicver >= 0x20) {
+                       /*
+                        * Intr-remapping uses pin number as the virtual vector
+                        * in the RTE. Actual vector is programmed in
+                        * intr-remapping table entry. Hence for the io-apic
+                        * EOI we use the pin number.
+                        */
+                       if (irq_remapped(irq))
+                               io_apic_eoi(entry->apic, entry->pin);
+                       else
+                               io_apic_eoi(entry->apic, cfg->vector);
+               } else {
+                       __mask_and_edge_IO_APIC_irq(entry);
+                       __unmask_and_level_IO_APIC_irq(entry);
+               }
+       }
+}
+
+static void eoi_ioapic_irq(struct irq_desc *desc)
+{
+       struct irq_cfg *cfg;
+       unsigned long flags;
+       unsigned int irq;
+
+       irq = desc->irq;
+       cfg = desc->chip_data;
+
+       spin_lock_irqsave(&ioapic_lock, flags);
+       __eoi_ioapic_irq(irq, cfg);
+       spin_unlock_irqrestore(&ioapic_lock, flags);
+}
+
 static void ack_apic_level(unsigned int irq)
 {
        struct irq_desc *desc = irq_to_desc(irq);
@@ -2525,6 +2586,19 @@ static void ack_apic_level(unsigned int irq)
         * level-triggered interrupt.  We mask the source for the time of the
         * operation to prevent an edge-triggered interrupt escaping meanwhile.
         * The idea is from Manfred Spraul.  --macro
+        *
+        * Also in the case when cpu goes offline, fixup_irqs() will forward
+        * any unhandled interrupt on the offlined cpu to the new cpu
+        * destination that is handling the corresponding interrupt. This
+        * interrupt forwarding is done via IPI's. Hence, in this case also
+        * level-triggered io-apic interrupt will be seen as an edge
+        * interrupt in the IRR. And we can't rely on the cpu's EOI
+        * to be broadcasted to the IO-APIC's which will clear the remoteIRR
+        * corresponding to the level-triggered interrupt. Hence on IO-APIC's
+        * supporting EOI register, we do an explicit EOI to clear the
+        * remote IRR and on IO-APIC's which don't have an EOI register,
+        * we use the above logic (mask+edge followed by unmask+level) from
+        * Manfred Spraul to clear the remote IRR.
         */
        cfg = desc->chip_data;
        i = cfg->vector;
@@ -2536,6 +2610,19 @@ static void ack_apic_level(unsigned int irq)
         */
        ack_APIC_irq();
 
+       /*
+        * Tail end of clearing remote IRR bit (either by delivering the EOI
+        * message via io-apic EOI register write or simulating it using
+        * mask+edge followed by unnask+level logic) manually when the
+        * level triggered interrupt is seen as the edge triggered interrupt
+        * at the cpu.
+        */
+       if (!(v & (1 << (i & 0x1f)))) {
+               atomic_inc(&irq_mis_count);
+
+               eoi_ioapic_irq(desc);
+       }
+
        /* Now we can move and renable the irq */
        if (unlikely(do_unmask_irq)) {
                /* Only migrate the irq if the ack has been received.
@@ -2569,41 +2656,9 @@ static void ack_apic_level(unsigned int irq)
                        move_masked_irq(irq);
                unmask_IO_APIC_irq_desc(desc);
        }
-
-       /* Tail end of version 0x11 I/O APIC bug workaround */
-       if (!(v & (1 << (i & 0x1f)))) {
-               atomic_inc(&irq_mis_count);
-               spin_lock(&ioapic_lock);
-               __mask_and_edge_IO_APIC_irq(cfg);
-               __unmask_and_level_IO_APIC_irq(cfg);
-               spin_unlock(&ioapic_lock);
-       }
 }
 
 #ifdef CONFIG_INTR_REMAP
-static void __eoi_ioapic_irq(unsigned int irq, struct irq_cfg *cfg)
-{
-       struct irq_pin_list *entry;
-
-       for_each_irq_pin(entry, cfg->irq_2_pin)
-               io_apic_eoi(entry->apic, entry->pin);
-}
-
-static void
-eoi_ioapic_irq(struct irq_desc *desc)
-{
-       struct irq_cfg *cfg;
-       unsigned long flags;
-       unsigned int irq;
-
-       irq = desc->irq;
-       cfg = desc->chip_data;
-
-       spin_lock_irqsave(&ioapic_lock, flags);
-       __eoi_ioapic_irq(irq, cfg);
-       spin_unlock_irqrestore(&ioapic_lock, flags);
-}
-
 static void ir_ack_apic_edge(unsigned int irq)
 {
        ack_APIC_irq();
@@ -3157,6 +3212,7 @@ unsigned int create_irq_nr(unsigned int irq_want, int node)
                        continue;
 
                desc_new = move_irq_desc(desc_new, node);
+               cfg_new = desc_new->chip_data;
 
                if (__assign_irq_vector(new, cfg_new, apic->target_cpus()) == 0)
                        irq = new;
@@ -3708,75 +3764,6 @@ int arch_setup_ht_irq(unsigned int irq, struct pci_dev *dev)
 }
 #endif /* CONFIG_HT_IRQ */
 
-#ifdef CONFIG_X86_UV
-/*
- * Re-target the irq to the specified CPU and enable the specified MMR located
- * on the specified blade to allow the sending of MSIs to the specified CPU.
- */
-int arch_enable_uv_irq(char *irq_name, unsigned int irq, int cpu, int mmr_blade,
-                      unsigned long mmr_offset)
-{
-       const struct cpumask *eligible_cpu = cpumask_of(cpu);
-       struct irq_cfg *cfg;
-       int mmr_pnode;
-       unsigned long mmr_value;
-       struct uv_IO_APIC_route_entry *entry;
-       unsigned long flags;
-       int err;
-
-       BUILD_BUG_ON(sizeof(struct uv_IO_APIC_route_entry) != sizeof(unsigned long));
-
-       cfg = irq_cfg(irq);
-
-       err = assign_irq_vector(irq, cfg, eligible_cpu);
-       if (err != 0)
-               return err;
-
-       spin_lock_irqsave(&vector_lock, flags);
-       set_irq_chip_and_handler_name(irq, &uv_irq_chip, handle_percpu_irq,
-                                     irq_name);
-       spin_unlock_irqrestore(&vector_lock, flags);
-
-       mmr_value = 0;
-       entry = (struct uv_IO_APIC_route_entry *)&mmr_value;
-       entry->vector           = cfg->vector;
-       entry->delivery_mode    = apic->irq_delivery_mode;
-       entry->dest_mode        = apic->irq_dest_mode;
-       entry->polarity         = 0;
-       entry->trigger          = 0;
-       entry->mask             = 0;
-       entry->dest             = apic->cpu_mask_to_apicid(eligible_cpu);
-
-       mmr_pnode = uv_blade_to_pnode(mmr_blade);
-       uv_write_global_mmr64(mmr_pnode, mmr_offset, mmr_value);
-
-       if (cfg->move_in_progress)
-               send_cleanup_vector(cfg);
-
-       return irq;
-}
-
-/*
- * Disable the specified MMR located on the specified blade so that MSIs are
- * longer allowed to be sent.
- */
-void arch_disable_uv_irq(int mmr_blade, unsigned long mmr_offset)
-{
-       unsigned long mmr_value;
-       struct uv_IO_APIC_route_entry *entry;
-       int mmr_pnode;
-
-       BUILD_BUG_ON(sizeof(struct uv_IO_APIC_route_entry) != sizeof(unsigned long));
-
-       mmr_value = 0;
-       entry = (struct uv_IO_APIC_route_entry *)&mmr_value;
-       entry->mask = 1;
-
-       mmr_pnode = uv_blade_to_pnode(mmr_blade);
-       uv_write_global_mmr64(mmr_pnode, mmr_offset, mmr_value);
-}
-#endif /* CONFIG_X86_64 */
-
 int __init io_apic_get_redir_entries (int ioapic)
 {
        union IO_APIC_reg_01    reg_01;
@@ -3944,7 +3931,7 @@ int __init io_apic_get_unique_id(int ioapic, int apic_id)
         */
 
        if (physids_empty(apic_id_map))
-               apic_id_map = apic->ioapic_phys_id_map(phys_cpu_present_map);
+               apic->ioapic_phys_id_map(&phys_cpu_present_map, &apic_id_map);
 
        spin_lock_irqsave(&ioapic_lock, flags);
        reg_00.raw = io_apic_read(ioapic, 0);
@@ -3960,10 +3947,10 @@ int __init io_apic_get_unique_id(int ioapic, int apic_id)
         * Every APIC in a system must have a unique ID or we get lots of nice
         * 'stuck on smp_invalidate_needed IPI wait' messages.
         */
-       if (apic->check_apicid_used(apic_id_map, apic_id)) {
+       if (apic->check_apicid_used(&apic_id_map, apic_id)) {
 
                for (i = 0; i < get_physical_broadcast(); i++) {
-                       if (!apic->check_apicid_used(apic_id_map, i))
+                       if (!apic->check_apicid_used(&apic_id_map, i))
                                break;
                }
 
@@ -3976,7 +3963,7 @@ int __init io_apic_get_unique_id(int ioapic, int apic_id)
                apic_id = i;
        }
 
-       tmp = apic->apicid_to_cpu_present(apic_id);
+       apic->apicid_to_cpu_present(apic_id, &tmp);
        physids_or(apic_id_map, apic_id_map, tmp);
 
        if (reg_00.bits.ID != apic_id) {
@@ -4106,7 +4093,7 @@ static struct resource * __init ioapic_setup_resources(int nr_ioapics)
        for (i = 0; i < nr_ioapics; i++) {
                res[i].name = mem;
                res[i].flags = IORESOURCE_MEM | IORESOURCE_BUSY;
-               sprintf(mem,  "IOAPIC %u", i);
+               snprintf(mem, IOAPIC_RESOURCE_NAME_SIZE, "IOAPIC %u", i);
                mem += IOAPIC_RESOURCE_NAME_SIZE;
        }
 
@@ -4140,18 +4127,17 @@ void __init ioapic_init_mappings(void)
 #ifdef CONFIG_X86_32
 fake_ioapic_page:
 #endif
-                       ioapic_phys = (unsigned long)
-                               alloc_bootmem_pages(PAGE_SIZE);
+                       ioapic_phys = (unsigned long)alloc_bootmem_pages(PAGE_SIZE);
                        ioapic_phys = __pa(ioapic_phys);
                }
                set_fixmap_nocache(idx, ioapic_phys);
-               apic_printk(APIC_VERBOSE,
-                           "mapped IOAPIC to %08lx (%08lx)\n",
-                           __fix_to_virt(idx), ioapic_phys);
+               apic_printk(APIC_VERBOSE, "mapped IOAPIC to %08lx (%08lx)\n",
+                       __fix_to_virt(idx) + (ioapic_phys & ~PAGE_MASK),
+                       ioapic_phys);
                idx++;
 
                ioapic_res->start = ioapic_phys;
-               ioapic_res->end = ioapic_phys + (4 * 1024) - 1;
+               ioapic_res->end = ioapic_phys + IO_APIC_SLOT_SIZE - 1;
                ioapic_res++;
        }
 }
index 7ff61d6..6389432 100644 (file)
@@ -39,7 +39,8 @@
 int unknown_nmi_panic;
 int nmi_watchdog_enabled;
 
-static cpumask_t backtrace_mask __read_mostly;
+/* For reliability, we're prepared to waste bits here. */
+static DECLARE_BITMAP(backtrace_mask, NR_CPUS) __read_mostly;
 
 /* nmi_active:
  * >0: the lapic NMI watchdog is active, but can be disabled
@@ -414,7 +415,7 @@ nmi_watchdog_tick(struct pt_regs *regs, unsigned reason)
        }
 
        /* We can be called before check_nmi_watchdog, hence NULL check. */
-       if (cpumask_test_cpu(cpu, &backtrace_mask)) {
+       if (cpumask_test_cpu(cpu, to_cpumask(backtrace_mask))) {
                static DEFINE_SPINLOCK(lock);   /* Serialise the printks */
 
                spin_lock(&lock);
@@ -422,7 +423,7 @@ nmi_watchdog_tick(struct pt_regs *regs, unsigned reason)
                show_regs(regs);
                dump_stack();
                spin_unlock(&lock);
-               cpumask_clear_cpu(cpu, &backtrace_mask);
+               cpumask_clear_cpu(cpu, to_cpumask(backtrace_mask));
 
                rc = 1;
        }
@@ -558,14 +559,14 @@ void arch_trigger_all_cpu_backtrace(void)
 {
        int i;
 
-       cpumask_copy(&backtrace_mask, cpu_online_mask);
+       cpumask_copy(to_cpumask(backtrace_mask), cpu_online_mask);
 
        printk(KERN_INFO "sending NMI to all CPUs:\n");
        apic->send_IPI_all(NMI_VECTOR);
 
        /* Wait for up to 10 seconds for all CPUs to do the backtrace */
        for (i = 0; i < 10 * 1000; i++) {
-               if (cpumask_empty(&backtrace_mask))
+               if (cpumask_empty(to_cpumask(backtrace_mask)))
                        break;
                mdelay(1);
        }
index efa00e2..07cdbdc 100644 (file)
@@ -334,10 +334,9 @@ static inline const struct cpumask *numaq_target_cpus(void)
        return cpu_all_mask;
 }
 
-static inline unsigned long
-numaq_check_apicid_used(physid_mask_t bitmap, int apicid)
+static unsigned long numaq_check_apicid_used(physid_mask_t *map, int apicid)
 {
-       return physid_isset(apicid, bitmap);
+       return physid_isset(apicid, *map);
 }
 
 static inline unsigned long numaq_check_apicid_present(int bit)
@@ -371,10 +370,10 @@ static inline int numaq_multi_timer_check(int apic, int irq)
        return apic != 0 && irq == 0;
 }
 
-static inline physid_mask_t numaq_ioapic_phys_id_map(physid_mask_t phys_map)
+static inline void numaq_ioapic_phys_id_map(physid_mask_t *phys_map, physid_mask_t *retmap)
 {
        /* We don't have a good way to do this yet - hack */
-       return physids_promote(0xFUL);
+       return physids_promote(0xFUL, retmap);
 }
 
 static inline int numaq_cpu_to_logical_apicid(int cpu)
@@ -402,12 +401,12 @@ static inline int numaq_apicid_to_node(int logical_apicid)
        return logical_apicid >> 4;
 }
 
-static inline physid_mask_t numaq_apicid_to_cpu_present(int logical_apicid)
+static void numaq_apicid_to_cpu_present(int logical_apicid, physid_mask_t *retmap)
 {
        int node = numaq_apicid_to_node(logical_apicid);
        int cpu = __ffs(logical_apicid & 0xf);
 
-       return physid_mask_of_physid(cpu + 4*node);
+       physid_set_mask_of_physid(cpu + 4*node, retmap);
 }
 
 /* Where the IO area was mapped on multiquad, always 0 otherwise */
index 0c0182c..1a6559f 100644 (file)
@@ -108,7 +108,7 @@ struct apic apic_default = {
        .apicid_to_node                 = default_apicid_to_node,
        .cpu_to_logical_apicid          = default_cpu_to_logical_apicid,
        .cpu_present_to_apicid          = default_cpu_present_to_apicid,
-       .apicid_to_cpu_present          = default_apicid_to_cpu_present,
+       .apicid_to_cpu_present          = physid_set_mask_of_physid,
        .setup_portio_remap             = NULL,
        .check_phys_apicid_present      = default_check_phys_apicid_present,
        .enable_apic_mode               = NULL,
index 645ecc4..9b41926 100644 (file)
@@ -183,7 +183,7 @@ static const struct cpumask *summit_target_cpus(void)
        return cpumask_of(0);
 }
 
-static unsigned long summit_check_apicid_used(physid_mask_t bitmap, int apicid)
+static unsigned long summit_check_apicid_used(physid_mask_t *map, int apicid)
 {
        return 0;
 }
@@ -261,15 +261,15 @@ static int summit_cpu_present_to_apicid(int mps_cpu)
                return BAD_APICID;
 }
 
-static physid_mask_t summit_ioapic_phys_id_map(physid_mask_t phys_id_map)
+static void summit_ioapic_phys_id_map(physid_mask_t *phys_id_map, physid_mask_t *retmap)
 {
        /* For clustered we don't have a good way to do this yet - hack */
-       return physids_promote(0x0F);
+       physids_promote(0x0FL, retmap);
 }
 
-static physid_mask_t summit_apicid_to_cpu_present(int apicid)
+static void summit_apicid_to_cpu_present(int apicid, physid_mask_t *retmap)
 {
-       return physid_mask_of_physid(0);
+       physid_set_mask_of_physid(0, retmap);
 }
 
 static int summit_check_phys_apicid_present(int physical_apicid)
index 326c254..130c4b9 100644 (file)
@@ -409,6 +409,12 @@ static __init void map_mmioh_high(int max_pnode)
                map_high("MMIOH", mmioh.s.base, shift, max_pnode, map_uc);
 }
 
+static __init void map_low_mmrs(void)
+{
+       init_extra_mapping_uc(UV_GLOBAL_MMR32_BASE, UV_GLOBAL_MMR32_SIZE);
+       init_extra_mapping_uc(UV_LOCAL_MMR_BASE, UV_LOCAL_MMR_SIZE);
+}
+
 static __init void uv_rtc_init(void)
 {
        long status;
@@ -550,6 +556,8 @@ void __init uv_system_init(void)
        unsigned long mmr_base, present, paddr;
        unsigned short pnode_mask;
 
+       map_low_mmrs();
+
        m_n_config.v = uv_read_local_mmr(UVH_SI_ADDR_MAP_CONFIG);
        m_val = m_n_config.s.m_skt;
        n_val = m_n_config.s.n_skt;
index 151ace6..b5b6b23 100644 (file)
 #include <linux/module.h>
 
 #include <linux/poll.h>
-#include <linux/smp_lock.h>
 #include <linux/types.h>
 #include <linux/stddef.h>
 #include <linux/timer.h>
@@ -403,6 +402,7 @@ static DECLARE_WAIT_QUEUE_HEAD(apm_waitqueue);
 static DECLARE_WAIT_QUEUE_HEAD(apm_suspend_waitqueue);
 static struct apm_user *user_list;
 static DEFINE_SPINLOCK(user_list_lock);
+static DEFINE_MUTEX(apm_mutex);
 
 /*
  * Set up a segment that references the real mode segment 0x40
@@ -1531,7 +1531,7 @@ static long do_ioctl(struct file *filp, u_int cmd, u_long arg)
                return -EPERM;
        switch (cmd) {
        case APM_IOC_STANDBY:
-               lock_kernel();
+               mutex_lock(&apm_mutex);
                if (as->standbys_read > 0) {
                        as->standbys_read--;
                        as->standbys_pending--;
@@ -1540,10 +1540,10 @@ static long do_ioctl(struct file *filp, u_int cmd, u_long arg)
                        queue_event(APM_USER_STANDBY, as);
                if (standbys_pending <= 0)
                        standby();
-               unlock_kernel();
+               mutex_unlock(&apm_mutex);
                break;
        case APM_IOC_SUSPEND:
-               lock_kernel();
+               mutex_lock(&apm_mutex);
                if (as->suspends_read > 0) {
                        as->suspends_read--;
                        as->suspends_pending--;
@@ -1552,13 +1552,14 @@ static long do_ioctl(struct file *filp, u_int cmd, u_long arg)
                        queue_event(APM_USER_SUSPEND, as);
                if (suspends_pending <= 0) {
                        ret = suspend(1);
+                       mutex_unlock(&apm_mutex);
                } else {
                        as->suspend_wait = 1;
+                       mutex_unlock(&apm_mutex);
                        wait_event_interruptible(apm_suspend_waitqueue,
                                        as->suspend_wait == 0);
                        ret = as->suspend_result;
                }
-               unlock_kernel();
                return ret;
        default:
                return -ENOTTY;
@@ -1608,12 +1609,10 @@ static int do_open(struct inode *inode, struct file *filp)
 {
        struct apm_user *as;
 
-       lock_kernel();
        as = kmalloc(sizeof(*as), GFP_KERNEL);
        if (as == NULL) {
                printk(KERN_ERR "apm: cannot allocate struct of size %d bytes\n",
                       sizeof(*as));
-                      unlock_kernel();
                return -ENOMEM;
        }
        as->magic = APM_BIOS_MAGIC;
@@ -1635,7 +1634,6 @@ static int do_open(struct inode *inode, struct file *filp)
        user_list = as;
        spin_unlock(&user_list_lock);
        filp->private_data = as;
-       unlock_kernel();
        return 0;
 }
 
index 68537e9..1d2cb38 100644 (file)
@@ -5,6 +5,7 @@
 # Don't trace early stages of a secondary CPU boot
 ifdef CONFIG_FUNCTION_TRACER
 CFLAGS_REMOVE_common.o = -pg
+CFLAGS_REMOVE_perf_event.o = -pg
 endif
 
 # Make sure load_percpu_segment has no stackprotector
index c910a71..7128b37 100644 (file)
@@ -535,7 +535,7 @@ static void __cpuinit init_amd(struct cpuinfo_x86 *c)
                }
        }
 
-       display_cacheinfo(c);
+       cpu_detect_cache_sizes(c);
 
        /* Multi core CPU? */
        if (c->extended_cpuid_level >= 0x80000008) {
index c95e831..e58d978 100644 (file)
@@ -294,7 +294,7 @@ static void __cpuinit init_c3(struct cpuinfo_x86 *c)
                set_cpu_cap(c, X86_FEATURE_REP_GOOD);
        }
 
-       display_cacheinfo(c);
+       cpu_detect_cache_sizes(c);
 }
 
 enum {
index cc25c2b..a4ec8b6 100644 (file)
@@ -61,7 +61,7 @@ void __init setup_cpu_local_masks(void)
 static void __cpuinit default_init(struct cpuinfo_x86 *c)
 {
 #ifdef CONFIG_X86_64
-       display_cacheinfo(c);
+       cpu_detect_cache_sizes(c);
 #else
        /* Not much we can do here... */
        /* Check if at least it has cpuid */
@@ -383,7 +383,7 @@ static void __cpuinit get_model_name(struct cpuinfo_x86 *c)
        }
 }
 
-void __cpuinit display_cacheinfo(struct cpuinfo_x86 *c)
+void __cpuinit cpu_detect_cache_sizes(struct cpuinfo_x86 *c)
 {
        unsigned int n, dummy, ebx, ecx, edx, l2size;
 
@@ -391,8 +391,6 @@ void __cpuinit display_cacheinfo(struct cpuinfo_x86 *c)
 
        if (n >= 0x80000005) {
                cpuid(0x80000005, &dummy, &ebx, &ecx, &edx);
-               printk(KERN_INFO "CPU: L1 I Cache: %dK (%d bytes/line), D cache %dK (%d bytes/line)\n",
-                               edx>>24, edx&0xFF, ecx>>24, ecx&0xFF);
                c->x86_cache_size = (ecx>>24) + (edx>>24);
 #ifdef CONFIG_X86_64
                /* On K8 L1 TLB is inclusive, so don't count it */
@@ -422,9 +420,6 @@ void __cpuinit display_cacheinfo(struct cpuinfo_x86 *c)
 #endif
 
        c->x86_cache_size = l2size;
-
-       printk(KERN_INFO "CPU: L2 Cache: %dK (%d bytes/line)\n",
-                       l2size, ecx & 0xFF);
 }
 
 void __cpuinit detect_ht(struct cpuinfo_x86 *c)
@@ -659,24 +654,31 @@ void __init early_cpu_init(void)
        const struct cpu_dev *const *cdev;
        int count = 0;
 
+#ifdef PROCESSOR_SELECT
        printk(KERN_INFO "KERNEL supported cpus:\n");
+#endif
+
        for (cdev = __x86_cpu_dev_start; cdev < __x86_cpu_dev_end; cdev++) {
                const struct cpu_dev *cpudev = *cdev;
-               unsigned int j;
 
                if (count >= X86_VENDOR_NUM)
                        break;
                cpu_devs[count] = cpudev;
                count++;
 
-               for (j = 0; j < 2; j++) {
-                       if (!cpudev->c_ident[j])
-                               continue;
-                       printk(KERN_INFO "  %s %s\n", cpudev->c_vendor,
-                               cpudev->c_ident[j]);
+#ifdef PROCESSOR_SELECT
+               {
+                       unsigned int j;
+
+                       for (j = 0; j < 2; j++) {
+                               if (!cpudev->c_ident[j])
+                                       continue;
+                               printk(KERN_INFO "  %s %s\n", cpudev->c_vendor,
+                                       cpudev->c_ident[j]);
+                       }
                }
+#endif
        }
-
        early_identify_cpu(&boot_cpu_data);
 }
 
@@ -837,10 +839,8 @@ static void __cpuinit identify_cpu(struct cpuinfo_x86 *c)
                        boot_cpu_data.x86_capability[i] &= c->x86_capability[i];
        }
 
-#ifdef CONFIG_X86_MCE
        /* Init Machine Check Exception if available. */
-       mcheck_init(c);
-#endif
+       mcheck_cpu_init(c);
 
        select_idle_routine(c);
 
index 6de9a90..3624e8a 100644 (file)
@@ -32,6 +32,6 @@ struct cpu_dev {
 extern const struct cpu_dev *const __x86_cpu_dev_start[],
                            *const __x86_cpu_dev_end[];
 
-extern void display_cacheinfo(struct cpuinfo_x86 *c);
+extern void cpu_detect_cache_sizes(struct cpuinfo_x86 *c);
 
 #endif
index 19807b8..4fbd384 100644 (file)
@@ -373,7 +373,7 @@ static void __cpuinit init_nsc(struct cpuinfo_x86 *c)
        /* Handle the GX (Formally known as the GX2) */
 
        if (c->x86 == 5 && c->x86_model == 5)
-               display_cacheinfo(c);
+               cpu_detect_cache_sizes(c);
        else
                init_cyrix(c);
 }
index 804c40e..0df4c2b 100644 (file)
@@ -488,22 +488,6 @@ unsigned int __cpuinit init_intel_cacheinfo(struct cpuinfo_x86 *c)
 #endif
        }
 
-       if (trace)
-               printk(KERN_INFO "CPU: Trace cache: %dK uops", trace);
-       else if (l1i)
-               printk(KERN_INFO "CPU: L1 I cache: %dK", l1i);
-
-       if (l1d)
-               printk(KERN_CONT ", L1 D cache: %dK\n", l1d);
-       else
-               printk(KERN_CONT "\n");
-
-       if (l2)
-               printk(KERN_INFO "CPU: L2 cache: %dK\n", l2);
-
-       if (l3)
-               printk(KERN_INFO "CPU: L3 cache: %dK\n", l3);
-
        c->x86_cache_size = l3 ? l3 : (l2 ? l2 : (l1i+l1d));
 
        return l2;
index 721a77c..0bcaa38 100644 (file)
@@ -46,6 +46,9 @@
 
 #include "mce-internal.h"
 
+#define CREATE_TRACE_POINTS
+#include <trace/events/mce.h>
+
 int mce_disabled __read_mostly;
 
 #define MISC_MCELOG_MINOR      227
@@ -85,18 +88,26 @@ static DECLARE_WAIT_QUEUE_HEAD(mce_wait);
 static DEFINE_PER_CPU(struct mce, mces_seen);
 static int                     cpu_missing;
 
-static void default_decode_mce(struct mce *m)
+/*
+ * CPU/chipset specific EDAC code can register a notifier call here to print
+ * MCE errors in a human-readable form.
+ */
+ATOMIC_NOTIFIER_HEAD(x86_mce_decoder_chain);
+EXPORT_SYMBOL_GPL(x86_mce_decoder_chain);
+
+static int default_decode_mce(struct notifier_block *nb, unsigned long val,
+                              void *data)
 {
        pr_emerg("No human readable MCE decoding support on this CPU type.\n");
        pr_emerg("Run the message through 'mcelog --ascii' to decode.\n");
+
+       return NOTIFY_STOP;
 }
 
-/*
- * CPU/chipset specific EDAC code can register a callback here to print
- * MCE errors in a human-readable form:
- */
-void (*x86_mce_decode_callback)(struct mce *m) = default_decode_mce;
-EXPORT_SYMBOL(x86_mce_decode_callback);
+static struct notifier_block mce_dec_nb = {
+       .notifier_call = default_decode_mce,
+       .priority      = -1,
+};
 
 /* MCA banks polled by the period polling timer for corrected events */
 DEFINE_PER_CPU(mce_banks_t, mce_poll_banks) = {
@@ -141,6 +152,9 @@ void mce_log(struct mce *mce)
 {
        unsigned next, entry;
 
+       /* Emit the trace record: */
+       trace_mce_record(mce);
+
        mce->finished = 0;
        wmb();
        for (;;) {
@@ -204,9 +218,9 @@ static void print_mce(struct mce *m)
 
        /*
         * Print out human-readable details about the MCE error,
-        * (if the CPU has an implementation for that):
+        * (if the CPU has an implementation for that)
         */
-       x86_mce_decode_callback(m);
+       atomic_notifier_call_chain(&x86_mce_decoder_chain, 0, m);
 }
 
 static void print_mce_head(void)
@@ -1122,7 +1136,7 @@ static int check_interval = 5 * 60; /* 5 minutes */
 static DEFINE_PER_CPU(int, mce_next_interval); /* in jiffies */
 static DEFINE_PER_CPU(struct timer_list, mce_timer);
 
-static void mcheck_timer(unsigned long data)
+static void mce_start_timer(unsigned long data)
 {
        struct timer_list *t = &per_cpu(mce_timer, data);
        int *n;
@@ -1187,7 +1201,7 @@ int mce_notify_irq(void)
 }
 EXPORT_SYMBOL_GPL(mce_notify_irq);
 
-static int mce_banks_init(void)
+static int __cpuinit __mcheck_cpu_mce_banks_init(void)
 {
        int i;
 
@@ -1206,7 +1220,7 @@ static int mce_banks_init(void)
 /*
  * Initialize Machine Checks for a CPU.
  */
-static int __cpuinit mce_cap_init(void)
+static int __cpuinit __mcheck_cpu_cap_init(void)
 {
        unsigned b;
        u64 cap;
@@ -1228,7 +1242,7 @@ static int __cpuinit mce_cap_init(void)
        WARN_ON(banks != 0 && b != banks);
        banks = b;
        if (!mce_banks) {
-               int err = mce_banks_init();
+               int err = __mcheck_cpu_mce_banks_init();
 
                if (err)
                        return err;
@@ -1244,7 +1258,7 @@ static int __cpuinit mce_cap_init(void)
        return 0;
 }
 
-static void mce_init(void)
+static void __mcheck_cpu_init_generic(void)
 {
        mce_banks_t all_banks;
        u64 cap;
@@ -1273,7 +1287,7 @@ static void mce_init(void)
 }
 
 /* Add per CPU specific workarounds here */
-static int __cpuinit mce_cpu_quirks(struct cpuinfo_x86 *c)
+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");
@@ -1341,7 +1355,7 @@ static int __cpuinit mce_cpu_quirks(struct cpuinfo_x86 *c)
        return 0;
 }
 
-static void __cpuinit mce_ancient_init(struct cpuinfo_x86 *c)
+static void __cpuinit __mcheck_cpu_ancient_init(struct cpuinfo_x86 *c)
 {
        if (c->x86 != 5)
                return;
@@ -1355,7 +1369,7 @@ static void __cpuinit mce_ancient_init(struct cpuinfo_x86 *c)
        }
 }
 
-static void mce_cpu_features(struct cpuinfo_x86 *c)
+static void __mcheck_cpu_init_vendor(struct cpuinfo_x86 *c)
 {
        switch (c->x86_vendor) {
        case X86_VENDOR_INTEL:
@@ -1369,7 +1383,7 @@ static void mce_cpu_features(struct cpuinfo_x86 *c)
        }
 }
 
-static void mce_init_timer(void)
+static void __mcheck_cpu_init_timer(void)
 {
        struct timer_list *t = &__get_cpu_var(mce_timer);
        int *n = &__get_cpu_var(mce_next_interval);
@@ -1380,7 +1394,7 @@ static void mce_init_timer(void)
        *n = check_interval * HZ;
        if (!*n)
                return;
-       setup_timer(t, mcheck_timer, smp_processor_id());
+       setup_timer(t, mce_start_timer, smp_processor_id());
        t->expires = round_jiffies(jiffies + *n);
        add_timer_on(t, smp_processor_id());
 }
@@ -1400,27 +1414,28 @@ void (*machine_check_vector)(struct pt_regs *, long error_code) =
  * Called for each booted CPU to set up machine checks.
  * Must be called with preempt off:
  */
-void __cpuinit mcheck_init(struct cpuinfo_x86 *c)
+void __cpuinit mcheck_cpu_init(struct cpuinfo_x86 *c)
 {
        if (mce_disabled)
                return;
 
-       mce_ancient_init(c);
+       __mcheck_cpu_ancient_init(c);
 
        if (!mce_available(c))
                return;
 
-       if (mce_cap_init() < 0 || mce_cpu_quirks(c) < 0) {
+       if (__mcheck_cpu_cap_init() < 0 || __mcheck_cpu_apply_quirks(c) < 0) {
                mce_disabled = 1;
                return;
        }
 
        machine_check_vector = do_machine_check;
 
-       mce_init();
-       mce_cpu_features(c);
-       mce_init_timer();
+       __mcheck_cpu_init_generic();
+       __mcheck_cpu_init_vendor(c);
+       __mcheck_cpu_init_timer();
        INIT_WORK(&__get_cpu_var(mce_work), mce_process_work);
+
 }
 
 /*
@@ -1640,6 +1655,15 @@ static int __init mcheck_enable(char *str)
 }
 __setup("mce", mcheck_enable);
 
+int __init mcheck_init(void)
+{
+       atomic_notifier_chain_register(&x86_mce_decoder_chain, &mce_dec_nb);
+
+       mcheck_intel_therm_init();
+
+       return 0;
+}
+
 /*
  * Sysfs support
  */
@@ -1648,7 +1672,7 @@ __setup("mce", mcheck_enable);
  * Disable machine checks on suspend and shutdown. We can't really handle
  * them later.
  */
-static int mce_disable(void)
+static int mce_disable_error_reporting(void)
 {
        int i;
 
@@ -1663,12 +1687,12 @@ static int mce_disable(void)
 
 static int mce_suspend(struct sys_device *dev, pm_message_t state)
 {
-       return mce_disable();
+       return mce_disable_error_reporting();
 }
 
 static int mce_shutdown(struct sys_device *dev)
 {
-       return mce_disable();
+       return mce_disable_error_reporting();
 }
 
 /*
@@ -1678,8 +1702,8 @@ static int mce_shutdown(struct sys_device *dev)
  */
 static int mce_resume(struct sys_device *dev)
 {
-       mce_init();
-       mce_cpu_features(&current_cpu_data);
+       __mcheck_cpu_init_generic();
+       __mcheck_cpu_init_vendor(&current_cpu_data);
 
        return 0;
 }
@@ -1689,8 +1713,8 @@ static void mce_cpu_restart(void *data)
        del_timer_sync(&__get_cpu_var(mce_timer));
        if (!mce_available(&current_cpu_data))
                return;
-       mce_init();
-       mce_init_timer();
+       __mcheck_cpu_init_generic();
+       __mcheck_cpu_init_timer();
 }
 
 /* Reinit MCEs after user configuration changes */
@@ -1716,7 +1740,7 @@ static void mce_enable_ce(void *all)
        cmci_reenable();
        cmci_recheck();
        if (all)
-               mce_init_timer();
+               __mcheck_cpu_init_timer();
 }
 
 static struct sysdev_class mce_sysclass = {
@@ -1929,13 +1953,14 @@ static __cpuinit void mce_remove_device(unsigned int cpu)
 }
 
 /* Make sure there are no machine checks on offlined CPUs. */
-static void mce_disable_cpu(void *h)
+static void __cpuinit mce_disable_cpu(void *h)
 {
        unsigned long action = *(unsigned long *)h;
        int i;
 
        if (!mce_available(&current_cpu_data))
                return;
+
        if (!(action & CPU_TASKS_FROZEN))
                cmci_clear();
        for (i = 0; i < banks; i++) {
@@ -1946,7 +1971,7 @@ static void mce_disable_cpu(void *h)
        }
 }
 
-static void mce_reenable_cpu(void *h)
+static void __cpuinit mce_reenable_cpu(void *h)
 {
        unsigned long action = *(unsigned long *)h;
        int i;
@@ -2025,7 +2050,7 @@ static __init void mce_init_banks(void)
        }
 }
 
-static __init int mce_init_device(void)
+static __init int mcheck_init_device(void)
 {
        int err;
        int i = 0;
@@ -2053,7 +2078,7 @@ static __init int mce_init_device(void)
        return err;
 }
 
-device_initcall(mce_init_device);
+device_initcall(mcheck_init_device);
 
 /*
  * Old style boot options parsing. Only for compatibility.
@@ -2101,7 +2126,7 @@ static int fake_panic_set(void *data, u64 val)
 DEFINE_SIMPLE_ATTRIBUTE(fake_panic_fops, fake_panic_get,
                        fake_panic_set, "%llu\n");
 
-static int __init mce_debugfs_init(void)
+static int __init mcheck_debugfs_init(void)
 {
        struct dentry *dmce, *ffake_panic;
 
@@ -2115,5 +2140,5 @@ static int __init mce_debugfs_init(void)
 
        return 0;
 }
-late_initcall(mce_debugfs_init);
+late_initcall(mcheck_debugfs_init);
 #endif
index b3a1dba..4fef985 100644 (file)
@@ -49,6 +49,8 @@ static DEFINE_PER_CPU(struct thermal_state, thermal_state);
 
 static atomic_t therm_throt_en = ATOMIC_INIT(0);
 
+static u32 lvtthmr_init __read_mostly;
+
 #ifdef CONFIG_SYSFS
 #define define_therm_throt_sysdev_one_ro(_name)                                \
        static SYSDEV_ATTR(_name, 0444, therm_throt_sysdev_show_##_name, NULL)
@@ -254,6 +256,18 @@ asmlinkage void smp_thermal_interrupt(struct pt_regs *regs)
        ack_APIC_irq();
 }
 
+void __init mcheck_intel_therm_init(void)
+{
+       /*
+        * This function is only called on boot CPU. Save the init thermal
+        * LVT value on BSP and use that value to restore APs' thermal LVT
+        * entry BIOS programmed later
+        */
+       if (cpu_has(&boot_cpu_data, X86_FEATURE_ACPI) &&
+               cpu_has(&boot_cpu_data, X86_FEATURE_ACC))
+               lvtthmr_init = apic_read(APIC_LVTTHMR);
+}
+
 void intel_init_thermal(struct cpuinfo_x86 *c)
 {
        unsigned int cpu = smp_processor_id();
@@ -270,7 +284,20 @@ void intel_init_thermal(struct cpuinfo_x86 *c)
         * since it might be delivered via SMI already:
         */
        rdmsr(MSR_IA32_MISC_ENABLE, l, h);
-       h = apic_read(APIC_LVTTHMR);
+
+       /*
+        * The initial value of thermal LVT entries on all APs always reads
+        * 0x10000 because APs are woken up by BSP issuing INIT-SIPI-SIPI
+        * sequence to them and LVT registers are reset to 0s except for
+        * the mask bits which are set to 1s when APs receive INIT IPI.
+        * Always restore the value that BIOS has programmed on AP based on
+        * BSP's info we saved since BIOS is always setting the same value
+        * for all threads/cores
+        */
+       apic_write(APIC_LVTTHMR, lvtthmr_init);
+
+       h = lvtthmr_init;
+
        if ((l & MSR_IA32_MISC_ENABLE_TM1) && (h & APIC_DM_SMI)) {
                printk(KERN_DEBUG
                       "CPU%d: Thermal monitoring handled by SMI\n", cpu);
index b5801c3..c1bbed1 100644 (file)
@@ -77,6 +77,18 @@ struct cpu_hw_events {
        struct debug_store      *ds;
 };
 
+struct event_constraint {
+       unsigned long   idxmsk[BITS_TO_LONGS(X86_PMC_IDX_MAX)];
+       int             code;
+};
+
+#define EVENT_CONSTRAINT(c, m) { .code = (c), .idxmsk[0] = (m) }
+#define EVENT_CONSTRAINT_END  { .code = 0, .idxmsk[0] = 0 }
+
+#define for_each_event_constraint(e, c) \
+       for ((e) = (c); (e)->idxmsk[0]; (e)++)
+
+
 /*
  * struct x86_pmu - generic x86 pmu
  */
@@ -102,6 +114,8 @@ struct x86_pmu {
        u64             intel_ctrl;
        void            (*enable_bts)(u64 config);
        void            (*disable_bts)(void);
+       int             (*get_event_idx)(struct cpu_hw_events *cpuc,
+                                        struct hw_perf_event *hwc);
 };
 
 static struct x86_pmu x86_pmu __read_mostly;
@@ -110,6 +124,8 @@ static DEFINE_PER_CPU(struct cpu_hw_events, cpu_hw_events) = {
        .enabled = 1,
 };
 
+static const struct event_constraint *event_constraints;
+
 /*
  * Not sure about some of these
  */
@@ -155,6 +171,16 @@ static u64 p6_pmu_raw_event(u64 hw_event)
        return hw_event & P6_EVNTSEL_MASK;
 }
 
+static const struct event_constraint intel_p6_event_constraints[] =
+{
+       EVENT_CONSTRAINT(0xc1, 0x1),    /* FLOPS */
+       EVENT_CONSTRAINT(0x10, 0x1),    /* FP_COMP_OPS_EXE */
+       EVENT_CONSTRAINT(0x11, 0x1),    /* FP_ASSIST */
+       EVENT_CONSTRAINT(0x12, 0x2),    /* MUL */
+       EVENT_CONSTRAINT(0x13, 0x2),    /* DIV */
+       EVENT_CONSTRAINT(0x14, 0x1),    /* CYCLES_DIV_BUSY */
+       EVENT_CONSTRAINT_END
+};
 
 /*
  * Intel PerfMon v3. Used on Core2 and later.
@@ -170,6 +196,35 @@ static const u64 intel_perfmon_event_map[] =
   [PERF_COUNT_HW_BUS_CYCLES]           = 0x013c,
 };
 
+static const struct event_constraint intel_core_event_constraints[] =
+{
+       EVENT_CONSTRAINT(0x10, 0x1),    /* FP_COMP_OPS_EXE */
+       EVENT_CONSTRAINT(0x11, 0x2),    /* FP_ASSIST */
+       EVENT_CONSTRAINT(0x12, 0x2),    /* MUL */
+       EVENT_CONSTRAINT(0x13, 0x2),    /* DIV */
+       EVENT_CONSTRAINT(0x14, 0x1),    /* CYCLES_DIV_BUSY */
+       EVENT_CONSTRAINT(0x18, 0x1),    /* IDLE_DURING_DIV */
+       EVENT_CONSTRAINT(0x19, 0x2),    /* DELAYED_BYPASS */
+       EVENT_CONSTRAINT(0xa1, 0x1),    /* RS_UOPS_DISPATCH_CYCLES */
+       EVENT_CONSTRAINT(0xcb, 0x1),    /* MEM_LOAD_RETIRED */
+       EVENT_CONSTRAINT_END
+};
+
+static const struct event_constraint intel_nehalem_event_constraints[] =
+{
+       EVENT_CONSTRAINT(0x40, 0x3),    /* L1D_CACHE_LD */
+       EVENT_CONSTRAINT(0x41, 0x3),    /* L1D_CACHE_ST */
+       EVENT_CONSTRAINT(0x42, 0x3),    /* L1D_CACHE_LOCK */
+       EVENT_CONSTRAINT(0x43, 0x3),    /* L1D_ALL_REF */
+       EVENT_CONSTRAINT(0x4e, 0x3),    /* L1D_PREFETCH */
+       EVENT_CONSTRAINT(0x4c, 0x3),    /* LOAD_HIT_PRE */
+       EVENT_CONSTRAINT(0x51, 0x3),    /* L1D */
+       EVENT_CONSTRAINT(0x52, 0x3),    /* L1D_CACHE_PREFETCH_LOCK_FB_HIT */
+       EVENT_CONSTRAINT(0x53, 0x3),    /* L1D_CACHE_LOCK_FB_HIT */
+       EVENT_CONSTRAINT(0xc5, 0x3),    /* CACHE_LOCK_CYCLES */
+       EVENT_CONSTRAINT_END
+};
+
 static u64 intel_pmu_event_map(int hw_event)
 {
        return intel_perfmon_event_map[hw_event];
@@ -190,7 +245,7 @@ static u64 __read_mostly hw_cache_event_ids
                                [PERF_COUNT_HW_CACHE_OP_MAX]
                                [PERF_COUNT_HW_CACHE_RESULT_MAX];
 
-static const u64 nehalem_hw_cache_event_ids
+static __initconst u64 nehalem_hw_cache_event_ids
                                [PERF_COUNT_HW_CACHE_MAX]
                                [PERF_COUNT_HW_CACHE_OP_MAX]
                                [PERF_COUNT_HW_CACHE_RESULT_MAX] =
@@ -281,7 +336,7 @@ static const u64 nehalem_hw_cache_event_ids
  },
 };
 
-static const u64 core2_hw_cache_event_ids
+static __initconst u64 core2_hw_cache_event_ids
                                [PERF_COUNT_HW_CACHE_MAX]
                                [PERF_COUNT_HW_CACHE_OP_MAX]
                                [PERF_COUNT_HW_CACHE_RESULT_MAX] =
@@ -372,7 +427,7 @@ static const u64 core2_hw_cache_event_ids
  },
 };
 
-static const u64 atom_hw_cache_event_ids
+static __initconst u64 atom_hw_cache_event_ids
                                [PERF_COUNT_HW_CACHE_MAX]
                                [PERF_COUNT_HW_CACHE_OP_MAX]
                                [PERF_COUNT_HW_CACHE_RESULT_MAX] =
@@ -469,7 +524,7 @@ static u64 intel_pmu_raw_event(u64 hw_event)
 #define CORE_EVNTSEL_UNIT_MASK         0x0000FF00ULL
 #define CORE_EVNTSEL_EDGE_MASK         0x00040000ULL
 #define CORE_EVNTSEL_INV_MASK          0x00800000ULL
-#define CORE_EVNTSEL_REG_MASK  0xFF000000ULL
+#define CORE_EVNTSEL_REG_MASK          0xFF000000ULL
 
 #define CORE_EVNTSEL_MASK              \
        (CORE_EVNTSEL_EVENT_MASK |      \
@@ -481,7 +536,7 @@ static u64 intel_pmu_raw_event(u64 hw_event)
        return hw_event & CORE_EVNTSEL_MASK;
 }
 
-static const u64 amd_hw_cache_event_ids
+static __initconst u64 amd_hw_cache_event_ids
                                [PERF_COUNT_HW_CACHE_MAX]
                                [PERF_COUNT_HW_CACHE_OP_MAX]
                                [PERF_COUNT_HW_CACHE_RESULT_MAX] =
@@ -932,6 +987,8 @@ static int __hw_perf_event_init(struct perf_event *event)
         */
        hwc->config = ARCH_PERFMON_EVENTSEL_INT;
 
+       hwc->idx = -1;
+
        /*
         * Count user and OS events unless requested not to.
         */
@@ -1334,8 +1391,7 @@ static void amd_pmu_enable_event(struct hw_perf_event *hwc, int idx)
                x86_pmu_enable_event(hwc, idx);
 }
 
-static int
-fixed_mode_idx(struct perf_event *event, struct hw_perf_event *hwc)
+static int fixed_mode_idx(struct hw_perf_event *hwc)
 {
        unsigned int hw_event;
 
@@ -1349,6 +1405,12 @@ fixed_mode_idx(struct perf_event *event, struct hw_perf_event *hwc)
        if (!x86_pmu.num_events_fixed)
                return -1;
 
+       /*
+        * fixed counters do not take all possible filters
+        */
+       if (hwc->config & ARCH_PERFMON_EVENT_FILTER_MASK)
+               return -1;
+
        if (unlikely(hw_event == x86_pmu.event_map(PERF_COUNT_HW_INSTRUCTIONS)))
                return X86_PMC_IDX_FIXED_INSTRUCTIONS;
        if (unlikely(hw_event == x86_pmu.event_map(PERF_COUNT_HW_CPU_CYCLES)))
@@ -1360,22 +1422,57 @@ fixed_mode_idx(struct perf_event *event, struct hw_perf_event *hwc)
 }
 
 /*
- * Find a PMC slot for the freshly enabled / scheduled in event:
+ * generic counter allocator: get next free counter
  */
-static int x86_pmu_enable(struct perf_event *event)
+static int
+gen_get_event_idx(struct cpu_hw_events *cpuc, struct hw_perf_event *hwc)
+{
+       int idx;
+
+       idx = find_first_zero_bit(cpuc->used_mask, x86_pmu.num_events);
+       return idx == x86_pmu.num_events ? -1 : idx;
+}
+
+/*
+ * intel-specific counter allocator: check event constraints
+ */
+static int
+intel_get_event_idx(struct cpu_hw_events *cpuc, struct hw_perf_event *hwc)
+{
+       const struct event_constraint *event_constraint;
+       int i, code;
+
+       if (!event_constraints)
+               goto skip;
+
+       code = hwc->config & CORE_EVNTSEL_EVENT_MASK;
+
+       for_each_event_constraint(event_constraint, event_constraints) {
+               if (code == event_constraint->code) {
+                       for_each_bit(i, event_constraint->idxmsk, X86_PMC_IDX_MAX) {
+                               if (!test_and_set_bit(i, cpuc->used_mask))
+                                       return i;
+                       }
+                       return -1;
+               }
+       }
+skip:
+       return gen_get_event_idx(cpuc, hwc);
+}
+
+static int
+x86_schedule_event(struct cpu_hw_events *cpuc, struct hw_perf_event *hwc)
 {
-       struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
-       struct hw_perf_event *hwc = &event->hw;
        int idx;
 
-       idx = fixed_mode_idx(event, hwc);
+       idx = fixed_mode_idx(hwc);
        if (idx == X86_PMC_IDX_FIXED_BTS) {
                /* BTS is already occupied. */
                if (test_and_set_bit(idx, cpuc->used_mask))
                        return -EAGAIN;
 
                hwc->config_base        = 0;
-               hwc->event_base = 0;
+               hwc->event_base         = 0;
                hwc->idx                = idx;
        } else if (idx >= 0) {
                /*
@@ -1396,20 +1493,35 @@ static int x86_pmu_enable(struct perf_event *event)
        } else {
                idx = hwc->idx;
                /* Try to get the previous generic event again */
-               if (test_and_set_bit(idx, cpuc->used_mask)) {
+               if (idx == -1 || test_and_set_bit(idx, cpuc->used_mask)) {
 try_generic:
-                       idx = find_first_zero_bit(cpuc->used_mask,
-                                                 x86_pmu.num_events);
-                       if (idx == x86_pmu.num_events)
+                       idx = x86_pmu.get_event_idx(cpuc, hwc);
+                       if (idx == -1)
                                return -EAGAIN;
 
                        set_bit(idx, cpuc->used_mask);
                        hwc->idx = idx;
                }
-               hwc->config_base  = x86_pmu.eventsel;
-               hwc->event_base = x86_pmu.perfctr;
+               hwc->config_base = x86_pmu.eventsel;
+               hwc->event_base  = x86_pmu.perfctr;
        }
 
+       return idx;
+}
+
+/*
+ * Find a PMC slot for the freshly enabled / scheduled in event:
+ */
+static int x86_pmu_enable(struct perf_event *event)
+{
+       struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
+       struct hw_perf_event *hwc = &event->hw;
+       int idx;
+
+       idx = x86_schedule_event(cpuc, hwc);
+       if (idx < 0)
+               return idx;
+
        perf_events_lapic_init();
 
        x86_pmu.disable(hwc, idx);
@@ -1852,7 +1964,7 @@ static __read_mostly struct notifier_block perf_event_nmi_notifier = {
        .priority               = 1
 };
 
-static struct x86_pmu p6_pmu = {
+static __initconst struct x86_pmu p6_pmu = {
        .name                   = "p6",
        .handle_irq             = p6_pmu_handle_irq,
        .disable_all            = p6_pmu_disable_all,
@@ -1877,9 +1989,10 @@ static struct x86_pmu p6_pmu = {
         */
        .event_bits             = 32,
        .event_mask             = (1ULL << 32) - 1,
+       .get_event_idx          = intel_get_event_idx,
 };
 
-static struct x86_pmu intel_pmu = {
+static __initconst struct x86_pmu intel_pmu = {
        .name                   = "Intel",
        .handle_irq             = intel_pmu_handle_irq,
        .disable_all            = intel_pmu_disable_all,
@@ -1900,9 +2013,10 @@ static struct x86_pmu intel_pmu = {
        .max_period             = (1ULL << 31) - 1,
        .enable_bts             = intel_pmu_enable_bts,
        .disable_bts            = intel_pmu_disable_bts,
+       .get_event_idx          = intel_get_event_idx,
 };
 
-static struct x86_pmu amd_pmu = {
+static __initconst struct x86_pmu amd_pmu = {
        .name                   = "AMD",
        .handle_irq             = amd_pmu_handle_irq,
        .disable_all            = amd_pmu_disable_all,
@@ -1920,9 +2034,10 @@ static struct x86_pmu amd_pmu = {
        .apic                   = 1,
        /* use highest bit to detect overflow */
        .max_period             = (1ULL << 47) - 1,
+       .get_event_idx          = gen_get_event_idx,
 };
 
-static int p6_pmu_init(void)
+static __init int p6_pmu_init(void)
 {
        switch (boot_cpu_data.x86_model) {
        case 1:
@@ -1932,10 +2047,12 @@ static int p6_pmu_init(void)
        case 7:
        case 8:
        case 11: /* Pentium III */
+               event_constraints = intel_p6_event_constraints;
                break;
        case 9:
        case 13:
                /* Pentium M */
+               event_constraints = intel_p6_event_constraints;
                break;
        default:
                pr_cont("unsupported p6 CPU model %d ",
@@ -1954,7 +2071,7 @@ static int p6_pmu_init(void)
        return 0;
 }
 
-static int intel_pmu_init(void)
+static __init int intel_pmu_init(void)
 {
        union cpuid10_edx edx;
        union cpuid10_eax eax;
@@ -2007,12 +2124,14 @@ static int intel_pmu_init(void)
                       sizeof(hw_cache_event_ids));
 
                pr_cont("Core2 events, ");
+               event_constraints = intel_core_event_constraints;
                break;
        default:
        case 26:
                memcpy(hw_cache_event_ids, nehalem_hw_cache_event_ids,
                       sizeof(hw_cache_event_ids));
 
+               event_constraints = intel_nehalem_event_constraints;
                pr_cont("Nehalem/Corei7 events, ");
                break;
        case 28:
@@ -2025,7 +2144,7 @@ static int intel_pmu_init(void)
        return 0;
 }
 
-static int amd_pmu_init(void)
+static __init int amd_pmu_init(void)
 {
        /* Performance-monitoring supported from K7 and later: */
        if (boot_cpu_data.x86 < 6)
@@ -2105,11 +2224,47 @@ static const struct pmu pmu = {
        .unthrottle     = x86_pmu_unthrottle,
 };
 
+static int
+validate_event(struct cpu_hw_events *cpuc, struct perf_event *event)
+{
+       struct hw_perf_event fake_event = event->hw;
+
+       if (event->pmu && event->pmu != &pmu)
+               return 0;
+
+       return x86_schedule_event(cpuc, &fake_event) >= 0;
+}
+
+static int validate_group(struct perf_event *event)
+{
+       struct perf_event *sibling, *leader = event->group_leader;
+       struct cpu_hw_events fake_pmu;
+
+       memset(&fake_pmu, 0, sizeof(fake_pmu));
+
+       if (!validate_event(&fake_pmu, leader))
+               return -ENOSPC;
+
+       list_for_each_entry(sibling, &leader->sibling_list, group_entry) {
+               if (!validate_event(&fake_pmu, sibling))
+                       return -ENOSPC;
+       }
+
+       if (!validate_event(&fake_pmu, event))
+               return -ENOSPC;
+
+       return 0;
+}
+
 const struct pmu *hw_perf_event_init(struct perf_event *event)
 {
        int err;
 
        err = __hw_perf_event_init(event);
+       if (!err) {
+               if (event->group_leader != event)
+                       err = validate_group(event);
+       }
        if (err) {
                if (event->destroy)
                        event->destroy(event);
index fab786f..898df97 100644 (file)
@@ -712,7 +712,7 @@ static void probe_nmi_watchdog(void)
        switch (boot_cpu_data.x86_vendor) {
        case X86_VENDOR_AMD:
                if (boot_cpu_data.x86 != 6 && boot_cpu_data.x86 != 15 &&
-                   boot_cpu_data.x86 != 16)
+                   boot_cpu_data.x86 != 16 && boot_cpu_data.x86 != 17)
                        return;
                wd_ops = &k7_wd_ops;
                break;
index bb62b3e..2800074 100644 (file)
@@ -26,7 +26,7 @@ static void __cpuinit init_transmeta(struct cpuinfo_x86 *c)
 
        early_init_transmeta(c);
 
-       display_cacheinfo(c);
+       cpu_detect_cache_sizes(c);
 
        /* Print CMS and CPU revision */
        max = cpuid_eax(0x80860000);
index 6a52d4b..7ef24a7 100644 (file)
@@ -116,21 +116,16 @@ static int cpuid_open(struct inode *inode, struct file *file)
 {
        unsigned int cpu;
        struct cpuinfo_x86 *c;
-       int ret = 0;
-
-       lock_kernel();
 
        cpu = iminor(file->f_path.dentry->d_inode);
-       if (cpu >= nr_cpu_ids || !cpu_online(cpu)) {
-               ret = -ENXIO;   /* No such CPU */
-               goto out;
-       }
+       if (cpu >= nr_cpu_ids || !cpu_online(cpu))
+               return -ENXIO;  /* No such CPU */
+
        c = &cpu_data(cpu);
        if (c->cpuid_level < 0)
-               ret = -EIO;     /* CPUID not supported */
-out:
-       unlock_kernel();
-       return ret;
+               return -EIO;    /* CPUID not supported */
+
+       return 0;
 }
 
 /*
index 2d8a371..b8ce165 100644 (file)
@@ -268,11 +268,12 @@ int __kprobes __die(const char *str, struct pt_regs *regs, long err)
 
        show_registers(regs);
 #ifdef CONFIG_X86_32
-       sp = (unsigned long) (&regs->sp);
-       savesegment(ss, ss);
-       if (user_mode(regs)) {
+       if (user_mode_vm(regs)) {
                sp = regs->sp;
                ss = regs->ss & 0xffff;
+       } else {
+               sp = kernel_stack_pointer(regs);
+               savesegment(ss, ss);
        }
        printk(KERN_EMERG "EIP: [<%08lx>] ", regs->ip);
        print_symbol("%s", regs->ip);
index f7dd2a7..e0ed4c7 100644 (file)
@@ -10,9 +10,9 @@
 #include <linux/module.h>
 #include <linux/ptrace.h>
 #include <linux/kexec.h>
+#include <linux/sysfs.h>
 #include <linux/bug.h>
 #include <linux/nmi.h>
-#include <linux/sysfs.h>
 
 #include <asm/stacktrace.h>
 
@@ -35,6 +35,7 @@ void dump_trace(struct task_struct *task, struct pt_regs *regs,
 
        if (!stack) {
                unsigned long dummy;
+
                stack = &dummy;
                if (task && task != current)
                        stack = (unsigned long *)task->thread.sp;
@@ -57,8 +58,7 @@ void dump_trace(struct task_struct *task, struct pt_regs *regs,
 
                context = (struct thread_info *)
                        ((unsigned long)stack & (~(THREAD_SIZE - 1)));
-               bp = print_context_stack(context, stack, bp, ops,
-                                        data, NULL, &graph);
+               bp = print_context_stack(context, stack, bp, ops, data, NULL, &graph);
 
                stack = (unsigned long *)context->previous_esp;
                if (!stack)
@@ -72,7 +72,7 @@ EXPORT_SYMBOL(dump_trace);
 
 void
 show_stack_log_lvl(struct task_struct *task, struct pt_regs *regs,
-               unsigned long *sp, unsigned long bp, char *log_lvl)
+                  unsigned long *sp, unsigned long bp, char *log_lvl)
 {
        unsigned long *stack;
        int i;
@@ -156,4 +156,3 @@ int is_valid_bugaddr(unsigned long ip)
 
        return ud2 == 0x0b0f;
 }
-
index a071e6b..8e74093 100644 (file)
 #include <linux/module.h>
 #include <linux/ptrace.h>
 #include <linux/kexec.h>
+#include <linux/sysfs.h>
 #include <linux/bug.h>
 #include <linux/nmi.h>
-#include <linux/sysfs.h>
 
 #include <asm/stacktrace.h>
 
 #include "dumpstack.h"
 
+#define N_EXCEPTION_STACKS_END \
+               (N_EXCEPTION_STACKS + DEBUG_STKSZ/EXCEPTION_STKSZ - 2)
 
 static char x86_stack_ids[][8] = {
-               [DEBUG_STACK - 1] = "#DB",
-               [NMI_STACK - 1] = "NMI",
-               [DOUBLEFAULT_STACK - 1] = "#DF",
-               [STACKFAULT_STACK - 1] = "#SS",
-               [MCE_STACK - 1] = "#MC",
+               [ DEBUG_STACK-1                 ]       = "#DB",
+               [ NMI_STACK-1                   ]       = "NMI",
+               [ DOUBLEFAULT_STACK-1           ]       = "#DF",
+               [ STACKFAULT_STACK-1            ]       = "#SS",
+               [ MCE_STACK-1                   ]       = "#MC",
 #if DEBUG_STKSZ > EXCEPTION_STKSZ
-               [N_EXCEPTION_STACKS ...
-                       N_EXCEPTION_STACKS + DEBUG_STKSZ / EXCEPTION_STKSZ - 2] = "#DB[?]"
+               [ N_EXCEPTION_STACKS ...
+                 N_EXCEPTION_STACKS_END        ]       = "#DB[?]"
 #endif
-       };
+};
 
 int x86_is_stack_id(int id, char *name)
 {
@@ -37,7 +39,7 @@ int x86_is_stack_id(int id, char *name)
 }
 
 static unsigned long *in_exception_stack(unsigned cpu, unsigned long stack,
-                                       unsigned *usedp, char **idp)
+                                        unsigned *usedp, char **idp)
 {
        unsigned k;
 
@@ -202,21 +204,24 @@ EXPORT_SYMBOL(dump_trace);
 
 void
 show_stack_log_lvl(struct task_struct *task, struct pt_regs *regs,
-               unsigned long *sp, unsigned long bp, char *log_lvl)
+                  unsigned long *sp, unsigned long bp, char *log_lvl)
 {
+       unsigned long *irq_stack_end;
+       unsigned long *irq_stack;
        unsigned long *stack;
+       int cpu;
        int i;
-       const int cpu = smp_processor_id();
-       unsigned long *irq_stack_end =
-               (unsigned long *)(per_cpu(irq_stack_ptr, cpu));
-       unsigned long *irq_stack =
-               (unsigned long *)(per_cpu(irq_stack_ptr, cpu) - IRQ_STACK_SIZE);
+
+       preempt_disable();
+       cpu = smp_processor_id();
+
+       irq_stack_end   = (unsigned long *)(per_cpu(irq_stack_ptr, cpu));
+       irq_stack       = (unsigned long *)(per_cpu(irq_stack_ptr, cpu) - IRQ_STACK_SIZE);
 
        /*
-        * debugging aid: "show_stack(NULL, NULL);" prints the
-        * back trace for this cpu.
+        * Debugging aid: "show_stack(NULL, NULL);" prints the
+        * back trace for this cpu:
         */
-
        if (sp == NULL) {
                if (task)
                        sp = (unsigned long *)task->thread.sp;
@@ -240,6 +245,8 @@ show_stack_log_lvl(struct task_struct *task, struct pt_regs *regs,
                printk(" %016lx", *stack++);
                touch_nmi_watchdog();
        }
+       preempt_enable();
+
        printk("\n");
        show_trace_log_lvl(task, regs, sp, bp, log_lvl);
 }
@@ -303,4 +310,3 @@ int is_valid_bugaddr(unsigned long ip)
 
        return ud2 == 0x0b0f;
 }
-
index 7d52e9d..50b9c22 100644 (file)
@@ -334,6 +334,10 @@ ENTRY(ret_from_fork)
 END(ret_from_fork)
 
 /*
+ * Interrupt exit functions should be protected against kprobes
+ */
+       .pushsection .kprobes.text, "ax"
+/*
  * Return to user mode is not as complex as all this looks,
  * but we want the default path for a system call return to
  * go as quickly as possible which is why some of this is
@@ -383,6 +387,10 @@ need_resched:
 END(resume_kernel)
 #endif
        CFI_ENDPROC
+/*
+ * End of kprobes section
+ */
+       .popsection
 
 /* SYSENTER_RETURN points to after the "sysenter" instruction in
    the vsyscall page.  See vsyscall-sysentry.S, which defines the symbol.  */
@@ -513,6 +521,10 @@ sysexit_audit:
        PTGS_TO_GS_EX
 ENDPROC(ia32_sysenter_target)
 
+/*
+ * syscall stub including irq exit should be protected against kprobes
+ */
+       .pushsection .kprobes.text, "ax"
        # system call handler stub
 ENTRY(system_call)
        RING0_INT_FRAME                 # can't unwind into user space anyway
@@ -705,6 +717,10 @@ syscall_badsys:
        jmp resume_userspace
 END(syscall_badsys)
        CFI_ENDPROC
+/*
+ * End of kprobes section
+ */
+       .popsection
 
 /*
  * System calls that need a pt_regs pointer.
@@ -814,6 +830,10 @@ common_interrupt:
 ENDPROC(common_interrupt)
        CFI_ENDPROC
 
+/*
+ *  Irq entries should be protected against kprobes
+ */
+       .pushsection .kprobes.text, "ax"
 #define BUILD_INTERRUPT3(name, nr, fn) \
 ENTRY(name)                            \
        RING0_INT_FRAME;                \
@@ -980,6 +1000,10 @@ ENTRY(spurious_interrupt_bug)
        jmp error_code
        CFI_ENDPROC
 END(spurious_interrupt_bug)
+/*
+ * End of kprobes section
+ */
+       .popsection
 
 ENTRY(kernel_thread_helper)
        pushl $0                # fake return address for unwinder
index bd5bbdd..4deb8fc 100644 (file)
@@ -803,6 +803,10 @@ END(interrupt)
        call \func
        .endm
 
+/*
+ * Interrupt entry/exit should be protected against kprobes
+ */
+       .pushsection .kprobes.text, "ax"
        /*
         * The interrupt stubs push (~vector+0x80) onto the stack and
         * then jump to common_interrupt.
@@ -941,6 +945,10 @@ ENTRY(retint_kernel)
 
        CFI_ENDPROC
 END(common_interrupt)
+/*
+ * End of kprobes section
+ */
+       .popsection
 
 /*
  * APIC interrupts.
@@ -1491,12 +1499,17 @@ error_kernelspace:
        leaq irq_return(%rip),%rcx
        cmpq %rcx,RIP+8(%rsp)
        je error_swapgs
-       movl %ecx,%ecx  /* zero extend */
-       cmpq %rcx,RIP+8(%rsp)
-       je error_swapgs
+       movl %ecx,%eax  /* zero extend */
+       cmpq %rax,RIP+8(%rsp)
+       je bstep_iret
        cmpq $gs_change,RIP+8(%rsp)
        je error_swapgs
        jmp error_sti
+
+bstep_iret:
+       /* Fix truncated RIP */
+       movq %rcx,RIP+8(%rsp)
+       jmp error_swapgs
 END(error_entry)
 
 
index 780cd92..22db86a 100644 (file)
@@ -212,8 +212,8 @@ ENTRY(secondary_startup_64)
         */
        lgdt    early_gdt_descr(%rip)
 
-       /* set up data segments. actually 0 would do too */
-       movl $__KERNEL_DS,%eax
+       /* set up data segments */
+       xorl %eax,%eax
        movl %eax,%ds
        movl %eax,%ss
        movl %eax,%es
diff --git a/arch/x86/kernel/hw_breakpoint.c b/arch/x86/kernel/hw_breakpoint.c
new file mode 100644 (file)
index 0000000..d42f65a
--- /dev/null
@@ -0,0 +1,555 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Copyright (C) 2007 Alan Stern
+ * Copyright (C) 2009 IBM Corporation
+ * Copyright (C) 2009 Frederic Weisbecker <fweisbec@gmail.com>
+ *
+ * Authors: Alan Stern <stern@rowland.harvard.edu>
+ *          K.Prasad <prasad@linux.vnet.ibm.com>
+ *          Frederic Weisbecker <fweisbec@gmail.com>
+ */
+
+/*
+ * HW_breakpoint: a unified kernel/user-space hardware breakpoint facility,
+ * using the CPU's debug registers.
+ */
+
+#include <linux/perf_event.h>
+#include <linux/hw_breakpoint.h>
+#include <linux/irqflags.h>
+#include <linux/notifier.h>
+#include <linux/kallsyms.h>
+#include <linux/kprobes.h>
+#include <linux/percpu.h>
+#include <linux/kdebug.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/smp.h>
+
+#include <asm/hw_breakpoint.h>
+#include <asm/processor.h>
+#include <asm/debugreg.h>
+
+/* Per cpu debug control register value */
+DEFINE_PER_CPU(unsigned long, cpu_dr7);
+EXPORT_PER_CPU_SYMBOL(cpu_dr7);
+
+/* Per cpu debug address registers values */
+static DEFINE_PER_CPU(unsigned long, cpu_debugreg[HBP_NUM]);
+
+/*
+ * Stores the breakpoints currently in use on each breakpoint address
+ * register for each cpus
+ */
+static DEFINE_PER_CPU(struct perf_event *, bp_per_reg[HBP_NUM]);
+
+
+static inline unsigned long
+__encode_dr7(int drnum, unsigned int len, unsigned int type)
+{
+       unsigned long bp_info;
+
+       bp_info = (len | type) & 0xf;
+       bp_info <<= (DR_CONTROL_SHIFT + drnum * DR_CONTROL_SIZE);
+       bp_info |= (DR_GLOBAL_ENABLE << (drnum * DR_ENABLE_SIZE));
+
+       return bp_info;
+}
+
+/*
+ * Encode the length, type, Exact, and Enable bits for a particular breakpoint
+ * as stored in debug register 7.
+ */
+unsigned long encode_dr7(int drnum, unsigned int len, unsigned int type)
+{
+       return __encode_dr7(drnum, len, type) | DR_GLOBAL_SLOWDOWN;
+}
+
+/*
+ * Decode the length and type bits for a particular breakpoint as
+ * stored in debug register 7.  Return the "enabled" status.
+ */
+int decode_dr7(unsigned long dr7, int bpnum, unsigned *len, unsigned *type)
+{
+       int bp_info = dr7 >> (DR_CONTROL_SHIFT + bpnum * DR_CONTROL_SIZE);
+
+       *len = (bp_info & 0xc) | 0x40;
+       *type = (bp_info & 0x3) | 0x80;
+
+       return (dr7 >> (bpnum * DR_ENABLE_SIZE)) & 0x3;
+}
+
+/*
+ * Install a perf counter breakpoint.
+ *
+ * We seek a free debug address register and use it for this
+ * breakpoint. Eventually we enable it in the debug control register.
+ *
+ * Atomic: we hold the counter->ctx->lock and we only handle variables
+ * and registers local to this cpu.
+ */
+int arch_install_hw_breakpoint(struct perf_event *bp)
+{
+       struct arch_hw_breakpoint *info = counter_arch_bp(bp);
+       unsigned long *dr7;
+       int i;
+
+       for (i = 0; i < HBP_NUM; i++) {
+               struct perf_event **slot = &__get_cpu_var(bp_per_reg[i]);
+
+               if (!*slot) {
+                       *slot = bp;
+                       break;
+               }
+       }
+
+       if (WARN_ONCE(i == HBP_NUM, "Can't find any breakpoint slot"))
+               return -EBUSY;
+
+       set_debugreg(info->address, i);
+       __get_cpu_var(cpu_debugreg[i]) = info->address;
+
+       dr7 = &__get_cpu_var(cpu_dr7);
+       *dr7 |= encode_dr7(i, info->len, info->type);
+
+       set_debugreg(*dr7, 7);
+
+       return 0;
+}
+
+/*
+ * Uninstall the breakpoint contained in the given counter.
+ *
+ * First we search the debug address register it uses and then we disable
+ * it.
+ *
+ * Atomic: we hold the counter->ctx->lock and we only handle variables
+ * and registers local to this cpu.
+ */
+void arch_uninstall_hw_breakpoint(struct perf_event *bp)
+{
+       struct arch_hw_breakpoint *info = counter_arch_bp(bp);
+       unsigned long *dr7;
+       int i;
+
+       for (i = 0; i < HBP_NUM; i++) {
+               struct perf_event **slot = &__get_cpu_var(bp_per_reg[i]);
+
+               if (*slot == bp) {
+                       *slot = NULL;
+                       break;
+               }
+       }
+
+       if (WARN_ONCE(i == HBP_NUM, "Can't find any breakpoint slot"))
+               return;
+
+       dr7 = &__get_cpu_var(cpu_dr7);
+       *dr7 &= ~__encode_dr7(i, info->len, info->type);
+
+       set_debugreg(*dr7, 7);
+}
+
+static int get_hbp_len(u8 hbp_len)
+{
+       unsigned int len_in_bytes = 0;
+
+       switch (hbp_len) {
+       case X86_BREAKPOINT_LEN_1:
+               len_in_bytes = 1;
+               break;
+       case X86_BREAKPOINT_LEN_2:
+               len_in_bytes = 2;
+               break;
+       case X86_BREAKPOINT_LEN_4:
+               len_in_bytes = 4;
+               break;
+#ifdef CONFIG_X86_64
+       case X86_BREAKPOINT_LEN_8:
+               len_in_bytes = 8;
+               break;
+#endif
+       }
+       return len_in_bytes;
+}
+
+/*
+ * Check for virtual address in user space.
+ */
+int arch_check_va_in_userspace(unsigned long va, u8 hbp_len)
+{
+       unsigned int len;
+
+       len = get_hbp_len(hbp_len);
+
+       return (va <= TASK_SIZE - len);
+}
+
+/*
+ * Check for virtual address in kernel space.
+ */
+static int arch_check_va_in_kernelspace(unsigned long va, u8 hbp_len)
+{
+       unsigned int len;
+
+       len = get_hbp_len(hbp_len);
+
+       return (va >= TASK_SIZE) && ((va + len - 1) >= TASK_SIZE);
+}
+
+/*
+ * Store a breakpoint's encoded address, length, and type.
+ */
+static int arch_store_info(struct perf_event *bp)
+{
+       struct arch_hw_breakpoint *info = counter_arch_bp(bp);
+       /*
+        * For kernel-addresses, either the address or symbol name can be
+        * specified.
+        */
+       if (info->name)
+               info->address = (unsigned long)
+                               kallsyms_lookup_name(info->name);
+       if (info->address)
+               return 0;
+
+       return -EINVAL;
+}
+
+int arch_bp_generic_fields(int x86_len, int x86_type,
+                          int *gen_len, int *gen_type)
+{
+       /* Len */
+       switch (x86_len) {
+       case X86_BREAKPOINT_LEN_1:
+               *gen_len = HW_BREAKPOINT_LEN_1;
+               break;
+       case X86_BREAKPOINT_LEN_2:
+               *gen_len = HW_BREAKPOINT_LEN_2;
+               break;
+       case X86_BREAKPOINT_LEN_4:
+               *gen_len = HW_BREAKPOINT_LEN_4;
+               break;
+#ifdef CONFIG_X86_64
+       case X86_BREAKPOINT_LEN_8:
+               *gen_len = HW_BREAKPOINT_LEN_8;
+               break;
+#endif
+       default:
+               return -EINVAL;
+       }
+
+       /* Type */
+       switch (x86_type) {
+       case X86_BREAKPOINT_EXECUTE:
+               *gen_type = HW_BREAKPOINT_X;
+               break;
+       case X86_BREAKPOINT_WRITE:
+               *gen_type = HW_BREAKPOINT_W;
+               break;
+       case X86_BREAKPOINT_RW:
+               *gen_type = HW_BREAKPOINT_W | HW_BREAKPOINT_R;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+
+static int arch_build_bp_info(struct perf_event *bp)
+{
+       struct arch_hw_breakpoint *info = counter_arch_bp(bp);
+
+       info->address = bp->attr.bp_addr;
+
+       /* Len */
+       switch (bp->attr.bp_len) {
+       case HW_BREAKPOINT_LEN_1:
+               info->len = X86_BREAKPOINT_LEN_1;
+               break;
+       case HW_BREAKPOINT_LEN_2:
+               info->len = X86_BREAKPOINT_LEN_2;
+               break;
+       case HW_BREAKPOINT_LEN_4:
+               info->len = X86_BREAKPOINT_LEN_4;
+               break;
+#ifdef CONFIG_X86_64
+       case HW_BREAKPOINT_LEN_8:
+               info->len = X86_BREAKPOINT_LEN_8;
+               break;
+#endif
+       default:
+               return -EINVAL;
+       }
+
+       /* Type */
+       switch (bp->attr.bp_type) {
+       case HW_BREAKPOINT_W:
+               info->type = X86_BREAKPOINT_WRITE;
+               break;
+       case HW_BREAKPOINT_W | HW_BREAKPOINT_R:
+               info->type = X86_BREAKPOINT_RW;
+               break;
+       case HW_BREAKPOINT_X:
+               info->type = X86_BREAKPOINT_EXECUTE;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+/*
+ * Validate the arch-specific HW Breakpoint register settings
+ */
+int arch_validate_hwbkpt_settings(struct perf_event *bp,
+                                 struct task_struct *tsk)
+{
+       struct arch_hw_breakpoint *info = counter_arch_bp(bp);
+       unsigned int align;
+       int ret;
+
+
+       ret = arch_build_bp_info(bp);
+       if (ret)
+               return ret;
+
+       ret = -EINVAL;
+
+       if (info->type == X86_BREAKPOINT_EXECUTE)
+               /*
+                * Ptrace-refactoring code
+                * For now, we'll allow instruction breakpoint only for user-space
+                * addresses
+                */
+               if ((!arch_check_va_in_userspace(info->address, info->len)) &&
+                       info->len != X86_BREAKPOINT_EXECUTE)
+                       return ret;
+
+       switch (info->len) {
+       case X86_BREAKPOINT_LEN_1:
+               align = 0;
+               break;
+       case X86_BREAKPOINT_LEN_2:
+               align = 1;
+               break;
+       case X86_BREAKPOINT_LEN_4:
+               align = 3;
+               break;
+#ifdef CONFIG_X86_64
+       case X86_BREAKPOINT_LEN_8:
+               align = 7;
+               break;
+#endif
+       default:
+               return ret;
+       }
+
+       if (bp->callback)
+               ret = arch_store_info(bp);
+
+       if (ret < 0)
+               return ret;
+       /*
+        * Check that the low-order bits of the address are appropriate
+        * for the alignment implied by len.
+        */
+       if (info->address & align)
+               return -EINVAL;
+
+       /* Check that the virtual address is in the proper range */
+       if (tsk) {
+               if (!arch_check_va_in_userspace(info->address, info->len))
+                       return -EFAULT;
+       } else {
+               if (!arch_check_va_in_kernelspace(info->address, info->len))
+                       return -EFAULT;
+       }
+
+       return 0;
+}
+
+/*
+ * Dump the debug register contents to the user.
+ * We can't dump our per cpu values because it
+ * may contain cpu wide breakpoint, something that
+ * doesn't belong to the current task.
+ *
+ * TODO: include non-ptrace user breakpoints (perf)
+ */
+void aout_dump_debugregs(struct user *dump)
+{
+       int i;
+       int dr7 = 0;
+       struct perf_event *bp;
+       struct arch_hw_breakpoint *info;
+       struct thread_struct *thread = &current->thread;
+
+       for (i = 0; i < HBP_NUM; i++) {
+               bp = thread->ptrace_bps[i];
+
+               if (bp && !bp->attr.disabled) {
+                       dump->u_debugreg[i] = bp->attr.bp_addr;
+                       info = counter_arch_bp(bp);
+                       dr7 |= encode_dr7(i, info->len, info->type);
+               } else {
+                       dump->u_debugreg[i] = 0;
+               }
+       }
+
+       dump->u_debugreg[4] = 0;
+       dump->u_debugreg[5] = 0;
+       dump->u_debugreg[6] = current->thread.debugreg6;
+
+       dump->u_debugreg[7] = dr7;
+}
+EXPORT_SYMBOL_GPL(aout_dump_debugregs);
+
+/*
+ * Release the user breakpoints used by ptrace
+ */
+void flush_ptrace_hw_breakpoint(struct task_struct *tsk)
+{
+       int i;
+       struct thread_struct *t = &tsk->thread;
+
+       for (i = 0; i < HBP_NUM; i++) {
+               unregister_hw_breakpoint(t->ptrace_bps[i]);
+               t->ptrace_bps[i] = NULL;
+       }
+}
+
+void hw_breakpoint_restore(void)
+{
+       set_debugreg(__get_cpu_var(cpu_debugreg[0]), 0);
+       set_debugreg(__get_cpu_var(cpu_debugreg[1]), 1);
+       set_debugreg(__get_cpu_var(cpu_debugreg[2]), 2);
+       set_debugreg(__get_cpu_var(cpu_debugreg[3]), 3);
+       set_debugreg(current->thread.debugreg6, 6);
+       set_debugreg(__get_cpu_var(cpu_dr7), 7);
+}
+EXPORT_SYMBOL_GPL(hw_breakpoint_restore);
+
+/*
+ * Handle debug exception notifications.
+ *
+ * Return value is either NOTIFY_STOP or NOTIFY_DONE as explained below.
+ *
+ * NOTIFY_DONE returned if one of the following conditions is true.
+ * i) When the causative address is from user-space and the exception
+ * is a valid one, i.e. not triggered as a result of lazy debug register
+ * switching
+ * ii) When there are more bits than trap<n> set in DR6 register (such
+ * as BD, BS or BT) indicating that more than one debug condition is
+ * met and requires some more action in do_debug().
+ *
+ * NOTIFY_STOP returned for all other cases
+ *
+ */
+static int __kprobes hw_breakpoint_handler(struct die_args *args)
+{
+       int i, cpu, rc = NOTIFY_STOP;
+       struct perf_event *bp;
+       unsigned long dr7, dr6;
+       unsigned long *dr6_p;
+
+       /* The DR6 value is pointed by args->err */
+       dr6_p = (unsigned long *)ERR_PTR(args->err);
+       dr6 = *dr6_p;
+
+       /* Do an early return if no trap bits are set in DR6 */
+       if ((dr6 & DR_TRAP_BITS) == 0)
+               return NOTIFY_DONE;
+
+       get_debugreg(dr7, 7);
+       /* Disable breakpoints during exception handling */
+       set_debugreg(0UL, 7);
+       /*
+        * Assert that local interrupts are disabled
+        * Reset the DRn bits in the virtualized register value.
+        * The ptrace trigger routine will add in whatever is needed.
+        */
+       current->thread.debugreg6 &= ~DR_TRAP_BITS;
+       cpu = get_cpu();
+
+       /* Handle all the breakpoints that were triggered */
+       for (i = 0; i < HBP_NUM; ++i) {
+               if (likely(!(dr6 & (DR_TRAP0 << i))))
+                       continue;
+
+               /*
+                * The counter may be concurrently released but that can only
+                * occur from a call_rcu() path. We can then safely fetch
+                * the breakpoint, use its callback, touch its counter
+                * while we are in an rcu_read_lock() path.
+                */
+               rcu_read_lock();
+
+               bp = per_cpu(bp_per_reg[i], cpu);
+               if (bp)
+                       rc = NOTIFY_DONE;
+               /*
+                * Reset the 'i'th TRAP bit in dr6 to denote completion of
+                * exception handling
+                */
+               (*dr6_p) &= ~(DR_TRAP0 << i);
+               /*
+                * bp can be NULL due to lazy debug register switching
+                * or due to concurrent perf counter removing.
+                */
+               if (!bp) {
+                       rcu_read_unlock();
+                       break;
+               }
+
+               (bp->callback)(bp, args->regs);
+
+               rcu_read_unlock();
+       }
+       if (dr6 & (~DR_TRAP_BITS))
+               rc = NOTIFY_DONE;
+
+       set_debugreg(dr7, 7);
+       put_cpu();
+
+       return rc;
+}
+
+/*
+ * Handle debug exception notifications.
+ */
+int __kprobes hw_breakpoint_exceptions_notify(
+               struct notifier_block *unused, unsigned long val, void *data)
+{
+       if (val != DIE_DEBUG)
+               return NOTIFY_DONE;
+
+       return hw_breakpoint_handler(data);
+}
+
+void hw_breakpoint_pmu_read(struct perf_event *bp)
+{
+       /* TODO */
+}
+
+void hw_breakpoint_pmu_unthrottle(struct perf_event *bp)
+{
+       /* TODO */
+}
index 04bbd52..fee6cc2 100644 (file)
@@ -92,17 +92,17 @@ static int show_other_interrupts(struct seq_file *p, int prec)
                seq_printf(p, "%10u ", irq_stats(j)->irq_tlb_count);
        seq_printf(p, "  TLB shootdowns\n");
 #endif
-#ifdef CONFIG_X86_MCE
+#ifdef CONFIG_X86_THERMAL_VECTOR
        seq_printf(p, "%*s: ", prec, "TRM");
        for_each_online_cpu(j)
                seq_printf(p, "%10u ", irq_stats(j)->irq_thermal_count);
        seq_printf(p, "  Thermal event interrupts\n");
-# ifdef CONFIG_X86_MCE_THRESHOLD
+#endif
+#ifdef CONFIG_X86_MCE_THRESHOLD
        seq_printf(p, "%*s: ", prec, "THR");
        for_each_online_cpu(j)
                seq_printf(p, "%10u ", irq_stats(j)->irq_threshold_count);
        seq_printf(p, "  Threshold APIC interrupts\n");
-# endif
 #endif
 #ifdef CONFIG_X86_MCE
        seq_printf(p, "%*s: ", prec, "MCE");
@@ -194,11 +194,11 @@ u64 arch_irq_stat_cpu(unsigned int cpu)
        sum += irq_stats(cpu)->irq_call_count;
        sum += irq_stats(cpu)->irq_tlb_count;
 #endif
-#ifdef CONFIG_X86_MCE
+#ifdef CONFIG_X86_THERMAL_VECTOR
        sum += irq_stats(cpu)->irq_thermal_count;
-# ifdef CONFIG_X86_MCE_THRESHOLD
+#endif
+#ifdef CONFIG_X86_MCE_THRESHOLD
        sum += irq_stats(cpu)->irq_threshold_count;
-# endif
 #endif
 #ifdef CONFIG_X86_MCE
        sum += per_cpu(mce_exception_count, cpu);
@@ -274,3 +274,93 @@ void smp_generic_interrupt(struct pt_regs *regs)
 }
 
 EXPORT_SYMBOL_GPL(vector_used_by_percpu_irq);
+
+#ifdef CONFIG_HOTPLUG_CPU
+/* A cpu has been removed from cpu_online_mask.  Reset irq affinities. */
+void fixup_irqs(void)
+{
+       unsigned int irq, vector;
+       static int warned;
+       struct irq_desc *desc;
+
+       for_each_irq_desc(irq, desc) {
+               int break_affinity = 0;
+               int set_affinity = 1;
+               const struct cpumask *affinity;
+
+               if (!desc)
+                       continue;
+               if (irq == 2)
+                       continue;
+
+               /* interrupt's are disabled at this point */
+               spin_lock(&desc->lock);
+
+               affinity = desc->affinity;
+               if (!irq_has_action(irq) ||
+                   cpumask_equal(affinity, cpu_online_mask)) {
+                       spin_unlock(&desc->lock);
+                       continue;
+               }
+
+               /*
+                * Complete the irq move. This cpu is going down and for
+                * non intr-remapping case, we can't wait till this interrupt
+                * arrives at this cpu before completing the irq move.
+                */
+               irq_force_complete_move(irq);
+
+               if (cpumask_any_and(affinity, cpu_online_mask) >= nr_cpu_ids) {
+                       break_affinity = 1;
+                       affinity = cpu_all_mask;
+               }
+
+               if (!(desc->status & IRQ_MOVE_PCNTXT) && desc->chip->mask)
+                       desc->chip->mask(irq);
+
+               if (desc->chip->set_affinity)
+                       desc->chip->set_affinity(irq, affinity);
+               else if (!(warned++))
+                       set_affinity = 0;
+
+               if (!(desc->status & IRQ_MOVE_PCNTXT) && desc->chip->unmask)
+                       desc->chip->unmask(irq);
+
+               spin_unlock(&desc->lock);
+
+               if (break_affinity && set_affinity)
+                       printk("Broke affinity for irq %i\n", irq);
+               else if (!set_affinity)
+                       printk("Cannot set affinity for irq %i\n", irq);
+       }
+
+       /*
+        * We can remove mdelay() and then send spuriuous interrupts to
+        * new cpu targets for all the irqs that were handled previously by
+        * this cpu. While it works, I have seen spurious interrupt messages
+        * (nothing wrong but still...).
+        *
+        * So for now, retain mdelay(1) and check the IRR and then send those
+        * interrupts to new targets as this cpu is already offlined...
+        */
+       mdelay(1);
+
+       for (vector = FIRST_EXTERNAL_VECTOR; vector < NR_VECTORS; vector++) {
+               unsigned int irr;
+
+               if (__get_cpu_var(vector_irq)[vector] < 0)
+                       continue;
+
+               irr = apic_read(APIC_IRR + (vector / 32 * 0x10));
+               if (irr  & (1 << (vector % 32))) {
+                       irq = __get_cpu_var(vector_irq)[vector];
+
+                       desc = irq_to_desc(irq);
+                       spin_lock(&desc->lock);
+                       if (desc->chip->retrigger)
+                               desc->chip->retrigger(irq);
+                       spin_unlock(&desc->lock);
+               }
+       }
+}
+#endif
index 7d35d0f..10709f2 100644 (file)
@@ -211,48 +211,3 @@ bool handle_irq(unsigned irq, struct pt_regs *regs)
 
        return true;
 }
-
-#ifdef CONFIG_HOTPLUG_CPU
-
-/* A cpu has been removed from cpu_online_mask.  Reset irq affinities. */
-void fixup_irqs(void)
-{
-       unsigned int irq;
-       struct irq_desc *desc;
-
-       for_each_irq_desc(irq, desc) {
-               const struct cpumask *affinity;
-
-               if (!desc)
-                       continue;
-               if (irq == 2)
-                       continue;
-
-               affinity = desc->affinity;
-               if (cpumask_any_and(affinity, cpu_online_mask) >= nr_cpu_ids) {
-                       printk("Breaking affinity for irq %i\n", irq);
-                       affinity = cpu_all_mask;
-               }
-               if (desc->chip->set_affinity)
-                       desc->chip->set_affinity(irq, affinity);
-               else if (desc->action)
-                       printk_once("Cannot set affinity for irq %i\n", irq);
-       }
-
-#if 0
-       barrier();
-       /* Ingo Molnar says: "after the IO-APIC masks have been redirected
-          [note the nop - the interrupt-enable boundary on x86 is two
-          instructions from sti] - to flush out pending hardirqs and
-          IPIs. After this point nothing is supposed to reach this CPU." */
-       __asm__ __volatile__("sti; nop; cli");
-       barrier();
-#else
-       /* That doesn't seem sufficient.  Give it 1ms. */
-       local_irq_enable();
-       mdelay(1);
-       local_irq_disable();
-#endif
-}
-#endif
-
index 977d8b4..acf8fbf 100644 (file)
@@ -62,64 +62,6 @@ bool handle_irq(unsigned irq, struct pt_regs *regs)
        return true;
 }
 
-#ifdef CONFIG_HOTPLUG_CPU
-/* A cpu has been removed from cpu_online_mask.  Reset irq affinities. */
-void fixup_irqs(void)
-{
-       unsigned int irq;
-       static int warned;
-       struct irq_desc *desc;
-
-       for_each_irq_desc(irq, desc) {
-               int break_affinity = 0;
-               int set_affinity = 1;
-               const struct cpumask *affinity;
-
-               if (!desc)
-                       continue;
-               if (irq == 2)
-                       continue;
-
-               /* interrupt's are disabled at this point */
-               spin_lock(&desc->lock);
-
-               affinity = desc->affinity;
-               if (!irq_has_action(irq) ||
-                   cpumask_equal(affinity, cpu_online_mask)) {
-                       spin_unlock(&desc->lock);
-                       continue;
-               }
-
-               if (cpumask_any_and(affinity, cpu_online_mask) >= nr_cpu_ids) {
-                       break_affinity = 1;
-                       affinity = cpu_all_mask;
-               }
-
-               if (desc->chip->mask)
-                       desc->chip->mask(irq);
-
-               if (desc->chip->set_affinity)
-                       desc->chip->set_affinity(irq, affinity);
-               else if (!(warned++))
-                       set_affinity = 0;
-
-               if (desc->chip->unmask)
-                       desc->chip->unmask(irq);
-
-               spin_unlock(&desc->lock);
-
-               if (break_affinity && set_affinity)
-                       printk("Broke affinity for irq %i\n", irq);
-               else if (!set_affinity)
-                       printk("Cannot set affinity for irq %i\n", irq);
-       }
-
-       /* That doesn't seem sufficient.  Give it 1ms. */
-       local_irq_enable();
-       mdelay(1);
-       local_irq_disable();
-}
-#endif
 
 extern void call_softirq(void);
 
index 8d82a77..20a5b36 100644 (file)
@@ -43,6 +43,7 @@
 #include <linux/smp.h>
 #include <linux/nmi.h>
 
+#include <asm/debugreg.h>
 #include <asm/apicdef.h>
 #include <asm/system.h>
 
@@ -88,7 +89,6 @@ void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs)
        gdb_regs[GDB_SS]        = __KERNEL_DS;
        gdb_regs[GDB_FS]        = 0xFFFF;
        gdb_regs[GDB_GS]        = 0xFFFF;
-       gdb_regs[GDB_SP]        = (int)&regs->sp;
 #else
        gdb_regs[GDB_R8]        = regs->r8;
        gdb_regs[GDB_R9]        = regs->r9;
@@ -101,8 +101,8 @@ void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs)
        gdb_regs32[GDB_PS]      = regs->flags;
        gdb_regs32[GDB_CS]      = regs->cs;
        gdb_regs32[GDB_SS]      = regs->ss;
-       gdb_regs[GDB_SP]        = regs->sp;
 #endif
+       gdb_regs[GDB_SP]        = kernel_stack_pointer(regs);
 }
 
 /**
@@ -434,6 +434,11 @@ single_step_cont(struct pt_regs *regs, struct die_args *args)
                        "resuming...\n");
        kgdb_arch_handle_exception(args->trapnr, args->signr,
                                   args->err, "c", "", regs);
+       /*
+        * Reset the BS bit in dr6 (pointed by args->err) to
+        * denote completion of processing
+        */
+       (*(unsigned long *)ERR_PTR(args->err)) &= ~DR_STEP;
 
        return NOTIFY_STOP;
 }
index 7b5169d..1f3186c 100644 (file)
 #include <linux/preempt.h>
 #include <linux/module.h>
 #include <linux/kdebug.h>
+#include <linux/kallsyms.h>
 
 #include <asm/cacheflush.h>
 #include <asm/desc.h>
 #include <asm/pgtable.h>
 #include <asm/uaccess.h>
 #include <asm/alternative.h>
+#include <asm/insn.h>
+#include <asm/debugreg.h>
 
 void jprobe_return_end(void);
 
 DEFINE_PER_CPU(struct kprobe *, current_kprobe) = NULL;
 DEFINE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk);
 
-#ifdef CONFIG_X86_64
-#define stack_addr(regs) ((unsigned long *)regs->sp)
-#else
-/*
- * "&regs->sp" looks wrong, but it's correct for x86_32.  x86_32 CPUs
- * don't save the ss and esp registers if the CPU is already in kernel
- * mode when it traps.  So for kprobes, regs->sp and regs->ss are not
- * the [nonexistent] saved stack pointer and ss register, but rather
- * the top 8 bytes of the pre-int3 stack.  So &regs->sp happens to
- * point to the top of the pre-int3 stack.
- */
-#define stack_addr(regs) ((unsigned long *)&regs->sp)
-#endif
+#define stack_addr(regs) ((unsigned long *)kernel_stack_pointer(regs))
 
 #define W(row, b0, b1, b2, b3, b4, b5, b6, b7, b8, b9, ba, bb, bc, bd, be, bf)\
        (((b0##UL << 0x0)|(b1##UL << 0x1)|(b2##UL << 0x2)|(b3##UL << 0x3) |   \
@@ -106,50 +97,6 @@ static const u32 twobyte_is_boostable[256 / 32] = {
        /*      -----------------------------------------------         */
        /*      0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f          */
 };
-static const u32 onebyte_has_modrm[256 / 32] = {
-       /*      0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f          */
-       /*      -----------------------------------------------         */
-       W(0x00, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0) | /* 00 */
-       W(0x10, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0) , /* 10 */
-       W(0x20, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0) | /* 20 */
-       W(0x30, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0) , /* 30 */
-       W(0x40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) | /* 40 */
-       W(0x50, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) , /* 50 */
-       W(0x60, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0) | /* 60 */
-       W(0x70, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) , /* 70 */
-       W(0x80, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) | /* 80 */
-       W(0x90, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) , /* 90 */
-       W(0xa0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) | /* a0 */
-       W(0xb0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) , /* b0 */
-       W(0xc0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0) | /* c0 */
-       W(0xd0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1) , /* d0 */
-       W(0xe0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) | /* e0 */
-       W(0xf0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1)   /* f0 */
-       /*      -----------------------------------------------         */
-       /*      0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f          */
-};
-static const u32 twobyte_has_modrm[256 / 32] = {
-       /*      0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f          */
-       /*      -----------------------------------------------         */
-       W(0x00, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1) | /* 0f */
-       W(0x10, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0) , /* 1f */
-       W(0x20, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1) | /* 2f */
-       W(0x30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) , /* 3f */
-       W(0x40, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) | /* 4f */
-       W(0x50, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) , /* 5f */
-       W(0x60, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) | /* 6f */
-       W(0x70, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1) , /* 7f */
-       W(0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) | /* 8f */
-       W(0x90, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) , /* 9f */
-       W(0xa0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1) | /* af */
-       W(0xb0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1) , /* bf */
-       W(0xc0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0) | /* cf */
-       W(0xd0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) , /* df */
-       W(0xe0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) | /* ef */
-       W(0xf0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0)   /* ff */
-       /*      -----------------------------------------------         */
-       /*      0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f          */
-};
 #undef W
 
 struct kretprobe_blackpoint kretprobe_blacklist[] = {
@@ -244,6 +191,75 @@ retry:
        }
 }
 
+/* Recover the probed instruction at addr for further analysis. */
+static int recover_probed_instruction(kprobe_opcode_t *buf, unsigned long addr)
+{
+       struct kprobe *kp;
+       kp = get_kprobe((void *)addr);
+       if (!kp)
+               return -EINVAL;
+
+       /*
+        *  Basically, kp->ainsn.insn has an original instruction.
+        *  However, RIP-relative instruction can not do single-stepping
+        *  at different place, fix_riprel() tweaks the displacement of
+        *  that instruction. In that case, we can't recover the instruction
+        *  from the kp->ainsn.insn.
+        *
+        *  On the other hand, kp->opcode has a copy of the first byte of
+        *  the probed instruction, which is overwritten by int3. And
+        *  the instruction at kp->addr is not modified by kprobes except
+        *  for the first byte, we can recover the original instruction
+        *  from it and kp->opcode.
+        */
+       memcpy(buf, kp->addr, MAX_INSN_SIZE * sizeof(kprobe_opcode_t));
+       buf[0] = kp->opcode;
+       return 0;
+}
+
+/* Dummy buffers for kallsyms_lookup */
+static char __dummy_buf[KSYM_NAME_LEN];
+
+/* Check if paddr is at an instruction boundary */
+static int __kprobes can_probe(unsigned long paddr)
+{
+       int ret;
+       unsigned long addr, offset = 0;
+       struct insn insn;
+       kprobe_opcode_t buf[MAX_INSN_SIZE];
+
+       if (!kallsyms_lookup(paddr, NULL, &offset, NULL, __dummy_buf))
+               return 0;
+
+       /* Decode instructions */
+       addr = paddr - offset;
+       while (addr < paddr) {
+               kernel_insn_init(&insn, (void *)addr);
+               insn_get_opcode(&insn);
+
+               /*
+                * Check if the instruction has been modified by another
+                * kprobe, in which case we replace the breakpoint by the
+                * original instruction in our buffer.
+                */
+               if (insn.opcode.bytes[0] == BREAKPOINT_INSTRUCTION) {
+                       ret = recover_probed_instruction(buf, addr);
+                       if (ret)
+                               /*
+                                * Another debugging subsystem might insert
+                                * this breakpoint. In that case, we can't
+                                * recover it.
+                                */
+                               return 0;
+                       kernel_insn_init(&insn, buf);
+               }
+               insn_get_length(&insn);
+               addr += insn.length;
+       }
+
+       return (addr == paddr);
+}
+
 /*
  * Returns non-zero if opcode modifies the interrupt flag.
  */
@@ -277,68 +293,30 @@ static int __kprobes is_IF_modifier(kprobe_opcode_t *insn)
 static void __kprobes fix_riprel(struct kprobe *p)
 {
 #ifdef CONFIG_X86_64
-       u8 *insn = p->ainsn.insn;
-       s64 disp;
-       int need_modrm;
-
-       /* Skip legacy instruction prefixes.  */
-       while (1) {
-               switch (*insn) {
-               case 0x66:
-               case 0x67:
-               case 0x2e:
-               case 0x3e:
-               case 0x26:
-               case 0x64:
-               case 0x65:
-               case 0x36:
-               case 0xf0:
-               case 0xf3:
-               case 0xf2:
-                       ++insn;
-                       continue;
-               }
-               break;
-       }
+       struct insn insn;
+       kernel_insn_init(&insn, p->ainsn.insn);
 
-       /* Skip REX instruction prefix.  */
-       if (is_REX_prefix(insn))
-               ++insn;
-
-       if (*insn == 0x0f) {
-               /* Two-byte opcode.  */
-               ++insn;
-               need_modrm = test_bit(*insn,
-                                     (unsigned long *)twobyte_has_modrm);
-       } else
-               /* One-byte opcode.  */
-               need_modrm = test_bit(*insn,
-                                     (unsigned long *)onebyte_has_modrm);
-
-       if (need_modrm) {
-               u8 modrm = *++insn;
-               if ((modrm & 0xc7) == 0x05) {
-                       /* %rip+disp32 addressing mode */
-                       /* Displacement follows ModRM byte.  */
-                       ++insn;
-                       /*
-                        * The copied instruction uses the %rip-relative
-                        * addressing mode.  Adjust the displacement for the
-                        * difference between the original location of this
-                        * instruction and the location of the copy that will
-                        * actually be run.  The tricky bit here is making sure
-                        * that the sign extension happens correctly in this
-                        * calculation, since we need a signed 32-bit result to
-                        * be sign-extended to 64 bits when it's added to the
-                        * %rip value and yield the same 64-bit result that the
-                        * sign-extension of the original signed 32-bit
-                        * displacement would have given.
-                        */
-                       disp = (u8 *) p->addr + *((s32 *) insn) -
-                              (u8 *) p->ainsn.insn;
-                       BUG_ON((s64) (s32) disp != disp); /* Sanity check.  */
-                       *(s32 *)insn = (s32) disp;
-               }
+       if (insn_rip_relative(&insn)) {
+               s64 newdisp;
+               u8 *disp;
+               insn_get_displacement(&insn);
+               /*
+                * The copied instruction uses the %rip-relative addressing
+                * mode.  Adjust the displacement for the difference between
+                * the original location of this instruction and the location
+                * of the copy that will actually be run.  The tricky bit here
+                * is making sure that the sign extension happens correctly in
+                * this calculation, since we need a signed 32-bit result to
+                * be sign-extended to 64 bits when it's added to the %rip
+                * value and yield the same 64-bit result that the sign-
+                * extension of the original signed 32-bit displacement would
+                * have given.
+                */
+               newdisp = (u8 *) p->addr + (s64) insn.displacement.value -
+                         (u8 *) p->ainsn.insn;
+               BUG_ON((s64) (s32) newdisp != newdisp); /* Sanity check.  */
+               disp = (u8 *) p->ainsn.insn + insn_offset_displacement(&insn);
+               *(s32 *) disp = (s32) newdisp;
        }
 #endif
 }
@@ -359,6 +337,8 @@ static void __kprobes arch_copy_kprobe(struct kprobe *p)
 
 int __kprobes arch_prepare_kprobe(struct kprobe *p)
 {
+       if (!can_probe((unsigned long)p->addr))
+               return -EILSEQ;
        /* insn: must be on special executable page on x86. */
        p->ainsn.insn = get_insn_slot();
        if (!p->ainsn.insn)
@@ -472,17 +452,6 @@ static int __kprobes reenter_kprobe(struct kprobe *p, struct pt_regs *regs,
 {
        switch (kcb->kprobe_status) {
        case KPROBE_HIT_SSDONE:
-#ifdef CONFIG_X86_64
-               /* TODO: Provide re-entrancy from post_kprobes_handler() and
-                * avoid exception stack corruption while single-stepping on
-                * the instruction of the new probe.
-                */
-               arch_disarm_kprobe(p);
-               regs->ip = (unsigned long)p->addr;
-               reset_current_kprobe();
-               preempt_enable_no_resched();
-               break;
-#endif
        case KPROBE_HIT_ACTIVE:
                save_previous_kprobe(kcb);
                set_current_kprobe(p, regs, kcb);
@@ -491,18 +460,16 @@ static int __kprobes reenter_kprobe(struct kprobe *p, struct pt_regs *regs,
                kcb->kprobe_status = KPROBE_REENTER;
                break;
        case KPROBE_HIT_SS:
-               if (p == kprobe_running()) {
-                       regs->flags &= ~X86_EFLAGS_TF;
-                       regs->flags |= kcb->kprobe_saved_flags;
-                       return 0;
-               } else {
-                       /* A probe has been hit in the codepath leading up
-                        * to, or just after, single-stepping of a probed
-                        * instruction. This entire codepath should strictly
-                        * reside in .kprobes.text section. Raise a warning
-                        * to highlight this peculiar case.
-                        */
-               }
+               /* A probe has been hit in the codepath leading up to, or just
+                * after, single-stepping of a probed instruction. This entire
+                * codepath should strictly reside in .kprobes.text section.
+                * Raise a BUG or we'll continue in an endless reentering loop
+                * and eventually a stack overflow.
+                */
+               printk(KERN_WARNING "Unrecoverable kprobe detected at %p.\n",
+                      p->addr);
+               dump_kprobe(p);
+               BUG();
        default:
                /* impossible cases */
                WARN_ON(1);
@@ -967,8 +934,14 @@ int __kprobes kprobe_exceptions_notify(struct notifier_block *self,
                        ret = NOTIFY_STOP;
                break;
        case DIE_DEBUG:
-               if (post_kprobe_handler(args->regs))
+               if (post_kprobe_handler(args->regs)) {
+                       /*
+                        * Reset the BS bit in dr6 (pointed by args->err) to
+                        * denote completion of processing
+                        */
+                       (*(unsigned long *)ERR_PTR(args->err)) &= ~DR_STEP;
                        ret = NOTIFY_STOP;
+               }
                break;
        case DIE_GPF:
                /*
index c1c429d..c843f84 100644 (file)
@@ -25,6 +25,7 @@
 #include <asm/desc.h>
 #include <asm/system.h>
 #include <asm/cacheflush.h>
+#include <asm/debugreg.h>
 
 static void set_idt(void *newidt, __u16 limit)
 {
@@ -202,6 +203,7 @@ void machine_kexec(struct kimage *image)
 
        /* Interrupts aren't acceptable while we reboot */
        local_irq_disable();
+       hw_breakpoint_disable();
 
        if (image->preserve_context) {
 #ifdef CONFIG_X86_IO_APIC
index 84c3bf2..4a8bb82 100644 (file)
@@ -18,6 +18,7 @@
 #include <asm/pgtable.h>
 #include <asm/tlbflush.h>
 #include <asm/mmu_context.h>
+#include <asm/debugreg.h>
 
 static int init_one_level2_page(struct kimage *image, pgd_t *pgd,
                                unsigned long addr)
@@ -282,6 +283,7 @@ void machine_kexec(struct kimage *image)
 
        /* Interrupts aren't acceptable while we reboot */
        local_irq_disable();
+       hw_breakpoint_disable();
 
        if (image->preserve_context) {
 #ifdef CONFIG_X86_IO_APIC
index 378e9a8..2bcad39 100644 (file)
@@ -73,7 +73,6 @@
 #include <linux/platform_device.h>
 #include <linux/miscdevice.h>
 #include <linux/capability.h>
-#include <linux/smp_lock.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/mutex.h>
@@ -201,7 +200,6 @@ static int do_microcode_update(const void __user *buf, size_t size)
 
 static int microcode_open(struct inode *unused1, struct file *unused2)
 {
-       cycle_kernel_lock();
        return capable(CAP_SYS_RAWIO) ? 0 : -EPERM;
 }
 
index 6a3cefc..5534499 100644 (file)
@@ -174,21 +174,17 @@ static int msr_open(struct inode *inode, struct file *file)
 {
        unsigned int cpu = iminor(file->f_path.dentry->d_inode);
        struct cpuinfo_x86 *c = &cpu_data(cpu);
-       int ret = 0;
 
-       lock_kernel();
        cpu = iminor(file->f_path.dentry->d_inode);
 
-       if (cpu >= nr_cpu_ids || !cpu_online(cpu)) {
-               ret = -ENXIO;   /* No such CPU */
-               goto out;
-       }
+       if (cpu >= nr_cpu_ids || !cpu_online(cpu))
+               return -ENXIO;  /* No such CPU */
+
        c = &cpu_data(cpu);
        if (!cpu_has(c, X86_FEATURE_MSR))
-               ret = -EIO;     /* MSR not supported */
-out:
-       unlock_kernel();
-       return ret;
+               return -EIO;    /* MSR not supported */
+
+       return 0;
 }
 
 /*
index 5284cd2..5e2ba63 100644 (file)
@@ -9,7 +9,9 @@
 #include <linux/pm.h>
 #include <linux/clockchips.h>
 #include <linux/random.h>
+#include <linux/user-return-notifier.h>
 #include <trace/events/power.h>
+#include <linux/hw_breakpoint.h>
 #include <asm/system.h>
 #include <asm/apic.h>
 #include <asm/syscalls.h>
@@ -17,6 +19,7 @@
 #include <asm/uaccess.h>
 #include <asm/i387.h>
 #include <asm/ds.h>
+#include <asm/debugreg.h>
 
 unsigned long idle_halt;
 EXPORT_SYMBOL(idle_halt);
@@ -103,14 +106,7 @@ void flush_thread(void)
        }
 #endif
 
-       clear_tsk_thread_flag(tsk, TIF_DEBUG);
-
-       tsk->thread.debugreg0 = 0;
-       tsk->thread.debugreg1 = 0;
-       tsk->thread.debugreg2 = 0;
-       tsk->thread.debugreg3 = 0;
-       tsk->thread.debugreg6 = 0;
-       tsk->thread.debugreg7 = 0;
+       flush_ptrace_hw_breakpoint(tsk);
        memset(tsk->thread.tls_array, 0, sizeof(tsk->thread.tls_array));
        /*
         * Forget coprocessor state..
@@ -192,16 +188,6 @@ void __switch_to_xtra(struct task_struct *prev_p, struct task_struct *next_p,
        else if (next->debugctlmsr != prev->debugctlmsr)
                update_debugctlmsr(next->debugctlmsr);
 
-       if (test_tsk_thread_flag(next_p, TIF_DEBUG)) {
-               set_debugreg(next->debugreg0, 0);
-               set_debugreg(next->debugreg1, 1);
-               set_debugreg(next->debugreg2, 2);
-               set_debugreg(next->debugreg3, 3);
-               /* no 4 and 5 */
-               set_debugreg(next->debugreg6, 6);
-               set_debugreg(next->debugreg7, 7);
-       }
-
        if (test_tsk_thread_flag(prev_p, TIF_NOTSC) ^
            test_tsk_thread_flag(next_p, TIF_NOTSC)) {
                /* prev and next are different */
@@ -224,6 +210,7 @@ void __switch_to_xtra(struct task_struct *prev_p, struct task_struct *next_p,
                 */
                memset(tss->io_bitmap, 0xff, prev->io_bitmap_max);
        }
+       propagate_user_return_notify(prev_p, next_p);
 }
 
 int sys_fork(struct pt_regs *regs)
index 4cf7956..075580b 100644 (file)
@@ -58,6 +58,7 @@
 #include <asm/idle.h>
 #include <asm/syscalls.h>
 #include <asm/ds.h>
+#include <asm/debugreg.h>
 
 asmlinkage void ret_from_fork(void) __asm__("ret_from_fork");
 
@@ -134,7 +135,7 @@ void __show_regs(struct pt_regs *regs, int all)
                ss = regs->ss & 0xffff;
                gs = get_user_gs(regs);
        } else {
-               sp = (unsigned long) (&regs->sp);
+               sp = kernel_stack_pointer(regs);
                savesegment(ss, ss);
                savesegment(gs, gs);
        }
@@ -187,7 +188,7 @@ void __show_regs(struct pt_regs *regs, int all)
 
 void show_regs(struct pt_regs *regs)
 {
-       __show_regs(regs, 1);
+       show_registers(regs);
        show_trace(NULL, regs, &regs->sp, regs->bp);
 }
 
@@ -259,7 +260,12 @@ int copy_thread(unsigned long clone_flags, unsigned long sp,
 
        task_user_gs(p) = get_user_gs(regs);
 
+       p->thread.io_bitmap_ptr = NULL;
        tsk = current;
+       err = -ENOMEM;
+
+       memset(p->thread.ptrace_bps, 0, sizeof(p->thread.ptrace_bps));
+
        if (unlikely(test_tsk_thread_flag(tsk, TIF_IO_BITMAP))) {
                p->thread.io_bitmap_ptr = kmemdup(tsk->thread.io_bitmap_ptr,
                                                IO_BITMAP_BYTES, GFP_KERNEL);
index eb62cbc..a98fe88 100644 (file)
@@ -52,6 +52,7 @@
 #include <asm/idle.h>
 #include <asm/syscalls.h>
 #include <asm/ds.h>
+#include <asm/debugreg.h>
 
 asmlinkage extern void ret_from_fork(void);
 
@@ -226,8 +227,7 @@ void __show_regs(struct pt_regs *regs, int all)
 
 void show_regs(struct pt_regs *regs)
 {
-       printk(KERN_INFO "CPU %d:", smp_processor_id());
-       __show_regs(regs, 1);
+       show_registers(regs);
        show_trace(NULL, regs, (void *)(regs + 1), regs->bp);
 }
 
@@ -297,12 +297,16 @@ int copy_thread(unsigned long clone_flags, unsigned long sp,
 
        p->thread.fs = me->thread.fs;
        p->thread.gs = me->thread.gs;
+       p->thread.io_bitmap_ptr = NULL;
 
        savesegment(gs, p->thread.gsindex);
        savesegment(fs, p->thread.fsindex);
        savesegment(es, p->thread.es);
        savesegment(ds, p->thread.ds);
 
+       err = -ENOMEM;
+       memset(p->thread.ptrace_bps, 0, sizeof(p->thread.ptrace_bps));
+
        if (unlikely(test_tsk_thread_flag(me, TIF_IO_BITMAP))) {
                p->thread.io_bitmap_ptr = kmalloc(IO_BITMAP_BYTES, GFP_KERNEL);
                if (!p->thread.io_bitmap_ptr) {
@@ -341,6 +345,7 @@ out:
                kfree(p->thread.io_bitmap_ptr);
                p->thread.io_bitmap_max = 0;
        }
+
        return err;
 }
 
@@ -495,6 +500,7 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p)
         */
        if (preload_fpu)
                __math_state_restore();
+
        return prev_p;
 }
 
index 7b058a2..04d182a 100644 (file)
@@ -22,6 +22,8 @@
 #include <linux/seccomp.h>
 #include <linux/signal.h>
 #include <linux/workqueue.h>
+#include <linux/perf_event.h>
+#include <linux/hw_breakpoint.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
@@ -34,6 +36,7 @@
 #include <asm/prctl.h>
 #include <asm/proto.h>
 #include <asm/ds.h>
+#include <asm/hw_breakpoint.h>
 
 #include "tls.h"
 
@@ -49,6 +52,118 @@ enum x86_regset {
        REGSET_IOPERM32,
 };
 
+struct pt_regs_offset {
+       const char *name;
+       int offset;
+};
+
+#define REG_OFFSET_NAME(r) {.name = #r, .offset = offsetof(struct pt_regs, r)}
+#define REG_OFFSET_END {.name = NULL, .offset = 0}
+
+static const struct pt_regs_offset regoffset_table[] = {
+#ifdef CONFIG_X86_64
+       REG_OFFSET_NAME(r15),
+       REG_OFFSET_NAME(r14),
+       REG_OFFSET_NAME(r13),
+       REG_OFFSET_NAME(r12),
+       REG_OFFSET_NAME(r11),
+       REG_OFFSET_NAME(r10),
+       REG_OFFSET_NAME(r9),
+       REG_OFFSET_NAME(r8),
+#endif
+       REG_OFFSET_NAME(bx),
+       REG_OFFSET_NAME(cx),
+       REG_OFFSET_NAME(dx),
+       REG_OFFSET_NAME(si),
+       REG_OFFSET_NAME(di),
+       REG_OFFSET_NAME(bp),
+       REG_OFFSET_NAME(ax),
+#ifdef CONFIG_X86_32
+       REG_OFFSET_NAME(ds),
+       REG_OFFSET_NAME(es),
+       REG_OFFSET_NAME(fs),
+       REG_OFFSET_NAME(gs),
+#endif
+       REG_OFFSET_NAME(orig_ax),
+       REG_OFFSET_NAME(ip),
+       REG_OFFSET_NAME(cs),
+       REG_OFFSET_NAME(flags),
+       REG_OFFSET_NAME(sp),
+       REG_OFFSET_NAME(ss),
+       REG_OFFSET_END,
+};
+
+/**
+ * regs_query_register_offset() - query register offset from its name
+ * @name:      the name of a register
+ *
+ * regs_query_register_offset() returns the offset of a register in struct
+ * pt_regs from its name. If the name is invalid, this returns -EINVAL;
+ */
+int regs_query_register_offset(const char *name)
+{
+       const struct pt_regs_offset *roff;
+       for (roff = regoffset_table; roff->name != NULL; roff++)
+               if (!strcmp(roff->name, name))
+                       return roff->offset;
+       return -EINVAL;
+}
+
+/**
+ * regs_query_register_name() - query register name from its offset
+ * @offset:    the offset of a register in struct pt_regs.
+ *
+ * regs_query_register_name() returns the name of a register from its
+ * offset in struct pt_regs. If the @offset is invalid, this returns NULL;
+ */
+const char *regs_query_register_name(unsigned int offset)
+{
+       const struct pt_regs_offset *roff;
+       for (roff = regoffset_table; roff->name != NULL; roff++)
+               if (roff->offset == offset)
+                       return roff->name;
+       return NULL;
+}
+
+static const int arg_offs_table[] = {
+#ifdef CONFIG_X86_32
+       [0] = offsetof(struct pt_regs, ax),
+       [1] = offsetof(struct pt_regs, dx),
+       [2] = offsetof(struct pt_regs, cx)
+#else /* CONFIG_X86_64 */
+       [0] = offsetof(struct pt_regs, di),
+       [1] = offsetof(struct pt_regs, si),
+       [2] = offsetof(struct pt_regs, dx),
+       [3] = offsetof(struct pt_regs, cx),
+       [4] = offsetof(struct pt_regs, r8),
+       [5] = offsetof(struct pt_regs, r9)
+#endif
+};
+
+/**
+ * regs_get_argument_nth() - get Nth argument at function call
+ * @regs:      pt_regs which contains registers at function entry.
+ * @n:         argument number.
+ *
+ * regs_get_argument_nth() returns @n th argument of a function call.
+ * Since usually the kernel stack will be changed right after function entry,
+ * you must use this at function entry. If the @n th entry is NOT in the
+ * kernel stack or pt_regs, this returns 0.
+ */
+unsigned long regs_get_argument_nth(struct pt_regs *regs, unsigned int n)
+{
+       if (n < ARRAY_SIZE(arg_offs_table))
+               return *(unsigned long *)((char *)regs + arg_offs_table[n]);
+       else {
+               /*
+                * The typical case: arg n is on the stack.
+                * (Note: stack[0] = return address, so skip it)
+                */
+               n -= ARRAY_SIZE(arg_offs_table);
+               return regs_get_kernel_stack_nth(regs, 1 + n);
+       }
+}
+
 /*
  * does not yet catch signals sent when the child dies.
  * in exit.c or in signal.c.
@@ -137,11 +252,6 @@ static int set_segment_reg(struct task_struct *task,
        return 0;
 }
 
-static unsigned long debugreg_addr_limit(struct task_struct *task)
-{
-       return TASK_SIZE - 3;
-}
-
 #else  /* CONFIG_X86_64 */
 
 #define FLAG_MASK              (FLAG_MASK_32 | X86_EFLAGS_NT)
@@ -266,15 +376,6 @@ static int set_segment_reg(struct task_struct *task,
        return 0;
 }
 
-static unsigned long debugreg_addr_limit(struct task_struct *task)
-{
-#ifdef CONFIG_IA32_EMULATION
-       if (test_tsk_thread_flag(task, TIF_IA32))
-               return IA32_PAGE_OFFSET - 3;
-#endif
-       return TASK_SIZE_MAX - 7;
-}
-
 #endif /* CONFIG_X86_32 */
 
 static unsigned long get_flags(struct task_struct *task)
@@ -454,99 +555,239 @@ static int genregs_set(struct task_struct *target,
        return ret;
 }
 
+static void ptrace_triggered(struct perf_event *bp, void *data)
+{
+       int i;
+       struct thread_struct *thread = &(current->thread);
+
+       /*
+        * Store in the virtual DR6 register the fact that the breakpoint
+        * was hit so the thread's debugger will see it.
+        */
+       for (i = 0; i < HBP_NUM; i++) {
+               if (thread->ptrace_bps[i] == bp)
+                       break;
+       }
+
+       thread->debugreg6 |= (DR_TRAP0 << i);
+}
+
 /*
- * This function is trivial and will be inlined by the compiler.
- * Having it separates the implementation details of debug
- * registers from the interface details of ptrace.
+ * Walk through every ptrace breakpoints for this thread and
+ * build the dr7 value on top of their attributes.
+ *
  */
-static unsigned long ptrace_get_debugreg(struct task_struct *child, int n)
+static unsigned long ptrace_get_dr7(struct perf_event *bp[])
 {
-       switch (n) {
-       case 0:         return child->thread.debugreg0;
-       case 1:         return child->thread.debugreg1;
-       case 2:         return child->thread.debugreg2;
-       case 3:         return child->thread.debugreg3;
-       case 6:         return child->thread.debugreg6;
-       case 7:         return child->thread.debugreg7;
+       int i;
+       int dr7 = 0;
+       struct arch_hw_breakpoint *info;
+
+       for (i = 0; i < HBP_NUM; i++) {
+               if (bp[i] && !bp[i]->attr.disabled) {
+                       info = counter_arch_bp(bp[i]);
+                       dr7 |= encode_dr7(i, info->len, info->type);
+               }
        }
-       return 0;
+
+       return dr7;
 }
 
-static int ptrace_set_debugreg(struct task_struct *child,
-                              int n, unsigned long data)
+static struct perf_event *
+ptrace_modify_breakpoint(struct perf_event *bp, int len, int type,
+                        struct task_struct *tsk, int disabled)
 {
-       int i;
+       int err;
+       int gen_len, gen_type;
+       DEFINE_BREAKPOINT_ATTR(attr);
 
-       if (unlikely(n == 4 || n == 5))
-               return -EIO;
+       /*
+        * We shoud have at least an inactive breakpoint at this
+        * slot. It means the user is writing dr7 without having
+        * written the address register first
+        */
+       if (!bp)
+               return ERR_PTR(-EINVAL);
 
-       if (n < 4 && unlikely(data >= debugreg_addr_limit(child)))
-               return -EIO;
+       err = arch_bp_generic_fields(len, type, &gen_len, &gen_type);
+       if (err)
+               return ERR_PTR(err);
 
-       switch (n) {
-       case 0:         child->thread.debugreg0 = data; break;
-       case 1:         child->thread.debugreg1 = data; break;
-       case 2:         child->thread.debugreg2 = data; break;
-       case 3:         child->thread.debugreg3 = data; break;
+       attr = bp->attr;
+       attr.bp_len = gen_len;
+       attr.bp_type = gen_type;
+       attr.disabled = disabled;
 
-       case 6:
-               if ((data & ~0xffffffffUL) != 0)
-                       return -EIO;
-               child->thread.debugreg6 = data;
-               break;
+       return modify_user_hw_breakpoint(bp, &attr, bp->callback, tsk);
+}
+
+/*
+ * Handle ptrace writes to debug register 7.
+ */
+static int ptrace_write_dr7(struct task_struct *tsk, unsigned long data)
+{
+       struct thread_struct *thread = &(tsk->thread);
+       unsigned long old_dr7;
+       int i, orig_ret = 0, rc = 0;
+       int enabled, second_pass = 0;
+       unsigned len, type;
+       struct perf_event *bp;
+
+       data &= ~DR_CONTROL_RESERVED;
+       old_dr7 = ptrace_get_dr7(thread->ptrace_bps);
+restore:
+       /*
+        * Loop through all the hardware breakpoints, making the
+        * appropriate changes to each.
+        */
+       for (i = 0; i < HBP_NUM; i++) {
+               enabled = decode_dr7(data, i, &len, &type);
+               bp = thread->ptrace_bps[i];
+
+               if (!enabled) {
+                       if (bp) {
+                               /*
+                                * Don't unregister the breakpoints right-away,
+                                * unless all register_user_hw_breakpoint()
+                                * requests have succeeded. This prevents
+                                * any window of opportunity for debug
+                                * register grabbing by other users.
+                                */
+                               if (!second_pass)
+                                       continue;
+
+                               thread->ptrace_bps[i] = NULL;
+                               bp = ptrace_modify_breakpoint(bp, len, type,
+                                                             tsk, 1);
+                               if (IS_ERR(bp)) {
+                                       rc = PTR_ERR(bp);
+                                       thread->ptrace_bps[i] = NULL;
+                                       break;
+                               }
+                               thread->ptrace_bps[i] = bp;
+                       }
+                       continue;
+               }
+
+               bp = ptrace_modify_breakpoint(bp, len, type, tsk, 0);
+
+               /* Incorrect bp, or we have a bug in bp API */
+               if (IS_ERR(bp)) {
+                       rc = PTR_ERR(bp);
+                       thread->ptrace_bps[i] = NULL;
+                       break;
+               }
+               thread->ptrace_bps[i] = bp;
+       }
+       /*
+        * Make a second pass to free the remaining unused breakpoints
+        * or to restore the original breakpoints if an error occurred.
+        */
+       if (!second_pass) {
+               second_pass = 1;
+               if (rc < 0) {
+                       orig_ret = rc;
+                       data = old_dr7;
+               }
+               goto restore;
+       }
+       return ((orig_ret < 0) ? orig_ret : rc);
+}
+
+/*
+ * Handle PTRACE_PEEKUSR calls for the debug register area.
+ */
+static unsigned long ptrace_get_debugreg(struct task_struct *tsk, int n)
+{
+       struct thread_struct *thread = &(tsk->thread);
+       unsigned long val = 0;
 
-       case 7:
+       if (n < HBP_NUM) {
+               struct perf_event *bp;
+               bp = thread->ptrace_bps[n];
+               if (!bp)
+                       return 0;
+               val = bp->hw.info.address;
+       } else if (n == 6) {
+               val = thread->debugreg6;
+        } else if (n == 7) {
+               val = ptrace_get_dr7(thread->ptrace_bps);
+       }
+       return val;
+}
+
+static int ptrace_set_breakpoint_addr(struct task_struct *tsk, int nr,
+                                     unsigned long addr)
+{
+       struct perf_event *bp;
+       struct thread_struct *t = &tsk->thread;
+       DEFINE_BREAKPOINT_ATTR(attr);
+
+       if (!t->ptrace_bps[nr]) {
                /*
-                * Sanity-check data. Take one half-byte at once with
-                * check = (val >> (16 + 4*i)) & 0xf. It contains the
-                * R/Wi and LENi bits; bits 0 and 1 are R/Wi, and bits
-                * 2 and 3 are LENi. Given a list of invalid values,
-                * we do mask |= 1 << invalid_value, so that
-                * (mask >> check) & 1 is a correct test for invalid
-                * values.
-                *
-                * R/Wi contains the type of the breakpoint /
-                * watchpoint, LENi contains the length of the watched
-                * data in the watchpoint case.
-                *
-                * The invalid values are:
-                * - LENi == 0x10 (undefined), so mask |= 0x0f00.       [32-bit]
-                * - R/Wi == 0x10 (break on I/O reads or writes), so
-                *   mask |= 0x4444.
-                * - R/Wi == 0x00 && LENi != 0x00, so we have mask |=
-                *   0x1110.
-                *
-                * Finally, mask = 0x0f00 | 0x4444 | 0x1110 == 0x5f54.
-                *
-                * See the Intel Manual "System Programming Guide",
-                * 15.2.4
-                *
-                * Note that LENi == 0x10 is defined on x86_64 in long
-                * mode (i.e. even for 32-bit userspace software, but
-                * 64-bit kernel), so the x86_64 mask value is 0x5454.
-                * See the AMD manual no. 24593 (AMD64 System Programming)
+                * Put stub len and type to register (reserve) an inactive but
+                * correct bp
                 */
-#ifdef CONFIG_X86_32
-#define        DR7_MASK        0x5f54
-#else
-#define        DR7_MASK        0x5554
-#endif
-               data &= ~DR_CONTROL_RESERVED;
-               for (i = 0; i < 4; i++)
-                       if ((DR7_MASK >> ((data >> (16 + 4*i)) & 0xf)) & 1)
-                               return -EIO;
-               child->thread.debugreg7 = data;
-               if (data)
-                       set_tsk_thread_flag(child, TIF_DEBUG);
-               else
-                       clear_tsk_thread_flag(child, TIF_DEBUG);
-               break;
+               attr.bp_addr = addr;
+               attr.bp_len = HW_BREAKPOINT_LEN_1;
+               attr.bp_type = HW_BREAKPOINT_W;
+               attr.disabled = 1;
+
+               bp = register_user_hw_breakpoint(&attr, ptrace_triggered, tsk);
+       } else {
+               bp = t->ptrace_bps[nr];
+               t->ptrace_bps[nr] = NULL;
+
+               attr = bp->attr;
+               attr.bp_addr = addr;
+               bp = modify_user_hw_breakpoint(bp, &attr, bp->callback, tsk);
        }
+       /*
+        * CHECKME: the previous code returned -EIO if the addr wasn't a
+        * valid task virtual addr. The new one will return -EINVAL in this
+        * case.
+        * -EINVAL may be what we want for in-kernel breakpoints users, but
+        * -EIO looks better for ptrace, since we refuse a register writing
+        * for the user. And anyway this is the previous behaviour.
+        */
+       if (IS_ERR(bp))
+               return PTR_ERR(bp);
+
+       t->ptrace_bps[nr] = bp;
 
        return 0;
 }
 
 /*
+ * Handle PTRACE_POKEUSR calls for the debug register area.
+ */
+int ptrace_set_debugreg(struct task_struct *tsk, int n, unsigned long val)
+{
+       struct thread_struct *thread = &(tsk->thread);
+       int rc = 0;
+
+       /* There are no DR4 or DR5 registers */
+       if (n == 4 || n == 5)
+               return -EIO;
+
+       if (n == 6) {
+               thread->debugreg6 = val;
+               goto ret_path;
+       }
+       if (n < HBP_NUM) {
+               rc = ptrace_set_breakpoint_addr(tsk, n, val);
+               if (rc)
+                       return rc;
+       }
+       /* All that's left is DR7 */
+       if (n == 7)
+               rc = ptrace_write_dr7(tsk, val);
+
+ret_path:
+       return rc;
+}
+
+/*
  * These access the current or another (stopped) task's io permission
  * bitmap for debugging or core dump.
  */
index 2a34f9c..82e88cd 100644 (file)
 #ifdef CONFIG_X86_64
 #include <asm/numa_64.h>
 #endif
+#include <asm/mce.h>
 
 /*
  * end_pfn only includes RAM, while max_pfn_mapped includes all e820 entries.
@@ -247,7 +248,7 @@ EXPORT_SYMBOL(edd);
  *              from boot_params into a safe place.
  *
  */
-static inline void copy_edd(void)
+static inline void __init copy_edd(void)
 {
      memcpy(edd.mbr_signature, boot_params.edd_mbr_sig_buffer,
            sizeof(edd.mbr_signature));
@@ -256,7 +257,7 @@ static inline void copy_edd(void)
      edd.edd_info_nr = boot_params.eddbuf_entries;
 }
 #else
-static inline void copy_edd(void)
+static inline void __init copy_edd(void)
 {
 }
 #endif
@@ -1031,6 +1032,8 @@ void __init setup_arch(char **cmdline_p)
 #endif
 #endif
        x86_init.oem.banner();
+
+       mcheck_init();
 }
 
 #ifdef CONFIG_X86_32
index 6a44a76..74fe6d8 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/stddef.h>
 #include <linux/personality.h>
 #include <linux/uaccess.h>
+#include <linux/user-return-notifier.h>
 
 #include <asm/processor.h>
 #include <asm/ucontext.h>
@@ -799,15 +800,6 @@ static void do_signal(struct pt_regs *regs)
 
        signr = get_signal_to_deliver(&info, &ka, regs, NULL);
        if (signr > 0) {
-               /*
-                * Re-enable any watchpoints before delivering the
-                * signal to user space. The processor register will
-                * have been cleared if the watchpoint triggered
-                * inside the kernel.
-                */
-               if (current->thread.debugreg7)
-                       set_debugreg(current->thread.debugreg7, 7);
-
                /* Whee! Actually deliver the signal.  */
                if (handle_signal(signr, &info, &ka, oldset, regs) == 0) {
                        /*
@@ -872,6 +864,8 @@ do_notify_resume(struct pt_regs *regs, void *unused, __u32 thread_info_flags)
                if (current->replacement_session_keyring)
                        key_replace_session_keyring();
        }
+       if (thread_info_flags & _TIF_USER_RETURN_NOTIFY)
+               fire_user_return_notifiers();
 
 #ifdef CONFIG_X86_32
        clear_thread_flag(TIF_IRET);
index 565ebc6..324f2a4 100644 (file)
@@ -1250,16 +1250,7 @@ static void __ref remove_cpu_from_maps(int cpu)
 void cpu_disable_common(void)
 {
        int cpu = smp_processor_id();
-       /*
-        * HACK:
-        * Allow any queued timer interrupts to get serviced
-        * This is only a temporary solution until we cleanup
-        * fixup_irqs as we do for IA64.
-        */
-       local_irq_enable();
-       mdelay(1);
 
-       local_irq_disable();
        remove_siblinginfo(cpu);
 
        /* It's now safe to remove this processor from the online map */
index 7e37dce..3339917 100644 (file)
@@ -529,77 +529,56 @@ asmlinkage __kprobes struct pt_regs *sync_regs(struct pt_regs *eregs)
 dotraplinkage void __kprobes do_debug(struct pt_regs *regs, long error_code)
 {
        struct task_struct *tsk = current;
-       unsigned long condition;
+       unsigned long dr6;
        int si_code;
 
-       get_debugreg(condition, 6);
+       get_debugreg(dr6, 6);
 
        /* Catch kmemcheck conditions first of all! */
-       if (condition & DR_STEP && kmemcheck_trap(regs))
+       if ((dr6 & DR_STEP) && kmemcheck_trap(regs))
                return;
 
+       /* DR6 may or may not be cleared by the CPU */
+       set_debugreg(0, 6);
        /*
         * The processor cleared BTF, so don't mark that we need it set.
         */
        clear_tsk_thread_flag(tsk, TIF_DEBUGCTLMSR);
        tsk->thread.debugctlmsr = 0;
 
-       if (notify_die(DIE_DEBUG, "debug", regs, condition, error_code,
-                                               SIGTRAP) == NOTIFY_STOP)
+       /* Store the virtualized DR6 value */
+       tsk->thread.debugreg6 = dr6;
+
+       if (notify_die(DIE_DEBUG, "debug", regs, PTR_ERR(&dr6), error_code,
+                                                       SIGTRAP) == NOTIFY_STOP)
                return;
 
        /* It's safe to allow irq's after DR6 has been saved */
        preempt_conditional_sti(regs);
 
-       /* Mask out spurious debug traps due to lazy DR7 setting */
-       if (condition & (DR_TRAP0|DR_TRAP1|DR_TRAP2|DR_TRAP3)) {
-               if (!tsk->thread.debugreg7)
-                       goto clear_dr7;
+       if (regs->flags & X86_VM_MASK) {
+               handle_vm86_trap((struct kernel_vm86_regs *) regs,
+                               error_code, 1);
+               return;
        }
 
-#ifdef CONFIG_X86_32
-       if (regs->flags & X86_VM_MASK)
-               goto debug_vm86;
-#endif
-
-       /* Save debug status register where ptrace can see it */
-       tsk->thread.debugreg6 = condition;
-
        /*
-        * Single-stepping through TF: make sure we ignore any events in
-        * kernel space (but re-enable TF when returning to user mode).
+        * Single-stepping through system calls: ignore any exceptions in
+        * kernel space, but re-enable TF when returning to user mode.
+        *
+        * We already checked v86 mode above, so we can check for kernel mode
+        * by just checking the CPL of CS.
         */
-       if (condition & DR_STEP) {
-               if (!user_mode(regs))
-                       goto clear_TF_reenable;
+       if ((dr6 & DR_STEP) && !user_mode(regs)) {
+               tsk->thread.debugreg6 &= ~DR_STEP;
+               set_tsk_thread_flag(tsk, TIF_SINGLESTEP);
+               regs->flags &= ~X86_EFLAGS_TF;
        }
-
-       si_code = get_si_code(condition);
-       /* Ok, finally something we can handle */
-       send_sigtrap(tsk, regs, error_code, si_code);
-
-       /*
-        * Disable additional traps. They'll be re-enabled when
-        * the signal is delivered.
-        */
-clear_dr7:
-       set_debugreg(0, 7);
+       si_code = get_si_code(tsk->thread.debugreg6);
+       if (tsk->thread.debugreg6 & (DR_STEP | DR_TRAP_BITS))
+               send_sigtrap(tsk, regs, error_code, si_code);
        preempt_conditional_cli(regs);
-       return;
 
-#ifdef CONFIG_X86_32
-debug_vm86:
-       /* reenable preemption: handle_vm86_trap() might sleep */
-       dec_preempt_count();
-       handle_vm86_trap((struct kernel_vm86_regs *) regs, error_code, 1);
-       conditional_cli(regs);
-       return;
-#endif
-
-clear_TF_reenable:
-       set_tsk_thread_flag(tsk, TIF_SINGLESTEP);
-       regs->flags &= ~X86_EFLAGS_TF;
-       preempt_conditional_cli(regs);
        return;
 }
 
index f379309..eed1568 100644 (file)
@@ -114,13 +114,12 @@ void __cpuinit check_tsc_sync_source(int cpu)
                return;
 
        if (boot_cpu_has(X86_FEATURE_TSC_RELIABLE)) {
-               printk_once(KERN_INFO "Skipping synchronization checks as TSC is reliable.\n");
+               if (cpu == (nr_cpu_ids-1) || system_state != SYSTEM_BOOTING)
+                       pr_info(
+                       "Skipped synchronization checks as TSC is reliable.\n");
                return;
        }
 
-       pr_info("checking TSC synchronization [CPU#%d -> CPU#%d]:",
-               smp_processor_id(), cpu);
-
        /*
         * Reset it - in case this is a second bootup:
         */
@@ -142,12 +141,14 @@ void __cpuinit check_tsc_sync_source(int cpu)
                cpu_relax();
 
        if (nr_warps) {
-               printk("\n");
+               pr_warning("TSC synchronization [CPU#%d -> CPU#%d]:\n",
+                       smp_processor_id(), cpu);
                pr_warning("Measured %Ld cycles TSC warp between CPUs, "
                           "turning off TSC clock.\n", max_warp);
                mark_tsc_unstable("check_tsc_sync_source failed");
        } else {
-               printk(" passed.\n");
+               pr_debug("TSC synchronization [CPU#%d -> CPU#%d]: passed\n",
+                       smp_processor_id(), cpu);
        }
 
        /*
index aeef529..61d805d 100644 (file)
@@ -9,10 +9,25 @@
  */
 
 #include <linux/module.h>
+#include <linux/rbtree.h>
 #include <linux/irq.h>
 
 #include <asm/apic.h>
 #include <asm/uv/uv_irq.h>
+#include <asm/uv/uv_hub.h>
+
+/* MMR offset and pnode of hub sourcing interrupts for a given irq */
+struct uv_irq_2_mmr_pnode{
+       struct rb_node          list;
+       unsigned long           offset;
+       int                     pnode;
+       int                     irq;
+};
+
+static spinlock_t              uv_irq_lock;
+static struct rb_root          uv_irq_root;
+
+static int uv_set_irq_affinity(unsigned int, const struct cpumask *);
 
 static void uv_noop(unsigned int irq)
 {
@@ -39,25 +54,214 @@ struct irq_chip uv_irq_chip = {
        .unmask         = uv_noop,
        .eoi            = uv_ack_apic,
        .end            = uv_noop,
+       .set_affinity   = uv_set_irq_affinity,
 };
 
 /*
+ * Add offset and pnode information of the hub sourcing interrupts to the
+ * rb tree for a specific irq.
+ */
+static int uv_set_irq_2_mmr_info(int irq, unsigned long offset, unsigned blade)
+{
+       struct rb_node **link = &uv_irq_root.rb_node;
+       struct rb_node *parent = NULL;
+       struct uv_irq_2_mmr_pnode *n;
+       struct uv_irq_2_mmr_pnode *e;
+       unsigned long irqflags;
+
+       n = kmalloc_node(sizeof(struct uv_irq_2_mmr_pnode), GFP_KERNEL,
+                               uv_blade_to_memory_nid(blade));
+       if (!n)
+               return -ENOMEM;
+
+       n->irq = irq;
+       n->offset = offset;
+       n->pnode = uv_blade_to_pnode(blade);
+       spin_lock_irqsave(&uv_irq_lock, irqflags);
+       /* Find the right place in the rbtree: */
+       while (*link) {
+               parent = *link;
+               e = rb_entry(parent, struct uv_irq_2_mmr_pnode, list);
+
+               if (unlikely(irq == e->irq)) {
+                       /* irq entry exists */
+                       e->pnode = uv_blade_to_pnode(blade);
+                       e->offset = offset;
+                       spin_unlock_irqrestore(&uv_irq_lock, irqflags);
+                       kfree(n);
+                       return 0;
+               }
+
+               if (irq < e->irq)
+                       link = &(*link)->rb_left;
+               else
+                       link = &(*link)->rb_right;
+       }
+
+       /* Insert the node into the rbtree. */
+       rb_link_node(&n->list, parent, link);
+       rb_insert_color(&n->list, &uv_irq_root);
+
+       spin_unlock_irqrestore(&uv_irq_lock, irqflags);
+       return 0;
+}
+
+/* Retrieve offset and pnode information from the rb tree for a specific irq */
+int uv_irq_2_mmr_info(int irq, unsigned long *offset, int *pnode)
+{
+       struct uv_irq_2_mmr_pnode *e;
+       struct rb_node *n;
+       unsigned long irqflags;
+
+       spin_lock_irqsave(&uv_irq_lock, irqflags);
+       n = uv_irq_root.rb_node;
+       while (n) {
+               e = rb_entry(n, struct uv_irq_2_mmr_pnode, list);
+
+               if (e->irq == irq) {
+                       *offset = e->offset;
+                       *pnode = e->pnode;
+                       spin_unlock_irqrestore(&uv_irq_lock, irqflags);
+                       return 0;
+               }
+
+               if (irq < e->irq)
+                       n = n->rb_left;
+               else
+                       n = n->rb_right;
+       }
+       spin_unlock_irqrestore(&uv_irq_lock, irqflags);
+       return -1;
+}
+
+/*
+ * Re-target the irq to the specified CPU and enable the specified MMR located
+ * on the specified blade to allow the sending of MSIs to the specified CPU.
+ */
+static int
+arch_enable_uv_irq(char *irq_name, unsigned int irq, int cpu, int mmr_blade,
+                      unsigned long mmr_offset, int restrict)
+{
+       const struct cpumask *eligible_cpu = cpumask_of(cpu);
+       struct irq_desc *desc = irq_to_desc(irq);
+       struct irq_cfg *cfg;
+       int mmr_pnode;
+       unsigned long mmr_value;
+       struct uv_IO_APIC_route_entry *entry;
+       int err;
+
+       BUILD_BUG_ON(sizeof(struct uv_IO_APIC_route_entry) !=
+                       sizeof(unsigned long));
+
+       cfg = irq_cfg(irq);
+
+       err = assign_irq_vector(irq, cfg, eligible_cpu);
+       if (err != 0)
+               return err;
+
+       if (restrict == UV_AFFINITY_CPU)
+               desc->status |= IRQ_NO_BALANCING;
+       else
+               desc->status |= IRQ_MOVE_PCNTXT;
+
+       set_irq_chip_and_handler_name(irq, &uv_irq_chip, handle_percpu_irq,
+                                     irq_name);
+
+       mmr_value = 0;
+       entry = (struct uv_IO_APIC_route_entry *)&mmr_value;
+       entry->vector           = cfg->vector;
+       entry->delivery_mode    = apic->irq_delivery_mode;
+       entry->dest_mode        = apic->irq_dest_mode;
+       entry->polarity         = 0;
+       entry->trigger          = 0;
+       entry->mask             = 0;
+       entry->dest             = apic->cpu_mask_to_apicid(eligible_cpu);
+
+       mmr_pnode = uv_blade_to_pnode(mmr_blade);
+       uv_write_global_mmr64(mmr_pnode, mmr_offset, mmr_value);
+
+       if (cfg->move_in_progress)
+               send_cleanup_vector(cfg);
+
+       return irq;
+}
+
+/*
+ * Disable the specified MMR located on the specified blade so that MSIs are
+ * longer allowed to be sent.
+ */
+static void arch_disable_uv_irq(int mmr_pnode, unsigned long mmr_offset)
+{
+       unsigned long mmr_value;
+       struct uv_IO_APIC_route_entry *entry;
+
+       BUILD_BUG_ON(sizeof(struct uv_IO_APIC_route_entry) !=
+                       sizeof(unsigned long));
+
+       mmr_value = 0;
+       entry = (struct uv_IO_APIC_route_entry *)&mmr_value;
+       entry->mask = 1;
+
+       uv_write_global_mmr64(mmr_pnode, mmr_offset, mmr_value);
+}
+
+static int uv_set_irq_affinity(unsigned int irq, const struct cpumask *mask)
+{
+       struct irq_desc *desc = irq_to_desc(irq);
+       struct irq_cfg *cfg = desc->chip_data;
+       unsigned int dest;
+       unsigned long mmr_value;
+       struct uv_IO_APIC_route_entry *entry;
+       unsigned long mmr_offset;
+       unsigned mmr_pnode;
+
+       dest = set_desc_affinity(desc, mask);
+       if (dest == BAD_APICID)
+               return -1;
+
+       mmr_value = 0;
+       entry = (struct uv_IO_APIC_route_entry *)&mmr_value;
+
+       entry->vector           = cfg->vector;
+       entry->delivery_mode    = apic->irq_delivery_mode;
+       entry->dest_mode        = apic->irq_dest_mode;
+       entry->polarity         = 0;
+       entry->trigger          = 0;
+       entry->mask             = 0;
+       entry->dest             = dest;
+
+       /* Get previously stored MMR and pnode of hub sourcing interrupts */
+       if (uv_irq_2_mmr_info(irq, &mmr_offset, &mmr_pnode))
+               return -1;
+
+       uv_write_global_mmr64(mmr_pnode, mmr_offset, mmr_value);
+
+       if (cfg->move_in_progress)
+               send_cleanup_vector(cfg);
+
+       return 0;
+}
+
+/*
  * Set up a mapping of an available irq and vector, and enable the specified
  * MMR that defines the MSI that is to be sent to the specified CPU when an
  * interrupt is raised.
  */
 int uv_setup_irq(char *irq_name, int cpu, int mmr_blade,
-                unsigned long mmr_offset)
+                unsigned long mmr_offset, int restrict)
 {
-       int irq;
-       int ret;
+       int irq, ret;
+
+       irq = create_irq_nr(NR_IRQS_LEGACY, uv_blade_to_memory_nid(mmr_blade));
 
-       irq = create_irq();
        if (irq <= 0)
                return -EBUSY;
 
-       ret = arch_enable_uv_irq(irq_name, irq, cpu, mmr_blade, mmr_offset);
-       if (ret != irq)
+       ret = arch_enable_uv_irq(irq_name, irq, cpu, mmr_blade, mmr_offset,
+               restrict);
+       if (ret == irq)
+               uv_set_irq_2_mmr_info(irq, mmr_offset, mmr_blade);
+       else
                destroy_irq(irq);
 
        return ret;
@@ -71,9 +275,28 @@ EXPORT_SYMBOL_GPL(uv_setup_irq);
  *
  * Set mmr_blade and mmr_offset to what was passed in on uv_setup_irq().
  */
-void uv_teardown_irq(unsigned int irq, int mmr_blade, unsigned long mmr_offset)
+void uv_teardown_irq(unsigned int irq)
 {
-       arch_disable_uv_irq(mmr_blade, mmr_offset);
+       struct uv_irq_2_mmr_pnode *e;
+       struct rb_node *n;
+       unsigned long irqflags;
+
+       spin_lock_irqsave(&uv_irq_lock, irqflags);
+       n = uv_irq_root.rb_node;
+       while (n) {
+               e = rb_entry(n, struct uv_irq_2_mmr_pnode, list);
+               if (e->irq == irq) {
+                       arch_disable_uv_irq(e->pnode, e->offset);
+                       rb_erase(n, &uv_irq_root);
+                       kfree(e);
+                       break;
+               }
+               if (irq < e->irq)
+                       n = n->rb_left;
+               else
+                       n = n->rb_right;
+       }
+       spin_unlock_irqrestore(&uv_irq_lock, irqflags);
        destroy_irq(irq);
 }
 EXPORT_SYMBOL_GPL(uv_teardown_irq);
index f068553..abda6f5 100644 (file)
@@ -183,7 +183,7 @@ static void __init MP_processor_info(struct mpc_cpu *m)
                return;
        }
 
-       apic_cpus = apic->apicid_to_cpu_present(m->apicid);
+       apic->apicid_to_cpu_present(m->apicid, &apic_cpus);
        physids_or(phys_cpu_present_map, phys_cpu_present_map, apic_cpus);
        /*
         * Validate version
@@ -486,7 +486,7 @@ static void end_cobalt_irq(unsigned int irq)
 }
 
 static struct irq_chip cobalt_irq_type = {
-       .typename =     "Cobalt-APIC",
+       .name =         "Cobalt-APIC",
        .startup =      startup_cobalt_irq,
        .shutdown =     disable_cobalt_irq,
        .enable =       enable_cobalt_irq,
@@ -523,7 +523,7 @@ static void end_piix4_master_irq(unsigned int irq)
 }
 
 static struct irq_chip piix4_master_irq_type = {
-       .typename =     "PIIX4-master",
+       .name =         "PIIX4-master",
        .startup =      startup_piix4_master_irq,
        .ack =          ack_cobalt_irq,
        .end =          end_piix4_master_irq,
@@ -531,7 +531,7 @@ static struct irq_chip piix4_master_irq_type = {
 
 
 static struct irq_chip piix4_virtual_irq_type = {
-       .typename =     "PIIX4-virtual",
+       .name =         "PIIX4-virtual",
        .shutdown =     disable_8259A_irq,
        .enable =       enable_8259A_irq,
        .disable =      disable_8259A_irq,
index 8cb4974..e02d92d 100644 (file)
@@ -237,7 +237,7 @@ static ctl_table kernel_table2[] = {
 };
 
 static ctl_table kernel_root_table2[] = {
-       { .ctl_name = CTL_KERN, .procname = "kernel", .mode = 0555,
+       { .procname = "kernel", .mode = 0555,
          .child = kernel_table2 },
        {}
 };
index 3909e3b..a102976 100644 (file)
@@ -30,9 +30,8 @@ EXPORT_SYMBOL(__put_user_8);
 
 EXPORT_SYMBOL(copy_user_generic);
 EXPORT_SYMBOL(__copy_user_nocache);
-EXPORT_SYMBOL(copy_from_user);
-EXPORT_SYMBOL(copy_to_user);
-EXPORT_SYMBOL(__copy_from_user_inatomic);
+EXPORT_SYMBOL(_copy_from_user);
+EXPORT_SYMBOL(_copy_to_user);
 
 EXPORT_SYMBOL(copy_page);
 EXPORT_SYMBOL(clear_page);
index b84e571..4cd4983 100644 (file)
@@ -28,6 +28,7 @@ config KVM
        select HAVE_KVM_IRQCHIP
        select HAVE_KVM_EVENTFD
        select KVM_APIC_ARCHITECTURE
+       select USER_RETURN_NOTIFIER
        ---help---
          Support hosting fully virtualized guest machines using hardware
          virtualization extensions.  You will need a fairly recent
index 0e7fe78..31a7035 100644 (file)
@@ -6,7 +6,8 @@ CFLAGS_svm.o := -I.
 CFLAGS_vmx.o := -I.
 
 kvm-y                  += $(addprefix ../../../virt/kvm/, kvm_main.o ioapic.o \
-                               coalesced_mmio.o irq_comm.o eventfd.o)
+                               coalesced_mmio.o irq_comm.o eventfd.o \
+                               assigned-dev.o)
 kvm-$(CONFIG_IOMMU_API)        += $(addprefix ../../../virt/kvm/, iommu.o)
 
 kvm-y                  += x86.o mmu.o emulate.o i8259.o irq.o lapic.o \
index 1be5cd6..7e8faea 100644 (file)
@@ -75,6 +75,8 @@
 #define Group       (1<<14)     /* Bits 3:5 of modrm byte extend opcode */
 #define GroupDual   (1<<15)     /* Alternate decoding of mod == 3 */
 #define GroupMask   0xff        /* Group number stored in bits 0:7 */
+/* Misc flags */
+#define No64       (1<<28)
 /* Source 2 operand type */
 #define Src2None    (0<<29)
 #define Src2CL      (1<<29)
@@ -92,19 +94,23 @@ static u32 opcode_table[256] = {
        /* 0x00 - 0x07 */
        ByteOp | DstMem | SrcReg | ModRM, DstMem | SrcReg | ModRM,
        ByteOp | DstReg | SrcMem | ModRM, DstReg | SrcMem | ModRM,
-       ByteOp | DstAcc | SrcImm, DstAcc | SrcImm, 0, 0,
+       ByteOp | DstAcc | SrcImm, DstAcc | SrcImm,
+       ImplicitOps | Stack | No64, ImplicitOps | Stack | No64,
        /* 0x08 - 0x0F */
        ByteOp | DstMem | SrcReg | ModRM, DstMem | SrcReg | ModRM,
        ByteOp | DstReg | SrcMem | ModRM, DstReg | SrcMem | ModRM,
-       0, 0, 0, 0,
+       ByteOp | DstAcc | SrcImm, DstAcc | SrcImm,
+       ImplicitOps | Stack | No64, 0,
        /* 0x10 - 0x17 */
        ByteOp | DstMem | SrcReg | ModRM, DstMem | SrcReg | ModRM,
        ByteOp | DstReg | SrcMem | ModRM, DstReg | SrcMem | ModRM,
-       ByteOp | DstAcc | SrcImm, DstAcc | SrcImm, 0, 0,
+       ByteOp | DstAcc | SrcImm, DstAcc | SrcImm,
+       ImplicitOps | Stack | No64, ImplicitOps | Stack | No64,
        /* 0x18 - 0x1F */
        ByteOp | DstMem | SrcReg | ModRM, DstMem | SrcReg | ModRM,
        ByteOp | DstReg | SrcMem | ModRM, DstReg | SrcMem | ModRM,
-       ByteOp | DstAcc | SrcImm, DstAcc | SrcImm, 0, 0,
+       ByteOp | DstAcc | SrcImm, DstAcc | SrcImm,
+       ImplicitOps | Stack | No64, ImplicitOps | Stack | No64,
        /* 0x20 - 0x27 */
        ByteOp | DstMem | SrcReg | ModRM, DstMem | SrcReg | ModRM,
        ByteOp | DstReg | SrcMem | ModRM, DstReg | SrcMem | ModRM,
@@ -133,7 +139,8 @@ static u32 opcode_table[256] = {
        DstReg | Stack, DstReg | Stack, DstReg | Stack, DstReg | Stack,
        DstReg | Stack, DstReg | Stack, DstReg | Stack, DstReg | Stack,
        /* 0x60 - 0x67 */
-       0, 0, 0, DstReg | SrcMem32 | ModRM | Mov /* movsxd (x86/64) */ ,
+       ImplicitOps | Stack | No64, ImplicitOps | Stack | No64,
+       0, DstReg | SrcMem32 | ModRM | Mov /* movsxd (x86/64) */ ,
        0, 0, 0, 0,
        /* 0x68 - 0x6F */
        SrcImm | Mov | Stack, 0, SrcImmByte | Mov | Stack, 0,
@@ -158,7 +165,7 @@ static u32 opcode_table[256] = {
        /* 0x90 - 0x97 */
        DstReg, DstReg, DstReg, DstReg, DstReg, DstReg, DstReg, DstReg,
        /* 0x98 - 0x9F */
-       0, 0, SrcImm | Src2Imm16, 0,
+       0, 0, SrcImm | Src2Imm16 | No64, 0,
        ImplicitOps | Stack, ImplicitOps | Stack, 0, 0,
        /* 0xA0 - 0xA7 */
        ByteOp | DstReg | SrcMem | Mov | MemAbs, DstReg | SrcMem | Mov | MemAbs,
@@ -185,7 +192,7 @@ static u32 opcode_table[256] = {
        ByteOp | DstMem | SrcImm | ModRM | Mov, DstMem | SrcImm | ModRM | Mov,
        /* 0xC8 - 0xCF */
        0, 0, 0, ImplicitOps | Stack,
-       ImplicitOps, SrcImmByte, ImplicitOps, ImplicitOps,
+       ImplicitOps, SrcImmByte, ImplicitOps | No64, ImplicitOps,
        /* 0xD0 - 0xD7 */
        ByteOp | DstMem | SrcImplicit | ModRM, DstMem | SrcImplicit | ModRM,
        ByteOp | DstMem | SrcImplicit | ModRM, DstMem | SrcImplicit | ModRM,
@@ -198,7 +205,7 @@ static u32 opcode_table[256] = {
        ByteOp | SrcImmUByte, SrcImmUByte,
        /* 0xE8 - 0xEF */
        SrcImm | Stack, SrcImm | ImplicitOps,
-       SrcImmU | Src2Imm16, SrcImmByte | ImplicitOps,
+       SrcImmU | Src2Imm16 | No64, SrcImmByte | ImplicitOps,
        SrcNone | ByteOp | ImplicitOps, SrcNone | ImplicitOps,
        SrcNone | ByteOp | ImplicitOps, SrcNone | ImplicitOps,
        /* 0xF0 - 0xF7 */
@@ -244,11 +251,13 @@ static u32 twobyte_table[256] = {
        /* 0x90 - 0x9F */
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        /* 0xA0 - 0xA7 */
-       0, 0, 0, DstMem | SrcReg | ModRM | BitOp,
+       ImplicitOps | Stack, ImplicitOps | Stack,
+       0, DstMem | SrcReg | ModRM | BitOp,
        DstMem | SrcReg | Src2ImmByte | ModRM,
        DstMem | SrcReg | Src2CL | ModRM, 0, 0,
        /* 0xA8 - 0xAF */
-       0, 0, 0, DstMem | SrcReg | ModRM | BitOp,
+       ImplicitOps | Stack, ImplicitOps | Stack,
+       0, DstMem | SrcReg | ModRM | BitOp,
        DstMem | SrcReg | Src2ImmByte | ModRM,
        DstMem | SrcReg | Src2CL | ModRM,
        ModRM, 0,
@@ -613,6 +622,9 @@ static int do_insn_fetch(struct x86_emulate_ctxt *ctxt,
 {
        int rc = 0;
 
+       /* x86 instructions are limited to 15 bytes. */
+       if (eip + size - ctxt->decode.eip_orig > 15)
+               return X86EMUL_UNHANDLEABLE;
        eip += ctxt->cs_base;
        while (size--) {
                rc = do_fetch_insn_byte(ctxt, ops, eip++, dest++);
@@ -871,7 +883,7 @@ x86_decode_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
        /* Shadow copy of register state. Committed on successful emulation. */
 
        memset(c, 0, sizeof(struct decode_cache));
-       c->eip = kvm_rip_read(ctxt->vcpu);
+       c->eip = c->eip_orig = kvm_rip_read(ctxt->vcpu);
        ctxt->cs_base = seg_base(ctxt, VCPU_SREG_CS);
        memcpy(c->regs, ctxt->vcpu->arch.regs, sizeof c->regs);
 
@@ -962,6 +974,11 @@ done_prefixes:
                }
        }
 
+       if (mode == X86EMUL_MODE_PROT64 && (c->d & No64)) {
+               kvm_report_emulation_failure(ctxt->vcpu, "invalid x86/64 instruction");;
+               return -1;
+       }
+
        if (c->d & Group) {
                group = c->d & GroupMask;
                c->modrm = insn_fetch(u8, 1, c->eip);
@@ -1186,6 +1203,69 @@ static int emulate_pop(struct x86_emulate_ctxt *ctxt,
        return rc;
 }
 
+static void emulate_push_sreg(struct x86_emulate_ctxt *ctxt, int seg)
+{
+       struct decode_cache *c = &ctxt->decode;
+       struct kvm_segment segment;
+
+       kvm_x86_ops->get_segment(ctxt->vcpu, &segment, seg);
+
+       c->src.val = segment.selector;
+       emulate_push(ctxt);
+}
+
+static int emulate_pop_sreg(struct x86_emulate_ctxt *ctxt,
+                            struct x86_emulate_ops *ops, int seg)
+{
+       struct decode_cache *c = &ctxt->decode;
+       unsigned long selector;
+       int rc;
+
+       rc = emulate_pop(ctxt, ops, &selector, c->op_bytes);
+       if (rc != 0)
+               return rc;
+
+       rc = kvm_load_segment_descriptor(ctxt->vcpu, (u16)selector, 1, seg);
+       return rc;
+}
+
+static void emulate_pusha(struct x86_emulate_ctxt *ctxt)
+{
+       struct decode_cache *c = &ctxt->decode;
+       unsigned long old_esp = c->regs[VCPU_REGS_RSP];
+       int reg = VCPU_REGS_RAX;
+
+       while (reg <= VCPU_REGS_RDI) {
+               (reg == VCPU_REGS_RSP) ?
+               (c->src.val = old_esp) : (c->src.val = c->regs[reg]);
+
+               emulate_push(ctxt);
+               ++reg;
+       }
+}
+
+static int emulate_popa(struct x86_emulate_ctxt *ctxt,
+                       struct x86_emulate_ops *ops)
+{
+       struct decode_cache *c = &ctxt->decode;
+       int rc = 0;
+       int reg = VCPU_REGS_RDI;
+
+       while (reg >= VCPU_REGS_RAX) {
+               if (reg == VCPU_REGS_RSP) {
+                       register_address_increment(c, &c->regs[VCPU_REGS_RSP],
+                                                       c->op_bytes);
+                       --reg;
+               }
+
+               rc = emulate_pop(ctxt, ops, &c->regs[reg], c->op_bytes);
+               if (rc != 0)
+                       break;
+               --reg;
+       }
+       return rc;
+}
+
 static inline int emulate_grp1a(struct x86_emulate_ctxt *ctxt,
                                struct x86_emulate_ops *ops)
 {
@@ -1707,18 +1787,45 @@ special_insn:
              add:              /* add */
                emulate_2op_SrcV("add", c->src, c->dst, ctxt->eflags);
                break;
+       case 0x06:              /* push es */
+               emulate_push_sreg(ctxt, VCPU_SREG_ES);
+               break;
+       case 0x07:              /* pop es */
+               rc = emulate_pop_sreg(ctxt, ops, VCPU_SREG_ES);
+               if (rc != 0)
+                       goto done;
+               break;
        case 0x08 ... 0x0d:
              or:               /* or */
                emulate_2op_SrcV("or", c->src, c->dst, ctxt->eflags);
                break;
+       case 0x0e:              /* push cs */
+               emulate_push_sreg(ctxt, VCPU_SREG_CS);
+               break;
        case 0x10 ... 0x15:
              adc:              /* adc */
                emulate_2op_SrcV("adc", c->src, c->dst, ctxt->eflags);
                break;
+       case 0x16:              /* push ss */
+               emulate_push_sreg(ctxt, VCPU_SREG_SS);
+               break;
+       case 0x17:              /* pop ss */
+               rc = emulate_pop_sreg(ctxt, ops, VCPU_SREG_SS);
+               if (rc != 0)
+                       goto done;
+               break;
        case 0x18 ... 0x1d:
              sbb:              /* sbb */
                emulate_2op_SrcV("sbb", c->src, c->dst, ctxt->eflags);
                break;
+       case 0x1e:              /* push ds */
+               emulate_push_sreg(ctxt, VCPU_SREG_DS);
+               break;
+       case 0x1f:              /* pop ds */
+               rc = emulate_pop_sreg(ctxt, ops, VCPU_SREG_DS);
+               if (rc != 0)
+                       goto done;
+               break;
        case 0x20 ... 0x25:
              and:              /* and */
                emulate_2op_SrcV("and", c->src, c->dst, ctxt->eflags);
@@ -1750,6 +1857,14 @@ special_insn:
                if (rc != 0)
                        goto done;
                break;
+       case 0x60:      /* pusha */
+               emulate_pusha(ctxt);
+               break;
+       case 0x61:      /* popa */
+               rc = emulate_popa(ctxt, ops);
+               if (rc != 0)
+                       goto done;
+               break;
        case 0x63:              /* movsxd */
                if (ctxt->mode != X86EMUL_MODE_PROT64)
                        goto cannot_emulate;
@@ -1761,7 +1876,7 @@ special_insn:
                break;
        case 0x6c:              /* insb */
        case 0x6d:              /* insw/insd */
-                if (kvm_emulate_pio_string(ctxt->vcpu, NULL,
+                if (kvm_emulate_pio_string(ctxt->vcpu,
                                1,
                                (c->d & ByteOp) ? 1 : c->op_bytes,
                                c->rep_prefix ?
@@ -1777,7 +1892,7 @@ special_insn:
                return 0;
        case 0x6e:              /* outsb */
        case 0x6f:              /* outsw/outsd */
-               if (kvm_emulate_pio_string(ctxt->vcpu, NULL,
+               if (kvm_emulate_pio_string(ctxt->vcpu,
                                0,
                                (c->d & ByteOp) ? 1 : c->op_bytes,
                                c->rep_prefix ?
@@ -2070,7 +2185,7 @@ special_insn:
        case 0xef: /* out (e/r)ax,dx */
                port = c->regs[VCPU_REGS_RDX];
                io_dir_in = 0;
-       do_io:  if (kvm_emulate_pio(ctxt->vcpu, NULL, io_dir_in,
+       do_io:  if (kvm_emulate_pio(ctxt->vcpu, io_dir_in,
                                   (c->d & ByteOp) ? 1 : c->op_bytes,
                                   port) != 0) {
                        c->eip = saved_eip;
@@ -2297,6 +2412,14 @@ twobyte_insn:
                        jmp_rel(c, c->src.val);
                c->dst.type = OP_NONE;
                break;
+       case 0xa0:        /* push fs */
+               emulate_push_sreg(ctxt, VCPU_SREG_FS);
+               break;
+       case 0xa1:       /* pop fs */
+               rc = emulate_pop_sreg(ctxt, ops, VCPU_SREG_FS);
+               if (rc != 0)
+                       goto done;
+               break;
        case 0xa3:
              bt:               /* bt */
                c->dst.type = OP_NONE;
@@ -2308,6 +2431,14 @@ twobyte_insn:
        case 0xa5: /* shld cl, r, r/m */
                emulate_2op_cl("shld", c->src2, c->src, c->dst, ctxt->eflags);
                break;
+       case 0xa8:      /* push gs */
+               emulate_push_sreg(ctxt, VCPU_SREG_GS);
+               break;
+       case 0xa9:      /* pop gs */
+               rc = emulate_pop_sreg(ctxt, ops, VCPU_SREG_GS);
+               if (rc != 0)
+                       goto done;
+               break;
        case 0xab:
              bts:              /* bts */
                /* only subword offset */
index 144e7f6..fab7440 100644 (file)
@@ -688,10 +688,8 @@ static void __inject_pit_timer_intr(struct kvm *kvm)
        struct kvm_vcpu *vcpu;
        int i;
 
-       mutex_lock(&kvm->irq_lock);
        kvm_set_irq(kvm, kvm->arch.vpit->irq_source_id, 0, 1);
        kvm_set_irq(kvm, kvm->arch.vpit->irq_source_id, 0, 0);
-       mutex_unlock(&kvm->irq_lock);
 
        /*
         * Provides NMI watchdog support via Virtual Wire mode.
index 01f1516..d057c0c 100644 (file)
@@ -38,7 +38,15 @@ static void pic_clear_isr(struct kvm_kpic_state *s, int irq)
        s->isr_ack |= (1 << irq);
        if (s != &s->pics_state->pics[0])
                irq += 8;
+       /*
+        * We are dropping lock while calling ack notifiers since ack
+        * notifier callbacks for assigned devices call into PIC recursively.
+        * Other interrupt may be delivered to PIC while lock is dropped but
+        * it should be safe since PIC state is already updated at this stage.
+        */
+       spin_unlock(&s->pics_state->lock);
        kvm_notify_acked_irq(s->pics_state->kvm, SELECT_PIC(irq), irq);
+       spin_lock(&s->pics_state->lock);
 }
 
 void kvm_pic_clear_isr_ack(struct kvm *kvm)
@@ -176,16 +184,18 @@ int kvm_pic_set_irq(void *opaque, int irq, int level)
 static inline void pic_intack(struct kvm_kpic_state *s, int irq)
 {
        s->isr |= 1 << irq;
-       if (s->auto_eoi) {
-               if (s->rotate_on_auto_eoi)
-                       s->priority_add = (irq + 1) & 7;
-               pic_clear_isr(s, irq);
-       }
        /*
         * We don't clear a level sensitive interrupt here
         */
        if (!(s->elcr & (1 << irq)))
                s->irr &= ~(1 << irq);
+
+       if (s->auto_eoi) {
+               if (s->rotate_on_auto_eoi)
+                       s->priority_add = (irq + 1) & 7;
+               pic_clear_isr(s, irq);
+       }
+
 }
 
 int kvm_pic_read_irq(struct kvm *kvm)
@@ -225,22 +235,11 @@ int kvm_pic_read_irq(struct kvm *kvm)
 
 void kvm_pic_reset(struct kvm_kpic_state *s)
 {
-       int irq, irqbase, n;
+       int irq;
        struct kvm *kvm = s->pics_state->irq_request_opaque;
        struct kvm_vcpu *vcpu0 = kvm->bsp_vcpu;
+       u8 irr = s->irr, isr = s->imr;
 
-       if (s == &s->pics_state->pics[0])
-               irqbase = 0;
-       else
-               irqbase = 8;
-
-       for (irq = 0; irq < PIC_NUM_PINS/2; irq++) {
-               if (vcpu0 && kvm_apic_accept_pic_intr(vcpu0))
-                       if (s->irr & (1 << irq) || s->isr & (1 << irq)) {
-                               n = irq + irqbase;
-                               kvm_notify_acked_irq(kvm, SELECT_PIC(n), n);
-                       }
-       }
        s->last_irr = 0;
        s->irr = 0;
        s->imr = 0;
@@ -256,6 +255,13 @@ void kvm_pic_reset(struct kvm_kpic_state *s)
        s->rotate_on_auto_eoi = 0;
        s->special_fully_nested_mode = 0;
        s->init4 = 0;
+
+       for (irq = 0; irq < PIC_NUM_PINS/2; irq++) {
+               if (vcpu0 && kvm_apic_accept_pic_intr(vcpu0))
+                       if (irr & (1 << irq) || isr & (1 << irq)) {
+                               pic_clear_isr(s, irq);
+                       }
+       }
 }
 
 static void pic_ioport_write(void *opaque, u32 addr, u32 val)
@@ -298,9 +304,9 @@ static void pic_ioport_write(void *opaque, u32 addr, u32 val)
                                priority = get_priority(s, s->isr);
                                if (priority != 8) {
                                        irq = (priority + s->priority_add) & 7;
-                                       pic_clear_isr(s, irq);
                                        if (cmd == 5)
                                                s->priority_add = (irq + 1) & 7;
+                                       pic_clear_isr(s, irq);
                                        pic_update_irq(s->pics_state);
                                }
                                break;
index 7d6058a..be399e2 100644 (file)
@@ -71,6 +71,7 @@ struct kvm_pic {
        int output;             /* intr from master PIC */
        struct kvm_io_device dev;
        void (*ack_notifier)(void *opaque, int irq);
+       unsigned long irq_states[16];
 };
 
 struct kvm_pic *kvm_create_pic(struct kvm *kvm);
@@ -85,7 +86,11 @@ static inline struct kvm_pic *pic_irqchip(struct kvm *kvm)
 
 static inline int irqchip_in_kernel(struct kvm *kvm)
 {
-       return pic_irqchip(kvm) != NULL;
+       int ret;
+
+       ret = (pic_irqchip(kvm) != NULL);
+       smp_rmb();
+       return ret;
 }
 
 void kvm_pic_reset(struct kvm_kpic_state *s);
index 23c2176..cd60c0b 100644 (file)
@@ -32,7 +32,6 @@
 #include <asm/current.h>
 #include <asm/apicdef.h>
 #include <asm/atomic.h>
-#include <asm/apicdef.h>
 #include "kvm_cache_regs.h"
 #include "irq.h"
 #include "trace.h"
@@ -471,11 +470,8 @@ static void apic_set_eoi(struct kvm_lapic *apic)
                trigger_mode = IOAPIC_LEVEL_TRIG;
        else
                trigger_mode = IOAPIC_EDGE_TRIG;
-       if (!(apic_get_reg(apic, APIC_SPIV) & APIC_SPIV_DIRECTED_EOI)) {
-               mutex_lock(&apic->vcpu->kvm->irq_lock);
+       if (!(apic_get_reg(apic, APIC_SPIV) & APIC_SPIV_DIRECTED_EOI))
                kvm_ioapic_update_eoi(apic->vcpu->kvm, vector, trigger_mode);
-               mutex_unlock(&apic->vcpu->kvm->irq_lock);
-       }
 }
 
 static void apic_send_ipi(struct kvm_lapic *apic)
@@ -504,9 +500,7 @@ static void apic_send_ipi(struct kvm_lapic *apic)
                   irq.trig_mode, irq.level, irq.dest_mode, irq.delivery_mode,
                   irq.vector);
 
-       mutex_lock(&apic->vcpu->kvm->irq_lock);
        kvm_irq_delivery_to_apic(apic->vcpu->kvm, apic, &irq);
-       mutex_unlock(&apic->vcpu->kvm->irq_lock);
 }
 
 static u32 apic_get_tmcct(struct kvm_lapic *apic)
index 818b92a..4c3e5b2 100644 (file)
@@ -2789,7 +2789,7 @@ int kvm_mmu_page_fault(struct kvm_vcpu *vcpu, gva_t cr2, u32 error_code)
        if (r)
                goto out;
 
-       er = emulate_instruction(vcpu, vcpu->run, cr2, error_code, 0);
+       er = emulate_instruction(vcpu, cr2, error_code, 0);
 
        switch (er) {
        case EMULATE_DONE:
@@ -2800,6 +2800,7 @@ int kvm_mmu_page_fault(struct kvm_vcpu *vcpu, gva_t cr2, u32 error_code)
        case EMULATE_FAIL:
                vcpu->run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
                vcpu->run->internal.suberror = KVM_INTERNAL_ERROR_EMULATION;
+               vcpu->run->internal.ndata = 0;
                return 0;
        default:
                BUG();
index 72558f8..a601713 100644 (file)
@@ -467,7 +467,6 @@ static void FNAME(invlpg)(struct kvm_vcpu *vcpu, gva_t gva)
                level = iterator.level;
                sptep = iterator.sptep;
 
-               /* FIXME: properly handle invlpg on large guest pages */
                if (level == PT_PAGE_TABLE_LEVEL  ||
                    ((level == PT_DIRECTORY_LEVEL && is_large_pte(*sptep))) ||
                    ((level == PT_PDPE_LEVEL && is_large_pte(*sptep)))) {
index c17404a..3de0b37 100644 (file)
@@ -46,6 +46,7 @@ MODULE_LICENSE("GPL");
 #define SVM_FEATURE_NPT  (1 << 0)
 #define SVM_FEATURE_LBRV (1 << 1)
 #define SVM_FEATURE_SVML (1 << 2)
+#define SVM_FEATURE_PAUSE_FILTER (1 << 10)
 
 #define NESTED_EXIT_HOST       0       /* Exit handled on host level */
 #define NESTED_EXIT_DONE       1       /* Exit caused nested vmexit  */
@@ -53,15 +54,6 @@ MODULE_LICENSE("GPL");
 
 #define DEBUGCTL_RESERVED_BITS (~(0x3fULL))
 
-/* Turn on to get debugging output*/
-/* #define NESTED_DEBUG */
-
-#ifdef NESTED_DEBUG
-#define nsvm_printk(fmt, args...) printk(KERN_INFO fmt, ## args)
-#else
-#define nsvm_printk(fmt, args...) do {} while(0)
-#endif
-
 static const u32 host_save_user_msrs[] = {
 #ifdef CONFIG_X86_64
        MSR_STAR, MSR_LSTAR, MSR_CSTAR, MSR_SYSCALL_MASK, MSR_KERNEL_GS_BASE,
@@ -85,6 +77,9 @@ struct nested_state {
        /* gpa pointers to the real vectors */
        u64 vmcb_msrpm;
 
+       /* A VMEXIT is required but not yet emulated */
+       bool exit_required;
+
        /* cache for intercepts of the guest */
        u16 intercept_cr_read;
        u16 intercept_cr_write;
@@ -112,6 +107,8 @@ struct vcpu_svm {
        u32 *msrpm;
 
        struct nested_state nested;
+
+       bool nmi_singlestep;
 };
 
 /* enable NPT for AMD64 and X86 with PAE */
@@ -286,7 +283,7 @@ static void skip_emulated_instruction(struct kvm_vcpu *vcpu)
        struct vcpu_svm *svm = to_svm(vcpu);
 
        if (!svm->next_rip) {
-               if (emulate_instruction(vcpu, vcpu->run, 0, 0, EMULTYPE_SKIP) !=
+               if (emulate_instruction(vcpu, 0, 0, EMULTYPE_SKIP) !=
                                EMULATE_DONE)
                        printk(KERN_DEBUG "%s: NOP\n", __func__);
                return;
@@ -316,7 +313,7 @@ static void svm_hardware_disable(void *garbage)
        cpu_svm_disable();
 }
 
-static void svm_hardware_enable(void *garbage)
+static int svm_hardware_enable(void *garbage)
 {
 
        struct svm_cpu_data *svm_data;
@@ -325,16 +322,21 @@ static void svm_hardware_enable(void *garbage)
        struct desc_struct *gdt;
        int me = raw_smp_processor_id();
 
+       rdmsrl(MSR_EFER, efer);
+       if (efer & EFER_SVME)
+               return -EBUSY;
+
        if (!has_svm()) {
-               printk(KERN_ERR "svm_cpu_init: err EOPNOTSUPP on %d\n", me);
-               return;
+               printk(KERN_ERR "svm_hardware_enable: err EOPNOTSUPP on %d\n",
+                      me);
+               return -EINVAL;
        }
        svm_data = per_cpu(svm_data, me);
 
        if (!svm_data) {
-               printk(KERN_ERR "svm_cpu_init: svm_data is NULL on %d\n",
+               printk(KERN_ERR "svm_hardware_enable: svm_data is NULL on %d\n",
                       me);
-               return;
+               return -EINVAL;
        }
 
        svm_data->asid_generation = 1;
@@ -345,11 +347,12 @@ static void svm_hardware_enable(void *garbage)
        gdt = (struct desc_struct *)gdt_descr.base;
        svm_data->tss_desc = (struct kvm_ldttss_desc *)(gdt + GDT_ENTRY_TSS);
 
-       rdmsrl(MSR_EFER, efer);
        wrmsrl(MSR_EFER, efer | EFER_SVME);
 
        wrmsrl(MSR_VM_HSAVE_PA,
               page_to_pfn(svm_data->save_area) << PAGE_SHIFT);
+
+       return 0;
 }
 
 static void svm_cpu_uninit(int cpu)
@@ -476,7 +479,7 @@ static __init int svm_hardware_setup(void)
                kvm_enable_efer_bits(EFER_SVME);
        }
 
-       for_each_online_cpu(cpu) {
+       for_each_possible_cpu(cpu) {
                r = svm_cpu_init(cpu);
                if (r)
                        goto err;
@@ -510,7 +513,7 @@ static __exit void svm_hardware_unsetup(void)
 {
        int cpu;
 
-       for_each_online_cpu(cpu)
+       for_each_possible_cpu(cpu)
                svm_cpu_uninit(cpu);
 
        __free_pages(pfn_to_page(iopm_base >> PAGE_SHIFT), IOPM_ALLOC_ORDER);
@@ -625,11 +628,12 @@ static void init_vmcb(struct vcpu_svm *svm)
        save->rip = 0x0000fff0;
        svm->vcpu.arch.regs[VCPU_REGS_RIP] = save->rip;
 
-       /*
-        * cr0 val on cpu init should be 0x60000010, we enable cpu
-        * cache by default. the orderly way is to enable cache in bios.
+       /* This is the guest-visible cr0 value.
+        * svm_set_cr0() sets PG and WP and clears NW and CD on save->cr0.
         */
-       save->cr0 = 0x00000010 | X86_CR0_PG | X86_CR0_WP;
+       svm->vcpu.arch.cr0 = X86_CR0_NW | X86_CR0_CD | X86_CR0_ET;
+       kvm_set_cr0(&svm->vcpu, svm->vcpu.arch.cr0);
+
        save->cr4 = X86_CR4_PAE;
        /* rdx = ?? */
 
@@ -644,8 +648,6 @@ static void init_vmcb(struct vcpu_svm *svm)
                control->intercept_cr_write &= ~(INTERCEPT_CR0_MASK|
                                                 INTERCEPT_CR3_MASK);
                save->g_pat = 0x0007040600070406ULL;
-               /* enable caching because the QEMU Bios doesn't enable it */
-               save->cr0 = X86_CR0_ET;
                save->cr3 = 0;
                save->cr4 = 0;
        }
@@ -654,6 +656,11 @@ static void init_vmcb(struct vcpu_svm *svm)
        svm->nested.vmcb = 0;
        svm->vcpu.arch.hflags = 0;
 
+       if (svm_has(SVM_FEATURE_PAUSE_FILTER)) {
+               control->pause_filter_count = 3000;
+               control->intercept |= (1ULL << INTERCEPT_PAUSE);
+       }
+
        enable_gif(svm);
 }
 
@@ -758,14 +765,13 @@ static void svm_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
        int i;
 
        if (unlikely(cpu != vcpu->cpu)) {
-               u64 tsc_this, delta;
+               u64 delta;
 
                /*
                 * Make sure that the guest sees a monotonically
                 * increasing TSC.
                 */
-               rdtscll(tsc_this);
-               delta = vcpu->arch.host_tsc - tsc_this;
+               delta = vcpu->arch.host_tsc - native_read_tsc();
                svm->vmcb->control.tsc_offset += delta;
                if (is_nested(svm))
                        svm->nested.hsave->control.tsc_offset += delta;
@@ -787,7 +793,7 @@ static void svm_vcpu_put(struct kvm_vcpu *vcpu)
        for (i = 0; i < NR_HOST_SAVE_USER_MSRS; i++)
                wrmsrl(host_save_user_msrs[i], svm->host_user_msrs[i]);
 
-       rdtscll(vcpu->arch.host_tsc);
+       vcpu->arch.host_tsc = native_read_tsc();
 }
 
 static unsigned long svm_get_rflags(struct kvm_vcpu *vcpu)
@@ -1045,7 +1051,7 @@ static void update_db_intercept(struct kvm_vcpu *vcpu)
        svm->vmcb->control.intercept_exceptions &=
                ~((1 << DB_VECTOR) | (1 << BP_VECTOR));
 
-       if (vcpu->arch.singlestep)
+       if (svm->nmi_singlestep)
                svm->vmcb->control.intercept_exceptions |= (1 << DB_VECTOR);
 
        if (vcpu->guest_debug & KVM_GUESTDBG_ENABLE) {
@@ -1060,26 +1066,16 @@ static void update_db_intercept(struct kvm_vcpu *vcpu)
                vcpu->guest_debug = 0;
 }
 
-static int svm_guest_debug(struct kvm_vcpu *vcpu, struct kvm_guest_debug *dbg)
+static void svm_guest_debug(struct kvm_vcpu *vcpu, struct kvm_guest_debug *dbg)
 {
-       int old_debug = vcpu->guest_debug;
        struct vcpu_svm *svm = to_svm(vcpu);
 
-       vcpu->guest_debug = dbg->control;
-
-       update_db_intercept(vcpu);
-
        if (vcpu->guest_debug & KVM_GUESTDBG_USE_HW_BP)
                svm->vmcb->save.dr7 = dbg->arch.debugreg[7];
        else
                svm->vmcb->save.dr7 = vcpu->arch.dr7;
 
-       if (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP)
-               svm->vmcb->save.rflags |= X86_EFLAGS_TF | X86_EFLAGS_RF;
-       else if (old_debug & KVM_GUESTDBG_SINGLESTEP)
-               svm->vmcb->save.rflags &= ~(X86_EFLAGS_TF | X86_EFLAGS_RF);
-
-       return 0;
+       update_db_intercept(vcpu);
 }
 
 static void load_host_msrs(struct kvm_vcpu *vcpu)
@@ -1180,7 +1176,7 @@ static void svm_set_dr(struct kvm_vcpu *vcpu, int dr, unsigned long value,
        }
 }
 
-static int pf_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
+static int pf_interception(struct vcpu_svm *svm)
 {
        u64 fault_address;
        u32 error_code;
@@ -1194,17 +1190,19 @@ static int pf_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
        return kvm_mmu_page_fault(&svm->vcpu, fault_address, error_code);
 }
 
-static int db_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
+static int db_interception(struct vcpu_svm *svm)
 {
+       struct kvm_run *kvm_run = svm->vcpu.run;
+
        if (!(svm->vcpu.guest_debug &
              (KVM_GUESTDBG_SINGLESTEP | KVM_GUESTDBG_USE_HW_BP)) &&
-               !svm->vcpu.arch.singlestep) {
+               !svm->nmi_singlestep) {
                kvm_queue_exception(&svm->vcpu, DB_VECTOR);
                return 1;
        }
 
-       if (svm->vcpu.arch.singlestep) {
-               svm->vcpu.arch.singlestep = false;
+       if (svm->nmi_singlestep) {
+               svm->nmi_singlestep = false;
                if (!(svm->vcpu.guest_debug & KVM_GUESTDBG_SINGLESTEP))
                        svm->vmcb->save.rflags &=
                                ~(X86_EFLAGS_TF | X86_EFLAGS_RF);
@@ -1223,25 +1221,27 @@ static int db_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
        return 1;
 }
 
-static int bp_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
+static int bp_interception(struct vcpu_svm *svm)
 {
+       struct kvm_run *kvm_run = svm->vcpu.run;
+
        kvm_run->exit_reason = KVM_EXIT_DEBUG;
        kvm_run->debug.arch.pc = svm->vmcb->save.cs.base + svm->vmcb->save.rip;
        kvm_run->debug.arch.exception = BP_VECTOR;
        return 0;
 }
 
-static int ud_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
+static int ud_interception(struct vcpu_svm *svm)
 {
        int er;
 
-       er = emulate_instruction(&svm->vcpu, kvm_run, 0, 0, EMULTYPE_TRAP_UD);
+       er = emulate_instruction(&svm->vcpu, 0, 0, EMULTYPE_TRAP_UD);
        if (er != EMULATE_DONE)
                kvm_queue_exception(&svm->vcpu, UD_VECTOR);
        return 1;
 }
 
-static int nm_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
+static int nm_interception(struct vcpu_svm *svm)
 {
        svm->vmcb->control.intercept_exceptions &= ~(1 << NM_VECTOR);
        if (!(svm->vcpu.arch.cr0 & X86_CR0_TS))
@@ -1251,7 +1251,7 @@ static int nm_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
        return 1;
 }
 
-static int mc_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
+static int mc_interception(struct vcpu_svm *svm)
 {
        /*
         * On an #MC intercept the MCE handler is not called automatically in
@@ -1264,8 +1264,10 @@ static int mc_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
        return 1;
 }
 
-static int shutdown_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
+static int shutdown_interception(struct vcpu_svm *svm)
 {
+       struct kvm_run *kvm_run = svm->vcpu.run;
+
        /*
         * VMCB is undefined after a SHUTDOWN intercept
         * so reinitialize it.
@@ -1277,7 +1279,7 @@ static int shutdown_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
        return 0;
 }
 
-static int io_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
+static int io_interception(struct vcpu_svm *svm)
 {
        u32 io_info = svm->vmcb->control.exit_info_1; /* address size bug? */
        int size, in, string;
@@ -1291,7 +1293,7 @@ static int io_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
 
        if (string) {
                if (emulate_instruction(&svm->vcpu,
-                                       kvm_run, 0, 0, 0) == EMULATE_DO_MMIO)
+                                       0, 0, 0) == EMULATE_DO_MMIO)
                        return 0;
                return 1;
        }
@@ -1301,33 +1303,33 @@ static int io_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
        size = (io_info & SVM_IOIO_SIZE_MASK) >> SVM_IOIO_SIZE_SHIFT;
 
        skip_emulated_instruction(&svm->vcpu);
-       return kvm_emulate_pio(&svm->vcpu, kvm_run, in, size, port);
+       return kvm_emulate_pio(&svm->vcpu, in, size, port);
 }
 
-static int nmi_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
+static int nmi_interception(struct vcpu_svm *svm)
 {
        return 1;
 }
 
-static int intr_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
+static int intr_interception(struct vcpu_svm *svm)
 {
        ++svm->vcpu.stat.irq_exits;
        return 1;
 }
 
-static int nop_on_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
+static int nop_on_interception(struct vcpu_svm *svm)
 {
        return 1;
 }
 
-static int halt_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
+static int halt_interception(struct vcpu_svm *svm)
 {
        svm->next_rip = kvm_rip_read(&svm->vcpu) + 1;
        skip_emulated_instruction(&svm->vcpu);
        return kvm_emulate_halt(&svm->vcpu);
 }
 
-static int vmmcall_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
+static int vmmcall_interception(struct vcpu_svm *svm)
 {
        svm->next_rip = kvm_rip_read(&svm->vcpu) + 3;
        skip_emulated_instruction(&svm->vcpu);
@@ -1378,8 +1380,15 @@ static inline int nested_svm_intr(struct vcpu_svm *svm)
 
        svm->vmcb->control.exit_code = SVM_EXIT_INTR;
 
-       if (nested_svm_exit_handled(svm)) {
-               nsvm_printk("VMexit -> INTR\n");
+       if (svm->nested.intercept & 1ULL) {
+               /*
+                * The #vmexit can't be emulated here directly because this
+                * code path runs with irqs and preemtion disabled. A
+                * #vmexit emulation might sleep. Only signal request for
+                * the #vmexit here.
+                */
+               svm->nested.exit_required = true;
+               trace_kvm_nested_intr_vmexit(svm->vmcb->save.rip);
                return 1;
        }
 
@@ -1390,10 +1399,7 @@ static void *nested_svm_map(struct vcpu_svm *svm, u64 gpa, enum km_type idx)
 {
        struct page *page;
 
-       down_read(&current->mm->mmap_sem);
        page = gfn_to_page(svm->vcpu.kvm, gpa >> PAGE_SHIFT);
-       up_read(&current->mm->mmap_sem);
-
        if (is_error_page(page))
                goto error;
 
@@ -1532,14 +1538,12 @@ static int nested_svm_exit_handled(struct vcpu_svm *svm)
        }
        default: {
                u64 exit_bits = 1ULL << (exit_code - SVM_EXIT_INTR);
-               nsvm_printk("exit code: 0x%x\n", exit_code);
                if (svm->nested.intercept & exit_bits)
                        vmexit = NESTED_EXIT_DONE;
        }
        }
 
        if (vmexit == NESTED_EXIT_DONE) {
-               nsvm_printk("#VMEXIT reason=%04x\n", exit_code);
                nested_svm_vmexit(svm);
        }
 
@@ -1584,6 +1588,12 @@ static int nested_svm_vmexit(struct vcpu_svm *svm)
        struct vmcb *hsave = svm->nested.hsave;
        struct vmcb *vmcb = svm->vmcb;
 
+       trace_kvm_nested_vmexit_inject(vmcb->control.exit_code,
+                                      vmcb->control.exit_info_1,
+                                      vmcb->control.exit_info_2,
+                                      vmcb->control.exit_int_info,
+                                      vmcb->control.exit_int_info_err);
+
        nested_vmcb = nested_svm_map(svm, svm->nested.vmcb, KM_USER0);
        if (!nested_vmcb)
                return 1;
@@ -1617,6 +1627,22 @@ static int nested_svm_vmexit(struct vcpu_svm *svm)
        nested_vmcb->control.exit_info_2       = vmcb->control.exit_info_2;
        nested_vmcb->control.exit_int_info     = vmcb->control.exit_int_info;
        nested_vmcb->control.exit_int_info_err = vmcb->control.exit_int_info_err;
+
+       /*
+        * If we emulate a VMRUN/#VMEXIT in the same host #vmexit cycle we have
+        * to make sure that we do not lose injected events. So check event_inj
+        * here and copy it to exit_int_info if it is valid.
+        * Exit_int_info and event_inj can't be both valid because the case
+        * below only happens on a VMRUN instruction intercept which has
+        * no valid exit_int_info set.
+        */
+       if (vmcb->control.event_inj & SVM_EVTINJ_VALID) {
+               struct vmcb_control_area *nc = &nested_vmcb->control;
+
+               nc->exit_int_info     = vmcb->control.event_inj;
+               nc->exit_int_info_err = vmcb->control.event_inj_err;
+       }
+
        nested_vmcb->control.tlb_ctl           = 0;
        nested_vmcb->control.event_inj         = 0;
        nested_vmcb->control.event_inj_err     = 0;
@@ -1628,10 +1654,6 @@ static int nested_svm_vmexit(struct vcpu_svm *svm)
        /* Restore the original control entries */
        copy_vmcb_control_area(vmcb, hsave);
 
-       /* Kill any pending exceptions */
-       if (svm->vcpu.arch.exception.pending == true)
-               nsvm_printk("WARNING: Pending Exception\n");
-
        kvm_clear_exception_queue(&svm->vcpu);
        kvm_clear_interrupt_queue(&svm->vcpu);
 
@@ -1702,6 +1724,12 @@ static bool nested_svm_vmrun(struct vcpu_svm *svm)
        /* nested_vmcb is our indicator if nested SVM is activated */
        svm->nested.vmcb = svm->vmcb->save.rax;
 
+       trace_kvm_nested_vmrun(svm->vmcb->save.rip - 3, svm->nested.vmcb,
+                              nested_vmcb->save.rip,
+                              nested_vmcb->control.int_ctl,
+                              nested_vmcb->control.event_inj,
+                              nested_vmcb->control.nested_ctl);
+
        /* Clear internal status */
        kvm_clear_exception_queue(&svm->vcpu);
        kvm_clear_interrupt_queue(&svm->vcpu);
@@ -1789,28 +1817,15 @@ static bool nested_svm_vmrun(struct vcpu_svm *svm)
        svm->nested.intercept            = nested_vmcb->control.intercept;
 
        force_new_asid(&svm->vcpu);
-       svm->vmcb->control.exit_int_info = nested_vmcb->control.exit_int_info;
-       svm->vmcb->control.exit_int_info_err = nested_vmcb->control.exit_int_info_err;
        svm->vmcb->control.int_ctl = nested_vmcb->control.int_ctl | V_INTR_MASKING_MASK;
-       if (nested_vmcb->control.int_ctl & V_IRQ_MASK) {
-               nsvm_printk("nSVM Injecting Interrupt: 0x%x\n",
-                               nested_vmcb->control.int_ctl);
-       }
        if (nested_vmcb->control.int_ctl & V_INTR_MASKING_MASK)
                svm->vcpu.arch.hflags |= HF_VINTR_MASK;
        else
                svm->vcpu.arch.hflags &= ~HF_VINTR_MASK;
 
-       nsvm_printk("nSVM exit_int_info: 0x%x | int_state: 0x%x\n",
-                       nested_vmcb->control.exit_int_info,
-                       nested_vmcb->control.int_state);
-
        svm->vmcb->control.int_vector = nested_vmcb->control.int_vector;
        svm->vmcb->control.int_state = nested_vmcb->control.int_state;
        svm->vmcb->control.tsc_offset += nested_vmcb->control.tsc_offset;
-       if (nested_vmcb->control.event_inj & SVM_EVTINJ_VALID)
-               nsvm_printk("Injecting Event: 0x%x\n",
-                               nested_vmcb->control.event_inj);
        svm->vmcb->control.event_inj = nested_vmcb->control.event_inj;
        svm->vmcb->control.event_inj_err = nested_vmcb->control.event_inj_err;
 
@@ -1837,7 +1852,7 @@ static void nested_svm_vmloadsave(struct vmcb *from_vmcb, struct vmcb *to_vmcb)
        to_vmcb->save.sysenter_eip = from_vmcb->save.sysenter_eip;
 }
 
-static int vmload_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
+static int vmload_interception(struct vcpu_svm *svm)
 {
        struct vmcb *nested_vmcb;
 
@@ -1857,7 +1872,7 @@ static int vmload_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
        return 1;
 }
 
-static int vmsave_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
+static int vmsave_interception(struct vcpu_svm *svm)
 {
        struct vmcb *nested_vmcb;
 
@@ -1877,10 +1892,8 @@ static int vmsave_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
        return 1;
 }
 
-static int vmrun_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
+static int vmrun_interception(struct vcpu_svm *svm)
 {
-       nsvm_printk("VMrun\n");
-
        if (nested_svm_check_permissions(svm))
                return 1;
 
@@ -1907,7 +1920,7 @@ failed:
        return 1;
 }
 
-static int stgi_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
+static int stgi_interception(struct vcpu_svm *svm)
 {
        if (nested_svm_check_permissions(svm))
                return 1;
@@ -1920,7 +1933,7 @@ static int stgi_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
        return 1;
 }
 
-static int clgi_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
+static int clgi_interception(struct vcpu_svm *svm)
 {
        if (nested_svm_check_permissions(svm))
                return 1;
@@ -1937,10 +1950,12 @@ static int clgi_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
        return 1;
 }
 
-static int invlpga_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
+static int invlpga_interception(struct vcpu_svm *svm)
 {
        struct kvm_vcpu *vcpu = &svm->vcpu;
-       nsvm_printk("INVLPGA\n");
+
+       trace_kvm_invlpga(svm->vmcb->save.rip, vcpu->arch.regs[VCPU_REGS_RCX],
+                         vcpu->arch.regs[VCPU_REGS_RAX]);
 
        /* Let's treat INVLPGA the same as INVLPG (can be optimized!) */
        kvm_mmu_invlpg(vcpu, vcpu->arch.regs[VCPU_REGS_RAX]);
@@ -1950,15 +1965,21 @@ static int invlpga_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
        return 1;
 }
 
-static int invalid_op_interception(struct vcpu_svm *svm,
-                                  struct kvm_run *kvm_run)
+static int skinit_interception(struct vcpu_svm *svm)
 {
+       trace_kvm_skinit(svm->vmcb->save.rip, svm->vcpu.arch.regs[VCPU_REGS_RAX]);
+
        kvm_queue_exception(&svm->vcpu, UD_VECTOR);
        return 1;
 }
 
-static int task_switch_interception(struct vcpu_svm *svm,
-                                   struct kvm_run *kvm_run)
+static int invalid_op_interception(struct vcpu_svm *svm)
+{
+       kvm_queue_exception(&svm->vcpu, UD_VECTOR);
+       return 1;
+}
+
+static int task_switch_interception(struct vcpu_svm *svm)
 {
        u16 tss_selector;
        int reason;
@@ -2008,14 +2029,14 @@ static int task_switch_interception(struct vcpu_svm *svm,
        return kvm_task_switch(&svm->vcpu, tss_selector, reason);
 }
 
-static int cpuid_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
+static int cpuid_interception(struct vcpu_svm *svm)
 {
        svm->next_rip = kvm_rip_read(&svm->vcpu) + 2;
        kvm_emulate_cpuid(&svm->vcpu);
        return 1;
 }
 
-static int iret_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
+static int iret_interception(struct vcpu_svm *svm)
 {
        ++svm->vcpu.stat.nmi_window_exits;
        svm->vmcb->control.intercept &= ~(1UL << INTERCEPT_IRET);
@@ -2023,26 +2044,27 @@ static int iret_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
        return 1;
 }
 
-static int invlpg_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
+static int invlpg_interception(struct vcpu_svm *svm)
 {
-       if (emulate_instruction(&svm->vcpu, kvm_run, 0, 0, 0) != EMULATE_DONE)
+       if (emulate_instruction(&svm->vcpu, 0, 0, 0) != EMULATE_DONE)
                pr_unimpl(&svm->vcpu, "%s: failed\n", __func__);
        return 1;
 }
 
-static int emulate_on_interception(struct vcpu_svm *svm,
-                                  struct kvm_run *kvm_run)
+static int emulate_on_interception(struct vcpu_svm *svm)
 {
-       if (emulate_instruction(&svm->vcpu, NULL, 0, 0, 0) != EMULATE_DONE)
+       if (emulate_instruction(&svm->vcpu, 0, 0, 0) != EMULATE_DONE)
                pr_unimpl(&svm->vcpu, "%s: failed\n", __func__);
        return 1;
 }
 
-static int cr8_write_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
+static int cr8_write_interception(struct vcpu_svm *svm)
 {
+       struct kvm_run *kvm_run = svm->vcpu.run;
+
        u8 cr8_prev = kvm_get_cr8(&svm->vcpu);
        /* instruction emulation calls kvm_set_cr8() */
-       emulate_instruction(&svm->vcpu, NULL, 0, 0, 0);
+       emulate_instruction(&svm->vcpu, 0, 0, 0);
        if (irqchip_in_kernel(svm->vcpu.kvm)) {
                svm->vmcb->control.intercept_cr_write &= ~INTERCEPT_CR8_MASK;
                return 1;
@@ -2128,7 +2150,7 @@ static int svm_get_msr(struct kvm_vcpu *vcpu, unsigned ecx, u64 *data)
        return 0;
 }
 
-static int rdmsr_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
+static int rdmsr_interception(struct vcpu_svm *svm)
 {
        u32 ecx = svm->vcpu.arch.regs[VCPU_REGS_RCX];
        u64 data;
@@ -2221,7 +2243,7 @@ static int svm_set_msr(struct kvm_vcpu *vcpu, unsigned ecx, u64 data)
        return 0;
 }
 
-static int wrmsr_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
+static int wrmsr_interception(struct vcpu_svm *svm)
 {
        u32 ecx = svm->vcpu.arch.regs[VCPU_REGS_RCX];
        u64 data = (svm->vcpu.arch.regs[VCPU_REGS_RAX] & -1u)
@@ -2237,17 +2259,18 @@ static int wrmsr_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
        return 1;
 }
 
-static int msr_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
+static int msr_interception(struct vcpu_svm *svm)
 {
        if (svm->vmcb->control.exit_info_1)
-               return wrmsr_interception(svm, kvm_run);
+               return wrmsr_interception(svm);
        else
-               return rdmsr_interception(svm, kvm_run);
+               return rdmsr_interception(svm);
 }
 
-static int interrupt_window_interception(struct vcpu_svm *svm,
-                                  struct kvm_run *kvm_run)
+static int interrupt_window_interception(struct vcpu_svm *svm)
 {
+       struct kvm_run *kvm_run = svm->vcpu.run;
+
        svm_clear_vintr(svm);
        svm->vmcb->control.int_ctl &= ~V_IRQ_MASK;
        /*
@@ -2265,8 +2288,13 @@ static int interrupt_window_interception(struct vcpu_svm *svm,
        return 1;
 }
 
-static int (*svm_exit_handlers[])(struct vcpu_svm *svm,
-                                     struct kvm_run *kvm_run) = {
+static int pause_interception(struct vcpu_svm *svm)
+{
+       kvm_vcpu_on_spin(&(svm->vcpu));
+       return 1;
+}
+
+static int (*svm_exit_handlers[])(struct vcpu_svm *svm) = {
        [SVM_EXIT_READ_CR0]                     = emulate_on_interception,
        [SVM_EXIT_READ_CR3]                     = emulate_on_interception,
        [SVM_EXIT_READ_CR4]                     = emulate_on_interception,
@@ -2301,6 +2329,7 @@ static int (*svm_exit_handlers[])(struct vcpu_svm *svm,
        [SVM_EXIT_CPUID]                        = cpuid_interception,
        [SVM_EXIT_IRET]                         = iret_interception,
        [SVM_EXIT_INVD]                         = emulate_on_interception,
+       [SVM_EXIT_PAUSE]                        = pause_interception,
        [SVM_EXIT_HLT]                          = halt_interception,
        [SVM_EXIT_INVLPG]                       = invlpg_interception,
        [SVM_EXIT_INVLPGA]                      = invlpga_interception,
@@ -2314,26 +2343,36 @@ static int (*svm_exit_handlers[])(struct vcpu_svm *svm,
        [SVM_EXIT_VMSAVE]                       = vmsave_interception,
        [SVM_EXIT_STGI]                         = stgi_interception,
        [SVM_EXIT_CLGI]                         = clgi_interception,
-       [SVM_EXIT_SKINIT]                       = invalid_op_interception,
+       [SVM_EXIT_SKINIT]                       = skinit_interception,
        [SVM_EXIT_WBINVD]                       = emulate_on_interception,
        [SVM_EXIT_MONITOR]                      = invalid_op_interception,
        [SVM_EXIT_MWAIT]                        = invalid_op_interception,
        [SVM_EXIT_NPF]                          = pf_interception,
 };
 
-static int handle_exit(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
+static int handle_exit(struct kvm_vcpu *vcpu)
 {
        struct vcpu_svm *svm = to_svm(vcpu);
+       struct kvm_run *kvm_run = vcpu->run;
        u32 exit_code = svm->vmcb->control.exit_code;
 
        trace_kvm_exit(exit_code, svm->vmcb->save.rip);
 
+       if (unlikely(svm->nested.exit_required)) {
+               nested_svm_vmexit(svm);
+               svm->nested.exit_required = false;
+
+               return 1;
+       }
+
        if (is_nested(svm)) {
                int vmexit;
 
-               nsvm_printk("nested handle_exit: 0x%x | 0x%lx | 0x%lx | 0x%lx\n",
-                           exit_code, svm->vmcb->control.exit_info_1,
-                           svm->vmcb->control.exit_info_2, svm->vmcb->save.rip);
+               trace_kvm_nested_vmexit(svm->vmcb->save.rip, exit_code,
+                                       svm->vmcb->control.exit_info_1,
+                                       svm->vmcb->control.exit_info_2,
+                                       svm->vmcb->control.exit_int_info,
+                                       svm->vmcb->control.exit_int_info_err);
 
                vmexit = nested_svm_exit_special(svm);
 
@@ -2383,7 +2422,7 @@ static int handle_exit(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
                return 0;
        }
 
-       return svm_exit_handlers[exit_code](svm, kvm_run);
+       return svm_exit_handlers[exit_code](svm);
 }
 
 static void reload_tss(struct kvm_vcpu *vcpu)
@@ -2460,20 +2499,47 @@ static int svm_nmi_allowed(struct kvm_vcpu *vcpu)
                !(svm->vcpu.arch.hflags & HF_NMI_MASK);
 }
 
+static bool svm_get_nmi_mask(struct kvm_vcpu *vcpu)
+{
+       struct vcpu_svm *svm = to_svm(vcpu);
+
+       return !!(svm->vcpu.arch.hflags & HF_NMI_MASK);
+}
+
+static void svm_set_nmi_mask(struct kvm_vcpu *vcpu, bool masked)
+{
+       struct vcpu_svm *svm = to_svm(vcpu);
+
+       if (masked) {
+               svm->vcpu.arch.hflags |= HF_NMI_MASK;
+               svm->vmcb->control.intercept |= (1UL << INTERCEPT_IRET);
+       } else {
+               svm->vcpu.arch.hflags &= ~HF_NMI_MASK;
+               svm->vmcb->control.intercept &= ~(1UL << INTERCEPT_IRET);
+       }
+}
+
 static int svm_interrupt_allowed(struct kvm_vcpu *vcpu)
 {
        struct vcpu_svm *svm = to_svm(vcpu);
        struct vmcb *vmcb = svm->vmcb;
-       return (vmcb->save.rflags & X86_EFLAGS_IF) &&
-               !(vmcb->control.int_state & SVM_INTERRUPT_SHADOW_MASK) &&
-               gif_set(svm) &&
-               !(is_nested(svm) && (svm->vcpu.arch.hflags & HF_VINTR_MASK));
+       int ret;
+
+       if (!gif_set(svm) ||
+            (vmcb->control.int_state & SVM_INTERRUPT_SHADOW_MASK))
+               return 0;
+
+       ret = !!(vmcb->save.rflags & X86_EFLAGS_IF);
+
+       if (is_nested(svm))
+               return ret && !(svm->vcpu.arch.hflags & HF_VINTR_MASK);
+
+       return ret;
 }
 
 static void enable_irq_window(struct kvm_vcpu *vcpu)
 {
        struct vcpu_svm *svm = to_svm(vcpu);
-       nsvm_printk("Trying to open IRQ window\n");
 
        nested_svm_intr(svm);
 
@@ -2498,7 +2564,7 @@ static void enable_nmi_window(struct kvm_vcpu *vcpu)
        /* Something prevents NMI from been injected. Single step over
           possible problem (IRET or exception injection or interrupt
           shadow) */
-       vcpu->arch.singlestep = true;
+       svm->nmi_singlestep = true;
        svm->vmcb->save.rflags |= (X86_EFLAGS_TF | X86_EFLAGS_RF);
        update_db_intercept(vcpu);
 }
@@ -2588,13 +2654,20 @@ static void svm_complete_interrupts(struct vcpu_svm *svm)
 #define R "e"
 #endif
 
-static void svm_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+static void svm_vcpu_run(struct kvm_vcpu *vcpu)
 {
        struct vcpu_svm *svm = to_svm(vcpu);
        u16 fs_selector;
        u16 gs_selector;
        u16 ldt_selector;
 
+       /*
+        * A vmexit emulation is required before the vcpu can be executed
+        * again.
+        */
+       if (unlikely(svm->nested.exit_required))
+               return;
+
        svm->vmcb->save.rax = vcpu->arch.regs[VCPU_REGS_RAX];
        svm->vmcb->save.rsp = vcpu->arch.regs[VCPU_REGS_RSP];
        svm->vmcb->save.rip = vcpu->arch.regs[VCPU_REGS_RIP];
@@ -2893,6 +2966,8 @@ static struct kvm_x86_ops svm_x86_ops = {
        .queue_exception = svm_queue_exception,
        .interrupt_allowed = svm_interrupt_allowed,
        .nmi_allowed = svm_nmi_allowed,
+       .get_nmi_mask = svm_get_nmi_mask,
+       .set_nmi_mask = svm_set_nmi_mask,
        .enable_nmi_window = enable_nmi_window,
        .enable_irq_window = enable_irq_window,
        .update_cr8_intercept = update_cr8_intercept,
index 0d480e7..816e044 100644 (file)
@@ -349,6 +349,171 @@ TRACE_EVENT(kvm_apic_accept_irq,
                  __entry->coalesced ? " (coalesced)" : "")
 );
 
+/*
+ * Tracepoint for nested VMRUN
+ */
+TRACE_EVENT(kvm_nested_vmrun,
+           TP_PROTO(__u64 rip, __u64 vmcb, __u64 nested_rip, __u32 int_ctl,
+                    __u32 event_inj, bool npt),
+           TP_ARGS(rip, vmcb, nested_rip, int_ctl, event_inj, npt),
+
+       TP_STRUCT__entry(
+               __field(        __u64,          rip             )
+               __field(        __u64,          vmcb            )
+               __field(        __u64,          nested_rip      )
+               __field(        __u32,          int_ctl         )
+               __field(        __u32,          event_inj       )
+               __field(        bool,           npt             )
+       ),
+
+       TP_fast_assign(
+               __entry->rip            = rip;
+               __entry->vmcb           = vmcb;
+               __entry->nested_rip     = nested_rip;
+               __entry->int_ctl        = int_ctl;
+               __entry->event_inj      = event_inj;
+               __entry->npt            = npt;
+       ),
+
+       TP_printk("rip: 0x%016llx vmcb: 0x%016llx nrip: 0x%016llx int_ctl: 0x%08x "
+                 "event_inj: 0x%08x npt: %s\n",
+               __entry->rip, __entry->vmcb, __entry->nested_rip,
+               __entry->int_ctl, __entry->event_inj,
+               __entry->npt ? "on" : "off")
+);
+
+/*
+ * Tracepoint for #VMEXIT while nested
+ */
+TRACE_EVENT(kvm_nested_vmexit,
+           TP_PROTO(__u64 rip, __u32 exit_code,
+                    __u64 exit_info1, __u64 exit_info2,
+                    __u32 exit_int_info, __u32 exit_int_info_err),
+           TP_ARGS(rip, exit_code, exit_info1, exit_info2,
+                   exit_int_info, exit_int_info_err),
+
+       TP_STRUCT__entry(
+               __field(        __u64,          rip                     )
+               __field(        __u32,          exit_code               )
+               __field(        __u64,          exit_info1              )
+               __field(        __u64,          exit_info2              )
+               __field(        __u32,          exit_int_info           )
+               __field(        __u32,          exit_int_info_err       )
+       ),
+
+       TP_fast_assign(
+               __entry->rip                    = rip;
+               __entry->exit_code              = exit_code;
+               __entry->exit_info1             = exit_info1;
+               __entry->exit_info2             = exit_info2;
+               __entry->exit_int_info          = exit_int_info;
+               __entry->exit_int_info_err      = exit_int_info_err;
+       ),
+       TP_printk("rip: 0x%016llx reason: %s ext_inf1: 0x%016llx "
+                 "ext_inf2: 0x%016llx ext_int: 0x%08x ext_int_err: 0x%08x\n",
+                 __entry->rip,
+                 ftrace_print_symbols_seq(p, __entry->exit_code,
+                                          kvm_x86_ops->exit_reasons_str),
+                 __entry->exit_info1, __entry->exit_info2,
+                 __entry->exit_int_info, __entry->exit_int_info_err)
+);
+
+/*
+ * Tracepoint for #VMEXIT reinjected to the guest
+ */
+TRACE_EVENT(kvm_nested_vmexit_inject,
+           TP_PROTO(__u32 exit_code,
+                    __u64 exit_info1, __u64 exit_info2,
+                    __u32 exit_int_info, __u32 exit_int_info_err),
+           TP_ARGS(exit_code, exit_info1, exit_info2,
+                   exit_int_info, exit_int_info_err),
+
+       TP_STRUCT__entry(
+               __field(        __u32,          exit_code               )
+               __field(        __u64,          exit_info1              )
+               __field(        __u64,          exit_info2              )
+               __field(        __u32,          exit_int_info           )
+               __field(        __u32,          exit_int_info_err       )
+       ),
+
+       TP_fast_assign(
+               __entry->exit_code              = exit_code;
+               __entry->exit_info1             = exit_info1;
+               __entry->exit_info2             = exit_info2;
+               __entry->exit_int_info          = exit_int_info;
+               __entry->exit_int_info_err      = exit_int_info_err;
+       ),
+
+       TP_printk("reason: %s ext_inf1: 0x%016llx "
+                 "ext_inf2: 0x%016llx ext_int: 0x%08x ext_int_err: 0x%08x\n",
+                 ftrace_print_symbols_seq(p, __entry->exit_code,
+                                          kvm_x86_ops->exit_reasons_str),
+               __entry->exit_info1, __entry->exit_info2,
+               __entry->exit_int_info, __entry->exit_int_info_err)
+);
+
+/*
+ * Tracepoint for nested #vmexit because of interrupt pending
+ */
+TRACE_EVENT(kvm_nested_intr_vmexit,
+           TP_PROTO(__u64 rip),
+           TP_ARGS(rip),
+
+       TP_STRUCT__entry(
+               __field(        __u64,  rip     )
+       ),
+
+       TP_fast_assign(
+               __entry->rip    =       rip
+       ),
+
+       TP_printk("rip: 0x%016llx\n", __entry->rip)
+);
+
+/*
+ * Tracepoint for nested #vmexit because of interrupt pending
+ */
+TRACE_EVENT(kvm_invlpga,
+           TP_PROTO(__u64 rip, int asid, u64 address),
+           TP_ARGS(rip, asid, address),
+
+       TP_STRUCT__entry(
+               __field(        __u64,  rip     )
+               __field(        int,    asid    )
+               __field(        __u64,  address )
+       ),
+
+       TP_fast_assign(
+               __entry->rip            =       rip;
+               __entry->asid           =       asid;
+               __entry->address        =       address;
+       ),
+
+       TP_printk("rip: 0x%016llx asid: %d address: 0x%016llx\n",
+                 __entry->rip, __entry->asid, __entry->address)
+);
+
+/*
+ * Tracepoint for nested #vmexit because of interrupt pending
+ */
+TRACE_EVENT(kvm_skinit,
+           TP_PROTO(__u64 rip, __u32 slb),
+           TP_ARGS(rip, slb),
+
+       TP_STRUCT__entry(
+               __field(        __u64,  rip     )
+               __field(        __u32,  slb     )
+       ),
+
+       TP_fast_assign(
+               __entry->rip            =       rip;
+               __entry->slb            =       slb;
+       ),
+
+       TP_printk("rip: 0x%016llx slb: 0x%08x\n",
+                 __entry->rip, __entry->slb)
+);
+
 #endif /* _TRACE_KVM_H */
 
 /* This part must be outside protection */
index ed53b42..d4918d6 100644 (file)
@@ -61,12 +61,37 @@ module_param_named(unrestricted_guest,
 static int __read_mostly emulate_invalid_guest_state = 0;
 module_param(emulate_invalid_guest_state, bool, S_IRUGO);
 
+/*
+ * These 2 parameters are used to config the controls for Pause-Loop Exiting:
+ * ple_gap:    upper bound on the amount of time between two successive
+ *             executions of PAUSE in a loop. Also indicate if ple enabled.
+ *             According to test, this time is usually small than 41 cycles.
+ * ple_window: upper bound on the amount of time a guest is allowed to execute
+ *             in a PAUSE loop. Tests indicate that most spinlocks are held for
+ *             less than 2^12 cycles
+ * Time is measured based on a counter that runs at the same rate as the TSC,
+ * refer SDM volume 3b section 21.6.13 & 22.1.3.
+ */
+#define KVM_VMX_DEFAULT_PLE_GAP    41
+#define KVM_VMX_DEFAULT_PLE_WINDOW 4096
+static int ple_gap = KVM_VMX_DEFAULT_PLE_GAP;
+module_param(ple_gap, int, S_IRUGO);
+
+static int ple_window = KVM_VMX_DEFAULT_PLE_WINDOW;
+module_param(ple_window, int, S_IRUGO);
+
 struct vmcs {
        u32 revision_id;
        u32 abort;
        char data[0];
 };
 
+struct shared_msr_entry {
+       unsigned index;
+       u64 data;
+       u64 mask;
+};
+
 struct vcpu_vmx {
        struct kvm_vcpu       vcpu;
        struct list_head      local_vcpus_link;
@@ -74,13 +99,12 @@ struct vcpu_vmx {
        int                   launched;
        u8                    fail;
        u32                   idt_vectoring_info;
-       struct kvm_msr_entry *guest_msrs;
-       struct kvm_msr_entry *host_msrs;
+       struct shared_msr_entry *guest_msrs;
        int                   nmsrs;
        int                   save_nmsrs;
-       int                   msr_offset_efer;
 #ifdef CONFIG_X86_64
-       int                   msr_offset_kernel_gs_base;
+       u64                   msr_host_kernel_gs_base;
+       u64                   msr_guest_kernel_gs_base;
 #endif
        struct vmcs          *vmcs;
        struct {
@@ -88,7 +112,6 @@ struct vcpu_vmx {
                u16           fs_sel, gs_sel, ldt_sel;
                int           gs_ldt_reload_needed;
                int           fs_reload_needed;
-               int           guest_efer_loaded;
        } host_state;
        struct {
                int vm86_active;
@@ -107,7 +130,6 @@ struct vcpu_vmx {
        } rmode;
        int vpid;
        bool emulation_required;
-       enum emulation_result invalid_state_emulation_result;
 
        /* Support for vnmi-less CPUs */
        int soft_vnmi_blocked;
@@ -176,6 +198,8 @@ static struct kvm_vmx_segment_field {
        VMX_SEGMENT_FIELD(LDTR),
 };
 
+static u64 host_efer;
+
 static void ept_save_pdptrs(struct kvm_vcpu *vcpu);
 
 /*
@@ -184,28 +208,12 @@ static void ept_save_pdptrs(struct kvm_vcpu *vcpu);
  */
 static const u32 vmx_msr_index[] = {
 #ifdef CONFIG_X86_64
-       MSR_SYSCALL_MASK, MSR_LSTAR, MSR_CSTAR, MSR_KERNEL_GS_BASE,
+       MSR_SYSCALL_MASK, MSR_LSTAR, MSR_CSTAR,
 #endif
        MSR_EFER, MSR_K6_STAR,
 };
 #define NR_VMX_MSR ARRAY_SIZE(vmx_msr_index)
 
-static void load_msrs(struct kvm_msr_entry *e, int n)
-{
-       int i;
-
-       for (i = 0; i < n; ++i)
-               wrmsrl(e[i].index, e[i].data);
-}
-
-static void save_msrs(struct kvm_msr_entry *e, int n)
-{
-       int i;
-
-       for (i = 0; i < n; ++i)
-               rdmsrl(e[i].index, e[i].data);
-}
-
 static inline int is_page_fault(u32 intr_info)
 {
        return (intr_info & (INTR_INFO_INTR_TYPE_MASK | INTR_INFO_VECTOR_MASK |
@@ -320,6 +328,12 @@ static inline int cpu_has_vmx_unrestricted_guest(void)
                SECONDARY_EXEC_UNRESTRICTED_GUEST;
 }
 
+static inline int cpu_has_vmx_ple(void)
+{
+       return vmcs_config.cpu_based_2nd_exec_ctrl &
+               SECONDARY_EXEC_PAUSE_LOOP_EXITING;
+}
+
 static inline int vm_need_virtualize_apic_accesses(struct kvm *kvm)
 {
        return flexpriority_enabled &&
@@ -348,7 +362,7 @@ static int __find_msr_index(struct vcpu_vmx *vmx, u32 msr)
        int i;
 
        for (i = 0; i < vmx->nmsrs; ++i)
-               if (vmx->guest_msrs[i].index == msr)
+               if (vmx_msr_index[vmx->guest_msrs[i].index] == msr)
                        return i;
        return -1;
 }
@@ -379,7 +393,7 @@ static inline void __invept(int ext, u64 eptp, gpa_t gpa)
                        : : "a" (&operand), "c" (ext) : "cc", "memory");
 }
 
-static struct kvm_msr_entry *find_msr_entry(struct vcpu_vmx *vmx, u32 msr)
+static struct shared_msr_entry *find_msr_entry(struct vcpu_vmx *vmx, u32 msr)
 {
        int i;
 
@@ -570,17 +584,12 @@ static void reload_tss(void)
        load_TR_desc();
 }
 
-static void load_transition_efer(struct vcpu_vmx *vmx)
+static bool update_transition_efer(struct vcpu_vmx *vmx, int efer_offset)
 {
-       int efer_offset = vmx->msr_offset_efer;
-       u64 host_efer;
        u64 guest_efer;
        u64 ignore_bits;
 
-       if (efer_offset < 0)
-               return;
-       host_efer = vmx->host_msrs[efer_offset].data;
-       guest_efer = vmx->guest_msrs[efer_offset].data;
+       guest_efer = vmx->vcpu.arch.shadow_efer;
 
        /*
         * NX is emulated; LMA and LME handled by hardware; SCE meaninless
@@ -593,27 +602,17 @@ static void load_transition_efer(struct vcpu_vmx *vmx)
        if (guest_efer & EFER_LMA)
                ignore_bits &= ~(u64)EFER_SCE;
 #endif
-       if ((guest_efer & ~ignore_bits) == (host_efer & ~ignore_bits))
-               return;
-
-       vmx->host_state.guest_efer_loaded = 1;
        guest_efer &= ~ignore_bits;
        guest_efer |= host_efer & ignore_bits;
-       wrmsrl(MSR_EFER, guest_efer);
-       vmx->vcpu.stat.efer_reload++;
-}
-
-static void reload_host_efer(struct vcpu_vmx *vmx)
-{
-       if (vmx->host_state.guest_efer_loaded) {
-               vmx->host_state.guest_efer_loaded = 0;
-               load_msrs(vmx->host_msrs + vmx->msr_offset_efer, 1);
-       }
+       vmx->guest_msrs[efer_offset].data = guest_efer;
+       vmx->guest_msrs[efer_offset].mask = ~ignore_bits;
+       return true;
 }
 
 static void vmx_save_host_state(struct kvm_vcpu *vcpu)
 {
        struct vcpu_vmx *vmx = to_vmx(vcpu);
+       int i;
 
        if (vmx->host_state.loaded)
                return;
@@ -650,13 +649,15 @@ static void vmx_save_host_state(struct kvm_vcpu *vcpu)
 #endif
 
 #ifdef CONFIG_X86_64
-       if (is_long_mode(&vmx->vcpu))
-               save_msrs(vmx->host_msrs +
-                         vmx->msr_offset_kernel_gs_base, 1);
-
+       if (is_long_mode(&vmx->vcpu)) {
+               rdmsrl(MSR_KERNEL_GS_BASE, vmx->msr_host_kernel_gs_base);
+               wrmsrl(MSR_KERNEL_GS_BASE, vmx->msr_guest_kernel_gs_base);
+       }
 #endif
-       load_msrs(vmx->guest_msrs, vmx->save_nmsrs);
-       load_transition_efer(vmx);
+       for (i = 0; i < vmx->save_nmsrs; ++i)
+               kvm_set_shared_msr(vmx->guest_msrs[i].index,
+                                  vmx->guest_msrs[i].data,
+                                  vmx->guest_msrs[i].mask);
 }
 
 static void __vmx_load_host_state(struct vcpu_vmx *vmx)
@@ -684,9 +685,12 @@ static void __vmx_load_host_state(struct vcpu_vmx *vmx)
                local_irq_restore(flags);
        }
        reload_tss();
-       save_msrs(vmx->guest_msrs, vmx->save_nmsrs);
-       load_msrs(vmx->host_msrs, vmx->save_nmsrs);
-       reload_host_efer(vmx);
+#ifdef CONFIG_X86_64
+       if (is_long_mode(&vmx->vcpu)) {
+               rdmsrl(MSR_KERNEL_GS_BASE, vmx->msr_guest_kernel_gs_base);
+               wrmsrl(MSR_KERNEL_GS_BASE, vmx->msr_host_kernel_gs_base);
+       }
+#endif
 }
 
 static void vmx_load_host_state(struct vcpu_vmx *vmx)
@@ -877,19 +881,14 @@ static void vmx_queue_exception(struct kvm_vcpu *vcpu, unsigned nr,
 /*
  * Swap MSR entry in host/guest MSR entry array.
  */
-#ifdef CONFIG_X86_64
 static void move_msr_up(struct vcpu_vmx *vmx, int from, int to)
 {
-       struct kvm_msr_entry tmp;
+       struct shared_msr_entry tmp;
 
        tmp = vmx->guest_msrs[to];
        vmx->guest_msrs[to] = vmx->guest_msrs[from];
        vmx->guest_msrs[from] = tmp;
-       tmp = vmx->host_msrs[to];
-       vmx->host_msrs[to] = vmx->host_msrs[from];
-       vmx->host_msrs[from] = tmp;
 }
-#endif
 
 /*
  * Set up the vmcs to automatically save and restore system
@@ -898,15 +897,13 @@ static void move_msr_up(struct vcpu_vmx *vmx, int from, int to)
  */
 static void setup_msrs(struct vcpu_vmx *vmx)
 {
-       int save_nmsrs;
+       int save_nmsrs, index;
        unsigned long *msr_bitmap;
 
        vmx_load_host_state(vmx);
        save_nmsrs = 0;
 #ifdef CONFIG_X86_64
        if (is_long_mode(&vmx->vcpu)) {
-               int index;
-
                index = __find_msr_index(vmx, MSR_SYSCALL_MASK);
                if (index >= 0)
                        move_msr_up(vmx, index, save_nmsrs++);
@@ -916,9 +913,6 @@ static void setup_msrs(struct vcpu_vmx *vmx)
                index = __find_msr_index(vmx, MSR_CSTAR);
                if (index >= 0)
                        move_msr_up(vmx, index, save_nmsrs++);
-               index = __find_msr_index(vmx, MSR_KERNEL_GS_BASE);
-               if (index >= 0)
-                       move_msr_up(vmx, index, save_nmsrs++);
                /*
                 * MSR_K6_STAR is only needed on long mode guests, and only
                 * if efer.sce is enabled.
@@ -928,13 +922,11 @@ static void setup_msrs(struct vcpu_vmx *vmx)
                        move_msr_up(vmx, index, save_nmsrs++);
        }
 #endif
-       vmx->save_nmsrs = save_nmsrs;
+       index = __find_msr_index(vmx, MSR_EFER);
+       if (index >= 0 && update_transition_efer(vmx, index))
+               move_msr_up(vmx, index, save_nmsrs++);
 
-#ifdef CONFIG_X86_64
-       vmx->msr_offset_kernel_gs_base =
-               __find_msr_index(vmx, MSR_KERNEL_GS_BASE);
-#endif
-       vmx->msr_offset_efer = __find_msr_index(vmx, MSR_EFER);
+       vmx->save_nmsrs = save_nmsrs;
 
        if (cpu_has_vmx_msr_bitmap()) {
                if (is_long_mode(&vmx->vcpu))
@@ -976,7 +968,7 @@ static void guest_write_tsc(u64 guest_tsc, u64 host_tsc)
 static int vmx_get_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 *pdata)
 {
        u64 data;
-       struct kvm_msr_entry *msr;
+       struct shared_msr_entry *msr;
 
        if (!pdata) {
                printk(KERN_ERR "BUG: get_msr called with NULL pdata\n");
@@ -991,9 +983,13 @@ static int vmx_get_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 *pdata)
        case MSR_GS_BASE:
                data = vmcs_readl(GUEST_GS_BASE);
                break;
+       case MSR_KERNEL_GS_BASE:
+               vmx_load_host_state(to_vmx(vcpu));
+               data = to_vmx(vcpu)->msr_guest_kernel_gs_base;
+               break;
+#endif
        case MSR_EFER:
                return kvm_get_msr_common(vcpu, msr_index, pdata);
-#endif
        case MSR_IA32_TSC:
                data = guest_read_tsc();
                break;
@@ -1007,6 +1003,7 @@ static int vmx_get_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 *pdata)
                data = vmcs_readl(GUEST_SYSENTER_ESP);
                break;
        default:
+               vmx_load_host_state(to_vmx(vcpu));
                msr = find_msr_entry(to_vmx(vcpu), msr_index);
                if (msr) {
                        vmx_load_host_state(to_vmx(vcpu));
@@ -1028,7 +1025,7 @@ static int vmx_get_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 *pdata)
 static int vmx_set_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 data)
 {
        struct vcpu_vmx *vmx = to_vmx(vcpu);
-       struct kvm_msr_entry *msr;
+       struct shared_msr_entry *msr;
        u64 host_tsc;
        int ret = 0;
 
@@ -1044,6 +1041,10 @@ static int vmx_set_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 data)
        case MSR_GS_BASE:
                vmcs_writel(GUEST_GS_BASE, data);
                break;
+       case MSR_KERNEL_GS_BASE:
+               vmx_load_host_state(vmx);
+               vmx->msr_guest_kernel_gs_base = data;
+               break;
 #endif
        case MSR_IA32_SYSENTER_CS:
                vmcs_write32(GUEST_SYSENTER_CS, data);
@@ -1097,30 +1098,14 @@ static void vmx_cache_reg(struct kvm_vcpu *vcpu, enum kvm_reg reg)
        }
 }
 
-static int set_guest_debug(struct kvm_vcpu *vcpu, struct kvm_guest_debug *dbg)
+static void set_guest_debug(struct kvm_vcpu *vcpu, struct kvm_guest_debug *dbg)
 {
-       int old_debug = vcpu->guest_debug;
-       unsigned long flags;
-
-       vcpu->guest_debug = dbg->control;
-       if (!(vcpu->guest_debug & KVM_GUESTDBG_ENABLE))
-               vcpu->guest_debug = 0;
-
        if (vcpu->guest_debug & KVM_GUESTDBG_USE_HW_BP)
                vmcs_writel(GUEST_DR7, dbg->arch.debugreg[7]);
        else
                vmcs_writel(GUEST_DR7, vcpu->arch.dr7);
 
-       flags = vmcs_readl(GUEST_RFLAGS);
-       if (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP)
-               flags |= X86_EFLAGS_TF | X86_EFLAGS_RF;
-       else if (old_debug & KVM_GUESTDBG_SINGLESTEP)
-               flags &= ~(X86_EFLAGS_TF | X86_EFLAGS_RF);
-       vmcs_writel(GUEST_RFLAGS, flags);
-
        update_exception_bitmap(vcpu);
-
-       return 0;
 }
 
 static __init int cpu_has_kvm_support(void)
@@ -1139,12 +1124,15 @@ static __init int vmx_disabled_by_bios(void)
        /* locked but not enabled */
 }
 
-static void hardware_enable(void *garbage)
+static int hardware_enable(void *garbage)
 {
        int cpu = raw_smp_processor_id();
        u64 phys_addr = __pa(per_cpu(vmxarea, cpu));
        u64 old;
 
+       if (read_cr4() & X86_CR4_VMXE)
+               return -EBUSY;
+
        INIT_LIST_HEAD(&per_cpu(vcpus_on_cpu, cpu));
        rdmsrl(MSR_IA32_FEATURE_CONTROL, old);
        if ((old & (FEATURE_CONTROL_LOCKED |
@@ -1159,6 +1147,10 @@ static void hardware_enable(void *garbage)
        asm volatile (ASM_VMX_VMXON_RAX
                      : : "a"(&phys_addr), "m"(phys_addr)
                      : "memory", "cc");
+
+       ept_sync_global();
+
+       return 0;
 }
 
 static void vmclear_local_vcpus(void)
@@ -1250,7 +1242,8 @@ static __init int setup_vmcs_config(struct vmcs_config *vmcs_conf)
                        SECONDARY_EXEC_WBINVD_EXITING |
                        SECONDARY_EXEC_ENABLE_VPID |
                        SECONDARY_EXEC_ENABLE_EPT |
-                       SECONDARY_EXEC_UNRESTRICTED_GUEST;
+                       SECONDARY_EXEC_UNRESTRICTED_GUEST |
+                       SECONDARY_EXEC_PAUSE_LOOP_EXITING;
                if (adjust_vmx_controls(min2, opt2,
                                        MSR_IA32_VMX_PROCBASED_CTLS2,
                                        &_cpu_based_2nd_exec_control) < 0)
@@ -1344,15 +1337,17 @@ static void free_kvm_area(void)
 {
        int cpu;
 
-       for_each_online_cpu(cpu)
+       for_each_possible_cpu(cpu) {
                free_vmcs(per_cpu(vmxarea, cpu));
+               per_cpu(vmxarea, cpu) = NULL;
+       }
 }
 
 static __init int alloc_kvm_area(void)
 {
        int cpu;
 
-       for_each_online_cpu(cpu) {
+       for_each_possible_cpu(cpu) {
                struct vmcs *vmcs;
 
                vmcs = alloc_vmcs_cpu(cpu);
@@ -1394,6 +1389,9 @@ static __init int hardware_setup(void)
        if (enable_ept && !cpu_has_vmx_ept_2m_page())
                kvm_disable_largepages();
 
+       if (!cpu_has_vmx_ple())
+               ple_gap = 0;
+
        return alloc_kvm_area();
 }
 
@@ -1536,8 +1534,16 @@ continue_rmode:
 static void vmx_set_efer(struct kvm_vcpu *vcpu, u64 efer)
 {
        struct vcpu_vmx *vmx = to_vmx(vcpu);
-       struct kvm_msr_entry *msr = find_msr_entry(vmx, MSR_EFER);
+       struct shared_msr_entry *msr = find_msr_entry(vmx, MSR_EFER);
+
+       if (!msr)
+               return;
 
+       /*
+        * Force kernel_gs_base reloading before EFER changes, as control
+        * of this msr depends on is_long_mode().
+        */
+       vmx_load_host_state(to_vmx(vcpu));
        vcpu->arch.shadow_efer = efer;
        if (!msr)
                return;
@@ -1727,6 +1733,7 @@ static void vmx_set_cr3(struct kvm_vcpu *vcpu, unsigned long cr3)
                vmcs_write64(EPT_POINTER, eptp);
                guest_cr3 = is_paging(vcpu) ? vcpu->arch.cr3 :
                        vcpu->kvm->arch.ept_identity_map_addr;
+               ept_load_pdptrs(vcpu);
        }
 
        vmx_flush_tlb(vcpu);
@@ -2302,13 +2309,22 @@ static int vmx_vcpu_setup(struct vcpu_vmx *vmx)
                                ~SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES;
                if (vmx->vpid == 0)
                        exec_control &= ~SECONDARY_EXEC_ENABLE_VPID;
-               if (!enable_ept)
+               if (!enable_ept) {
                        exec_control &= ~SECONDARY_EXEC_ENABLE_EPT;
+                       enable_unrestricted_guest = 0;
+               }
                if (!enable_unrestricted_guest)
                        exec_control &= ~SECONDARY_EXEC_UNRESTRICTED_GUEST;
+               if (!ple_gap)
+                       exec_control &= ~SECONDARY_EXEC_PAUSE_LOOP_EXITING;
                vmcs_write32(SECONDARY_VM_EXEC_CONTROL, exec_control);
        }
 
+       if (ple_gap) {
+               vmcs_write32(PLE_GAP, ple_gap);
+               vmcs_write32(PLE_WINDOW, ple_window);
+       }
+
        vmcs_write32(PAGE_FAULT_ERROR_CODE_MASK, !!bypass_guest_pf);
        vmcs_write32(PAGE_FAULT_ERROR_CODE_MATCH, !!bypass_guest_pf);
        vmcs_write32(CR3_TARGET_COUNT, 0);           /* 22.2.1 */
@@ -2376,10 +2392,9 @@ static int vmx_vcpu_setup(struct vcpu_vmx *vmx)
                if (wrmsr_safe(index, data_low, data_high) < 0)
                        continue;
                data = data_low | ((u64)data_high << 32);
-               vmx->host_msrs[j].index = index;
-               vmx->host_msrs[j].reserved = 0;
-               vmx->host_msrs[j].data = data;
-               vmx->guest_msrs[j] = vmx->host_msrs[j];
+               vmx->guest_msrs[j].index = i;
+               vmx->guest_msrs[j].data = 0;
+               vmx->guest_msrs[j].mask = -1ull;
                ++vmx->nmsrs;
        }
 
@@ -2510,7 +2525,7 @@ static int vmx_vcpu_reset(struct kvm_vcpu *vcpu)
        if (vmx->vpid != 0)
                vmcs_write16(VIRTUAL_PROCESSOR_ID, vmx->vpid);
 
-       vmx->vcpu.arch.cr0 = 0x60000010;
+       vmx->vcpu.arch.cr0 = X86_CR0_NW | X86_CR0_CD | X86_CR0_ET;
        vmx_set_cr0(&vmx->vcpu, vmx->vcpu.arch.cr0); /* enter rmode */
        vmx_set_cr4(&vmx->vcpu, 0);
        vmx_set_efer(&vmx->vcpu, 0);
@@ -2627,6 +2642,34 @@ static int vmx_nmi_allowed(struct kvm_vcpu *vcpu)
                                GUEST_INTR_STATE_NMI));
 }
 
+static bool vmx_get_nmi_mask(struct kvm_vcpu *vcpu)
+{
+       if (!cpu_has_virtual_nmis())
+               return to_vmx(vcpu)->soft_vnmi_blocked;
+       else
+               return !!(vmcs_read32(GUEST_INTERRUPTIBILITY_INFO) &
+                         GUEST_INTR_STATE_NMI);
+}
+
+static void vmx_set_nmi_mask(struct kvm_vcpu *vcpu, bool masked)
+{
+       struct vcpu_vmx *vmx = to_vmx(vcpu);
+
+       if (!cpu_has_virtual_nmis()) {
+               if (vmx->soft_vnmi_blocked != masked) {
+                       vmx->soft_vnmi_blocked = masked;
+                       vmx->vnmi_blocked_time = 0;
+               }
+       } else {
+               if (masked)
+                       vmcs_set_bits(GUEST_INTERRUPTIBILITY_INFO,
+                                     GUEST_INTR_STATE_NMI);
+               else
+                       vmcs_clear_bits(GUEST_INTERRUPTIBILITY_INFO,
+                                       GUEST_INTR_STATE_NMI);
+       }
+}
+
 static int vmx_interrupt_allowed(struct kvm_vcpu *vcpu)
 {
        return (vmcs_readl(GUEST_RFLAGS) & X86_EFLAGS_IF) &&
@@ -2659,7 +2702,7 @@ static int handle_rmode_exception(struct kvm_vcpu *vcpu,
         * Cause the #SS fault with 0 error code in VM86 mode.
         */
        if (((vec == GP_VECTOR) || (vec == SS_VECTOR)) && err_code == 0)
-               if (emulate_instruction(vcpu, NULL, 0, 0, 0) == EMULATE_DONE)
+               if (emulate_instruction(vcpu, 0, 0, 0) == EMULATE_DONE)
                        return 1;
        /*
         * Forward all other exceptions that are valid in real mode.
@@ -2710,15 +2753,16 @@ static void kvm_machine_check(void)
 #endif
 }
 
-static int handle_machine_check(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+static int handle_machine_check(struct kvm_vcpu *vcpu)
 {
        /* already handled by vcpu_run */
        return 1;
 }
 
-static int handle_exception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+static int handle_exception(struct kvm_vcpu *vcpu)
 {
        struct vcpu_vmx *vmx = to_vmx(vcpu);
+       struct kvm_run *kvm_run = vcpu->run;
        u32 intr_info, ex_no, error_code;
        unsigned long cr2, rip, dr6;
        u32 vect_info;
@@ -2728,12 +2772,17 @@ static int handle_exception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
        intr_info = vmcs_read32(VM_EXIT_INTR_INFO);
 
        if (is_machine_check(intr_info))
-               return handle_machine_check(vcpu, kvm_run);
+               return handle_machine_check(vcpu);
 
        if ((vect_info & VECTORING_INFO_VALID_MASK) &&
-                                               !is_page_fault(intr_info))
-               printk(KERN_ERR "%s: unexpected, vectoring info 0x%x "
-                      "intr info 0x%x\n", __func__, vect_info, intr_info);
+           !is_page_fault(intr_info)) {
+               vcpu->run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
+               vcpu->run->internal.suberror = KVM_INTERNAL_ERROR_SIMUL_EX;
+               vcpu->run->internal.ndata = 2;
+               vcpu->run->internal.data[0] = vect_info;
+               vcpu->run->internal.data[1] = intr_info;
+               return 0;
+       }
 
        if ((intr_info & INTR_INFO_INTR_TYPE_MASK) == INTR_TYPE_NMI_INTR)
                return 1;  /* already handled by vmx_vcpu_run() */
@@ -2744,7 +2793,7 @@ static int handle_exception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
        }
 
        if (is_invalid_opcode(intr_info)) {
-               er = emulate_instruction(vcpu, kvm_run, 0, 0, EMULTYPE_TRAP_UD);
+               er = emulate_instruction(vcpu, 0, 0, EMULTYPE_TRAP_UD);
                if (er != EMULATE_DONE)
                        kvm_queue_exception(vcpu, UD_VECTOR);
                return 1;
@@ -2803,20 +2852,19 @@ static int handle_exception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
        return 0;
 }
 
-static int handle_external_interrupt(struct kvm_vcpu *vcpu,
-                                    struct kvm_run *kvm_run)
+static int handle_external_interrupt(struct kvm_vcpu *vcpu)
 {
        ++vcpu->stat.irq_exits;
        return 1;
 }
 
-static int handle_triple_fault(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+static int handle_triple_fault(struct kvm_vcpu *vcpu)
 {
-       kvm_run->exit_reason = KVM_EXIT_SHUTDOWN;
+       vcpu->run->exit_reason = KVM_EXIT_SHUTDOWN;
        return 0;
 }
 
-static int handle_io(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+static int handle_io(struct kvm_vcpu *vcpu)
 {
        unsigned long exit_qualification;
        int size, in, string;
@@ -2827,8 +2875,7 @@ static int handle_io(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
        string = (exit_qualification & 16) != 0;
 
        if (string) {
-               if (emulate_instruction(vcpu,
-                                       kvm_run, 0, 0, 0) == EMULATE_DO_MMIO)
+               if (emulate_instruction(vcpu, 0, 0, 0) == EMULATE_DO_MMIO)
                        return 0;
                return 1;
        }
@@ -2838,7 +2885,7 @@ static int handle_io(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
        port = exit_qualification >> 16;
 
        skip_emulated_instruction(vcpu);
-       return kvm_emulate_pio(vcpu, kvm_run, in, size, port);
+       return kvm_emulate_pio(vcpu, in, size, port);
 }
 
 static void
@@ -2852,7 +2899,7 @@ vmx_patch_hypercall(struct kvm_vcpu *vcpu, unsigned char *hypercall)
        hypercall[2] = 0xc1;
 }
 
-static int handle_cr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+static int handle_cr(struct kvm_vcpu *vcpu)
 {
        unsigned long exit_qualification, val;
        int cr;
@@ -2887,7 +2934,7 @@ static int handle_cr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
                                        return 1;
                                if (cr8_prev <= cr8)
                                        return 1;
-                               kvm_run->exit_reason = KVM_EXIT_SET_TPR;
+                               vcpu->run->exit_reason = KVM_EXIT_SET_TPR;
                                return 0;
                        }
                };
@@ -2922,13 +2969,13 @@ static int handle_cr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
        default:
                break;
        }
-       kvm_run->exit_reason = 0;
+       vcpu->run->exit_reason = 0;
        pr_unimpl(vcpu, "unhandled control register: op %d cr %d\n",
               (int)(exit_qualification >> 4) & 3, cr);
        return 0;
 }
 
-static int handle_dr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+static int handle_dr(struct kvm_vcpu *vcpu)
 {
        unsigned long exit_qualification;
        unsigned long val;
@@ -2944,13 +2991,13 @@ static int handle_dr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
                 * guest debugging itself.
                 */
                if (vcpu->guest_debug & KVM_GUESTDBG_USE_HW_BP) {
-                       kvm_run->debug.arch.dr6 = vcpu->arch.dr6;
-                       kvm_run->debug.arch.dr7 = dr;
-                       kvm_run->debug.arch.pc =
+                       vcpu->run->debug.arch.dr6 = vcpu->arch.dr6;
+                       vcpu->run->debug.arch.dr7 = dr;
+                       vcpu->run->debug.arch.pc =
                                vmcs_readl(GUEST_CS_BASE) +
                                vmcs_readl(GUEST_RIP);
-                       kvm_run->debug.arch.exception = DB_VECTOR;
-                       kvm_run->exit_reason = KVM_EXIT_DEBUG;
+                       vcpu->run->debug.arch.exception = DB_VECTOR;
+                       vcpu->run->exit_reason = KVM_EXIT_DEBUG;
                        return 0;
                } else {
                        vcpu->arch.dr7 &= ~DR7_GD;
@@ -3016,13 +3063,13 @@ static int handle_dr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
        return 1;
 }
 
-static int handle_cpuid(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+static int handle_cpuid(struct kvm_vcpu *vcpu)
 {
        kvm_emulate_cpuid(vcpu);
        return 1;
 }
 
-static int handle_rdmsr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+static int handle_rdmsr(struct kvm_vcpu *vcpu)
 {
        u32 ecx = vcpu->arch.regs[VCPU_REGS_RCX];
        u64 data;
@@ -3041,7 +3088,7 @@ static int handle_rdmsr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
        return 1;
 }
 
-static int handle_wrmsr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+static int handle_wrmsr(struct kvm_vcpu *vcpu)
 {
        u32 ecx = vcpu->arch.regs[VCPU_REGS_RCX];
        u64 data = (vcpu->arch.regs[VCPU_REGS_RAX] & -1u)
@@ -3058,14 +3105,12 @@ static int handle_wrmsr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
        return 1;
 }
 
-static int handle_tpr_below_threshold(struct kvm_vcpu *vcpu,
-                                     struct kvm_run *kvm_run)
+static int handle_tpr_below_threshold(struct kvm_vcpu *vcpu)
 {
        return 1;
 }
 
-static int handle_interrupt_window(struct kvm_vcpu *vcpu,
-                                  struct kvm_run *kvm_run)
+static int handle_interrupt_window(struct kvm_vcpu *vcpu)
 {
        u32 cpu_based_vm_exec_control;
 
@@ -3081,34 +3126,34 @@ static int handle_interrupt_window(struct kvm_vcpu *vcpu,
         * possible
         */
        if (!irqchip_in_kernel(vcpu->kvm) &&
-           kvm_run->request_interrupt_window &&
+           vcpu->run->request_interrupt_window &&
            !kvm_cpu_has_interrupt(vcpu)) {
-               kvm_run->exit_reason = KVM_EXIT_IRQ_WINDOW_OPEN;
+               vcpu->run->exit_reason = KVM_EXIT_IRQ_WINDOW_OPEN;
                return 0;
        }
        return 1;
 }
 
-static int handle_halt(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+static int handle_halt(struct kvm_vcpu *vcpu)
 {
        skip_emulated_instruction(vcpu);
        return kvm_emulate_halt(vcpu);
 }
 
-static int handle_vmcall(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+static int handle_vmcall(struct kvm_vcpu *vcpu)
 {
        skip_emulated_instruction(vcpu);
        kvm_emulate_hypercall(vcpu);
        return 1;
 }
 
-static int handle_vmx_insn(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+static int handle_vmx_insn(struct kvm_vcpu *vcpu)
 {
        kvm_queue_exception(vcpu, UD_VECTOR);
        return 1;
 }
 
-static int handle_invlpg(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+static int handle_invlpg(struct kvm_vcpu *vcpu)
 {
        unsigned long exit_qualification = vmcs_readl(EXIT_QUALIFICATION);
 
@@ -3117,14 +3162,14 @@ static int handle_invlpg(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
        return 1;
 }
 
-static int handle_wbinvd(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+static int handle_wbinvd(struct kvm_vcpu *vcpu)
 {
        skip_emulated_instruction(vcpu);
        /* TODO: Add support for VT-d/pass-through device */
        return 1;
 }
 
-static int handle_apic_access(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+static int handle_apic_access(struct kvm_vcpu *vcpu)
 {
        unsigned long exit_qualification;
        enum emulation_result er;
@@ -3133,7 +3178,7 @@ static int handle_apic_access(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
        exit_qualification = vmcs_readl(EXIT_QUALIFICATION);
        offset = exit_qualification & 0xffful;
 
-       er = emulate_instruction(vcpu, kvm_run, 0, 0, 0);
+       er = emulate_instruction(vcpu, 0, 0, 0);
 
        if (er !=  EMULATE_DONE) {
                printk(KERN_ERR
@@ -3144,7 +3189,7 @@ static int handle_apic_access(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
        return 1;
 }
 
-static int handle_task_switch(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+static int handle_task_switch(struct kvm_vcpu *vcpu)
 {
        struct vcpu_vmx *vmx = to_vmx(vcpu);
        unsigned long exit_qualification;
@@ -3198,7 +3243,7 @@ static int handle_task_switch(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
        return 1;
 }
 
-static int handle_ept_violation(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+static int handle_ept_violation(struct kvm_vcpu *vcpu)
 {
        unsigned long exit_qualification;
        gpa_t gpa;
@@ -3219,8 +3264,8 @@ static int handle_ept_violation(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
                        vmcs_readl(GUEST_LINEAR_ADDRESS));
                printk(KERN_ERR "EPT: Exit qualification is 0x%lx\n",
                        (long unsigned int)exit_qualification);
-               kvm_run->exit_reason = KVM_EXIT_UNKNOWN;
-               kvm_run->hw.hardware_exit_reason = EXIT_REASON_EPT_VIOLATION;
+               vcpu->run->exit_reason = KVM_EXIT_UNKNOWN;
+               vcpu->run->hw.hardware_exit_reason = EXIT_REASON_EPT_VIOLATION;
                return 0;
        }
 
@@ -3290,7 +3335,7 @@ static void ept_misconfig_inspect_spte(struct kvm_vcpu *vcpu, u64 spte,
        }
 }
 
-static int handle_ept_misconfig(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+static int handle_ept_misconfig(struct kvm_vcpu *vcpu)
 {
        u64 sptes[4];
        int nr_sptes, i;
@@ -3306,13 +3351,13 @@ static int handle_ept_misconfig(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
        for (i = PT64_ROOT_LEVEL; i > PT64_ROOT_LEVEL - nr_sptes; --i)
                ept_misconfig_inspect_spte(vcpu, sptes[i-1], i);
 
-       kvm_run->exit_reason = KVM_EXIT_UNKNOWN;
-       kvm_run->hw.hardware_exit_reason = EXIT_REASON_EPT_MISCONFIG;
+       vcpu->run->exit_reason = KVM_EXIT_UNKNOWN;
+       vcpu->run->hw.hardware_exit_reason = EXIT_REASON_EPT_MISCONFIG;
 
        return 0;
 }
 
-static int handle_nmi_window(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+static int handle_nmi_window(struct kvm_vcpu *vcpu)
 {
        u32 cpu_based_vm_exec_control;
 
@@ -3325,36 +3370,50 @@ static int handle_nmi_window(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
        return 1;
 }
 
-static void handle_invalid_guest_state(struct kvm_vcpu *vcpu,
-                               struct kvm_run *kvm_run)
+static int handle_invalid_guest_state(struct kvm_vcpu *vcpu)
 {
        struct vcpu_vmx *vmx = to_vmx(vcpu);
        enum emulation_result err = EMULATE_DONE;
-
-       local_irq_enable();
-       preempt_enable();
+       int ret = 1;
 
        while (!guest_state_valid(vcpu)) {
-               err = emulate_instruction(vcpu, kvm_run, 0, 0, 0);
+               err = emulate_instruction(vcpu, 0, 0, 0);
 
-               if (err == EMULATE_DO_MMIO)
-                       break;
+               if (err == EMULATE_DO_MMIO) {
+                       ret = 0;
+                       goto out;
+               }
 
                if (err != EMULATE_DONE) {
                        kvm_report_emulation_failure(vcpu, "emulation failure");
-                       break;
+                       vcpu->run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
+                       vcpu->run->internal.suberror = KVM_INTERNAL_ERROR_EMULATION;
+                       vcpu->run->internal.ndata = 0;
+                       ret = 0;
+                       goto out;
                }
 
                if (signal_pending(current))
-                       break;
+                       goto out;
                if (need_resched())
                        schedule();
        }
 
-       preempt_disable();
-       local_irq_disable();
+       vmx->emulation_required = 0;
+out:
+       return ret;
+}
 
-       vmx->invalid_state_emulation_result = err;
+/*
+ * Indicate a busy-waiting vcpu in spinlock. We do not enable the PAUSE
+ * exiting, so only get here on cpu with PAUSE-Loop-Exiting.
+ */
+static int handle_pause(struct kvm_vcpu *vcpu)
+{
+       skip_emulated_instruction(vcpu);
+       kvm_vcpu_on_spin(vcpu);
+
+       return 1;
 }
 
 /*
@@ -3362,8 +3421,7 @@ static void handle_invalid_guest_state(struct kvm_vcpu *vcpu,
  * may resume.  Otherwise they set the kvm_run parameter to indicate what needs
  * to be done to userspace and return 0.
  */
-static int (*kvm_vmx_exit_handlers[])(struct kvm_vcpu *vcpu,
-                                     struct kvm_run *kvm_run) = {
+static int (*kvm_vmx_exit_handlers[])(struct kvm_vcpu *vcpu) = {
        [EXIT_REASON_EXCEPTION_NMI]           = handle_exception,
        [EXIT_REASON_EXTERNAL_INTERRUPT]      = handle_external_interrupt,
        [EXIT_REASON_TRIPLE_FAULT]            = handle_triple_fault,
@@ -3394,6 +3452,7 @@ static int (*kvm_vmx_exit_handlers[])(struct kvm_vcpu *vcpu,
        [EXIT_REASON_MCE_DURING_VMENTRY]      = handle_machine_check,
        [EXIT_REASON_EPT_VIOLATION]           = handle_ept_violation,
        [EXIT_REASON_EPT_MISCONFIG]           = handle_ept_misconfig,
+       [EXIT_REASON_PAUSE_INSTRUCTION]       = handle_pause,
 };
 
 static const int kvm_vmx_max_exit_handlers =
@@ -3403,7 +3462,7 @@ static const int kvm_vmx_max_exit_handlers =
  * The guest has exited.  See if we can fix it or if we need userspace
  * assistance.
  */
-static int vmx_handle_exit(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
+static int vmx_handle_exit(struct kvm_vcpu *vcpu)
 {
        struct vcpu_vmx *vmx = to_vmx(vcpu);
        u32 exit_reason = vmx->exit_reason;
@@ -3411,13 +3470,9 @@ static int vmx_handle_exit(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
 
        trace_kvm_exit(exit_reason, kvm_rip_read(vcpu));
 
-       /* If we need to emulate an MMIO from handle_invalid_guest_state
-        * we just return 0 */
-       if (vmx->emulation_required && emulate_invalid_guest_state) {
-               if (guest_state_valid(vcpu))
-                       vmx->emulation_required = 0;
-               return vmx->invalid_state_emulation_result != EMULATE_DO_MMIO;
-       }
+       /* If guest state is invalid, start emulating */
+       if (vmx->emulation_required && emulate_invalid_guest_state)
+               return handle_invalid_guest_state(vcpu);
 
        /* Access CR3 don't cause VMExit in paging mode, so we need
         * to sync with guest real CR3. */
@@ -3425,8 +3480,8 @@ static int vmx_handle_exit(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
                vcpu->arch.cr3 = vmcs_readl(GUEST_CR3);
 
        if (unlikely(vmx->fail)) {
-               kvm_run->exit_reason = KVM_EXIT_FAIL_ENTRY;
-               kvm_run->fail_entry.hardware_entry_failure_reason
+               vcpu->run->exit_reason = KVM_EXIT_FAIL_ENTRY;
+               vcpu->run->fail_entry.hardware_entry_failure_reason
                        = vmcs_read32(VM_INSTRUCTION_ERROR);
                return 0;
        }
@@ -3459,10 +3514,10 @@ static int vmx_handle_exit(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
 
        if (exit_reason < kvm_vmx_max_exit_handlers
            && kvm_vmx_exit_handlers[exit_reason])
-               return kvm_vmx_exit_handlers[exit_reason](vcpu, kvm_run);
+               return kvm_vmx_exit_handlers[exit_reason](vcpu);
        else {
-               kvm_run->exit_reason = KVM_EXIT_UNKNOWN;
-               kvm_run->hw.hardware_exit_reason = exit_reason;
+               vcpu->run->exit_reason = KVM_EXIT_UNKNOWN;
+               vcpu->run->hw.hardware_exit_reason = exit_reason;
        }
        return 0;
 }
@@ -3600,23 +3655,18 @@ static void fixup_rmode_irq(struct vcpu_vmx *vmx)
 #define Q "l"
 #endif
 
-static void vmx_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+static void vmx_vcpu_run(struct kvm_vcpu *vcpu)
 {
        struct vcpu_vmx *vmx = to_vmx(vcpu);
 
-       if (enable_ept && is_paging(vcpu)) {
-               vmcs_writel(GUEST_CR3, vcpu->arch.cr3);
-               ept_load_pdptrs(vcpu);
-       }
        /* Record the guest's net vcpu time for enforced NMI injections. */
        if (unlikely(!cpu_has_virtual_nmis() && vmx->soft_vnmi_blocked))
                vmx->entry_time = ktime_get();
 
-       /* Handle invalid guest state instead of entering VMX */
-       if (vmx->emulation_required && emulate_invalid_guest_state) {
-               handle_invalid_guest_state(vcpu, kvm_run);
+       /* Don't enter VMX if guest state is invalid, let the exit handler
+          start emulation until we arrive back to a valid state */
+       if (vmx->emulation_required && emulate_invalid_guest_state)
                return;
-       }
 
        if (test_bit(VCPU_REGS_RSP, (unsigned long *)&vcpu->arch.regs_dirty))
                vmcs_writel(GUEST_RSP, vcpu->arch.regs[VCPU_REGS_RSP]);
@@ -3775,7 +3825,6 @@ static void vmx_free_vcpu(struct kvm_vcpu *vcpu)
                __clear_bit(vmx->vpid, vmx_vpid_bitmap);
        spin_unlock(&vmx_vpid_lock);
        vmx_free_vmcs(vcpu);
-       kfree(vmx->host_msrs);
        kfree(vmx->guest_msrs);
        kvm_vcpu_uninit(vcpu);
        kmem_cache_free(kvm_vcpu_cache, vmx);
@@ -3802,10 +3851,6 @@ static struct kvm_vcpu *vmx_create_vcpu(struct kvm *kvm, unsigned int id)
                goto uninit_vcpu;
        }
 
-       vmx->host_msrs = kmalloc(PAGE_SIZE, GFP_KERNEL);
-       if (!vmx->host_msrs)
-               goto free_guest_msrs;
-
        vmx->vmcs = alloc_vmcs();
        if (!vmx->vmcs)
                goto free_msrs;
@@ -3836,8 +3881,6 @@ static struct kvm_vcpu *vmx_create_vcpu(struct kvm *kvm, unsigned int id)
 free_vmcs:
        free_vmcs(vmx->vmcs);
 free_msrs:
-       kfree(vmx->host_msrs);
-free_guest_msrs:
        kfree(vmx->guest_msrs);
 uninit_vcpu:
        kvm_vcpu_uninit(&vmx->vcpu);
@@ -3973,6 +4016,8 @@ static struct kvm_x86_ops vmx_x86_ops = {
        .queue_exception = vmx_queue_exception,
        .interrupt_allowed = vmx_interrupt_allowed,
        .nmi_allowed = vmx_nmi_allowed,
+       .get_nmi_mask = vmx_get_nmi_mask,
+       .set_nmi_mask = vmx_set_nmi_mask,
        .enable_nmi_window = enable_nmi_window,
        .enable_irq_window = enable_irq_window,
        .update_cr8_intercept = update_cr8_intercept,
@@ -3987,7 +4032,12 @@ static struct kvm_x86_ops vmx_x86_ops = {
 
 static int __init vmx_init(void)
 {
-       int r;
+       int r, i;
+
+       rdmsrl_safe(MSR_EFER, &host_efer);
+
+       for (i = 0; i < NR_VMX_MSR; ++i)
+               kvm_define_shared_msr(i, vmx_msr_index[i]);
 
        vmx_io_bitmap_a = (unsigned long *)__get_free_page(GFP_KERNEL);
        if (!vmx_io_bitmap_a)
@@ -4049,8 +4099,6 @@ static int __init vmx_init(void)
        if (bypass_guest_pf)
                kvm_mmu_set_nonpresent_ptes(~0xffeull, 0ull);
 
-       ept_sync_global();
-
        return 0;
 
 out3:
index ae07d26..9d06896 100644 (file)
 #include <linux/iommu.h>
 #include <linux/intel-iommu.h>
 #include <linux/cpufreq.h>
+#include <linux/user-return-notifier.h>
 #include <trace/events/kvm.h>
 #undef TRACE_INCLUDE_FILE
 #define CREATE_TRACE_POINTS
 #include "trace.h"
 
+#include <asm/debugreg.h>
 #include <asm/uaccess.h>
 #include <asm/msr.h>
 #include <asm/desc.h>
@@ -87,6 +89,25 @@ EXPORT_SYMBOL_GPL(kvm_x86_ops);
 int ignore_msrs = 0;
 module_param_named(ignore_msrs, ignore_msrs, bool, S_IRUGO | S_IWUSR);
 
+#define KVM_NR_SHARED_MSRS 16
+
+struct kvm_shared_msrs_global {
+       int nr;
+       struct kvm_shared_msr {
+               u32 msr;
+               u64 value;
+       } msrs[KVM_NR_SHARED_MSRS];
+};
+
+struct kvm_shared_msrs {
+       struct user_return_notifier urn;
+       bool registered;
+       u64 current_value[KVM_NR_SHARED_MSRS];
+};
+
+static struct kvm_shared_msrs_global __read_mostly shared_msrs_global;
+static DEFINE_PER_CPU(struct kvm_shared_msrs, shared_msrs);
+
 struct kvm_stats_debugfs_item debugfs_entries[] = {
        { "pf_fixed", VCPU_STAT(pf_fixed) },
        { "pf_guest", VCPU_STAT(pf_guest) },
@@ -123,6 +144,72 @@ struct kvm_stats_debugfs_item debugfs_entries[] = {
        { NULL }
 };
 
+static void kvm_on_user_return(struct user_return_notifier *urn)
+{
+       unsigned slot;
+       struct kvm_shared_msr *global;
+       struct kvm_shared_msrs *locals
+               = container_of(urn, struct kvm_shared_msrs, urn);
+
+       for (slot = 0; slot < shared_msrs_global.nr; ++slot) {
+               global = &shared_msrs_global.msrs[slot];
+               if (global->value != locals->current_value[slot]) {
+                       wrmsrl(global->msr, global->value);
+                       locals->current_value[slot] = global->value;
+               }
+       }
+       locals->registered = false;
+       user_return_notifier_unregister(urn);
+}
+
+void kvm_define_shared_msr(unsigned slot, u32 msr)
+{
+       int cpu;
+       u64 value;
+
+       if (slot >= shared_msrs_global.nr)
+               shared_msrs_global.nr = slot + 1;
+       shared_msrs_global.msrs[slot].msr = msr;
+       rdmsrl_safe(msr, &value);
+       shared_msrs_global.msrs[slot].value = value;
+       for_each_online_cpu(cpu)
+               per_cpu(shared_msrs, cpu).current_value[slot] = value;
+}
+EXPORT_SYMBOL_GPL(kvm_define_shared_msr);
+
+static void kvm_shared_msr_cpu_online(void)
+{
+       unsigned i;
+       struct kvm_shared_msrs *locals = &__get_cpu_var(shared_msrs);
+
+       for (i = 0; i < shared_msrs_global.nr; ++i)
+               locals->current_value[i] = shared_msrs_global.msrs[i].value;
+}
+
+void kvm_set_shared_msr(unsigned slot, u64 value, u64 mask)
+{
+       struct kvm_shared_msrs *smsr = &__get_cpu_var(shared_msrs);
+
+       if (((value ^ smsr->current_value[slot]) & mask) == 0)
+               return;
+       smsr->current_value[slot] = value;
+       wrmsrl(shared_msrs_global.msrs[slot].msr, value);
+       if (!smsr->registered) {
+               smsr->urn.on_user_return = kvm_on_user_return;
+               user_return_notifier_register(&smsr->urn);
+               smsr->registered = true;
+       }
+}
+EXPORT_SYMBOL_GPL(kvm_set_shared_msr);
+
+static void drop_user_return_notifiers(void *ignore)
+{
+       struct kvm_shared_msrs *smsr = &__get_cpu_var(shared_msrs);
+
+       if (smsr->registered)
+               kvm_on_user_return(&smsr->urn);
+}
+
 unsigned long segment_base(u16 selector)
 {
        struct descriptor_table gdt;
@@ -484,16 +571,19 @@ static inline u32 bit(int bitno)
  * and KVM_SET_MSRS, and KVM_GET_MSR_INDEX_LIST.
  *
  * This list is modified at module load time to reflect the
- * capabilities of the host cpu.
+ * capabilities of the host cpu. This capabilities test skips MSRs that are
+ * kvm-specific. Those are put in the beginning of the list.
  */
+
+#define KVM_SAVE_MSRS_BEGIN    2
 static u32 msrs_to_save[] = {
+       MSR_KVM_SYSTEM_TIME, MSR_KVM_WALL_CLOCK,
        MSR_IA32_SYSENTER_CS, MSR_IA32_SYSENTER_ESP, MSR_IA32_SYSENTER_EIP,
        MSR_K6_STAR,
 #ifdef CONFIG_X86_64
        MSR_CSTAR, MSR_KERNEL_GS_BASE, MSR_SYSCALL_MASK, MSR_LSTAR,
 #endif
-       MSR_IA32_TSC, MSR_KVM_SYSTEM_TIME, MSR_KVM_WALL_CLOCK,
-       MSR_IA32_PERF_STATUS, MSR_IA32_CR_PAT, MSR_VM_HSAVE_PA
+       MSR_IA32_TSC, MSR_IA32_PERF_STATUS, MSR_IA32_CR_PAT, MSR_VM_HSAVE_PA
 };
 
 static unsigned num_msrs_to_save;
@@ -677,7 +767,8 @@ static void kvm_write_guest_time(struct kvm_vcpu *v)
        /* With all the info we got, fill in the values */
 
        vcpu->hv_clock.system_time = ts.tv_nsec +
-                                    (NSEC_PER_SEC * (u64)ts.tv_sec);
+                                    (NSEC_PER_SEC * (u64)ts.tv_sec) + v->kvm->arch.kvmclock_offset;
+
        /*
         * The interface expects us to write an even number signaling that the
         * update is finished. Since the guest won't see the intermediate
@@ -835,6 +926,38 @@ static int set_msr_mce(struct kvm_vcpu *vcpu, u32 msr, u64 data)
        return 0;
 }
 
+static int xen_hvm_config(struct kvm_vcpu *vcpu, u64 data)
+{
+       struct kvm *kvm = vcpu->kvm;
+       int lm = is_long_mode(vcpu);
+       u8 *blob_addr = lm ? (u8 *)(long)kvm->arch.xen_hvm_config.blob_addr_64
+               : (u8 *)(long)kvm->arch.xen_hvm_config.blob_addr_32;
+       u8 blob_size = lm ? kvm->arch.xen_hvm_config.blob_size_64
+               : kvm->arch.xen_hvm_config.blob_size_32;
+       u32 page_num = data & ~PAGE_MASK;
+       u64 page_addr = data & PAGE_MASK;
+       u8 *page;
+       int r;
+
+       r = -E2BIG;
+       if (page_num >= blob_size)
+               goto out;
+       r = -ENOMEM;
+       page = kzalloc(PAGE_SIZE, GFP_KERNEL);
+       if (!page)
+               goto out;
+       r = -EFAULT;
+       if (copy_from_user(page, blob_addr + (page_num * PAGE_SIZE), PAGE_SIZE))
+               goto out_free;
+       if (kvm_write_guest(kvm, page_addr, page, PAGE_SIZE))
+               goto out_free;
+       r = 0;
+out_free:
+       kfree(page);
+out:
+       return r;
+}
+
 int kvm_set_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 data)
 {
        switch (msr) {
@@ -950,6 +1073,8 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 data)
                        "0x%x data 0x%llx\n", msr, data);
                break;
        default:
+               if (msr && (msr == vcpu->kvm->arch.xen_hvm_config.msr))
+                       return xen_hvm_config(vcpu, data);
                if (!ignore_msrs) {
                        pr_unimpl(vcpu, "unhandled wrmsr: 0x%x data %llx\n",
                                msr, data);
@@ -1224,6 +1349,9 @@ int kvm_dev_ioctl_check_extension(long ext)
        case KVM_CAP_PIT2:
        case KVM_CAP_PIT_STATE2:
        case KVM_CAP_SET_IDENTITY_MAP_ADDR:
+       case KVM_CAP_XEN_HVM:
+       case KVM_CAP_ADJUST_CLOCK:
+       case KVM_CAP_VCPU_EVENTS:
                r = 1;
                break;
        case KVM_CAP_COALESCED_MMIO:
@@ -1238,8 +1366,8 @@ int kvm_dev_ioctl_check_extension(long ext)
        case KVM_CAP_NR_MEMSLOTS:
                r = KVM_MEMORY_SLOTS;
                break;
-       case KVM_CAP_PV_MMU:
-               r = !tdp_enabled;
+       case KVM_CAP_PV_MMU:    /* obsolete */
+               r = 0;
                break;
        case KVM_CAP_IOMMU:
                r = iommu_found();
@@ -1326,6 +1454,12 @@ out:
 void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
 {
        kvm_x86_ops->vcpu_load(vcpu, cpu);
+       if (unlikely(per_cpu(cpu_tsc_khz, cpu) == 0)) {
+               unsigned long khz = cpufreq_quick_get(cpu);
+               if (!khz)
+                       khz = tsc_khz;
+               per_cpu(cpu_tsc_khz, cpu) = khz;
+       }
        kvm_request_guest_time_update(vcpu);
 }
 
@@ -1759,6 +1893,61 @@ static int kvm_vcpu_ioctl_x86_set_mce(struct kvm_vcpu *vcpu,
        return 0;
 }
 
+static void kvm_vcpu_ioctl_x86_get_vcpu_events(struct kvm_vcpu *vcpu,
+                                              struct kvm_vcpu_events *events)
+{
+       vcpu_load(vcpu);
+
+       events->exception.injected = vcpu->arch.exception.pending;
+       events->exception.nr = vcpu->arch.exception.nr;
+       events->exception.has_error_code = vcpu->arch.exception.has_error_code;
+       events->exception.error_code = vcpu->arch.exception.error_code;
+
+       events->interrupt.injected = vcpu->arch.interrupt.pending;
+       events->interrupt.nr = vcpu->arch.interrupt.nr;
+       events->interrupt.soft = vcpu->arch.interrupt.soft;
+
+       events->nmi.injected = vcpu->arch.nmi_injected;
+       events->nmi.pending = vcpu->arch.nmi_pending;
+       events->nmi.masked = kvm_x86_ops->get_nmi_mask(vcpu);
+
+       events->sipi_vector = vcpu->arch.sipi_vector;
+
+       events->flags = 0;
+
+       vcpu_put(vcpu);
+}
+
+static int kvm_vcpu_ioctl_x86_set_vcpu_events(struct kvm_vcpu *vcpu,
+                                             struct kvm_vcpu_events *events)
+{
+       if (events->flags)
+               return -EINVAL;
+
+       vcpu_load(vcpu);
+
+       vcpu->arch.exception.pending = events->exception.injected;
+       vcpu->arch.exception.nr = events->exception.nr;
+       vcpu->arch.exception.has_error_code = events->exception.has_error_code;
+       vcpu->arch.exception.error_code = events->exception.error_code;
+
+       vcpu->arch.interrupt.pending = events->interrupt.injected;
+       vcpu->arch.interrupt.nr = events->interrupt.nr;
+       vcpu->arch.interrupt.soft = events->interrupt.soft;
+       if (vcpu->arch.interrupt.pending && irqchip_in_kernel(vcpu->kvm))
+               kvm_pic_clear_isr_ack(vcpu->kvm);
+
+       vcpu->arch.nmi_injected = events->nmi.injected;
+       vcpu->arch.nmi_pending = events->nmi.pending;
+       kvm_x86_ops->set_nmi_mask(vcpu, events->nmi.masked);
+
+       vcpu->arch.sipi_vector = events->sipi_vector;
+
+       vcpu_put(vcpu);
+
+       return 0;
+}
+
 long kvm_arch_vcpu_ioctl(struct file *filp,
                         unsigned int ioctl, unsigned long arg)
 {
@@ -1769,6 +1958,9 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
 
        switch (ioctl) {
        case KVM_GET_LAPIC: {
+               r = -EINVAL;
+               if (!vcpu->arch.apic)
+                       goto out;
                lapic = kzalloc(sizeof(struct kvm_lapic_state), GFP_KERNEL);
 
                r = -ENOMEM;
@@ -1784,6 +1976,9 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
                break;
        }
        case KVM_SET_LAPIC: {
+               r = -EINVAL;
+               if (!vcpu->arch.apic)
+                       goto out;
                lapic = kmalloc(sizeof(struct kvm_lapic_state), GFP_KERNEL);
                r = -ENOMEM;
                if (!lapic)
@@ -1910,6 +2105,27 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
                r = kvm_vcpu_ioctl_x86_set_mce(vcpu, &mce);
                break;
        }
+       case KVM_GET_VCPU_EVENTS: {
+               struct kvm_vcpu_events events;
+
+               kvm_vcpu_ioctl_x86_get_vcpu_events(vcpu, &events);
+
+               r = -EFAULT;
+               if (copy_to_user(argp, &events, sizeof(struct kvm_vcpu_events)))
+                       break;
+               r = 0;
+               break;
+       }
+       case KVM_SET_VCPU_EVENTS: {
+               struct kvm_vcpu_events events;
+
+               r = -EFAULT;
+               if (copy_from_user(&events, argp, sizeof(struct kvm_vcpu_events)))
+                       break;
+
+               r = kvm_vcpu_ioctl_x86_set_vcpu_events(vcpu, &events);
+               break;
+       }
        default:
                r = -EINVAL;
        }
@@ -2038,9 +2254,7 @@ static int kvm_vm_ioctl_get_irqchip(struct kvm *kvm, struct kvm_irqchip *chip)
                        sizeof(struct kvm_pic_state));
                break;
        case KVM_IRQCHIP_IOAPIC:
-               memcpy(&chip->chip.ioapic,
-                       ioapic_irqchip(kvm),
-                       sizeof(struct kvm_ioapic_state));
+               r = kvm_get_ioapic(kvm, &chip->chip.ioapic);
                break;
        default:
                r = -EINVAL;
@@ -2070,11 +2284,7 @@ static int kvm_vm_ioctl_set_irqchip(struct kvm *kvm, struct kvm_irqchip *chip)
                spin_unlock(&pic_irqchip(kvm)->lock);
                break;
        case KVM_IRQCHIP_IOAPIC:
-               mutex_lock(&kvm->irq_lock);
-               memcpy(ioapic_irqchip(kvm),
-                       &chip->chip.ioapic,
-                       sizeof(struct kvm_ioapic_state));
-               mutex_unlock(&kvm->irq_lock);
+               r = kvm_set_ioapic(kvm, &chip->chip.ioapic);
                break;
        default:
                r = -EINVAL;
@@ -2182,7 +2392,7 @@ long kvm_arch_vm_ioctl(struct file *filp,
 {
        struct kvm *kvm = filp->private_data;
        void __user *argp = (void __user *)arg;
-       int r = -EINVAL;
+       int r = -ENOTTY;
        /*
         * This union makes it completely explicit to gcc-3.x
         * that these two variables' stack usage should be
@@ -2244,25 +2454,39 @@ long kvm_arch_vm_ioctl(struct file *filp,
                if (r)
                        goto out;
                break;
-       case KVM_CREATE_IRQCHIP:
+       case KVM_CREATE_IRQCHIP: {
+               struct kvm_pic *vpic;
+
+               mutex_lock(&kvm->lock);
+               r = -EEXIST;
+               if (kvm->arch.vpic)
+                       goto create_irqchip_unlock;
                r = -ENOMEM;
-               kvm->arch.vpic = kvm_create_pic(kvm);
-               if (kvm->arch.vpic) {
+               vpic = kvm_create_pic(kvm);
+               if (vpic) {
                        r = kvm_ioapic_init(kvm);
                        if (r) {
-                               kfree(kvm->arch.vpic);
-                               kvm->arch.vpic = NULL;
-                               goto out;
+                               kfree(vpic);
+                               goto create_irqchip_unlock;
                        }
                } else
-                       goto out;
+                       goto create_irqchip_unlock;
+               smp_wmb();
+               kvm->arch.vpic = vpic;
+               smp_wmb();
                r = kvm_setup_default_irq_routing(kvm);
                if (r) {
+                       mutex_lock(&kvm->irq_lock);
                        kfree(kvm->arch.vpic);
                        kfree(kvm->arch.vioapic);
-                       goto out;
+                       kvm->arch.vpic = NULL;
+                       kvm->arch.vioapic = NULL;
+                       mutex_unlock(&kvm->irq_lock);
                }
+       create_irqchip_unlock:
+               mutex_unlock(&kvm->lock);
                break;
+       }
        case KVM_CREATE_PIT:
                u.pit_config.flags = KVM_PIT_SPEAKER_DUMMY;
                goto create_pit;
@@ -2292,10 +2516,8 @@ long kvm_arch_vm_ioctl(struct file *filp,
                        goto out;
                if (irqchip_in_kernel(kvm)) {
                        __s32 status;
-                       mutex_lock(&kvm->irq_lock);
                        status = kvm_set_irq(kvm, KVM_USERSPACE_IRQ_SOURCE_ID,
                                        irq_event.irq, irq_event.level);
-                       mutex_unlock(&kvm->irq_lock);
                        if (ioctl == KVM_IRQ_LINE_STATUS) {
                                irq_event.status = status;
                                if (copy_to_user(argp, &irq_event,
@@ -2421,6 +2643,55 @@ long kvm_arch_vm_ioctl(struct file *filp,
                r = 0;
                break;
        }
+       case KVM_XEN_HVM_CONFIG: {
+               r = -EFAULT;
+               if (copy_from_user(&kvm->arch.xen_hvm_config, argp,
+                                  sizeof(struct kvm_xen_hvm_config)))
+                       goto out;
+               r = -EINVAL;
+               if (kvm->arch.xen_hvm_config.flags)
+                       goto out;
+               r = 0;
+               break;
+       }
+       case KVM_SET_CLOCK: {
+               struct timespec now;
+               struct kvm_clock_data user_ns;
+               u64 now_ns;
+               s64 delta;
+
+               r = -EFAULT;
+               if (copy_from_user(&user_ns, argp, sizeof(user_ns)))
+                       goto out;
+
+               r = -EINVAL;
+               if (user_ns.flags)
+                       goto out;
+
+               r = 0;
+               ktime_get_ts(&now);
+               now_ns = timespec_to_ns(&now);
+               delta = user_ns.clock - now_ns;
+               kvm->arch.kvmclock_offset = delta;
+               break;
+       }
+       case KVM_GET_CLOCK: {
+               struct timespec now;
+               struct kvm_clock_data user_ns;
+               u64 now_ns;
+
+               ktime_get_ts(&now);
+               now_ns = timespec_to_ns(&now);
+               user_ns.clock = kvm->arch.kvmclock_offset + now_ns;
+               user_ns.flags = 0;
+
+               r = -EFAULT;
+               if (copy_to_user(argp, &user_ns, sizeof(user_ns)))
+                       goto out;
+               r = 0;
+               break;
+       }
+
        default:
                ;
        }
@@ -2433,7 +2704,8 @@ static void kvm_init_msr_list(void)
        u32 dummy[2];
        unsigned i, j;
 
-       for (i = j = 0; i < ARRAY_SIZE(msrs_to_save); i++) {
+       /* skip the first msrs in the list. KVM-specific */
+       for (i = j = KVM_SAVE_MSRS_BEGIN; i < ARRAY_SIZE(msrs_to_save); i++) {
                if (rdmsr_safe(msrs_to_save[i], &dummy[0], &dummy[1]) < 0)
                        continue;
                if (j < i)
@@ -2757,13 +3029,13 @@ static void cache_all_regs(struct kvm_vcpu *vcpu)
 }
 
 int emulate_instruction(struct kvm_vcpu *vcpu,
-                       struct kvm_run *run,
                        unsigned long cr2,
                        u16 error_code,
                        int emulation_type)
 {
        int r, shadow_mask;
        struct decode_cache *c;
+       struct kvm_run *run = vcpu->run;
 
        kvm_clear_exception_queue(vcpu);
        vcpu->arch.mmio_fault_cr2 = cr2;
@@ -2783,7 +3055,7 @@ int emulate_instruction(struct kvm_vcpu *vcpu,
                kvm_x86_ops->get_cs_db_l_bits(vcpu, &cs_db, &cs_l);
 
                vcpu->arch.emulate_ctxt.vcpu = vcpu;
-               vcpu->arch.emulate_ctxt.eflags = kvm_x86_ops->get_rflags(vcpu);
+               vcpu->arch.emulate_ctxt.eflags = kvm_get_rflags(vcpu);
                vcpu->arch.emulate_ctxt.mode =
                        (vcpu->arch.emulate_ctxt.eflags & X86_EFLAGS_VM)
                        ? X86EMUL_MODE_REAL : cs_l
@@ -2861,7 +3133,7 @@ int emulate_instruction(struct kvm_vcpu *vcpu,
                return EMULATE_DO_MMIO;
        }
 
-       kvm_x86_ops->set_rflags(vcpu, vcpu->arch.emulate_ctxt.eflags);
+       kvm_set_rflags(vcpu, vcpu->arch.emulate_ctxt.eflags);
 
        if (vcpu->mmio_is_write) {
                vcpu->mmio_needed = 0;
@@ -2969,8 +3241,7 @@ static int pio_string_write(struct kvm_vcpu *vcpu)
        return r;
 }
 
-int kvm_emulate_pio(struct kvm_vcpu *vcpu, struct kvm_run *run, int in,
-                 int size, unsigned port)
+int kvm_emulate_pio(struct kvm_vcpu *vcpu, int in, int size, unsigned port)
 {
        unsigned long val;
 
@@ -2999,7 +3270,7 @@ int kvm_emulate_pio(struct kvm_vcpu *vcpu, struct kvm_run *run, int in,
 }
 EXPORT_SYMBOL_GPL(kvm_emulate_pio);
 
-int kvm_emulate_pio_string(struct kvm_vcpu *vcpu, struct kvm_run *run, int in,
+int kvm_emulate_pio_string(struct kvm_vcpu *vcpu, int in,
                  int size, unsigned long count, int down,
                  gva_t address, int rep, unsigned port)
 {
@@ -3072,9 +3343,6 @@ static void bounce_off(void *info)
        /* nothing */
 }
 
-static unsigned int  ref_freq;
-static unsigned long tsc_khz_ref;
-
 static int kvmclock_cpufreq_notifier(struct notifier_block *nb, unsigned long val,
                                     void *data)
 {
@@ -3083,14 +3351,11 @@ static int kvmclock_cpufreq_notifier(struct notifier_block *nb, unsigned long va
        struct kvm_vcpu *vcpu;
        int i, send_ipi = 0;
 
-       if (!ref_freq)
-               ref_freq = freq->old;
-
        if (val == CPUFREQ_PRECHANGE && freq->old > freq->new)
                return 0;
        if (val == CPUFREQ_POSTCHANGE && freq->old < freq->new)
                return 0;
-       per_cpu(cpu_tsc_khz, freq->cpu) = cpufreq_scale(tsc_khz_ref, ref_freq, freq->new);
+       per_cpu(cpu_tsc_khz, freq->cpu) = freq->new;
 
        spin_lock(&kvm_lock);
        list_for_each_entry(kvm, &vm_list, vm_list) {
@@ -3127,9 +3392,28 @@ static struct notifier_block kvmclock_cpufreq_notifier_block = {
         .notifier_call  = kvmclock_cpufreq_notifier
 };
 
+static void kvm_timer_init(void)
+{
+       int cpu;
+
+       if (!boot_cpu_has(X86_FEATURE_CONSTANT_TSC)) {
+               cpufreq_register_notifier(&kvmclock_cpufreq_notifier_block,
+                                         CPUFREQ_TRANSITION_NOTIFIER);
+               for_each_online_cpu(cpu) {
+                       unsigned long khz = cpufreq_get(cpu);
+                       if (!khz)
+                               khz = tsc_khz;
+                       per_cpu(cpu_tsc_khz, cpu) = khz;
+               }
+       } else {
+               for_each_possible_cpu(cpu)
+                       per_cpu(cpu_tsc_khz, cpu) = tsc_khz;
+       }
+}
+
 int kvm_arch_init(void *opaque)
 {
-       int r, cpu;
+       int r;
        struct kvm_x86_ops *ops = (struct kvm_x86_ops *)opaque;
 
        if (kvm_x86_ops) {
@@ -3161,13 +3445,7 @@ int kvm_arch_init(void *opaque)
        kvm_mmu_set_mask_ptes(PT_USER_MASK, PT_ACCESSED_MASK,
                        PT_DIRTY_MASK, PT64_NX_MASK, 0);
 
-       for_each_possible_cpu(cpu)
-               per_cpu(cpu_tsc_khz, cpu) = tsc_khz;
-       if (!boot_cpu_has(X86_FEATURE_CONSTANT_TSC)) {
-               tsc_khz_ref = tsc_khz;
-               cpufreq_register_notifier(&kvmclock_cpufreq_notifier_block,
-                                         CPUFREQ_TRANSITION_NOTIFIER);
-       }
+       kvm_timer_init();
 
        return 0;
 
@@ -3295,7 +3573,7 @@ void realmode_lmsw(struct kvm_vcpu *vcpu, unsigned long msw,
                   unsigned long *rflags)
 {
        kvm_lmsw(vcpu, msw);
-       *rflags = kvm_x86_ops->get_rflags(vcpu);
+       *rflags = kvm_get_rflags(vcpu);
 }
 
 unsigned long realmode_get_cr(struct kvm_vcpu *vcpu, int cr)
@@ -3333,7 +3611,7 @@ void realmode_set_cr(struct kvm_vcpu *vcpu, int cr, unsigned long val,
        switch (cr) {
        case 0:
                kvm_set_cr0(vcpu, mk_cr_64(vcpu->arch.cr0, val));
-               *rflags = kvm_x86_ops->get_rflags(vcpu);
+               *rflags = kvm_get_rflags(vcpu);
                break;
        case 2:
                vcpu->arch.cr2 = val;
@@ -3453,18 +3731,18 @@ EXPORT_SYMBOL_GPL(kvm_emulate_cpuid);
  *
  * No need to exit to userspace if we already have an interrupt queued.
  */
-static int dm_request_for_irq_injection(struct kvm_vcpu *vcpu,
-                                         struct kvm_run *kvm_run)
+static int dm_request_for_irq_injection(struct kvm_vcpu *vcpu)
 {
        return (!irqchip_in_kernel(vcpu->kvm) && !kvm_cpu_has_interrupt(vcpu) &&
-               kvm_run->request_interrupt_window &&
+               vcpu->run->request_interrupt_window &&
                kvm_arch_interrupt_allowed(vcpu));
 }
 
-static void post_kvm_run_save(struct kvm_vcpu *vcpu,
-                             struct kvm_run *kvm_run)
+static void post_kvm_run_save(struct kvm_vcpu *vcpu)
 {
-       kvm_run->if_flag = (kvm_x86_ops->get_rflags(vcpu) & X86_EFLAGS_IF) != 0;
+       struct kvm_run *kvm_run = vcpu->run;
+
+       kvm_run->if_flag = (kvm_get_rflags(vcpu) & X86_EFLAGS_IF) != 0;
        kvm_run->cr8 = kvm_get_cr8(vcpu);
        kvm_run->apic_base = kvm_get_apic_base(vcpu);
        if (irqchip_in_kernel(vcpu->kvm))
@@ -3525,7 +3803,7 @@ static void update_cr8_intercept(struct kvm_vcpu *vcpu)
        kvm_x86_ops->update_cr8_intercept(vcpu, tpr, max_irr);
 }
 
-static void inject_pending_event(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+static void inject_pending_event(struct kvm_vcpu *vcpu)
 {
        /* try to reinject previous events if any */
        if (vcpu->arch.exception.pending) {
@@ -3561,11 +3839,11 @@ static void inject_pending_event(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
        }
 }
 
-static int vcpu_enter_guest(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
 {
        int r;
        bool req_int_win = !irqchip_in_kernel(vcpu->kvm) &&
-               kvm_run->request_interrupt_window;
+               vcpu->run->request_interrupt_window;
 
        if (vcpu->requests)
                if (test_and_clear_bit(KVM_REQ_MMU_RELOAD, &vcpu->requests))
@@ -3586,12 +3864,12 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
                        kvm_x86_ops->tlb_flush(vcpu);
                if (test_and_clear_bit(KVM_REQ_REPORT_TPR_ACCESS,
                                       &vcpu->requests)) {
-                       kvm_run->exit_reason = KVM_EXIT_TPR_ACCESS;
+                       vcpu->run->exit_reason = KVM_EXIT_TPR_ACCESS;
                        r = 0;
                        goto out;
                }
                if (test_and_clear_bit(KVM_REQ_TRIPLE_FAULT, &vcpu->requests)) {
-                       kvm_run->exit_reason = KVM_EXIT_SHUTDOWN;
+                       vcpu->run->exit_reason = KVM_EXIT_SHUTDOWN;
                        r = 0;
                        goto out;
                }
@@ -3615,7 +3893,7 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
                goto out;
        }
 
-       inject_pending_event(vcpu, kvm_run);
+       inject_pending_event(vcpu);
 
        /* enable NMI/IRQ window open exits if needed */
        if (vcpu->arch.nmi_pending)
@@ -3641,16 +3919,17 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
        }
 
        trace_kvm_entry(vcpu->vcpu_id);
-       kvm_x86_ops->run(vcpu, kvm_run);
+       kvm_x86_ops->run(vcpu);
 
-       if (unlikely(vcpu->arch.switch_db_regs || test_thread_flag(TIF_DEBUG))) {
-               set_debugreg(current->thread.debugreg0, 0);
-               set_debugreg(current->thread.debugreg1, 1);
-               set_debugreg(current->thread.debugreg2, 2);
-               set_debugreg(current->thread.debugreg3, 3);
-               set_debugreg(current->thread.debugreg6, 6);
-               set_debugreg(current->thread.debugreg7, 7);
-       }
+       /*
+        * If the guest has used debug registers, at least dr7
+        * will be disabled while returning to the host.
+        * If we don't have active breakpoints in the host, we don't
+        * care about the messed up debug address registers. But if
+        * we have some of them active, restore the old state.
+        */
+       if (hw_breakpoint_active())
+               hw_breakpoint_restore();
 
        set_bit(KVM_REQ_KICK, &vcpu->requests);
        local_irq_enable();
@@ -3682,13 +3961,13 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
 
        kvm_lapic_sync_from_vapic(vcpu);
 
-       r = kvm_x86_ops->handle_exit(kvm_run, vcpu);
+       r = kvm_x86_ops->handle_exit(vcpu);
 out:
        return r;
 }
 
 
-static int __vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+static int __vcpu_run(struct kvm_vcpu *vcpu)
 {
        int r;
 
@@ -3708,7 +3987,7 @@ static int __vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
        r = 1;
        while (r > 0) {
                if (vcpu->arch.mp_state == KVM_MP_STATE_RUNNABLE)
-                       r = vcpu_enter_guest(vcpu, kvm_run);
+                       r = vcpu_enter_guest(vcpu);
                else {
                        up_read(&vcpu->kvm->slots_lock);
                        kvm_vcpu_block(vcpu);
@@ -3736,14 +4015,14 @@ static int __vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
                if (kvm_cpu_has_pending_timer(vcpu))
                        kvm_inject_pending_timer_irqs(vcpu);
 
-               if (dm_request_for_irq_injection(vcpu, kvm_run)) {
+               if (dm_request_for_irq_injection(vcpu)) {
                        r = -EINTR;
-                       kvm_run->exit_reason = KVM_EXIT_INTR;
+                       vcpu->run->exit_reason = KVM_EXIT_INTR;
                        ++vcpu->stat.request_irq_exits;
                }
                if (signal_pending(current)) {
                        r = -EINTR;
-                       kvm_run->exit_reason = KVM_EXIT_INTR;
+                       vcpu->run->exit_reason = KVM_EXIT_INTR;
                        ++vcpu->stat.signal_exits;
                }
                if (need_resched()) {
@@ -3754,7 +4033,7 @@ static int __vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
        }
 
        up_read(&vcpu->kvm->slots_lock);
-       post_kvm_run_save(vcpu, kvm_run);
+       post_kvm_run_save(vcpu);
 
        vapic_exit(vcpu);
 
@@ -3787,15 +4066,13 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
                if (r)
                        goto out;
        }
-#if CONFIG_HAS_IOMEM
        if (vcpu->mmio_needed) {
                memcpy(vcpu->mmio_data, kvm_run->mmio.data, 8);
                vcpu->mmio_read_completed = 1;
                vcpu->mmio_needed = 0;
 
                down_read(&vcpu->kvm->slots_lock);
-               r = emulate_instruction(vcpu, kvm_run,
-                                       vcpu->arch.mmio_fault_cr2, 0,
+               r = emulate_instruction(vcpu, vcpu->arch.mmio_fault_cr2, 0,
                                        EMULTYPE_NO_DECODE);
                up_read(&vcpu->kvm->slots_lock);
                if (r == EMULATE_DO_MMIO) {
@@ -3806,12 +4083,11 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
                        goto out;
                }
        }
-#endif
        if (kvm_run->exit_reason == KVM_EXIT_HYPERCALL)
                kvm_register_write(vcpu, VCPU_REGS_RAX,
                                     kvm_run->hypercall.ret);
 
-       r = __vcpu_run(vcpu, kvm_run);
+       r = __vcpu_run(vcpu);
 
 out:
        if (vcpu->sigset_active)
@@ -3845,13 +4121,7 @@ int kvm_arch_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
 #endif
 
        regs->rip = kvm_rip_read(vcpu);
-       regs->rflags = kvm_x86_ops->get_rflags(vcpu);
-
-       /*
-        * Don't leak debug flags in case they were set for guest debugging
-        */
-       if (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP)
-               regs->rflags &= ~(X86_EFLAGS_TF | X86_EFLAGS_RF);
+       regs->rflags = kvm_get_rflags(vcpu);
 
        vcpu_put(vcpu);
 
@@ -3879,12 +4149,10 @@ int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
        kvm_register_write(vcpu, VCPU_REGS_R13, regs->r13);
        kvm_register_write(vcpu, VCPU_REGS_R14, regs->r14);
        kvm_register_write(vcpu, VCPU_REGS_R15, regs->r15);
-
 #endif
 
        kvm_rip_write(vcpu, regs->rip);
-       kvm_x86_ops->set_rflags(vcpu, regs->rflags);
-
+       kvm_set_rflags(vcpu, regs->rflags);
 
        vcpu->arch.exception.pending = false;
 
@@ -4103,7 +4371,7 @@ static int is_vm86_segment(struct kvm_vcpu *vcpu, int seg)
 {
        return (seg != VCPU_SREG_LDTR) &&
                (seg != VCPU_SREG_TR) &&
-               (kvm_x86_ops->get_rflags(vcpu) & X86_EFLAGS_VM);
+               (kvm_get_rflags(vcpu) & X86_EFLAGS_VM);
 }
 
 int kvm_load_segment_descriptor(struct kvm_vcpu *vcpu, u16 selector,
@@ -4131,7 +4399,7 @@ static void save_state_to_tss32(struct kvm_vcpu *vcpu,
 {
        tss->cr3 = vcpu->arch.cr3;
        tss->eip = kvm_rip_read(vcpu);
-       tss->eflags = kvm_x86_ops->get_rflags(vcpu);
+       tss->eflags = kvm_get_rflags(vcpu);
        tss->eax = kvm_register_read(vcpu, VCPU_REGS_RAX);
        tss->ecx = kvm_register_read(vcpu, VCPU_REGS_RCX);
        tss->edx = kvm_register_read(vcpu, VCPU_REGS_RDX);
@@ -4155,7 +4423,7 @@ static int load_state_from_tss32(struct kvm_vcpu *vcpu,
        kvm_set_cr3(vcpu, tss->cr3);
 
        kvm_rip_write(vcpu, tss->eip);
-       kvm_x86_ops->set_rflags(vcpu, tss->eflags | 2);
+       kvm_set_rflags(vcpu, tss->eflags | 2);
 
        kvm_register_write(vcpu, VCPU_REGS_RAX, tss->eax);
        kvm_register_write(vcpu, VCPU_REGS_RCX, tss->ecx);
@@ -4193,7 +4461,7 @@ static void save_state_to_tss16(struct kvm_vcpu *vcpu,
                                struct tss_segment_16 *tss)
 {
        tss->ip = kvm_rip_read(vcpu);
-       tss->flag = kvm_x86_ops->get_rflags(vcpu);
+       tss->flag = kvm_get_rflags(vcpu);
        tss->ax = kvm_register_read(vcpu, VCPU_REGS_RAX);
        tss->cx = kvm_register_read(vcpu, VCPU_REGS_RCX);
        tss->dx = kvm_register_read(vcpu, VCPU_REGS_RDX);
@@ -4208,14 +4476,13 @@ static void save_state_to_tss16(struct kvm_vcpu *vcpu,
        tss->ss = get_segment_selector(vcpu, VCPU_SREG_SS);
        tss->ds = get_segment_selector(vcpu, VCPU_SREG_DS);
        tss->ldt = get_segment_selector(vcpu, VCPU_SREG_LDTR);
-       tss->prev_task_link = get_segment_selector(vcpu, VCPU_SREG_TR);
 }
 
 static int load_state_from_tss16(struct kvm_vcpu *vcpu,
                                 struct tss_segment_16 *tss)
 {
        kvm_rip_write(vcpu, tss->ip);
-       kvm_x86_ops->set_rflags(vcpu, tss->flag | 2);
+       kvm_set_rflags(vcpu, tss->flag | 2);
        kvm_register_write(vcpu, VCPU_REGS_RAX, tss->ax);
        kvm_register_write(vcpu, VCPU_REGS_RCX, tss->cx);
        kvm_register_write(vcpu, VCPU_REGS_RDX, tss->dx);
@@ -4361,8 +4628,8 @@ int kvm_task_switch(struct kvm_vcpu *vcpu, u16 tss_selector, int reason)
        }
 
        if (reason == TASK_SWITCH_IRET) {
-               u32 eflags = kvm_x86_ops->get_rflags(vcpu);
-               kvm_x86_ops->set_rflags(vcpu, eflags & ~X86_EFLAGS_NT);
+               u32 eflags = kvm_get_rflags(vcpu);
+               kvm_set_rflags(vcpu, eflags & ~X86_EFLAGS_NT);
        }
 
        /* set back link to prev task only if NT bit is set in eflags
@@ -4370,11 +4637,6 @@ int kvm_task_switch(struct kvm_vcpu *vcpu, u16 tss_selector, int reason)
        if (reason != TASK_SWITCH_CALL && reason != TASK_SWITCH_GATE)
                old_tss_sel = 0xffff;
 
-       /* set back link to prev task only if NT bit is set in eflags
-          note that old_tss_sel is not used afetr this point */
-       if (reason != TASK_SWITCH_CALL && reason != TASK_SWITCH_GATE)
-               old_tss_sel = 0xffff;
-
        if (nseg_desc.type & 8)
                ret = kvm_task_switch_32(vcpu, tss_selector, old_tss_sel,
                                         old_tss_base, &nseg_desc);
@@ -4383,8 +4645,8 @@ int kvm_task_switch(struct kvm_vcpu *vcpu, u16 tss_selector, int reason)
                                         old_tss_base, &nseg_desc);
 
        if (reason == TASK_SWITCH_CALL || reason == TASK_SWITCH_GATE) {
-               u32 eflags = kvm_x86_ops->get_rflags(vcpu);
-               kvm_x86_ops->set_rflags(vcpu, eflags | X86_EFLAGS_NT);
+               u32 eflags = kvm_get_rflags(vcpu);
+               kvm_set_rflags(vcpu, eflags | X86_EFLAGS_NT);
        }
 
        if (reason != TASK_SWITCH_IRET) {
@@ -4436,8 +4698,10 @@ int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu,
 
        mmu_reset_needed |= vcpu->arch.cr4 != sregs->cr4;
        kvm_x86_ops->set_cr4(vcpu, sregs->cr4);
-       if (!is_long_mode(vcpu) && is_pae(vcpu))
+       if (!is_long_mode(vcpu) && is_pae(vcpu)) {
                load_pdptrs(vcpu, vcpu->arch.cr3);
+               mmu_reset_needed = 1;
+       }
 
        if (mmu_reset_needed)
                kvm_mmu_reset_context(vcpu);
@@ -4478,12 +4742,32 @@ int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu,
 int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu,
                                        struct kvm_guest_debug *dbg)
 {
+       unsigned long rflags;
        int i, r;
 
        vcpu_load(vcpu);
 
-       if ((dbg->control & (KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_USE_HW_BP)) ==
-           (KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_USE_HW_BP)) {
+       if (dbg->control & (KVM_GUESTDBG_INJECT_DB | KVM_GUESTDBG_INJECT_BP)) {
+               r = -EBUSY;
+               if (vcpu->arch.exception.pending)
+                       goto unlock_out;
+               if (dbg->control & KVM_GUESTDBG_INJECT_DB)
+                       kvm_queue_exception(vcpu, DB_VECTOR);
+               else
+                       kvm_queue_exception(vcpu, BP_VECTOR);
+       }
+
+       /*
+        * Read rflags as long as potentially injected trace flags are still
+        * filtered out.
+        */
+       rflags = kvm_get_rflags(vcpu);
+
+       vcpu->guest_debug = dbg->control;
+       if (!(vcpu->guest_debug & KVM_GUESTDBG_ENABLE))
+               vcpu->guest_debug = 0;
+
+       if (vcpu->guest_debug & KVM_GUESTDBG_USE_HW_BP) {
                for (i = 0; i < KVM_NR_DB_REGS; ++i)
                        vcpu->arch.eff_db[i] = dbg->arch.debugreg[i];
                vcpu->arch.switch_db_regs =
@@ -4494,13 +4778,23 @@ int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu,
                vcpu->arch.switch_db_regs = (vcpu->arch.dr7 & DR7_BP_EN_MASK);
        }
 
-       r = kvm_x86_ops->set_guest_debug(vcpu, dbg);
+       if (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP) {
+               vcpu->arch.singlestep_cs =
+                       get_segment_selector(vcpu, VCPU_SREG_CS);
+               vcpu->arch.singlestep_rip = kvm_rip_read(vcpu);
+       }
+
+       /*
+        * Trigger an rflags update that will inject or remove the trace
+        * flags.
+        */
+       kvm_set_rflags(vcpu, rflags);
+
+       kvm_x86_ops->set_guest_debug(vcpu, dbg);
 
-       if (dbg->control & KVM_GUESTDBG_INJECT_DB)
-               kvm_queue_exception(vcpu, DB_VECTOR);
-       else if (dbg->control & KVM_GUESTDBG_INJECT_BP)
-               kvm_queue_exception(vcpu, BP_VECTOR);
+       r = 0;
 
+unlock_out:
        vcpu_put(vcpu);
 
        return r;
@@ -4701,14 +4995,26 @@ int kvm_arch_vcpu_reset(struct kvm_vcpu *vcpu)
        return kvm_x86_ops->vcpu_reset(vcpu);
 }
 
-void kvm_arch_hardware_enable(void *garbage)
+int kvm_arch_hardware_enable(void *garbage)
 {
-       kvm_x86_ops->hardware_enable(garbage);
+       /*
+        * Since this may be called from a hotplug notifcation,
+        * we can't get the CPU frequency directly.
+        */
+       if (!boot_cpu_has(X86_FEATURE_CONSTANT_TSC)) {
+               int cpu = raw_smp_processor_id();
+               per_cpu(cpu_tsc_khz, cpu) = 0;
+       }
+
+       kvm_shared_msr_cpu_online();
+
+       return kvm_x86_ops->hardware_enable(garbage);
 }
 
 void kvm_arch_hardware_disable(void *garbage)
 {
        kvm_x86_ops->hardware_disable(garbage);
+       drop_user_return_notifiers(garbage);
 }
 
 int kvm_arch_hardware_setup(void)
@@ -4946,8 +5252,36 @@ int kvm_arch_interrupt_allowed(struct kvm_vcpu *vcpu)
        return kvm_x86_ops->interrupt_allowed(vcpu);
 }
 
+unsigned long kvm_get_rflags(struct kvm_vcpu *vcpu)
+{
+       unsigned long rflags;
+
+       rflags = kvm_x86_ops->get_rflags(vcpu);
+       if (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP)
+               rflags &= ~(unsigned long)(X86_EFLAGS_TF | X86_EFLAGS_RF);
+       return rflags;
+}
+EXPORT_SYMBOL_GPL(kvm_get_rflags);
+
+void kvm_set_rflags(struct kvm_vcpu *vcpu, unsigned long rflags)
+{
+       if (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP &&
+           vcpu->arch.singlestep_cs ==
+                       get_segment_selector(vcpu, VCPU_SREG_CS) &&
+           vcpu->arch.singlestep_rip == kvm_rip_read(vcpu))
+               rflags |= X86_EFLAGS_TF | X86_EFLAGS_RF;
+       kvm_x86_ops->set_rflags(vcpu, rflags);
+}
+EXPORT_SYMBOL_GPL(kvm_set_rflags);
+
 EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_exit);
 EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_inj_virq);
 EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_page_fault);
 EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_msr);
 EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_cr);
+EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_nested_vmrun);
+EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_nested_vmexit);
+EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_nested_vmexit_inject);
+EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_nested_intr_vmexit);
+EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_invlpga);
+EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_skinit);
diff --git a/arch/x86/lib/.gitignore b/arch/x86/lib/.gitignore
new file mode 100644 (file)
index 0000000..8df89f0
--- /dev/null
@@ -0,0 +1 @@
+inat-tables.c
index 85f5db9..a2d6472 100644 (file)
@@ -2,12 +2,25 @@
 # Makefile for x86 specific library files.
 #
 
+inat_tables_script = $(srctree)/arch/x86/tools/gen-insn-attr-x86.awk
+inat_tables_maps = $(srctree)/arch/x86/lib/x86-opcode-map.txt
+quiet_cmd_inat_tables = GEN     $@
+      cmd_inat_tables = $(AWK) -f $(inat_tables_script) $(inat_tables_maps) > $@
+
+$(obj)/inat-tables.c: $(inat_tables_script) $(inat_tables_maps)
+       $(call cmd,inat_tables)
+
+$(obj)/inat.o: $(obj)/inat-tables.c
+
+clean-files := inat-tables.c
+
 obj-$(CONFIG_SMP) := msr.o
 
 lib-y := delay.o
 lib-y += thunk_$(BITS).o
 lib-y += usercopy_$(BITS).o getuser.o putuser.o
 lib-y += memcpy_$(BITS).o
+lib-y += insn.o inat.o
 
 obj-y += msr-reg.o msr-reg-export.o
 
index 6ba0f7b..cf889d4 100644 (file)
@@ -65,7 +65,7 @@
        .endm
 
 /* Standard copy_to_user with segment limit checking */
-ENTRY(copy_to_user)
+ENTRY(_copy_to_user)
        CFI_STARTPROC
        GET_THREAD_INFO(%rax)
        movq %rdi,%rcx
@@ -75,10 +75,10 @@ ENTRY(copy_to_user)
        jae bad_to_user
        ALTERNATIVE_JUMP X86_FEATURE_REP_GOOD,copy_user_generic_unrolled,copy_user_generic_string
        CFI_ENDPROC
-ENDPROC(copy_to_user)
+ENDPROC(_copy_to_user)
 
 /* Standard copy_from_user with segment limit checking */
-ENTRY(copy_from_user)
+ENTRY(_copy_from_user)
        CFI_STARTPROC
        GET_THREAD_INFO(%rax)
        movq %rsi,%rcx
@@ -88,7 +88,7 @@ ENTRY(copy_from_user)
        jae bad_from_user
        ALTERNATIVE_JUMP X86_FEATURE_REP_GOOD,copy_user_generic_unrolled,copy_user_generic_string
        CFI_ENDPROC
-ENDPROC(copy_from_user)
+ENDPROC(_copy_from_user)
 
 ENTRY(copy_user_generic)
        CFI_STARTPROC
@@ -96,12 +96,6 @@ ENTRY(copy_user_generic)
        CFI_ENDPROC
 ENDPROC(copy_user_generic)
 
-ENTRY(__copy_from_user_inatomic)
-       CFI_STARTPROC
-       ALTERNATIVE_JUMP X86_FEATURE_REP_GOOD,copy_user_generic_unrolled,copy_user_generic_string
-       CFI_ENDPROC
-ENDPROC(__copy_from_user_inatomic)
-
        .section .fixup,"ax"
        /* must zero dest */
 ENTRY(bad_from_user)
diff --git a/arch/x86/lib/inat.c b/arch/x86/lib/inat.c
new file mode 100644 (file)
index 0000000..46fc4ee
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * x86 instruction attribute tables
+ *
+ * Written by Masami Hiramatsu <mhiramat@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 <asm/insn.h>
+
+/* Attribute tables are generated from opcode map */
+#include "inat-tables.c"
+
+/* Attribute search APIs */
+insn_attr_t inat_get_opcode_attribute(insn_byte_t opcode)
+{
+       return inat_primary_table[opcode];
+}
+
+insn_attr_t inat_get_escape_attribute(insn_byte_t opcode, insn_byte_t last_pfx,
+                                     insn_attr_t esc_attr)
+{
+       const insn_attr_t *table;
+       insn_attr_t lpfx_attr;
+       int n, m = 0;
+
+       n = inat_escape_id(esc_attr);
+       if (last_pfx) {
+               lpfx_attr = inat_get_opcode_attribute(last_pfx);
+               m = inat_last_prefix_id(lpfx_attr);
+       }
+       table = inat_escape_tables[n][0];
+       if (!table)
+               return 0;
+       if (inat_has_variant(table[opcode]) && m) {
+               table = inat_escape_tables[n][m];
+               if (!table)
+                       return 0;
+       }
+       return table[opcode];
+}
+
+insn_attr_t inat_get_group_attribute(insn_byte_t modrm, insn_byte_t last_pfx,
+                                    insn_attr_t grp_attr)
+{
+       const insn_attr_t *table;
+       insn_attr_t lpfx_attr;
+       int n, m = 0;
+
+       n = inat_group_id(grp_attr);
+       if (last_pfx) {
+               lpfx_attr = inat_get_opcode_attribute(last_pfx);
+               m = inat_last_prefix_id(lpfx_attr);
+       }
+       table = inat_group_tables[n][0];
+       if (!table)
+               return inat_group_common_attribute(grp_attr);
+       if (inat_has_variant(table[X86_MODRM_REG(modrm)]) && m) {
+               table = inat_group_tables[n][m];
+               if (!table)
+                       return inat_group_common_attribute(grp_attr);
+       }
+       return table[X86_MODRM_REG(modrm)] |
+              inat_group_common_attribute(grp_attr);
+}
+
+insn_attr_t inat_get_avx_attribute(insn_byte_t opcode, insn_byte_t vex_m,
+                                  insn_byte_t vex_p)
+{
+       const insn_attr_t *table;
+       if (vex_m > X86_VEX_M_MAX || vex_p > INAT_LSTPFX_MAX)
+               return 0;
+       table = inat_avx_tables[vex_m][vex_p];
+       if (!table)
+               return 0;
+       return table[opcode];
+}
+
diff --git a/arch/x86/lib/insn.c b/arch/x86/lib/insn.c
new file mode 100644 (file)
index 0000000..9f33b98
--- /dev/null
@@ -0,0 +1,516 @@
+/*
+ * x86 instruction analysis
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Copyright (C) IBM Corporation, 2002, 2004, 2009
+ */
+
+#include <linux/string.h>
+#include <asm/inat.h>
+#include <asm/insn.h>
+
+#define get_next(t, insn)      \
+       ({t r; r = *(t*)insn->next_byte; insn->next_byte += sizeof(t); r; })
+
+#define peek_next(t, insn)     \
+       ({t r; r = *(t*)insn->next_byte; r; })
+
+#define peek_nbyte_next(t, insn, n)    \
+       ({t r; r = *(t*)((insn)->next_byte + n); r; })
+
+/**
+ * insn_init() - initialize struct insn
+ * @insn:      &struct insn to be initialized
+ * @kaddr:     address (in kernel memory) of instruction (or copy thereof)
+ * @x86_64:    !0 for 64-bit kernel or 64-bit app
+ */
+void insn_init(struct insn *insn, const void *kaddr, int x86_64)
+{
+       memset(insn, 0, sizeof(*insn));
+       insn->kaddr = kaddr;
+       insn->next_byte = kaddr;
+       insn->x86_64 = x86_64 ? 1 : 0;
+       insn->opnd_bytes = 4;
+       if (x86_64)
+               insn->addr_bytes = 8;
+       else
+               insn->addr_bytes = 4;
+}
+
+/**
+ * insn_get_prefixes - scan x86 instruction prefix bytes
+ * @insn:      &struct insn containing instruction
+ *
+ * Populates the @insn->prefixes bitmap, and updates @insn->next_byte
+ * to point to the (first) opcode.  No effect if @insn->prefixes.got
+ * is already set.
+ */
+void insn_get_prefixes(struct insn *insn)
+{
+       struct insn_field *prefixes = &insn->prefixes;
+       insn_attr_t attr;
+       insn_byte_t b, lb;
+       int i, nb;
+
+       if (prefixes->got)
+               return;
+
+       nb = 0;
+       lb = 0;
+       b = peek_next(insn_byte_t, insn);
+       attr = inat_get_opcode_attribute(b);
+       while (inat_is_legacy_prefix(attr)) {
+               /* Skip if same prefix */
+               for (i = 0; i < nb; i++)
+                       if (prefixes->bytes[i] == b)
+                               goto found;
+               if (nb == 4)
+                       /* Invalid instruction */
+                       break;
+               prefixes->bytes[nb++] = b;
+               if (inat_is_address_size_prefix(attr)) {
+                       /* address size switches 2/4 or 4/8 */
+                       if (insn->x86_64)
+                               insn->addr_bytes ^= 12;
+                       else
+                               insn->addr_bytes ^= 6;
+               } else if (inat_is_operand_size_prefix(attr)) {
+                       /* oprand size switches 2/4 */
+                       insn->opnd_bytes ^= 6;
+               }
+found:
+               prefixes->nbytes++;
+               insn->next_byte++;
+               lb = b;
+               b = peek_next(insn_byte_t, insn);
+               attr = inat_get_opcode_attribute(b);
+       }
+       /* Set the last prefix */
+       if (lb && lb != insn->prefixes.bytes[3]) {
+               if (unlikely(insn->prefixes.bytes[3])) {
+                       /* Swap the last prefix */
+                       b = insn->prefixes.bytes[3];
+                       for (i = 0; i < nb; i++)
+                               if (prefixes->bytes[i] == lb)
+                                       prefixes->bytes[i] = b;
+               }
+               insn->prefixes.bytes[3] = lb;
+       }
+
+       /* Decode REX prefix */
+       if (insn->x86_64) {
+               b = peek_next(insn_byte_t, insn);
+               attr = inat_get_opcode_attribute(b);
+               if (inat_is_rex_prefix(attr)) {
+                       insn->rex_prefix.value = b;
+                       insn->rex_prefix.nbytes = 1;
+                       insn->next_byte++;
+                       if (X86_REX_W(b))
+                               /* REX.W overrides opnd_size */
+                               insn->opnd_bytes = 8;
+               }
+       }
+       insn->rex_prefix.got = 1;
+
+       /* Decode VEX prefix */
+       b = peek_next(insn_byte_t, insn);
+       attr = inat_get_opcode_attribute(b);
+       if (inat_is_vex_prefix(attr)) {
+               insn_byte_t b2 = peek_nbyte_next(insn_byte_t, insn, 1);
+               if (!insn->x86_64) {
+                       /*
+                        * In 32-bits mode, if the [7:6] bits (mod bits of
+                        * ModRM) on the second byte are not 11b, it is
+                        * LDS or LES.
+                        */
+                       if (X86_MODRM_MOD(b2) != 3)
+                               goto vex_end;
+               }
+               insn->vex_prefix.bytes[0] = b;
+               insn->vex_prefix.bytes[1] = b2;
+               if (inat_is_vex3_prefix(attr)) {
+                       b2 = peek_nbyte_next(insn_byte_t, insn, 2);
+                       insn->vex_prefix.bytes[2] = b2;
+                       insn->vex_prefix.nbytes = 3;
+                       insn->next_byte += 3;
+                       if (insn->x86_64 && X86_VEX_W(b2))
+                               /* VEX.W overrides opnd_size */
+                               insn->opnd_bytes = 8;
+               } else {
+                       insn->vex_prefix.nbytes = 2;
+                       insn->next_byte += 2;
+               }
+       }
+vex_end:
+       insn->vex_prefix.got = 1;
+
+       prefixes->got = 1;
+       return;
+}
+
+/**
+ * insn_get_opcode - collect opcode(s)
+ * @insn:      &struct insn containing instruction
+ *
+ * Populates @insn->opcode, updates @insn->next_byte to point past the
+ * opcode byte(s), and set @insn->attr (except for groups).
+ * If necessary, first collects any preceding (prefix) bytes.
+ * Sets @insn->opcode.value = opcode1.  No effect if @insn->opcode.got
+ * is already 1.
+ */
+void insn_get_opcode(struct insn *insn)
+{
+       struct insn_field *opcode = &insn->opcode;
+       insn_byte_t op, pfx;
+       if (opcode->got)
+               return;
+       if (!insn->prefixes.got)
+               insn_get_prefixes(insn);
+
+       /* Get first opcode */
+       op = get_next(insn_byte_t, insn);
+       opcode->bytes[0] = op;
+       opcode->nbytes = 1;
+
+       /* Check if there is VEX prefix or not */
+       if (insn_is_avx(insn)) {
+               insn_byte_t m, p;
+               m = insn_vex_m_bits(insn);
+               p = insn_vex_p_bits(insn);
+               insn->attr = inat_get_avx_attribute(op, m, p);
+               if (!inat_accept_vex(insn->attr))
+                       insn->attr = 0; /* This instruction is bad */
+               goto end;       /* VEX has only 1 byte for opcode */
+       }
+
+       insn->attr = inat_get_opcode_attribute(op);
+       while (inat_is_escape(insn->attr)) {
+               /* Get escaped opcode */
+               op = get_next(insn_byte_t, insn);
+               opcode->bytes[opcode->nbytes++] = op;
+               pfx = insn_last_prefix(insn);
+               insn->attr = inat_get_escape_attribute(op, pfx, insn->attr);
+       }
+       if (inat_must_vex(insn->attr))
+               insn->attr = 0; /* This instruction is bad */
+end:
+       opcode->got = 1;
+}
+
+/**
+ * insn_get_modrm - collect ModRM byte, if any
+ * @insn:      &struct insn containing instruction
+ *
+ * Populates @insn->modrm and updates @insn->next_byte to point past the
+ * ModRM byte, if any.  If necessary, first collects the preceding bytes
+ * (prefixes and opcode(s)).  No effect if @insn->modrm.got is already 1.
+ */
+void insn_get_modrm(struct insn *insn)
+{
+       struct insn_field *modrm = &insn->modrm;
+       insn_byte_t pfx, mod;
+       if (modrm->got)
+               return;
+       if (!insn->opcode.got)
+               insn_get_opcode(insn);
+
+       if (inat_has_modrm(insn->attr)) {
+               mod = get_next(insn_byte_t, insn);
+               modrm->value = mod;
+               modrm->nbytes = 1;
+               if (inat_is_group(insn->attr)) {
+                       pfx = insn_last_prefix(insn);
+                       insn->attr = inat_get_group_attribute(mod, pfx,
+                                                             insn->attr);
+               }
+       }
+
+       if (insn->x86_64 && inat_is_force64(insn->attr))
+               insn->opnd_bytes = 8;
+       modrm->got = 1;
+}
+
+
+/**
+ * insn_rip_relative() - Does instruction use RIP-relative addressing mode?
+ * @insn:      &struct insn containing instruction
+ *
+ * If necessary, first collects the instruction up to and including the
+ * ModRM byte.  No effect if @insn->x86_64 is 0.
+ */
+int insn_rip_relative(struct insn *insn)
+{
+       struct insn_field *modrm = &insn->modrm;
+
+       if (!insn->x86_64)
+               return 0;
+       if (!modrm->got)
+               insn_get_modrm(insn);
+       /*
+        * For rip-relative instructions, the mod field (top 2 bits)
+        * is zero and the r/m field (bottom 3 bits) is 0x5.
+        */
+       return (modrm->nbytes && (modrm->value & 0xc7) == 0x5);
+}
+
+/**
+ * insn_get_sib() - Get the SIB byte of instruction
+ * @insn:      &struct insn containing instruction
+ *
+ * If necessary, first collects the instruction up to and including the
+ * ModRM byte.
+ */
+void insn_get_sib(struct insn *insn)
+{
+       insn_byte_t modrm;
+
+       if (insn->sib.got)
+               return;
+       if (!insn->modrm.got)
+               insn_get_modrm(insn);
+       if (insn->modrm.nbytes) {
+               modrm = (insn_byte_t)insn->modrm.value;
+               if (insn->addr_bytes != 2 &&
+                   X86_MODRM_MOD(modrm) != 3 && X86_MODRM_RM(modrm) == 4) {
+                       insn->sib.value = get_next(insn_byte_t, insn);
+                       insn->sib.nbytes = 1;
+               }
+       }
+       insn->sib.got = 1;
+}
+
+
+/**
+ * insn_get_displacement() - Get the displacement of instruction
+ * @insn:      &struct insn containing instruction
+ *
+ * If necessary, first collects the instruction up to and including the
+ * SIB byte.
+ * Displacement value is sign-expanded.
+ */
+void insn_get_displacement(struct insn *insn)
+{
+       insn_byte_t mod, rm, base;
+
+       if (insn->displacement.got)
+               return;
+       if (!insn->sib.got)
+               insn_get_sib(insn);
+       if (insn->modrm.nbytes) {
+               /*
+                * Interpreting the modrm byte:
+                * mod = 00 - no displacement fields (exceptions below)
+                * mod = 01 - 1-byte displacement field
+                * mod = 10 - displacement field is 4 bytes, or 2 bytes if
+                *      address size = 2 (0x67 prefix in 32-bit mode)
+                * mod = 11 - no memory operand
+                *
+                * If address size = 2...
+                * mod = 00, r/m = 110 - displacement field is 2 bytes
+                *
+                * If address size != 2...
+                * mod != 11, r/m = 100 - SIB byte exists
+                * mod = 00, SIB base = 101 - displacement field is 4 bytes
+                * mod = 00, r/m = 101 - rip-relative addressing, displacement
+                *      field is 4 bytes
+                */
+               mod = X86_MODRM_MOD(insn->modrm.value);
+               rm = X86_MODRM_RM(insn->modrm.value);
+               base = X86_SIB_BASE(insn->sib.value);
+               if (mod == 3)
+                       goto out;
+               if (mod == 1) {
+                       insn->displacement.value = get_next(char, insn);
+                       insn->displacement.nbytes = 1;
+               } else if (insn->addr_bytes == 2) {
+                       if ((mod == 0 && rm == 6) || mod == 2) {
+                               insn->displacement.value =
+                                        get_next(short, insn);
+                               insn->displacement.nbytes = 2;
+                       }
+               } else {
+                       if ((mod == 0 && rm == 5) || mod == 2 ||
+                           (mod == 0 && base == 5)) {
+                               insn->displacement.value = get_next(int, insn);
+                               insn->displacement.nbytes = 4;
+                       }
+               }
+       }
+out:
+       insn->displacement.got = 1;
+}
+
+/* Decode moffset16/32/64 */
+static void __get_moffset(struct insn *insn)
+{
+       switch (insn->addr_bytes) {
+       case 2:
+               insn->moffset1.value = get_next(short, insn);
+               insn->moffset1.nbytes = 2;
+               break;
+       case 4:
+               insn->moffset1.value = get_next(int, insn);
+               insn->moffset1.nbytes = 4;
+               break;
+       case 8:
+               insn->moffset1.value = get_next(int, insn);
+               insn->moffset1.nbytes = 4;
+               insn->moffset2.value = get_next(int, insn);
+               insn->moffset2.nbytes = 4;
+               break;
+       }
+       insn->moffset1.got = insn->moffset2.got = 1;
+}
+
+/* Decode imm v32(Iz) */
+static void __get_immv32(struct insn *insn)
+{
+       switch (insn->opnd_bytes) {
+       case 2:
+               insn->immediate.value = get_next(short, insn);
+               insn->immediate.nbytes = 2;
+               break;
+       case 4:
+       case 8:
+               insn->immediate.value = get_next(int, insn);
+               insn->immediate.nbytes = 4;
+               break;
+       }
+}
+
+/* Decode imm v64(Iv/Ov) */
+static void __get_immv(struct insn *insn)
+{
+       switch (insn->opnd_bytes) {
+       case 2:
+               insn->immediate1.value = get_next(short, insn);
+               insn->immediate1.nbytes = 2;
+               break;
+       case 4:
+               insn->immediate1.value = get_next(int, insn);
+               insn->immediate1.nbytes = 4;
+               break;
+       case 8:
+               insn->immediate1.value = get_next(int, insn);
+               insn->immediate1.nbytes = 4;
+               insn->immediate2.value = get_next(int, insn);
+               insn->immediate2.nbytes = 4;
+               break;
+       }
+       insn->immediate1.got = insn->immediate2.got = 1;
+}
+
+/* Decode ptr16:16/32(Ap) */
+static void __get_immptr(struct insn *insn)
+{
+       switch (insn->opnd_bytes) {
+       case 2:
+               insn->immediate1.value = get_next(short, insn);
+               insn->immediate1.nbytes = 2;
+               break;
+       case 4:
+               insn->immediate1.value = get_next(int, insn);
+               insn->immediate1.nbytes = 4;
+               break;
+       case 8:
+               /* ptr16:64 is not exist (no segment) */
+               return;
+       }
+       insn->immediate2.value = get_next(unsigned short, insn);
+       insn->immediate2.nbytes = 2;
+       insn->immediate1.got = insn->immediate2.got = 1;
+}
+
+/**
+ * insn_get_immediate() - Get the immediates of instruction
+ * @insn:      &struct insn containing instruction
+ *
+ * If necessary, first collects the instruction up to and including the
+ * displacement bytes.
+ * Basically, most of immediates are sign-expanded. Unsigned-value can be
+ * get by bit masking with ((1 << (nbytes * 8)) - 1)
+ */
+void insn_get_immediate(struct insn *insn)
+{
+       if (insn->immediate.got)
+               return;
+       if (!insn->displacement.got)
+               insn_get_displacement(insn);
+
+       if (inat_has_moffset(insn->attr)) {
+               __get_moffset(insn);
+               goto done;
+       }
+
+       if (!inat_has_immediate(insn->attr))
+               /* no immediates */
+               goto done;
+
+       switch (inat_immediate_size(insn->attr)) {
+       case INAT_IMM_BYTE:
+               insn->immediate.value = get_next(char, insn);
+               insn->immediate.nbytes = 1;
+               break;
+       case INAT_IMM_WORD:
+               insn->immediate.value = get_next(short, insn);
+               insn->immediate.nbytes = 2;
+               break;
+       case INAT_IMM_DWORD:
+               insn->immediate.value = get_next(int, insn);
+               insn->immediate.nbytes = 4;
+               break;
+       case INAT_IMM_QWORD:
+               insn->immediate1.value = get_next(int, insn);
+               insn->immediate1.nbytes = 4;
+               insn->immediate2.value = get_next(int, insn);
+               insn->immediate2.nbytes = 4;
+               break;
+       case INAT_IMM_PTR:
+               __get_immptr(insn);
+               break;
+       case INAT_IMM_VWORD32:
+               __get_immv32(insn);
+               break;
+       case INAT_IMM_VWORD:
+               __get_immv(insn);
+               break;
+       default:
+               break;
+       }
+       if (inat_has_second_immediate(insn->attr)) {
+               insn->immediate2.value = get_next(char, insn);
+               insn->immediate2.nbytes = 1;
+       }
+done:
+       insn->immediate.got = 1;
+}
+
+/**
+ * insn_get_length() - Get the length of instruction
+ * @insn:      &struct insn containing instruction
+ *
+ * If necessary, first collects the instruction up to and including the
+ * immediates bytes.
+ */
+void insn_get_length(struct insn *insn)
+{
+       if (insn->length)
+               return;
+       if (!insn->immediate.got)
+               insn_get_immediate(insn);
+       insn->length = (unsigned char)((unsigned long)insn->next_byte
+                                    - (unsigned long)insn->kaddr);
+}
index 33a1e3c..41628b1 100644 (file)
@@ -71,14 +71,9 @@ int wrmsr_on_cpu(unsigned int cpu, u32 msr_no, u32 l, u32 h)
 }
 EXPORT_SYMBOL(wrmsr_on_cpu);
 
-/* rdmsr on a bunch of CPUs
- *
- * @mask:       which CPUs
- * @msr_no:     which MSR
- * @msrs:       array of MSR values
- *
- */
-void rdmsr_on_cpus(const cpumask_t *mask, u32 msr_no, struct msr *msrs)
+static void __rwmsr_on_cpus(const struct cpumask *mask, u32 msr_no,
+                           struct msr *msrs,
+                           void (*msr_func) (void *info))
 {
        struct msr_info rv;
        int this_cpu;
@@ -92,11 +87,23 @@ void rdmsr_on_cpus(const cpumask_t *mask, u32 msr_no, struct msr *msrs)
        this_cpu = get_cpu();
 
        if (cpumask_test_cpu(this_cpu, mask))
-               __rdmsr_on_cpu(&rv);
+               msr_func(&rv);
 
-       smp_call_function_many(mask, __rdmsr_on_cpu, &rv, 1);
+       smp_call_function_many(mask, msr_func, &rv, 1);
        put_cpu();
 }
+
+/* rdmsr on a bunch of CPUs
+ *
+ * @mask:       which CPUs
+ * @msr_no:     which MSR
+ * @msrs:       array of MSR values
+ *
+ */
+void rdmsr_on_cpus(const struct cpumask *mask, u32 msr_no, struct msr *msrs)
+{
+       __rwmsr_on_cpus(mask, msr_no, msrs, __rdmsr_on_cpu);
+}
 EXPORT_SYMBOL(rdmsr_on_cpus);
 
 /*
@@ -107,24 +114,9 @@ EXPORT_SYMBOL(rdmsr_on_cpus);
  * @msrs:       array of MSR values
  *
  */
-void wrmsr_on_cpus(const cpumask_t *mask, u32 msr_no, struct msr *msrs)
+void wrmsr_on_cpus(const struct cpumask *mask, u32 msr_no, struct msr *msrs)
 {
-       struct msr_info rv;
-       int this_cpu;
-
-       memset(&rv, 0, sizeof(rv));
-
-       rv.off    = cpumask_first(mask);
-       rv.msrs   = msrs;
-       rv.msr_no = msr_no;
-
-       this_cpu = get_cpu();
-
-       if (cpumask_test_cpu(this_cpu, mask))
-               __wrmsr_on_cpu(&rv);
-
-       smp_call_function_many(mask, __wrmsr_on_cpu, &rv, 1);
-       put_cpu();
+       __rwmsr_on_cpus(mask, msr_no, msrs, __wrmsr_on_cpu);
 }
 EXPORT_SYMBOL(wrmsr_on_cpus);
 
index 1f118d4..e218d5d 100644 (file)
@@ -874,7 +874,7 @@ EXPORT_SYMBOL(copy_to_user);
  * data to the requested size using zero bytes.
  */
 unsigned long
-copy_from_user(void *to, const void __user *from, unsigned long n)
+_copy_from_user(void *to, const void __user *from, unsigned long n)
 {
        if (access_ok(VERIFY_READ, from, n))
                n = __copy_from_user(to, from, n);
@@ -882,4 +882,10 @@ copy_from_user(void *to, const void __user *from, unsigned long n)
                memset(to, 0, n);
        return n;
 }
-EXPORT_SYMBOL(copy_from_user);
+EXPORT_SYMBOL(_copy_from_user);
+
+void copy_from_user_overflow(void)
+{
+       WARN(1, "Buffer overflow detected!\n");
+}
+EXPORT_SYMBOL(copy_from_user_overflow);
diff --git a/arch/x86/lib/x86-opcode-map.txt b/arch/x86/lib/x86-opcode-map.txt
new file mode 100644 (file)
index 0000000..a793da5
--- /dev/null
@@ -0,0 +1,893 @@
+# x86 Opcode Maps
+#
+#<Opcode maps>
+# Table: table-name
+# Referrer: escaped-name
+# AVXcode: avx-code
+# opcode: mnemonic|GrpXXX [operand1[,operand2...]] [(extra1)[,(extra2)...] [| 2nd-mnemonic ...]
+# (or)
+# opcode: escape # escaped-name
+# EndTable
+#
+#<group maps>
+# GrpTable: GrpXXX
+# reg:  mnemonic [operand1[,operand2...]] [(extra1)[,(extra2)...] [| 2nd-mnemonic ...]
+# EndTable
+#
+# AVX Superscripts
+#  (VEX): this opcode can accept VEX prefix.
+#  (oVEX): this opcode requires VEX prefix.
+#  (o128): this opcode only supports 128bit VEX.
+#  (o256): this opcode only supports 256bit VEX.
+#
+
+Table: one byte opcode
+Referrer:
+AVXcode:
+# 0x00 - 0x0f
+00: ADD Eb,Gb
+01: ADD Ev,Gv
+02: ADD Gb,Eb
+03: ADD Gv,Ev
+04: ADD AL,Ib
+05: ADD rAX,Iz
+06: PUSH ES (i64)
+07: POP ES (i64)
+08: OR Eb,Gb
+09: OR Ev,Gv
+0a: OR Gb,Eb
+0b: OR Gv,Ev
+0c: OR AL,Ib
+0d: OR rAX,Iz
+0e: PUSH CS (i64)
+0f: escape # 2-byte escape
+# 0x10 - 0x1f
+10: ADC Eb,Gb
+11: ADC Ev,Gv
+12: ADC Gb,Eb
+13: ADC Gv,Ev
+14: ADC AL,Ib
+15: ADC rAX,Iz
+16: PUSH SS (i64)
+17: POP SS (i64)
+18: SBB Eb,Gb
+19: SBB Ev,Gv
+1a: SBB Gb,Eb
+1b: SBB Gv,Ev
+1c: SBB AL,Ib
+1d: SBB rAX,Iz
+1e: PUSH DS (i64)
+1f: POP DS (i64)
+# 0x20 - 0x2f
+20: AND Eb,Gb
+21: AND Ev,Gv
+22: AND Gb,Eb
+23: AND Gv,Ev
+24: AND AL,Ib
+25: AND rAx,Iz
+26: SEG=ES (Prefix)
+27: DAA (i64)
+28: SUB Eb,Gb
+29: SUB Ev,Gv
+2a: SUB Gb,Eb
+2b: SUB Gv,Ev
+2c: SUB AL,Ib
+2d: SUB rAX,Iz
+2e: SEG=CS (Prefix)
+2f: DAS (i64)
+# 0x30 - 0x3f
+30: XOR Eb,Gb
+31: XOR Ev,Gv
+32: XOR Gb,Eb
+33: XOR Gv,Ev
+34: XOR AL,Ib
+35: XOR rAX,Iz
+36: SEG=SS (Prefix)
+37: AAA (i64)
+38: CMP Eb,Gb
+39: CMP Ev,Gv
+3a: CMP Gb,Eb
+3b: CMP Gv,Ev
+3c: CMP AL,Ib
+3d: CMP rAX,Iz
+3e: SEG=DS (Prefix)
+3f: AAS (i64)
+# 0x40 - 0x4f
+40: INC eAX (i64) | REX (o64)
+41: INC eCX (i64) | REX.B (o64)
+42: INC eDX (i64) | REX.X (o64)
+43: INC eBX (i64) | REX.XB (o64)
+44: INC eSP (i64) | REX.R (o64)
+45: INC eBP (i64) | REX.RB (o64)
+46: INC eSI (i64) | REX.RX (o64)
+47: INC eDI (i64) | REX.RXB (o64)
+48: DEC eAX (i64) | REX.W (o64)
+49: DEC eCX (i64) | REX.WB (o64)
+4a: DEC eDX (i64) | REX.WX (o64)
+4b: DEC eBX (i64) | REX.WXB (o64)
+4c: DEC eSP (i64) | REX.WR (o64)
+4d: DEC eBP (i64) | REX.WRB (o64)
+4e: DEC eSI (i64) | REX.WRX (o64)
+4f: DEC eDI (i64) | REX.WRXB (o64)
+# 0x50 - 0x5f
+50: PUSH rAX/r8 (d64)
+51: PUSH rCX/r9 (d64)
+52: PUSH rDX/r10 (d64)
+53: PUSH rBX/r11 (d64)
+54: PUSH rSP/r12 (d64)
+55: PUSH rBP/r13 (d64)
+56: PUSH rSI/r14 (d64)
+57: PUSH rDI/r15 (d64)
+58: POP rAX/r8 (d64)
+59: POP rCX/r9 (d64)
+5a: POP rDX/r10 (d64)
+5b: POP rBX/r11 (d64)
+5c: POP rSP/r12 (d64)
+5d: POP rBP/r13 (d64)
+5e: POP rSI/r14 (d64)
+5f: POP rDI/r15 (d64)
+# 0x60 - 0x6f
+60: PUSHA/PUSHAD (i64)
+61: POPA/POPAD (i64)
+62: BOUND Gv,Ma (i64)
+63: ARPL Ew,Gw (i64) | MOVSXD Gv,Ev (o64)
+64: SEG=FS (Prefix)
+65: SEG=GS (Prefix)
+66: Operand-Size (Prefix)
+67: Address-Size (Prefix)
+68: PUSH Iz (d64)
+69: IMUL Gv,Ev,Iz
+6a: PUSH Ib (d64)
+6b: IMUL Gv,Ev,Ib
+6c: INS/INSB Yb,DX
+6d: INS/INSW/INSD Yz,DX
+6e: OUTS/OUTSB DX,Xb
+6f: OUTS/OUTSW/OUTSD DX,Xz
+# 0x70 - 0x7f
+70: JO Jb
+71: JNO Jb
+72: JB/JNAE/JC Jb
+73: JNB/JAE/JNC Jb
+74: JZ/JE Jb
+75: JNZ/JNE Jb
+76: JBE/JNA Jb
+77: JNBE/JA Jb
+78: JS Jb
+79: JNS Jb
+7a: JP/JPE Jb
+7b: JNP/JPO Jb
+7c: JL/JNGE Jb
+7d: JNL/JGE Jb
+7e: JLE/JNG Jb
+7f: JNLE/JG Jb
+# 0x80 - 0x8f
+80: Grp1 Eb,Ib (1A)
+81: Grp1 Ev,Iz (1A)
+82: Grp1 Eb,Ib (1A),(i64)
+83: Grp1 Ev,Ib (1A)
+84: TEST Eb,Gb
+85: TEST Ev,Gv
+86: XCHG Eb,Gb
+87: XCHG Ev,Gv
+88: MOV Eb,Gb
+89: MOV Ev,Gv
+8a: MOV Gb,Eb
+8b: MOV Gv,Ev
+8c: MOV Ev,Sw
+8d: LEA Gv,M
+8e: MOV Sw,Ew
+8f: Grp1A (1A) | POP Ev (d64)
+# 0x90 - 0x9f
+90: NOP | PAUSE (F3) | XCHG r8,rAX
+91: XCHG rCX/r9,rAX
+92: XCHG rDX/r10,rAX
+93: XCHG rBX/r11,rAX
+94: XCHG rSP/r12,rAX
+95: XCHG rBP/r13,rAX
+96: XCHG rSI/r14,rAX
+97: XCHG rDI/r15,rAX
+98: CBW/CWDE/CDQE
+99: CWD/CDQ/CQO
+9a: CALLF Ap (i64)
+9b: FWAIT/WAIT
+9c: PUSHF/D/Q Fv (d64)
+9d: POPF/D/Q Fv (d64)
+9e: SAHF
+9f: LAHF
+# 0xa0 - 0xaf
+a0: MOV AL,Ob
+a1: MOV rAX,Ov
+a2: MOV Ob,AL
+a3: MOV Ov,rAX
+a4: MOVS/B Xb,Yb
+a5: MOVS/W/D/Q Xv,Yv
+a6: CMPS/B Xb,Yb
+a7: CMPS/W/D Xv,Yv
+a8: TEST AL,Ib
+a9: TEST rAX,Iz
+aa: STOS/B Yb,AL
+ab: STOS/W/D/Q Yv,rAX
+ac: LODS/B AL,Xb
+ad: LODS/W/D/Q rAX,Xv
+ae: SCAS/B AL,Yb
+af: SCAS/W/D/Q rAX,Xv
+# 0xb0 - 0xbf
+b0: MOV AL/R8L,Ib
+b1: MOV CL/R9L,Ib
+b2: MOV DL/R10L,Ib
+b3: MOV BL/R11L,Ib
+b4: MOV AH/R12L,Ib
+b5: MOV CH/R13L,Ib
+b6: MOV DH/R14L,Ib
+b7: MOV BH/R15L,Ib
+b8: MOV rAX/r8,Iv
+b9: MOV rCX/r9,Iv
+ba: MOV rDX/r10,Iv
+bb: MOV rBX/r11,Iv
+bc: MOV rSP/r12,Iv
+bd: MOV rBP/r13,Iv
+be: MOV rSI/r14,Iv
+bf: MOV rDI/r15,Iv
+# 0xc0 - 0xcf
+c0: Grp2 Eb,Ib (1A)
+c1: Grp2 Ev,Ib (1A)
+c2: RETN Iw (f64)
+c3: RETN
+c4: LES Gz,Mp (i64) | 3bytes-VEX (Prefix)
+c5: LDS Gz,Mp (i64) | 2bytes-VEX (Prefix)
+c6: Grp11 Eb,Ib (1A)
+c7: Grp11 Ev,Iz (1A)
+c8: ENTER Iw,Ib
+c9: LEAVE (d64)
+ca: RETF Iw
+cb: RETF
+cc: INT3
+cd: INT Ib
+ce: INTO (i64)
+cf: IRET/D/Q
+# 0xd0 - 0xdf
+d0: Grp2 Eb,1 (1A)
+d1: Grp2 Ev,1 (1A)
+d2: Grp2 Eb,CL (1A)
+d3: Grp2 Ev,CL (1A)
+d4: AAM Ib (i64)
+d5: AAD Ib (i64)
+d6:
+d7: XLAT/XLATB
+d8: ESC
+d9: ESC
+da: ESC
+db: ESC
+dc: ESC
+dd: ESC
+de: ESC
+df: ESC
+# 0xe0 - 0xef
+e0: LOOPNE/LOOPNZ Jb (f64)
+e1: LOOPE/LOOPZ Jb (f64)
+e2: LOOP Jb (f64)
+e3: JrCXZ Jb (f64)
+e4: IN AL,Ib
+e5: IN eAX,Ib
+e6: OUT Ib,AL
+e7: OUT Ib,eAX
+e8: CALL Jz (f64)
+e9: JMP-near Jz (f64)
+ea: JMP-far Ap (i64)
+eb: JMP-short Jb (f64)
+ec: IN AL,DX
+ed: IN eAX,DX
+ee: OUT DX,AL
+ef: OUT DX,eAX
+# 0xf0 - 0xff
+f0: LOCK (Prefix)
+f1:
+f2: REPNE (Prefix)
+f3: REP/REPE (Prefix)
+f4: HLT
+f5: CMC
+f6: Grp3_1 Eb (1A)
+f7: Grp3_2 Ev (1A)
+f8: CLC
+f9: STC
+fa: CLI
+fb: STI
+fc: CLD
+fd: STD
+fe: Grp4 (1A)
+ff: Grp5 (1A)
+EndTable
+
+Table: 2-byte opcode (0x0f)
+Referrer: 2-byte escape
+AVXcode: 1
+# 0x0f 0x00-0x0f
+00: Grp6 (1A)
+01: Grp7 (1A)
+02: LAR Gv,Ew
+03: LSL Gv,Ew
+04:
+05: SYSCALL (o64)
+06: CLTS
+07: SYSRET (o64)
+08: INVD
+09: WBINVD
+0a:
+0b: UD2 (1B)
+0c:
+0d: NOP Ev | GrpP
+0e: FEMMS
+# 3DNow! uses the last imm byte as opcode extension.
+0f: 3DNow! Pq,Qq,Ib
+# 0x0f 0x10-0x1f
+10: movups Vps,Wps (VEX) | movss Vss,Wss (F3),(VEX),(o128) | movupd Vpd,Wpd (66),(VEX) | movsd Vsd,Wsd (F2),(VEX),(o128)
+11: movups Wps,Vps (VEX) | movss Wss,Vss (F3),(VEX),(o128) | movupd Wpd,Vpd (66),(VEX) | movsd Wsd,Vsd (F2),(VEX),(o128)
+12: movlps Vq,Mq (VEX),(o128) | movlpd Vq,Mq (66),(VEX),(o128) | movhlps Vq,Uq (VEX),(o128) | movddup Vq,Wq (F2),(VEX) | movsldup Vq,Wq (F3),(VEX)
+13: mpvlps Mq,Vq (VEX),(o128) | movlpd Mq,Vq (66),(VEX),(o128)
+14: unpcklps Vps,Wq (VEX) | unpcklpd Vpd,Wq (66),(VEX)
+15: unpckhps Vps,Wq (VEX) | unpckhpd Vpd,Wq (66),(VEX)
+16: movhps Vq,Mq (VEX),(o128) | movhpd Vq,Mq (66),(VEX),(o128) | movlsps Vq,Uq (VEX),(o128) | movshdup Vq,Wq (F3),(VEX)
+17: movhps Mq,Vq (VEX),(o128) | movhpd Mq,Vq (66),(VEX),(o128)
+18: Grp16 (1A)
+19:
+1a:
+1b:
+1c:
+1d:
+1e:
+1f: NOP Ev
+# 0x0f 0x20-0x2f
+20: MOV Rd,Cd
+21: MOV Rd,Dd
+22: MOV Cd,Rd
+23: MOV Dd,Rd
+24:
+25:
+26:
+27:
+28: movaps Vps,Wps (VEX) | movapd Vpd,Wpd (66),(VEX)
+29: movaps Wps,Vps (VEX) | movapd Wpd,Vpd (66),(VEX)
+2a: cvtpi2ps Vps,Qpi | cvtsi2ss Vss,Ed/q (F3),(VEX),(o128) | cvtpi2pd Vpd,Qpi (66) | cvtsi2sd Vsd,Ed/q (F2),(VEX),(o128)
+2b: movntps Mps,Vps (VEX) | movntpd Mpd,Vpd (66),(VEX)
+2c: cvttps2pi Ppi,Wps | cvttss2si  Gd/q,Wss (F3),(VEX),(o128) | cvttpd2pi Ppi,Wpd (66) | cvttsd2si Gd/q,Wsd (F2),(VEX),(o128)
+2d: cvtps2pi Ppi,Wps | cvtss2si Gd/q,Wss (F3),(VEX),(o128) | cvtpd2pi Qpi,Wpd (66) | cvtsd2si Gd/q,Wsd (F2),(VEX),(o128)
+2e: ucomiss Vss,Wss (VEX),(o128) | ucomisd  Vsd,Wsd (66),(VEX),(o128)
+2f: comiss Vss,Wss (VEX),(o128) | comisd  Vsd,Wsd (66),(VEX),(o128)
+# 0x0f 0x30-0x3f
+30: WRMSR
+31: RDTSC
+32: RDMSR
+33: RDPMC
+34: SYSENTER
+35: SYSEXIT
+36:
+37: GETSEC
+38: escape # 3-byte escape 1
+39:
+3a: escape # 3-byte escape 2
+3b:
+3c:
+3d:
+3e:
+3f:
+# 0x0f 0x40-0x4f
+40: CMOVO Gv,Ev
+41: CMOVNO Gv,Ev
+42: CMOVB/C/NAE Gv,Ev
+43: CMOVAE/NB/NC Gv,Ev
+44: CMOVE/Z Gv,Ev
+45: CMOVNE/NZ Gv,Ev
+46: CMOVBE/NA Gv,Ev
+47: CMOVA/NBE Gv,Ev
+48: CMOVS Gv,Ev
+49: CMOVNS Gv,Ev
+4a: CMOVP/PE Gv,Ev
+4b: CMOVNP/PO Gv,Ev
+4c: CMOVL/NGE Gv,Ev
+4d: CMOVNL/GE Gv,Ev
+4e: CMOVLE/NG Gv,Ev
+4f: CMOVNLE/G Gv,Ev
+# 0x0f 0x50-0x5f
+50: movmskps Gd/q,Ups (VEX) | movmskpd Gd/q,Upd (66),(VEX)
+51: sqrtps Vps,Wps (VEX) | sqrtss Vss,Wss (F3),(VEX),(o128) | sqrtpd Vpd,Wpd (66),(VEX) | sqrtsd Vsd,Wsd (F2),(VEX),(o128)
+52: rsqrtps Vps,Wps (VEX) | rsqrtss Vss,Wss (F3),(VEX),(o128)
+53: rcpps Vps,Wps (VEX) | rcpss Vss,Wss (F3),(VEX),(o128)
+54: andps Vps,Wps (VEX) | andpd Vpd,Wpd (66),(VEX)
+55: andnps Vps,Wps (VEX) | andnpd Vpd,Wpd (66),(VEX)
+56: orps Vps,Wps (VEX) | orpd Vpd,Wpd (66),(VEX)
+57: xorps Vps,Wps (VEX) | xorpd Vpd,Wpd (66),(VEX)
+58: addps Vps,Wps (VEX) | addss Vss,Wss (F3),(VEX),(o128) | addpd Vpd,Wpd (66),(VEX) | addsd Vsd,Wsd (F2),(VEX),(o128)
+59: mulps Vps,Wps (VEX) | mulss Vss,Wss (F3),(VEX),(o128) | mulpd Vpd,Wpd (66),(VEX) | mulsd Vsd,Wsd (F2),(VEX),(o128)
+5a: cvtps2pd Vpd,Wps (VEX) | cvtss2sd Vsd,Wss (F3),(VEX),(o128) | cvtpd2ps Vps,Wpd (66),(VEX) | cvtsd2ss Vsd,Wsd (F2),(VEX),(o128)
+5b: cvtdq2ps Vps,Wdq (VEX) | cvtps2dq Vdq,Wps (66),(VEX) | cvttps2dq Vdq,Wps (F3),(VEX)
+5c: subps Vps,Wps (VEX) | subss Vss,Wss (F3),(VEX),(o128) | subpd Vpd,Wpd (66),(VEX) | subsd Vsd,Wsd (F2),(VEX),(o128)
+5d: minps Vps,Wps (VEX) | minss Vss,Wss (F3),(VEX),(o128) | minpd Vpd,Wpd (66),(VEX) | minsd Vsd,Wsd (F2),(VEX),(o128)
+5e: divps Vps,Wps (VEX) | divss Vss,Wss (F3),(VEX),(o128) | divpd Vpd,Wpd (66),(VEX) | divsd Vsd,Wsd (F2),(VEX),(o128)
+5f: maxps Vps,Wps (VEX) | maxss Vss,Wss (F3),(VEX),(o128) | maxpd Vpd,Wpd (66),(VEX) | maxsd Vsd,Wsd (F2),(VEX),(o128)
+# 0x0f 0x60-0x6f
+60: punpcklbw Pq,Qd | punpcklbw Vdq,Wdq (66),(VEX),(o128)
+61: punpcklwd Pq,Qd | punpcklwd Vdq,Wdq (66),(VEX),(o128)
+62: punpckldq Pq,Qd | punpckldq Vdq,Wdq (66),(VEX),(o128)
+63: packsswb Pq,Qq | packsswb Vdq,Wdq (66),(VEX),(o128)
+64: pcmpgtb Pq,Qq | pcmpgtb Vdq,Wdq (66),(VEX),(o128)
+65: pcmpgtw Pq,Qq | pcmpgtw Vdq,Wdq (66),(VEX),(o128)
+66: pcmpgtd Pq,Qq | pcmpgtd Vdq,Wdq (66),(VEX),(o128)
+67: packuswb Pq,Qq | packuswb Vdq,Wdq (66),(VEX),(o128)
+68: punpckhbw Pq,Qd | punpckhbw Vdq,Wdq (66),(VEX),(o128)
+69: punpckhwd Pq,Qd | punpckhwd Vdq,Wdq (66),(VEX),(o128)
+6a: punpckhdq Pq,Qd | punpckhdq Vdq,Wdq (66),(VEX),(o128)
+6b: packssdw Pq,Qd | packssdw Vdq,Wdq (66),(VEX),(o128)
+6c: punpcklqdq Vdq,Wdq (66),(VEX),(o128)
+6d: punpckhqdq Vdq,Wdq (66),(VEX),(o128)
+6e: movd/q/ Pd,Ed/q | movd/q Vdq,Ed/q (66),(VEX),(o128)
+6f: movq Pq,Qq | movdqa Vdq,Wdq (66),(VEX) | movdqu Vdq,Wdq (F3),(VEX)
+# 0x0f 0x70-0x7f
+70: pshufw Pq,Qq,Ib | pshufd Vdq,Wdq,Ib (66),(VEX),(o128) | pshufhw Vdq,Wdq,Ib (F3),(VEX),(o128) | pshuflw VdqWdq,Ib (F2),(VEX),(o128)
+71: Grp12 (1A)
+72: Grp13 (1A)
+73: Grp14 (1A)
+74: pcmpeqb Pq,Qq | pcmpeqb Vdq,Wdq (66),(VEX),(o128)
+75: pcmpeqw Pq,Qq | pcmpeqw Vdq,Wdq (66),(VEX),(o128)
+76: pcmpeqd Pq,Qq | pcmpeqd Vdq,Wdq (66),(VEX),(o128)
+77: emms/vzeroupper/vzeroall (VEX)
+78: VMREAD Ed/q,Gd/q
+79: VMWRITE Gd/q,Ed/q
+7a:
+7b:
+7c: haddps Vps,Wps (F2),(VEX) | haddpd Vpd,Wpd (66),(VEX)
+7d: hsubps Vps,Wps (F2),(VEX) | hsubpd Vpd,Wpd (66),(VEX)
+7e: movd/q Ed/q,Pd | movd/q Ed/q,Vdq (66),(VEX),(o128) | movq Vq,Wq (F3),(VEX),(o128)
+7f: movq Qq,Pq | movdqa Wdq,Vdq (66),(VEX) | movdqu Wdq,Vdq (F3),(VEX)
+# 0x0f 0x80-0x8f
+80: JO Jz (f64)
+81: JNO Jz (f64)
+82: JB/JNAE/JC Jz (f64)
+83: JNB/JAE/JNC Jz (f64)
+84: JZ/JE Jz (f64)
+85: JNZ/JNE Jz (f64)
+86: JBE/JNA Jz (f64)
+87: JNBE/JA Jz (f64)
+88: JS Jz (f64)
+89: JNS Jz (f64)
+8a: JP/JPE Jz (f64)
+8b: JNP/JPO Jz (f64)
+8c: JL/JNGE Jz (f64)
+8d: JNL/JGE Jz (f64)
+8e: JLE/JNG Jz (f64)
+8f: JNLE/JG Jz (f64)
+# 0x0f 0x90-0x9f
+90: SETO Eb
+91: SETNO Eb
+92: SETB/C/NAE Eb
+93: SETAE/NB/NC Eb
+94: SETE/Z Eb
+95: SETNE/NZ Eb
+96: SETBE/NA Eb
+97: SETA/NBE Eb
+98: SETS Eb
+99: SETNS Eb
+9a: SETP/PE Eb
+9b: SETNP/PO Eb
+9c: SETL/NGE Eb
+9d: SETNL/GE Eb
+9e: SETLE/NG Eb
+9f: SETNLE/G Eb
+# 0x0f 0xa0-0xaf
+a0: PUSH FS (d64)
+a1: POP FS (d64)
+a2: CPUID
+a3: BT Ev,Gv
+a4: SHLD Ev,Gv,Ib
+a5: SHLD Ev,Gv,CL
+a6: GrpPDLK
+a7: GrpRNG
+a8: PUSH GS (d64)
+a9: POP GS (d64)
+aa: RSM
+ab: BTS Ev,Gv
+ac: SHRD Ev,Gv,Ib
+ad: SHRD Ev,Gv,CL
+ae: Grp15 (1A),(1C)
+af: IMUL Gv,Ev
+# 0x0f 0xb0-0xbf
+b0: CMPXCHG Eb,Gb
+b1: CMPXCHG Ev,Gv
+b2: LSS Gv,Mp
+b3: BTR Ev,Gv
+b4: LFS Gv,Mp
+b5: LGS Gv,Mp
+b6: MOVZX Gv,Eb
+b7: MOVZX Gv,Ew
+b8: JMPE | POPCNT Gv,Ev (F3)
+b9: Grp10 (1A)
+ba: Grp8 Ev,Ib (1A)
+bb: BTC Ev,Gv
+bc: BSF Gv,Ev
+bd: BSR Gv,Ev
+be: MOVSX Gv,Eb
+bf: MOVSX Gv,Ew
+# 0x0f 0xc0-0xcf
+c0: XADD Eb,Gb
+c1: XADD Ev,Gv
+c2: cmpps Vps,Wps,Ib (VEX) | cmpss Vss,Wss,Ib (F3),(VEX),(o128) | cmppd Vpd,Wpd,Ib (66),(VEX) | cmpsd Vsd,Wsd,Ib (F2),(VEX)
+c3: movnti Md/q,Gd/q
+c4: pinsrw Pq,Rd/q/Mw,Ib | pinsrw Vdq,Rd/q/Mw,Ib (66),(VEX),(o128)
+c5: pextrw Gd,Nq,Ib | pextrw Gd,Udq,Ib (66),(VEX),(o128)
+c6: shufps Vps,Wps,Ib (VEX) | shufpd Vpd,Wpd,Ib (66),(VEX)
+c7: Grp9 (1A)
+c8: BSWAP RAX/EAX/R8/R8D
+c9: BSWAP RCX/ECX/R9/R9D
+ca: BSWAP RDX/EDX/R10/R10D
+cb: BSWAP RBX/EBX/R11/R11D
+cc: BSWAP RSP/ESP/R12/R12D
+cd: BSWAP RBP/EBP/R13/R13D
+ce: BSWAP RSI/ESI/R14/R14D
+cf: BSWAP RDI/EDI/R15/R15D
+# 0x0f 0xd0-0xdf
+d0: addsubps Vps,Wps (F2),(VEX) | addsubpd Vpd,Wpd (66),(VEX)
+d1: psrlw Pq,Qq | psrlw Vdq,Wdq (66),(VEX),(o128)
+d2: psrld Pq,Qq | psrld Vdq,Wdq (66),(VEX),(o128)
+d3: psrlq Pq,Qq | psrlq Vdq,Wdq (66),(VEX),(o128)
+d4: paddq Pq,Qq | paddq Vdq,Wdq (66),(VEX),(o128)
+d5: pmullw Pq,Qq | pmullw Vdq,Wdq (66),(VEX),(o128)
+d6: movq Wq,Vq (66),(VEX),(o128) | movq2dq Vdq,Nq (F3) | movdq2q Pq,Uq (F2)
+d7: pmovmskb Gd,Nq | pmovmskb Gd,Udq (66),(VEX),(o128)
+d8: psubusb Pq,Qq | psubusb Vdq,Wdq (66),(VEX),(o128)
+d9: psubusw Pq,Qq | psubusw Vdq,Wdq (66),(VEX),(o128)
+da: pminub Pq,Qq | pminub Vdq,Wdq (66),(VEX),(o128)
+db: pand Pq,Qq | pand Vdq,Wdq (66),(VEX),(o128)
+dc: paddusb Pq,Qq | paddusb Vdq,Wdq (66),(VEX),(o128)
+dd: paddusw Pq,Qq | paddusw Vdq,Wdq (66),(VEX),(o128)
+de: pmaxub Pq,Qq | pmaxub Vdq,Wdq (66),(VEX),(o128)
+df: pandn Pq,Qq | pandn Vdq,Wdq (66),(VEX),(o128)
+# 0x0f 0xe0-0xef
+e0: pavgb Pq,Qq | pavgb Vdq,Wdq (66),(VEX),(o128)
+e1: psraw Pq,Qq | psraw Vdq,Wdq (66),(VEX),(o128)
+e2: psrad Pq,Qq | psrad Vdq,Wdq (66),(VEX),(o128)
+e3: pavgw Pq,Qq | pavgw Vdq,Wdq (66),(VEX),(o128)
+e4: pmulhuw Pq,Qq | pmulhuw Vdq,Wdq (66),(VEX),(o128)
+e5: pmulhw Pq,Qq | pmulhw Vdq,Wdq (66),(VEX),(o128)
+e6: cvtpd2dq Vdq,Wpd (F2),(VEX) | cvttpd2dq Vdq,Wpd (66),(VEX) | cvtdq2pd Vpd,Wdq (F3),(VEX)
+e7: movntq Mq,Pq | movntdq Mdq,Vdq (66),(VEX)
+e8: psubsb Pq,Qq | psubsb Vdq,Wdq (66),(VEX),(o128)
+e9: psubsw Pq,Qq | psubsw Vdq,Wdq (66),(VEX),(o128)
+ea: pminsw Pq,Qq | pminsw Vdq,Wdq (66),(VEX),(o128)
+eb: por Pq,Qq | por Vdq,Wdq (66),(VEX),(o128)
+ec: paddsb Pq,Qq | paddsb Vdq,Wdq (66),(VEX),(o128)
+ed: paddsw Pq,Qq | paddsw Vdq,Wdq (66),(VEX),(o128)
+ee: pmaxsw Pq,Qq | pmaxsw Vdq,Wdq (66),(VEX),(o128)
+ef: pxor Pq,Qq | pxor Vdq,Wdq (66),(VEX),(o128)
+# 0x0f 0xf0-0xff
+f0: lddqu Vdq,Mdq (F2),(VEX)
+f1: psllw Pq,Qq | psllw Vdq,Wdq (66),(VEX),(o128)
+f2: pslld Pq,Qq | pslld Vdq,Wdq (66),(VEX),(o128)
+f3: psllq Pq,Qq | psllq Vdq,Wdq (66),(VEX),(o128)
+f4: pmuludq Pq,Qq | pmuludq Vdq,Wdq (66),(VEX),(o128)
+f5: pmaddwd Pq,Qq | pmaddwd Vdq,Wdq (66),(VEX),(o128)
+f6: psadbw Pq,Qq | psadbw Vdq,Wdq (66),(VEX),(o128)
+f7: maskmovq Pq,Nq | maskmovdqu Vdq,Udq (66),(VEX),(o128)
+f8: psubb Pq,Qq | psubb Vdq,Wdq (66),(VEX),(o128)
+f9: psubw Pq,Qq | psubw Vdq,Wdq (66),(VEX),(o128)
+fa: psubd Pq,Qq | psubd Vdq,Wdq (66),(VEX),(o128)
+fb: psubq Pq,Qq | psubq Vdq,Wdq (66),(VEX),(o128)
+fc: paddb Pq,Qq | paddb Vdq,Wdq (66),(VEX),(o128)
+fd: paddw Pq,Qq | paddw Vdq,Wdq (66),(VEX),(o128)
+fe: paddd Pq,Qq | paddd Vdq,Wdq (66),(VEX),(o128)
+ff:
+EndTable
+
+Table: 3-byte opcode 1 (0x0f 0x38)
+Referrer: 3-byte escape 1
+AVXcode: 2
+# 0x0f 0x38 0x00-0x0f
+00: pshufb Pq,Qq | pshufb Vdq,Wdq (66),(VEX),(o128)
+01: phaddw Pq,Qq | phaddw Vdq,Wdq (66),(VEX),(o128)
+02: phaddd Pq,Qq | phaddd Vdq,Wdq (66),(VEX),(o128)
+03: phaddsw Pq,Qq | phaddsw Vdq,Wdq (66),(VEX),(o128)
+04: pmaddubsw Pq,Qq | pmaddubsw Vdq,Wdq (66),(VEX),(o128)
+05: phsubw Pq,Qq | phsubw Vdq,Wdq (66),(VEX),(o128)
+06: phsubd Pq,Qq | phsubd Vdq,Wdq (66),(VEX),(o128)
+07: phsubsw Pq,Qq | phsubsw Vdq,Wdq (66),(VEX),(o128)
+08: psignb Pq,Qq | psignb Vdq,Wdq (66),(VEX),(o128)
+09: psignw Pq,Qq | psignw Vdq,Wdq (66),(VEX),(o128)
+0a: psignd Pq,Qq | psignd Vdq,Wdq (66),(VEX),(o128)
+0b: pmulhrsw Pq,Qq | pmulhrsw Vdq,Wdq (66),(VEX),(o128)
+0c: Vpermilps /r (66),(oVEX)
+0d: Vpermilpd /r (66),(oVEX)
+0e: vtestps /r (66),(oVEX)
+0f: vtestpd /r (66),(oVEX)
+# 0x0f 0x38 0x10-0x1f
+10: pblendvb Vdq,Wdq (66)
+11:
+12:
+13:
+14: blendvps Vdq,Wdq (66)
+15: blendvpd Vdq,Wdq (66)
+16:
+17: ptest Vdq,Wdq (66),(VEX)
+18: vbroadcastss /r (66),(oVEX)
+19: vbroadcastsd /r (66),(oVEX),(o256)
+1a: vbroadcastf128 /r (66),(oVEX),(o256)
+1b:
+1c: pabsb Pq,Qq | pabsb Vdq,Wdq (66),(VEX),(o128)
+1d: pabsw Pq,Qq | pabsw Vdq,Wdq (66),(VEX),(o128)
+1e: pabsd Pq,Qq | pabsd Vdq,Wdq (66),(VEX),(o128)
+1f:
+# 0x0f 0x38 0x20-0x2f
+20: pmovsxbw Vdq,Udq/Mq (66),(VEX),(o128)
+21: pmovsxbd Vdq,Udq/Md (66),(VEX),(o128)
+22: pmovsxbq Vdq,Udq/Mw (66),(VEX),(o128)
+23: pmovsxwd Vdq,Udq/Mq (66),(VEX),(o128)
+24: pmovsxwq Vdq,Udq/Md (66),(VEX),(o128)
+25: pmovsxdq Vdq,Udq/Mq (66),(VEX),(o128)
+26:
+27:
+28: pmuldq Vdq,Wdq (66),(VEX),(o128)
+29: pcmpeqq Vdq,Wdq (66),(VEX),(o128)
+2a: movntdqa Vdq,Mdq (66),(VEX),(o128)
+2b: packusdw Vdq,Wdq (66),(VEX),(o128)
+2c: vmaskmovps(ld) /r (66),(oVEX)
+2d: vmaskmovpd(ld) /r (66),(oVEX)
+2e: vmaskmovps(st) /r (66),(oVEX)
+2f: vmaskmovpd(st) /r (66),(oVEX)
+# 0x0f 0x38 0x30-0x3f
+30: pmovzxbw Vdq,Udq/Mq (66),(VEX),(o128)
+31: pmovzxbd Vdq,Udq/Md (66),(VEX),(o128)
+32: pmovzxbq Vdq,Udq/Mw (66),(VEX),(o128)
+33: pmovzxwd Vdq,Udq/Mq (66),(VEX),(o128)
+34: pmovzxwq Vdq,Udq/Md (66),(VEX),(o128)
+35: pmovzxdq Vdq,Udq/Mq (66),(VEX),(o128)
+36:
+37: pcmpgtq Vdq,Wdq (66),(VEX),(o128)
+38: pminsb Vdq,Wdq (66),(VEX),(o128)
+39: pminsd Vdq,Wdq (66),(VEX),(o128)
+3a: pminuw Vdq,Wdq (66),(VEX),(o128)
+3b: pminud Vdq,Wdq (66),(VEX),(o128)
+3c: pmaxsb Vdq,Wdq (66),(VEX),(o128)
+3d: pmaxsd Vdq,Wdq (66),(VEX),(o128)
+3e: pmaxuw Vdq,Wdq (66),(VEX),(o128)
+3f: pmaxud Vdq,Wdq (66),(VEX),(o128)
+# 0x0f 0x38 0x40-0x8f
+40: pmulld Vdq,Wdq (66),(VEX),(o128)
+41: phminposuw Vdq,Wdq (66),(VEX),(o128)
+80: INVEPT Gd/q,Mdq (66)
+81: INVPID Gd/q,Mdq (66)
+# 0x0f 0x38 0x90-0xbf (FMA)
+96: vfmaddsub132pd/ps /r (66),(VEX)
+97: vfmsubadd132pd/ps /r (66),(VEX)
+98: vfmadd132pd/ps /r (66),(VEX)
+99: vfmadd132sd/ss /r (66),(VEX),(o128)
+9a: vfmsub132pd/ps /r (66),(VEX)
+9b: vfmsub132sd/ss /r (66),(VEX),(o128)
+9c: vfnmadd132pd/ps /r (66),(VEX)
+9d: vfnmadd132sd/ss /r (66),(VEX),(o128)
+9e: vfnmsub132pd/ps /r (66),(VEX)
+9f: vfnmsub132sd/ss /r (66),(VEX),(o128)
+a6: vfmaddsub213pd/ps /r (66),(VEX)
+a7: vfmsubadd213pd/ps /r (66),(VEX)
+a8: vfmadd213pd/ps /r (66),(VEX)
+a9: vfmadd213sd/ss /r (66),(VEX),(o128)
+aa: vfmsub213pd/ps /r (66),(VEX)
+ab: vfmsub213sd/ss /r (66),(VEX),(o128)
+ac: vfnmadd213pd/ps /r (66),(VEX)
+ad: vfnmadd213sd/ss /r (66),(VEX),(o128)
+ae: vfnmsub213pd/ps /r (66),(VEX)
+af: vfnmsub213sd/ss /r (66),(VEX),(o128)
+b6: vfmaddsub231pd/ps /r (66),(VEX)
+b7: vfmsubadd231pd/ps /r (66),(VEX)
+b8: vfmadd231pd/ps /r (66),(VEX)
+b9: vfmadd231sd/ss /r (66),(VEX),(o128)
+ba: vfmsub231pd/ps /r (66),(VEX)
+bb: vfmsub231sd/ss /r (66),(VEX),(o128)
+bc: vfnmadd231pd/ps /r (66),(VEX)
+bd: vfnmadd231sd/ss /r (66),(VEX),(o128)
+be: vfnmsub231pd/ps /r (66),(VEX)
+bf: vfnmsub231sd/ss /r (66),(VEX),(o128)
+# 0x0f 0x38 0xc0-0xff
+db: aesimc Vdq,Wdq (66),(VEX),(o128)
+dc: aesenc Vdq,Wdq (66),(VEX),(o128)
+dd: aesenclast Vdq,Wdq (66),(VEX),(o128)
+de: aesdec Vdq,Wdq (66),(VEX),(o128)
+df: aesdeclast Vdq,Wdq (66),(VEX),(o128)
+f0: MOVBE Gv,Mv | CRC32 Gd,Eb (F2)
+f1: MOVBE Mv,Gv | CRC32 Gd,Ev (F2)
+EndTable
+
+Table: 3-byte opcode 2 (0x0f 0x3a)
+Referrer: 3-byte escape 2
+AVXcode: 3
+# 0x0f 0x3a 0x00-0xff
+04: vpermilps /r,Ib (66),(oVEX)
+05: vpermilpd /r,Ib (66),(oVEX)
+06: vperm2f128 /r,Ib (66),(oVEX),(o256)
+08: roundps Vdq,Wdq,Ib (66),(VEX)
+09: roundpd Vdq,Wdq,Ib (66),(VEX)
+0a: roundss Vss,Wss,Ib (66),(VEX),(o128)
+0b: roundsd Vsd,Wsd,Ib (66),(VEX),(o128)
+0c: blendps Vdq,Wdq,Ib (66),(VEX)
+0d: blendpd Vdq,Wdq,Ib (66),(VEX)
+0e: pblendw Vdq,Wdq,Ib (66),(VEX),(o128)
+0f: palignr Pq,Qq,Ib | palignr Vdq,Wdq,Ib (66),(VEX),(o128)
+14: pextrb Rd/Mb,Vdq,Ib (66),(VEX),(o128)
+15: pextrw Rd/Mw,Vdq,Ib (66),(VEX),(o128)
+16: pextrd/pextrq Ed/q,Vdq,Ib (66),(VEX),(o128)
+17: extractps Ed,Vdq,Ib (66),(VEX),(o128)
+18: vinsertf128 /r,Ib (66),(oVEX),(o256)
+19: vextractf128 /r,Ib (66),(oVEX),(o256)
+20: pinsrb Vdq,Rd/q/Mb,Ib (66),(VEX),(o128)
+21: insertps Vdq,Udq/Md,Ib (66),(VEX),(o128)
+22: pinsrd/pinsrq Vdq,Ed/q,Ib (66),(VEX),(o128)
+40: dpps Vdq,Wdq,Ib (66),(VEX)
+41: dppd Vdq,Wdq,Ib (66),(VEX),(o128)
+42: mpsadbw Vdq,Wdq,Ib (66),(VEX),(o128)
+44: pclmulq Vdq,Wdq,Ib (66),(VEX),(o128)
+4a: vblendvps /r,Ib (66),(oVEX)
+4b: vblendvpd /r,Ib (66),(oVEX)
+4c: vpblendvb /r,Ib (66),(oVEX),(o128)
+60: pcmpestrm Vdq,Wdq,Ib (66),(VEX),(o128)
+61: pcmpestri Vdq,Wdq,Ib (66),(VEX),(o128)
+62: pcmpistrm Vdq,Wdq,Ib (66),(VEX),(o128)
+63: pcmpistri Vdq,Wdq,Ib (66),(VEX),(o128)
+df: aeskeygenassist Vdq,Wdq,Ib (66),(VEX),(o128)
+EndTable
+
+GrpTable: Grp1
+0: ADD
+1: OR
+2: ADC
+3: SBB
+4: AND
+5: SUB
+6: XOR
+7: CMP
+EndTable
+
+GrpTable: Grp1A
+0: POP
+EndTable
+
+GrpTable: Grp2
+0: ROL
+1: ROR
+2: RCL
+3: RCR
+4: SHL/SAL
+5: SHR
+6:
+7: SAR
+EndTable
+
+GrpTable: Grp3_1
+0: TEST Eb,Ib
+1:
+2: NOT Eb
+3: NEG Eb
+4: MUL AL,Eb
+5: IMUL AL,Eb
+6: DIV AL,Eb
+7: IDIV AL,Eb
+EndTable
+
+GrpTable: Grp3_2
+0: TEST Ev,Iz
+1:
+2: NOT Ev
+3: NEG Ev
+4: MUL rAX,Ev
+5: IMUL rAX,Ev
+6: DIV rAX,Ev
+7: IDIV rAX,Ev
+EndTable
+
+GrpTable: Grp4
+0: INC Eb
+1: DEC Eb
+EndTable
+
+GrpTable: Grp5
+0: INC Ev
+1: DEC Ev
+2: CALLN Ev (f64)
+3: CALLF Ep
+4: JMPN Ev (f64)
+5: JMPF Ep
+6: PUSH Ev (d64)
+7:
+EndTable
+
+GrpTable: Grp6
+0: SLDT Rv/Mw
+1: STR Rv/Mw
+2: LLDT Ew
+3: LTR Ew
+4: VERR Ew
+5: VERW Ew
+EndTable
+
+GrpTable: Grp7
+0: SGDT Ms | VMCALL (001),(11B) | VMLAUNCH (010),(11B) | VMRESUME (011),(11B) | VMXOFF (100),(11B)
+1: SIDT Ms | MONITOR (000),(11B) | MWAIT (001)
+2: LGDT Ms | XGETBV (000),(11B) | XSETBV (001),(11B)
+3: LIDT Ms
+4: SMSW Mw/Rv
+5:
+6: LMSW Ew
+7: INVLPG Mb | SWAPGS (o64),(000),(11B) | RDTSCP (001),(11B)
+EndTable
+
+GrpTable: Grp8
+4: BT
+5: BTS
+6: BTR
+7: BTC
+EndTable
+
+GrpTable: Grp9
+1: CMPXCHG8B/16B Mq/Mdq
+6: VMPTRLD Mq | VMCLEAR Mq (66) | VMXON Mq (F3)
+7: VMPTRST Mq
+EndTable
+
+GrpTable: Grp10
+EndTable
+
+GrpTable: Grp11
+0: MOV
+EndTable
+
+GrpTable: Grp12
+2: psrlw Nq,Ib (11B) | psrlw Udq,Ib (66),(11B),(VEX),(o128)
+4: psraw Nq,Ib (11B) | psraw Udq,Ib (66),(11B),(VEX),(o128)
+6: psllw Nq,Ib (11B) | psllw Udq,Ib (66),(11B),(VEX),(o128)
+EndTable
+
+GrpTable: Grp13
+2: psrld Nq,Ib (11B) | psrld Udq,Ib (66),(11B),(VEX),(o128)
+4: psrad Nq,Ib (11B) | psrad Udq,Ib (66),(11B),(VEX),(o128)
+6: pslld Nq,Ib (11B) | pslld Udq,Ib (66),(11B),(VEX),(o128)
+EndTable
+
+GrpTable: Grp14
+2: psrlq Nq,Ib (11B) | psrlq Udq,Ib (66),(11B),(VEX),(o128)
+3: psrldq Udq,Ib (66),(11B),(VEX),(o128)
+6: psllq Nq,Ib (11B) | psllq Udq,Ib (66),(11B),(VEX),(o128)
+7: pslldq Udq,Ib (66),(11B),(VEX),(o128)
+EndTable
+
+GrpTable: Grp15
+0: fxsave
+1: fxstor
+2: ldmxcsr (VEX)
+3: stmxcsr (VEX)
+4: XSAVE
+5: XRSTOR | lfence (11B)
+6: mfence (11B)
+7: clflush | sfence (11B)
+EndTable
+
+GrpTable: Grp16
+0: prefetch NTA
+1: prefetch T0
+2: prefetch T1
+3: prefetch T2
+EndTable
+
+# AMD's Prefetch Group
+GrpTable: GrpP
+0: PREFETCH
+1: PREFETCHW
+EndTable
+
+GrpTable: GrpPDLK
+0: MONTMUL
+1: XSHA1
+2: XSHA2
+EndTable
+
+GrpTable: GrpRNG
+0: xstore-rng
+1: xcrypt-ecb
+2: xcrypt-cbc
+4: xcrypt-cfb
+5: xcrypt-ofb
+EndTable
index 61b41ca..d0474ad 100644 (file)
@@ -35,34 +35,3 @@ int fixup_exception(struct pt_regs *regs)
 
        return 0;
 }
-
-#ifdef CONFIG_X86_64
-/*
- * Need to defined our own search_extable on X86_64 to work around
- * a B stepping K8 bug.
- */
-const struct exception_table_entry *
-search_extable(const struct exception_table_entry *first,
-              const struct exception_table_entry *last,
-              unsigned long value)
-{
-       /* B stepping K8 bug */
-       if ((value >> 32) == 0)
-               value |= 0xffffffffUL << 32;
-
-       while (first <= last) {
-               const struct exception_table_entry *mid;
-               long diff;
-
-               mid = (last - first) / 2 + first;
-               diff = mid->insn - value;
-               if (diff == 0)
-                       return mid;
-               else if (diff < 0)
-                       first = mid+1;
-               else
-                       last = mid-1;
-       }
-       return NULL;
-}
-#endif
index f4cee90..f627779 100644 (file)
@@ -38,7 +38,8 @@ enum x86_pf_error_code {
  * Returns 0 if mmiotrace is disabled, or if the fault is not
  * handled by mmiotrace:
  */
-static inline int kmmio_fault(struct pt_regs *regs, unsigned long addr)
+static inline int __kprobes
+kmmio_fault(struct pt_regs *regs, unsigned long addr)
 {
        if (unlikely(is_kmmio_active()))
                if (kmmio_handler(regs, addr) == 1)
@@ -46,7 +47,7 @@ static inline int kmmio_fault(struct pt_regs *regs, unsigned long addr)
        return 0;
 }
 
-static inline int notify_page_fault(struct pt_regs *regs)
+static inline int __kprobes notify_page_fault(struct pt_regs *regs)
 {
        int ret = 0;
 
@@ -240,7 +241,7 @@ void vmalloc_sync_all(void)
  *
  *   Handle a fault on the vmalloc or module mapping area
  */
-static noinline int vmalloc_fault(unsigned long address)
+static noinline __kprobes int vmalloc_fault(unsigned long address)
 {
        unsigned long pgd_paddr;
        pmd_t *pmd_k;
@@ -357,7 +358,7 @@ void vmalloc_sync_all(void)
  *
  * This assumes no large pages in there.
  */
-static noinline int vmalloc_fault(unsigned long address)
+static noinline __kprobes int vmalloc_fault(unsigned long address)
 {
        pgd_t *pgd, *pgd_ref;
        pud_t *pud, *pud_ref;
@@ -658,7 +659,7 @@ no_context(struct pt_regs *regs, unsigned long error_code,
        show_fault_oops(regs, error_code, address);
 
        stackend = end_of_stack(tsk);
-       if (*stackend != STACK_END_MAGIC)
+       if (tsk != &init_task && *stackend != STACK_END_MAGIC)
                printk(KERN_ALERT "Thread overran stack, or stack corrupted\n");
 
        tsk->thread.cr2         = address;
@@ -860,7 +861,7 @@ static int spurious_fault_check(unsigned long error_code, pte_t *pte)
  * There are no security implications to leaving a stale TLB when
  * increasing the permissions on a page.
  */
-static noinline int
+static noinline __kprobes int
 spurious_fault(unsigned long error_code, unsigned long address)
 {
        pgd_t *pgd;
index 16ccbd7..11a4ad4 100644 (file)
@@ -540,8 +540,14 @@ kmmio_die_notifier(struct notifier_block *nb, unsigned long val, void *args)
        struct die_args *arg = args;
 
        if (val == DIE_DEBUG && (arg->err & DR_STEP))
-               if (post_kmmio_handler(arg->err, arg->regs) == 1)
+               if (post_kmmio_handler(arg->err, arg->regs) == 1) {
+                       /*
+                        * Reset the BS bit in dr6 (pointed by args->err) to
+                        * denote completion of processing
+                        */
+                       (*(unsigned long *)ERR_PTR(arg->err)) &= ~DR_STEP;
                        return NOTIFY_STOP;
+               }
 
        return NOTIFY_DONE;
 }
index dbb5381..9d7ce96 100644 (file)
@@ -136,7 +136,7 @@ acpi_numa_x2apic_affinity_init(struct acpi_srat_x2apic_cpu_affinity *pa)
        apicid_to_node[apic_id] = node;
        node_set(node, cpu_nodes_parsed);
        acpi_numa = 1;
-       printk(KERN_INFO "SRAT: PXM %u -> APIC %u -> Node %u\n",
+       printk(KERN_INFO "SRAT: PXM %u -> APIC 0x%04x -> Node %u\n",
               pxm, apic_id, node);
 }
 
@@ -170,7 +170,7 @@ acpi_numa_processor_affinity_init(struct acpi_srat_cpu_affinity *pa)
        apicid_to_node[apic_id] = node;
        node_set(node, cpu_nodes_parsed);
        acpi_numa = 1;
-       printk(KERN_INFO "SRAT: PXM %u -> APIC %u -> Node %u\n",
+       printk(KERN_INFO "SRAT: PXM %u -> APIC 0x%02x -> Node %u\n",
               pxm, apic_id, node);
 }
 
index 8aa85f1..0a979f3 100644 (file)
@@ -18,6 +18,7 @@
 #include <asm/mce.h>
 #include <asm/xcr.h>
 #include <asm/suspend.h>
+#include <asm/debugreg.h>
 
 #ifdef CONFIG_X86_32
 static struct saved_context saved_context;
@@ -142,31 +143,6 @@ static void fix_processor_context(void)
 #endif
        load_TR_desc();                         /* This does ltr */
        load_LDT(&current->active_mm->context); /* This does lldt */
-
-       /*
-        * Now maybe reload the debug registers
-        */
-       if (current->thread.debugreg7) {
-#ifdef CONFIG_X86_32
-               set_debugreg(current->thread.debugreg0, 0);
-               set_debugreg(current->thread.debugreg1, 1);
-               set_debugreg(current->thread.debugreg2, 2);
-               set_debugreg(current->thread.debugreg3, 3);
-               /* no 4 and 5 */
-               set_debugreg(current->thread.debugreg6, 6);
-               set_debugreg(current->thread.debugreg7, 7);
-#else
-               /* CONFIG_X86_64 */
-               loaddebug(&current->thread, 0);
-               loaddebug(&current->thread, 1);
-               loaddebug(&current->thread, 2);
-               loaddebug(&current->thread, 3);
-               /* no 4 and 5 */
-               loaddebug(&current->thread, 6);
-               loaddebug(&current->thread, 7);
-#endif
-       }
-
 }
 
 /**
diff --git a/arch/x86/tools/Makefile b/arch/x86/tools/Makefile
new file mode 100644 (file)
index 0000000..f820826
--- /dev/null
@@ -0,0 +1,31 @@
+PHONY += posttest
+
+ifeq ($(KBUILD_VERBOSE),1)
+  posttest_verbose = -v
+else
+  posttest_verbose =
+endif
+
+ifeq ($(CONFIG_64BIT),y)
+  posttest_64bit = -y
+else
+  posttest_64bit = -n
+endif
+
+distill_awk = $(srctree)/arch/x86/tools/distill.awk
+chkobjdump = $(srctree)/arch/x86/tools/chkobjdump.awk
+
+quiet_cmd_posttest = TEST    $@
+      cmd_posttest = ($(OBJDUMP) -v | $(AWK) -f $(chkobjdump)) || $(OBJDUMP) -d -j .text $(objtree)/vmlinux | $(AWK) -f $(distill_awk) | $(obj)/test_get_len $(posttest_64bit) $(posttest_verbose)
+
+posttest: $(obj)/test_get_len vmlinux
+       $(call cmd,posttest)
+
+hostprogs-y    := test_get_len
+
+# -I needed for generated C source and C source which in the kernel tree.
+HOSTCFLAGS_test_get_len.o := -Wall -I$(objtree)/arch/x86/lib/ -I$(srctree)/arch/x86/include/ -I$(srctree)/arch/x86/lib/ -I$(srctree)/include/
+
+# Dependencies are also needed.
+$(obj)/test_get_len.o: $(srctree)/arch/x86/lib/insn.c $(srctree)/arch/x86/lib/inat.c $(srctree)/arch/x86/include/asm/inat_types.h $(srctree)/arch/x86/include/asm/inat.h $(srctree)/arch/x86/include/asm/insn.h $(objtree)/arch/x86/lib/inat-tables.c
+
diff --git a/arch/x86/tools/chkobjdump.awk b/arch/x86/tools/chkobjdump.awk
new file mode 100644 (file)
index 0000000..0d13cd9
--- /dev/null
@@ -0,0 +1,23 @@
+# GNU objdump version checker
+#
+# Usage:
+# objdump -v | awk -f chkobjdump.awk
+BEGIN {
+       # objdump version 2.19 or later is OK for the test.
+       od_ver = 2;
+       od_sver = 19;
+}
+
+/^GNU/ {
+       split($4, ver, ".");
+       if (ver[1] > od_ver ||
+           (ver[1] == od_ver && ver[2] >= od_sver)) {
+               exit 1;
+       } else {
+               printf("Warning: objdump version %s is older than %d.%d\n",
+                      $4, od_ver, od_sver);
+               print("Warning: Skipping posttest.");
+               # Logic is inverted, because we just skip test without error.
+               exit 0;
+       }
+}
diff --git a/arch/x86/tools/distill.awk b/arch/x86/tools/distill.awk
new file mode 100644 (file)
index 0000000..c13c0ee
--- /dev/null
@@ -0,0 +1,47 @@
+#!/bin/awk -f
+# Usage: objdump -d a.out | awk -f distill.awk | ./test_get_len
+# Distills the disassembly as follows:
+# - Removes all lines except the disassembled instructions.
+# - For instructions that exceed 1 line (7 bytes), crams all the hex bytes
+# into a single line.
+# - Remove bad(or prefix only) instructions
+
+BEGIN {
+       prev_addr = ""
+       prev_hex = ""
+       prev_mnemonic = ""
+       bad_expr = "(\\(bad\\)|^rex|^.byte|^rep(z|nz)$|^lock$|^es$|^cs$|^ss$|^ds$|^fs$|^gs$|^data(16|32)$|^addr(16|32|64))"
+       fwait_expr = "^9b "
+       fwait_str="9b\tfwait"
+}
+
+/^ *[0-9a-f]+ <[^>]*>:/ {
+       # Symbol entry
+       printf("%s%s\n", $2, $1)
+}
+
+/^ *[0-9a-f]+:/ {
+       if (split($0, field, "\t") < 3) {
+               # This is a continuation of the same insn.
+               prev_hex = prev_hex field[2]
+       } else {
+               # Skip bad instructions
+               if (match(prev_mnemonic, bad_expr))
+                       prev_addr = ""
+               # Split fwait from other f* instructions
+               if (match(prev_hex, fwait_expr) && prev_mnemonic != "fwait") {
+                       printf "%s\t%s\n", prev_addr, fwait_str
+                       sub(fwait_expr, "", prev_hex)
+               }
+               if (prev_addr != "")
+                       printf "%s\t%s\t%s\n", prev_addr, prev_hex, prev_mnemonic
+               prev_addr = field[1]
+               prev_hex = field[2]
+               prev_mnemonic = field[3]
+       }
+}
+
+END {
+       if (prev_addr != "")
+               printf "%s\t%s\t%s\n", prev_addr, prev_hex, prev_mnemonic
+}
diff --git a/arch/x86/tools/gen-insn-attr-x86.awk b/arch/x86/tools/gen-insn-attr-x86.awk
new file mode 100644 (file)
index 0000000..e34e92a
--- /dev/null
@@ -0,0 +1,380 @@
+#!/bin/awk -f
+# gen-insn-attr-x86.awk: Instruction attribute table generator
+# Written by Masami Hiramatsu <mhiramat@redhat.com>
+#
+# Usage: awk -f gen-insn-attr-x86.awk x86-opcode-map.txt > inat-tables.c
+
+# Awk implementation sanity check
+function check_awk_implement() {
+       if (!match("abc", "[[:lower:]]+"))
+               return "Your awk doesn't support charactor-class."
+       if (sprintf("%x", 0) != "0")
+               return "Your awk has a printf-format problem."
+       return ""
+}
+
+# Clear working vars
+function clear_vars() {
+       delete table
+       delete lptable2
+       delete lptable1
+       delete lptable3
+       eid = -1 # escape id
+       gid = -1 # group id
+       aid = -1 # AVX id
+       tname = ""
+}
+
+BEGIN {
+       # Implementation error checking
+       awkchecked = check_awk_implement()
+       if (awkchecked != "") {
+               print "Error: " awkchecked > "/dev/stderr"
+               print "Please try to use gawk." > "/dev/stderr"
+               exit 1
+       }
+
+       # Setup generating tables
+       print "/* x86 opcode map generated from x86-opcode-map.txt */"
+       print "/* Do not change this code. */\n"
+       ggid = 1
+       geid = 1
+       gaid = 0
+       delete etable
+       delete gtable
+       delete atable
+
+       opnd_expr = "^[[:alpha:]/]"
+       ext_expr = "^\\("
+       sep_expr = "^\\|$"
+       group_expr = "^Grp[[:alnum:]]+"
+
+       imm_expr = "^[IJAO][[:lower:]]"
+       imm_flag["Ib"] = "INAT_MAKE_IMM(INAT_IMM_BYTE)"
+       imm_flag["Jb"] = "INAT_MAKE_IMM(INAT_IMM_BYTE)"
+       imm_flag["Iw"] = "INAT_MAKE_IMM(INAT_IMM_WORD)"
+       imm_flag["Id"] = "INAT_MAKE_IMM(INAT_IMM_DWORD)"
+       imm_flag["Iq"] = "INAT_MAKE_IMM(INAT_IMM_QWORD)"
+       imm_flag["Ap"] = "INAT_MAKE_IMM(INAT_IMM_PTR)"
+       imm_flag["Iz"] = "INAT_MAKE_IMM(INAT_IMM_VWORD32)"
+       imm_flag["Jz"] = "INAT_MAKE_IMM(INAT_IMM_VWORD32)"
+       imm_flag["Iv"] = "INAT_MAKE_IMM(INAT_IMM_VWORD)"
+       imm_flag["Ob"] = "INAT_MOFFSET"
+       imm_flag["Ov"] = "INAT_MOFFSET"
+
+       modrm_expr = "^([CDEGMNPQRSUVW/][[:lower:]]+|NTA|T[012])"
+       force64_expr = "\\([df]64\\)"
+       rex_expr = "^REX(\\.[XRWB]+)*"
+       fpu_expr = "^ESC" # TODO
+
+       lprefix1_expr = "\\(66\\)"
+       lprefix2_expr = "\\(F3\\)"
+       lprefix3_expr = "\\(F2\\)"
+       max_lprefix = 4
+
+       vexok_expr = "\\(VEX\\)"
+       vexonly_expr = "\\(oVEX\\)"
+
+       prefix_expr = "\\(Prefix\\)"
+       prefix_num["Operand-Size"] = "INAT_PFX_OPNDSZ"
+       prefix_num["REPNE"] = "INAT_PFX_REPNE"
+       prefix_num["REP/REPE"] = "INAT_PFX_REPE"
+       prefix_num["LOCK"] = "INAT_PFX_LOCK"
+       prefix_num["SEG=CS"] = "INAT_PFX_CS"
+       prefix_num["SEG=DS"] = "INAT_PFX_DS"
+       prefix_num["SEG=ES"] = "INAT_PFX_ES"
+       prefix_num["SEG=FS"] = "INAT_PFX_FS"
+       prefix_num["SEG=GS"] = "INAT_PFX_GS"
+       prefix_num["SEG=SS"] = "INAT_PFX_SS"
+       prefix_num["Address-Size"] = "INAT_PFX_ADDRSZ"
+       prefix_num["2bytes-VEX"] = "INAT_PFX_VEX2"
+       prefix_num["3bytes-VEX"] = "INAT_PFX_VEX3"
+
+       clear_vars()
+}
+
+function semantic_error(msg) {
+       print "Semantic error at " NR ": " msg > "/dev/stderr"
+       exit 1
+}
+
+function debug(msg) {
+       print "DEBUG: " msg
+}
+
+function array_size(arr,   i,c) {
+       c = 0
+       for (i in arr)
+               c++
+       return c
+}
+
+/^Table:/ {
+       print "/* " $0 " */"
+       if (tname != "")
+               semantic_error("Hit Table: before EndTable:.");
+}
+
+/^Referrer:/ {
+       if (NF != 1) {
+               # escape opcode table
+               ref = ""
+               for (i = 2; i <= NF; i++)
+                       ref = ref $i
+               eid = escape[ref]
+               tname = sprintf("inat_escape_table_%d", eid)
+       }
+}
+
+/^AVXcode:/ {
+       if (NF != 1) {
+               # AVX/escape opcode table
+               aid = $2
+               if (gaid <= aid)
+                       gaid = aid + 1
+               if (tname == "")        # AVX only opcode table
+                       tname = sprintf("inat_avx_table_%d", $2)
+       }
+       if (aid == -1 && eid == -1)     # primary opcode table
+               tname = "inat_primary_table"
+}
+
+/^GrpTable:/ {
+       print "/* " $0 " */"
+       if (!($2 in group))
+               semantic_error("No group: " $2 )
+       gid = group[$2]
+       tname = "inat_group_table_" gid
+}
+
+function print_table(tbl,name,fmt,n)
+{
+       print "const insn_attr_t " name " = {"
+       for (i = 0; i < n; i++) {
+               id = sprintf(fmt, i)
+               if (tbl[id])
+                       print " [" id "] = " tbl[id] ","
+       }
+       print "};"
+}
+
+/^EndTable/ {
+       if (gid != -1) {
+               # print group tables
+               if (array_size(table) != 0) {
+                       print_table(table, tname "[INAT_GROUP_TABLE_SIZE]",
+                                   "0x%x", 8)
+                       gtable[gid,0] = tname
+               }
+               if (array_size(lptable1) != 0) {
+                       print_table(lptable1, tname "_1[INAT_GROUP_TABLE_SIZE]",
+                                   "0x%x", 8)
+                       gtable[gid,1] = tname "_1"
+               }
+               if (array_size(lptable2) != 0) {
+                       print_table(lptable2, tname "_2[INAT_GROUP_TABLE_SIZE]",
+                                   "0x%x", 8)
+                       gtable[gid,2] = tname "_2"
+               }
+               if (array_size(lptable3) != 0) {
+                       print_table(lptable3, tname "_3[INAT_GROUP_TABLE_SIZE]",
+                                   "0x%x", 8)
+                       gtable[gid,3] = tname "_3"
+               }
+       } else {
+               # print primary/escaped tables
+               if (array_size(table) != 0) {
+                       print_table(table, tname "[INAT_OPCODE_TABLE_SIZE]",
+                                   "0x%02x", 256)
+                       etable[eid,0] = tname
+                       if (aid >= 0)
+                               atable[aid,0] = tname
+               }
+               if (array_size(lptable1) != 0) {
+                       print_table(lptable1,tname "_1[INAT_OPCODE_TABLE_SIZE]",
+                                   "0x%02x", 256)
+                       etable[eid,1] = tname "_1"
+                       if (aid >= 0)
+                               atable[aid,1] = tname "_1"
+               }
+               if (array_size(lptable2) != 0) {
+                       print_table(lptable2,tname "_2[INAT_OPCODE_TABLE_SIZE]",
+                                   "0x%02x", 256)
+                       etable[eid,2] = tname "_2"
+                       if (aid >= 0)
+                               atable[aid,2] = tname "_2"
+               }
+               if (array_size(lptable3) != 0) {
+                       print_table(lptable3,tname "_3[INAT_OPCODE_TABLE_SIZE]",
+                                   "0x%02x", 256)
+                       etable[eid,3] = tname "_3"
+                       if (aid >= 0)
+                               atable[aid,3] = tname "_3"
+               }
+       }
+       print ""
+       clear_vars()
+}
+
+function add_flags(old,new) {
+       if (old && new)
+               return old " | " new
+       else if (old)
+               return old
+       else
+               return new
+}
+
+# convert operands to flags.
+function convert_operands(opnd,       i,imm,mod)
+{
+       imm = null
+       mod = null
+       for (i in opnd) {
+               i  = opnd[i]
+               if (match(i, imm_expr) == 1) {
+                       if (!imm_flag[i])
+                               semantic_error("Unknown imm opnd: " i)
+                       if (imm) {
+                               if (i != "Ib")
+                                       semantic_error("Second IMM error")
+                               imm = add_flags(imm, "INAT_SCNDIMM")
+                       } else
+                               imm = imm_flag[i]
+               } else if (match(i, modrm_expr))
+                       mod = "INAT_MODRM"
+       }
+       return add_flags(imm, mod)
+}
+
+/^[0-9a-f]+\:/ {
+       if (NR == 1)
+               next
+       # get index
+       idx = "0x" substr($1, 1, index($1,":") - 1)
+       if (idx in table)
+               semantic_error("Redefine " idx " in " tname)
+
+       # check if escaped opcode
+       if ("escape" == $2) {
+               if ($3 != "#")
+                       semantic_error("No escaped name")
+               ref = ""
+               for (i = 4; i <= NF; i++)
+                       ref = ref $i
+               if (ref in escape)
+                       semantic_error("Redefine escape (" ref ")")
+               escape[ref] = geid
+               geid++
+               table[idx] = "INAT_MAKE_ESCAPE(" escape[ref] ")"
+               next
+       }
+
+       variant = null
+       # converts
+       i = 2
+       while (i <= NF) {
+               opcode = $(i++)
+               delete opnds
+               ext = null
+               flags = null
+               opnd = null
+               # parse one opcode
+               if (match($i, opnd_expr)) {
+                       opnd = $i
+                       split($(i++), opnds, ",")
+                       flags = convert_operands(opnds)
+               }
+               if (match($i, ext_expr))
+                       ext = $(i++)
+               if (match($i, sep_expr))
+                       i++
+               else if (i < NF)
+                       semantic_error($i " is not a separator")
+
+               # check if group opcode
+               if (match(opcode, group_expr)) {
+                       if (!(opcode in group)) {
+                               group[opcode] = ggid
+                               ggid++
+                       }
+                       flags = add_flags(flags, "INAT_MAKE_GROUP(" group[opcode] ")")
+               }
+               # check force(or default) 64bit
+               if (match(ext, force64_expr))
+                       flags = add_flags(flags, "INAT_FORCE64")
+
+               # check REX prefix
+               if (match(opcode, rex_expr))
+                       flags = add_flags(flags, "INAT_MAKE_PREFIX(INAT_PFX_REX)")
+
+               # check coprocessor escape : TODO
+               if (match(opcode, fpu_expr))
+                       flags = add_flags(flags, "INAT_MODRM")
+
+               # check VEX only code
+               if (match(ext, vexonly_expr))
+                       flags = add_flags(flags, "INAT_VEXOK | INAT_VEXONLY")
+
+               # check VEX only code
+               if (match(ext, vexok_expr))
+                       flags = add_flags(flags, "INAT_VEXOK")
+
+               # check prefixes
+               if (match(ext, prefix_expr)) {
+                       if (!prefix_num[opcode])
+                               semantic_error("Unknown prefix: " opcode)
+                       flags = add_flags(flags, "INAT_MAKE_PREFIX(" prefix_num[opcode] ")")
+               }
+               if (length(flags) == 0)
+                       continue
+               # check if last prefix
+               if (match(ext, lprefix1_expr)) {
+                       lptable1[idx] = add_flags(lptable1[idx],flags)
+                       variant = "INAT_VARIANT"
+               } else if (match(ext, lprefix2_expr)) {
+                       lptable2[idx] = add_flags(lptable2[idx],flags)
+                       variant = "INAT_VARIANT"
+               } else if (match(ext, lprefix3_expr)) {
+                       lptable3[idx] = add_flags(lptable3[idx],flags)
+                       variant = "INAT_VARIANT"
+               } else {
+                       table[idx] = add_flags(table[idx],flags)
+               }
+       }
+       if (variant)
+               table[idx] = add_flags(table[idx],variant)
+}
+
+END {
+       if (awkchecked != "")
+               exit 1
+       # print escape opcode map's array
+       print "/* Escape opcode map array */"
+       print "const insn_attr_t const *inat_escape_tables[INAT_ESC_MAX + 1]" \
+             "[INAT_LSTPFX_MAX + 1] = {"
+       for (i = 0; i < geid; i++)
+               for (j = 0; j < max_lprefix; j++)
+                       if (etable[i,j])
+                               print " ["i"]["j"] = "etable[i,j]","
+       print "};\n"
+       # print group opcode map's array
+       print "/* Group opcode map array */"
+       print "const insn_attr_t const *inat_group_tables[INAT_GRP_MAX + 1]"\
+             "[INAT_LSTPFX_MAX + 1] = {"
+       for (i = 0; i < ggid; i++)
+               for (j = 0; j < max_lprefix; j++)
+                       if (gtable[i,j])
+                               print " ["i"]["j"] = "gtable[i,j]","
+       print "};\n"
+       # print AVX opcode map's array
+       print "/* AVX opcode map array */"
+       print "const insn_attr_t const *inat_avx_tables[X86_VEX_M_MAX + 1]"\
+             "[INAT_LSTPFX_MAX + 1] = {"
+       for (i = 0; i < gaid; i++)
+               for (j = 0; j < max_lprefix; j++)
+                       if (atable[i,j])
+                               print " ["i"]["j"] = "atable[i,j]","
+       print "};"
+}
+
diff --git a/arch/x86/tools/test_get_len.c b/arch/x86/tools/test_get_len.c
new file mode 100644 (file)
index 0000000..d8214dc
--- /dev/null
@@ -0,0 +1,173 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Copyright (C) IBM Corporation, 2009
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <unistd.h>
+
+#define unlikely(cond) (cond)
+
+#include <asm/insn.h>
+#include <inat.c>
+#include <insn.c>
+
+/*
+ * Test of instruction analysis in general and insn_get_length() in
+ * particular.  See if insn_get_length() and the disassembler agree
+ * on the length of each instruction in an elf disassembly.
+ *
+ * Usage: objdump -d a.out | awk -f distill.awk | ./test_get_len
+ */
+
+const char *prog;
+static int verbose;
+static int x86_64;
+
+static void usage(void)
+{
+       fprintf(stderr, "Usage: objdump -d a.out | awk -f distill.awk |"
+               " %s [-y|-n] [-v] \n", prog);
+       fprintf(stderr, "\t-y   64bit mode\n");
+       fprintf(stderr, "\t-n   32bit mode\n");
+       fprintf(stderr, "\t-v   verbose mode\n");
+       exit(1);
+}
+
+static void malformed_line(const char *line, int line_nr)
+{
+       fprintf(stderr, "%s: malformed line %d:\n%s", prog, line_nr, line);
+       exit(3);
+}
+
+static void dump_field(FILE *fp, const char *name, const char *indent,
+                      struct insn_field *field)
+{
+       fprintf(fp, "%s.%s = {\n", indent, name);
+       fprintf(fp, "%s\t.value = %d, bytes[] = {%x, %x, %x, %x},\n",
+               indent, field->value, field->bytes[0], field->bytes[1],
+               field->bytes[2], field->bytes[3]);
+       fprintf(fp, "%s\t.got = %d, .nbytes = %d},\n", indent,
+               field->got, field->nbytes);
+}
+
+static void dump_insn(FILE *fp, struct insn *insn)
+{
+       fprintf(fp, "Instruction = { \n");
+       dump_field(fp, "prefixes", "\t",        &insn->prefixes);
+       dump_field(fp, "rex_prefix", "\t",      &insn->rex_prefix);
+       dump_field(fp, "vex_prefix", "\t",      &insn->vex_prefix);
+       dump_field(fp, "opcode", "\t",          &insn->opcode);
+       dump_field(fp, "modrm", "\t",           &insn->modrm);
+       dump_field(fp, "sib", "\t",             &insn->sib);
+       dump_field(fp, "displacement", "\t",    &insn->displacement);
+       dump_field(fp, "immediate1", "\t",      &insn->immediate1);
+       dump_field(fp, "immediate2", "\t",      &insn->immediate2);
+       fprintf(fp, "\t.attr = %x, .opnd_bytes = %d, .addr_bytes = %d,\n",
+               insn->attr, insn->opnd_bytes, insn->addr_bytes);
+       fprintf(fp, "\t.length = %d, .x86_64 = %d, .kaddr = %p}\n",
+               insn->length, insn->x86_64, insn->kaddr);
+}
+
+static void parse_args(int argc, char **argv)
+{
+       int c;
+       prog = argv[0];
+       while ((c = getopt(argc, argv, "ynv")) != -1) {
+               switch (c) {
+               case 'y':
+                       x86_64 = 1;
+                       break;
+               case 'n':
+                       x86_64 = 0;
+                       break;
+               case 'v':
+                       verbose = 1;
+                       break;
+               default:
+                       usage();
+               }
+       }
+}
+
+#define BUFSIZE 256
+
+int main(int argc, char **argv)
+{
+       char line[BUFSIZE], sym[BUFSIZE] = "<unknown>";
+       unsigned char insn_buf[16];
+       struct insn insn;
+       int insns = 0, c;
+       int warnings = 0;
+
+       parse_args(argc, argv);
+
+       while (fgets(line, BUFSIZE, stdin)) {
+               char copy[BUFSIZE], *s, *tab1, *tab2;
+               int nb = 0;
+               unsigned int b;
+
+               if (line[0] == '<') {
+                       /* Symbol line */
+                       strcpy(sym, line);
+                       continue;
+               }
+
+               insns++;
+               memset(insn_buf, 0, 16);
+               strcpy(copy, line);
+               tab1 = strchr(copy, '\t');
+               if (!tab1)
+                       malformed_line(line, insns);
+               s = tab1 + 1;
+               s += strspn(s, " ");
+               tab2 = strchr(s, '\t');
+               if (!tab2)
+                       malformed_line(line, insns);
+               *tab2 = '\0';   /* Characters beyond tab2 aren't examined */
+               while (s < tab2) {
+                       if (sscanf(s, "%x", &b) == 1) {
+                               insn_buf[nb++] = (unsigned char) b;
+                               s += 3;
+                       } else
+                               break;
+               }
+               /* Decode an instruction */
+               insn_init(&insn, insn_buf, x86_64);
+               insn_get_length(&insn);
+               if (insn.length != nb) {
+                       warnings++;
+                       fprintf(stderr, "Warning: %s found difference at %s\n",
+                               prog, sym);
+                       fprintf(stderr, "Warning: %s", line);
+                       fprintf(stderr, "Warning: objdump says %d bytes, but "
+                               "insn_get_length() says %d\n", nb,
+                               insn.length);
+                       if (verbose)
+                               dump_insn(stderr, &insn);
+               }
+       }
+       if (warnings)
+               fprintf(stderr, "Warning: decoded and checked %d"
+                       " instructions with %d warnings\n", insns, warnings);
+       else
+               fprintf(stderr, "Succeed: decoded and checked %d"
+                       " instructions\n", insns);
+       return 0;
+}
index 58bc00f..02b442e 100644 (file)
@@ -393,7 +393,6 @@ static ctl_table abi_table2[] = {
 
 static ctl_table abi_root_table2[] = {
        {
-               .ctl_name = CTL_ABI,
                .procname = "abi",
                .mode = 0555,
                .child = abi_table2
index b7b8fbe..a508f2f 100644 (file)
@@ -101,6 +101,7 @@ static inline void __invalidate_icache_page_alias(unsigned long virt,
 #define flush_cache_vmap(start,end)    flush_cache_all()
 #define flush_cache_vunmap(start,end)  flush_cache_all()
 
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 1
 extern void flush_dcache_page(struct page*);
 extern void flush_cache_range(struct vm_area_struct*, ulong, ulong);
 extern void flush_cache_page(struct vm_area_struct*, unsigned long, unsigned long);
index 9be0b56..e20fbde 100644 (file)
@@ -77,6 +77,28 @@ config BLK_DEV_INTEGRITY
        T10/SCSI Data Integrity Field or the T13/ATA External Path
        Protection.  If in doubt, say N.
 
+config BLK_CGROUP
+       bool
+       depends on CGROUPS
+       default n
+       ---help---
+       Generic block IO controller cgroup interface. This is the common
+       cgroup interface which should be used by various IO controlling
+       policies.
+
+       Currently, CFQ IO scheduler uses it to recognize task groups and
+       control disk bandwidth allocation (proportional time slice allocation)
+       to such task groups.
+
+config DEBUG_BLK_CGROUP
+       bool
+       depends on BLK_CGROUP
+       default n
+       ---help---
+       Enable some debugging help. Currently it stores the cgroup path
+       in the blk group which can be used by cfq for tracing various
+       group related activity.
+
 endif # BLOCK
 
 config BLOCK_COMPAT
index 7e803fc..b71abfb 100644 (file)
@@ -12,24 +12,14 @@ config IOSCHED_NOOP
          that do their own scheduling and require only minimal assistance from
          the kernel.
 
-config IOSCHED_AS
-       tristate "Anticipatory I/O scheduler"
-       default y
-       ---help---
-         The anticipatory I/O scheduler is generally a good choice for most
-         environments, but is quite large and complex when compared to the
-         deadline I/O scheduler, it can also be slower in some cases
-         especially some database loads.
-
 config IOSCHED_DEADLINE
        tristate "Deadline I/O scheduler"
        default y
        ---help---
-         The deadline I/O scheduler is simple and compact, and is often as
-         good as the anticipatory I/O scheduler, and in some database
-         workloads, better. In the case of a single process performing I/O to
-         a disk at any one time, its behaviour is almost identical to the
-         anticipatory I/O scheduler and so is a good choice.
+         The deadline I/O scheduler is simple and compact. It will provide
+         CSCAN service with FIFO expiration of requests, switching to
+         a new point in the service tree and doing a batch of IO from there
+         in case of expiry.
 
 config IOSCHED_CFQ
        tristate "CFQ I/O scheduler"
@@ -37,9 +27,28 @@ config IOSCHED_CFQ
        ---help---
          The CFQ I/O scheduler tries to distribute bandwidth equally
          among all processes in the system. It should provide a fair
-         working environment, suitable for desktop systems.
+         and low latency working environment, suitable for both desktop
+         and server systems.
+
          This is the default I/O scheduler.
 
+config CFQ_GROUP_IOSCHED
+       bool "CFQ Group Scheduling support"
+       depends on IOSCHED_CFQ && CGROUPS
+       select BLK_CGROUP
+       default n
+       ---help---
+         Enable group IO scheduling in CFQ.
+
+config DEBUG_CFQ_IOSCHED
+       bool "Debug CFQ Scheduling"
+       depends on CFQ_GROUP_IOSCHED
+       select DEBUG_BLK_CGROUP
+       default n
+       ---help---
+         Enable CFQ IO scheduling debugging in CFQ. Currently it makes
+         blktrace output more verbose.
+
 choice
        prompt "Default I/O scheduler"
        default DEFAULT_CFQ
@@ -47,9 +56,6 @@ choice
          Select the I/O scheduler which will be used by default for all
          block devices.
 
-       config DEFAULT_AS
-               bool "Anticipatory" if IOSCHED_AS=y
-
        config DEFAULT_DEADLINE
                bool "Deadline" if IOSCHED_DEADLINE=y
 
@@ -63,7 +69,6 @@ endchoice
 
 config DEFAULT_IOSCHED
        string
-       default "anticipatory" if DEFAULT_AS
        default "deadline" if DEFAULT_DEADLINE
        default "cfq" if DEFAULT_CFQ
        default "noop" if DEFAULT_NOOP
index ba74ca6..cb2d515 100644 (file)
@@ -8,8 +8,8 @@ obj-$(CONFIG_BLOCK) := elevator.o blk-core.o blk-tag.o blk-sysfs.o \
                        blk-iopoll.o ioctl.o genhd.o scsi_ioctl.o
 
 obj-$(CONFIG_BLK_DEV_BSG)      += bsg.o
+obj-$(CONFIG_BLK_CGROUP)       += blk-cgroup.o
 obj-$(CONFIG_IOSCHED_NOOP)     += noop-iosched.o
-obj-$(CONFIG_IOSCHED_AS)       += as-iosched.o
 obj-$(CONFIG_IOSCHED_DEADLINE) += deadline-iosched.o
 obj-$(CONFIG_IOSCHED_CFQ)      += cfq-iosched.o
 
diff --git a/block/as-iosched.c b/block/as-iosched.c
deleted file mode 100644 (file)
index ce8ba57..0000000
+++ /dev/null
@@ -1,1520 +0,0 @@
-/*
- *  Anticipatory & deadline i/o scheduler.
- *
- *  Copyright (C) 2002 Jens Axboe <axboe@kernel.dk>
- *                     Nick Piggin <nickpiggin@yahoo.com.au>
- *
- */
-#include <linux/kernel.h>
-#include <linux/fs.h>
-#include <linux/blkdev.h>
-#include <linux/elevator.h>
-#include <linux/bio.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-#include <linux/compiler.h>
-#include <linux/rbtree.h>
-#include <linux/interrupt.h>
-
-/*
- * See Documentation/block/as-iosched.txt
- */
-
-/*
- * max time before a read is submitted.
- */
-#define default_read_expire (HZ / 8)
-
-/*
- * ditto for writes, these limits are not hard, even
- * if the disk is capable of satisfying them.
- */
-#define default_write_expire (HZ / 4)
-
-/*
- * read_batch_expire describes how long we will allow a stream of reads to
- * persist before looking to see whether it is time to switch over to writes.
- */
-#define default_read_batch_expire (HZ / 2)
-
-/*
- * write_batch_expire describes how long we want a stream of writes to run for.
- * This is not a hard limit, but a target we set for the auto-tuning thingy.
- * See, the problem is: we can send a lot of writes to disk cache / TCQ in
- * a short amount of time...
- */
-#define default_write_batch_expire (HZ / 8)
-
-/*
- * max time we may wait to anticipate a read (default around 6ms)
- */
-#define default_antic_expire ((HZ / 150) ? HZ / 150 : 1)
-
-/*
- * Keep track of up to 20ms thinktimes. We can go as big as we like here,
- * however huge values tend to interfere and not decay fast enough. A program
- * might be in a non-io phase of operation. Waiting on user input for example,
- * or doing a lengthy computation. A small penalty can be justified there, and
- * will still catch out those processes that constantly have large thinktimes.
- */
-#define MAX_THINKTIME (HZ/50UL)
-
-/* Bits in as_io_context.state */
-enum as_io_states {
-       AS_TASK_RUNNING=0,      /* Process has not exited */
-       AS_TASK_IOSTARTED,      /* Process has started some IO */
-       AS_TASK_IORUNNING,      /* Process has completed some IO */
-};
-
-enum anticipation_status {
-       ANTIC_OFF=0,            /* Not anticipating (normal operation)  */
-       ANTIC_WAIT_REQ,         /* The last read has not yet completed  */
-       ANTIC_WAIT_NEXT,        /* Currently anticipating a request vs
-                                  last read (which has completed) */
-       ANTIC_FINISHED,         /* Anticipating but have found a candidate
-                                * or timed out */
-};
-
-struct as_data {
-       /*
-        * run time data
-        */
-
-       struct request_queue *q;        /* the "owner" queue */
-
-       /*
-        * requests (as_rq s) are present on both sort_list and fifo_list
-        */
-       struct rb_root sort_list[2];
-       struct list_head fifo_list[2];
-
-       struct request *next_rq[2];     /* next in sort order */
-       sector_t last_sector[2];        /* last SYNC & ASYNC sectors */
-
-       unsigned long exit_prob;        /* probability a task will exit while
-                                          being waited on */
-       unsigned long exit_no_coop;     /* probablility an exited task will
-                                          not be part of a later cooperating
-                                          request */
-       unsigned long new_ttime_total;  /* mean thinktime on new proc */
-       unsigned long new_ttime_mean;
-       u64 new_seek_total;             /* mean seek on new proc */
-       sector_t new_seek_mean;
-
-       unsigned long current_batch_expires;
-       unsigned long last_check_fifo[2];
-       int changed_batch;              /* 1: waiting for old batch to end */
-       int new_batch;                  /* 1: waiting on first read complete */
-       int batch_data_dir;             /* current batch SYNC / ASYNC */
-       int write_batch_count;          /* max # of reqs in a write batch */
-       int current_write_count;        /* how many requests left this batch */
-       int write_batch_idled;          /* has the write batch gone idle? */
-
-       enum anticipation_status antic_status;
-       unsigned long antic_start;      /* jiffies: when it started */
-       struct timer_list antic_timer;  /* anticipatory scheduling timer */
-       struct work_struct antic_work;  /* Deferred unplugging */
-       struct io_context *io_context;  /* Identify the expected process */
-       int ioc_finished; /* IO associated with io_context is finished */
-       int nr_dispatched;
-
-       /*
-        * settings that change how the i/o scheduler behaves
-        */
-       unsigned long fifo_expire[2];
-       unsigned long batch_expire[2];
-       unsigned long antic_expire;
-};
-
-/*
- * per-request data.
- */
-enum arq_state {
-       AS_RQ_NEW=0,            /* New - not referenced and not on any lists */
-       AS_RQ_QUEUED,           /* In the request queue. It belongs to the
-                                  scheduler */
-       AS_RQ_DISPATCHED,       /* On the dispatch list. It belongs to the
-                                  driver now */
-       AS_RQ_PRESCHED,         /* Debug poisoning for requests being used */
-       AS_RQ_REMOVED,
-       AS_RQ_MERGED,
-       AS_RQ_POSTSCHED,        /* when they shouldn't be */
-};
-
-#define RQ_IOC(rq)     ((struct io_context *) (rq)->elevator_private)
-#define RQ_STATE(rq)   ((enum arq_state)(rq)->elevator_private2)
-#define RQ_SET_STATE(rq, state)        ((rq)->elevator_private2 = (void *) state)
-
-static DEFINE_PER_CPU(unsigned long, as_ioc_count);
-static struct completion *ioc_gone;
-static DEFINE_SPINLOCK(ioc_gone_lock);
-
-static void as_move_to_dispatch(struct as_data *ad, struct request *rq);
-static void as_antic_stop(struct as_data *ad);
-
-/*
- * IO Context helper functions
- */
-
-/* Called to deallocate the as_io_context */
-static void free_as_io_context(struct as_io_context *aic)
-{
-       kfree(aic);
-       elv_ioc_count_dec(as_ioc_count);
-       if (ioc_gone) {
-               /*
-                * AS scheduler is exiting, grab exit lock and check
-                * the pending io context count. If it hits zero,
-                * complete ioc_gone and set it back to NULL.
-                */
-               spin_lock(&ioc_gone_lock);
-               if (ioc_gone && !elv_ioc_count_read(as_ioc_count)) {
-                       complete(ioc_gone);
-                       ioc_gone = NULL;
-               }
-               spin_unlock(&ioc_gone_lock);
-       }
-}
-
-static void as_trim(struct io_context *ioc)
-{
-       spin_lock_irq(&ioc->lock);
-       if (ioc->aic)
-               free_as_io_context(ioc->aic);
-       ioc->aic = NULL;
-       spin_unlock_irq(&ioc->lock);
-}
-
-/* Called when the task exits */
-static void exit_as_io_context(struct as_io_context *aic)
-{
-       WARN_ON(!test_bit(AS_TASK_RUNNING, &aic->state));
-       clear_bit(AS_TASK_RUNNING, &aic->state);
-}
-
-static struct as_io_context *alloc_as_io_context(void)
-{
-       struct as_io_context *ret;
-
-       ret = kmalloc(sizeof(*ret), GFP_ATOMIC);
-       if (ret) {
-               ret->dtor = free_as_io_context;
-               ret->exit = exit_as_io_context;
-               ret->state = 1 << AS_TASK_RUNNING;
-               atomic_set(&ret->nr_queued, 0);
-               atomic_set(&ret->nr_dispatched, 0);
-               spin_lock_init(&ret->lock);
-               ret->ttime_total = 0;
-               ret->ttime_samples = 0;
-               ret->ttime_mean = 0;
-               ret->seek_total = 0;
-               ret->seek_samples = 0;
-               ret->seek_mean = 0;
-               elv_ioc_count_inc(as_ioc_count);
-       }
-
-       return ret;
-}
-
-/*
- * If the current task has no AS IO context then create one and initialise it.
- * Then take a ref on the task's io context and return it.
- */
-static struct io_context *as_get_io_context(int node)
-{
-       struct io_context *ioc = get_io_context(GFP_ATOMIC, node);
-       if (ioc && !ioc->aic) {
-               ioc->aic = alloc_as_io_context();
-               if (!ioc->aic) {
-                       put_io_context(ioc);
-                       ioc = NULL;
-               }
-       }
-       return ioc;
-}
-
-static void as_put_io_context(struct request *rq)
-{
-       struct as_io_context *aic;
-
-       if (unlikely(!RQ_IOC(rq)))
-               return;
-
-       aic = RQ_IOC(rq)->aic;
-
-       if (rq_is_sync(rq) && aic) {
-               unsigned long flags;
-
-               spin_lock_irqsave(&aic->lock, flags);
-               set_bit(AS_TASK_IORUNNING, &aic->state);
-               aic->last_end_request = jiffies;
-               spin_unlock_irqrestore(&aic->lock, flags);
-       }
-
-       put_io_context(RQ_IOC(rq));
-}
-
-/*
- * rb tree support functions
- */
-#define RQ_RB_ROOT(ad, rq)     (&(ad)->sort_list[rq_is_sync((rq))])
-
-static void as_add_rq_rb(struct as_data *ad, struct request *rq)
-{
-       struct request *alias;
-
-       while ((unlikely(alias = elv_rb_add(RQ_RB_ROOT(ad, rq), rq)))) {
-               as_move_to_dispatch(ad, alias);
-               as_antic_stop(ad);
-       }
-}
-
-static inline void as_del_rq_rb(struct as_data *ad, struct request *rq)
-{
-       elv_rb_del(RQ_RB_ROOT(ad, rq), rq);
-}
-
-/*
- * IO Scheduler proper
- */
-
-#define MAXBACK (1024 * 1024)  /*
-                                * Maximum distance the disk will go backward
-                                * for a request.
-                                */
-
-#define BACK_PENALTY   2
-
-/*
- * as_choose_req selects the preferred one of two requests of the same data_dir
- * ignoring time - eg. timeouts, which is the job of as_dispatch_request
- */
-static struct request *
-as_choose_req(struct as_data *ad, struct request *rq1, struct request *rq2)
-{
-       int data_dir;
-       sector_t last, s1, s2, d1, d2;
-       int r1_wrap=0, r2_wrap=0;       /* requests are behind the disk head */
-       const sector_t maxback = MAXBACK;
-
-       if (rq1 == NULL || rq1 == rq2)
-               return rq2;
-       if (rq2 == NULL)
-               return rq1;
-
-       data_dir = rq_is_sync(rq1);
-
-       last = ad->last_sector[data_dir];
-       s1 = blk_rq_pos(rq1);
-       s2 = blk_rq_pos(rq2);
-
-       BUG_ON(data_dir != rq_is_sync(rq2));
-
-       /*
-        * Strict one way elevator _except_ in the case where we allow
-        * short backward seeks which are biased as twice the cost of a
-        * similar forward seek.
-        */
-       if (s1 >= last)
-               d1 = s1 - last;
-       else if (s1+maxback >= last)
-               d1 = (last - s1)*BACK_PENALTY;
-       else {
-               r1_wrap = 1;
-               d1 = 0; /* shut up, gcc */
-       }
-
-       if (s2 >= last)
-               d2 = s2 - last;
-       else if (s2+maxback >= last)
-               d2 = (last - s2)*BACK_PENALTY;
-       else {
-               r2_wrap = 1;
-               d2 = 0;
-       }
-
-       /* Found required data */
-       if (!r1_wrap && r2_wrap)
-               return rq1;
-       else if (!r2_wrap && r1_wrap)
-               return rq2;
-       else if (r1_wrap && r2_wrap) {
-               /* both behind the head */
-               if (s1 <= s2)
-                       return rq1;
-               else
-                       return rq2;
-       }
-
-       /* Both requests in front of the head */
-       if (d1 < d2)
-               return rq1;
-       else if (d2 < d1)
-               return rq2;
-       else {
-               if (s1 >= s2)
-                       return rq1;
-               else
-                       return rq2;
-       }
-}
-
-/*
- * as_find_next_rq finds the next request after @prev in elevator order.
- * this with as_choose_req form the basis for how the scheduler chooses
- * what request to process next. Anticipation works on top of this.
- */
-static struct request *
-as_find_next_rq(struct as_data *ad, struct request *last)
-{
-       struct rb_node *rbnext = rb_next(&last->rb_node);
-       struct rb_node *rbprev = rb_prev(&last->rb_node);
-       struct request *next = NULL, *prev = NULL;
-
-       BUG_ON(RB_EMPTY_NODE(&last->rb_node));
-
-       if (rbprev)
-               prev = rb_entry_rq(rbprev);
-
-       if (rbnext)
-               next = rb_entry_rq(rbnext);
-       else {
-               const int data_dir = rq_is_sync(last);
-
-               rbnext = rb_first(&ad->sort_list[data_dir]);
-               if (rbnext && rbnext != &last->rb_node)
-                       next = rb_entry_rq(rbnext);
-       }
-
-       return as_choose_req(ad, next, prev);
-}
-
-/*
- * anticipatory scheduling functions follow
- */
-
-/*
- * as_antic_expired tells us when we have anticipated too long.
- * The funny "absolute difference" math on the elapsed time is to handle
- * jiffy wraps, and disks which have been idle for 0x80000000 jiffies.
- */
-static int as_antic_expired(struct as_data *ad)
-{
-       long delta_jif;
-
-       delta_jif = jiffies - ad->antic_start;
-       if (unlikely(delta_jif < 0))
-               delta_jif = -delta_jif;
-       if (delta_jif < ad->antic_expire)
-               return 0;
-
-       return 1;
-}
-
-/*
- * as_antic_waitnext starts anticipating that a nice request will soon be
- * submitted. See also as_antic_waitreq
- */
-static void as_antic_waitnext(struct as_data *ad)
-{
-       unsigned long timeout;
-
-       BUG_ON(ad->antic_status != ANTIC_OFF
-                       && ad->antic_status != ANTIC_WAIT_REQ);
-
-       timeout = ad->antic_start + ad->antic_expire;
-
-       mod_timer(&ad->antic_timer, timeout);
-
-       ad->antic_status = ANTIC_WAIT_NEXT;
-}
-
-/*
- * as_antic_waitreq starts anticipating. We don't start timing the anticipation
- * until the request that we're anticipating on has finished. This means we
- * are timing from when the candidate process wakes up hopefully.
- */
-static void as_antic_waitreq(struct as_data *ad)
-{
-       BUG_ON(ad->antic_status == ANTIC_FINISHED);
-       if (ad->antic_status == ANTIC_OFF) {
-               if (!ad->io_context || ad->ioc_finished)
-                       as_antic_waitnext(ad);
-               else
-                       ad->antic_status = ANTIC_WAIT_REQ;
-       }
-}
-
-/*
- * This is called directly by the functions in this file to stop anticipation.
- * We kill the timer and schedule a call to the request_fn asap.
- */
-static void as_antic_stop(struct as_data *ad)
-{
-       int status = ad->antic_status;
-
-       if (status == ANTIC_WAIT_REQ || status == ANTIC_WAIT_NEXT) {
-               if (status == ANTIC_WAIT_NEXT)
-                       del_timer(&ad->antic_timer);
-               ad->antic_status = ANTIC_FINISHED;
-               /* see as_work_handler */
-               kblockd_schedule_work(ad->q, &ad->antic_work);
-       }
-}
-
-/*
- * as_antic_timeout is the timer function set by as_antic_waitnext.
- */
-static void as_antic_timeout(unsigned long data)
-{
-       struct request_queue *q = (struct request_queue *)data;
-       struct as_data *ad = q->elevator->elevator_data;
-       unsigned long flags;
-
-       spin_lock_irqsave(q->queue_lock, flags);
-       if (ad->antic_status == ANTIC_WAIT_REQ
-                       || ad->antic_status == ANTIC_WAIT_NEXT) {
-               struct as_io_context *aic;
-               spin_lock(&ad->io_context->lock);
-               aic = ad->io_context->aic;
-
-               ad->antic_status = ANTIC_FINISHED;
-               kblockd_schedule_work(q, &ad->antic_work);
-
-               if (aic->ttime_samples == 0) {
-                       /* process anticipated on has exited or timed out*/
-                       ad->exit_prob = (7*ad->exit_prob + 256)/8;
-               }
-               if (!test_bit(AS_TASK_RUNNING, &aic->state)) {
-                       /* process not "saved" by a cooperating request */
-                       ad->exit_no_coop = (7*ad->exit_no_coop + 256)/8;
-               }
-               spin_unlock(&ad->io_context->lock);
-       }
-       spin_unlock_irqrestore(q->queue_lock, flags);
-}
-
-static void as_update_thinktime(struct as_data *ad, struct as_io_context *aic,
-                               unsigned long ttime)
-{
-       /* fixed point: 1.0 == 1<<8 */
-       if (aic->ttime_samples == 0) {
-               ad->new_ttime_total = (7*ad->new_ttime_total + 256*ttime) / 8;
-               ad->new_ttime_mean = ad->new_ttime_total / 256;
-
-               ad->exit_prob = (7*ad->exit_prob)/8;
-       }
-       aic->ttime_samples = (7*aic->ttime_samples + 256) / 8;
-       aic->ttime_total = (7*aic->ttime_total + 256*ttime) / 8;
-       aic->ttime_mean = (aic->ttime_total + 128) / aic->ttime_samples;
-}
-
-static void as_update_seekdist(struct as_data *ad, struct as_io_context *aic,
-                               sector_t sdist)
-{
-       u64 total;
-
-       if (aic->seek_samples == 0) {
-               ad->new_seek_total = (7*ad->new_seek_total + 256*(u64)sdist)/8;
-               ad->new_seek_mean = ad->new_seek_total / 256;
-       }
-
-       /*
-        * Don't allow the seek distance to get too large from the
-        * odd fragment, pagein, etc
-        */
-       if (aic->seek_samples <= 60) /* second&third seek */
-               sdist = min(sdist, (aic->seek_mean * 4) + 2*1024*1024);
-       else
-               sdist = min(sdist, (aic->seek_mean * 4) + 2*1024*64);
-
-       aic->seek_samples = (7*aic->seek_samples + 256) / 8;
-       aic->seek_total = (7*aic->seek_total + (u64)256*sdist) / 8;
-       total = aic->seek_total + (aic->seek_samples/2);
-       do_div(total, aic->seek_samples);
-       aic->seek_mean = (sector_t)total;
-}
-
-/*
- * as_update_iohist keeps a decaying histogram of IO thinktimes, and
- * updates @aic->ttime_mean based on that. It is called when a new
- * request is queued.
- */
-static void as_update_iohist(struct as_data *ad, struct as_io_context *aic,
-                               struct request *rq)
-{
-       int data_dir = rq_is_sync(rq);
-       unsigned long thinktime = 0;
-       sector_t seek_dist;
-
-       if (aic == NULL)
-               return;
-
-       if (data_dir == BLK_RW_SYNC) {
-               unsigned long in_flight = atomic_read(&aic->nr_queued)
-                                       + atomic_read(&aic->nr_dispatched);
-               spin_lock(&aic->lock);
-               if (test_bit(AS_TASK_IORUNNING, &aic->state) ||
-                       test_bit(AS_TASK_IOSTARTED, &aic->state)) {
-                       /* Calculate read -> read thinktime */
-                       if (test_bit(AS_TASK_IORUNNING, &aic->state)
-                                                       && in_flight == 0) {
-                               thinktime = jiffies - aic->last_end_request;
-                               thinktime = min(thinktime, MAX_THINKTIME-1);
-                       }
-                       as_update_thinktime(ad, aic, thinktime);
-
-                       /* Calculate read -> read seek distance */
-                       if (aic->last_request_pos < blk_rq_pos(rq))
-                               seek_dist = blk_rq_pos(rq) -
-                                           aic->last_request_pos;
-                       else
-                               seek_dist = aic->last_request_pos -
-                                           blk_rq_pos(rq);
-                       as_update_seekdist(ad, aic, seek_dist);
-               }
-               aic->last_request_pos = blk_rq_pos(rq) + blk_rq_sectors(rq);
-               set_bit(AS_TASK_IOSTARTED, &aic->state);
-               spin_unlock(&aic->lock);
-       }
-}
-
-/*
- * as_close_req decides if one request is considered "close" to the
- * previous one issued.
- */
-static int as_close_req(struct as_data *ad, struct as_io_context *aic,
-                       struct request *rq)
-{
-       unsigned long delay;    /* jiffies */
-       sector_t last = ad->last_sector[ad->batch_data_dir];
-       sector_t next = blk_rq_pos(rq);
-       sector_t delta; /* acceptable close offset (in sectors) */
-       sector_t s;
-
-       if (ad->antic_status == ANTIC_OFF || !ad->ioc_finished)
-               delay = 0;
-       else
-               delay = jiffies - ad->antic_start;
-
-       if (delay == 0)
-               delta = 8192;
-       else if (delay <= (20 * HZ / 1000) && delay <= ad->antic_expire)
-               delta = 8192 << delay;
-       else
-               return 1;
-
-       if ((last <= next + (delta>>1)) && (next <= last + delta))
-               return 1;
-
-       if (last < next)
-               s = next - last;
-       else
-               s = last - next;
-
-       if (aic->seek_samples == 0) {
-               /*
-                * Process has just started IO. Use past statistics to
-                * gauge success possibility
-                */
-               if (ad->new_seek_mean > s) {
-                       /* this request is better than what we're expecting */
-                       return 1;
-               }
-
-       } else {
-               if (aic->seek_mean > s) {
-                       /* this request is better than what we're expecting */
-                       return 1;
-               }
-       }
-
-       return 0;
-}
-
-/*
- * as_can_break_anticipation returns true if we have been anticipating this
- * request.
- *
- * It also returns true if the process against which we are anticipating
- * submits a write - that's presumably an fsync, O_SYNC write, etc. We want to
- * dispatch it ASAP, because we know that application will not be submitting
- * any new reads.
- *
- * If the task which has submitted the request has exited, break anticipation.
- *
- * If this task has queued some other IO, do not enter enticipation.
- */
-static int as_can_break_anticipation(struct as_data *ad, struct request *rq)
-{
-       struct io_context *ioc;
-       struct as_io_context *aic;
-
-       ioc = ad->io_context;
-       BUG_ON(!ioc);
-       spin_lock(&ioc->lock);
-
-       if (rq && ioc == RQ_IOC(rq)) {
-               /* request from same process */
-               spin_unlock(&ioc->lock);
-               return 1;
-       }
-
-       if (ad->ioc_finished && as_antic_expired(ad)) {
-               /*
-                * In this situation status should really be FINISHED,
-                * however the timer hasn't had the chance to run yet.
-                */
-               spin_unlock(&ioc->lock);
-               return 1;
-       }
-
-       aic = ioc->aic;
-       if (!aic) {
-               spin_unlock(&ioc->lock);
-               return 0;
-       }
-
-       if (atomic_read(&aic->nr_queued) > 0) {
-               /* process has more requests queued */
-               spin_unlock(&ioc->lock);
-               return 1;
-       }
-
-       if (atomic_read(&aic->nr_dispatched) > 0) {
-               /* process has more requests dispatched */
-               spin_unlock(&ioc->lock);
-               return 1;
-       }
-
-       if (rq && rq_is_sync(rq) && as_close_req(ad, aic, rq)) {
-               /*
-                * Found a close request that is not one of ours.
-                *
-                * This makes close requests from another process update
-                * our IO history. Is generally useful when there are
-                * two or more cooperating processes working in the same
-                * area.
-                */
-               if (!test_bit(AS_TASK_RUNNING, &aic->state)) {
-                       if (aic->ttime_samples == 0)
-                               ad->exit_prob = (7*ad->exit_prob + 256)/8;
-
-                       ad->exit_no_coop = (7*ad->exit_no_coop)/8;
-               }
-
-               as_update_iohist(ad, aic, rq);
-               spin_unlock(&ioc->lock);
-               return 1;
-       }
-
-       if (!test_bit(AS_TASK_RUNNING, &aic->state)) {
-               /* process anticipated on has exited */
-               if (aic->ttime_samples == 0)
-                       ad->exit_prob = (7*ad->exit_prob + 256)/8;
-
-               if (ad->exit_no_coop > 128) {
-                       spin_unlock(&ioc->lock);
-                       return 1;
-               }
-       }
-
-       if (aic->ttime_samples == 0) {
-               if (ad->new_ttime_mean > ad->antic_expire) {
-                       spin_unlock(&ioc->lock);
-                       return 1;
-               }
-               if (ad->exit_prob * ad->exit_no_coop > 128*256) {
-                       spin_unlock(&ioc->lock);
-                       return 1;
-               }
-       } else if (aic->ttime_mean > ad->antic_expire) {
-               /* the process thinks too much between requests */
-               spin_unlock(&ioc->lock);
-               return 1;
-       }
-       spin_unlock(&ioc->lock);
-       return 0;
-}
-
-/*
- * as_can_anticipate indicates whether we should either run rq
- * or keep anticipating a better request.
- */
-static int as_can_anticipate(struct as_data *ad, struct request *rq)
-{
-#if 0 /* disable for now, we need to check tag level as well */
-       /*
-        * SSD device without seek penalty, disable idling
-        */
-       if (blk_queue_nonrot(ad->q)) axman
-               return 0;
-#endif
-
-       if (!ad->io_context)
-               /*
-                * Last request submitted was a write
-                */
-               return 0;
-
-       if (ad->antic_status == ANTIC_FINISHED)
-               /*
-                * Don't restart if we have just finished. Run the next request
-                */
-               return 0;
-
-       if (as_can_break_anticipation(ad, rq))
-               /*
-                * This request is a good candidate. Don't keep anticipating,
-                * run it.
-                */
-               return 0;
-
-       /*
-        * OK from here, we haven't finished, and don't have a decent request!
-        * Status is either ANTIC_OFF so start waiting,
-        * ANTIC_WAIT_REQ so continue waiting for request to finish
-        * or ANTIC_WAIT_NEXT so continue waiting for an acceptable request.
-        */
-
-       return 1;
-}
-
-/*
- * as_update_rq must be called whenever a request (rq) is added to
- * the sort_list. This function keeps caches up to date, and checks if the
- * request might be one we are "anticipating"
- */
-static void as_update_rq(struct as_data *ad, struct request *rq)
-{
-       const int data_dir = rq_is_sync(rq);
-
-       /* keep the next_rq cache up to date */
-       ad->next_rq[data_dir] = as_choose_req(ad, rq, ad->next_rq[data_dir]);
-
-       /*
-        * have we been anticipating this request?
-        * or does it come from the same process as the one we are anticipating
-        * for?
-        */
-       if (ad->antic_status == ANTIC_WAIT_REQ
-                       || ad->antic_status == ANTIC_WAIT_NEXT) {
-               if (as_can_break_anticipation(ad, rq))
-                       as_antic_stop(ad);
-       }
-}
-
-/*
- * Gathers timings and resizes the write batch automatically
- */
-static void update_write_batch(struct as_data *ad)
-{
-       unsigned long batch = ad->batch_expire[BLK_RW_ASYNC];
-       long write_time;
-
-       write_time = (jiffies - ad->current_batch_expires) + batch;
-       if (write_time < 0)
-               write_time = 0;
-
-       if (write_time > batch && !ad->write_batch_idled) {
-               if (write_time > batch * 3)
-                       ad->write_batch_count /= 2;
-               else
-                       ad->write_batch_count--;
-       } else if (write_time < batch && ad->current_write_count == 0) {
-               if (batch > write_time * 3)
-                       ad->write_batch_count *= 2;
-               else
-                       ad->write_batch_count++;
-       }
-
-       if (ad->write_batch_count < 1)
-               ad->write_batch_count = 1;
-}
-
-/*
- * as_completed_request is to be called when a request has completed and
- * returned something to the requesting process, be it an error or data.
- */
-static void as_completed_request(struct request_queue *q, struct request *rq)
-{
-       struct as_data *ad = q->elevator->elevator_data;
-
-       WARN_ON(!list_empty(&rq->queuelist));
-
-       if (RQ_STATE(rq) != AS_RQ_REMOVED) {
-               WARN(1, "rq->state %d\n", RQ_STATE(rq));
-               goto out;
-       }
-
-       if (ad->changed_batch && ad->nr_dispatched == 1) {
-               ad->current_batch_expires = jiffies +
-                                       ad->batch_expire[ad->batch_data_dir];
-               kblockd_schedule_work(q, &ad->antic_work);
-               ad->changed_batch = 0;
-
-               if (ad->batch_data_dir == BLK_RW_SYNC)
-                       ad->new_batch = 1;
-       }
-       WARN_ON(ad->nr_dispatched == 0);
-       ad->nr_dispatched--;
-
-       /*
-        * Start counting the batch from when a request of that direction is
-        * actually serviced. This should help devices with big TCQ windows
-        * and writeback caches
-        */
-       if (ad->new_batch && ad->batch_data_dir == rq_is_sync(rq)) {
-               update_write_batch(ad);
-               ad->current_batch_expires = jiffies +
-                               ad->batch_expire[BLK_RW_SYNC];
-               ad->new_batch = 0;
-       }
-
-       if (ad->io_context == RQ_IOC(rq) && ad->io_context) {
-               ad->antic_start = jiffies;
-               ad->ioc_finished = 1;
-               if (ad->antic_status == ANTIC_WAIT_REQ) {
-                       /*
-                        * We were waiting on this request, now anticipate
-                        * the next one
-                        */
-                       as_antic_waitnext(ad);
-               }
-       }
-
-       as_put_io_context(rq);
-out:
-       RQ_SET_STATE(rq, AS_RQ_POSTSCHED);
-}
-
-/*
- * as_remove_queued_request removes a request from the pre dispatch queue
- * without updating refcounts. It is expected the caller will drop the
- * reference unless it replaces the request at somepart of the elevator
- * (ie. the dispatch queue)
- */
-static void as_remove_queued_request(struct request_queue *q,
-                                    struct request *rq)
-{
-       const int data_dir = rq_is_sync(rq);
-       struct as_data *ad = q->elevator->elevator_data;
-       struct io_context *ioc;
-
-       WARN_ON(RQ_STATE(rq) != AS_RQ_QUEUED);
-
-       ioc = RQ_IOC(rq);
-       if (ioc && ioc->aic) {
-               BUG_ON(!atomic_read(&ioc->aic->nr_queued));
-               atomic_dec(&ioc->aic->nr_queued);
-       }
-
-       /*
-        * Update the "next_rq" cache if we are about to remove its
-        * entry
-        */
-       if (ad->next_rq[data_dir] == rq)
-               ad->next_rq[data_dir] = as_find_next_rq(ad, rq);
-
-       rq_fifo_clear(rq);
-       as_del_rq_rb(ad, rq);
-}
-
-/*
- * as_fifo_expired returns 0 if there are no expired requests on the fifo,
- * 1 otherwise.  It is ratelimited so that we only perform the check once per
- * `fifo_expire' interval.  Otherwise a large number of expired requests
- * would create a hopeless seekstorm.
- *
- * See as_antic_expired comment.
- */
-static int as_fifo_expired(struct as_data *ad, int adir)
-{
-       struct request *rq;
-       long delta_jif;
-
-       delta_jif = jiffies - ad->last_check_fifo[adir];
-       if (unlikely(delta_jif < 0))
-               delta_jif = -delta_jif;
-       if (delta_jif < ad->fifo_expire[adir])
-               return 0;
-
-       ad->last_check_fifo[adir] = jiffies;
-
-       if (list_empty(&ad->fifo_list[adir]))
-               return 0;
-
-       rq = rq_entry_fifo(ad->fifo_list[adir].next);
-
-       return time_after(jiffies, rq_fifo_time(rq));
-}
-
-/*
- * as_batch_expired returns true if the current batch has expired. A batch
- * is a set of reads or a set of writes.
- */
-static inline int as_batch_expired(struct as_data *ad)
-{
-       if (ad->changed_batch || ad->new_batch)
-               return 0;
-
-       if (ad->batch_data_dir == BLK_RW_SYNC)
-               /* TODO! add a check so a complete fifo gets written? */
-               return time_after(jiffies, ad->current_batch_expires);
-
-       return time_after(jiffies, ad->current_batch_expires)
-               || ad->current_write_count == 0;
-}
-
-/*
- * move an entry to dispatch queue
- */
-static void as_move_to_dispatch(struct as_data *ad, struct request *rq)
-{
-       const int data_dir = rq_is_sync(rq);
-
-       BUG_ON(RB_EMPTY_NODE(&rq->rb_node));
-
-       as_antic_stop(ad);
-       ad->antic_status = ANTIC_OFF;
-
-       /*
-        * This has to be set in order to be correctly updated by
-        * as_find_next_rq
-        */
-       ad->last_sector[data_dir] = blk_rq_pos(rq) + blk_rq_sectors(rq);
-
-       if (data_dir == BLK_RW_SYNC) {
-               struct io_context *ioc = RQ_IOC(rq);
-               /* In case we have to anticipate after this */
-               copy_io_context(&ad->io_context, &ioc);
-       } else {
-               if (ad->io_context) {
-                       put_io_context(ad->io_context);
-                       ad->io_context = NULL;
-               }
-
-               if (ad->current_write_count != 0)
-                       ad->current_write_count--;
-       }
-       ad->ioc_finished = 0;
-
-       ad->next_rq[data_dir] = as_find_next_rq(ad, rq);
-
-       /*
-        * take it off the sort and fifo list, add to dispatch queue
-        */
-       as_remove_queued_request(ad->q, rq);
-       WARN_ON(RQ_STATE(rq) != AS_RQ_QUEUED);
-
-       elv_dispatch_sort(ad->q, rq);
-
-       RQ_SET_STATE(rq, AS_RQ_DISPATCHED);
-       if (RQ_IOC(rq) && RQ_IOC(rq)->aic)
-               atomic_inc(&RQ_IOC(rq)->aic->nr_dispatched);
-       ad->nr_dispatched++;
-}
-
-/*
- * as_dispatch_request selects the best request according to
- * read/write expire, batch expire, etc, and moves it to the dispatch
- * queue. Returns 1 if a request was found, 0 otherwise.
- */
-static int as_dispatch_request(struct request_queue *q, int force)
-{
-       struct as_data *ad = q->elevator->elevator_data;
-       const int reads = !list_empty(&ad->fifo_list[BLK_RW_SYNC]);
-       const int writes = !list_empty(&ad->fifo_list[BLK_RW_ASYNC]);
-       struct request *rq;
-
-       if (unlikely(force)) {
-               /*
-                * Forced dispatch, accounting is useless.  Reset
-                * accounting states and dump fifo_lists.  Note that
-                * batch_data_dir is reset to BLK_RW_SYNC to avoid
-                * screwing write batch accounting as write batch
-                * accounting occurs on W->R transition.
-                */
-               int dispatched = 0;
-
-               ad->batch_data_dir = BLK_RW_SYNC;
-               ad->changed_batch = 0;
-               ad->new_batch = 0;
-
-               while (ad->next_rq[BLK_RW_SYNC]) {
-                       as_move_to_dispatch(ad, ad->next_rq[BLK_RW_SYNC]);
-                       dispatched++;
-               }
-               ad->last_check_fifo[BLK_RW_SYNC] = jiffies;
-
-               while (ad->next_rq[BLK_RW_ASYNC]) {
-                       as_move_to_dispatch(ad, ad->next_rq[BLK_RW_ASYNC]);
-                       dispatched++;
-               }
-               ad->last_check_fifo[BLK_RW_ASYNC] = jiffies;
-
-               return dispatched;
-       }
-
-       /* Signal that the write batch was uncontended, so we can't time it */
-       if (ad->batch_data_dir == BLK_RW_ASYNC && !reads) {
-               if (ad->current_write_count == 0 || !writes)
-                       ad->write_batch_idled = 1;
-       }
-
-       if (!(reads || writes)
-               || ad->antic_status == ANTIC_WAIT_REQ
-               || ad->antic_status == ANTIC_WAIT_NEXT
-               || ad->changed_batch)
-               return 0;
-
-       if (!(reads && writes && as_batch_expired(ad))) {
-               /*
-                * batch is still running or no reads or no writes
-                */
-               rq = ad->next_rq[ad->batch_data_dir];
-
-               if (ad->batch_data_dir == BLK_RW_SYNC && ad->antic_expire) {
-                       if (as_fifo_expired(ad, BLK_RW_SYNC))
-                               goto fifo_expired;
-
-                       if (as_can_anticipate(ad, rq)) {
-                               as_antic_waitreq(ad);
-                               return 0;
-                       }
-               }
-
-               if (rq) {
-                       /* we have a "next request" */
-                       if (reads && !writes)
-                               ad->current_batch_expires =
-                                       jiffies + ad->batch_expire[BLK_RW_SYNC];
-                       goto dispatch_request;
-               }
-       }
-
-       /*
-        * at this point we are not running a batch. select the appropriate
-        * data direction (read / write)
-        */
-
-       if (reads) {
-               BUG_ON(RB_EMPTY_ROOT(&ad->sort_list[BLK_RW_SYNC]));
-
-               if (writes && ad->batch_data_dir == BLK_RW_SYNC)
-                       /*
-                        * Last batch was a read, switch to writes
-                        */
-                       goto dispatch_writes;
-
-               if (ad->batch_data_dir == BLK_RW_ASYNC) {
-                       WARN_ON(ad->new_batch);
-                       ad->changed_batch = 1;
-               }
-               ad->batch_data_dir = BLK_RW_SYNC;
-               rq = rq_entry_fifo(ad->fifo_list[BLK_RW_SYNC].next);
-               ad->last_check_fifo[ad->batch_data_dir] = jiffies;
-               goto dispatch_request;
-       }
-
-       /*
-        * the last batch was a read
-        */
-
-       if (writes) {
-dispatch_writes:
-               BUG_ON(RB_EMPTY_ROOT(&ad->sort_list[BLK_RW_ASYNC]));
-
-               if (ad->batch_data_dir == BLK_RW_SYNC) {
-                       ad->changed_batch = 1;
-
-                       /*
-                        * new_batch might be 1 when the queue runs out of
-                        * reads. A subsequent submission of a write might
-                        * cause a change of batch before the read is finished.
-                        */
-                       ad->new_batch = 0;
-               }
-               ad->batch_data_dir = BLK_RW_ASYNC;
-               ad->current_write_count = ad->write_batch_count;
-               ad->write_batch_idled = 0;
-               rq = rq_entry_fifo(ad->fifo_list[BLK_RW_ASYNC].next);
-               ad->last_check_fifo[BLK_RW_ASYNC] = jiffies;
-               goto dispatch_request;
-       }
-
-       BUG();
-       return 0;
-
-dispatch_request:
-       /*
-        * If a request has expired, service it.
-        */
-
-       if (as_fifo_expired(ad, ad->batch_data_dir)) {
-fifo_expired:
-               rq = rq_entry_fifo(ad->fifo_list[ad->batch_data_dir].next);
-       }
-
-       if (ad->changed_batch) {
-               WARN_ON(ad->new_batch);
-
-               if (ad->nr_dispatched)
-                       return 0;
-
-               if (ad->batch_data_dir == BLK_RW_ASYNC)
-                       ad->current_batch_expires = jiffies +
-                                       ad->batch_expire[BLK_RW_ASYNC];
-               else
-                       ad->new_batch = 1;
-
-               ad->changed_batch = 0;
-       }
-
-       /*
-        * rq is the selected appropriate request.
-        */
-       as_move_to_dispatch(ad, rq);
-
-       return 1;
-}
-
-/*
- * add rq to rbtree and fifo
- */
-static void as_add_request(struct request_queue *q, struct request *rq)
-{
-       struct as_data *ad = q->elevator->elevator_data;
-       int data_dir;
-
-       RQ_SET_STATE(rq, AS_RQ_NEW);
-
-       data_dir = rq_is_sync(rq);
-
-       rq->elevator_private = as_get_io_context(q->node);
-
-       if (RQ_IOC(rq)) {
-               as_update_iohist(ad, RQ_IOC(rq)->aic, rq);
-               atomic_inc(&RQ_IOC(rq)->aic->nr_queued);
-       }
-
-       as_add_rq_rb(ad, rq);
-
-       /*
-        * set expire time and add to fifo list
-        */
-       rq_set_fifo_time(rq, jiffies + ad->fifo_expire[data_dir]);
-       list_add_tail(&rq->queuelist, &ad->fifo_list[data_dir]);
-
-       as_update_rq(ad, rq); /* keep state machine up to date */
-       RQ_SET_STATE(rq, AS_RQ_QUEUED);
-}
-
-static void as_activate_request(struct request_queue *q, struct request *rq)
-{
-       WARN_ON(RQ_STATE(rq) != AS_RQ_DISPATCHED);
-       RQ_SET_STATE(rq, AS_RQ_REMOVED);
-       if (RQ_IOC(rq) && RQ_IOC(rq)->aic)
-               atomic_dec(&RQ_IOC(rq)->aic->nr_dispatched);
-}
-
-static void as_deactivate_request(struct request_queue *q, struct request *rq)
-{
-       WARN_ON(RQ_STATE(rq) != AS_RQ_REMOVED);
-       RQ_SET_STATE(rq, AS_RQ_DISPATCHED);
-       if (RQ_IOC(rq) && RQ_IOC(rq)->aic)
-               atomic_inc(&RQ_IOC(rq)->aic->nr_dispatched);
-}
-
-/*
- * as_queue_empty tells us if there are requests left in the device. It may
- * not be the case that a driver can get the next request even if the queue
- * is not empty - it is used in the block layer to check for plugging and
- * merging opportunities
- */
-static int as_queue_empty(struct request_queue *q)
-{
-       struct as_data *ad = q->elevator->elevator_data;
-
-       return list_empty(&ad->fifo_list[BLK_RW_ASYNC])
-               && list_empty(&ad->fifo_list[BLK_RW_SYNC]);
-}
-
-static int
-as_merge(struct request_queue *q, struct request **req, struct bio *bio)
-{
-       struct as_data *ad = q->elevator->elevator_data;
-       sector_t rb_key = bio->bi_sector + bio_sectors(bio);
-       struct request *__rq;
-
-       /*
-        * check for front merge
-        */
-       __rq = elv_rb_find(&ad->sort_list[bio_data_dir(bio)], rb_key);
-       if (__rq && elv_rq_merge_ok(__rq, bio)) {
-               *req = __rq;
-               return ELEVATOR_FRONT_MERGE;
-       }
-
-       return ELEVATOR_NO_MERGE;
-}
-
-static void as_merged_request(struct request_queue *q, struct request *req,
-                             int type)
-{
-       struct as_data *ad = q->elevator->elevator_data;
-
-       /*
-        * if the merge was a front merge, we need to reposition request
-        */
-       if (type == ELEVATOR_FRONT_MERGE) {
-               as_del_rq_rb(ad, req);
-               as_add_rq_rb(ad, req);
-               /*
-                * Note! At this stage of this and the next function, our next
-                * request may not be optimal - eg the request may have "grown"
-                * behind the disk head. We currently don't bother adjusting.
-                */
-       }
-}
-
-static void as_merged_requests(struct request_queue *q, struct request *req,
-                               struct request *next)
-{
-       /*
-        * if next expires before rq, assign its expire time to arq
-        * and move into next position (next will be deleted) in fifo
-        */
-       if (!list_empty(&req->queuelist) && !list_empty(&next->queuelist)) {
-               if (time_before(rq_fifo_time(next), rq_fifo_time(req))) {
-                       list_move(&req->queuelist, &next->queuelist);
-                       rq_set_fifo_time(req, rq_fifo_time(next));
-               }
-       }
-
-       /*
-        * kill knowledge of next, this one is a goner
-        */
-       as_remove_queued_request(q, next);
-       as_put_io_context(next);
-
-       RQ_SET_STATE(next, AS_RQ_MERGED);
-}
-
-/*
- * This is executed in a "deferred" process context, by kblockd. It calls the
- * driver's request_fn so the driver can submit that request.
- *
- * IMPORTANT! This guy will reenter the elevator, so set up all queue global
- * state before calling, and don't rely on any state over calls.
- *
- * FIXME! dispatch queue is not a queue at all!
- */
-static void as_work_handler(struct work_struct *work)
-{
-       struct as_data *ad = container_of(work, struct as_data, antic_work);
-
-       blk_run_queue(ad->q);
-}
-
-static int as_may_queue(struct request_queue *q, int rw)
-{
-       int ret = ELV_MQUEUE_MAY;
-       struct as_data *ad = q->elevator->elevator_data;
-       struct io_context *ioc;
-       if (ad->antic_status == ANTIC_WAIT_REQ ||
-                       ad->antic_status == ANTIC_WAIT_NEXT) {
-               ioc = as_get_io_context(q->node);
-               if (ad->io_context == ioc)
-                       ret = ELV_MQUEUE_MUST;
-               put_io_context(ioc);
-       }
-
-       return ret;
-}
-
-static void as_exit_queue(struct elevator_queue *e)
-{
-       struct as_data *ad = e->elevator_data;
-
-       del_timer_sync(&ad->antic_timer);
-       cancel_work_sync(&ad->antic_work);
-
-       BUG_ON(!list_empty(&ad->fifo_list[BLK_RW_SYNC]));
-       BUG_ON(!list_empty(&ad->fifo_list[BLK_RW_ASYNC]));
-
-       put_io_context(ad->io_context);
-       kfree(ad);
-}
-
-/*
- * initialize elevator private data (as_data).
- */
-static void *as_init_queue(struct request_queue *q)
-{
-       struct as_data *ad;
-
-       ad = kmalloc_node(sizeof(*ad), GFP_KERNEL | __GFP_ZERO, q->node);
-       if (!ad)
-               return NULL;
-
-       ad->q = q; /* Identify what queue the data belongs to */
-
-       /* anticipatory scheduling helpers */
-       ad->antic_timer.function = as_antic_timeout;
-       ad->antic_timer.data = (unsigned long)q;
-       init_timer(&ad->antic_timer);
-       INIT_WORK(&ad->antic_work, as_work_handler);
-
-       INIT_LIST_HEAD(&ad->fifo_list[BLK_RW_SYNC]);
-       INIT_LIST_HEAD(&ad->fifo_list[BLK_RW_ASYNC]);
-       ad->sort_list[BLK_RW_SYNC] = RB_ROOT;
-       ad->sort_list[BLK_RW_ASYNC] = RB_ROOT;
-       ad->fifo_expire[BLK_RW_SYNC] = default_read_expire;
-       ad->fifo_expire[BLK_RW_ASYNC] = default_write_expire;
-       ad->antic_expire = default_antic_expire;
-       ad->batch_expire[BLK_RW_SYNC] = default_read_batch_expire;
-       ad->batch_expire[BLK_RW_ASYNC] = default_write_batch_expire;
-
-       ad->current_batch_expires = jiffies + ad->batch_expire[BLK_RW_SYNC];
-       ad->write_batch_count = ad->batch_expire[BLK_RW_ASYNC] / 10;
-       if (ad->write_batch_count < 2)
-               ad->write_batch_count = 2;
-
-       return ad;
-}
-
-/*
- * sysfs parts below
- */
-
-static ssize_t
-as_var_show(unsigned int var, char *page)
-{
-       return sprintf(page, "%d\n", var);
-}
-
-static ssize_t
-as_var_store(unsigned long *var, const char *page, size_t count)
-{
-       char *p = (char *) page;
-
-       *var = simple_strtoul(p, &p, 10);
-       return count;
-}
-
-static ssize_t est_time_show(struct elevator_queue *e, char *page)
-{
-       struct as_data *ad = e->elevator_data;
-       int pos = 0;
-
-       pos += sprintf(page+pos, "%lu %% exit probability\n",
-                               100*ad->exit_prob/256);
-       pos += sprintf(page+pos, "%lu %% probability of exiting without a "
-                               "cooperating process submitting IO\n",
-                               100*ad->exit_no_coop/256);
-       pos += sprintf(page+pos, "%lu ms new thinktime\n", ad->new_ttime_mean);
-       pos += sprintf(page+pos, "%llu sectors new seek distance\n",
-                               (unsigned long long)ad->new_seek_mean);
-
-       return pos;
-}
-
-#define SHOW_FUNCTION(__FUNC, __VAR)                           \
-static ssize_t __FUNC(struct elevator_queue *e, char *page)    \
-{                                                              \
-       struct as_data *ad = e->elevator_data;                  \
-       return as_var_show(jiffies_to_msecs((__VAR)), (page));  \
-}
-SHOW_FUNCTION(as_read_expire_show, ad->fifo_expire[BLK_RW_SYNC]);
-SHOW_FUNCTION(as_write_expire_show, ad->fifo_expire[BLK_RW_ASYNC]);
-SHOW_FUNCTION(as_antic_expire_show, ad->antic_expire);
-SHOW_FUNCTION(as_read_batch_expire_show, ad->batch_expire[BLK_RW_SYNC]);
-SHOW_FUNCTION(as_write_batch_expire_show, ad->batch_expire[BLK_RW_ASYNC]);
-#undef SHOW_FUNCTION
-
-#define STORE_FUNCTION(__FUNC, __PTR, MIN, MAX)                                \
-static ssize_t __FUNC(struct elevator_queue *e, const char *page, size_t count)        \
-{                                                                      \
-       struct as_data *ad = e->elevator_data;                          \
-       int ret = as_var_store(__PTR, (page), count);                   \
-       if (*(__PTR) < (MIN))                                           \
-               *(__PTR) = (MIN);                                       \
-       else if (*(__PTR) > (MAX))                                      \
-               *(__PTR) = (MAX);                                       \
-       *(__PTR) = msecs_to_jiffies(*(__PTR));                          \
-       return ret;                                                     \
-}
-STORE_FUNCTION(as_read_expire_store, &ad->fifo_expire[BLK_RW_SYNC], 0, INT_MAX);
-STORE_FUNCTION(as_write_expire_store,
-                       &ad->fifo_expire[BLK_RW_ASYNC], 0, INT_MAX);
-STORE_FUNCTION(as_antic_expire_store, &ad->antic_expire, 0, INT_MAX);
-STORE_FUNCTION(as_read_batch_expire_store,
-                       &ad->batch_expire[BLK_RW_SYNC], 0, INT_MAX);
-STORE_FUNCTION(as_write_batch_expire_store,
-                       &ad->batch_expire[BLK_RW_ASYNC], 0, INT_MAX);
-#undef STORE_FUNCTION
-
-#define AS_ATTR(name) \
-       __ATTR(name, S_IRUGO|S_IWUSR, as_##name##_show, as_##name##_store)
-
-static struct elv_fs_entry as_attrs[] = {
-       __ATTR_RO(est_time),
-       AS_ATTR(read_expire),
-       AS_ATTR(write_expire),
-       AS_ATTR(antic_expire),
-       AS_ATTR(read_batch_expire),
-       AS_ATTR(write_batch_expire),
-       __ATTR_NULL
-};
-
-static struct elevator_type iosched_as = {
-       .ops = {
-               .elevator_merge_fn =            as_merge,
-               .elevator_merged_fn =           as_merged_request,
-               .elevator_merge_req_fn =        as_merged_requests,
-               .elevator_dispatch_fn =         as_dispatch_request,
-               .elevator_add_req_fn =          as_add_request,
-               .elevator_activate_req_fn =     as_activate_request,
-               .elevator_deactivate_req_fn =   as_deactivate_request,
-               .elevator_queue_empty_fn =      as_queue_empty,
-               .elevator_completed_req_fn =    as_completed_request,
-               .elevator_former_req_fn =       elv_rb_former_request,
-               .elevator_latter_req_fn =       elv_rb_latter_request,
-               .elevator_may_queue_fn =        as_may_queue,
-               .elevator_init_fn =             as_init_queue,
-               .elevator_exit_fn =             as_exit_queue,
-               .trim =                         as_trim,
-       },
-
-       .elevator_attrs = as_attrs,
-       .elevator_name = "anticipatory",
-       .elevator_owner = THIS_MODULE,
-};
-
-static int __init as_init(void)
-{
-       elv_register(&iosched_as);
-
-       return 0;
-}
-
-static void __exit as_exit(void)
-{
-       DECLARE_COMPLETION_ONSTACK(all_gone);
-       elv_unregister(&iosched_as);
-       ioc_gone = &all_gone;
-       /* ioc_gone's update must be visible before reading ioc_count */
-       smp_wmb();
-       if (elv_ioc_count_read(as_ioc_count))
-               wait_for_completion(&all_gone);
-       synchronize_rcu();
-}
-
-module_init(as_init);
-module_exit(as_exit);
-
-MODULE_AUTHOR("Nick Piggin");
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("anticipatory IO scheduler");
diff --git a/block/blk-cgroup.c b/block/blk-cgroup.c
new file mode 100644 (file)
index 0000000..1fa2654
--- /dev/null
@@ -0,0 +1,361 @@
+/*
+ * Common Block IO controller cgroup interface
+ *
+ * Based on ideas and code from CFQ, CFS and BFQ:
+ * Copyright (C) 2003 Jens Axboe <axboe@kernel.dk>
+ *
+ * Copyright (C) 2008 Fabio Checconi <fabio@gandalf.sssup.it>
+ *                   Paolo Valente <paolo.valente@unimore.it>
+ *
+ * Copyright (C) 2009 Vivek Goyal <vgoyal@redhat.com>
+ *                   Nauman Rafique <nauman@google.com>
+ */
+#include <linux/ioprio.h>
+#include <linux/seq_file.h>
+#include <linux/kdev_t.h>
+#include <linux/module.h>
+#include <linux/err.h>
+#include "blk-cgroup.h"
+
+static DEFINE_SPINLOCK(blkio_list_lock);
+static LIST_HEAD(blkio_list);
+
+struct blkio_cgroup blkio_root_cgroup = { .weight = 2*BLKIO_WEIGHT_DEFAULT };
+EXPORT_SYMBOL_GPL(blkio_root_cgroup);
+
+bool blkiocg_css_tryget(struct blkio_cgroup *blkcg)
+{
+       if (!css_tryget(&blkcg->css))
+               return false;
+       return true;
+}
+EXPORT_SYMBOL_GPL(blkiocg_css_tryget);
+
+void blkiocg_css_put(struct blkio_cgroup *blkcg)
+{
+       css_put(&blkcg->css);
+}
+EXPORT_SYMBOL_GPL(blkiocg_css_put);
+
+struct blkio_cgroup *cgroup_to_blkio_cgroup(struct cgroup *cgroup)
+{
+       return container_of(cgroup_subsys_state(cgroup, blkio_subsys_id),
+                           struct blkio_cgroup, css);
+}
+EXPORT_SYMBOL_GPL(cgroup_to_blkio_cgroup);
+
+void blkiocg_update_blkio_group_stats(struct blkio_group *blkg,
+                       unsigned long time, unsigned long sectors)
+{
+       blkg->time += time;
+       blkg->sectors += sectors;
+}
+EXPORT_SYMBOL_GPL(blkiocg_update_blkio_group_stats);
+
+void blkiocg_add_blkio_group(struct blkio_cgroup *blkcg,
+                       struct blkio_group *blkg, void *key, dev_t dev)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&blkcg->lock, flags);
+       rcu_assign_pointer(blkg->key, key);
+       blkg->blkcg_id = css_id(&blkcg->css);
+       hlist_add_head_rcu(&blkg->blkcg_node, &blkcg->blkg_list);
+       spin_unlock_irqrestore(&blkcg->lock, flags);
+#ifdef CONFIG_DEBUG_BLK_CGROUP
+       /* Need to take css reference ? */
+       cgroup_path(blkcg->css.cgroup, blkg->path, sizeof(blkg->path));
+#endif
+       blkg->dev = dev;
+}
+EXPORT_SYMBOL_GPL(blkiocg_add_blkio_group);
+
+static void __blkiocg_del_blkio_group(struct blkio_group *blkg)
+{
+       hlist_del_init_rcu(&blkg->blkcg_node);
+       blkg->blkcg_id = 0;
+}
+
+/*
+ * returns 0 if blkio_group was still on cgroup list. Otherwise returns 1
+ * indicating that blk_group was unhashed by the time we got to it.
+ */
+int blkiocg_del_blkio_group(struct blkio_group *blkg)
+{
+       struct blkio_cgroup *blkcg;
+       unsigned long flags;
+       struct cgroup_subsys_state *css;
+       int ret = 1;
+
+       rcu_read_lock();
+       css = css_lookup(&blkio_subsys, blkg->blkcg_id);
+       if (!css)
+               goto out;
+
+       blkcg = container_of(css, struct blkio_cgroup, css);
+       spin_lock_irqsave(&blkcg->lock, flags);
+       if (!hlist_unhashed(&blkg->blkcg_node)) {
+               __blkiocg_del_blkio_group(blkg);
+               ret = 0;
+       }
+       spin_unlock_irqrestore(&blkcg->lock, flags);
+out:
+       rcu_read_unlock();
+       return ret;
+}
+EXPORT_SYMBOL_GPL(blkiocg_del_blkio_group);
+
+/* called under rcu_read_lock(). */
+struct blkio_group *blkiocg_lookup_group(struct blkio_cgroup *blkcg, void *key)
+{
+       struct blkio_group *blkg;
+       struct hlist_node *n;
+       void *__key;
+
+       hlist_for_each_entry_rcu(blkg, n, &blkcg->blkg_list, blkcg_node) {
+               __key = blkg->key;
+               if (__key == key)
+                       return blkg;
+       }
+
+       return NULL;
+}
+EXPORT_SYMBOL_GPL(blkiocg_lookup_group);
+
+#define SHOW_FUNCTION(__VAR)                                           \
+static u64 blkiocg_##__VAR##_read(struct cgroup *cgroup,               \
+                                      struct cftype *cftype)           \
+{                                                                      \
+       struct blkio_cgroup *blkcg;                                     \
+                                                                       \
+       blkcg = cgroup_to_blkio_cgroup(cgroup);                         \
+       return (u64)blkcg->__VAR;                                       \
+}
+
+SHOW_FUNCTION(weight);
+#undef SHOW_FUNCTION
+
+static int
+blkiocg_weight_write(struct cgroup *cgroup, struct cftype *cftype, u64 val)
+{
+       struct blkio_cgroup *blkcg;
+       struct blkio_group *blkg;
+       struct hlist_node *n;
+       struct blkio_policy_type *blkiop;
+
+       if (val < BLKIO_WEIGHT_MIN || val > BLKIO_WEIGHT_MAX)
+               return -EINVAL;
+
+       blkcg = cgroup_to_blkio_cgroup(cgroup);
+       spin_lock_irq(&blkcg->lock);
+       blkcg->weight = (unsigned int)val;
+       hlist_for_each_entry(blkg, n, &blkcg->blkg_list, blkcg_node) {
+               spin_lock(&blkio_list_lock);
+               list_for_each_entry(blkiop, &blkio_list, list)
+                       blkiop->ops.blkio_update_group_weight_fn(blkg,
+                                       blkcg->weight);
+               spin_unlock(&blkio_list_lock);
+       }
+       spin_unlock_irq(&blkcg->lock);
+       return 0;
+}
+
+#define SHOW_FUNCTION_PER_GROUP(__VAR)                                 \
+static int blkiocg_##__VAR##_read(struct cgroup *cgroup,               \
+                       struct cftype *cftype, struct seq_file *m)      \
+{                                                                      \
+       struct blkio_cgroup *blkcg;                                     \
+       struct blkio_group *blkg;                                       \
+       struct hlist_node *n;                                           \
+                                                                       \
+       if (!cgroup_lock_live_group(cgroup))                            \
+               return -ENODEV;                                         \
+                                                                       \
+       blkcg = cgroup_to_blkio_cgroup(cgroup);                         \
+       rcu_read_lock();                                                \
+       hlist_for_each_entry_rcu(blkg, n, &blkcg->blkg_list, blkcg_node) {\
+               if (blkg->dev)                                          \
+                       seq_printf(m, "%u:%u %lu\n", MAJOR(blkg->dev),  \
+                                MINOR(blkg->dev), blkg->__VAR);        \
+       }                                                               \
+       rcu_read_unlock();                                              \
+       cgroup_unlock();                                                \
+       return 0;                                                       \
+}
+
+SHOW_FUNCTION_PER_GROUP(time);
+SHOW_FUNCTION_PER_GROUP(sectors);
+#ifdef CONFIG_DEBUG_BLK_CGROUP
+SHOW_FUNCTION_PER_GROUP(dequeue);
+#endif
+#undef SHOW_FUNCTION_PER_GROUP
+
+#ifdef CONFIG_DEBUG_BLK_CGROUP
+void blkiocg_update_blkio_group_dequeue_stats(struct blkio_group *blkg,
+                       unsigned long dequeue)
+{
+       blkg->dequeue += dequeue;
+}
+EXPORT_SYMBOL_GPL(blkiocg_update_blkio_group_dequeue_stats);
+#endif
+
+struct cftype blkio_files[] = {
+       {
+               .name = "weight",
+               .read_u64 = blkiocg_weight_read,
+               .write_u64 = blkiocg_weight_write,
+       },
+       {
+               .name = "time",
+               .read_seq_string = blkiocg_time_read,
+       },
+       {
+               .name = "sectors",
+               .read_seq_string = blkiocg_sectors_read,
+       },
+#ifdef CONFIG_DEBUG_BLK_CGROUP
+       {
+               .name = "dequeue",
+               .read_seq_string = blkiocg_dequeue_read,
+       },
+#endif
+};
+
+static int blkiocg_populate(struct cgroup_subsys *subsys, struct cgroup *cgroup)
+{
+       return cgroup_add_files(cgroup, subsys, blkio_files,
+                               ARRAY_SIZE(blkio_files));
+}
+
+static void blkiocg_destroy(struct cgroup_subsys *subsys, struct cgroup *cgroup)
+{
+       struct blkio_cgroup *blkcg = cgroup_to_blkio_cgroup(cgroup);
+       unsigned long flags;
+       struct blkio_group *blkg;
+       void *key;
+       struct blkio_policy_type *blkiop;
+
+       rcu_read_lock();
+remove_entry:
+       spin_lock_irqsave(&blkcg->lock, flags);
+
+       if (hlist_empty(&blkcg->blkg_list)) {
+               spin_unlock_irqrestore(&blkcg->lock, flags);
+               goto done;
+       }
+
+       blkg = hlist_entry(blkcg->blkg_list.first, struct blkio_group,
+                               blkcg_node);
+       key = rcu_dereference(blkg->key);
+       __blkiocg_del_blkio_group(blkg);
+
+       spin_unlock_irqrestore(&blkcg->lock, flags);
+
+       /*
+        * This blkio_group is being unlinked as associated cgroup is going
+        * away. Let all the IO controlling policies know about this event.
+        *
+        * Currently this is static call to one io controlling policy. Once
+        * we have more policies in place, we need some dynamic registration
+        * of callback function.
+        */
+       spin_lock(&blkio_list_lock);
+       list_for_each_entry(blkiop, &blkio_list, list)
+               blkiop->ops.blkio_unlink_group_fn(key, blkg);
+       spin_unlock(&blkio_list_lock);
+       goto remove_entry;
+done:
+       free_css_id(&blkio_subsys, &blkcg->css);
+       rcu_read_unlock();
+       kfree(blkcg);
+}
+
+static struct cgroup_subsys_state *
+blkiocg_create(struct cgroup_subsys *subsys, struct cgroup *cgroup)
+{
+       struct blkio_cgroup *blkcg, *parent_blkcg;
+
+       if (!cgroup->parent) {
+               blkcg = &blkio_root_cgroup;
+               goto done;
+       }
+
+       /* Currently we do not support hierarchy deeper than two level (0,1) */
+       parent_blkcg = cgroup_to_blkio_cgroup(cgroup->parent);
+       if (css_depth(&parent_blkcg->css) > 0)
+               return ERR_PTR(-EINVAL);
+
+       blkcg = kzalloc(sizeof(*blkcg), GFP_KERNEL);
+       if (!blkcg)
+               return ERR_PTR(-ENOMEM);
+
+       blkcg->weight = BLKIO_WEIGHT_DEFAULT;
+done:
+       spin_lock_init(&blkcg->lock);
+       INIT_HLIST_HEAD(&blkcg->blkg_list);
+
+       return &blkcg->css;
+}
+
+/*
+ * We cannot support shared io contexts, as we have no mean to support
+ * two tasks with the same ioc in two different groups without major rework
+ * of the main cic data structures.  For now we allow a task to change
+ * its cgroup only if it's the only owner of its ioc.
+ */
+static int blkiocg_can_attach(struct cgroup_subsys *subsys,
+                               struct cgroup *cgroup, struct task_struct *tsk,
+                               bool threadgroup)
+{
+       struct io_context *ioc;
+       int ret = 0;
+
+       /* task_lock() is needed to avoid races with exit_io_context() */
+       task_lock(tsk);
+       ioc = tsk->io_context;
+       if (ioc && atomic_read(&ioc->nr_tasks) > 1)
+               ret = -EINVAL;
+       task_unlock(tsk);
+
+       return ret;
+}
+
+static void blkiocg_attach(struct cgroup_subsys *subsys, struct cgroup *cgroup,
+                               struct cgroup *prev, struct task_struct *tsk,
+                               bool threadgroup)
+{
+       struct io_context *ioc;
+
+       task_lock(tsk);
+       ioc = tsk->io_context;
+       if (ioc)
+               ioc->cgroup_changed = 1;
+       task_unlock(tsk);
+}
+
+struct cgroup_subsys blkio_subsys = {
+       .name = "blkio",
+       .create = blkiocg_create,
+       .can_attach = blkiocg_can_attach,
+       .attach = blkiocg_attach,
+       .destroy = blkiocg_destroy,
+       .populate = blkiocg_populate,
+       .subsys_id = blkio_subsys_id,
+       .use_id = 1,
+};
+
+void blkio_policy_register(struct blkio_policy_type *blkiop)
+{
+       spin_lock(&blkio_list_lock);
+       list_add_tail(&blkiop->list, &blkio_list);
+       spin_unlock(&blkio_list_lock);
+}
+EXPORT_SYMBOL_GPL(blkio_policy_register);
+
+void blkio_policy_unregister(struct blkio_policy_type *blkiop)
+{
+       spin_lock(&blkio_list_lock);
+       list_del_init(&blkiop->list);
+       spin_unlock(&blkio_list_lock);
+}
+EXPORT_SYMBOL_GPL(blkio_policy_unregister);
diff --git a/block/blk-cgroup.h b/block/blk-cgroup.h
new file mode 100644 (file)
index 0000000..4d316df
--- /dev/null
@@ -0,0 +1,127 @@
+#ifndef _BLK_CGROUP_H
+#define _BLK_CGROUP_H
+/*
+ * Common Block IO controller cgroup interface
+ *
+ * Based on ideas and code from CFQ, CFS and BFQ:
+ * Copyright (C) 2003 Jens Axboe <axboe@kernel.dk>
+ *
+ * Copyright (C) 2008 Fabio Checconi <fabio@gandalf.sssup.it>
+ *                   Paolo Valente <paolo.valente@unimore.it>
+ *
+ * Copyright (C) 2009 Vivek Goyal <vgoyal@redhat.com>
+ *                   Nauman Rafique <nauman@google.com>
+ */
+
+#include <linux/cgroup.h>
+
+#ifdef CONFIG_BLK_CGROUP
+
+struct blkio_cgroup {
+       struct cgroup_subsys_state css;
+       unsigned int weight;
+       spinlock_t lock;
+       struct hlist_head blkg_list;
+};
+
+struct blkio_group {
+       /* An rcu protected unique identifier for the group */
+       void *key;
+       struct hlist_node blkcg_node;
+       unsigned short blkcg_id;
+#ifdef CONFIG_DEBUG_BLK_CGROUP
+       /* Store cgroup path */
+       char path[128];
+       /* How many times this group has been removed from service tree */
+       unsigned long dequeue;
+#endif
+       /* The device MKDEV(major, minor), this group has been created for */
+       dev_t   dev;
+
+       /* total disk time and nr sectors dispatched by this group */
+       unsigned long time;
+       unsigned long sectors;
+};
+
+extern bool blkiocg_css_tryget(struct blkio_cgroup *blkcg);
+extern void blkiocg_css_put(struct blkio_cgroup *blkcg);
+
+typedef void (blkio_unlink_group_fn) (void *key, struct blkio_group *blkg);
+typedef void (blkio_update_group_weight_fn) (struct blkio_group *blkg,
+                                               unsigned int weight);
+
+struct blkio_policy_ops {
+       blkio_unlink_group_fn *blkio_unlink_group_fn;
+       blkio_update_group_weight_fn *blkio_update_group_weight_fn;
+};
+
+struct blkio_policy_type {
+       struct list_head list;
+       struct blkio_policy_ops ops;
+};
+
+/* Blkio controller policy registration */
+extern void blkio_policy_register(struct blkio_policy_type *);
+extern void blkio_policy_unregister(struct blkio_policy_type *);
+
+#else
+
+struct blkio_group {
+};
+
+struct blkio_policy_type {
+};
+
+static inline void blkio_policy_register(struct blkio_policy_type *blkiop) { }
+static inline void blkio_policy_unregister(struct blkio_policy_type *blkiop) { }
+
+#endif
+
+#define BLKIO_WEIGHT_MIN       100
+#define BLKIO_WEIGHT_MAX       1000
+#define BLKIO_WEIGHT_DEFAULT   500
+
+#ifdef CONFIG_DEBUG_BLK_CGROUP
+static inline char *blkg_path(struct blkio_group *blkg)
+{
+       return blkg->path;
+}
+void blkiocg_update_blkio_group_dequeue_stats(struct blkio_group *blkg,
+                               unsigned long dequeue);
+#else
+static inline char *blkg_path(struct blkio_group *blkg) { return NULL; }
+static inline void blkiocg_update_blkio_group_dequeue_stats(
+                       struct blkio_group *blkg, unsigned long dequeue) {}
+#endif
+
+#ifdef CONFIG_BLK_CGROUP
+extern struct blkio_cgroup blkio_root_cgroup;
+extern struct blkio_cgroup *cgroup_to_blkio_cgroup(struct cgroup *cgroup);
+extern void blkiocg_add_blkio_group(struct blkio_cgroup *blkcg,
+                       struct blkio_group *blkg, void *key, dev_t dev);
+extern int blkiocg_del_blkio_group(struct blkio_group *blkg);
+extern struct blkio_group *blkiocg_lookup_group(struct blkio_cgroup *blkcg,
+                                               void *key);
+void blkiocg_update_blkio_group_stats(struct blkio_group *blkg,
+                       unsigned long time, unsigned long sectors);
+#else
+struct cgroup;
+static inline struct blkio_cgroup *
+cgroup_to_blkio_cgroup(struct cgroup *cgroup) { return NULL; }
+
+static inline void blkiocg_add_blkio_group(struct blkio_cgroup *blkcg,
+                       struct blkio_group *blkg, void *key, dev_t dev)
+{
+}
+
+static inline int
+blkiocg_del_blkio_group(struct blkio_group *blkg) { return 0; }
+
+static inline struct blkio_group *
+blkiocg_lookup_group(struct blkio_cgroup *blkcg, void *key) { return NULL; }
+static inline void blkiocg_update_blkio_group_stats(struct blkio_group *blkg,
+                       unsigned long time, unsigned long sectors)
+{
+}
+#endif
+#endif /* _BLK_CGROUP_H */
index 71da511..718897e 100644 (file)
@@ -2358,6 +2358,25 @@ void blk_rq_bio_prep(struct request_queue *q, struct request *rq,
                rq->rq_disk = bio->bi_bdev->bd_disk;
 }
 
+#if ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE
+/**
+ * rq_flush_dcache_pages - Helper function to flush all pages in a request
+ * @rq: the request to be flushed
+ *
+ * Description:
+ *     Flush all pages in @rq.
+ */
+void rq_flush_dcache_pages(struct request *rq)
+{
+       struct req_iterator iter;
+       struct bio_vec *bvec;
+
+       rq_for_each_segment(bvec, rq, iter)
+               flush_dcache_page(bvec->bv_page);
+}
+EXPORT_SYMBOL_GPL(rq_flush_dcache_pages);
+#endif
+
 /**
  * blk_lld_busy - Check if underlying low-level drivers of a device are busy
  * @q : the queue of the device being checked
index d4ed600..cbdabb0 100644 (file)
@@ -66,22 +66,22 @@ static void cfq_exit(struct io_context *ioc)
 }
 
 /* Called by the exitting task */
-void exit_io_context(void)
+void exit_io_context(struct task_struct *task)
 {
        struct io_context *ioc;
 
-       task_lock(current);
-       ioc = current->io_context;
-       current->io_context = NULL;
-       task_unlock(current);
+       task_lock(task);
+       ioc = task->io_context;
+       task->io_context = NULL;
+       task_unlock(task);
 
        if (atomic_dec_and_test(&ioc->nr_tasks)) {
                if (ioc->aic && ioc->aic->exit)
                        ioc->aic->exit(ioc->aic);
                cfq_exit(ioc);
 
-               put_io_context(ioc);
        }
+       put_io_context(ioc);
 }
 
 struct io_context *alloc_io_context(gfp_t gfp_flags, int node)
index 66d4aa8..dd1f1e0 100644 (file)
@@ -8,6 +8,7 @@
 #include <linux/blkdev.h>
 #include <linux/bootmem.h>     /* for max_pfn/max_low_pfn */
 #include <linux/gcd.h>
+#include <linux/jiffies.h>
 
 #include "blk.h"
 
@@ -96,7 +97,11 @@ void blk_set_default_limits(struct queue_limits *lim)
        lim->max_segment_size = MAX_SEGMENT_SIZE;
        lim->max_sectors = BLK_DEF_MAX_SECTORS;
        lim->max_hw_sectors = INT_MAX;
-       lim->max_discard_sectors = SAFE_MAX_SECTORS;
+       lim->max_discard_sectors = 0;
+       lim->discard_granularity = 0;
+       lim->discard_alignment = 0;
+       lim->discard_misaligned = 0;
+       lim->discard_zeroes_data = -1;
        lim->logical_block_size = lim->physical_block_size = lim->io_min = 512;
        lim->bounce_pfn = (unsigned long)(BLK_BOUNCE_ANY >> PAGE_SHIFT);
        lim->alignment_offset = 0;
@@ -141,7 +146,7 @@ void blk_queue_make_request(struct request_queue *q, make_request_fn *mfn)
        q->nr_batching = BLK_BATCH_REQ;
 
        q->unplug_thresh = 4;           /* hmm */
-       q->unplug_delay = (3 * HZ) / 1000;      /* 3 milliseconds */
+       q->unplug_delay = msecs_to_jiffies(3);  /* 3 milliseconds */
        if (q->unplug_delay == 0)
                q->unplug_delay = 1;
 
@@ -488,6 +493,16 @@ void blk_queue_stack_limits(struct request_queue *t, struct request_queue *b)
 }
 EXPORT_SYMBOL(blk_queue_stack_limits);
 
+static unsigned int lcm(unsigned int a, unsigned int b)
+{
+       if (a && b)
+               return (a * b) / gcd(a, b);
+       else if (b)
+               return b;
+
+       return a;
+}
+
 /**
  * blk_stack_limits - adjust queue_limits for stacked devices
  * @t: the stacking driver limits (top)
@@ -502,6 +517,10 @@ EXPORT_SYMBOL(blk_queue_stack_limits);
 int blk_stack_limits(struct queue_limits *t, struct queue_limits *b,
                     sector_t offset)
 {
+       int ret;
+
+       ret = 0;
+
        t->max_sectors = min_not_zero(t->max_sectors, b->max_sectors);
        t->max_hw_sectors = min_not_zero(t->max_hw_sectors, b->max_hw_sectors);
        t->bounce_pfn = min_not_zero(t->bounce_pfn, b->bounce_pfn);
@@ -526,12 +545,19 @@ int blk_stack_limits(struct queue_limits *t, struct queue_limits *b,
 
        t->io_min = max(t->io_min, b->io_min);
        t->no_cluster |= b->no_cluster;
+       t->discard_zeroes_data &= b->discard_zeroes_data;
 
        /* Bottom device offset aligned? */
        if (offset &&
            (offset & (b->physical_block_size - 1)) != b->alignment_offset) {
                t->misaligned = 1;
-               return -1;
+               ret = -1;
+       }
+
+       if (offset &&
+           (offset & (b->discard_granularity - 1)) != b->discard_alignment) {
+               t->discard_misaligned = 1;
+               ret = -1;
        }
 
        /* If top has no alignment offset, inherit from bottom */
@@ -539,23 +565,26 @@ int blk_stack_limits(struct queue_limits *t, struct queue_limits *b,
                t->alignment_offset =
                        b->alignment_offset & (b->physical_block_size - 1);
 
+       if (!t->discard_alignment)
+               t->discard_alignment =
+                       b->discard_alignment & (b->discard_granularity - 1);
+
        /* Top device aligned on logical block boundary? */
        if (t->alignment_offset & (t->logical_block_size - 1)) {
                t->misaligned = 1;
-               return -1;
+               ret = -1;
        }
 
-       /* Find lcm() of optimal I/O size */
-       if (t->io_opt && b->io_opt)
-               t->io_opt = (t->io_opt * b->io_opt) / gcd(t->io_opt, b->io_opt);
-       else if (b->io_opt)
-               t->io_opt = b->io_opt;
+       /* Find lcm() of optimal I/O size and granularity */
+       t->io_opt = lcm(t->io_opt, b->io_opt);
+       t->discard_granularity = lcm(t->discard_granularity,
+                                    b->discard_granularity);
 
        /* Verify that optimal I/O size is a multiple of io_min */
        if (t->io_min && t->io_opt % t->io_min)
-               return -1;
+               ret = -1;
 
-       return 0;
+       return ret;
 }
 EXPORT_SYMBOL(blk_stack_limits);
 
index 8a6d81a..8606c95 100644 (file)
@@ -126,6 +126,21 @@ static ssize_t queue_io_opt_show(struct request_queue *q, char *page)
        return queue_var_show(queue_io_opt(q), page);
 }
 
+static ssize_t queue_discard_granularity_show(struct request_queue *q, char *page)
+{
+       return queue_var_show(q->limits.discard_granularity, page);
+}
+
+static ssize_t queue_discard_max_show(struct request_queue *q, char *page)
+{
+       return queue_var_show(q->limits.max_discard_sectors << 9, page);
+}
+
+static ssize_t queue_discard_zeroes_data_show(struct request_queue *q, char *page)
+{
+       return queue_var_show(queue_discard_zeroes_data(q), page);
+}
+
 static ssize_t
 queue_max_sectors_store(struct request_queue *q, const char *page, size_t count)
 {
@@ -293,6 +308,21 @@ static struct queue_sysfs_entry queue_io_opt_entry = {
        .show = queue_io_opt_show,
 };
 
+static struct queue_sysfs_entry queue_discard_granularity_entry = {
+       .attr = {.name = "discard_granularity", .mode = S_IRUGO },
+       .show = queue_discard_granularity_show,
+};
+
+static struct queue_sysfs_entry queue_discard_max_entry = {
+       .attr = {.name = "discard_max_bytes", .mode = S_IRUGO },
+       .show = queue_discard_max_show,
+};
+
+static struct queue_sysfs_entry queue_discard_zeroes_data_entry = {
+       .attr = {.name = "discard_zeroes_data", .mode = S_IRUGO },
+       .show = queue_discard_zeroes_data_show,
+};
+
 static struct queue_sysfs_entry queue_nonrot_entry = {
        .attr = {.name = "rotational", .mode = S_IRUGO | S_IWUSR },
        .show = queue_nonrot_show,
@@ -328,6 +358,9 @@ static struct attribute *default_attrs[] = {
        &queue_physical_block_size_entry.attr,
        &queue_io_min_entry.attr,
        &queue_io_opt_entry.attr,
+       &queue_discard_granularity_entry.attr,
+       &queue_discard_max_entry.attr,
+       &queue_discard_zeroes_data_entry.attr,
        &queue_nonrot_entry.attr,
        &queue_nomerges_entry.attr,
        &queue_rq_affinity_entry.attr,
index 0676301..a9fd2d8 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/blkdev.h>
 #include <linux/poll.h>
 #include <linux/cdev.h>
+#include <linux/jiffies.h>
 #include <linux/percpu.h>
 #include <linux/uio.h>
 #include <linux/idr.h>
@@ -197,7 +198,7 @@ static int blk_fill_sgv4_hdr_rq(struct request_queue *q, struct request *rq,
        rq->cmd_len = hdr->request_len;
        rq->cmd_type = REQ_TYPE_BLOCK_PC;
 
-       rq->timeout = (hdr->timeout * HZ) / 1000;
+       rq->timeout = msecs_to_jiffies(hdr->timeout);
        if (!rq->timeout)
                rq->timeout = q->sg_timeout;
        if (!rq->timeout)
index aa1e953..cfb0b2f 100644 (file)
@@ -9,9 +9,11 @@
 #include <linux/module.h>
 #include <linux/blkdev.h>
 #include <linux/elevator.h>
+#include <linux/jiffies.h>
 #include <linux/rbtree.h>
 #include <linux/ioprio.h>
 #include <linux/blktrace_api.h>
+#include "blk-cgroup.h"
 
 /*
  * tunables
@@ -27,6 +29,8 @@ static const int cfq_slice_sync = HZ / 10;
 static int cfq_slice_async = HZ / 25;
 static const int cfq_slice_async_rq = 2;
 static int cfq_slice_idle = HZ / 125;
+static const int cfq_target_latency = HZ * 3/10; /* 300 ms */
+static const int cfq_hist_divisor = 4;
 
 /*
  * offset from end of service tree
@@ -38,8 +42,15 @@ static int cfq_slice_idle = HZ / 125;
  */
 #define CFQ_MIN_TT             (2)
 
+/*
+ * Allow merged cfqqs to perform this amount of seeky I/O before
+ * deciding to break the queues up again.
+ */
+#define CFQQ_COOP_TOUT         (HZ)
+
 #define CFQ_SLICE_SCALE                (5)
 #define CFQ_HW_QUEUE_MIN       (5)
+#define CFQ_SERVICE_SHIFT       12
 
 #define RQ_CIC(rq)             \
        ((struct cfq_io_context *) (rq)->elevator_private)
@@ -57,6 +68,7 @@ static DEFINE_SPINLOCK(ioc_gone_lock);
 #define cfq_class_rt(cfqq)     ((cfqq)->ioprio_class == IOPRIO_CLASS_RT)
 
 #define sample_valid(samples)  ((samples) > 80)
+#define rb_entry_cfqg(node)    rb_entry((node), struct cfq_group, rb_node)
 
 /*
  * Most of our rbtree usage is for sorting with min extraction, so
@@ -67,8 +79,12 @@ static DEFINE_SPINLOCK(ioc_gone_lock);
 struct cfq_rb_root {
        struct rb_root rb;
        struct rb_node *left;
+       unsigned count;
+       u64 min_vdisktime;
+       struct rb_node *active;
+       unsigned total_weight;
 };
-#define CFQ_RB_ROOT    (struct cfq_rb_root) { RB_ROOT, NULL, }
+#define CFQ_RB_ROOT    (struct cfq_rb_root) { RB_ROOT, NULL, 0, 0, }
 
 /*
  * Per process-grouping structure
@@ -99,6 +115,11 @@ struct cfq_queue {
        /* fifo list of requests in sort_list */
        struct list_head fifo;
 
+       /* time when queue got scheduled in to dispatch first request. */
+       unsigned long dispatch_start;
+       unsigned int allocated_slice;
+       /* time when first request from queue completed and slice started. */
+       unsigned long slice_start;
        unsigned long slice_end;
        long slice_resid;
        unsigned int slice_dispatch;
@@ -112,7 +133,71 @@ struct cfq_queue {
        unsigned short ioprio, org_ioprio;
        unsigned short ioprio_class, org_ioprio_class;
 
+       unsigned int seek_samples;
+       u64 seek_total;
+       sector_t seek_mean;
+       sector_t last_request_pos;
+       unsigned long seeky_start;
+
        pid_t pid;
+
+       struct cfq_rb_root *service_tree;
+       struct cfq_queue *new_cfqq;
+       struct cfq_group *cfqg;
+       struct cfq_group *orig_cfqg;
+       /* Sectors dispatched in current dispatch round */
+       unsigned long nr_sectors;
+};
+
+/*
+ * First index in the service_trees.
+ * IDLE is handled separately, so it has negative index
+ */
+enum wl_prio_t {
+       BE_WORKLOAD = 0,
+       RT_WORKLOAD = 1,
+       IDLE_WORKLOAD = 2,
+};
+
+/*
+ * Second index in the service_trees.
+ */
+enum wl_type_t {
+       ASYNC_WORKLOAD = 0,
+       SYNC_NOIDLE_WORKLOAD = 1,
+       SYNC_WORKLOAD = 2
+};
+
+/* This is per cgroup per device grouping structure */
+struct cfq_group {
+       /* group service_tree member */
+       struct rb_node rb_node;
+
+       /* group service_tree key */
+       u64 vdisktime;
+       unsigned int weight;
+       bool on_st;
+
+       /* number of cfqq currently on this group */
+       int nr_cfqq;
+
+       /* Per group busy queus average. Useful for workload slice calc. */
+       unsigned int busy_queues_avg[2];
+       /*
+        * rr lists of queues with requests, onle rr for each priority class.
+        * Counts are embedded in the cfq_rb_root
+        */
+       struct cfq_rb_root service_trees[2][3];
+       struct cfq_rb_root service_tree_idle;
+
+       unsigned long saved_workload_slice;
+       enum wl_type_t saved_workload;
+       enum wl_prio_t saved_serving_prio;
+       struct blkio_group blkg;
+#ifdef CONFIG_CFQ_GROUP_IOSCHED
+       struct hlist_node cfqd_node;
+       atomic_t ref;
+#endif
 };
 
 /*
@@ -120,11 +205,20 @@ struct cfq_queue {
  */
 struct cfq_data {
        struct request_queue *queue;
+       /* Root service tree for cfq_groups */
+       struct cfq_rb_root grp_service_tree;
+       struct cfq_group root_group;
+       /* Number of active cfq groups on group service tree */
+       int nr_groups;
 
        /*
-        * rr list of queues with requests and the count of them
+        * The priority currently being served
         */
-       struct cfq_rb_root service_tree;
+       enum wl_prio_t serving_prio;
+       enum wl_type_t serving_type;
+       unsigned long workload_expires;
+       struct cfq_group *serving_group;
+       bool noidle_tree_requires_idle;
 
        /*
         * Each priority tree is sorted by next_request position.  These
@@ -143,8 +237,14 @@ struct cfq_data {
         */
        int rq_queued;
        int hw_tag;
-       int hw_tag_samples;
-       int rq_in_driver_peak;
+       /*
+        * hw_tag can be
+        * -1 => indeterminate, (cfq will behave as if NCQ is present, to allow better detection)
+        *  1 => NCQ is present (hw_tag_est_depth is the estimated max depth)
+        *  0 => no NCQ
+        */
+       int hw_tag_est_depth;
+       unsigned int hw_tag_samples;
 
        /*
         * idle window management
@@ -174,6 +274,7 @@ struct cfq_data {
        unsigned int cfq_slice_async_rq;
        unsigned int cfq_slice_idle;
        unsigned int cfq_latency;
+       unsigned int cfq_group_isolation;
 
        struct list_head cic_list;
 
@@ -183,8 +284,28 @@ struct cfq_data {
        struct cfq_queue oom_cfqq;
 
        unsigned long last_end_sync_rq;
+
+       /* List of cfq groups being managed on this device*/
+       struct hlist_head cfqg_list;
+       struct rcu_head rcu;
 };
 
+static struct cfq_group *cfq_get_next_cfqg(struct cfq_data *cfqd);
+
+static struct cfq_rb_root *service_tree_for(struct cfq_group *cfqg,
+                                           enum wl_prio_t prio,
+                                           enum wl_type_t type,
+                                           struct cfq_data *cfqd)
+{
+       if (!cfqg)
+               return NULL;
+
+       if (prio == IDLE_WORKLOAD)
+               return &cfqg->service_tree_idle;
+
+       return &cfqg->service_trees[prio][type];
+}
+
 enum cfqq_state_flags {
        CFQ_CFQQ_FLAG_on_rr = 0,        /* on round-robin busy list */
        CFQ_CFQQ_FLAG_wait_request,     /* waiting for a request */
@@ -195,8 +316,10 @@ enum cfqq_state_flags {
        CFQ_CFQQ_FLAG_prio_changed,     /* task priority has changed */
        CFQ_CFQQ_FLAG_slice_new,        /* no requests dispatched in slice */
        CFQ_CFQQ_FLAG_sync,             /* synchronous queue */
-       CFQ_CFQQ_FLAG_coop,             /* has done a coop jump of the queue */
-       CFQ_CFQQ_FLAG_coop_preempt,     /* coop preempt */
+       CFQ_CFQQ_FLAG_coop,             /* cfqq is shared */
+       CFQ_CFQQ_FLAG_deep,             /* sync cfqq experienced large depth */
+       CFQ_CFQQ_FLAG_wait_busy,        /* Waiting for next request */
+       CFQ_CFQQ_FLAG_wait_busy_done,   /* Got new request. Expire the queue */
 };
 
 #define CFQ_CFQQ_FNS(name)                                             \
@@ -223,14 +346,78 @@ CFQ_CFQQ_FNS(prio_changed);
 CFQ_CFQQ_FNS(slice_new);
 CFQ_CFQQ_FNS(sync);
 CFQ_CFQQ_FNS(coop);
-CFQ_CFQQ_FNS(coop_preempt);
+CFQ_CFQQ_FNS(deep);
+CFQ_CFQQ_FNS(wait_busy);
+CFQ_CFQQ_FNS(wait_busy_done);
 #undef CFQ_CFQQ_FNS
 
+#ifdef CONFIG_DEBUG_CFQ_IOSCHED
+#define cfq_log_cfqq(cfqd, cfqq, fmt, args...) \
+       blk_add_trace_msg((cfqd)->queue, "cfq%d%c %s " fmt, (cfqq)->pid, \
+                       cfq_cfqq_sync((cfqq)) ? 'S' : 'A', \
+                       blkg_path(&(cfqq)->cfqg->blkg), ##args);
+
+#define cfq_log_cfqg(cfqd, cfqg, fmt, args...)                         \
+       blk_add_trace_msg((cfqd)->queue, "%s " fmt,                     \
+                               blkg_path(&(cfqg)->blkg), ##args);      \
+
+#else
 #define cfq_log_cfqq(cfqd, cfqq, fmt, args...) \
        blk_add_trace_msg((cfqd)->queue, "cfq%d " fmt, (cfqq)->pid, ##args)
+#define cfq_log_cfqg(cfqd, cfqg, fmt, args...)         do {} while (0);
+#endif
 #define cfq_log(cfqd, fmt, args...)    \
        blk_add_trace_msg((cfqd)->queue, "cfq " fmt, ##args)
 
+/* Traverses through cfq group service trees */
+#define for_each_cfqg_st(cfqg, i, j, st) \
+       for (i = 0; i <= IDLE_WORKLOAD; i++) \
+               for (j = 0, st = i < IDLE_WORKLOAD ? &cfqg->service_trees[i][j]\
+                       : &cfqg->service_tree_idle; \
+                       (i < IDLE_WORKLOAD && j <= SYNC_WORKLOAD) || \
+                       (i == IDLE_WORKLOAD && j == 0); \
+                       j++, st = i < IDLE_WORKLOAD ? \
+                       &cfqg->service_trees[i][j]: NULL) \
+
+
+static inline enum wl_prio_t cfqq_prio(struct cfq_queue *cfqq)
+{
+       if (cfq_class_idle(cfqq))
+               return IDLE_WORKLOAD;
+       if (cfq_class_rt(cfqq))
+               return RT_WORKLOAD;
+       return BE_WORKLOAD;
+}
+
+
+static enum wl_type_t cfqq_type(struct cfq_queue *cfqq)
+{
+       if (!cfq_cfqq_sync(cfqq))
+               return ASYNC_WORKLOAD;
+       if (!cfq_cfqq_idle_window(cfqq))
+               return SYNC_NOIDLE_WORKLOAD;
+       return SYNC_WORKLOAD;
+}
+
+static inline int cfq_group_busy_queues_wl(enum wl_prio_t wl,
+                                       struct cfq_data *cfqd,
+                                       struct cfq_group *cfqg)
+{
+       if (wl == IDLE_WORKLOAD)
+               return cfqg->service_tree_idle.count;
+
+       return cfqg->service_trees[wl][ASYNC_WORKLOAD].count
+               + cfqg->service_trees[wl][SYNC_NOIDLE_WORKLOAD].count
+               + cfqg->service_trees[wl][SYNC_WORKLOAD].count;
+}
+
+static inline int cfqg_busy_async_queues(struct cfq_data *cfqd,
+                                       struct cfq_group *cfqg)
+{
+       return cfqg->service_trees[RT_WORKLOAD][ASYNC_WORKLOAD].count
+               + cfqg->service_trees[BE_WORKLOAD][ASYNC_WORKLOAD].count;
+}
+
 static void cfq_dispatch_insert(struct request_queue *, struct request *);
 static struct cfq_queue *cfq_get_queue(struct cfq_data *, bool,
                                       struct io_context *, gfp_t);
@@ -279,7 +466,7 @@ static int cfq_queue_empty(struct request_queue *q)
 {
        struct cfq_data *cfqd = q->elevator->elevator_data;
 
-       return !cfqd->busy_queues;
+       return !cfqd->rq_queued;
 }
 
 /*
@@ -303,10 +490,110 @@ cfq_prio_to_slice(struct cfq_data *cfqd, struct cfq_queue *cfqq)
        return cfq_prio_slice(cfqd, cfq_cfqq_sync(cfqq), cfqq->ioprio);
 }
 
+static inline u64 cfq_scale_slice(unsigned long delta, struct cfq_group *cfqg)
+{
+       u64 d = delta << CFQ_SERVICE_SHIFT;
+
+       d = d * BLKIO_WEIGHT_DEFAULT;
+       do_div(d, cfqg->weight);
+       return d;
+}
+
+static inline u64 max_vdisktime(u64 min_vdisktime, u64 vdisktime)
+{
+       s64 delta = (s64)(vdisktime - min_vdisktime);
+       if (delta > 0)
+               min_vdisktime = vdisktime;
+
+       return min_vdisktime;
+}
+
+static inline u64 min_vdisktime(u64 min_vdisktime, u64 vdisktime)
+{
+       s64 delta = (s64)(vdisktime - min_vdisktime);
+       if (delta < 0)
+               min_vdisktime = vdisktime;
+
+       return min_vdisktime;
+}
+
+static void update_min_vdisktime(struct cfq_rb_root *st)
+{
+       u64 vdisktime = st->min_vdisktime;
+       struct cfq_group *cfqg;
+
+       if (st->active) {
+               cfqg = rb_entry_cfqg(st->active);
+               vdisktime = cfqg->vdisktime;
+       }
+
+       if (st->left) {
+               cfqg = rb_entry_cfqg(st->left);
+               vdisktime = min_vdisktime(vdisktime, cfqg->vdisktime);
+       }
+
+       st->min_vdisktime = max_vdisktime(st->min_vdisktime, vdisktime);
+}
+
+/*
+ * get averaged number of queues of RT/BE priority.
+ * average is updated, with a formula that gives more weight to higher numbers,
+ * to quickly follows sudden increases and decrease slowly
+ */
+
+static inline unsigned cfq_group_get_avg_queues(struct cfq_data *cfqd,
+                                       struct cfq_group *cfqg, bool rt)
+{
+       unsigned min_q, max_q;
+       unsigned mult  = cfq_hist_divisor - 1;
+       unsigned round = cfq_hist_divisor / 2;
+       unsigned busy = cfq_group_busy_queues_wl(rt, cfqd, cfqg);
+
+       min_q = min(cfqg->busy_queues_avg[rt], busy);
+       max_q = max(cfqg->busy_queues_avg[rt], busy);
+       cfqg->busy_queues_avg[rt] = (mult * max_q + min_q + round) /
+               cfq_hist_divisor;
+       return cfqg->busy_queues_avg[rt];
+}
+
+static inline unsigned
+cfq_group_slice(struct cfq_data *cfqd, struct cfq_group *cfqg)
+{
+       struct cfq_rb_root *st = &cfqd->grp_service_tree;
+
+       return cfq_target_latency * cfqg->weight / st->total_weight;
+}
+
 static inline void
 cfq_set_prio_slice(struct cfq_data *cfqd, struct cfq_queue *cfqq)
 {
-       cfqq->slice_end = cfq_prio_to_slice(cfqd, cfqq) + jiffies;
+       unsigned slice = cfq_prio_to_slice(cfqd, cfqq);
+       if (cfqd->cfq_latency) {
+               /*
+                * interested queues (we consider only the ones with the same
+                * priority class in the cfq group)
+                */
+               unsigned iq = cfq_group_get_avg_queues(cfqd, cfqq->cfqg,
+                                               cfq_class_rt(cfqq));
+               unsigned sync_slice = cfqd->cfq_slice[1];
+               unsigned expect_latency = sync_slice * iq;
+               unsigned group_slice = cfq_group_slice(cfqd, cfqq->cfqg);
+
+               if (expect_latency > group_slice) {
+                       unsigned base_low_slice = 2 * cfqd->cfq_slice_idle;
+                       /* scale low_slice according to IO priority
+                        * and sync vs async */
+                       unsigned low_slice =
+                               min(slice, base_low_slice * slice / sync_slice);
+                       /* the adapted slice value is scaled to fit all iqs
+                        * into the target latency */
+                       slice = max(slice * group_slice / expect_latency,
+                                   low_slice);
+               }
+       }
+       cfqq->slice_start = jiffies;
+       cfqq->slice_end = jiffies + slice;
+       cfqq->allocated_slice = slice;
        cfq_log_cfqq(cfqd, cfqq, "set_slice=%lu", cfqq->slice_end - jiffies);
 }
 
@@ -331,9 +618,9 @@ static inline bool cfq_slice_used(struct cfq_queue *cfqq)
  * behind the head is penalized and only allowed to a certain extent.
  */
 static struct request *
-cfq_choose_req(struct cfq_data *cfqd, struct request *rq1, struct request *rq2)
+cfq_choose_req(struct cfq_data *cfqd, struct request *rq1, struct request *rq2, sector_t last)
 {
-       sector_t last, s1, s2, d1 = 0, d2 = 0;
+       sector_t s1, s2, d1 = 0, d2 = 0;
        unsigned long back_max;
 #define CFQ_RQ1_WRAP   0x01 /* request 1 wraps */
 #define CFQ_RQ2_WRAP   0x02 /* request 2 wraps */
@@ -356,8 +643,6 @@ cfq_choose_req(struct cfq_data *cfqd, struct request *rq1, struct request *rq2)
        s1 = blk_rq_pos(rq1);
        s2 = blk_rq_pos(rq2);
 
-       last = cfqd->last_position;
-
        /*
         * by definition, 1KiB is 2 sectors
         */
@@ -425,6 +710,10 @@ cfq_choose_req(struct cfq_data *cfqd, struct request *rq1, struct request *rq2)
  */
 static struct cfq_queue *cfq_rb_first(struct cfq_rb_root *root)
 {
+       /* Service tree is empty */
+       if (!root->count)
+               return NULL;
+
        if (!root->left)
                root->left = rb_first(&root->rb);
 
@@ -434,6 +723,17 @@ static struct cfq_queue *cfq_rb_first(struct cfq_rb_root *root)
        return NULL;
 }
 
+static struct cfq_group *cfq_rb_first_group(struct cfq_rb_root *root)
+{
+       if (!root->left)
+               root->left = rb_first(&root->rb);
+
+       if (root->left)
+               return rb_entry_cfqg(root->left);
+
+       return NULL;
+}
+
 static void rb_erase_init(struct rb_node *n, struct rb_root *root)
 {
        rb_erase(n, root);
@@ -445,6 +745,7 @@ static void cfq_rb_erase(struct rb_node *n, struct cfq_rb_root *root)
        if (root->left == n)
                root->left = NULL;
        rb_erase_init(n, &root->rb);
+       --root->count;
 }
 
 /*
@@ -471,7 +772,7 @@ cfq_find_next_rq(struct cfq_data *cfqd, struct cfq_queue *cfqq,
                        next = rb_entry_rq(rbnext);
        }
 
-       return cfq_choose_req(cfqd, next, prev);
+       return cfq_choose_req(cfqd, next, prev, blk_rq_pos(last));
 }
 
 static unsigned long cfq_slice_offset(struct cfq_data *cfqd,
@@ -480,12 +781,336 @@ static unsigned long cfq_slice_offset(struct cfq_data *cfqd,
        /*
         * just an approximation, should be ok.
         */
-       return (cfqd->busy_queues - 1) * (cfq_prio_slice(cfqd, 1, 0) -
+       return (cfqq->cfqg->nr_cfqq - 1) * (cfq_prio_slice(cfqd, 1, 0) -
                       cfq_prio_slice(cfqd, cfq_cfqq_sync(cfqq), cfqq->ioprio));
 }
 
+static inline s64
+cfqg_key(struct cfq_rb_root *st, struct cfq_group *cfqg)
+{
+       return cfqg->vdisktime - st->min_vdisktime;
+}
+
+static void
+__cfq_group_service_tree_add(struct cfq_rb_root *st, struct cfq_group *cfqg)
+{
+       struct rb_node **node = &st->rb.rb_node;
+       struct rb_node *parent = NULL;
+       struct cfq_group *__cfqg;
+       s64 key = cfqg_key(st, cfqg);
+       int left = 1;
+
+       while (*node != NULL) {
+               parent = *node;
+               __cfqg = rb_entry_cfqg(parent);
+
+               if (key < cfqg_key(st, __cfqg))
+                       node = &parent->rb_left;
+               else {
+                       node = &parent->rb_right;
+                       left = 0;
+               }
+       }
+
+       if (left)
+               st->left = &cfqg->rb_node;
+
+       rb_link_node(&cfqg->rb_node, parent, node);
+       rb_insert_color(&cfqg->rb_node, &st->rb);
+}
+
+static void
+cfq_group_service_tree_add(struct cfq_data *cfqd, struct cfq_group *cfqg)
+{
+       struct cfq_rb_root *st = &cfqd->grp_service_tree;
+       struct cfq_group *__cfqg;
+       struct rb_node *n;
+
+       cfqg->nr_cfqq++;
+       if (cfqg->on_st)
+               return;
+
+       /*
+        * Currently put the group at the end. Later implement something
+        * so that groups get lesser vtime based on their weights, so that
+        * if group does not loose all if it was not continously backlogged.
+        */
+       n = rb_last(&st->rb);
+       if (n) {
+               __cfqg = rb_entry_cfqg(n);
+               cfqg->vdisktime = __cfqg->vdisktime + CFQ_IDLE_DELAY;
+       } else
+               cfqg->vdisktime = st->min_vdisktime;
+
+       __cfq_group_service_tree_add(st, cfqg);
+       cfqg->on_st = true;
+       cfqd->nr_groups++;
+       st->total_weight += cfqg->weight;
+}
+
+static void
+cfq_group_service_tree_del(struct cfq_data *cfqd, struct cfq_group *cfqg)
+{
+       struct cfq_rb_root *st = &cfqd->grp_service_tree;
+
+       if (st->active == &cfqg->rb_node)
+               st->active = NULL;
+
+       BUG_ON(cfqg->nr_cfqq < 1);
+       cfqg->nr_cfqq--;
+
+       /* If there are other cfq queues under this group, don't delete it */
+       if (cfqg->nr_cfqq)
+               return;
+
+       cfq_log_cfqg(cfqd, cfqg, "del_from_rr group");
+       cfqg->on_st = false;
+       cfqd->nr_groups--;
+       st->total_weight -= cfqg->weight;
+       if (!RB_EMPTY_NODE(&cfqg->rb_node))
+               cfq_rb_erase(&cfqg->rb_node, st);
+       cfqg->saved_workload_slice = 0;
+       blkiocg_update_blkio_group_dequeue_stats(&cfqg->blkg, 1);
+}
+
+static inline unsigned int cfq_cfqq_slice_usage(struct cfq_queue *cfqq)
+{
+       unsigned int slice_used;
+
+       /*
+        * Queue got expired before even a single request completed or
+        * got expired immediately after first request completion.
+        */
+       if (!cfqq->slice_start || cfqq->slice_start == jiffies) {
+               /*
+                * Also charge the seek time incurred to the group, otherwise
+                * if there are mutiple queues in the group, each can dispatch
+                * a single request on seeky media and cause lots of seek time
+                * and group will never know it.
+                */
+               slice_used = max_t(unsigned, (jiffies - cfqq->dispatch_start),
+                                       1);
+       } else {
+               slice_used = jiffies - cfqq->slice_start;
+               if (slice_used > cfqq->allocated_slice)
+                       slice_used = cfqq->allocated_slice;
+       }
+
+       cfq_log_cfqq(cfqq->cfqd, cfqq, "sl_used=%u sect=%lu", slice_used,
+                               cfqq->nr_sectors);
+       return slice_used;
+}
+
+static void cfq_group_served(struct cfq_data *cfqd, struct cfq_group *cfqg,
+                               struct cfq_queue *cfqq)
+{
+       struct cfq_rb_root *st = &cfqd->grp_service_tree;
+       unsigned int used_sl, charge_sl;
+       int nr_sync = cfqg->nr_cfqq - cfqg_busy_async_queues(cfqd, cfqg)
+                       - cfqg->service_tree_idle.count;
+
+       BUG_ON(nr_sync < 0);
+       used_sl = charge_sl = cfq_cfqq_slice_usage(cfqq);
+
+       if (!cfq_cfqq_sync(cfqq) && !nr_sync)
+               charge_sl = cfqq->allocated_slice;
+
+       /* Can't update vdisktime while group is on service tree */
+       cfq_rb_erase(&cfqg->rb_node, st);
+       cfqg->vdisktime += cfq_scale_slice(charge_sl, cfqg);
+       __cfq_group_service_tree_add(st, cfqg);
+
+       /* This group is being expired. Save the context */
+       if (time_after(cfqd->workload_expires, jiffies)) {
+               cfqg->saved_workload_slice = cfqd->workload_expires
+                                               - jiffies;
+               cfqg->saved_workload = cfqd->serving_type;
+               cfqg->saved_serving_prio = cfqd->serving_prio;
+       } else
+               cfqg->saved_workload_slice = 0;
+
+       cfq_log_cfqg(cfqd, cfqg, "served: vt=%llu min_vt=%llu", cfqg->vdisktime,
+                                       st->min_vdisktime);
+       blkiocg_update_blkio_group_stats(&cfqg->blkg, used_sl,
+                                               cfqq->nr_sectors);
+}
+
+#ifdef CONFIG_CFQ_GROUP_IOSCHED
+static inline struct cfq_group *cfqg_of_blkg(struct blkio_group *blkg)
+{
+       if (blkg)
+               return container_of(blkg, struct cfq_group, blkg);
+       return NULL;
+}
+
+void
+cfq_update_blkio_group_weight(struct blkio_group *blkg, unsigned int weight)
+{
+       cfqg_of_blkg(blkg)->weight = weight;
+}
+
+static struct cfq_group *
+cfq_find_alloc_cfqg(struct cfq_data *cfqd, struct cgroup *cgroup, int create)
+{
+       struct blkio_cgroup *blkcg = cgroup_to_blkio_cgroup(cgroup);
+       struct cfq_group *cfqg = NULL;
+       void *key = cfqd;
+       int i, j;
+       struct cfq_rb_root *st;
+       struct backing_dev_info *bdi = &cfqd->queue->backing_dev_info;
+       unsigned int major, minor;
+
+       /* Do we need to take this reference */
+       if (!blkiocg_css_tryget(blkcg))
+               return NULL;;
+
+       cfqg = cfqg_of_blkg(blkiocg_lookup_group(blkcg, key));
+       if (cfqg || !create)
+               goto done;
+
+       cfqg = kzalloc_node(sizeof(*cfqg), GFP_ATOMIC, cfqd->queue->node);
+       if (!cfqg)
+               goto done;
+
+       cfqg->weight = blkcg->weight;
+       for_each_cfqg_st(cfqg, i, j, st)
+               *st = CFQ_RB_ROOT;
+       RB_CLEAR_NODE(&cfqg->rb_node);
+
+       /*
+        * Take the initial reference that will be released on destroy
+        * This can be thought of a joint reference by cgroup and
+        * elevator which will be dropped by either elevator exit
+        * or cgroup deletion path depending on who is exiting first.
+        */
+       atomic_set(&cfqg->ref, 1);
+
+       /* Add group onto cgroup list */
+       sscanf(dev_name(bdi->dev), "%u:%u", &major, &minor);
+       blkiocg_add_blkio_group(blkcg, &cfqg->blkg, (void *)cfqd,
+                                       MKDEV(major, minor));
+
+       /* Add group on cfqd list */
+       hlist_add_head(&cfqg->cfqd_node, &cfqd->cfqg_list);
+
+done:
+       blkiocg_css_put(blkcg);
+       return cfqg;
+}
+
 /*
- * The cfqd->service_tree holds all pending cfq_queue's that have
+ * Search for the cfq group current task belongs to. If create = 1, then also
+ * create the cfq group if it does not exist. request_queue lock must be held.
+ */
+static struct cfq_group *cfq_get_cfqg(struct cfq_data *cfqd, int create)
+{
+       struct cgroup *cgroup;
+       struct cfq_group *cfqg = NULL;
+
+       rcu_read_lock();
+       cgroup = task_cgroup(current, blkio_subsys_id);
+       cfqg = cfq_find_alloc_cfqg(cfqd, cgroup, create);
+       if (!cfqg && create)
+               cfqg = &cfqd->root_group;
+       rcu_read_unlock();
+       return cfqg;
+}
+
+static void cfq_link_cfqq_cfqg(struct cfq_queue *cfqq, struct cfq_group *cfqg)
+{
+       /* Currently, all async queues are mapped to root group */
+       if (!cfq_cfqq_sync(cfqq))
+               cfqg = &cfqq->cfqd->root_group;
+
+       cfqq->cfqg = cfqg;
+       /* cfqq reference on cfqg */
+       atomic_inc(&cfqq->cfqg->ref);
+}
+
+static void cfq_put_cfqg(struct cfq_group *cfqg)
+{
+       struct cfq_rb_root *st;
+       int i, j;
+
+       BUG_ON(atomic_read(&cfqg->ref) <= 0);
+       if (!atomic_dec_and_test(&cfqg->ref))
+               return;
+       for_each_cfqg_st(cfqg, i, j, st)
+               BUG_ON(!RB_EMPTY_ROOT(&st->rb) || st->active != NULL);
+       kfree(cfqg);
+}
+
+static void cfq_destroy_cfqg(struct cfq_data *cfqd, struct cfq_group *cfqg)
+{
+       /* Something wrong if we are trying to remove same group twice */
+       BUG_ON(hlist_unhashed(&cfqg->cfqd_node));
+
+       hlist_del_init(&cfqg->cfqd_node);
+
+       /*
+        * Put the reference taken at the time of creation so that when all
+        * queues are gone, group can be destroyed.
+        */
+       cfq_put_cfqg(cfqg);
+}
+
+static void cfq_release_cfq_groups(struct cfq_data *cfqd)
+{
+       struct hlist_node *pos, *n;
+       struct cfq_group *cfqg;
+
+       hlist_for_each_entry_safe(cfqg, pos, n, &cfqd->cfqg_list, cfqd_node) {
+               /*
+                * If cgroup removal path got to blk_group first and removed
+                * it from cgroup list, then it will take care of destroying
+                * cfqg also.
+                */
+               if (!blkiocg_del_blkio_group(&cfqg->blkg))
+                       cfq_destroy_cfqg(cfqd, cfqg);
+       }
+}
+
+/*
+ * Blk cgroup controller notification saying that blkio_group object is being
+ * delinked as associated cgroup object is going away. That also means that
+ * no new IO will come in this group. So get rid of this group as soon as
+ * any pending IO in the group is finished.
+ *
+ * This function is called under rcu_read_lock(). key is the rcu protected
+ * pointer. That means "key" is a valid cfq_data pointer as long as we are rcu
+ * read lock.
+ *
+ * "key" was fetched from blkio_group under blkio_cgroup->lock. That means
+ * it should not be NULL as even if elevator was exiting, cgroup deltion
+ * path got to it first.
+ */
+void cfq_unlink_blkio_group(void *key, struct blkio_group *blkg)
+{
+       unsigned long  flags;
+       struct cfq_data *cfqd = key;
+
+       spin_lock_irqsave(cfqd->queue->queue_lock, flags);
+       cfq_destroy_cfqg(cfqd, cfqg_of_blkg(blkg));
+       spin_unlock_irqrestore(cfqd->queue->queue_lock, flags);
+}
+
+#else /* GROUP_IOSCHED */
+static struct cfq_group *cfq_get_cfqg(struct cfq_data *cfqd, int create)
+{
+       return &cfqd->root_group;
+}
+static inline void
+cfq_link_cfqq_cfqg(struct cfq_queue *cfqq, struct cfq_group *cfqg) {
+       cfqq->cfqg = cfqg;
+}
+
+static void cfq_release_cfq_groups(struct cfq_data *cfqd) {}
+static inline void cfq_put_cfqg(struct cfq_group *cfqg) {}
+
+#endif /* GROUP_IOSCHED */
+
+/*
+ * The cfqd->service_trees holds all pending cfq_queue's that have
  * requests waiting to be processed. It is sorted in the order that
  * we will service the queues.
  */
@@ -495,11 +1120,42 @@ static void cfq_service_tree_add(struct cfq_data *cfqd, struct cfq_queue *cfqq,
        struct rb_node **p, *parent;
        struct cfq_queue *__cfqq;
        unsigned long rb_key;
+       struct cfq_rb_root *service_tree;
        int left;
+       int new_cfqq = 1;
+       int group_changed = 0;
+
+#ifdef CONFIG_CFQ_GROUP_IOSCHED
+       if (!cfqd->cfq_group_isolation
+           && cfqq_type(cfqq) == SYNC_NOIDLE_WORKLOAD
+           && cfqq->cfqg && cfqq->cfqg != &cfqd->root_group) {
+               /* Move this cfq to root group */
+               cfq_log_cfqq(cfqd, cfqq, "moving to root group");
+               if (!RB_EMPTY_NODE(&cfqq->rb_node))
+                       cfq_group_service_tree_del(cfqd, cfqq->cfqg);
+               cfqq->orig_cfqg = cfqq->cfqg;
+               cfqq->cfqg = &cfqd->root_group;
+               atomic_inc(&cfqd->root_group.ref);
+               group_changed = 1;
+       } else if (!cfqd->cfq_group_isolation
+                  && cfqq_type(cfqq) == SYNC_WORKLOAD && cfqq->orig_cfqg) {
+               /* cfqq is sequential now needs to go to its original group */
+               BUG_ON(cfqq->cfqg != &cfqd->root_group);
+               if (!RB_EMPTY_NODE(&cfqq->rb_node))
+                       cfq_group_service_tree_del(cfqd, cfqq->cfqg);
+               cfq_put_cfqg(cfqq->cfqg);
+               cfqq->cfqg = cfqq->orig_cfqg;
+               cfqq->orig_cfqg = NULL;
+               group_changed = 1;
+               cfq_log_cfqq(cfqd, cfqq, "moved to origin group");
+       }
+#endif
 
+       service_tree = service_tree_for(cfqq->cfqg, cfqq_prio(cfqq),
+                                               cfqq_type(cfqq), cfqd);
        if (cfq_class_idle(cfqq)) {
                rb_key = CFQ_IDLE_DELAY;
-               parent = rb_last(&cfqd->service_tree.rb);
+               parent = rb_last(&service_tree->rb);
                if (parent && parent != &cfqq->rb_node) {
                        __cfqq = rb_entry(parent, struct cfq_queue, rb_node);
                        rb_key += __cfqq->rb_key;
@@ -517,23 +1173,27 @@ static void cfq_service_tree_add(struct cfq_data *cfqd, struct cfq_queue *cfqq,
                cfqq->slice_resid = 0;
        } else {
                rb_key = -HZ;
-               __cfqq = cfq_rb_first(&cfqd->service_tree);
+               __cfqq = cfq_rb_first(service_tree);
                rb_key += __cfqq ? __cfqq->rb_key : jiffies;
        }
 
        if (!RB_EMPTY_NODE(&cfqq->rb_node)) {
+               new_cfqq = 0;
                /*
                 * same position, nothing more to do
                 */
-               if (rb_key == cfqq->rb_key)
+               if (rb_key == cfqq->rb_key &&
+                   cfqq->service_tree == service_tree)
                        return;
 
-               cfq_rb_erase(&cfqq->rb_node, &cfqd->service_tree);
+               cfq_rb_erase(&cfqq->rb_node, cfqq->service_tree);
+               cfqq->service_tree = NULL;
        }
 
        left = 1;
        parent = NULL;
-       p = &cfqd->service_tree.rb.rb_node;
+       cfqq->service_tree = service_tree;
+       p = &service_tree->rb.rb_node;
        while (*p) {
                struct rb_node **n;
 
@@ -541,35 +1201,28 @@ static void cfq_service_tree_add(struct cfq_data *cfqd, struct cfq_queue *cfqq,
                __cfqq = rb_entry(parent, struct cfq_queue, rb_node);
 
                /*
-                * sort RT queues first, we always want to give
-                * preference to them. IDLE queues goes to the back.
-                * after that, sort on the next service time.
+                * sort by key, that represents service time.
                 */
-               if (cfq_class_rt(cfqq) > cfq_class_rt(__cfqq))
-                       n = &(*p)->rb_left;
-               else if (cfq_class_rt(cfqq) < cfq_class_rt(__cfqq))
-                       n = &(*p)->rb_right;
-               else if (cfq_class_idle(cfqq) < cfq_class_idle(__cfqq))
-                       n = &(*p)->rb_left;
-               else if (cfq_class_idle(cfqq) > cfq_class_idle(__cfqq))
-                       n = &(*p)->rb_right;
-               else if (time_before(rb_key, __cfqq->rb_key))
+               if (time_before(rb_key, __cfqq->rb_key))
                        n = &(*p)->rb_left;
-               else
+               else {
                        n = &(*p)->rb_right;
-
-               if (n == &(*p)->rb_right)
                        left = 0;
+               }
 
                p = n;
        }
 
        if (left)
-               cfqd->service_tree.left = &cfqq->rb_node;
+               service_tree->left = &cfqq->rb_node;
 
        cfqq->rb_key = rb_key;
        rb_link_node(&cfqq->rb_node, parent, p);
-       rb_insert_color(&cfqq->rb_node, &cfqd->service_tree.rb);
+       rb_insert_color(&cfqq->rb_node, &service_tree->rb);
+       service_tree->count++;
+       if ((add_front || !new_cfqq) && !group_changed)
+               return;
+       cfq_group_service_tree_add(cfqd, cfqq->cfqg);
 }
 
 static struct cfq_queue *
@@ -671,13 +1324,16 @@ static void cfq_del_cfqq_rr(struct cfq_data *cfqd, struct cfq_queue *cfqq)
        BUG_ON(!cfq_cfqq_on_rr(cfqq));
        cfq_clear_cfqq_on_rr(cfqq);
 
-       if (!RB_EMPTY_NODE(&cfqq->rb_node))
-               cfq_rb_erase(&cfqq->rb_node, &cfqd->service_tree);
+       if (!RB_EMPTY_NODE(&cfqq->rb_node)) {
+               cfq_rb_erase(&cfqq->rb_node, cfqq->service_tree);
+               cfqq->service_tree = NULL;
+       }
        if (cfqq->p_root) {
                rb_erase(&cfqq->p_node, cfqq->p_root);
                cfqq->p_root = NULL;
        }
 
+       cfq_group_service_tree_del(cfqd, cfqq->cfqg);
        BUG_ON(!cfqd->busy_queues);
        cfqd->busy_queues--;
 }
@@ -688,7 +1344,6 @@ static void cfq_del_cfqq_rr(struct cfq_data *cfqd, struct cfq_queue *cfqq)
 static void cfq_del_rq_rb(struct request *rq)
 {
        struct cfq_queue *cfqq = RQ_CFQQ(rq);
-       struct cfq_data *cfqd = cfqq->cfqd;
        const int sync = rq_is_sync(rq);
 
        BUG_ON(!cfqq->queued[sync]);
@@ -696,8 +1351,17 @@ static void cfq_del_rq_rb(struct request *rq)
 
        elv_rb_del(&cfqq->sort_list, rq);
 
-       if (cfq_cfqq_on_rr(cfqq) && RB_EMPTY_ROOT(&cfqq->sort_list))
-               cfq_del_cfqq_rr(cfqd, cfqq);
+       if (cfq_cfqq_on_rr(cfqq) && RB_EMPTY_ROOT(&cfqq->sort_list)) {
+               /*
+                * Queue will be deleted from service tree when we actually
+                * expire it later. Right now just remove it from prio tree
+                * as it is empty.
+                */
+               if (cfqq->p_root) {
+                       rb_erase(&cfqq->p_node, cfqq->p_root);
+                       cfqq->p_root = NULL;
+               }
+       }
 }
 
 static void cfq_add_rq_rb(struct request *rq)
@@ -722,7 +1386,7 @@ static void cfq_add_rq_rb(struct request *rq)
         * check if this request is a better next-serve candidate
         */
        prev = cfqq->next_rq;
-       cfqq->next_rq = cfq_choose_req(cfqd, cfqq->next_rq, rq);
+       cfqq->next_rq = cfq_choose_req(cfqd, cfqq->next_rq, rq, cfqd->last_position);
 
        /*
         * adjust priority tree position, if ->next_rq changes
@@ -829,6 +1493,7 @@ static void
 cfq_merged_requests(struct request_queue *q, struct request *rq,
                    struct request *next)
 {
+       struct cfq_queue *cfqq = RQ_CFQQ(rq);
        /*
         * reposition in fifo if next is older than rq
         */
@@ -838,6 +1503,8 @@ cfq_merged_requests(struct request_queue *q, struct request *rq,
                rq_set_fifo_time(rq, rq_fifo_time(next));
        }
 
+       if (cfqq->next_rq == next)
+               cfqq->next_rq = rq;
        cfq_remove_request(next);
 }
 
@@ -848,6 +1515,9 @@ static int cfq_allow_merge(struct request_queue *q, struct request *rq,
        struct cfq_io_context *cic;
        struct cfq_queue *cfqq;
 
+       /* Deny merge if bio and rq don't belong to same cfq group */
+       if ((RQ_CFQQ(rq))->cfqg != cfq_get_cfqg(cfqd, 0))
+               return false;
        /*
         * Disallow merge of a sync bio into an async request.
         */
@@ -871,8 +1541,12 @@ static void __cfq_set_active_queue(struct cfq_data *cfqd,
 {
        if (cfqq) {
                cfq_log_cfqq(cfqd, cfqq, "set_active");
+               cfqq->slice_start = 0;
+               cfqq->dispatch_start = jiffies;
+               cfqq->allocated_slice = 0;
                cfqq->slice_end = 0;
                cfqq->slice_dispatch = 0;
+               cfqq->nr_sectors = 0;
 
                cfq_clear_cfqq_wait_request(cfqq);
                cfq_clear_cfqq_must_dispatch(cfqq);
@@ -899,6 +1573,8 @@ __cfq_slice_expired(struct cfq_data *cfqd, struct cfq_queue *cfqq,
                del_timer(&cfqd->idle_slice_timer);
 
        cfq_clear_cfqq_wait_request(cfqq);
+       cfq_clear_cfqq_wait_busy(cfqq);
+       cfq_clear_cfqq_wait_busy_done(cfqq);
 
        /*
         * store what was left of this slice, if the queue idled/timed out
@@ -908,11 +1584,19 @@ __cfq_slice_expired(struct cfq_data *cfqd, struct cfq_queue *cfqq,
                cfq_log_cfqq(cfqd, cfqq, "resid=%ld", cfqq->slice_resid);
        }
 
+       cfq_group_served(cfqd, cfqq->cfqg, cfqq);
+
+       if (cfq_cfqq_on_rr(cfqq) && RB_EMPTY_ROOT(&cfqq->sort_list))
+               cfq_del_cfqq_rr(cfqd, cfqq);
+
        cfq_resort_rr_list(cfqd, cfqq);
 
        if (cfqq == cfqd->active_queue)
                cfqd->active_queue = NULL;
 
+       if (&cfqq->cfqg->rb_node == cfqd->grp_service_tree.active)
+               cfqd->grp_service_tree.active = NULL;
+
        if (cfqd->active_cic) {
                put_io_context(cfqd->active_cic->ioc);
                cfqd->active_cic = NULL;
@@ -933,10 +1617,39 @@ static inline void cfq_slice_expired(struct cfq_data *cfqd, bool timed_out)
  */
 static struct cfq_queue *cfq_get_next_queue(struct cfq_data *cfqd)
 {
-       if (RB_EMPTY_ROOT(&cfqd->service_tree.rb))
+       struct cfq_rb_root *service_tree =
+               service_tree_for(cfqd->serving_group, cfqd->serving_prio,
+                                       cfqd->serving_type, cfqd);
+
+       if (!cfqd->rq_queued)
                return NULL;
 
-       return cfq_rb_first(&cfqd->service_tree);
+       /* There is nothing to dispatch */
+       if (!service_tree)
+               return NULL;
+       if (RB_EMPTY_ROOT(&service_tree->rb))
+               return NULL;
+       return cfq_rb_first(service_tree);
+}
+
+static struct cfq_queue *cfq_get_next_queue_forced(struct cfq_data *cfqd)
+{
+       struct cfq_group *cfqg;
+       struct cfq_queue *cfqq;
+       int i, j;
+       struct cfq_rb_root *st;
+
+       if (!cfqd->rq_queued)
+               return NULL;
+
+       cfqg = cfq_get_next_cfqg(cfqd);
+       if (!cfqg)
+               return NULL;
+
+       for_each_cfqg_st(cfqg, i, j, st)
+               if ((cfqq = cfq_rb_first(st)) != NULL)
+                       return cfqq;
+       return NULL;
 }
 
 /*
@@ -945,14 +1658,8 @@ static struct cfq_queue *cfq_get_next_queue(struct cfq_data *cfqd)
 static struct cfq_queue *cfq_set_active_queue(struct cfq_data *cfqd,
                                              struct cfq_queue *cfqq)
 {
-       if (!cfqq) {
+       if (!cfqq)
                cfqq = cfq_get_next_queue(cfqd);
-               if (cfqq && !cfq_cfqq_coop_preempt(cfqq))
-                       cfq_clear_cfqq_coop(cfqq);
-       }
-
-       if (cfqq)
-               cfq_clear_cfqq_coop_preempt(cfqq);
 
        __cfq_set_active_queue(cfqd, cfqq);
        return cfqq;
@@ -967,16 +1674,16 @@ static inline sector_t cfq_dist_from_last(struct cfq_data *cfqd,
                return cfqd->last_position - blk_rq_pos(rq);
 }
 
-#define CIC_SEEK_THR   8 * 1024
-#define CIC_SEEKY(cic) ((cic)->seek_mean > CIC_SEEK_THR)
+#define CFQQ_SEEK_THR          8 * 1024
+#define CFQQ_SEEKY(cfqq)       ((cfqq)->seek_mean > CFQQ_SEEK_THR)
 
-static inline int cfq_rq_close(struct cfq_data *cfqd, struct request *rq)
+static inline int cfq_rq_close(struct cfq_data *cfqd, struct cfq_queue *cfqq,
+                              struct request *rq)
 {
-       struct cfq_io_context *cic = cfqd->active_cic;
-       sector_t sdist = cic->seek_mean;
+       sector_t sdist = cfqq->seek_mean;
 
-       if (!sample_valid(cic->seek_samples))
-               sdist = CIC_SEEK_THR;
+       if (!sample_valid(cfqq->seek_samples))
+               sdist = CFQQ_SEEK_THR;
 
        return cfq_dist_from_last(cfqd, rq) <= sdist;
 }
@@ -1005,7 +1712,7 @@ static struct cfq_queue *cfqq_close(struct cfq_data *cfqd,
         * will contain the closest sector.
         */
        __cfqq = rb_entry(parent, struct cfq_queue, p_node);
-       if (cfq_rq_close(cfqd, __cfqq->next_rq))
+       if (cfq_rq_close(cfqd, cur_cfqq, __cfqq->next_rq))
                return __cfqq;
 
        if (blk_rq_pos(__cfqq->next_rq) < sector)
@@ -1016,7 +1723,7 @@ static struct cfq_queue *cfqq_close(struct cfq_data *cfqd,
                return NULL;
 
        __cfqq = rb_entry(node, struct cfq_queue, p_node);
-       if (cfq_rq_close(cfqd, __cfqq->next_rq))
+       if (cfq_rq_close(cfqd, cur_cfqq, __cfqq->next_rq))
                return __cfqq;
 
        return NULL;
@@ -1033,16 +1740,13 @@ static struct cfq_queue *cfqq_close(struct cfq_data *cfqd,
  * assumption.
  */
 static struct cfq_queue *cfq_close_cooperator(struct cfq_data *cfqd,
-                                             struct cfq_queue *cur_cfqq,
-                                             bool probe)
+                                             struct cfq_queue *cur_cfqq)
 {
        struct cfq_queue *cfqq;
 
-       /*
-        * A valid cfq_io_context is necessary to compare requests against
-        * the seek_mean of the current cfqq.
-        */
-       if (!cfqd->active_cic)
+       if (!cfq_cfqq_sync(cur_cfqq))
+               return NULL;
+       if (CFQQ_SEEKY(cur_cfqq))
                return NULL;
 
        /*
@@ -1054,14 +1758,55 @@ static struct cfq_queue *cfq_close_cooperator(struct cfq_data *cfqd,
        if (!cfqq)
                return NULL;
 
-       if (cfq_cfqq_coop(cfqq))
+       /* If new queue belongs to different cfq_group, don't choose it */
+       if (cur_cfqq->cfqg != cfqq->cfqg)
+               return NULL;
+
+       /*
+        * It only makes sense to merge sync queues.
+        */
+       if (!cfq_cfqq_sync(cfqq))
+               return NULL;
+       if (CFQQ_SEEKY(cfqq))
+               return NULL;
+
+       /*
+        * Do not merge queues of different priority classes
+        */
+       if (cfq_class_rt(cfqq) != cfq_class_rt(cur_cfqq))
                return NULL;
 
-       if (!probe)
-               cfq_mark_cfqq_coop(cfqq);
        return cfqq;
 }
 
+/*
+ * Determine whether we should enforce idle window for this queue.
+ */
+
+static bool cfq_should_idle(struct cfq_data *cfqd, struct cfq_queue *cfqq)
+{
+       enum wl_prio_t prio = cfqq_prio(cfqq);
+       struct cfq_rb_root *service_tree = cfqq->service_tree;
+
+       BUG_ON(!service_tree);
+       BUG_ON(!service_tree->count);
+
+       /* We never do for idle class queues. */
+       if (prio == IDLE_WORKLOAD)
+               return false;
+
+       /* We do for queues that were marked with idle window flag. */
+       if (cfq_cfqq_idle_window(cfqq) &&
+          !(blk_queue_nonrot(cfqd->queue) && cfqd->hw_tag))
+               return true;
+
+       /*
+        * Otherwise, we do only if they are the last ones
+        * in their service tree.
+        */
+       return service_tree->count == 1;
+}
+
 static void cfq_arm_slice_timer(struct cfq_data *cfqd)
 {
        struct cfq_queue *cfqq = cfqd->active_queue;
@@ -1082,13 +1827,13 @@ static void cfq_arm_slice_timer(struct cfq_data *cfqd)
        /*
         * idle is disabled, either manually or by past process history
         */
-       if (!cfqd->cfq_slice_idle || !cfq_cfqq_idle_window(cfqq))
+       if (!cfqd->cfq_slice_idle || !cfq_should_idle(cfqd, cfqq))
                return;
 
        /*
-        * still requests with the driver, don't idle
+        * still active requests from this queue, don't idle
         */
-       if (rq_in_driver(cfqd))
+       if (cfqq->dispatched)
                return;
 
        /*
@@ -1109,14 +1854,7 @@ static void cfq_arm_slice_timer(struct cfq_data *cfqd)
 
        cfq_mark_cfqq_wait_request(cfqq);
 
-       /*
-        * we don't want to idle for seeks, but we do want to allow
-        * fair distribution of slice time for a process doing back-to-back
-        * seeks. so allow a little bit of time for him to submit a new rq
-        */
        sl = cfqd->cfq_slice_idle;
-       if (sample_valid(cic->seek_samples) && CIC_SEEKY(cic))
-               sl = min(sl, msecs_to_jiffies(CFQ_MIN_TT));
 
        mod_timer(&cfqd->idle_slice_timer, jiffies + sl);
        cfq_log_cfqq(cfqd, cfqq, "arm_idle: %lu", sl);
@@ -1139,6 +1877,7 @@ static void cfq_dispatch_insert(struct request_queue *q, struct request *rq)
 
        if (cfq_cfqq_sync(cfqq))
                cfqd->sync_flight++;
+       cfqq->nr_sectors += blk_rq_sectors(rq);
 }
 
 /*
@@ -1175,6 +1914,207 @@ cfq_prio_to_maxrq(struct cfq_data *cfqd, struct cfq_queue *cfqq)
 }
 
 /*
+ * Must be called with the queue_lock held.
+ */
+static int cfqq_process_refs(struct cfq_queue *cfqq)
+{
+       int process_refs, io_refs;
+
+       io_refs = cfqq->allocated[READ] + cfqq->allocated[WRITE];
+       process_refs = atomic_read(&cfqq->ref) - io_refs;
+       BUG_ON(process_refs < 0);
+       return process_refs;
+}
+
+static void cfq_setup_merge(struct cfq_queue *cfqq, struct cfq_queue *new_cfqq)
+{
+       int process_refs, new_process_refs;
+       struct cfq_queue *__cfqq;
+
+       /* Avoid a circular list and skip interim queue merges */
+       while ((__cfqq = new_cfqq->new_cfqq)) {
+               if (__cfqq == cfqq)
+                       return;
+               new_cfqq = __cfqq;
+       }
+
+       process_refs = cfqq_process_refs(cfqq);
+       /*
+        * If the process for the cfqq has gone away, there is no
+        * sense in merging the queues.
+        */
+       if (process_refs == 0)
+               return;
+
+       /*
+        * Merge in the direction of the lesser amount of work.
+        */
+       new_process_refs = cfqq_process_refs(new_cfqq);
+       if (new_process_refs >= process_refs) {
+               cfqq->new_cfqq = new_cfqq;
+               atomic_add(process_refs, &new_cfqq->ref);
+       } else {
+               new_cfqq->new_cfqq = cfqq;
+               atomic_add(new_process_refs, &cfqq->ref);
+       }
+}
+
+static enum wl_type_t cfq_choose_wl(struct cfq_data *cfqd,
+                               struct cfq_group *cfqg, enum wl_prio_t prio,
+                               bool prio_changed)
+{
+       struct cfq_queue *queue;
+       int i;
+       bool key_valid = false;
+       unsigned long lowest_key = 0;
+       enum wl_type_t cur_best = SYNC_NOIDLE_WORKLOAD;
+
+       if (prio_changed) {
+               /*
+                * When priorities switched, we prefer starting
+                * from SYNC_NOIDLE (first choice), or just SYNC
+                * over ASYNC
+                */
+               if (service_tree_for(cfqg, prio, cur_best, cfqd)->count)
+                       return cur_best;
+               cur_best = SYNC_WORKLOAD;
+               if (service_tree_for(cfqg, prio, cur_best, cfqd)->count)
+                       return cur_best;
+
+               return ASYNC_WORKLOAD;
+       }
+
+       for (i = 0; i < 3; ++i) {
+               /* otherwise, select the one with lowest rb_key */
+               queue = cfq_rb_first(service_tree_for(cfqg, prio, i, cfqd));
+               if (queue &&
+                   (!key_valid || time_before(queue->rb_key, lowest_key))) {
+                       lowest_key = queue->rb_key;
+                       cur_best = i;
+                       key_valid = true;
+               }
+       }
+
+       return cur_best;
+}
+
+static void choose_service_tree(struct cfq_data *cfqd, struct cfq_group *cfqg)
+{
+       enum wl_prio_t previous_prio = cfqd->serving_prio;
+       bool prio_changed;
+       unsigned slice;
+       unsigned count;
+       struct cfq_rb_root *st;
+       unsigned group_slice;
+
+       if (!cfqg) {
+               cfqd->serving_prio = IDLE_WORKLOAD;
+               cfqd->workload_expires = jiffies + 1;
+               return;
+       }
+
+       /* Choose next priority. RT > BE > IDLE */
+       if (cfq_group_busy_queues_wl(RT_WORKLOAD, cfqd, cfqg))
+               cfqd->serving_prio = RT_WORKLOAD;
+       else if (cfq_group_busy_queues_wl(BE_WORKLOAD, cfqd, cfqg))
+               cfqd->serving_prio = BE_WORKLOAD;
+       else {
+               cfqd->serving_prio = IDLE_WORKLOAD;
+               cfqd->workload_expires = jiffies + 1;
+               return;
+       }
+
+       /*
+        * For RT and BE, we have to choose also the type
+        * (SYNC, SYNC_NOIDLE, ASYNC), and to compute a workload
+        * expiration time
+        */
+       prio_changed = (cfqd->serving_prio != previous_prio);
+       st = service_tree_for(cfqg, cfqd->serving_prio, cfqd->serving_type,
+                               cfqd);
+       count = st->count;
+
+       /*
+        * If priority didn't change, check workload expiration,
+        * and that we still have other queues ready
+        */
+       if (!prio_changed && count &&
+           !time_after(jiffies, cfqd->workload_expires))
+               return;
+
+       /* otherwise select new workload type */
+       cfqd->serving_type =
+               cfq_choose_wl(cfqd, cfqg, cfqd->serving_prio, prio_changed);
+       st = service_tree_for(cfqg, cfqd->serving_prio, cfqd->serving_type,
+                               cfqd);
+       count = st->count;
+
+       /*
+        * the workload slice is computed as a fraction of target latency
+        * proportional to the number of queues in that workload, over
+        * all the queues in the same priority class
+        */
+       group_slice = cfq_group_slice(cfqd, cfqg);
+
+       slice = group_slice * count /
+               max_t(unsigned, cfqg->busy_queues_avg[cfqd->serving_prio],
+                     cfq_group_busy_queues_wl(cfqd->serving_prio, cfqd, cfqg));
+
+       if (cfqd->serving_type == ASYNC_WORKLOAD) {
+               unsigned int tmp;
+
+               /*
+                * Async queues are currently system wide. Just taking
+                * proportion of queues with-in same group will lead to higher
+                * async ratio system wide as generally root group is going
+                * to have higher weight. A more accurate thing would be to
+                * calculate system wide asnc/sync ratio.
+                */
+               tmp = cfq_target_latency * cfqg_busy_async_queues(cfqd, cfqg);
+               tmp = tmp/cfqd->busy_queues;
+               slice = min_t(unsigned, slice, tmp);
+
+               /* async workload slice is scaled down according to
+                * the sync/async slice ratio. */
+               slice = slice * cfqd->cfq_slice[0] / cfqd->cfq_slice[1];
+       } else
+               /* sync workload slice is at least 2 * cfq_slice_idle */
+               slice = max(slice, 2 * cfqd->cfq_slice_idle);
+
+       slice = max_t(unsigned, slice, CFQ_MIN_TT);
+       cfqd->workload_expires = jiffies + slice;
+       cfqd->noidle_tree_requires_idle = false;
+}
+
+static struct cfq_group *cfq_get_next_cfqg(struct cfq_data *cfqd)
+{
+       struct cfq_rb_root *st = &cfqd->grp_service_tree;
+       struct cfq_group *cfqg;
+
+       if (RB_EMPTY_ROOT(&st->rb))
+               return NULL;
+       cfqg = cfq_rb_first_group(st);
+       st->active = &cfqg->rb_node;
+       update_min_vdisktime(st);
+       return cfqg;
+}
+
+static void cfq_choose_cfqg(struct cfq_data *cfqd)
+{
+       struct cfq_group *cfqg = cfq_get_next_cfqg(cfqd);
+
+       cfqd->serving_group = cfqg;
+
+       /* Restore the workload type data */
+       if (cfqg->saved_workload_slice) {
+               cfqd->workload_expires = jiffies + cfqg->saved_workload_slice;
+               cfqd->serving_type = cfqg->saved_workload;
+               cfqd->serving_prio = cfqg->saved_serving_prio;
+       }
+       choose_service_tree(cfqd, cfqg);
+}
+
+/*
  * Select a queue for service. If we have a current active queue,
  * check whether to continue servicing it, or retrieve and set a new one.
  */
@@ -1186,10 +2126,13 @@ static struct cfq_queue *cfq_select_queue(struct cfq_data *cfqd)
        if (!cfqq)
                goto new_queue;
 
+       if (!cfqd->rq_queued)
+               return NULL;
        /*
         * The active queue has run out of time, expire it and select new.
         */
-       if (cfq_slice_used(cfqq) && !cfq_cfqq_must_dispatch(cfqq))
+       if ((cfq_slice_used(cfqq) || cfq_cfqq_wait_busy_done(cfqq))
+            && !cfq_cfqq_must_dispatch(cfqq))
                goto expire;
 
        /*
@@ -1203,11 +2146,14 @@ static struct cfq_queue *cfq_select_queue(struct cfq_data *cfqd)
         * If another queue has a request waiting within our mean seek
         * distance, let it run.  The expire code will check for close
         * cooperators and put the close queue at the front of the service
-        * tree.
+        * tree.  If possible, merge the expiring queue with the new cfqq.
         */
-       new_cfqq = cfq_close_cooperator(cfqd, cfqq, 0);
-       if (new_cfqq)
+       new_cfqq = cfq_close_cooperator(cfqd, cfqq);
+       if (new_cfqq) {
+               if (!cfqq->new_cfqq)
+                       cfq_setup_merge(cfqq, new_cfqq);
                goto expire;
+       }
 
        /*
         * No requests pending. If the active queue still has requests in
@@ -1215,7 +2161,7 @@ static struct cfq_queue *cfq_select_queue(struct cfq_data *cfqd)
         * conditions to happen (or time out) before selecting a new queue.
         */
        if (timer_pending(&cfqd->idle_slice_timer) ||
-           (cfqq->dispatched && cfq_cfqq_idle_window(cfqq))) {
+           (cfqq->dispatched && cfq_should_idle(cfqd, cfqq))) {
                cfqq = NULL;
                goto keep_queue;
        }
@@ -1223,6 +2169,13 @@ static struct cfq_queue *cfq_select_queue(struct cfq_data *cfqd)
 expire:
        cfq_slice_expired(cfqd, 0);
 new_queue:
+       /*
+        * Current queue expired. Check if we have to switch to a new
+        * service tree
+        */
+       if (!new_cfqq)
+               cfq_choose_cfqg(cfqd);
+
        cfqq = cfq_set_active_queue(cfqd, new_cfqq);
 keep_queue:
        return cfqq;
@@ -1238,6 +2191,9 @@ static int __cfq_forced_dispatch_cfqq(struct cfq_queue *cfqq)
        }
 
        BUG_ON(!list_empty(&cfqq->fifo));
+
+       /* By default cfqq is not expired if it is empty. Do it explicitly */
+       __cfq_slice_expired(cfqq->cfqd, cfqq, 0);
        return dispatched;
 }
 
@@ -1250,11 +2206,10 @@ static int cfq_forced_dispatch(struct cfq_data *cfqd)
        struct cfq_queue *cfqq;
        int dispatched = 0;
 
-       while ((cfqq = cfq_rb_first(&cfqd->service_tree)) != NULL)
+       while ((cfqq = cfq_get_next_queue_forced(cfqd)) != NULL)
                dispatched += __cfq_forced_dispatch_cfqq(cfqq);
 
        cfq_slice_expired(cfqd, 0);
-
        BUG_ON(cfqd->busy_queues);
 
        cfq_log(cfqd, "forced_dispatch=%d", dispatched);
@@ -1268,7 +2223,7 @@ static bool cfq_may_dispatch(struct cfq_data *cfqd, struct cfq_queue *cfqq)
        /*
         * Drain async requests before we start sync IO
         */
-       if (cfq_cfqq_idle_window(cfqq) && cfqd->rq_in_driver[BLK_RW_ASYNC])
+       if (cfq_should_idle(cfqd, cfqq) && cfqd->rq_in_driver[BLK_RW_ASYNC])
                return false;
 
        /*
@@ -1298,9 +2253,9 @@ static bool cfq_may_dispatch(struct cfq_data *cfqd, struct cfq_queue *cfqq)
                        return false;
 
                /*
-                * Sole queue user, allow bigger slice
+                * Sole queue user, no limit
                 */
-               max_dispatch *= 4;
+               max_dispatch = -1;
        }
 
        /*
@@ -1407,11 +2362,13 @@ static int cfq_dispatch_requests(struct request_queue *q, int force)
  * task holds one reference to the queue, dropped when task exits. each rq
  * in-flight on this queue also holds a reference, dropped when rq is freed.
  *
+ * Each cfq queue took a reference on the parent group. Drop it now.
  * queue lock must be held here.
  */
 static void cfq_put_queue(struct cfq_queue *cfqq)
 {
        struct cfq_data *cfqd = cfqq->cfqd;
+       struct cfq_group *cfqg, *orig_cfqg;
 
        BUG_ON(atomic_read(&cfqq->ref) <= 0);
 
@@ -1421,14 +2378,19 @@ static void cfq_put_queue(struct cfq_queue *cfqq)
        cfq_log_cfqq(cfqd, cfqq, "put_queue");
        BUG_ON(rb_first(&cfqq->sort_list));
        BUG_ON(cfqq->allocated[READ] + cfqq->allocated[WRITE]);
-       BUG_ON(cfq_cfqq_on_rr(cfqq));
+       cfqg = cfqq->cfqg;
+       orig_cfqg = cfqq->orig_cfqg;
 
        if (unlikely(cfqd->active_queue == cfqq)) {
                __cfq_slice_expired(cfqd, cfqq, 0);
                cfq_schedule_dispatch(cfqd);
        }
 
+       BUG_ON(cfq_cfqq_on_rr(cfqq));
        kmem_cache_free(cfq_pool, cfqq);
+       cfq_put_cfqg(cfqg);
+       if (orig_cfqg)
+               cfq_put_cfqg(orig_cfqg);
 }
 
 /*
@@ -1518,11 +2480,29 @@ static void cfq_free_io_context(struct io_context *ioc)
 
 static void cfq_exit_cfqq(struct cfq_data *cfqd, struct cfq_queue *cfqq)
 {
+       struct cfq_queue *__cfqq, *next;
+
        if (unlikely(cfqq == cfqd->active_queue)) {
                __cfq_slice_expired(cfqd, cfqq, 0);
                cfq_schedule_dispatch(cfqd);
        }
 
+       /*
+        * If this queue was scheduled to merge with another queue, be
+        * sure to drop the reference taken on that queue (and others in
+        * the merge chain).  See cfq_setup_merge and cfq_merge_cfqqs.
+        */
+       __cfqq = cfqq->new_cfqq;
+       while (__cfqq) {
+               if (__cfqq == cfqq) {
+                       WARN(1, "cfqq->new_cfqq loop detected\n");
+                       break;
+               }
+               next = __cfqq->new_cfqq;
+               cfq_put_queue(__cfqq);
+               __cfqq = next;
+       }
+
        cfq_put_queue(cfqq);
 }
 
@@ -1703,14 +2683,51 @@ static void cfq_init_cfqq(struct cfq_data *cfqd, struct cfq_queue *cfqq,
        cfqq->pid = pid;
 }
 
+#ifdef CONFIG_CFQ_GROUP_IOSCHED
+static void changed_cgroup(struct io_context *ioc, struct cfq_io_context *cic)
+{
+       struct cfq_queue *sync_cfqq = cic_to_cfqq(cic, 1);
+       struct cfq_data *cfqd = cic->key;
+       unsigned long flags;
+       struct request_queue *q;
+
+       if (unlikely(!cfqd))
+               return;
+
+       q = cfqd->queue;
+
+       spin_lock_irqsave(q->queue_lock, flags);
+
+       if (sync_cfqq) {
+               /*
+                * Drop reference to sync queue. A new sync queue will be
+                * assigned in new group upon arrival of a fresh request.
+                */
+               cfq_log_cfqq(cfqd, sync_cfqq, "changed cgroup");
+               cic_set_cfqq(cic, NULL, 1);
+               cfq_put_queue(sync_cfqq);
+       }
+
+       spin_unlock_irqrestore(q->queue_lock, flags);
+}
+
+static void cfq_ioc_set_cgroup(struct io_context *ioc)
+{
+       call_for_each_cic(ioc, changed_cgroup);
+       ioc->cgroup_changed = 0;
+}
+#endif  /* CONFIG_CFQ_GROUP_IOSCHED */
+
 static struct cfq_queue *
 cfq_find_alloc_queue(struct cfq_data *cfqd, bool is_sync,
                     struct io_context *ioc, gfp_t gfp_mask)
 {
        struct cfq_queue *cfqq, *new_cfqq = NULL;
        struct cfq_io_context *cic;
+       struct cfq_group *cfqg;
 
 retry:
+       cfqg = cfq_get_cfqg(cfqd, 1);
        cic = cfq_cic_lookup(cfqd, ioc);
        /* cic always exists here */
        cfqq = cic_to_cfqq(cic, is_sync);
@@ -1741,6 +2758,7 @@ retry:
                if (cfqq) {
                        cfq_init_cfqq(cfqd, cfqq, current->pid, is_sync);
                        cfq_init_prio_data(cfqq, ioc);
+                       cfq_link_cfqq_cfqg(cfqq, cfqg);
                        cfq_log_cfqq(cfqd, cfqq, "alloced");
                } else
                        cfqq = &cfqd->oom_cfqq;
@@ -1932,6 +2950,10 @@ out:
        if (unlikely(ioc->ioprio_changed))
                cfq_ioc_set_ioprio(ioc);
 
+#ifdef CONFIG_CFQ_GROUP_IOSCHED
+       if (unlikely(ioc->cgroup_changed))
+               cfq_ioc_set_cgroup(ioc);
+#endif
        return cic;
 err_free:
        cfq_cic_free(cic);
@@ -1952,33 +2974,46 @@ cfq_update_io_thinktime(struct cfq_data *cfqd, struct cfq_io_context *cic)
 }
 
 static void
-cfq_update_io_seektime(struct cfq_data *cfqd, struct cfq_io_context *cic,
+cfq_update_io_seektime(struct cfq_data *cfqd, struct cfq_queue *cfqq,
                       struct request *rq)
 {
        sector_t sdist;
        u64 total;
 
-       if (!cic->last_request_pos)
+       if (!cfqq->last_request_pos)
                sdist = 0;
-       else if (cic->last_request_pos < blk_rq_pos(rq))
-               sdist = blk_rq_pos(rq) - cic->last_request_pos;
+       else if (cfqq->last_request_pos < blk_rq_pos(rq))
+               sdist = blk_rq_pos(rq) - cfqq->last_request_pos;
        else
-               sdist = cic->last_request_pos - blk_rq_pos(rq);
+               sdist = cfqq->last_request_pos - blk_rq_pos(rq);
 
        /*
         * Don't allow the seek distance to get too large from the
         * odd fragment, pagein, etc
         */
-       if (cic->seek_samples <= 60) /* second&third seek */
-               sdist = min(sdist, (cic->seek_mean * 4) + 2*1024*1024);
+       if (cfqq->seek_samples <= 60) /* second&third seek */
+               sdist = min(sdist, (cfqq->seek_mean * 4) + 2*1024*1024);
        else
-               sdist = min(sdist, (cic->seek_mean * 4) + 2*1024*64);
+               sdist = min(sdist, (cfqq->seek_mean * 4) + 2*1024*64);
 
-       cic->seek_samples = (7*cic->seek_samples + 256) / 8;
-       cic->seek_total = (7*cic->seek_total + (u64)256*sdist) / 8;
-       total = cic->seek_total + (cic->seek_samples/2);
-       do_div(total, cic->seek_samples);
-       cic->seek_mean = (sector_t)total;
+       cfqq->seek_samples = (7*cfqq->seek_samples + 256) / 8;
+       cfqq->seek_total = (7*cfqq->seek_total + (u64)256*sdist) / 8;
+       total = cfqq->seek_total + (cfqq->seek_samples/2);
+       do_div(total, cfqq->seek_samples);
+       cfqq->seek_mean = (sector_t)total;
+
+       /*
+        * If this cfqq is shared between multiple processes, check to
+        * make sure that those processes are still issuing I/Os within
+        * the mean seek distance.  If not, it may be time to break the
+        * queues apart again.
+        */
+       if (cfq_cfqq_coop(cfqq)) {
+               if (CFQQ_SEEKY(cfqq) && !cfqq->seeky_start)
+                       cfqq->seeky_start = jiffies;
+               else if (!CFQQ_SEEKY(cfqq))
+                       cfqq->seeky_start = 0;
+       }
 }
 
 /*
@@ -1999,14 +3034,15 @@ cfq_update_idle_window(struct cfq_data *cfqd, struct cfq_queue *cfqq,
 
        enable_idle = old_idle = cfq_cfqq_idle_window(cfqq);
 
+       if (cfqq->queued[0] + cfqq->queued[1] >= 4)
+               cfq_mark_cfqq_deep(cfqq);
+
        if (!atomic_read(&cic->ioc->nr_tasks) || !cfqd->cfq_slice_idle ||
-           (!cfqd->cfq_latency && cfqd->hw_tag && CIC_SEEKY(cic)))
+           (!cfq_cfqq_deep(cfqq) && sample_valid(cfqq->seek_samples)
+            && CFQQ_SEEKY(cfqq)))
                enable_idle = 0;
        else if (sample_valid(cic->ttime_samples)) {
-               unsigned int slice_idle = cfqd->cfq_slice_idle;
-               if (sample_valid(cic->seek_samples) && CIC_SEEKY(cic))
-                       slice_idle = msecs_to_jiffies(CFQ_MIN_TT);
-               if (cic->ttime_mean > slice_idle)
+               if (cic->ttime_mean > cfqd->cfq_slice_idle)
                        enable_idle = 0;
                else
                        enable_idle = 1;
@@ -2035,9 +3071,6 @@ cfq_should_preempt(struct cfq_data *cfqd, struct cfq_queue *new_cfqq,
        if (!cfqq)
                return false;
 
-       if (cfq_slice_used(cfqq))
-               return true;
-
        if (cfq_class_idle(new_cfqq))
                return false;
 
@@ -2051,6 +3084,19 @@ cfq_should_preempt(struct cfq_data *cfqd, struct cfq_queue *new_cfqq,
        if (rq_is_sync(rq) && !cfq_cfqq_sync(cfqq))
                return true;
 
+       if (new_cfqq->cfqg != cfqq->cfqg)
+               return false;
+
+       if (cfq_slice_used(cfqq))
+               return true;
+
+       /* Allow preemption only if we are idling on sync-noidle tree */
+       if (cfqd->serving_type == SYNC_NOIDLE_WORKLOAD &&
+           cfqq_type(new_cfqq) == SYNC_NOIDLE_WORKLOAD &&
+           new_cfqq->service_tree->count == 2 &&
+           RB_EMPTY_ROOT(&cfqq->sort_list))
+               return true;
+
        /*
         * So both queues are sync. Let the new request get disk time if
         * it's a metadata request and the current queue is doing regular IO.
@@ -2071,16 +3117,8 @@ cfq_should_preempt(struct cfq_data *cfqd, struct cfq_queue *new_cfqq,
         * if this request is as-good as one we would expect from the
         * current cfqq, let it preempt
         */
-       if (cfq_rq_close(cfqd, rq) && (!cfq_cfqq_coop(new_cfqq) ||
-           cfqd->busy_queues == 1)) {
-               /*
-                * Mark new queue coop_preempt, so its coop flag will not be
-                * cleared when new queue gets scheduled at the very first time
-                */
-               cfq_mark_cfqq_coop_preempt(new_cfqq);
-               cfq_mark_cfqq_coop(new_cfqq);
+       if (cfq_rq_close(cfqd, cfqq, rq))
                return true;
-       }
 
        return false;
 }
@@ -2121,12 +3159,16 @@ cfq_rq_enqueued(struct cfq_data *cfqd, struct cfq_queue *cfqq,
                cfqq->meta_pending++;
 
        cfq_update_io_thinktime(cfqd, cic);
-       cfq_update_io_seektime(cfqd, cic, rq);
+       cfq_update_io_seektime(cfqd, cfqq, rq);
        cfq_update_idle_window(cfqd, cfqq, cic);
 
-       cic->last_request_pos = blk_rq_pos(rq) + blk_rq_sectors(rq);
+       cfqq->last_request_pos = blk_rq_pos(rq) + blk_rq_sectors(rq);
 
        if (cfqq == cfqd->active_queue) {
+               if (cfq_cfqq_wait_busy(cfqq)) {
+                       cfq_clear_cfqq_wait_busy(cfqq);
+                       cfq_mark_cfqq_wait_busy_done(cfqq);
+               }
                /*
                 * Remember that we saw a request from this process, but
                 * don't start queuing just yet. Otherwise we risk seeing lots
@@ -2141,9 +3183,9 @@ cfq_rq_enqueued(struct cfq_data *cfqd, struct cfq_queue *cfqq,
                        if (blk_rq_bytes(rq) > PAGE_CACHE_SIZE ||
                            cfqd->busy_queues > 1) {
                                del_timer(&cfqd->idle_slice_timer);
-                       __blk_run_queue(cfqd->queue);
-                       }
-                       cfq_mark_cfqq_must_dispatch(cfqq);
+                               __blk_run_queue(cfqd->queue);
+                       } else
+                               cfq_mark_cfqq_must_dispatch(cfqq);
                }
        } else if (cfq_should_preempt(cfqd, cfqq, rq)) {
                /*
@@ -2165,10 +3207,9 @@ static void cfq_insert_request(struct request_queue *q, struct request *rq)
        cfq_log_cfqq(cfqd, cfqq, "insert_request");
        cfq_init_prio_data(cfqq, RQ_CIC(rq)->ioc);
 
-       cfq_add_rq_rb(rq);
-
        rq_set_fifo_time(rq, jiffies + cfqd->cfq_fifo_expire[rq_is_sync(rq)]);
        list_add_tail(&rq->queuelist, &cfqq->fifo);
+       cfq_add_rq_rb(rq);
 
        cfq_rq_enqueued(cfqd, cfqq, rq);
 }
@@ -2179,23 +3220,35 @@ static void cfq_insert_request(struct request_queue *q, struct request *rq)
  */
 static void cfq_update_hw_tag(struct cfq_data *cfqd)
 {
-       if (rq_in_driver(cfqd) > cfqd->rq_in_driver_peak)
-               cfqd->rq_in_driver_peak = rq_in_driver(cfqd);
+       struct cfq_queue *cfqq = cfqd->active_queue;
+
+       if (rq_in_driver(cfqd) > cfqd->hw_tag_est_depth)
+               cfqd->hw_tag_est_depth = rq_in_driver(cfqd);
+
+       if (cfqd->hw_tag == 1)
+               return;
 
        if (cfqd->rq_queued <= CFQ_HW_QUEUE_MIN &&
            rq_in_driver(cfqd) <= CFQ_HW_QUEUE_MIN)
                return;
 
+       /*
+        * If active queue hasn't enough requests and can idle, cfq might not
+        * dispatch sufficient requests to hardware. Don't zero hw_tag in this
+        * case
+        */
+       if (cfqq && cfq_cfqq_idle_window(cfqq) &&
+           cfqq->dispatched + cfqq->queued[0] + cfqq->queued[1] <
+           CFQ_HW_QUEUE_MIN && rq_in_driver(cfqd) < CFQ_HW_QUEUE_MIN)
+               return;
+
        if (cfqd->hw_tag_samples++ < 50)
                return;
 
-       if (cfqd->rq_in_driver_peak >= CFQ_HW_QUEUE_MIN)
+       if (cfqd->hw_tag_est_depth >= CFQ_HW_QUEUE_MIN)
                cfqd->hw_tag = 1;
        else
                cfqd->hw_tag = 0;
-
-       cfqd->hw_tag_samples = 0;
-       cfqd->rq_in_driver_peak = 0;
 }
 
 static void cfq_completed_request(struct request_queue *q, struct request *rq)
@@ -2206,7 +3259,7 @@ static void cfq_completed_request(struct request_queue *q, struct request *rq)
        unsigned long now;
 
        now = jiffies;
-       cfq_log_cfqq(cfqd, cfqq, "complete");
+       cfq_log_cfqq(cfqd, cfqq, "complete rqnoidle %d", !!rq_noidle(rq));
 
        cfq_update_hw_tag(cfqd);
 
@@ -2234,18 +3287,40 @@ static void cfq_completed_request(struct request_queue *q, struct request *rq)
                        cfq_set_prio_slice(cfqd, cfqq);
                        cfq_clear_cfqq_slice_new(cfqq);
                }
+
+               /*
+                * If this queue consumed its slice and this is last queue
+                * in the group, wait for next request before we expire
+                * the queue
+                */
+               if (cfq_slice_used(cfqq) && cfqq->cfqg->nr_cfqq == 1) {
+                       cfqq->slice_end = jiffies + cfqd->cfq_slice_idle;
+                       cfq_mark_cfqq_wait_busy(cfqq);
+               }
+
                /*
-                * If there are no requests waiting in this queue, and
-                * there are other queues ready to issue requests, AND
-                * those other queues are issuing requests within our
-                * mean seek distance, give them a chance to run instead
-                * of idling.
+                * Idling is not enabled on:
+                * - expired queues
+                * - idle-priority queues
+                * - async queues
+                * - queues with still some requests queued
+                * - when there is a close cooperator
                 */
                if (cfq_slice_used(cfqq) || cfq_class_idle(cfqq))
                        cfq_slice_expired(cfqd, 1);
-               else if (cfqq_empty && !cfq_close_cooperator(cfqd, cfqq, 1) &&
-                        sync && !rq_noidle(rq))
-                       cfq_arm_slice_timer(cfqd);
+               else if (sync && cfqq_empty &&
+                        !cfq_close_cooperator(cfqd, cfqq)) {
+                       cfqd->noidle_tree_requires_idle |= !rq_noidle(rq);
+                       /*
+                        * Idling is enabled for SYNC_WORKLOAD.
+                        * SYNC_NOIDLE_WORKLOAD idles at the end of the tree
+                        * only if we processed at least one !rq_noidle request
+                        */
+                       if (cfqd->serving_type == SYNC_WORKLOAD
+                           || cfqd->noidle_tree_requires_idle
+                           || cfqq->cfqg->nr_cfqq == 1)
+                               cfq_arm_slice_timer(cfqd);
+               }
        }
 
        if (!rq_in_driver(cfqd))
@@ -2269,12 +3344,10 @@ static void cfq_prio_boost(struct cfq_queue *cfqq)
                        cfqq->ioprio = IOPRIO_NORM;
        } else {
                /*
-                * check if we need to unboost the queue
+                * unboost the queue (if needed)
                 */
-               if (cfqq->ioprio_class != cfqq->org_ioprio_class)
-                       cfqq->ioprio_class = cfqq->org_ioprio_class;
-               if (cfqq->ioprio != cfqq->org_ioprio)
-                       cfqq->ioprio = cfqq->org_ioprio;
+               cfqq->ioprio_class = cfqq->org_ioprio_class;
+               cfqq->ioprio = cfqq->org_ioprio;
        }
 }
 
@@ -2338,6 +3411,43 @@ static void cfq_put_request(struct request *rq)
        }
 }
 
+static struct cfq_queue *
+cfq_merge_cfqqs(struct cfq_data *cfqd, struct cfq_io_context *cic,
+               struct cfq_queue *cfqq)
+{
+       cfq_log_cfqq(cfqd, cfqq, "merging with queue %p", cfqq->new_cfqq);
+       cic_set_cfqq(cic, cfqq->new_cfqq, 1);
+       cfq_mark_cfqq_coop(cfqq->new_cfqq);
+       cfq_put_queue(cfqq);
+       return cic_to_cfqq(cic, 1);
+}
+
+static int should_split_cfqq(struct cfq_queue *cfqq)
+{
+       if (cfqq->seeky_start &&
+           time_after(jiffies, cfqq->seeky_start + CFQQ_COOP_TOUT))
+               return 1;
+       return 0;
+}
+
+/*
+ * Returns NULL if a new cfqq should be allocated, or the old cfqq if this
+ * was the last process referring to said cfqq.
+ */
+static struct cfq_queue *
+split_cfqq(struct cfq_io_context *cic, struct cfq_queue *cfqq)
+{
+       if (cfqq_process_refs(cfqq) == 1) {
+               cfqq->seeky_start = 0;
+               cfqq->pid = current->pid;
+               cfq_clear_cfqq_coop(cfqq);
+               return cfqq;
+       }
+
+       cic_set_cfqq(cic, NULL, 1);
+       cfq_put_queue(cfqq);
+       return NULL;
+}
 /*
  * Allocate cfq data structures associated with this request.
  */
@@ -2360,10 +3470,30 @@ cfq_set_request(struct request_queue *q, struct request *rq, gfp_t gfp_mask)
        if (!cic)
                goto queue_fail;
 
+new_queue:
        cfqq = cic_to_cfqq(cic, is_sync);
        if (!cfqq || cfqq == &cfqd->oom_cfqq) {
                cfqq = cfq_get_queue(cfqd, is_sync, cic->ioc, gfp_mask);
                cic_set_cfqq(cic, cfqq, is_sync);
+       } else {
+               /*
+                * If the queue was seeky for too long, break it apart.
+                */
+               if (cfq_cfqq_coop(cfqq) && should_split_cfqq(cfqq)) {
+                       cfq_log_cfqq(cfqd, cfqq, "breaking apart cfqq");
+                       cfqq = split_cfqq(cic, cfqq);
+                       if (!cfqq)
+                               goto new_queue;
+               }
+
+               /*
+                * Check to see if this queue is scheduled to merge with
+                * another, closely cooperating queue.  The merging of
+                * queues happens here as it must be done in process context.
+                * The reference on new_cfqq was taken in merge_cfqqs.
+                */
+               if (cfqq->new_cfqq)
+                       cfqq = cfq_merge_cfqqs(cfqd, cic, cfqq);
        }
 
        cfqq->allocated[rw]++;
@@ -2438,6 +3568,11 @@ static void cfq_idle_slice_timer(unsigned long data)
                 */
                if (!RB_EMPTY_ROOT(&cfqq->sort_list))
                        goto out_kick;
+
+               /*
+                * Queue depth flag is reset only when the idle didn't succeed
+                */
+               cfq_clear_cfqq_deep(cfqq);
        }
 expire:
        cfq_slice_expired(cfqd, timed_out);
@@ -2468,6 +3603,11 @@ static void cfq_put_async_queues(struct cfq_data *cfqd)
                cfq_put_queue(cfqd->async_idle_cfqq);
 }
 
+static void cfq_cfqd_free(struct rcu_head *head)
+{
+       kfree(container_of(head, struct cfq_data, rcu));
+}
+
 static void cfq_exit_queue(struct elevator_queue *e)
 {
        struct cfq_data *cfqd = e->elevator_data;
@@ -2489,25 +3629,49 @@ static void cfq_exit_queue(struct elevator_queue *e)
        }
 
        cfq_put_async_queues(cfqd);
+       cfq_release_cfq_groups(cfqd);
+       blkiocg_del_blkio_group(&cfqd->root_group.blkg);
 
        spin_unlock_irq(q->queue_lock);
 
        cfq_shutdown_timer_wq(cfqd);
 
-       kfree(cfqd);
+       /* Wait for cfqg->blkg->key accessors to exit their grace periods. */
+       call_rcu(&cfqd->rcu, cfq_cfqd_free);
 }
 
 static void *cfq_init_queue(struct request_queue *q)
 {
        struct cfq_data *cfqd;
-       int i;
+       int i, j;
+       struct cfq_group *cfqg;
+       struct cfq_rb_root *st;
 
        cfqd = kmalloc_node(sizeof(*cfqd), GFP_KERNEL | __GFP_ZERO, q->node);
        if (!cfqd)
                return NULL;
 
-       cfqd->service_tree = CFQ_RB_ROOT;
+       /* Init root service tree */
+       cfqd->grp_service_tree = CFQ_RB_ROOT;
+
+       /* Init root group */
+       cfqg = &cfqd->root_group;
+       for_each_cfqg_st(cfqg, i, j, st)
+               *st = CFQ_RB_ROOT;
+       RB_CLEAR_NODE(&cfqg->rb_node);
 
+       /* Give preference to root group over other groups */
+       cfqg->weight = 2*BLKIO_WEIGHT_DEFAULT;
+
+#ifdef CONFIG_CFQ_GROUP_IOSCHED
+       /*
+        * Take a reference to root group which we never drop. This is just
+        * to make sure that cfq_put_cfqg() does not try to kfree root group
+        */
+       atomic_set(&cfqg->ref, 1);
+       blkiocg_add_blkio_group(&blkio_root_cgroup, &cfqg->blkg, (void *)cfqd,
+                                       0);
+#endif
        /*
         * Not strictly needed (since RB_ROOT just clears the node and we
         * zeroed cfqd on alloc), but better be safe in case someone decides
@@ -2523,6 +3687,7 @@ static void *cfq_init_queue(struct request_queue *q)
         */
        cfq_init_cfqq(cfqd, &cfqd->oom_cfqq, 1, 0);
        atomic_inc(&cfqd->oom_cfqq.ref);
+       cfq_link_cfqq_cfqg(&cfqd->oom_cfqq, &cfqd->root_group);
 
        INIT_LIST_HEAD(&cfqd->cic_list);
 
@@ -2544,8 +3709,10 @@ static void *cfq_init_queue(struct request_queue *q)
        cfqd->cfq_slice_async_rq = cfq_slice_async_rq;
        cfqd->cfq_slice_idle = cfq_slice_idle;
        cfqd->cfq_latency = 1;
-       cfqd->hw_tag = 1;
+       cfqd->cfq_group_isolation = 0;
+       cfqd->hw_tag = -1;
        cfqd->last_end_sync_rq = jiffies;
+       INIT_RCU_HEAD(&cfqd->rcu);
        return cfqd;
 }
 
@@ -2614,6 +3781,7 @@ SHOW_FUNCTION(cfq_slice_sync_show, cfqd->cfq_slice[1], 1);
 SHOW_FUNCTION(cfq_slice_async_show, cfqd->cfq_slice[0], 1);
 SHOW_FUNCTION(cfq_slice_async_rq_show, cfqd->cfq_slice_async_rq, 0);
 SHOW_FUNCTION(cfq_low_latency_show, cfqd->cfq_latency, 0);
+SHOW_FUNCTION(cfq_group_isolation_show, cfqd->cfq_group_isolation, 0);
 #undef SHOW_FUNCTION
 
 #define STORE_FUNCTION(__FUNC, __PTR, MIN, MAX, __CONV)                        \
@@ -2646,6 +3814,7 @@ STORE_FUNCTION(cfq_slice_async_store, &cfqd->cfq_slice[0], 1, UINT_MAX, 1);
 STORE_FUNCTION(cfq_slice_async_rq_store, &cfqd->cfq_slice_async_rq, 1,
                UINT_MAX, 0);
 STORE_FUNCTION(cfq_low_latency_store, &cfqd->cfq_latency, 0, 1, 0);
+STORE_FUNCTION(cfq_group_isolation_store, &cfqd->cfq_group_isolation, 0, 1, 0);
 #undef STORE_FUNCTION
 
 #define CFQ_ATTR(name) \
@@ -2662,6 +3831,7 @@ static struct elv_fs_entry cfq_attrs[] = {
        CFQ_ATTR(slice_async_rq),
        CFQ_ATTR(slice_idle),
        CFQ_ATTR(low_latency),
+       CFQ_ATTR(group_isolation),
        __ATTR_NULL
 };
 
@@ -2691,6 +3861,17 @@ static struct elevator_type iosched_cfq = {
        .elevator_owner =       THIS_MODULE,
 };
 
+#ifdef CONFIG_CFQ_GROUP_IOSCHED
+static struct blkio_policy_type blkio_policy_cfq = {
+       .ops = {
+               .blkio_unlink_group_fn =        cfq_unlink_blkio_group,
+               .blkio_update_group_weight_fn = cfq_update_blkio_group_weight,
+       },
+};
+#else
+static struct blkio_policy_type blkio_policy_cfq;
+#endif
+
 static int __init cfq_init(void)
 {
        /*
@@ -2705,6 +3886,7 @@ static int __init cfq_init(void)
                return -ENOMEM;
 
        elv_register(&iosched_cfq);
+       blkio_policy_register(&blkio_policy_cfq);
 
        return 0;
 }
@@ -2712,6 +3894,7 @@ static int __init cfq_init(void)
 static void __exit cfq_exit(void)
 {
        DECLARE_COMPLETION_ONSTACK(all_gone);
+       blkio_policy_unregister(&blkio_policy_cfq);
        elv_unregister(&iosched_cfq);
        ioc_gone = &all_gone;
        /* ioc_gone's update must be visible before reading ioc_count */
index 9bd086c..4eb8e9e 100644 (file)
@@ -747,6 +747,8 @@ long compat_blkdev_ioctl(struct file *file, unsigned cmd, unsigned long arg)
                return compat_put_uint(arg, bdev_io_opt(bdev));
        case BLKALIGNOFF:
                return compat_put_int(arg, bdev_alignment_offset(bdev));
+       case BLKDISCARDZEROES:
+               return compat_put_uint(arg, bdev_discard_zeroes_data(bdev));
        case BLKFLSBUF:
        case BLKROSET:
        case BLKDISCARD:
index a847046..9ad5ccc 100644 (file)
@@ -154,10 +154,7 @@ static struct elevator_type *elevator_get(const char *name)
 
                spin_unlock(&elv_list_lock);
 
-               if (!strcmp(name, "anticipatory"))
-                       sprintf(elv, "as-iosched");
-               else
-                       sprintf(elv, "%s-iosched", name);
+               sprintf(elv, "%s-iosched", name);
 
                request_module("%s", elv);
                spin_lock(&elv_list_lock);
@@ -193,10 +190,7 @@ static int __init elevator_setup(char *str)
         * Be backwards-compatible with previous kernels, so users
         * won't get the wrong elevator.
         */
-       if (!strcmp(str, "as"))
-               strcpy(chosen_elevator, "anticipatory");
-       else
-               strncpy(chosen_elevator, str, sizeof(chosen_elevator) - 1);
+       strncpy(chosen_elevator, str, sizeof(chosen_elevator) - 1);
        return 1;
 }
 
index 517e433..b11a4ad 100644 (file)
@@ -861,12 +861,23 @@ static ssize_t disk_alignment_offset_show(struct device *dev,
        return sprintf(buf, "%d\n", queue_alignment_offset(disk->queue));
 }
 
+static ssize_t disk_discard_alignment_show(struct device *dev,
+                                          struct device_attribute *attr,
+                                          char *buf)
+{
+       struct gendisk *disk = dev_to_disk(dev);
+
+       return sprintf(buf, "%u\n", queue_discard_alignment(disk->queue));
+}
+
 static DEVICE_ATTR(range, S_IRUGO, disk_range_show, NULL);
 static DEVICE_ATTR(ext_range, S_IRUGO, disk_ext_range_show, NULL);
 static DEVICE_ATTR(removable, S_IRUGO, disk_removable_show, NULL);
 static DEVICE_ATTR(ro, S_IRUGO, disk_ro_show, NULL);
 static DEVICE_ATTR(size, S_IRUGO, part_size_show, NULL);
 static DEVICE_ATTR(alignment_offset, S_IRUGO, disk_alignment_offset_show, NULL);
+static DEVICE_ATTR(discard_alignment, S_IRUGO, disk_discard_alignment_show,
+                  NULL);
 static DEVICE_ATTR(capability, S_IRUGO, disk_capability_show, NULL);
 static DEVICE_ATTR(stat, S_IRUGO, part_stat_show, NULL);
 static DEVICE_ATTR(inflight, S_IRUGO, part_inflight_show, NULL);
@@ -887,6 +898,7 @@ static struct attribute *disk_attrs[] = {
        &dev_attr_ro.attr,
        &dev_attr_size.attr,
        &dev_attr_alignment_offset.attr,
+       &dev_attr_discard_alignment.attr,
        &dev_attr_capability.attr,
        &dev_attr_stat.attr,
        &dev_attr_inflight.attr,
index 1f4d1de..be48ea5 100644 (file)
@@ -280,6 +280,8 @@ int blkdev_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd,
                return put_uint(arg, bdev_io_opt(bdev));
        case BLKALIGNOFF:
                return put_int(arg, bdev_alignment_offset(bdev));
+       case BLKDISCARDZEROES:
+               return put_uint(arg, bdev_discard_zeroes_data(bdev));
        case BLKSECTGET:
                return put_ushort(arg, queue_max_sectors(bdev_get_queue(bdev)));
        case BLKRASET:
index e5b1001..a8b5a10 100644 (file)
@@ -35,7 +35,9 @@
 struct blk_cmd_filter {
        unsigned long read_ok[BLK_SCSI_CMD_PER_LONG];
        unsigned long write_ok[BLK_SCSI_CMD_PER_LONG];
-} blk_default_cmd_filter;
+};
+
+static struct blk_cmd_filter blk_default_cmd_filter;
 
 /* Command group 3 is reserved and should never be used.  */
 const unsigned char scsi_command_size_tbl[8] =
@@ -675,7 +677,7 @@ int scsi_cmd_ioctl(struct request_queue *q, struct gendisk *bd_disk, fmode_t mod
 }
 EXPORT_SYMBOL(scsi_cmd_ioctl);
 
-int __init blk_scsi_ioctl_init(void)
+static int __init blk_scsi_ioctl_init(void)
 {
        blk_set_cmd_filter_defaults(&blk_default_cmd_filter);
        return 0;
index 5dc07e4..1c38733 100644 (file)
 #ifdef CONFIG_CRYPTO_FIPS
 static struct ctl_table crypto_sysctl_table[] = {
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "fips_enabled",
                .data           = &fips_enabled,
                .maxlen         = sizeof(int),
                .mode           = 0444,
-               .proc_handler   = &proc_dointvec
-       },
-       {
-               .ctl_name = 0,
+               .proc_handler   = proc_dointvec
        },
+       {}
 };
 
 static struct ctl_table crypto_dir_table[] = {
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "crypto",
                .mode           = 0555,
                .child          = crypto_sysctl_table
        },
-       {
-               .ctl_name = 0,
-       },
+       {}
 };
 
 static struct ctl_table_header *crypto_sysctls;
index f2df6e2..676f08b 100644 (file)
@@ -3,7 +3,7 @@
 #
 
 menuconfig ATA
-       tristate "Serial ATA (prod) and Parallel ATA (experimental) drivers"
+       tristate "Serial ATA and Parallel ATA drivers"
        depends on HAS_IOMEM
        depends on BLOCK
        depends on !(M32R || M68K) || BROKEN
@@ -374,8 +374,8 @@ config PATA_HPT366
          If unsure, say N.
 
 config PATA_HPT37X
-       tristate "HPT 370/370A/371/372/374/302 PATA support (Experimental)"
-       depends on PCI && EXPERIMENTAL
+       tristate "HPT 370/370A/371/372/374/302 PATA support"
+       depends on PCI
        help
          This option enables support for the majority of the later HPT
          PATA controllers via the new ATA layer.
@@ -383,8 +383,8 @@ config PATA_HPT37X
          If unsure, say N.
 
 config PATA_HPT3X2N
-       tristate "HPT 372N/302N PATA support (Experimental)"
-       depends on PCI && EXPERIMENTAL
+       tristate "HPT 372N/302N PATA support"
+       depends on PCI
        help
          This option enables support for the N variant HPT PATA
          controllers via the new ATA layer
@@ -401,7 +401,7 @@ config PATA_HPT3X3
          If unsure, say N.
 
 config PATA_HPT3X3_DMA
-       bool "HPT 343/363 DMA support (Experimental)"
+       bool "HPT 343/363 DMA support"
        depends on PATA_HPT3X3
        help
          This option enables DMA support for the HPT343/363
@@ -510,8 +510,8 @@ config PATA_NETCELL
          If unsure, say N.
 
 config PATA_NINJA32
-       tristate "Ninja32/Delkin Cardbus ATA support (Experimental)"
-       depends on PCI && EXPERIMENTAL
+       tristate "Ninja32/Delkin Cardbus ATA support"
+       depends on PCI
        help
          This option enables support for the Ninja32, Delkin and
          possibly other brands of Cardbus ATA adapter
@@ -573,6 +573,14 @@ config PATA_PCMCIA
 
          If unsure, say N.
 
+config PATA_PDC2027X
+       tristate "Promise PATA 2027x support"
+       depends on PCI
+       help
+         This option enables support for Promise PATA pdc20268 to pdc20277 host adapters.
+
+         If unsure, say N.
+
 config PATA_PDC_OLD
        tristate "Older Promise PATA controller support"
        depends on PCI
@@ -643,14 +651,6 @@ config PATA_SERVERWORKS
 
          If unsure, say N.
 
-config PATA_PDC2027X
-       tristate "Promise PATA 2027x support"
-       depends on PCI
-       help
-         This option enables support for Promise PATA pdc20268 to pdc20277 host adapters.
-
-         If unsure, say N.
-
 config PATA_SIL680
        tristate "CMD / Silicon Image 680 PATA support"
        depends on PCI
@@ -667,6 +667,15 @@ config PATA_SIS
 
          If unsure, say N.
 
+config PATA_TOSHIBA
+       tristate "Toshiba Piccolo support (Experimental)"
+       depends on PCI && EXPERIMENTAL
+       help
+         Support for the Toshiba Piccolo controllers. Currently only the
+         primary channel is supported by this driver.
+
+         If unsure, say N.
+
 config PATA_VIA
        tristate "VIA PATA support"
        depends on PCI
index 01e126f..d909435 100644 (file)
@@ -63,6 +63,7 @@ obj-$(CONFIG_PATA_RZ1000)     += pata_rz1000.o
 obj-$(CONFIG_PATA_SC1200)      += pata_sc1200.o
 obj-$(CONFIG_PATA_SERVERWORKS) += pata_serverworks.o
 obj-$(CONFIG_PATA_SIL680)      += pata_sil680.o
+obj-$(CONFIG_PATA_TOSHIBA)     += pata_piccolo.o
 obj-$(CONFIG_PATA_VIA)         += pata_via.o
 obj-$(CONFIG_PATA_WINBOND)     += pata_sl82c105.o
 obj-$(CONFIG_PATA_WINBOND_VLB) += pata_winbond.o
index a3241a1..b8bea10 100644 (file)
@@ -113,6 +113,7 @@ enum {
        board_ahci_mcp65        = 6,
        board_ahci_nopmp        = 7,
        board_ahci_yesncq       = 8,
+       board_ahci_nosntf       = 9,
 
        /* global controller registers */
        HOST_CAP                = 0x00, /* host capabilities */
@@ -235,6 +236,7 @@ enum {
        AHCI_HFLAG_NO_SUSPEND           = (1 << 10), /* don't suspend */
        AHCI_HFLAG_SRST_TOUT_IS_OFFLINE = (1 << 11), /* treat SRST timeout as
                                                        link offline */
+       AHCI_HFLAG_NO_SNTF              = (1 << 12), /* no sntf */
 
        /* ap->flags bits */
 
@@ -508,7 +510,7 @@ static const struct ata_port_info ahci_port_info[] = {
                .udma_mask      = ATA_UDMA6,
                .port_ops       = &ahci_ops,
        },
-       /* board_ahci_yesncq */
+       [board_ahci_yesncq] =
        {
                AHCI_HFLAGS     (AHCI_HFLAG_YES_NCQ),
                .flags          = AHCI_FLAG_COMMON,
@@ -516,6 +518,14 @@ static const struct ata_port_info ahci_port_info[] = {
                .udma_mask      = ATA_UDMA6,
                .port_ops       = &ahci_ops,
        },
+       [board_ahci_nosntf] =
+       {
+               AHCI_HFLAGS     (AHCI_HFLAG_NO_SNTF),
+               .flags          = AHCI_FLAG_COMMON,
+               .pio_mask       = ATA_PIO4,
+               .udma_mask      = ATA_UDMA6,
+               .port_ops       = &ahci_ops,
+       },
 };
 
 static const struct pci_device_id ahci_pci_tbl[] = {
@@ -531,7 +541,7 @@ static const struct pci_device_id ahci_pci_tbl[] = {
        { PCI_VDEVICE(INTEL, 0x2683), board_ahci }, /* ESB2 */
        { PCI_VDEVICE(INTEL, 0x27c6), board_ahci }, /* ICH7-M DH */
        { PCI_VDEVICE(INTEL, 0x2821), board_ahci }, /* ICH8 */
-       { PCI_VDEVICE(INTEL, 0x2822), board_ahci }, /* ICH8 */
+       { PCI_VDEVICE(INTEL, 0x2822), board_ahci_nosntf }, /* ICH8 */
        { PCI_VDEVICE(INTEL, 0x2824), board_ahci }, /* ICH8 */
        { PCI_VDEVICE(INTEL, 0x2829), board_ahci }, /* ICH8M */
        { PCI_VDEVICE(INTEL, 0x282a), board_ahci }, /* ICH8M */
@@ -849,6 +859,12 @@ static void ahci_save_initial_config(struct pci_dev *pdev,
                cap &= ~HOST_CAP_PMP;
        }
 
+       if ((cap & HOST_CAP_SNTF) && (hpriv->flags & AHCI_HFLAG_NO_SNTF)) {
+               dev_printk(KERN_INFO, &pdev->dev,
+                          "controller can't do SNTF, turning off CAP_SNTF\n");
+               cap &= ~HOST_CAP_SNTF;
+       }
+
        if (pdev->vendor == PCI_VENDOR_ID_JMICRON && pdev->device == 0x2361 &&
            port_map != 1) {
                dev_printk(KERN_INFO, &pdev->dev,
@@ -2988,6 +3004,14 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        if (pdev->vendor == PCI_VENDOR_ID_MARVELL && !marvell_enable)
                return -ENODEV;
 
+       /* Promise's PDC42819 is a SAS/SATA controller that has an AHCI mode.
+        * At the moment, we can only use the AHCI mode. Let the users know
+        * that for SAS drives they're out of luck.
+        */
+       if (pdev->vendor == PCI_VENDOR_ID_PROMISE)
+               dev_printk(KERN_INFO, &pdev->dev, "PDC42819 "
+                          "can only drive SATA devices with this driver\n");
+
        /* acquire resources */
        rc = pcim_enable_device(pdev);
        if (rc)
index ecfd22b..12e26c3 100644 (file)
@@ -168,9 +168,12 @@ static struct pci_device_id ata_generic[] = {
        { PCI_DEVICE(PCI_VENDOR_ID_VIA,    PCI_DEVICE_ID_VIA_82C561), },
        { PCI_DEVICE(PCI_VENDOR_ID_OPTI,   PCI_DEVICE_ID_OPTI_82C558), },
        { PCI_DEVICE(PCI_VENDOR_ID_CENATEK,PCI_DEVICE_ID_CENATEK_IDE), },
-       { PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO), },
+#if !defined(CONFIG_PATA_TOSHIBA) && !defined(CONFIG_PATA_TOSHIBA_MODULE)
        { PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO_1), },
        { PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO_2),  },
+       { PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO_3),  },
+       { PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO_5),  },
+#endif 
        /* Must come last. If you add entries adjust this table appropriately */
        { PCI_ANY_ID,           PCI_ANY_ID,                        PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_STORAGE_IDE << 8, 0xFFFFFF00UL, 1},
        { 0, },
index 9ac4e37..0c6155f 100644 (file)
@@ -869,10 +869,10 @@ static void do_pata_set_dmamode(struct ata_port *ap, struct ata_device *adev, in
                                (timings[pio][1] << 8);
                }
 
-               if (ap->udma_mask) {
+               if (ap->udma_mask)
                        udma_enable &= ~(1 << devid);
-                       pci_write_config_word(dev, master_port, master_data);
-               }
+
+               pci_write_config_word(dev, master_port, master_data);
        }
        /* Don't scribble on 0x48 if the controller does not support UDMA */
        if (ap->udma_mask)
index b0882cd..1245838 100644 (file)
@@ -807,12 +807,11 @@ static int ata_acpi_exec_tfs(struct ata_device *dev, int *nr_executed)
  * EH context.
  *
  * RETURNS:
- * 0 on success, -errno on failure.
+ * 0 on success, -ENOENT if _SDD doesn't exist, -errno on failure.
  */
 static int ata_acpi_push_id(struct ata_device *dev)
 {
        struct ata_port *ap = dev->link->ap;
-       int err;
        acpi_status status;
        struct acpi_object_list input;
        union acpi_object in_params[1];
@@ -835,12 +834,16 @@ static int ata_acpi_push_id(struct ata_device *dev)
        status = acpi_evaluate_object(dev->acpi_handle, "_SDD", &input, NULL);
        swap_buf_le16(dev->id, ATA_ID_WORDS);
 
-       err = ACPI_FAILURE(status) ? -EIO : 0;
-       if (err < 0)
+       if (status == AE_NOT_FOUND)
+               return -ENOENT;
+
+       if (ACPI_FAILURE(status)) {
                ata_dev_printk(dev, KERN_WARNING,
                               "ACPI _SDD failed (AE 0x%x)\n", status);
+               return -EIO;
+       }
 
-       return err;
+       return 0;
 }
 
 /**
@@ -971,7 +974,7 @@ int ata_acpi_on_devcfg(struct ata_device *dev)
        /* do _SDD if SATA */
        if (acpi_sata) {
                rc = ata_acpi_push_id(dev);
-               if (rc)
+               if (rc && rc != -ENOENT)
                        goto acpi_err;
        }
 
index dc72690..22ff51b 100644 (file)
@@ -6616,6 +6616,13 @@ static int __init ata_init(void)
 {
        ata_parse_force_param();
 
+       /*
+        * FIXME: In UP case, there is only one workqueue thread and if you
+        * have more than one PIO device, latency is bloody awful, with
+        * occasional multi-second "hiccups" as one PIO device waits for
+        * another.  It's an ugly wart that users DO occasionally complain
+        * about; luckily most users have at most one PIO polled device.
+        */
        ata_wq = create_workqueue("ata");
        if (!ata_wq)
                goto free_force_tbl;
index bba2ae5..0ea97c9 100644 (file)
@@ -110,6 +110,13 @@ static const unsigned long ata_eh_identify_timeouts[] = {
        ULONG_MAX,
 };
 
+static const unsigned long ata_eh_flush_timeouts[] = {
+       15000,  /* be generous with flush */
+       15000,  /* ditto */
+       30000,  /* and even more generous */
+       ULONG_MAX,
+};
+
 static const unsigned long ata_eh_other_timeouts[] = {
         5000,  /* same rationale as identify timeout */
        10000,  /* ditto */
@@ -147,6 +154,8 @@ ata_eh_cmd_timeout_table[ATA_EH_CMD_TIMEOUT_TABLE_SIZE] = {
          .timeouts = ata_eh_other_timeouts, },
        { .commands = CMDS(ATA_CMD_INIT_DEV_PARAMS),
          .timeouts = ata_eh_other_timeouts, },
+       { .commands = CMDS(ATA_CMD_FLUSH, ATA_CMD_FLUSH_EXT),
+         .timeouts = ata_eh_flush_timeouts },
 };
 #undef CMDS
 
@@ -3112,6 +3121,82 @@ static int atapi_eh_clear_ua(struct ata_device *dev)
        return 0;
 }
 
+/**
+ *     ata_eh_maybe_retry_flush - Retry FLUSH if necessary
+ *     @dev: ATA device which may need FLUSH retry
+ *
+ *     If @dev failed FLUSH, it needs to be reported upper layer
+ *     immediately as it means that @dev failed to remap and already
+ *     lost at least a sector and further FLUSH retrials won't make
+ *     any difference to the lost sector.  However, if FLUSH failed
+ *     for other reasons, for example transmission error, FLUSH needs
+ *     to be retried.
+ *
+ *     This function determines whether FLUSH failure retry is
+ *     necessary and performs it if so.
+ *
+ *     RETURNS:
+ *     0 if EH can continue, -errno if EH needs to be repeated.
+ */
+static int ata_eh_maybe_retry_flush(struct ata_device *dev)
+{
+       struct ata_link *link = dev->link;
+       struct ata_port *ap = link->ap;
+       struct ata_queued_cmd *qc;
+       struct ata_taskfile tf;
+       unsigned int err_mask;
+       int rc = 0;
+
+       /* did flush fail for this device? */
+       if (!ata_tag_valid(link->active_tag))
+               return 0;
+
+       qc = __ata_qc_from_tag(ap, link->active_tag);
+       if (qc->dev != dev || (qc->tf.command != ATA_CMD_FLUSH_EXT &&
+                              qc->tf.command != ATA_CMD_FLUSH))
+               return 0;
+
+       /* if the device failed it, it should be reported to upper layers */
+       if (qc->err_mask & AC_ERR_DEV)
+               return 0;
+
+       /* flush failed for some other reason, give it another shot */
+       ata_tf_init(dev, &tf);
+
+       tf.command = qc->tf.command;
+       tf.flags |= ATA_TFLAG_DEVICE;
+       tf.protocol = ATA_PROT_NODATA;
+
+       ata_dev_printk(dev, KERN_WARNING, "retrying FLUSH 0x%x Emask 0x%x\n",
+                      tf.command, qc->err_mask);
+
+       err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0, 0);
+       if (!err_mask) {
+               /*
+                * FLUSH is complete but there's no way to
+                * successfully complete a failed command from EH.
+                * Making sure retry is allowed at least once and
+                * retrying it should do the trick - whatever was in
+                * the cache is already on the platter and this won't
+                * cause infinite loop.
+                */
+               qc->scsicmd->allowed = max(qc->scsicmd->allowed, 1);
+       } else {
+               ata_dev_printk(dev, KERN_WARNING, "FLUSH failed Emask 0x%x\n",
+                              err_mask);
+               rc = -EIO;
+
+               /* if device failed it, report it to upper layers */
+               if (err_mask & AC_ERR_DEV) {
+                       qc->err_mask |= AC_ERR_DEV;
+                       qc->result_tf = tf;
+                       if (!(ap->pflags & ATA_PFLAG_FROZEN))
+                               rc = 0;
+               }
+       }
+       return rc;
+}
+
 static int ata_link_nr_enabled(struct ata_link *link)
 {
        struct ata_device *dev;
@@ -3455,6 +3540,15 @@ int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
                        }
                }
 
+               /* retry flush if necessary */
+               ata_for_each_dev(dev, link, ALL) {
+                       if (dev->class != ATA_DEV_ATA)
+                               continue;
+                       rc = ata_eh_maybe_retry_flush(dev);
+                       if (rc)
+                               goto dev_fail;
+               }
+
                /* configure link power saving */
                if (ehc->i.action & ATA_EH_LPM)
                        ata_for_each_dev(dev, link, ALL)
index b4ee28d..62e6b9e 100644 (file)
@@ -47,6 +47,7 @@
 #include <linux/hdreg.h>
 #include <linux/uaccess.h>
 #include <linux/suspend.h>
+#include <asm/unaligned.h>
 
 #include "libata.h"
 
@@ -154,8 +155,7 @@ static ssize_t ata_scsi_lpm_put(struct device *dev,
         */
        for (i = 1; i < ARRAY_SIZE(link_pm_policy); i++) {
                const int len = strlen(link_pm_policy[i].name);
-               if (strncmp(link_pm_policy[i].name, buf, len) == 0 &&
-                  buf[len] == '\n') {
+               if (strncmp(link_pm_policy[i].name, buf, len) == 0) {
                        policy = link_pm_policy[i].value;
                        break;
                }
@@ -1964,6 +1964,7 @@ static unsigned int ata_scsiop_inq_00(struct ata_scsi_args *args, u8 *rbuf)
                0x80,   /* page 0x80, unit serial no page */
                0x83,   /* page 0x83, device ident page */
                0x89,   /* page 0x89, ata info page */
+               0xb0,   /* page 0xb0, block limits page */
                0xb1,   /* page 0xb1, block device characteristics page */
        };
 
@@ -2085,6 +2086,43 @@ static unsigned int ata_scsiop_inq_89(struct ata_scsi_args *args, u8 *rbuf)
        return 0;
 }
 
+static unsigned int ata_scsiop_inq_b0(struct ata_scsi_args *args, u8 *rbuf)
+{
+       u32 min_io_sectors;
+
+       rbuf[1] = 0xb0;
+       rbuf[3] = 0x3c;         /* required VPD size with unmap support */
+
+       /*
+        * Optimal transfer length granularity.
+        *
+        * This is always one physical block, but for disks with a smaller
+        * logical than physical sector size we need to figure out what the
+        * latter is.
+        */
+       if (ata_id_has_large_logical_sectors(args->id))
+               min_io_sectors = ata_id_logical_per_physical_sectors(args->id);
+       else
+               min_io_sectors = 1;
+       put_unaligned_be16(min_io_sectors, &rbuf[6]);
+
+       /*
+        * Optimal unmap granularity.
+        *
+        * The ATA spec doesn't even know about a granularity or alignment
+        * for the TRIM command.  We can leave away most of the unmap related
+        * VPD page entries, but we have specifify a granularity to signal
+        * that we support some form of unmap - in thise case via WRITE SAME
+        * with the unmap bit set.
+        */
+       if (ata_id_has_trim(args->id)) {
+               put_unaligned_be32(65535 * 512 / 8, &rbuf[20]);
+               put_unaligned_be32(1, &rbuf[28]);
+       }
+
+       return 0;
+}
+
 static unsigned int ata_scsiop_inq_b1(struct ata_scsi_args *args, u8 *rbuf)
 {
        int form_factor = ata_id_form_factor(args->id);
@@ -2374,6 +2412,13 @@ static unsigned int ata_scsiop_read_cap(struct ata_scsi_args *args, u8 *rbuf)
                rbuf[13] = log_per_phys;
                rbuf[14] = (lowest_aligned >> 8) & 0x3f;
                rbuf[15] = lowest_aligned;
+
+               if (ata_id_has_trim(args->id)) {
+                       rbuf[14] |= 0x80; /* TPE */
+
+                       if (ata_id_has_zero_after_trim(args->id))
+                               rbuf[14] |= 0x40; /* TPRZ */
+               }
        }
 
        return 0;
@@ -2896,6 +2941,58 @@ static unsigned int ata_scsi_pass_thru(struct ata_queued_cmd *qc)
        return 1;
 }
 
+static unsigned int ata_scsi_write_same_xlat(struct ata_queued_cmd *qc)
+{
+       struct ata_taskfile *tf = &qc->tf;
+       struct scsi_cmnd *scmd = qc->scsicmd;
+       struct ata_device *dev = qc->dev;
+       const u8 *cdb = scmd->cmnd;
+       u64 block;
+       u32 n_block;
+       u32 size;
+       void *buf;
+
+       /* we may not issue DMA commands if no DMA mode is set */
+       if (unlikely(!dev->dma_mode))
+               goto invalid_fld;
+
+       if (unlikely(scmd->cmd_len < 16))
+               goto invalid_fld;
+       scsi_16_lba_len(cdb, &block, &n_block);
+
+       /* for now we only support WRITE SAME with the unmap bit set */
+       if (unlikely(!(cdb[1] & 0x8)))
+               goto invalid_fld;
+
+       /*
+        * WRITE SAME always has a sector sized buffer as payload, this
+        * should never be a multiple entry S/G list.
+        */
+       if (!scsi_sg_count(scmd))
+               goto invalid_fld;
+
+       buf = page_address(sg_page(scsi_sglist(scmd)));
+       size = ata_set_lba_range_entries(buf, 512, block, n_block);
+
+       tf->protocol = ATA_PROT_DMA;
+       tf->hob_feature = 0;
+       tf->feature = ATA_DSM_TRIM;
+       tf->hob_nsect = (size / 512) >> 8;
+       tf->nsect = size / 512;
+       tf->command = ATA_CMD_DSM;
+       tf->flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE | ATA_TFLAG_LBA48 |
+                    ATA_TFLAG_WRITE;
+
+       ata_qc_set_pc_nbytes(qc);
+
+       return 0;
+
+ invalid_fld:
+       ata_scsi_set_sense(scmd, ILLEGAL_REQUEST, 0x24, 0x00);
+       /* "Invalid field in cdb" */
+       return 1;
+}
+
 /**
  *     ata_get_xlat_func - check if SCSI to ATA translation is possible
  *     @dev: ATA device
@@ -2920,6 +3017,9 @@ static inline ata_xlat_func_t ata_get_xlat_func(struct ata_device *dev, u8 cmd)
        case WRITE_16:
                return ata_scsi_rw_xlat;
 
+       case 0x93 /*WRITE_SAME_16*/:
+               return ata_scsi_write_same_xlat;
+
        case SYNCHRONIZE_CACHE:
                if (ata_try_flush_cache(dev))
                        return ata_scsi_flush_xlat;
@@ -3109,6 +3209,9 @@ void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd,
                case 0x89:
                        ata_scsi_rbuf_fill(&args, ata_scsiop_inq_89);
                        break;
+               case 0xb0:
+                       ata_scsi_rbuf_fill(&args, ata_scsiop_inq_b0);
+                       break;
                case 0xb1:
                        ata_scsi_rbuf_fill(&args, ata_scsiop_inq_b1);
                        break;
index bbbb1fa..51eb1e2 100644 (file)
@@ -2384,7 +2384,7 @@ void ata_sff_post_internal_cmd(struct ata_queued_cmd *qc)
        ap->hsm_task_state = HSM_ST_IDLE;
 
        if (ap->ioaddr.bmdma_addr)
-               ata_bmdma_stop(qc);
+               ap->ops->bmdma_stop(qc);
 
        spin_unlock_irqrestore(ap->lock, flags);
 }
index 1432dc9..9434114 100644 (file)
@@ -453,7 +453,9 @@ static void ali_init_chipset(struct pci_dev *pdev)
                        /* Clear CD-ROM DMA write bit */
                        tmp &= 0x7F;
                /* Cable and UDMA */
-               pci_write_config_byte(pdev, 0x4B, tmp | 0x09);
+               if (pdev->revision >= 0xc2)
+                       tmp |= 0x01;
+               pci_write_config_byte(pdev, 0x4B, tmp | 0x08);
                /*
                 * CD_ROM DMA on (0x53 bit 0). Enable this even if we want
                 * to use PIO. 0x53 bit 1 (rev 20 only) - enable FIFO control
index f98dffe..dadfc35 100644 (file)
@@ -31,7 +31,7 @@
 #include <linux/libata.h>
 
 #define DRV_NAME "pata_cmd64x"
-#define DRV_VERSION "0.2.5"
+#define DRV_VERSION "0.3.1"
 
 /*
  * CMD64x specific registers definition.
@@ -254,17 +254,109 @@ static void cmd648_bmdma_stop(struct ata_queued_cmd *qc)
 }
 
 /**
- *     cmd646r1_dma_stop       -       DMA stop callback
+ *     cmd64x_bmdma_stop       -       DMA stop callback
  *     @qc: Command in progress
  *
- *     Stub for now while investigating the r1 quirk in the old driver.
+ *     Track the completion of live DMA commands and clear the
+ *     host->private_data DMA tracking flag as we do.
  */
 
-static void cmd646r1_bmdma_stop(struct ata_queued_cmd *qc)
+static void cmd64x_bmdma_stop(struct ata_queued_cmd *qc)
 {
+       struct ata_port *ap = qc->ap;
        ata_bmdma_stop(qc);
+       WARN_ON(ap->host->private_data != ap);
+       ap->host->private_data = NULL;
 }
 
+/**
+ *     cmd64x_qc_defer         -       Defer logic for chip limits
+ *     @qc: queued command
+ *
+ *     Decide whether we can issue the command. Called under the host lock.
+ */
+
+static int cmd64x_qc_defer(struct ata_queued_cmd *qc)
+{
+       struct ata_host *host = qc->ap->host;
+       struct ata_port *alt = host->ports[1 ^ qc->ap->port_no];
+       int rc;
+       int dma = 0;
+
+       /* Apply the ATA rules first */
+       rc = ata_std_qc_defer(qc);
+       if (rc)
+               return rc;
+
+       if (qc->tf.protocol == ATAPI_PROT_DMA ||
+                       qc->tf.protocol == ATA_PROT_DMA)
+               dma = 1;
+
+       /* If the other port is not live then issue the command */
+       if (alt == NULL || !alt->qc_active) {
+               if (dma)
+                       host->private_data = qc->ap;
+               return 0;
+       }
+       /* If there is a live DMA command then wait */
+       if (host->private_data != NULL)
+               return  ATA_DEFER_PORT;
+       if (dma)
+               /* Cannot overlap our DMA command */
+               return ATA_DEFER_PORT;
+       return 0;
+}
+
+/**
+ *     cmd64x_interrupt - ATA host interrupt handler
+ *     @irq: irq line (unused)
+ *     @dev_instance: pointer to our ata_host information structure
+ *
+ *     Our interrupt handler for PCI IDE devices.  Calls
+ *     ata_sff_host_intr() for each port that is flagging an IRQ. We cannot
+ *     use the defaults as we need to avoid touching status/altstatus during
+ *     a DMA.
+ *
+ *     LOCKING:
+ *     Obtains host lock during operation.
+ *
+ *     RETURNS:
+ *     IRQ_NONE or IRQ_HANDLED.
+ */
+irqreturn_t cmd64x_interrupt(int irq, void *dev_instance)
+{
+       struct ata_host *host = dev_instance;
+       struct pci_dev *pdev = to_pci_dev(host->dev);
+       unsigned int i;
+       unsigned int handled = 0;
+       unsigned long flags;
+       static const u8 irq_reg[2] = { CFR, ARTTIM23 };
+       static const u8 irq_mask[2] = { 1 << 2, 1 << 4 };
+
+       /* TODO: make _irqsave conditional on x86 PCI IDE legacy mode */
+       spin_lock_irqsave(&host->lock, flags);
+
+       for (i = 0; i < host->n_ports; i++) {
+               struct ata_port *ap;
+               u8 reg;
+
+               pci_read_config_byte(pdev, irq_reg[i], &reg);
+               ap = host->ports[i];
+               if (ap && (reg & irq_mask[i]) &&
+                   !(ap->flags & ATA_FLAG_DISABLED)) {
+                       struct ata_queued_cmd *qc;
+
+                       qc = ata_qc_from_tag(ap, ap->link.active_tag);
+                       if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING)) &&
+                           (qc->flags & ATA_QCFLAG_ACTIVE))
+                               handled |= ata_sff_host_intr(ap, qc);
+               }
+       }
+
+       spin_unlock_irqrestore(&host->lock, flags);
+
+       return IRQ_RETVAL(handled);
+}
 static struct scsi_host_template cmd64x_sht = {
        ATA_BMDMA_SHT(DRV_NAME),
 };
@@ -273,6 +365,8 @@ static const struct ata_port_operations cmd64x_base_ops = {
        .inherits       = &ata_bmdma_port_ops,
        .set_piomode    = cmd64x_set_piomode,
        .set_dmamode    = cmd64x_set_dmamode,
+       .bmdma_stop     = cmd64x_bmdma_stop,
+       .qc_defer       = cmd64x_qc_defer,
 };
 
 static struct ata_port_operations cmd64x_port_ops = {
@@ -282,7 +376,6 @@ static struct ata_port_operations cmd64x_port_ops = {
 
 static struct ata_port_operations cmd646r1_port_ops = {
        .inherits       = &cmd64x_base_ops,
-       .bmdma_stop     = cmd646r1_bmdma_stop,
        .cable_detect   = ata_cable_40wire,
 };
 
@@ -290,12 +383,11 @@ static struct ata_port_operations cmd648_port_ops = {
        .inherits       = &cmd64x_base_ops,
        .bmdma_stop     = cmd648_bmdma_stop,
        .cable_detect   = cmd648_cable_detect,
+       .qc_defer       = ata_std_qc_defer
 };
 
 static int cmd64x_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
 {
-       u32 class_rev;
-
        static const struct ata_port_info cmd_info[6] = {
                {       /* CMD 643 - no UDMA */
                        .flags = ATA_FLAG_SLAVE_POSS,
@@ -340,40 +432,43 @@ static int cmd64x_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
        const struct ata_port_info *ppi[] = { &cmd_info[id->driver_data], NULL };
        u8 mrdmode;
        int rc;
+       struct ata_host *host;
 
        rc = pcim_enable_device(pdev);
        if (rc)
                return rc;
 
-       pci_read_config_dword(pdev, PCI_CLASS_REVISION, &class_rev);
-       class_rev &= 0xFF;
-
        if (id->driver_data == 0)       /* 643 */
                ata_pci_bmdma_clear_simplex(pdev);
 
        if (pdev->device == PCI_DEVICE_ID_CMD_646) {
                /* Does UDMA work ? */
-               if (class_rev > 4)
+               if (pdev->revision > 4)
                        ppi[0] = &cmd_info[2];
                /* Early rev with other problems ? */
-               else if (class_rev == 1)
+               else if (pdev->revision == 1)
                        ppi[0] = &cmd_info[3];
        }
 
+
        pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 64);
        pci_read_config_byte(pdev, MRDMODE, &mrdmode);
        mrdmode &= ~ 0x30;      /* IRQ set up */
        mrdmode |= 0x02;        /* Memory read line enable */
        pci_write_config_byte(pdev, MRDMODE, mrdmode);
 
-       /* Force PIO 0 here.. */
-
        /* PPC specific fixup copied from old driver */
 #ifdef CONFIG_PPC
        pci_write_config_byte(pdev, UDIDETCR0, 0xF0);
 #endif
+       rc = ata_pci_sff_prepare_host(pdev, ppi, &host);
+       if (rc)
+               return rc;
+       /* We use this pointer to track the AP which has DMA running */
+       host->private_data = NULL;
 
-       return ata_pci_sff_init_one(pdev, ppi, &cmd64x_sht, NULL);
+       pci_set_master(pdev);
+       return ata_pci_sff_activate_host(host, cmd64x_interrupt, &cmd64x_sht);
 }
 
 #ifdef CONFIG_PM
index 0df83cf..95ebdac 100644 (file)
@@ -90,48 +90,12 @@ static void cs5520_set_timings(struct ata_port *ap, struct ata_device *adev, int
 }
 
 /**
- *     cs5520_enable_dma       -       turn on DMA bits
- *
- *     Turn on the DMA bits for this disk. Needed because the BIOS probably
- *     has not done the work for us. Belongs in the core SATA code.
- */
-
-static void cs5520_enable_dma(struct ata_port *ap, struct ata_device *adev)
-{
-       /* Set the DMA enable/disable flag */
-       u8 reg = ioread8(ap->ioaddr.bmdma_addr + 0x02);
-       reg |= 1<<(adev->devno + 5);
-       iowrite8(reg, ap->ioaddr.bmdma_addr + 0x02);
-}
-
-/**
- *     cs5520_set_dmamode      -       program DMA timings
- *     @ap: ATA port
- *     @adev: ATA device
- *
- *     Program the DMA mode timings for the controller according to the pio
- *     clocking table. Note that this device sets the DMA timings to PIO
- *     mode values. This may seem bizarre but the 5520 architecture talks
- *     PIO mode to the disk and DMA mode to the controller so the underlying
- *     transfers are PIO timed.
- */
-
-static void cs5520_set_dmamode(struct ata_port *ap, struct ata_device *adev)
-{
-       static const int dma_xlate[3] = { XFER_PIO_0, XFER_PIO_3, XFER_PIO_4 };
-       cs5520_set_timings(ap, adev, dma_xlate[adev->dma_mode]);
-       cs5520_enable_dma(ap, adev);
-}
-
-/**
  *     cs5520_set_piomode      -       program PIO timings
  *     @ap: ATA port
  *     @adev: ATA device
  *
  *     Program the PIO mode timings for the controller according to the pio
- *     clocking table. We know pio_mode will equal dma_mode because of the
- *     CS5520 architecture. At least once we turned DMA on and wrote a
- *     mode setter.
+ *     clocking table.
  */
 
 static void cs5520_set_piomode(struct ata_port *ap, struct ata_device *adev)
@@ -149,7 +113,6 @@ static struct ata_port_operations cs5520_port_ops = {
        .qc_prep                = ata_sff_dumb_qc_prep,
        .cable_detect           = ata_cable_40wire,
        .set_piomode            = cs5520_set_piomode,
-       .set_dmamode            = cs5520_set_dmamode,
 };
 
 static int __devinit cs5520_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
index 6da4cb4..ffee397 100644 (file)
@@ -224,7 +224,7 @@ static struct scsi_host_template cs5536_sht = {
 };
 
 static struct ata_port_operations cs5536_port_ops = {
-       .inherits               = &ata_bmdma_port_ops,
+       .inherits               = &ata_bmdma32_port_ops,
        .cable_detect           = cs5536_cable_detect,
        .set_piomode            = cs5536_set_piomode,
        .set_dmamode            = cs5536_set_dmamode,
index 2a6412f..b2e71e6 100644 (file)
@@ -2,6 +2,7 @@
  *    pata_efar.c - EFAR PIIX clone controller driver
  *
  *     (C) 2005 Red Hat
+ *     (C) 2009 Bartlomiej Zolnierkiewicz
  *
  *    Some parts based on ata_piix.c by Jeff Garzik and others.
  *
@@ -118,12 +119,12 @@ static void efar_set_piomode (struct ata_port *ap, struct ata_device *adev)
                int shift = 4 * ap->port_no;
                u8 slave_data;
 
-               idetm_data &= 0xCC0F;
+               idetm_data &= 0xFF0F;
                idetm_data |= (control << 4);
 
                /* Slave timing in separate register */
                pci_read_config_byte(dev, 0x44, &slave_data);
-               slave_data &= 0x0F << shift;
+               slave_data &= ap->port_no ? 0x0F : 0xF0;
                slave_data |= ((timings[pio][0] << 2) | timings[pio][1]) << shift;
                pci_write_config_byte(dev, 0x44, slave_data);
        }
@@ -200,7 +201,7 @@ static void efar_set_dmamode (struct ata_port *ap, struct ata_device *adev)
                        master_data &= 0xFF4F;  /* Mask out IORDY|TIME1|DMAONLY */
                        master_data |= control << 4;
                        pci_read_config_byte(dev, 0x44, &slave_data);
-                       slave_data &= (0x0F + 0xE1 * ap->port_no);
+                       slave_data &= ap->port_no ? 0x0F : 0xF0;
                        /* Load the matching timing */
                        slave_data |= ((timings[pio][0] << 2) | timings[pio][1]) << (ap->port_no ? 4 : 0);
                        pci_write_config_byte(dev, 0x44, slave_data);
@@ -251,7 +252,7 @@ static int efar_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
        static const struct ata_port_info info = {
                .flags          = ATA_FLAG_SLAVE_POSS,
                .pio_mask       = ATA_PIO4,
-               .mwdma_mask     = ATA_MWDMA2,
+               .mwdma_mask     = ATA_MWDMA12_ONLY,
                .udma_mask      = ATA_UDMA4,
                .port_ops       = &efar_ops,
        };
index d7f2da1..0bd48e8 100644 (file)
@@ -27,7 +27,7 @@
 #include <linux/libata.h>
 
 #define DRV_NAME       "pata_hpt366"
-#define DRV_VERSION    "0.6.2"
+#define DRV_VERSION    "0.6.7"
 
 struct hpt_clock {
        u8      xfer_mode;
@@ -36,24 +36,22 @@ struct hpt_clock {
 
 /* key for bus clock timings
  * bit
- * 0:3    data_high_time. inactive time of DIOW_/DIOR_ for PIO and MW
- *        DMA. cycles = value + 1
- * 4:8    data_low_time. active time of DIOW_/DIOR_ for PIO and MW
- *        DMA. cycles = value + 1
- * 9:12   cmd_high_time. inactive time of DIOW_/DIOR_ during task file
+ * 0:3    data_high_time. Inactive time of DIOW_/DIOR_ for PIO and MW DMA.
+ *        cycles = value + 1
+ * 4:7    data_low_time. Active time of DIOW_/DIOR_ for PIO and MW DMA.
+ *        cycles = value + 1
+ * 8:11   cmd_high_time. Inactive time of DIOW_/DIOR_ during task file
  *        register access.
- * 13:17  cmd_low_time. active time of DIOW_/DIOR_ during task file
+ * 12:15  cmd_low_time. Active time of DIOW_/DIOR_ during task file
  *        register access.
- * 18:21  udma_cycle_time. clock freq and clock cycles for UDMA xfer.
- *        during task file register access.
- * 22:24  pre_high_time. time to initialize 1st cycle for PIO and MW DMA
- *        xfer.
- * 25:27  cmd_pre_high_time. time to initialize 1st PIO cycle for task
+ * 16:18  udma_cycle_time. Clock cycles for UDMA xfer?
+ * 19:21  pre_high_time. Time to initialize 1st cycle for PIO and MW DMA xfer.
+ * 22:24  cmd_pre_high_time. Time to initialize 1st PIO cycle for task file
  *        register access.
- * 28     UDMA enable
- * 29     DMA enable
- * 30     PIO_MST enable. if set, the chip is in bus master mode during
- *        PIO.
+ * 28     UDMA enable.
+ * 29     DMA  enable.
+ * 30     PIO_MST enable. If set, the chip is in bus master mode during
+ *        PIO xfer.
  * 31     FIFO enable.
  */
 
@@ -344,7 +342,6 @@ static int hpt36x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
        const struct ata_port_info *ppi[] = { &info_hpt366, NULL };
 
        void *hpriv = NULL;
-       u32 class_rev;
        u32 reg1;
        int rc;
 
@@ -352,13 +349,10 @@ static int hpt36x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
        if (rc)
                return rc;
 
-       pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
-       class_rev &= 0xFF;
-
        /* May be a later chip in disguise. Check */
        /* Newer chips are not in the HPT36x driver. Ignore them */
-       if (class_rev > 2)
-                       return -ENODEV;
+       if (dev->revision > 2)
+               return -ENODEV;
 
        hpt36x_init_chipset(dev);
 
index d0a7df2..4224cfc 100644 (file)
@@ -24,7 +24,7 @@
 #include <linux/libata.h>
 
 #define DRV_NAME       "pata_hpt37x"
-#define DRV_VERSION    "0.6.12"
+#define DRV_VERSION    "0.6.14"
 
 struct hpt_clock {
        u8      xfer_speed;
@@ -303,72 +303,79 @@ static unsigned long hpt370a_filter(struct ata_device *adev, unsigned long mask)
 }
 
 /**
- *     hpt37x_pre_reset        -       reset the hpt37x bus
- *     @link: ATA link to reset
- *     @deadline: deadline jiffies for the operation
+ *     hpt37x_cable_detect     -       Detect the cable type
+ *     @ap: ATA port to detect on
  *
- *     Perform the initial reset handling for the 370/372 and 374 func 0
+ *     Return the cable type attached to this port
  */
 
-static int hpt37x_pre_reset(struct ata_link *link, unsigned long deadline)
+static int hpt37x_cable_detect(struct ata_port *ap)
 {
-       u8 scr2, ata66;
-       struct ata_port *ap = link->ap;
        struct pci_dev *pdev = to_pci_dev(ap->host->dev);
-       static const struct pci_bits hpt37x_enable_bits[] = {
-               { 0x50, 1, 0x04, 0x04 },
-               { 0x54, 1, 0x04, 0x04 }
-       };
-       if (!pci_test_config_bits(pdev, &hpt37x_enable_bits[ap->port_no]))
-               return -ENOENT;
+       u8 scr2, ata66;
 
        pci_read_config_byte(pdev, 0x5B, &scr2);
        pci_write_config_byte(pdev, 0x5B, scr2 & ~0x01);
+
+       udelay(10); /* debounce */
+
        /* Cable register now active */
        pci_read_config_byte(pdev, 0x5A, &ata66);
        /* Restore state */
        pci_write_config_byte(pdev, 0x5B, scr2);
 
        if (ata66 & (2 >> ap->port_no))
-               ap->cbl = ATA_CBL_PATA40;
+               return ATA_CBL_PATA40;
        else
-               ap->cbl = ATA_CBL_PATA80;
-
-       /* Reset the state machine */
-       pci_write_config_byte(pdev, 0x50 + 4 * ap->port_no, 0x37);
-       udelay(100);
-
-       return ata_sff_prereset(link, deadline);
+               return ATA_CBL_PATA80;
 }
 
-static int hpt374_fn1_pre_reset(struct ata_link *link, unsigned long deadline)
+/**
+ *     hpt374_fn1_cable_detect -       Detect the cable type
+ *     @ap: ATA port to detect on
+ *
+ *     Return the cable type attached to this port
+ */
+
+static int hpt374_fn1_cable_detect(struct ata_port *ap)
 {
-       static const struct pci_bits hpt37x_enable_bits[] = {
-               { 0x50, 1, 0x04, 0x04 },
-               { 0x54, 1, 0x04, 0x04 }
-       };
-       u16 mcr3;
-       u8 ata66;
-       struct ata_port *ap = link->ap;
        struct pci_dev *pdev = to_pci_dev(ap->host->dev);
        unsigned int mcrbase = 0x50 + 4 * ap->port_no;
-
-       if (!pci_test_config_bits(pdev, &hpt37x_enable_bits[ap->port_no]))
-               return -ENOENT;
+       u16 mcr3;
+       u8 ata66;
 
        /* Do the extra channel work */
        pci_read_config_word(pdev, mcrbase + 2, &mcr3);
-       /* Set bit 15 of 0x52 to enable TCBLID as input
-        */
+       /* Set bit 15 of 0x52 to enable TCBLID as input */
        pci_write_config_word(pdev, mcrbase + 2, mcr3 | 0x8000);
        pci_read_config_byte(pdev, 0x5A, &ata66);
        /* Reset TCBLID/FCBLID to output */
        pci_write_config_word(pdev, mcrbase + 2, mcr3);
 
        if (ata66 & (2 >> ap->port_no))
-               ap->cbl = ATA_CBL_PATA40;
+               return ATA_CBL_PATA40;
        else
-               ap->cbl = ATA_CBL_PATA80;
+               return ATA_CBL_PATA80;
+}
+
+/**
+ *     hpt37x_pre_reset        -       reset the hpt37x bus
+ *     @link: ATA link to reset
+ *     @deadline: deadline jiffies for the operation
+ *
+ *     Perform the initial reset handling for the HPT37x.
+ */
+
+static int hpt37x_pre_reset(struct ata_link *link, unsigned long deadline)
+{
+       struct ata_port *ap = link->ap;
+       struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+       static const struct pci_bits hpt37x_enable_bits[] = {
+               { 0x50, 1, 0x04, 0x04 },
+               { 0x54, 1, 0x04, 0x04 }
+       };
+       if (!pci_test_config_bits(pdev, &hpt37x_enable_bits[ap->port_no]))
+               return -ENOENT;
 
        /* Reset the state machine */
        pci_write_config_byte(pdev, 0x50 + 4 * ap->port_no, 0x37);
@@ -404,9 +411,8 @@ static void hpt370_set_piomode(struct ata_port *ap, struct ata_device *adev)
 
        pci_read_config_dword(pdev, addr1, &reg);
        mode = hpt37x_find_mode(ap, adev->pio_mode);
-       mode &= ~0x8000000;     /* No FIFO in PIO */
-       mode &= ~0x30070000;    /* Leave config bits alone */
-       reg &= 0x30070000;      /* Strip timing bits */
+       mode &= 0xCFC3FFFF;     /* Leave DMA bits alone */
+       reg &= ~0xCFC3FFFF;     /* Strip timing bits */
        pci_write_config_dword(pdev, addr1, reg | mode);
 }
 
@@ -423,8 +429,7 @@ static void hpt370_set_dmamode(struct ata_port *ap, struct ata_device *adev)
 {
        struct pci_dev *pdev = to_pci_dev(ap->host->dev);
        u32 addr1, addr2;
-       u32 reg;
-       u32 mode;
+       u32 reg, mode, mask;
        u8 fast;
 
        addr1 = 0x40 + 4 * (adev->devno + 2 * ap->port_no);
@@ -436,11 +441,12 @@ static void hpt370_set_dmamode(struct ata_port *ap, struct ata_device *adev)
        fast |= 0x01;
        pci_write_config_byte(pdev, addr2, fast);
 
+       mask = adev->dma_mode < XFER_UDMA_0 ? 0x31C001FF : 0x303C0000;
+
        pci_read_config_dword(pdev, addr1, &reg);
        mode = hpt37x_find_mode(ap, adev->dma_mode);
-       mode |= 0x8000000;      /* FIFO in MWDMA or UDMA */
-       mode &= ~0xC0000000;    /* Leave config bits alone */
-       reg &= 0xC0000000;      /* Strip timing bits */
+       mode &= mask;
+       reg &= ~mask;
        pci_write_config_dword(pdev, addr1, reg | mode);
 }
 
@@ -508,9 +514,8 @@ static void hpt372_set_piomode(struct ata_port *ap, struct ata_device *adev)
        mode = hpt37x_find_mode(ap, adev->pio_mode);
 
        printk("Find mode for %d reports %X\n", adev->pio_mode, mode);
-       mode &= ~0x80000000;    /* No FIFO in PIO */
-       mode &= ~0x30070000;    /* Leave config bits alone */
-       reg &= 0x30070000;      /* Strip timing bits */
+       mode &= 0xCFC3FFFF;     /* Leave DMA bits alone */
+       reg &= ~0xCFC3FFFF;     /* Strip timing bits */
        pci_write_config_dword(pdev, addr1, reg | mode);
 }
 
@@ -527,8 +532,7 @@ static void hpt372_set_dmamode(struct ata_port *ap, struct ata_device *adev)
 {
        struct pci_dev *pdev = to_pci_dev(ap->host->dev);
        u32 addr1, addr2;
-       u32 reg;
-       u32 mode;
+       u32 reg, mode, mask;
        u8 fast;
 
        addr1 = 0x40 + 4 * (adev->devno + 2 * ap->port_no);
@@ -539,12 +543,13 @@ static void hpt372_set_dmamode(struct ata_port *ap, struct ata_device *adev)
        fast &= ~0x07;
        pci_write_config_byte(pdev, addr2, fast);
 
+       mask = adev->dma_mode < XFER_UDMA_0 ? 0x31C001FF : 0x303C0000;
+
        pci_read_config_dword(pdev, addr1, &reg);
        mode = hpt37x_find_mode(ap, adev->dma_mode);
        printk("Find mode for DMA %d reports %X\n", adev->dma_mode, mode);
-       mode &= ~0xC0000000;    /* Leave config bits alone */
-       mode |= 0x80000000;     /* FIFO in MWDMA or UDMA */
-       reg &= 0xC0000000;      /* Strip timing bits */
+       mode &= mask;
+       reg &= ~mask;
        pci_write_config_dword(pdev, addr1, reg | mode);
 }
 
@@ -584,6 +589,7 @@ static struct ata_port_operations hpt370_port_ops = {
        .bmdma_stop     = hpt370_bmdma_stop,
 
        .mode_filter    = hpt370_filter,
+       .cable_detect   = hpt37x_cable_detect,
        .set_piomode    = hpt370_set_piomode,
        .set_dmamode    = hpt370_set_dmamode,
        .prereset       = hpt37x_pre_reset,
@@ -608,6 +614,7 @@ static struct ata_port_operations hpt372_port_ops = {
 
        .bmdma_stop     = hpt37x_bmdma_stop,
 
+       .cable_detect   = hpt37x_cable_detect,
        .set_piomode    = hpt372_set_piomode,
        .set_dmamode    = hpt372_set_dmamode,
        .prereset       = hpt37x_pre_reset,
@@ -620,7 +627,8 @@ static struct ata_port_operations hpt372_port_ops = {
 
 static struct ata_port_operations hpt374_fn1_port_ops = {
        .inherits       = &hpt372_port_ops,
-       .prereset       = hpt374_fn1_pre_reset,
+       .cable_detect   = hpt374_fn1_cable_detect,
+       .prereset       = hpt37x_pre_reset,
 };
 
 /**
@@ -791,9 +799,8 @@ static int hpt37x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
        static const int MHz[4] = { 33, 40, 50, 66 };
        void *private_data = NULL;
        const struct ata_port_info *ppi[] = { NULL, NULL };
-
+       u8 rev = dev->revision;
        u8 irqmask;
-       u32 class_rev;
        u8 mcr1;
        u32 freq;
        int prefer_dpll = 1;
@@ -808,19 +815,16 @@ static int hpt37x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
        if (rc)
                return rc;
 
-       pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
-       class_rev &= 0xFF;
-
        if (dev->device == PCI_DEVICE_ID_TTI_HPT366) {
                /* May be a later chip in disguise. Check */
                /* Older chips are in the HPT366 driver. Ignore them */
-               if (class_rev < 3)
+               if (rev < 3)
                        return -ENODEV;
                /* N series chips have their own driver. Ignore */
-               if (class_rev == 6)
+               if (rev == 6)
                        return -ENODEV;
 
-               switch(class_rev) {
+               switch(rev) {
                        case 3:
                                ppi[0] = &info_hpt370;
                                chip_table = &hpt370;
@@ -836,28 +840,29 @@ static int hpt37x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
                                chip_table = &hpt372;
                                break;
                        default:
-                               printk(KERN_ERR "pata_hpt37x: Unknown HPT366 subtype please report (%d).\n", class_rev);
+                               printk(KERN_ERR "pata_hpt37x: Unknown HPT366 "
+                                      "subtype, please report (%d).\n", rev);
                                return -ENODEV;
                }
        } else {
                switch(dev->device) {
                        case PCI_DEVICE_ID_TTI_HPT372:
                                /* 372N if rev >= 2*/
-                               if (class_rev >= 2)
+                               if (rev >= 2)
                                        return -ENODEV;
                                ppi[0] = &info_hpt372;
                                chip_table = &hpt372a;
                                break;
                        case PCI_DEVICE_ID_TTI_HPT302:
                                /* 302N if rev > 1 */
-                               if (class_rev > 1)
+                               if (rev > 1)
                                        return -ENODEV;
                                ppi[0] = &info_hpt372;
                                /* Check this */
                                chip_table = &hpt302;
                                break;
                        case PCI_DEVICE_ID_TTI_HPT371:
-                               if (class_rev > 1)
+                               if (rev > 1)
                                        return -ENODEV;
                                ppi[0] = &info_hpt372;
                                chip_table = &hpt371;
index 3d59fe0..9a09a1b 100644 (file)
@@ -25,7 +25,7 @@
 #include <linux/libata.h>
 
 #define DRV_NAME       "pata_hpt3x2n"
-#define DRV_VERSION    "0.3.4"
+#define DRV_VERSION    "0.3.7"
 
 enum {
        HPT_PCI_FAST    =       (1 << 31),
@@ -80,14 +80,13 @@ static struct hpt_clock hpt3x2n_clocks[] = {
 
        {       XFER_MW_DMA_2,  0x2c829c62      },
        {       XFER_MW_DMA_1,  0x2c829c66      },
-       {       XFER_MW_DMA_0,  0x2c829d2c      },
+       {       XFER_MW_DMA_0,  0x2c829d2e      },
 
        {       XFER_PIO_4,     0x0c829c62      },
        {       XFER_PIO_3,     0x0c829c84      },
        {       XFER_PIO_2,     0x0c829ca6      },
        {       XFER_PIO_1,     0x0d029d26      },
        {       XFER_PIO_0,     0x0d029d5e      },
-       {       0,              0x0d029d5e      }
 };
 
 /**
@@ -128,12 +127,15 @@ static int hpt3x2n_cable_detect(struct ata_port *ap)
 
        pci_read_config_byte(pdev, 0x5B, &scr2);
        pci_write_config_byte(pdev, 0x5B, scr2 & ~0x01);
+
+       udelay(10); /* debounce */
+
        /* Cable register now active */
        pci_read_config_byte(pdev, 0x5A, &ata66);
        /* Restore state */
        pci_write_config_byte(pdev, 0x5B, scr2);
 
-       if (ata66 & (1 << ap->port_no))
+       if (ata66 & (2 >> ap->port_no))
                return ATA_CBL_PATA40;
        else
                return ATA_CBL_PATA80;
@@ -185,9 +187,8 @@ static void hpt3x2n_set_piomode(struct ata_port *ap, struct ata_device *adev)
 
        pci_read_config_dword(pdev, addr1, &reg);
        mode = hpt3x2n_find_mode(ap, adev->pio_mode);
-       mode &= ~0x8000000;     /* No FIFO in PIO */
-       mode &= ~0x30070000;    /* Leave config bits alone */
-       reg &= 0x30070000;      /* Strip timing bits */
+       mode &= 0xCFC3FFFF;     /* Leave DMA bits alone */
+       reg &= ~0xCFC3FFFF;     /* Strip timing bits */
        pci_write_config_dword(pdev, addr1, reg | mode);
 }
 
@@ -204,8 +205,7 @@ static void hpt3x2n_set_dmamode(struct ata_port *ap, struct ata_device *adev)
 {
        struct pci_dev *pdev = to_pci_dev(ap->host->dev);
        u32 addr1, addr2;
-       u32 reg;
-       u32 mode;
+       u32 reg, mode, mask;
        u8 fast;
 
        addr1 = 0x40 + 4 * (adev->devno + 2 * ap->port_no);
@@ -216,11 +216,12 @@ static void hpt3x2n_set_dmamode(struct ata_port *ap, struct ata_device *adev)
        fast &= ~0x07;
        pci_write_config_byte(pdev, addr2, fast);
 
+       mask = adev->dma_mode < XFER_UDMA_0 ? 0x31C001FF : 0x303C0000;
+
        pci_read_config_dword(pdev, addr1, &reg);
        mode = hpt3x2n_find_mode(ap, adev->dma_mode);
-       mode |= 0x8000000;      /* FIFO in MWDMA or UDMA */
-       mode &= ~0xC0000000;    /* Leave config bits alone */
-       reg &= 0xC0000000;      /* Strip timing bits */
+       mode &= mask;
+       reg &= ~mask;
        pci_write_config_dword(pdev, addr1, reg | mode);
 }
 
@@ -447,10 +448,8 @@ static int hpt3x2n_init_one(struct pci_dev *dev, const struct pci_device_id *id)
                .port_ops = &hpt3x2n_port_ops
        };
        const struct ata_port_info *ppi[] = { &info, NULL };
-
+       u8 rev = dev->revision;
        u8 irqmask;
-       u32 class_rev;
-
        unsigned int pci_mhz;
        unsigned int f_low, f_high;
        int adjust;
@@ -462,26 +461,23 @@ static int hpt3x2n_init_one(struct pci_dev *dev, const struct pci_device_id *id)
        if (rc)
                return rc;
 
-       pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
-       class_rev &= 0xFF;
-
        switch(dev->device) {
                case PCI_DEVICE_ID_TTI_HPT366:
-                       if (class_rev < 6)
+                       if (rev < 6)
                                return -ENODEV;
                        break;
                case PCI_DEVICE_ID_TTI_HPT371:
-                       if (class_rev < 2)
+                       if (rev < 2)
                                return -ENODEV;
                        /* 371N if rev > 1 */
                        break;
                case PCI_DEVICE_ID_TTI_HPT372:
                        /* 372N if rev >= 2*/
-                       if (class_rev < 2)
+                       if (rev < 2)
                                return -ENODEV;
                        break;
                case PCI_DEVICE_ID_TTI_HPT302:
-                       if (class_rev < 2)
+                       if (rev < 2)
                                return -ENODEV;
                        break;
                case PCI_DEVICE_ID_TTI_HPT372N:
index 7e31025..c86c716 100644 (file)
@@ -255,8 +255,17 @@ static int hpt3x3_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
 #ifdef CONFIG_PM
 static int hpt3x3_reinit_one(struct pci_dev *dev)
 {
+       struct ata_host *host = dev_get_drvdata(&dev->dev);
+       int rc;
+
+       rc = ata_pci_device_do_resume(dev);
+       if (rc)
+               return rc;
+
        hpt3x3_init_chipset(dev);
-       return ata_pci_device_resume(dev);
+
+       ata_host_resume(host);
+       return 0;
 }
 #endif
 
index f156da8..8f3325a 100644 (file)
@@ -22,7 +22,7 @@
 #define DRV_VERSION    "0.0.3"
 
 /**
- *     it8213_pre_reset        -       check for 40/80 pin
+ *     it8213_pre_reset        -       probe begin
  *     @link: link
  *     @deadline: deadline jiffies for the operation
  *
@@ -92,18 +92,17 @@ static void it8213_set_piomode (struct ata_port *ap, struct ata_device *adev)
                            { 2, 1 },
                            { 2, 3 }, };
 
-       if (pio > 2)
-               control |= 1;   /* TIME1 enable */
+       if (pio > 1)
+               control |= 1;   /* TIME */
        if (ata_pio_need_iordy(adev))   /* PIO 3/4 require IORDY */
-               control |= 2;   /* IORDY enable */
+               control |= 2;   /* IE */
        /* Bit 2 is set for ATAPI on the IT8213 - reverse of ICH/PIIX */
        if (adev->class != ATA_DEV_ATA)
-               control |= 4;
+               control |= 4;   /* PPE */
 
        pci_read_config_word(dev, idetm_port, &idetm_data);
 
-       /* Enable PPE, IE and TIME as appropriate */
-
+       /* Set PPE, IE, and TIME as appropriate */
        if (adev->devno == 0) {
                idetm_data &= 0xCCF0;
                idetm_data |= control;
@@ -112,17 +111,17 @@ static void it8213_set_piomode (struct ata_port *ap, struct ata_device *adev)
        } else {
                u8 slave_data;
 
-               idetm_data &= 0xCC0F;
+               idetm_data &= 0xFF0F;
                idetm_data |= (control << 4);
 
                /* Slave timing in separate register */
                pci_read_config_byte(dev, 0x44, &slave_data);
                slave_data &= 0xF0;
-               slave_data |= ((timings[pio][0] << 2) | timings[pio][1]) << 4;
+               slave_data |= (timings[pio][0] << 2) | timings[pio][1];
                pci_write_config_byte(dev, 0x44, slave_data);
        }
 
-       idetm_data |= 0x4000;   /* Ensure SITRE is enabled */
+       idetm_data |= 0x4000;   /* Ensure SITRE is set */
        pci_write_config_word(dev, idetm_port, idetm_data);
 }
 
@@ -173,10 +172,10 @@ static void it8213_set_dmamode (struct ata_port *ap, struct ata_device *adev)
 
                udma_enable |= (1 << devid);
 
-               /* Load the UDMA mode number */
+               /* Load the UDMA cycle time */
                pci_read_config_word(dev, 0x4A, &udma_timing);
                udma_timing &= ~(3 << (4 * devid));
-               udma_timing |= (udma & 3) << (4 * devid);
+               udma_timing |= u_speed << (4 * devid);
                pci_write_config_word(dev, 0x4A, udma_timing);
 
                /* Load the clock selection */
@@ -211,7 +210,7 @@ static void it8213_set_dmamode (struct ata_port *ap, struct ata_device *adev)
                        master_data &= 0xFF4F;  /* Mask out IORDY|TIME1|DMAONLY */
                        master_data |= control << 4;
                        pci_read_config_byte(dev, 0x44, &slave_data);
-                       slave_data &= (0x0F + 0xE1 * ap->port_no);
+                       slave_data &= 0xF0;
                        /* Load the matching timing */
                        slave_data |= ((timings[pio][0] << 2) | timings[pio][1]) << (ap->port_no ? 4 : 0);
                        pci_write_config_byte(dev, 0x44, slave_data);
@@ -263,7 +262,7 @@ static int it8213_init_one (struct pci_dev *pdev, const struct pci_device_id *en
        static const struct ata_port_info info = {
                .flags          = ATA_FLAG_SLAVE_POSS,
                .pio_mask       = ATA_PIO4,
-               .mwdma_mask     = ATA_MWDMA2,
+               .mwdma_mask     = ATA_MWDMA12_ONLY,
                .udma_mask      = ATA_UDMA4, /* FIXME: want UDMA 100? */
                .port_ops       = &it8213_ops,
        };
index 188bc2f..edc5c1f 100644 (file)
@@ -955,7 +955,7 @@ static int it821x_reinit_one(struct pci_dev *pdev)
 static const struct pci_device_id it821x[] = {
        { PCI_VDEVICE(ITE, PCI_DEVICE_ID_ITE_8211), },
        { PCI_VDEVICE(ITE, PCI_DEVICE_ID_ITE_8212), },
-       { PCI_VDEVICE(RDC, 0x1010), },
+       { PCI_VDEVICE(RDC, PCI_DEVICE_ID_RDC_D1010), },
 
        { },
 };
index 6932e56..9df1ff7 100644 (file)
  *             http://www.ryston.cz/petr/vlb/pdc20230b.html
  *             http://www.ryston.cz/petr/vlb/pdc20230c.html
  *             http://www.ryston.cz/petr/vlb/pdc20630.html
+ *     QDI65x0:
+ *             http://www.ryston.cz/petr/vlb/qd6500.html
+ *             http://www.ryston.cz/petr/vlb/qd6580.html
+ *
+ *     QDI65x0 probe code based on drivers/ide/legacy/qd65xx.c
+ *     Rewritten from the work of Colten Edwards <pje120@cs.usask.ca> by
+ *     Samuel Thibault <samuel.thibault@ens-lyon.org>
  *
  *  Unsupported but docs exist:
  *     Appian/Adaptec AIC25VL01/Cirrus Logic PD7220
@@ -35,7 +42,7 @@
  *  the MPIIX where the tuning is PCI side but the IDE is "ISA side".
  *
  *  Specific support is included for the ht6560a/ht6560b/opti82c611a/
- *  opti82c465mv/promise 20230c/20630/winbond83759A
+ *  opti82c465mv/promise 20230c/20630/qdi65x0/winbond83759A
  *
  *  Use the autospeed and pio_mask options with:
  *     Appian ADI/2 aka CLPD7220 or AIC25VL01.
@@ -672,7 +679,7 @@ static void qdi6580dp_set_piomode(struct ata_port *ap, struct ata_device *adev)
        outb(timing, ld_qdi->timing + 2 * ap->port_no);
        /* Clear the FIFO */
        if (adev->class != ATA_DEV_ATA)
-               outb(0x5F, ld_qdi->timing + 3);
+               outb(0x5F, (ld_qdi->timing & 0xFFF0) + 3);
 }
 
 /**
@@ -707,7 +714,7 @@ static void qdi6580_set_piomode(struct ata_port *ap, struct ata_device *adev)
        outb(timing, ld_qdi->timing + 2 * adev->devno);
        /* Clear the FIFO */
        if (adev->class != ATA_DEV_ATA)
-               outb(0x5F, ld_qdi->timing + 3);
+               outb(0x5F, (ld_qdi->timing & 0xFFF0) + 3);
 }
 
 /**
@@ -787,6 +794,7 @@ static struct ata_port_operations qdi6580_port_ops = {
 static struct ata_port_operations qdi6580dp_port_ops = {
        .inherits       = &legacy_base_port_ops,
        .set_piomode    = qdi6580dp_set_piomode,
+       .qc_issue       = qdi_qc_issue,
        .sff_data_xfer  = vlb32_data_xfer,
 };
 
index 2096fb7..950da39 100644 (file)
@@ -58,7 +58,7 @@ static int marvell_pata_active(struct pci_dev *pdev)
 }
 
 /**
- *     marvell_pre_reset       -       check for 40/80 pin
+ *     marvell_pre_reset       -       probe begin
  *     @link: link
  *     @deadline: deadline jiffies for the operation
  *
index 773b159..061aa1c 100644 (file)
@@ -325,6 +325,13 @@ static struct scsi_host_template ns87415_sht = {
        ATA_BMDMA_SHT(DRV_NAME),
 };
 
+static void ns87415_fixup(struct pci_dev *pdev)
+{
+       /* Select 512 byte sectors */
+       pci_write_config_byte(pdev, 0x55, 0xEE);
+       /* Select PIO0 8bit clocking */
+       pci_write_config_byte(pdev, 0x54, 0xB7);
+}
 
 /**
  *     ns87415_init_one - Register 87415 ATA PCI device with kernel services
@@ -371,10 +378,8 @@ static int ns87415_init_one (struct pci_dev *pdev, const struct pci_device_id *e
        if (rc)
                return rc;
 
-       /* Select 512 byte sectors */
-       pci_write_config_byte(pdev, 0x55, 0xEE);
-       /* Select PIO0 8bit clocking */
-       pci_write_config_byte(pdev, 0x54, 0xB7);
+       ns87415_fixup(pdev);
+
        return ata_pci_sff_init_one(pdev, ppi, &ns87415_sht, NULL);
 }
 
@@ -384,6 +389,23 @@ static const struct pci_device_id ns87415_pci_tbl[] = {
        { }     /* terminate list */
 };
 
+#ifdef CONFIG_PM
+static int ns87415_reinit_one(struct pci_dev *pdev)
+{
+       struct ata_host *host = dev_get_drvdata(&pdev->dev);
+       int rc;
+
+       rc = ata_pci_device_do_resume(pdev);
+       if (rc)
+               return rc;
+
+       ns87415_fixup(pdev);
+
+       ata_host_resume(host);
+       return 0;
+}
+#endif
+
 static struct pci_driver ns87415_pci_driver = {
        .name                   = DRV_NAME,
        .id_table               = ns87415_pci_tbl,
@@ -391,7 +413,7 @@ static struct pci_driver ns87415_pci_driver = {
        .remove                 = ata_pci_remove_one,
 #ifdef CONFIG_PM
        .suspend                = ata_pci_device_suspend,
-       .resume                 = ata_pci_device_resume,
+       .resume                 = ns87415_reinit_one,
 #endif
 };
 
index 84ac503..9a8687d 100644 (file)
@@ -239,7 +239,7 @@ static int oldpiix_init_one (struct pci_dev *pdev, const struct pci_device_id *e
        static const struct ata_port_info info = {
                .flags          = ATA_FLAG_SLAVE_POSS,
                .pio_mask       = ATA_PIO4,
-               .mwdma_mask     = ATA_MWDMA2,
+               .mwdma_mask     = ATA_MWDMA12_ONLY,
                .port_ops       = &oldpiix_pata_ops,
        };
        const struct ata_port_info *ppi[] = { &info, NULL };
diff --git a/drivers/ata/pata_piccolo.c b/drivers/ata/pata_piccolo.c
new file mode 100644 (file)
index 0000000..bfe0180
--- /dev/null
@@ -0,0 +1,140 @@
+/*
+ *  pata_piccolo.c - Toshiba Piccolo PATA/SATA controller driver.
+ *
+ *  This is basically an update to ata_generic.c to add Toshiba Piccolo support
+ *  then split out to keep ata_generic "clean".
+ *
+ *  Copyright 2005 Red Hat Inc, all rights reserved.
+ *
+ *  Elements from ide/pci/generic.c
+ *         Copyright (C) 2001-2002     Andre Hedrick <andre@linux-ide.org>
+ *         Portions (C) Copyright 2002  Red Hat Inc <alan@redhat.com>
+ *
+ *  May be copied or modified under the terms of the GNU General Public License
+ *
+ *  The timing data tables/programming info are courtesy of the NetBSD driver
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <scsi/scsi_host.h>
+#include <linux/libata.h>
+
+#define DRV_NAME "pata_piccolo"
+#define DRV_VERSION "0.0.1"
+
+
+
+static void tosh_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+       static const u16 pio[6] = {     /* For reg 0x50 low word & E088 */
+               0x0566, 0x0433, 0x0311, 0x0201, 0x0200, 0x0100
+       };
+       struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+       u16 conf;
+       pci_read_config_word(pdev, 0x50, &conf);
+       conf &= 0xE088;
+       conf |= pio[adev->pio_mode - XFER_PIO_0];
+       pci_write_config_word(pdev, 0x50, conf);
+}
+
+static void tosh_set_dmamode(struct ata_port *ap, struct ata_device *adev)
+{
+       struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+       u32 conf;
+       pci_read_config_dword(pdev, 0x5C, &conf);
+       conf &= 0x78FFE088;     /* Keep the other bits */
+       if (adev->dma_mode >= XFER_UDMA_0) {
+               int udma = adev->dma_mode - XFER_UDMA_0;
+               conf |= 0x80000000;
+               conf |= (udma + 2) << 28;
+               conf |= (2 - udma) * 0x111;     /* spread into three nibbles */
+       } else {
+               static const u32 mwdma[4] = {
+                       0x0655, 0x0200, 0x0200, 0x0100
+               };
+               conf |= mwdma[adev->dma_mode - XFER_MW_DMA_0];
+       }
+       pci_write_config_dword(pdev, 0x5C, conf);
+}
+
+
+static struct scsi_host_template tosh_sht = {
+       ATA_BMDMA_SHT(DRV_NAME),
+};
+
+static struct ata_port_operations tosh_port_ops = {
+       .inherits       = &ata_bmdma_port_ops,
+       .cable_detect   = ata_cable_unknown,
+       .set_piomode    = tosh_set_piomode,
+       .set_dmamode    = tosh_set_dmamode
+};
+
+/**
+ *     ata_tosh_init           -       attach generic IDE
+ *     @dev: PCI device found
+ *     @id: match entry
+ *
+ *     Called each time a matching IDE interface is found. We check if the
+ *     interface is one we wish to claim and if so we perform any chip
+ *     specific hacks then let the ATA layer do the heavy lifting.
+ */
+
+static int ata_tosh_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+       static const struct ata_port_info info = {
+               .flags = ATA_FLAG_SLAVE_POSS,
+               .pio_mask = ATA_PIO5,
+               .mwdma_mask = ATA_MWDMA2,
+               .udma_mask = ATA_UDMA2,
+               .port_ops = &tosh_port_ops
+       };
+       const struct ata_port_info *ppi[] = { &info, &ata_dummy_port_info };
+       /* Just one port for the moment */
+       return ata_pci_sff_init_one(dev, ppi, &tosh_sht, NULL);
+}
+
+static struct pci_device_id ata_tosh[] = {
+       { PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO_1), },
+       { PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO_2),  },
+       { PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO_3),  },
+       { PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO_5),  },
+       { 0, },
+};
+
+static struct pci_driver ata_tosh_pci_driver = {
+       .name           = DRV_NAME,
+       .id_table       = ata_tosh,
+       .probe          = ata_tosh_init_one,
+       .remove         = ata_pci_remove_one,
+#ifdef CONFIG_PM
+       .suspend        = ata_pci_device_suspend,
+       .resume         = ata_pci_device_resume,
+#endif
+};
+
+static int __init ata_tosh_init(void)
+{
+       return pci_register_driver(&ata_tosh_pci_driver);
+}
+
+
+static void __exit ata_tosh_exit(void)
+{
+       pci_unregister_driver(&ata_tosh_pci_driver);
+}
+
+
+MODULE_AUTHOR("Alan Cox");
+MODULE_DESCRIPTION("Low level driver for Toshiba Piccolo ATA");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, ata_tosh);
+MODULE_VERSION(DRV_VERSION);
+
+module_init(ata_tosh_init);
+module_exit(ata_tosh_exit);
+
index 4401b33..4fd25e7 100644 (file)
@@ -139,9 +139,9 @@ static void radisys_set_dmamode (struct ata_port *ap, struct ata_device *adev)
                pci_read_config_byte(dev, 0x4A, &udma_mode);
 
                if (adev->xfer_mode == XFER_UDMA_2)
-                       udma_mode &= ~ (1 << adev->devno);
+                       udma_mode &= ~(2 << (adev->devno * 4));
                else /* UDMA 4 */
-                       udma_mode |= (1 << adev->devno);
+                       udma_mode |= (2 << (adev->devno * 4));
 
                pci_write_config_byte(dev, 0x4A, udma_mode);
 
index c843a1e..237a24d 100644 (file)
@@ -284,7 +284,7 @@ static struct ata_port_info rdc_port_info = {
 
        .flags          = ATA_FLAG_SLAVE_POSS,
        .pio_mask       = ATA_PIO4,
-       .mwdma_mask     = ATA_MWDMA2,
+       .mwdma_mask     = ATA_MWDMA12_ONLY,
        .udma_mask      = ATA_UDMA5,
        .port_ops       = &rdc_pata_ops,
 };
index a5e4dfe..2932998 100644 (file)
@@ -105,11 +105,20 @@ static int rz1000_init_one (struct pci_dev *pdev, const struct pci_device_id *en
 #ifdef CONFIG_PM
 static int rz1000_reinit_one(struct pci_dev *pdev)
 {
+       struct ata_host *host = dev_get_drvdata(&pdev->dev);
+       int rc;
+
+       rc = ata_pci_device_do_resume(pdev);
+       if (rc)
+               return rc;
+
        /* If this fails on resume (which is a "cant happen" case), we
           must stop as any progress risks data loss */
        if (rz1000_fifo_disable(pdev))
                panic("rz1000 fifo");
-       return ata_pci_device_resume(pdev);
+
+       ata_host_resume(host);
+       return 0;
 }
 #endif
 
index 4cb649d..a2ace48 100644 (file)
@@ -212,13 +212,11 @@ static struct ata_port_operations sil680_port_ops = {
 
 static u8 sil680_init_chip(struct pci_dev *pdev, int *try_mmio)
 {
-       u32 class_rev   = 0;
        u8 tmpbyte      = 0;
 
-        pci_read_config_dword(pdev, PCI_CLASS_REVISION, &class_rev);
-        class_rev &= 0xff;
         /* FIXME: double check */
-       pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, (class_rev) ? 1 : 255);
+       pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE,
+                             pdev->revision ? 1 : 255);
 
        pci_write_config_byte(pdev, 0x80, 0x00);
        pci_write_config_byte(pdev, 0x84, 0x00);
index 488e77b..5c30d56 100644 (file)
@@ -2,7 +2,7 @@
  *    pata_sis.c - SiS ATA driver
  *
  *     (C) 2005 Red Hat
- *     (C) 2007 Bartlomiej Zolnierkiewicz
+ *     (C) 2007,2009 Bartlomiej Zolnierkiewicz
  *
  *    Based upon linux/drivers/ide/pci/sis5513.c
  * Copyright (C) 1999-2000     Andre Hedrick <andre@linux-ide.org>
@@ -829,6 +829,23 @@ static int sis_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
        return ata_pci_sff_init_one(pdev, ppi, &sis_sht, chipset);
 }
 
+#ifdef CONFIG_PM
+static int sis_reinit_one(struct pci_dev *pdev)
+{
+       struct ata_host *host = dev_get_drvdata(&pdev->dev);
+       int rc;
+
+       rc = ata_pci_device_do_resume(pdev);
+       if (rc)
+               return rc;
+
+       sis_fixup(pdev, host->private_data);
+
+       ata_host_resume(host);
+       return 0;
+}
+#endif
+
 static const struct pci_device_id sis_pci_tbl[] = {
        { PCI_VDEVICE(SI, 0x5513), },   /* SiS 5513 */
        { PCI_VDEVICE(SI, 0x5518), },   /* SiS 5518 */
@@ -844,7 +861,7 @@ static struct pci_driver sis_pci_driver = {
        .remove                 = ata_pci_remove_one,
 #ifdef CONFIG_PM
        .suspend                = ata_pci_device_suspend,
-       .resume                 = ata_pci_device_resume,
+       .resume                 = sis_reinit_one,
 #endif
 };
 
index 88984b8..0d97890 100644 (file)
@@ -303,14 +303,21 @@ static void via_do_set_mode(struct ata_port *ap, struct ata_device *adev, int mo
        }
 
        /* Set UDMA unless device is not UDMA capable */
-       if (udma_type && t.udma) {
-               u8 cable80_status;
+       if (udma_type) {
+               u8 udma_etc;
 
-               /* Get 80-wire cable detection bit */
-               pci_read_config_byte(pdev, 0x50 + offset, &cable80_status);
-               cable80_status &= 0x10;
+               pci_read_config_byte(pdev, 0x50 + offset, &udma_etc);
 
-               pci_write_config_byte(pdev, 0x50 + offset, ut | cable80_status);
+               /* clear transfer mode bit */
+               udma_etc &= ~0x20;
+
+               if (t.udma) {
+                       /* preserve 80-wire cable detection bit */
+                       udma_etc &= 0x10;
+                       udma_etc |= ut;
+               }
+
+               pci_write_config_byte(pdev, 0x50 + offset, udma_etc);
        }
 }
 
@@ -337,6 +344,32 @@ static void via_set_dmamode(struct ata_port *ap, struct ata_device *adev)
 }
 
 /**
+ *     via_mode_filter         -       filter buggy device/mode pairs
+ *     @dev: ATA device
+ *     @mask: Mode bitmask
+ *
+ *     We need to apply some minimal filtering for old controllers and at least
+ *     one breed of Transcend SSD. Return the updated mask.
+ */
+
+static unsigned long via_mode_filter(struct ata_device *dev, unsigned long mask)
+{
+       struct ata_host *host = dev->link->ap->host;
+       const struct via_isa_bridge *config = host->private_data;
+       unsigned char model_num[ATA_ID_PROD_LEN + 1];
+
+       if (config->id == PCI_DEVICE_ID_VIA_82C586_0) {
+               ata_id_c_string(dev->id, model_num, ATA_ID_PROD, sizeof(model_num));
+               if (strcmp(model_num, "TS64GSSD25-M") == 0) {
+                       ata_dev_printk(dev, KERN_WARNING,
+       "disabling UDMA mode due to reported lockups with this device.\n");
+                       mask &= ~ ATA_MASK_UDMA;
+               }
+       }
+       return ata_bmdma_mode_filter(dev, mask);
+}
+
+/**
  *     via_tf_load - send taskfile registers to host controller
  *     @ap: Port to which output is sent
  *     @tf: ATA taskfile register set
@@ -427,6 +460,7 @@ static struct ata_port_operations via_port_ops = {
        .prereset       = via_pre_reset,
        .sff_tf_load    = via_tf_load,
        .port_start     = via_port_start,
+       .mode_filter    = via_mode_filter,
 };
 
 static struct ata_port_operations via_port_ops_noirq = {
@@ -526,7 +560,7 @@ static int via_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
                .port_ops = &via_port_ops
        };
        const struct ata_port_info *ppi[] = { NULL, NULL };
-       struct pci_dev *isa = NULL;
+       struct pci_dev *isa;
        const struct via_isa_bridge *config;
        static int printed_version;
        u8 enable;
@@ -551,15 +585,13 @@ static int via_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
                if ((isa = pci_get_device(PCI_VENDOR_ID_VIA +
                        !!(config->flags & VIA_BAD_ID),
                        config->id, NULL))) {
+                       u8 rev = isa->revision;
+                       pci_dev_put(isa);
 
-                       if (isa->revision >= config->rev_min &&
-                           isa->revision <= config->rev_max)
+                       if (rev >= config->rev_min && rev <= config->rev_max)
                                break;
-                       pci_dev_put(isa);
                }
 
-       pci_dev_put(isa);
-
        if (!(config->flags & VIA_NO_ENABLES)) {
                /* 0x40 low bits indicate enabled channels */
                pci_read_config_byte(pdev, 0x40 , &enable);
index 172b57e..8a5d35b 100644 (file)
@@ -34,7 +34,7 @@ enum {
 
        SATA_FSL_HOST_FLAGS     = (ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
                                ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA |
-                               ATA_FLAG_PMP | ATA_FLAG_NCQ),
+                               ATA_FLAG_PMP | ATA_FLAG_NCQ | ATA_FLAG_AN),
 
        SATA_FSL_MAX_CMDS       = SATA_FSL_QUEUE_DEPTH,
        SATA_FSL_CMD_HDR_SIZE   = 16,   /* 4 DWORDS */
@@ -132,7 +132,7 @@ enum {
        INT_ON_SINGL_DEVICE_ERR = (1 << 1),
        INT_ON_CMD_COMPLETE = 1,
 
-       INT_ON_ERROR = INT_ON_FATAL_ERR |
+       INT_ON_ERROR = INT_ON_FATAL_ERR | INT_ON_SNOTIFY_UPDATE |
            INT_ON_PHYRDY_CHG | INT_ON_SINGL_DEVICE_ERR,
 
        /*
@@ -153,7 +153,7 @@ enum {
        IE_ON_CMD_COMPLETE = 1,
 
        DEFAULT_PORT_IRQ_ENABLE_MASK = IE_ON_FATAL_ERR | IE_ON_PHYRDY_CHG |
-           IE_ON_SIGNATURE_UPDATE |
+           IE_ON_SIGNATURE_UPDATE | IE_ON_SNOTIFY_UPDATE |
            IE_ON_SINGL_DEVICE_ERR | IE_ON_CMD_COMPLETE,
 
        EXT_INDIRECT_SEG_PRD_FLAG = (1 << 31),
@@ -992,9 +992,8 @@ static void sata_fsl_error_intr(struct ata_port *ap)
         */
 
        sata_fsl_scr_read(&ap->link, SCR_ERROR, &SError);
-       if (unlikely(SError & 0xFFFF0000)) {
+       if (unlikely(SError & 0xFFFF0000))
                sata_fsl_scr_write(&ap->link, SCR_ERROR, SError);
-       }
 
        DPRINTK("error_intr,hStat=0x%x,CE=0x%x,DE =0x%x,SErr=0x%x\n",
                hstatus, cereg, ioread32(hcr_base + DE), SError);
@@ -1007,6 +1006,10 @@ static void sata_fsl_error_intr(struct ata_port *ap)
                freeze = 1;
        }
 
+       /* Handle SDB FIS receive & notify update */
+       if (hstatus & INT_ON_SNOTIFY_UPDATE)
+               sata_async_notification(ap);
+
        /* Handle PHYRDY change notification */
        if (hstatus & INT_ON_PHYRDY_CHG) {
                DPRINTK("SATA FSL: PHYRDY change indication\n");
@@ -1070,9 +1073,9 @@ static void sata_fsl_error_intr(struct ata_port *ap)
        }
 
        /* record error info */
-       if (qc) {
+       if (qc)
                qc->err_mask |= err_mask;
-       else
+       else
                ehi->err_mask |= err_mask;
 
        ehi->action |= action;
@@ -1103,7 +1106,6 @@ static void sata_fsl_host_intr(struct ata_port *ap)
        if (unlikely(SError & 0xFFFF0000)) {
                DPRINTK("serror @host_intr : 0x%x\n", SError);
                sata_fsl_error_intr(ap);
-
        }
 
        if (unlikely(hstatus & INT_ON_ERROR)) {
index 6f5093b..a8a7be0 100644 (file)
@@ -2217,7 +2217,7 @@ static unsigned int mv_qc_issue_fis(struct ata_queued_cmd *qc)
        int err = 0;
 
        ata_tf_to_fis(&qc->tf, link->pmp, 1, (void *)fis);
-       err = mv_send_fis(ap, fis, sizeof(fis) / sizeof(fis[0]));
+       err = mv_send_fis(ap, fis, ARRAY_SIZE(fis));
        if (err)
                return err;
 
index e6946fc..1370df6 100644 (file)
@@ -417,6 +417,10 @@ static struct ata_port_operations sil24_ops = {
 #endif
 };
 
+static int sata_sil24_msi;    /* Disable MSI */
+module_param_named(msi, sata_sil24_msi, bool, S_IRUGO);
+MODULE_PARM_DESC(msi, "Enable MSI (Default: false)");
+
 /*
  * Use bits 30-31 of port_flags to encode available port numbers.
  * Current maxium is 4.
@@ -1340,6 +1344,11 @@ static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 
        sil24_init_controller(host);
 
+       if (sata_sil24_msi && !pci_enable_msi(pdev)) {
+               dev_printk(KERN_INFO, &pdev->dev, "Using MSI\n");
+               pci_intx(pdev, 0);
+       }
+
        pci_set_master(pdev);
        return ata_host_activate(host, pdev->irq, sil24_interrupt, IRQF_SHARED,
                                 &sil24_sht);
index 846d89e..5a01ece 100644 (file)
@@ -185,6 +185,7 @@ int __pm_runtime_suspend(struct device *dev, bool from_wq)
        }
 
        dev->power.runtime_status = RPM_SUSPENDING;
+       dev->power.deferred_resume = false;
 
        if (dev->bus && dev->bus->pm && dev->bus->pm->runtime_suspend) {
                spin_unlock_irq(&dev->power.lock);
@@ -200,7 +201,6 @@ int __pm_runtime_suspend(struct device *dev, bool from_wq)
        if (retval) {
                dev->power.runtime_status = RPM_ACTIVE;
                pm_runtime_cancel_pending(dev);
-               dev->power.deferred_resume = false;
 
                if (retval == -EAGAIN || retval == -EBUSY) {
                        notify = true;
@@ -217,7 +217,6 @@ int __pm_runtime_suspend(struct device *dev, bool from_wq)
        wake_up_all(&dev->power.wait_queue);
 
        if (dev->power.deferred_resume) {
-               dev->power.deferred_resume = false;
                __pm_runtime_resume(dev, false);
                retval = -EAGAIN;
                goto out;
@@ -626,6 +625,8 @@ int pm_schedule_suspend(struct device *dev, unsigned int delay)
                goto out;
 
        dev->power.timer_expires = jiffies + msecs_to_jiffies(delay);
+       if (!dev->power.timer_expires)
+               dev->power.timer_expires = 1;
        mod_timer(&dev->power.suspend_timer, dev->power.timer_expires);
 
  out:
@@ -659,13 +660,17 @@ static int __pm_request_resume(struct device *dev)
 
        pm_runtime_deactivate_timer(dev);
 
+       if (dev->power.runtime_status == RPM_SUSPENDING) {
+               dev->power.deferred_resume = true;
+               return retval;
+       }
        if (dev->power.request_pending) {
                /* If non-resume request is pending, we can overtake it. */
                dev->power.request = retval ? RPM_REQ_NONE : RPM_REQ_RESUME;
                return retval;
-       } else if (retval) {
-               return retval;
        }
+       if (retval)
+               return retval;
 
        dev->power.request = RPM_REQ_RESUME;
        dev->power.request_pending = true;
@@ -777,7 +782,7 @@ int __pm_runtime_set_status(struct device *dev, unsigned int status)
        }
 
        if (parent) {
-               spin_lock(&parent->power.lock);
+               spin_lock_nested(&parent->power.lock, SINGLE_DEPTH_NESTING);
 
                /*
                 * It is invalid to put an active child under a parent that is
@@ -786,12 +791,10 @@ int __pm_runtime_set_status(struct device *dev, unsigned int status)
                 */
                if (!parent->power.disable_depth
                    && !parent->power.ignore_children
-                   && parent->power.runtime_status != RPM_ACTIVE) {
+                   && parent->power.runtime_status != RPM_ACTIVE)
                        error = -EBUSY;
-               } else {
-                       if (dev->power.runtime_status == RPM_SUSPENDED)
-                               atomic_inc(&parent->power.child_count);
-               }
+               else if (dev->power.runtime_status == RPM_SUSPENDED)
+                       atomic_inc(&parent->power.child_count);
 
                spin_unlock(&parent->power.lock);
 
index 1d886e0..77bfce5 100644 (file)
@@ -271,6 +271,8 @@ config BLK_DEV_CRYPTOLOOP
          instead, which can be configured to be on-disk compatible with the
          cryptoloop device.
 
+source "drivers/block/drbd/Kconfig"
+
 config BLK_DEV_NBD
        tristate "Network block device support"
        depends on NET
index cdaa3f8..aff5ac9 100644 (file)
@@ -36,5 +36,6 @@ obj-$(CONFIG_BLK_DEV_UB)      += ub.o
 obj-$(CONFIG_BLK_DEV_HD)       += hd.o
 
 obj-$(CONFIG_XEN_BLKDEV_FRONTEND)      += xen-blkfront.o
+obj-$(CONFIG_BLK_DEV_DRBD)     += drbd/
 
 swim_mod-objs  := swim.o swim_asm.o
index 92b1263..873e594 100644 (file)
@@ -179,19 +179,17 @@ static int rebuild_lun_table(ctlr_info_t *h, int first_time, int via_ioctl);
 static int deregister_disk(ctlr_info_t *h, int drv_index,
                           int clear_all, int via_ioctl);
 
-static void cciss_read_capacity(int ctlr, int logvol, int withirq,
+static void cciss_read_capacity(int ctlr, int logvol,
                        sector_t *total_size, unsigned int *block_size);
-static void cciss_read_capacity_16(int ctlr, int logvol, int withirq,
+static void cciss_read_capacity_16(int ctlr, int logvol,
                        sector_t *total_size, unsigned int *block_size);
 static void cciss_geometry_inquiry(int ctlr, int logvol,
-                       int withirq, sector_t total_size,
+                       sector_t total_size,
                        unsigned int block_size, InquiryData_struct *inq_buff,
                                   drive_info_struct *drv);
 static void __devinit cciss_interrupt_mode(ctlr_info_t *, struct pci_dev *,
                                           __u32);
 static void start_io(ctlr_info_t *h);
-static int sendcmd(__u8 cmd, int ctlr, void *buff, size_t size,
-                  __u8 page_code, unsigned char *scsi3addr, int cmd_type);
 static int sendcmd_withirq(__u8 cmd, int ctlr, void *buff, size_t size,
                        __u8 page_code, unsigned char scsi3addr[],
                        int cmd_type);
@@ -424,12 +422,9 @@ cciss_proc_write(struct file *file, const char __user *buf,
        if (strncmp(ENGAGE_SCSI, buffer, sizeof ENGAGE_SCSI - 1) == 0) {
                struct seq_file *seq = file->private_data;
                ctlr_info_t *h = seq->private;
-               int rc;
 
-               rc = cciss_engage_scsi(h->ctlr);
-               if (rc != 0)
-                       err = -rc;
-               else
+               err = cciss_engage_scsi(h->ctlr);
+               if (err == 0)
                        err = length;
        } else
 #endif /* CONFIG_CISS_SCSI_TAPE */
@@ -1657,9 +1652,11 @@ static void cciss_softirq_done(struct request *rq)
 {
        CommandList_struct *cmd = rq->completion_data;
        ctlr_info_t *h = hba[cmd->ctlr];
+       SGDescriptor_struct *curr_sg = cmd->SG;
        unsigned long flags;
        u64bit temp64;
        int i, ddir;
+       int sg_index = 0;
 
        if (cmd->Request.Type.Direction == XFER_READ)
                ddir = PCI_DMA_FROMDEVICE;
@@ -1669,9 +1666,22 @@ static void cciss_softirq_done(struct request *rq)
        /* command did not need to be retried */
        /* unmap the DMA mapping for all the scatter gather elements */
        for (i = 0; i < cmd->Header.SGList; i++) {
-               temp64.val32.lower = cmd->SG[i].Addr.lower;
-               temp64.val32.upper = cmd->SG[i].Addr.upper;
-               pci_unmap_page(h->pdev, temp64.val, cmd->SG[i].Len, ddir);
+               if (curr_sg[sg_index].Ext == CCISS_SG_CHAIN) {
+                       temp64.val32.lower = cmd->SG[i].Addr.lower;
+                       temp64.val32.upper = cmd->SG[i].Addr.upper;
+                       pci_dma_sync_single_for_cpu(h->pdev, temp64.val,
+                                               cmd->SG[i].Len, ddir);
+                       pci_unmap_single(h->pdev, temp64.val,
+                                               cmd->SG[i].Len, ddir);
+                       /* Point to the next block */
+                       curr_sg = h->cmd_sg_list[cmd->cmdindex]->sgchain;
+                       sg_index = 0;
+               }
+               temp64.val32.lower = curr_sg[sg_index].Addr.lower;
+               temp64.val32.upper = curr_sg[sg_index].Addr.upper;
+               pci_unmap_page(h->pdev, temp64.val, curr_sg[sg_index].Len,
+                               ddir);
+               ++sg_index;
        }
 
 #ifdef CCISS_DEBUG
@@ -1701,7 +1711,7 @@ static inline void log_unit_to_scsi3addr(ctlr_info_t *h,
  * via the inquiry page 0.  Model, vendor, and rev are set to empty strings if
  * they cannot be read.
  */
-static void cciss_get_device_descr(int ctlr, int logvol, int withirq,
+static void cciss_get_device_descr(int ctlr, int logvol,
                                   char *vendor, char *model, char *rev)
 {
        int rc;
@@ -1717,14 +1727,8 @@ static void cciss_get_device_descr(int ctlr, int logvol, int withirq,
                return;
 
        log_unit_to_scsi3addr(hba[ctlr], scsi3addr, logvol);
-       if (withirq)
-               rc = sendcmd_withirq(CISS_INQUIRY, ctlr, inq_buf,
-                            sizeof(InquiryData_struct), 0,
-                               scsi3addr, TYPE_CMD);
-       else
-               rc = sendcmd(CISS_INQUIRY, ctlr, inq_buf,
-                            sizeof(InquiryData_struct), 0,
-                               scsi3addr, TYPE_CMD);
+       rc = sendcmd_withirq(CISS_INQUIRY, ctlr, inq_buf, sizeof(*inq_buf), 0,
+                       scsi3addr, TYPE_CMD);
        if (rc == IO_OK) {
                memcpy(vendor, &inq_buf->data_byte[8], VENDOR_LEN);
                vendor[VENDOR_LEN] = '\0';
@@ -1743,7 +1747,7 @@ static void cciss_get_device_descr(int ctlr, int logvol, int withirq,
  * number cannot be had, for whatever reason, 16 bytes of 0xff
  * are returned instead.
  */
-static void cciss_get_serial_no(int ctlr, int logvol, int withirq,
+static void cciss_get_serial_no(int ctlr, int logvol,
                                unsigned char *serial_no, int buflen)
 {
 #define PAGE_83_INQ_BYTES 64
@@ -1759,12 +1763,8 @@ static void cciss_get_serial_no(int ctlr, int logvol, int withirq,
                return;
        memset(serial_no, 0, buflen);
        log_unit_to_scsi3addr(hba[ctlr], scsi3addr, logvol);
-       if (withirq)
-               rc = sendcmd_withirq(CISS_INQUIRY, ctlr, buf,
-                       PAGE_83_INQ_BYTES, 0x83, scsi3addr, TYPE_CMD);
-       else
-               rc = sendcmd(CISS_INQUIRY, ctlr, buf,
-                       PAGE_83_INQ_BYTES, 0x83, scsi3addr, TYPE_CMD);
+       rc = sendcmd_withirq(CISS_INQUIRY, ctlr, buf,
+               PAGE_83_INQ_BYTES, 0x83, scsi3addr, TYPE_CMD);
        if (rc == IO_OK)
                memcpy(serial_no, &buf[8], buflen);
        kfree(buf);
@@ -1793,10 +1793,10 @@ static int cciss_add_disk(ctlr_info_t *h, struct gendisk *disk,
        blk_queue_bounce_limit(disk->queue, h->pdev->dma_mask);
 
        /* This is a hardware imposed limit. */
-       blk_queue_max_hw_segments(disk->queue, MAXSGENTRIES);
+       blk_queue_max_hw_segments(disk->queue, h->maxsgentries);
 
        /* This is a limit in the driver and could be eliminated. */
-       blk_queue_max_phys_segments(disk->queue, MAXSGENTRIES);
+       blk_queue_max_phys_segments(disk->queue, h->maxsgentries);
 
        blk_queue_max_sectors(disk->queue, h->cciss_max_sectors);
 
@@ -1852,18 +1852,16 @@ static void cciss_update_drive_info(int ctlr, int drv_index, int first_time,
 
        /* testing to see if 16-byte CDBs are already being used */
        if (h->cciss_read == CCISS_READ_16) {
-               cciss_read_capacity_16(h->ctlr, drv_index, 1,
+               cciss_read_capacity_16(h->ctlr, drv_index,
                        &total_size, &block_size);
 
        } else {
-               cciss_read_capacity(ctlr, drv_index, 1,
-                                   &total_size, &block_size);
-
+               cciss_read_capacity(ctlr, drv_index, &total_size, &block_size);
                /* if read_capacity returns all F's this volume is >2TB */
                /* in size so we switch to 16-byte CDB's for all */
                /* read/write ops */
                if (total_size == 0xFFFFFFFFULL) {
-                       cciss_read_capacity_16(ctlr, drv_index, 1,
+                       cciss_read_capacity_16(ctlr, drv_index,
                        &total_size, &block_size);
                        h->cciss_read = CCISS_READ_16;
                        h->cciss_write = CCISS_WRITE_16;
@@ -1873,14 +1871,14 @@ static void cciss_update_drive_info(int ctlr, int drv_index, int first_time,
                }
        }
 
-       cciss_geometry_inquiry(ctlr, drv_index, 1, total_size, block_size,
+       cciss_geometry_inquiry(ctlr, drv_index, total_size, block_size,
                               inq_buff, drvinfo);
        drvinfo->block_size = block_size;
        drvinfo->nr_blocks = total_size + 1;
 
-       cciss_get_device_descr(ctlr, drv_index, 1, drvinfo->vendor,
+       cciss_get_device_descr(ctlr, drv_index, drvinfo->vendor,
                                drvinfo->model, drvinfo->rev);
-       cciss_get_serial_no(ctlr, drv_index, 1, drvinfo->serial_no,
+       cciss_get_serial_no(ctlr, drv_index, drvinfo->serial_no,
                        sizeof(drvinfo->serial_no));
        /* Save the lunid in case we deregister the disk, below. */
        memcpy(drvinfo->LunID, h->drv[drv_index]->LunID,
@@ -2531,6 +2529,8 @@ static int check_target_status(ctlr_info_t *h, CommandList_struct *c)
                case 0: return IO_OK; /* no sense */
                case 1: return IO_OK; /* recovered error */
                default:
+                       if (check_for_unit_attention(h, c))
+                               return IO_NEEDS_RETRY;
                        printk(KERN_WARNING "cciss%d: cmd 0x%02x "
                                "check condition, sense key = 0x%02x\n",
                                h->ctlr, c->Request.CDB[0],
@@ -2672,7 +2672,7 @@ static int sendcmd_withirq(__u8 cmd, int ctlr, void *buff, size_t size,
 }
 
 static void cciss_geometry_inquiry(int ctlr, int logvol,
-                                  int withirq, sector_t total_size,
+                                  sector_t total_size,
                                   unsigned int block_size,
                                   InquiryData_struct *inq_buff,
                                   drive_info_struct *drv)
@@ -2683,14 +2683,8 @@ static void cciss_geometry_inquiry(int ctlr, int logvol,
 
        memset(inq_buff, 0, sizeof(InquiryData_struct));
        log_unit_to_scsi3addr(hba[ctlr], scsi3addr, logvol);
-       if (withirq)
-               return_code = sendcmd_withirq(CISS_INQUIRY, ctlr,
-                                             inq_buff, sizeof(*inq_buff),
-                                             0xC1, scsi3addr, TYPE_CMD);
-       else
-               return_code = sendcmd(CISS_INQUIRY, ctlr, inq_buff,
-                                     sizeof(*inq_buff), 0xC1, scsi3addr,
-                                     TYPE_CMD);
+       return_code = sendcmd_withirq(CISS_INQUIRY, ctlr, inq_buff,
+                       sizeof(*inq_buff), 0xC1, scsi3addr, TYPE_CMD);
        if (return_code == IO_OK) {
                if (inq_buff->data_byte[8] == 0xFF) {
                        printk(KERN_WARNING
@@ -2723,7 +2717,7 @@ static void cciss_geometry_inquiry(int ctlr, int logvol,
 }
 
 static void
-cciss_read_capacity(int ctlr, int logvol, int withirq, sector_t *total_size,
+cciss_read_capacity(int ctlr, int logvol, sector_t *total_size,
                    unsigned int *block_size)
 {
        ReadCapdata_struct *buf;
@@ -2737,14 +2731,8 @@ cciss_read_capacity(int ctlr, int logvol, int withirq, sector_t *total_size,
        }
 
        log_unit_to_scsi3addr(hba[ctlr], scsi3addr, logvol);
-       if (withirq)
-               return_code = sendcmd_withirq(CCISS_READ_CAPACITY,
-                               ctlr, buf, sizeof(ReadCapdata_struct),
-                                       0, scsi3addr, TYPE_CMD);
-       else
-               return_code = sendcmd(CCISS_READ_CAPACITY,
-                               ctlr, buf, sizeof(ReadCapdata_struct),
-                                       0, scsi3addr, TYPE_CMD);
+       return_code = sendcmd_withirq(CCISS_READ_CAPACITY, ctlr, buf,
+               sizeof(ReadCapdata_struct), 0, scsi3addr, TYPE_CMD);
        if (return_code == IO_OK) {
                *total_size = be32_to_cpu(*(__be32 *) buf->total_size);
                *block_size = be32_to_cpu(*(__be32 *) buf->block_size);
@@ -2756,8 +2744,8 @@ cciss_read_capacity(int ctlr, int logvol, int withirq, sector_t *total_size,
        kfree(buf);
 }
 
-static void
-cciss_read_capacity_16(int ctlr, int logvol, int withirq, sector_t *total_size,                                unsigned int *block_size)
+static void cciss_read_capacity_16(int ctlr, int logvol,
+       sector_t *total_size, unsigned int *block_size)
 {
        ReadCapdata_struct_16 *buf;
        int return_code;
@@ -2770,16 +2758,9 @@ cciss_read_capacity_16(int ctlr, int logvol, int withirq, sector_t *total_size,
        }
 
        log_unit_to_scsi3addr(hba[ctlr], scsi3addr, logvol);
-       if (withirq) {
-               return_code = sendcmd_withirq(CCISS_READ_CAPACITY_16,
-                       ctlr, buf, sizeof(ReadCapdata_struct_16),
-                               0, scsi3addr, TYPE_CMD);
-       }
-       else {
-               return_code = sendcmd(CCISS_READ_CAPACITY_16,
-                       ctlr, buf, sizeof(ReadCapdata_struct_16),
-                               0, scsi3addr, TYPE_CMD);
-       }
+       return_code = sendcmd_withirq(CCISS_READ_CAPACITY_16,
+               ctlr, buf, sizeof(ReadCapdata_struct_16),
+                       0, scsi3addr, TYPE_CMD);
        if (return_code == IO_OK) {
                *total_size = be64_to_cpu(*(__be64 *) buf->total_size);
                *block_size = be32_to_cpu(*(__be32 *) buf->block_size);
@@ -2820,13 +2801,13 @@ static int cciss_revalidate(struct gendisk *disk)
                return 1;
        }
        if (h->cciss_read == CCISS_READ_10) {
-               cciss_read_capacity(h->ctlr, logvol, 1,
+               cciss_read_capacity(h->ctlr, logvol,
                                        &total_size, &block_size);
        } else {
-               cciss_read_capacity_16(h->ctlr, logvol, 1,
+               cciss_read_capacity_16(h->ctlr, logvol,
                                        &total_size, &block_size);
        }
-       cciss_geometry_inquiry(h->ctlr, logvol, 1, total_size, block_size,
+       cciss_geometry_inquiry(h->ctlr, logvol, total_size, block_size,
                               inq_buff, drv);
 
        blk_queue_logical_block_size(drv->queue, drv->block_size);
@@ -2837,167 +2818,6 @@ static int cciss_revalidate(struct gendisk *disk)
 }
 
 /*
- *   Wait polling for a command to complete.
- *   The memory mapped FIFO is polled for the completion.
- *   Used only at init time, interrupts from the HBA are disabled.
- */
-static unsigned long pollcomplete(int ctlr)
-{
-       unsigned long done;
-       int i;
-
-       /* Wait (up to 20 seconds) for a command to complete */
-
-       for (i = 20 * HZ; i > 0; i--) {
-               done = hba[ctlr]->access.command_completed(hba[ctlr]);
-               if (done == FIFO_EMPTY)
-                       schedule_timeout_uninterruptible(1);
-               else
-                       return done;
-       }
-       /* Invalid address to tell caller we ran out of time */
-       return 1;
-}
-
-/* Send command c to controller h and poll for it to complete.
- * Turns interrupts off on the board.  Used at driver init time
- * and during SCSI error recovery.
- */
-static int sendcmd_core(ctlr_info_t *h, CommandList_struct *c)
-{
-       int i;
-       unsigned long complete;
-       int status = IO_ERROR;
-       u64bit buff_dma_handle;
-
-resend_cmd1:
-
-       /* Disable interrupt on the board. */
-       h->access.set_intr_mask(h, CCISS_INTR_OFF);
-
-       /* Make sure there is room in the command FIFO */
-       /* Actually it should be completely empty at this time */
-       /* unless we are in here doing error handling for the scsi */
-       /* tape side of the driver. */
-       for (i = 200000; i > 0; i--) {
-               /* if fifo isn't full go */
-               if (!(h->access.fifo_full(h)))
-                       break;
-               udelay(10);
-               printk(KERN_WARNING "cciss cciss%d: SendCmd FIFO full,"
-                      " waiting!\n", h->ctlr);
-       }
-       h->access.submit_command(h, c); /* Send the cmd */
-       do {
-               complete = pollcomplete(h->ctlr);
-
-#ifdef CCISS_DEBUG
-               printk(KERN_DEBUG "cciss: command completed\n");
-#endif                         /* CCISS_DEBUG */
-
-               if (complete == 1) {
-                       printk(KERN_WARNING
-                              "cciss cciss%d: SendCmd Timeout out, "
-                              "No command list address returned!\n", h->ctlr);
-                       status = IO_ERROR;
-                       break;
-               }
-
-               /* Make sure it's the command we're expecting. */
-               if ((complete & ~CISS_ERROR_BIT) != c->busaddr) {
-                       printk(KERN_WARNING "cciss%d: Unexpected command "
-                               "completion.\n", h->ctlr);
-                       continue;
-               }
-
-               /* It is our command.  If no error, we're done. */
-               if (!(complete & CISS_ERROR_BIT)) {
-                       status = IO_OK;
-                       break;
-               }
-
-               /* There is an error... */
-
-               /* if data overrun or underun on Report command ignore it */
-               if (((c->Request.CDB[0] == CISS_REPORT_LOG) ||
-                    (c->Request.CDB[0] == CISS_REPORT_PHYS) ||
-                    (c->Request.CDB[0] == CISS_INQUIRY)) &&
-                       ((c->err_info->CommandStatus == CMD_DATA_OVERRUN) ||
-                        (c->err_info->CommandStatus == CMD_DATA_UNDERRUN))) {
-                       complete = c->busaddr;
-                       status = IO_OK;
-                       break;
-               }
-
-               if (c->err_info->CommandStatus == CMD_UNSOLICITED_ABORT) {
-                       printk(KERN_WARNING "cciss%d: unsolicited abort %p\n",
-                               h->ctlr, c);
-                       if (c->retry_count < MAX_CMD_RETRIES) {
-                               printk(KERN_WARNING "cciss%d: retrying %p\n",
-                                  h->ctlr, c);
-                               c->retry_count++;
-                               /* erase the old error information */
-                               memset(c->err_info, 0, sizeof(c->err_info));
-                               goto resend_cmd1;
-                       }
-                       printk(KERN_WARNING "cciss%d: retried %p too many "
-                               "times\n", h->ctlr, c);
-                       status = IO_ERROR;
-                       break;
-               }
-
-               if (c->err_info->CommandStatus == CMD_UNABORTABLE) {
-                       printk(KERN_WARNING "cciss%d: command could not be "
-                               "aborted.\n", h->ctlr);
-                       status = IO_ERROR;
-                       break;
-               }
-
-               if (c->err_info->CommandStatus == CMD_TARGET_STATUS) {
-                       status = check_target_status(h, c);
-                       break;
-               }
-
-               printk(KERN_WARNING "cciss%d: sendcmd error\n", h->ctlr);
-               printk(KERN_WARNING "cmd = 0x%02x, CommandStatus = 0x%02x\n",
-                       c->Request.CDB[0], c->err_info->CommandStatus);
-               status = IO_ERROR;
-               break;
-
-       } while (1);
-
-       /* unlock the data buffer from DMA */
-       buff_dma_handle.val32.lower = c->SG[0].Addr.lower;
-       buff_dma_handle.val32.upper = c->SG[0].Addr.upper;
-       pci_unmap_single(h->pdev, (dma_addr_t) buff_dma_handle.val,
-                        c->SG[0].Len, PCI_DMA_BIDIRECTIONAL);
-       return status;
-}
-
-/*
- * Send a command to the controller, and wait for it to complete.
- * Used at init time, and during SCSI error recovery.
- */
-static int sendcmd(__u8 cmd, int ctlr, void *buff, size_t size,
-       __u8 page_code, unsigned char *scsi3addr, int cmd_type)
-{
-       CommandList_struct *c;
-       int status;
-
-       c = cmd_alloc(hba[ctlr], 1);
-       if (!c) {
-               printk(KERN_WARNING "cciss: unable to get memory");
-               return IO_ERROR;
-       }
-       status = fill_cmd(c, cmd, ctlr, buff, size, page_code,
-               scsi3addr, cmd_type);
-       if (status == IO_OK)
-               status = sendcmd_core(hba[ctlr], c);
-       cmd_free(hba[ctlr], c, 1);
-       return status;
-}
-
-/*
  * Map (physical) PCI mem into (virtual) kernel space
  */
 static void __iomem *remap_pci_mem(ulong base, ulong size)
@@ -3255,9 +3075,13 @@ static void do_cciss_request(struct request_queue *q)
        int seg;
        struct request *creq;
        u64bit temp64;
-       struct scatterlist tmp_sg[MAXSGENTRIES];
+       struct scatterlist *tmp_sg;
+       SGDescriptor_struct *curr_sg;
        drive_info_struct *drv;
        int i, dir;
+       int nseg = 0;
+       int sg_index = 0;
+       int chained = 0;
 
        /* We call start_io here in case there is a command waiting on the
         * queue that has not been sent.
@@ -3270,13 +3094,14 @@ static void do_cciss_request(struct request_queue *q)
        if (!creq)
                goto startio;
 
-       BUG_ON(creq->nr_phys_segments > MAXSGENTRIES);
+       BUG_ON(creq->nr_phys_segments > h->maxsgentries);
 
        if ((c = cmd_alloc(h, 1)) == NULL)
                goto full;
 
        blk_start_request(creq);
 
+       tmp_sg = h->scatter_list[c->cmdindex];
        spin_unlock_irq(q->queue_lock);
 
        c->cmd_type = CMD_RWREQ;
@@ -3305,7 +3130,7 @@ static void do_cciss_request(struct request_queue *q)
               (int)blk_rq_pos(creq), (int)blk_rq_sectors(creq));
 #endif                         /* CCISS_DEBUG */
 
-       sg_init_table(tmp_sg, MAXSGENTRIES);
+       sg_init_table(tmp_sg, h->maxsgentries);
        seg = blk_rq_map_sg(q, creq, tmp_sg);
 
        /* get the DMA records for the setup */
@@ -3314,25 +3139,70 @@ static void do_cciss_request(struct request_queue *q)
        else
                dir = PCI_DMA_TODEVICE;
 
+       curr_sg = c->SG;
+       sg_index = 0;
+       chained = 0;
+
        for (i = 0; i < seg; i++) {
-               c->SG[i].Len = tmp_sg[i].length;
+               if (((sg_index+1) == (h->max_cmd_sgentries)) &&
+                       !chained && ((seg - i) > 1)) {
+                       nseg = seg - i;
+                       curr_sg[sg_index].Len = (nseg) *
+                                       sizeof(SGDescriptor_struct);
+                       curr_sg[sg_index].Ext = CCISS_SG_CHAIN;
+
+                       /* Point to next chain block. */
+                       curr_sg = h->cmd_sg_list[c->cmdindex]->sgchain;
+                       sg_index = 0;
+                       chained = 1;
+               }
+               curr_sg[sg_index].Len = tmp_sg[i].length;
                temp64.val = (__u64) pci_map_page(h->pdev, sg_page(&tmp_sg[i]),
-                                                 tmp_sg[i].offset,
-                                                 tmp_sg[i].length, dir);
-               c->SG[i].Addr.lower = temp64.val32.lower;
-               c->SG[i].Addr.upper = temp64.val32.upper;
-               c->SG[i].Ext = 0;       // we are not chaining
+                                               tmp_sg[i].offset,
+                                               tmp_sg[i].length, dir);
+               curr_sg[sg_index].Addr.lower = temp64.val32.lower;
+               curr_sg[sg_index].Addr.upper = temp64.val32.upper;
+               curr_sg[sg_index].Ext = 0;  /* we are not chaining */
+
+               ++sg_index;
+       }
+
+       if (chained) {
+               int len;
+               curr_sg = c->SG;
+               sg_index = h->max_cmd_sgentries - 1;
+               len = curr_sg[sg_index].Len;
+               /* Setup pointer to next chain block.
+                * Fill out last element in current chain
+                * block with address of next chain block.
+                */
+               temp64.val = pci_map_single(h->pdev,
+                                       h->cmd_sg_list[c->cmdindex]->sgchain,
+                                       len, dir);
+
+               h->cmd_sg_list[c->cmdindex]->sg_chain_dma = temp64.val;
+               curr_sg[sg_index].Addr.lower = temp64.val32.lower;
+               curr_sg[sg_index].Addr.upper = temp64.val32.upper;
+
+               pci_dma_sync_single_for_device(h->pdev,
+                               h->cmd_sg_list[c->cmdindex]->sg_chain_dma,
+                               len, dir);
        }
+
        /* track how many SG entries we are using */
        if (seg > h->maxSG)
                h->maxSG = seg;
 
 #ifdef CCISS_DEBUG
-       printk(KERN_DEBUG "cciss: Submitting %u sectors in %d segments\n",
-              blk_rq_sectors(creq), seg);
+       printk(KERN_DEBUG "cciss: Submitting %ld sectors in %d segments "
+                       "chained[%d]\n",
+                       blk_rq_sectors(creq), seg, chained);
 #endif                         /* CCISS_DEBUG */
 
-       c->Header.SGList = c->Header.SGTotal = seg;
+       c->Header.SGList = c->Header.SGTotal = seg + chained;
+       if (seg > h->max_cmd_sgentries)
+               c->Header.SGList = h->max_cmd_sgentries;
+
        if (likely(blk_fs_request(creq))) {
                if(h->cciss_read == CCISS_READ_10) {
                        c->Request.CDB[1] = 0;
@@ -3513,28 +3383,33 @@ static int add_to_scan_list(struct ctlr_info *h)
  * @h:                    Pointer to the controller.
  *
  * Removes the controller from the rescan queue if present. Blocks if
- * the controller is currently conducting a rescan.
+ * the controller is currently conducting a rescan.  The controller
+ * can be in one of three states:
+ * 1. Doesn't need a scan
+ * 2. On the scan list, but not scanning yet (we remove it)
+ * 3. Busy scanning (and not on the list). In this case we want to wait for
+ *    the scan to complete to make sure the scanning thread for this
+ *    controller is completely idle.
  **/
 static void remove_from_scan_list(struct ctlr_info *h)
 {
        struct ctlr_info *test_h, *tmp_h;
-       int scanning = 0;
 
        mutex_lock(&scan_mutex);
        list_for_each_entry_safe(test_h, tmp_h, &scan_q, scan_list) {
-               if (test_h == h) {
+               if (test_h == h) { /* state 2. */
                        list_del(&h->scan_list);
                        complete_all(&h->scan_wait);
                        mutex_unlock(&scan_mutex);
                        return;
                }
        }
-       if (&h->busy_scanning)
-               scanning = 0;
-       mutex_unlock(&scan_mutex);
-
-       if (scanning)
+       if (h->busy_scanning) { /* state 3. */
+               mutex_unlock(&scan_mutex);
                wait_for_completion(&h->scan_wait);
+       } else { /* state 1, nothing to do. */
+               mutex_unlock(&scan_mutex);
+       }
 }
 
 /**
@@ -3573,13 +3448,11 @@ static int scan_thread(void *data)
                        h->busy_scanning = 1;
                        mutex_unlock(&scan_mutex);
 
-                       if (h) {
-                               rebuild_lun_table(h, 0, 0);
-                               complete_all(&h->scan_wait);
-                               mutex_lock(&scan_mutex);
-                               h->busy_scanning = 0;
-                               mutex_unlock(&scan_mutex);
-                       }
+                       rebuild_lun_table(h, 0, 0);
+                       complete_all(&h->scan_wait);
+                       mutex_lock(&scan_mutex);
+                       h->busy_scanning = 0;
+                       mutex_unlock(&scan_mutex);
                }
        }
 
@@ -3605,8 +3478,22 @@ static int check_for_unit_attention(ctlr_info_t *h, CommandList_struct *c)
        case REPORT_LUNS_CHANGED:
                printk(KERN_WARNING "cciss%d: report LUN data "
                        "changed\n", h->ctlr);
-               add_to_scan_list(h);
-               wake_up_process(cciss_scan_thread);
+       /*
+        * Here, we could call add_to_scan_list and wake up the scan thread,
+        * except that it's quite likely that we will get more than one
+        * REPORT_LUNS_CHANGED condition in quick succession, which means
+        * that those which occur after the first one will likely happen
+        * *during* the scan_thread's rescan.  And the rescan code is not
+        * robust enough to restart in the middle, undoing what it has already
+        * done, and it's not clear that it's even possible to do this, since
+        * part of what it does is notify the block layer, which starts
+        * doing it's own i/o to read partition tables and so on, and the
+        * driver doesn't have visibility to know what might need undoing.
+        * In any event, if possible, it is horribly complicated to get right
+        * so we just don't do it for now.
+        *
+        * Note: this REPORT_LUNS_CHANGED condition only occurs on the MSA2012.
+        */
                return 1;
        break;
        case POWER_OR_RESET:
@@ -3888,6 +3775,23 @@ static int __devinit cciss_pci_init(ctlr_info_t *c, struct pci_dev *pdev)
         * leave a little room for ioctl calls.
         */
        c->max_commands = readl(&(c->cfgtable->CmdsOutMax));
+       c->maxsgentries = readl(&(c->cfgtable->MaxSGElements));
+
+       /*
+        * Limit native command to 32 s/g elements to save dma'able memory.
+        * Howvever spec says if 0, use 31
+        */
+
+       c->max_cmd_sgentries = 31;
+       if (c->maxsgentries > 512) {
+               c->max_cmd_sgentries = 32;
+               c->chainsize = c->maxsgentries - c->max_cmd_sgentries + 1;
+               c->maxsgentries -= 1;   /* account for chain pointer */
+       } else {
+               c->maxsgentries = 31;   /* Default to traditional value */
+               c->chainsize = 0;       /* traditional */
+       }
+
        c->product_name = products[prod_index].product_name;
        c->access = *(products[prod_index].access);
        c->nr_cmds = c->max_commands - 4;
@@ -4214,6 +4118,7 @@ static int __devinit cciss_init_one(struct pci_dev *pdev,
 {
        int i;
        int j = 0;
+       int k = 0;
        int rc;
        int dac, return_code;
        InquiryData_struct *inq_buff;
@@ -4317,6 +4222,53 @@ static int __devinit cciss_init_one(struct pci_dev *pdev,
                printk(KERN_ERR "cciss: out of memory");
                goto clean4;
        }
+
+       /* Need space for temp scatter list */
+       hba[i]->scatter_list = kmalloc(hba[i]->max_commands *
+                                               sizeof(struct scatterlist *),
+                                               GFP_KERNEL);
+       for (k = 0; k < hba[i]->nr_cmds; k++) {
+               hba[i]->scatter_list[k] = kmalloc(sizeof(struct scatterlist) *
+                                                       hba[i]->maxsgentries,
+                                                       GFP_KERNEL);
+               if (hba[i]->scatter_list[k] == NULL) {
+                       printk(KERN_ERR "cciss%d: could not allocate "
+                               "s/g lists\n", i);
+                       goto clean4;
+               }
+       }
+       hba[i]->cmd_sg_list = kmalloc(sizeof(struct Cmd_sg_list *) *
+                                               hba[i]->nr_cmds,
+                                               GFP_KERNEL);
+       if (!hba[i]->cmd_sg_list) {
+               printk(KERN_ERR "cciss%d: Cannot get memory for "
+                       "s/g chaining.\n", i);
+               goto clean4;
+       }
+       /* Build up chain blocks for each command */
+       if (hba[i]->chainsize > 0) {
+               for (j = 0; j < hba[i]->nr_cmds; j++) {
+                       hba[i]->cmd_sg_list[j] =
+                                       kmalloc(sizeof(struct Cmd_sg_list),
+                                                       GFP_KERNEL);
+                       if (!hba[i]->cmd_sg_list[j]) {
+                               printk(KERN_ERR "cciss%d: Cannot get memory "
+                                       "for chain block.\n", i);
+                               goto clean4;
+                       }
+                       /* Need a block of chainsized s/g elements. */
+                       hba[i]->cmd_sg_list[j]->sgchain =
+                                       kmalloc((hba[i]->chainsize *
+                                               sizeof(SGDescriptor_struct)),
+                                               GFP_KERNEL);
+                       if (!hba[i]->cmd_sg_list[j]->sgchain) {
+                               printk(KERN_ERR "cciss%d: Cannot get memory "
+                                       "for s/g chains\n", i);
+                               goto clean4;
+                       }
+               }
+       }
+
        spin_lock_init(&hba[i]->lock);
 
        /* Initialize the pdev driver private data.
@@ -4362,7 +4314,7 @@ static int __devinit cciss_init_one(struct pci_dev *pdev,
 
        cciss_procinit(i);
 
-       hba[i]->cciss_max_sectors = 2048;
+       hba[i]->cciss_max_sectors = 8192;
 
        rebuild_lun_table(hba[i], 1, 0);
        hba[i]->busy_initializing = 0;
@@ -4370,6 +4322,20 @@ static int __devinit cciss_init_one(struct pci_dev *pdev,
 
 clean4:
        kfree(hba[i]->cmd_pool_bits);
+       /* Free up sg elements */
+       for (k = 0; k < hba[i]->nr_cmds; k++)
+               kfree(hba[i]->scatter_list[k]);
+       kfree(hba[i]->scatter_list);
+       /* Only free up extra s/g lists if controller supports them */
+       if (hba[i]->chainsize > 0) {
+               for (j = 0; j < hba[i]->nr_cmds; j++) {
+                       if (hba[i]->cmd_sg_list[j]) {
+                               kfree(hba[i]->cmd_sg_list[j]->sgchain);
+                               kfree(hba[i]->cmd_sg_list[j]);
+                       }
+               }
+               kfree(hba[i]->cmd_sg_list);
+       }
        if (hba[i]->cmd_pool)
                pci_free_consistent(hba[i]->pdev,
                                    hba[i]->nr_cmds * sizeof(CommandList_struct),
@@ -4400,30 +4366,28 @@ clean_no_release_regions:
 
 static void cciss_shutdown(struct pci_dev *pdev)
 {
-       ctlr_info_t *tmp_ptr;
-       int i;
-       char flush_buf[4];
+       ctlr_info_t *h;
+       char *flush_buf;
        int return_code;
 
-       tmp_ptr = pci_get_drvdata(pdev);
-       if (tmp_ptr == NULL)
-               return;
-       i = tmp_ptr->ctlr;
-       if (hba[i] == NULL)
+       h = pci_get_drvdata(pdev);
+       flush_buf = kzalloc(4, GFP_KERNEL);
+       if (!flush_buf) {
+               printk(KERN_WARNING
+                       "cciss:%d cache not flushed, out of memory.\n",
+                       h->ctlr);
                return;
-
-       /* Turn board interrupts off  and send the flush cache command */
-       /* sendcmd will turn off interrupt, and send the flush...
-        * To write all data in the battery backed cache to disks */
-       memset(flush_buf, 0, 4);
-       return_code = sendcmd(CCISS_CACHE_FLUSH, i, flush_buf, 4, 0,
-               CTLR_LUNID, TYPE_CMD);
-       if (return_code == IO_OK) {
-               printk(KERN_INFO "Completed flushing cache on controller %d\n", i);
-       } else {
-               printk(KERN_WARNING "Error flushing cache on controller %d\n", i);
        }
-       free_irq(hba[i]->intr[2], hba[i]);
+       /* write all data in the battery backed cache to disk */
+       memset(flush_buf, 0, 4);
+       return_code = sendcmd_withirq(CCISS_CACHE_FLUSH, h->ctlr, flush_buf,
+               4, 0, CTLR_LUNID, TYPE_CMD);
+       kfree(flush_buf);
+       if (return_code != IO_OK)
+               printk(KERN_WARNING "cciss%d: Error flushing cache\n",
+                       h->ctlr);
+       h->access.set_intr_mask(h, CCISS_INTR_OFF);
+       free_irq(h->intr[2], h);
 }
 
 static void __devexit cciss_remove_one(struct pci_dev *pdev)
@@ -4485,6 +4449,20 @@ static void __devexit cciss_remove_one(struct pci_dev *pdev)
        pci_free_consistent(hba[i]->pdev, hba[i]->nr_cmds * sizeof(ErrorInfo_struct),
                            hba[i]->errinfo_pool, hba[i]->errinfo_pool_dhandle);
        kfree(hba[i]->cmd_pool_bits);
+       /* Free up sg elements */
+       for (j = 0; j < hba[i]->nr_cmds; j++)
+               kfree(hba[i]->scatter_list[j]);
+       kfree(hba[i]->scatter_list);
+       /* Only free up extra s/g lists if controller supports them */
+       if (hba[i]->chainsize > 0) {
+               for (j = 0; j < hba[i]->nr_cmds; j++) {
+                       if (hba[i]->cmd_sg_list[j]) {
+                               kfree(hba[i]->cmd_sg_list[j]->sgchain);
+                               kfree(hba[i]->cmd_sg_list[j]);
+                       }
+               }
+               kfree(hba[i]->cmd_sg_list);
+       }
        /*
         * Deliberately omit pci_disable_device(): it does something nasty to
         * Smart Array controllers that pci_enable_device does not undo
index 31524cf..1d95db2 100644 (file)
@@ -55,7 +55,13 @@ typedef struct _drive_info_struct
        char device_initialized;     /* indicates whether dev is initialized */
 } drive_info_struct;
 
-struct ctlr_info 
+struct Cmd_sg_list {
+       SGDescriptor_struct     *sgchain;
+       dma_addr_t              sg_chain_dma;
+       int                     chain_block_size;
+};
+
+struct ctlr_info
 {
        int     ctlr;
        char    devname[8];
@@ -75,6 +81,16 @@ struct ctlr_info
        int     num_luns;
        int     highest_lun;
        int     usage_count;  /* number of opens all all minor devices */
+       /* Need space for temp sg list
+        * number of scatter/gathers supported
+        * number of scatter/gathers in chained block
+        */
+       struct  scatterlist **scatter_list;
+       int     maxsgentries;
+       int     chainsize;
+       int     max_cmd_sgentries;
+       struct Cmd_sg_list **cmd_sg_list;
+
 #      define DOORBELL_INT     0
 #      define PERF_MODE_INT    1
 #      define SIMPLE_MODE_INT  2
index dbaed1e..b50a9b2 100644 (file)
@@ -7,7 +7,8 @@
 
 //general boundary defintions
 #define SENSEINFOBYTES          32//note that this value may vary between host implementations
-#define MAXSGENTRIES            31
+#define MAXSGENTRIES            32
+#define CCISS_SG_CHAIN          0x80000000
 #define MAXREPLYQS              256
 
 //Command Status value
@@ -319,6 +320,10 @@ typedef struct _CfgTable_struct {
   BYTE             ServerName[16];
   DWORD            HeartBeat;
   DWORD            SCSI_Prefetch;
+  DWORD            MaxSGElements;
+  DWORD            MaxLogicalUnits;
+  DWORD            MaxPhysicalDrives;
+  DWORD            MaxPhysicalDrivesPerLogicalUnit;
 } CfgTable_struct;
 #pragma pack()  
 #endif // CCISS_CMD_H
index 3315268..5d0e46d 100644 (file)
@@ -755,7 +755,7 @@ complete_scsi_command( CommandList_struct *cp, int timeout, __u32 tag)
                                                cp,  
                                                ei->ScsiStatus); 
 #endif
-                                       cmd->result |= (ei->ScsiStatus < 1);
+                                       cmd->result |= (ei->ScsiStatus << 1);
                                }
                                else {  /* scsi status is zero??? How??? */
                                        
@@ -1547,7 +1547,7 @@ cciss_engage_scsi(int ctlr)
        if (sa->registered) {
                printk("cciss%d: SCSI subsystem already engaged.\n", ctlr);
                spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
-               return ENXIO;
+               return -ENXIO;
        }
        sa->registered = 1;
        spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
diff --git a/drivers/block/drbd/Kconfig b/drivers/block/drbd/Kconfig
new file mode 100644 (file)
index 0000000..f4acd04
--- /dev/null
@@ -0,0 +1,71 @@
+#
+# DRBD device driver configuration
+#
+
+comment "DRBD disabled because PROC_FS, INET or CONNECTOR not selected"
+       depends on !PROC_FS || !INET || !CONNECTOR
+
+config BLK_DEV_DRBD
+       tristate "DRBD Distributed Replicated Block Device support"
+       depends on PROC_FS && INET && CONNECTOR
+       select LRU_CACHE
+       default n
+       help
+
+         NOTE: In order to authenticate connections you have to select
+         CRYPTO_HMAC and a hash function as well.
+
+         DRBD is a shared-nothing, synchronously replicated block device. It
+         is designed to serve as a building block for high availability
+         clusters and in this context, is a "drop-in" replacement for shared
+         storage. Simplistically, you could see it as a network RAID 1.
+
+         Each minor device has a role, which can be 'primary' or 'secondary'.
+         On the node with the primary device the application is supposed to
+         run and to access the device (/dev/drbdX). Every write is sent to
+         the local 'lower level block device' and, across the network, to the
+         node with the device in 'secondary' state.  The secondary device
+         simply writes the data to its lower level block device.
+
+         DRBD can also be used in dual-Primary mode (device writable on both
+         nodes), which means it can exhibit shared disk semantics in a
+         shared-nothing cluster.  Needless to say, on top of dual-Primary
+         DRBD utilizing a cluster file system is necessary to maintain for
+         cache coherency.
+
+         For automatic failover you need a cluster manager (e.g. heartbeat).
+         See also: http://www.drbd.org/, http://www.linux-ha.org
+
+         If unsure, say N.
+
+config DRBD_FAULT_INJECTION
+       bool "DRBD fault injection"
+       depends on BLK_DEV_DRBD
+       help
+
+         Say Y here if you want to simulate IO errors, in order to test DRBD's
+         behavior.
+
+         The actual simulation of IO errors is done by writing 3 values to
+         /sys/module/drbd/parameters/
+
+         enable_faults: bitmask of...
+         1     meta data write
+         2               read
+         4     resync data write
+         8                 read
+         16    data write
+         32    data read
+         64    read ahead
+         128   kmalloc of bitmap
+         256   allocation of EE (epoch_entries)
+
+         fault_devs: bitmask of minor numbers
+         fault_rate: frequency in percent
+
+         Example: Simulate data write errors on /dev/drbd0 with a probability of 5%.
+               echo 16 > /sys/module/drbd/parameters/enable_faults
+               echo 1 > /sys/module/drbd/parameters/fault_devs
+               echo 5 > /sys/module/drbd/parameters/fault_rate
+
+         If unsure, say N.
diff --git a/drivers/block/drbd/Makefile b/drivers/block/drbd/Makefile
new file mode 100644 (file)
index 0000000..0d3f337
--- /dev/null
@@ -0,0 +1,5 @@
+drbd-y := drbd_bitmap.o drbd_proc.o
+drbd-y += drbd_worker.o drbd_receiver.o drbd_req.o drbd_actlog.o
+drbd-y += drbd_main.o drbd_strings.o drbd_nl.o
+
+obj-$(CONFIG_BLK_DEV_DRBD)     += drbd.o
diff --git a/drivers/block/drbd/drbd_actlog.c b/drivers/block/drbd/drbd_actlog.c
new file mode 100644 (file)
index 0000000..17956ff
--- /dev/null
@@ -0,0 +1,1424 @@
+/*
+   drbd_actlog.c
+
+   This file is part of DRBD by Philipp Reisner and Lars Ellenberg.
+
+   Copyright (C) 2003-2008, LINBIT Information Technologies GmbH.
+   Copyright (C) 2003-2008, Philipp Reisner <philipp.reisner@linbit.com>.
+   Copyright (C) 2003-2008, Lars Ellenberg <lars.ellenberg@linbit.com>.
+
+   drbd is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   drbd 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 drbd; see the file COPYING.  If not, write to
+   the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ */
+
+#include <linux/slab.h>
+#include <linux/drbd.h>
+#include "drbd_int.h"
+#include "drbd_wrappers.h"
+
+/* We maintain a trivial check sum in our on disk activity log.
+ * With that we can ensure correct operation even when the storage
+ * device might do a partial (last) sector write while loosing power.
+ */
+struct __packed al_transaction {
+       u32       magic;
+       u32       tr_number;
+       struct __packed {
+               u32 pos;
+               u32 extent; } updates[1 + AL_EXTENTS_PT];
+       u32       xor_sum;
+};
+
+struct update_odbm_work {
+       struct drbd_work w;
+       unsigned int enr;
+};
+
+struct update_al_work {
+       struct drbd_work w;
+       struct lc_element *al_ext;
+       struct completion event;
+       unsigned int enr;
+       /* if old_enr != LC_FREE, write corresponding bitmap sector, too */
+       unsigned int old_enr;
+};
+
+struct drbd_atodb_wait {
+       atomic_t           count;
+       struct completion  io_done;
+       struct drbd_conf   *mdev;
+       int                error;
+};
+
+
+int w_al_write_transaction(struct drbd_conf *, struct drbd_work *, int);
+
+static int _drbd_md_sync_page_io(struct drbd_conf *mdev,
+                                struct drbd_backing_dev *bdev,
+                                struct page *page, sector_t sector,
+                                int rw, int size)
+{
+       struct bio *bio;
+       struct drbd_md_io md_io;
+       int ok;
+
+       md_io.mdev = mdev;
+       init_completion(&md_io.event);
+       md_io.error = 0;
+
+       if ((rw & WRITE) && !test_bit(MD_NO_BARRIER, &mdev->flags))
+               rw |= (1 << BIO_RW_BARRIER);
+       rw |= ((1<<BIO_RW_UNPLUG) | (1<<BIO_RW_SYNCIO));
+
+ retry:
+       bio = bio_alloc(GFP_NOIO, 1);
+       bio->bi_bdev = bdev->md_bdev;
+       bio->bi_sector = sector;
+       ok = (bio_add_page(bio, page, size, 0) == size);
+       if (!ok)
+               goto out;
+       bio->bi_private = &md_io;
+       bio->bi_end_io = drbd_md_io_complete;
+       bio->bi_rw = rw;
+
+       if (FAULT_ACTIVE(mdev, (rw & WRITE) ? DRBD_FAULT_MD_WR : DRBD_FAULT_MD_RD))
+               bio_endio(bio, -EIO);
+       else
+               submit_bio(rw, bio);
+       wait_for_completion(&md_io.event);
+       ok = bio_flagged(bio, BIO_UPTODATE) && md_io.error == 0;
+
+       /* check for unsupported barrier op.
+        * would rather check on EOPNOTSUPP, but that is not reliable.
+        * don't try again for ANY return value != 0 */
+       if (unlikely(bio_rw_flagged(bio, BIO_RW_BARRIER) && !ok)) {
+               /* Try again with no barrier */
+               dev_warn(DEV, "Barriers not supported on meta data device - disabling\n");
+               set_bit(MD_NO_BARRIER, &mdev->flags);
+               rw &= ~(1 << BIO_RW_BARRIER);
+               bio_put(bio);
+               goto retry;
+       }
+ out:
+       bio_put(bio);
+       return ok;
+}
+
+int drbd_md_sync_page_io(struct drbd_conf *mdev, struct drbd_backing_dev *bdev,
+                        sector_t sector, int rw)
+{
+       int logical_block_size, mask, ok;
+       int offset = 0;
+       struct page *iop = mdev->md_io_page;
+
+       D_ASSERT(mutex_is_locked(&mdev->md_io_mutex));
+
+       BUG_ON(!bdev->md_bdev);
+
+       logical_block_size = bdev_logical_block_size(bdev->md_bdev);
+       if (logical_block_size == 0)
+               logical_block_size = MD_SECTOR_SIZE;
+
+       /* in case logical_block_size != 512 [ s390 only? ] */
+       if (logical_block_size != MD_SECTOR_SIZE) {
+               mask = (logical_block_size / MD_SECTOR_SIZE) - 1;
+               D_ASSERT(mask == 1 || mask == 3 || mask == 7);
+               D_ASSERT(logical_block_size == (mask+1) * MD_SECTOR_SIZE);
+               offset = sector & mask;
+               sector = sector & ~mask;
+               iop = mdev->md_io_tmpp;
+
+               if (rw & WRITE) {
+                       /* these are GFP_KERNEL pages, pre-allocated
+                        * on device initialization */
+                       void *p = page_address(mdev->md_io_page);
+                       void *hp = page_address(mdev->md_io_tmpp);
+
+                       ok = _drbd_md_sync_page_io(mdev, bdev, iop, sector,
+                                       READ, logical_block_size);
+
+                       if (unlikely(!ok)) {
+                               dev_err(DEV, "drbd_md_sync_page_io(,%llus,"
+                                   "READ [logical_block_size!=512]) failed!\n",
+                                   (unsigned long long)sector);
+                               return 0;
+                       }
+
+                       memcpy(hp + offset*MD_SECTOR_SIZE, p, MD_SECTOR_SIZE);
+               }
+       }
+
+       if (sector < drbd_md_first_sector(bdev) ||
+           sector > drbd_md_last_sector(bdev))
+               dev_alert(DEV, "%s [%d]:%s(,%llus,%s) out of range md access!\n",
+                    current->comm, current->pid, __func__,
+                    (unsigned long long)sector, (rw & WRITE) ? "WRITE" : "READ");
+
+       ok = _drbd_md_sync_page_io(mdev, bdev, iop, sector, rw, logical_block_size);
+       if (unlikely(!ok)) {
+               dev_err(DEV, "drbd_md_sync_page_io(,%llus,%s) failed!\n",
+                   (unsigned long long)sector, (rw & WRITE) ? "WRITE" : "READ");
+               return 0;
+       }
+
+       if (logical_block_size != MD_SECTOR_SIZE && !(rw & WRITE)) {
+               void *p = page_address(mdev->md_io_page);
+               void *hp = page_address(mdev->md_io_tmpp);
+
+               memcpy(p, hp + offset*MD_SECTOR_SIZE, MD_SECTOR_SIZE);
+       }
+
+       return ok;
+}
+
+static struct lc_element *_al_get(struct drbd_conf *mdev, unsigned int enr)
+{
+       struct lc_element *al_ext;
+       struct lc_element *tmp;
+       unsigned long     al_flags = 0;
+
+       spin_lock_irq(&mdev->al_lock);
+       tmp = lc_find(mdev->resync, enr/AL_EXT_PER_BM_SECT);
+       if (unlikely(tmp != NULL)) {
+               struct bm_extent  *bm_ext = lc_entry(tmp, struct bm_extent, lce);
+               if (test_bit(BME_NO_WRITES, &bm_ext->flags)) {
+                       spin_unlock_irq(&mdev->al_lock);
+                       return NULL;
+               }
+       }
+       al_ext   = lc_get(mdev->act_log, enr);
+       al_flags = mdev->act_log->flags;
+       spin_unlock_irq(&mdev->al_lock);
+
+       /*
+       if (!al_ext) {
+               if (al_flags & LC_STARVING)
+                       dev_warn(DEV, "Have to wait for LRU element (AL too small?)\n");
+               if (al_flags & LC_DIRTY)
+                       dev_warn(DEV, "Ongoing AL update (AL device too slow?)\n");
+       }
+       */
+
+       return al_ext;
+}
+
+void drbd_al_begin_io(struct drbd_conf *mdev, sector_t sector)
+{
+       unsigned int enr = (sector >> (AL_EXTENT_SHIFT-9));
+       struct lc_element *al_ext;
+       struct update_al_work al_work;
+
+       D_ASSERT(atomic_read(&mdev->local_cnt) > 0);
+
+       wait_event(mdev->al_wait, (al_ext = _al_get(mdev, enr)));
+
+       if (al_ext->lc_number != enr) {
+               /* drbd_al_write_transaction(mdev,al_ext,enr);
+                * recurses into generic_make_request(), which
+                * disallows recursion, bios being serialized on the
+                * current->bio_tail list now.
+                * we have to delegate updates to the activity log
+                * to the worker thread. */
+               init_completion(&al_work.event);
+               al_work.al_ext = al_ext;
+               al_work.enr = enr;
+               al_work.old_enr = al_ext->lc_number;
+               al_work.w.cb = w_al_write_transaction;
+               drbd_queue_work_front(&mdev->data.work, &al_work.w);
+               wait_for_completion(&al_work.event);
+
+               mdev->al_writ_cnt++;
+
+               spin_lock_irq(&mdev->al_lock);
+               lc_changed(mdev->act_log, al_ext);
+               spin_unlock_irq(&mdev->al_lock);
+               wake_up(&mdev->al_wait);
+       }
+}
+
+void drbd_al_complete_io(struct drbd_conf *mdev, sector_t sector)
+{
+       unsigned int enr = (sector >> (AL_EXTENT_SHIFT-9));
+       struct lc_element *extent;
+       unsigned long flags;
+
+       spin_lock_irqsave(&mdev->al_lock, flags);
+
+       extent = lc_find(mdev->act_log, enr);
+
+       if (!extent) {
+               spin_unlock_irqrestore(&mdev->al_lock, flags);
+               dev_err(DEV, "al_complete_io() called on inactive extent %u\n", enr);
+               return;
+       }
+
+       if (lc_put(mdev->act_log, extent) == 0)
+               wake_up(&mdev->al_wait);
+
+       spin_unlock_irqrestore(&mdev->al_lock, flags);
+}
+
+int
+w_al_write_transaction(struct drbd_conf *mdev, struct drbd_work *w, int unused)
+{
+       struct update_al_work *aw = container_of(w, struct update_al_work, w);
+       struct lc_element *updated = aw->al_ext;
+       const unsigned int new_enr = aw->enr;
+       const unsigned int evicted = aw->old_enr;
+       struct al_transaction *buffer;
+       sector_t sector;
+       int i, n, mx;
+       unsigned int extent_nr;
+       u32 xor_sum = 0;
+
+       if (!get_ldev(mdev)) {
+               dev_err(DEV, "get_ldev() failed in w_al_write_transaction\n");
+               complete(&((struct update_al_work *)w)->event);
+               return 1;
+       }
+       /* do we have to do a bitmap write, first?
+        * TODO reduce maximum latency:
+        * submit both bios, then wait for both,
+        * instead of doing two synchronous sector writes. */
+       if (mdev->state.conn < C_CONNECTED && evicted != LC_FREE)
+               drbd_bm_write_sect(mdev, evicted/AL_EXT_PER_BM_SECT);
+
+       mutex_lock(&mdev->md_io_mutex); /* protects md_io_page, al_tr_cycle, ... */
+       buffer = (struct al_transaction *)page_address(mdev->md_io_page);
+
+       buffer->magic = __constant_cpu_to_be32(DRBD_MAGIC);
+       buffer->tr_number = cpu_to_be32(mdev->al_tr_number);
+
+       n = lc_index_of(mdev->act_log, updated);
+
+       buffer->updates[0].pos = cpu_to_be32(n);
+       buffer->updates[0].extent = cpu_to_be32(new_enr);
+
+       xor_sum ^= new_enr;
+
+       mx = min_t(int, AL_EXTENTS_PT,
+                  mdev->act_log->nr_elements - mdev->al_tr_cycle);
+       for (i = 0; i < mx; i++) {
+               unsigned idx = mdev->al_tr_cycle + i;
+               extent_nr = lc_element_by_index(mdev->act_log, idx)->lc_number;
+               buffer->updates[i+1].pos = cpu_to_be32(idx);
+               buffer->updates[i+1].extent = cpu_to_be32(extent_nr);
+               xor_sum ^= extent_nr;
+       }
+       for (; i < AL_EXTENTS_PT; i++) {
+               buffer->updates[i+1].pos = __constant_cpu_to_be32(-1);
+               buffer->updates[i+1].extent = __constant_cpu_to_be32(LC_FREE);
+               xor_sum ^= LC_FREE;
+       }
+       mdev->al_tr_cycle += AL_EXTENTS_PT;
+       if (mdev->al_tr_cycle >= mdev->act_log->nr_elements)
+               mdev->al_tr_cycle = 0;
+
+       buffer->xor_sum = cpu_to_be32(xor_sum);
+
+       sector =  mdev->ldev->md.md_offset
+               + mdev->ldev->md.al_offset + mdev->al_tr_pos;
+
+       if (!drbd_md_sync_page_io(mdev, mdev->ldev, sector, WRITE))
+               drbd_chk_io_error(mdev, 1, TRUE);
+
+       if (++mdev->al_tr_pos >
+           div_ceil(mdev->act_log->nr_elements, AL_EXTENTS_PT))
+               mdev->al_tr_pos = 0;
+
+       D_ASSERT(mdev->al_tr_pos < MD_AL_MAX_SIZE);
+       mdev->al_tr_number++;
+
+       mutex_unlock(&mdev->md_io_mutex);
+
+       complete(&((struct update_al_work *)w)->event);
+       put_ldev(mdev);
+
+       return 1;
+}
+
+/**
+ * drbd_al_read_tr() - Read a single transaction from the on disk activity log
+ * @mdev:      DRBD device.
+ * @bdev:      Block device to read form.
+ * @b:         pointer to an al_transaction.
+ * @index:     On disk slot of the transaction to read.
+ *
+ * Returns -1 on IO error, 0 on checksum error and 1 upon success.
+ */
+static int drbd_al_read_tr(struct drbd_conf *mdev,
+                          struct drbd_backing_dev *bdev,
+                          struct al_transaction *b,
+                          int index)
+{
+       sector_t sector;
+       int rv, i;
+       u32 xor_sum = 0;
+
+       sector = bdev->md.md_offset + bdev->md.al_offset + index;
+
+       /* Dont process error normally,
+        * as this is done before disk is attached! */
+       if (!drbd_md_sync_page_io(mdev, bdev, sector, READ))
+               return -1;
+
+       rv = (be32_to_cpu(b->magic) == DRBD_MAGIC);
+
+       for (i = 0; i < AL_EXTENTS_PT + 1; i++)
+               xor_sum ^= be32_to_cpu(b->updates[i].extent);
+       rv &= (xor_sum == be32_to_cpu(b->xor_sum));
+
+       return rv;
+}
+
+/**
+ * drbd_al_read_log() - Restores the activity log from its on disk representation.
+ * @mdev:      DRBD device.
+ * @bdev:      Block device to read form.
+ *
+ * Returns 1 on success, returns 0 when reading the log failed due to IO errors.
+ */
+int drbd_al_read_log(struct drbd_conf *mdev, struct drbd_backing_dev *bdev)
+{
+       struct al_transaction *buffer;
+       int i;
+       int rv;
+       int mx;
+       int active_extents = 0;
+       int transactions = 0;
+       int found_valid = 0;
+       int from = 0;
+       int to = 0;
+       u32 from_tnr = 0;
+       u32 to_tnr = 0;
+       u32 cnr;
+
+       mx = div_ceil(mdev->act_log->nr_elements, AL_EXTENTS_PT);
+
+       /* lock out all other meta data io for now,
+        * and make sure the page is mapped.
+        */
+       mutex_lock(&mdev->md_io_mutex);
+       buffer = page_address(mdev->md_io_page);
+
+       /* Find the valid transaction in the log */
+       for (i = 0; i <= mx; i++) {
+               rv = drbd_al_read_tr(mdev, bdev, buffer, i);
+               if (rv == 0)
+                       continue;
+               if (rv == -1) {
+                       mutex_unlock(&mdev->md_io_mutex);
+                       return 0;
+               }
+               cnr = be32_to_cpu(buffer->tr_number);
+
+               if (++found_valid == 1) {
+                       from = i;
+                       to = i;
+                       from_tnr = cnr;
+                       to_tnr = cnr;
+                       continue;
+               }
+               if ((int)cnr - (int)from_tnr < 0) {
+                       D_ASSERT(from_tnr - cnr + i - from == mx+1);
+                       from = i;
+                       from_tnr = cnr;
+               }
+               if ((int)cnr - (int)to_tnr > 0) {
+                       D_ASSERT(cnr - to_tnr == i - to);
+                       to = i;
+                       to_tnr = cnr;
+               }
+       }
+
+       if (!found_valid) {
+               dev_warn(DEV, "No usable activity log found.\n");
+               mutex_unlock(&mdev->md_io_mutex);
+               return 1;
+       }
+
+       /* Read the valid transactions.
+        * dev_info(DEV, "Reading from %d to %d.\n",from,to); */
+       i = from;
+       while (1) {
+               int j, pos;
+               unsigned int extent_nr;
+               unsigned int trn;
+
+               rv = drbd_al_read_tr(mdev, bdev, buffer, i);
+               ERR_IF(rv == 0) goto cancel;
+               if (rv == -1) {
+                       mutex_unlock(&mdev->md_io_mutex);
+                       return 0;
+               }
+
+               trn = be32_to_cpu(buffer->tr_number);
+
+               spin_lock_irq(&mdev->al_lock);
+
+               /* This loop runs backwards because in the cyclic
+                  elements there might be an old version of the
+                  updated element (in slot 0). So the element in slot 0
+                  can overwrite old versions. */
+               for (j = AL_EXTENTS_PT; j >= 0; j--) {
+                       pos = be32_to_cpu(buffer->updates[j].pos);
+                       extent_nr = be32_to_cpu(buffer->updates[j].extent);
+
+                       if (extent_nr == LC_FREE)
+                               continue;
+
+                       lc_set(mdev->act_log, extent_nr, pos);
+                       active_extents++;
+               }
+               spin_unlock_irq(&mdev->al_lock);
+
+               transactions++;
+
+cancel:
+               if (i == to)
+                       break;
+               i++;
+               if (i > mx)
+                       i = 0;
+       }
+
+       mdev->al_tr_number = to_tnr+1;
+       mdev->al_tr_pos = to;
+       if (++mdev->al_tr_pos >
+           div_ceil(mdev->act_log->nr_elements, AL_EXTENTS_PT))
+               mdev->al_tr_pos = 0;
+
+       /* ok, we are done with it */
+       mutex_unlock(&mdev->md_io_mutex);
+
+       dev_info(DEV, "Found %d transactions (%d active extents) in activity log.\n",
+            transactions, active_extents);
+
+       return 1;
+}
+
+static void atodb_endio(struct bio *bio, int error)
+{
+       struct drbd_atodb_wait *wc = bio->bi_private;
+       struct drbd_conf *mdev = wc->mdev;
+       struct page *page;
+       int uptodate = bio_flagged(bio, BIO_UPTODATE);
+
+       /* strange behavior of some lower level drivers...
+        * fail the request by clearing the uptodate flag,
+        * but do not return any error?! */
+       if (!error && !uptodate)
+               error = -EIO;
+
+       drbd_chk_io_error(mdev, error, TRUE);
+       if (error && wc->error == 0)
+               wc->error = error;
+
+       if (atomic_dec_and_test(&wc->count))
+               complete(&wc->io_done);
+
+       page = bio->bi_io_vec[0].bv_page;
+       put_page(page);
+       bio_put(bio);
+       mdev->bm_writ_cnt++;
+       put_ldev(mdev);
+}
+
+#define S2W(s) ((s)<<(BM_EXT_SHIFT-BM_BLOCK_SHIFT-LN2_BPL))
+/* activity log to on disk bitmap -- prepare bio unless that sector
+ * is already covered by previously prepared bios */
+static int atodb_prepare_unless_covered(struct drbd_conf *mdev,
+                                       struct bio **bios,
+                                       unsigned int enr,
+                                       struct drbd_atodb_wait *wc) __must_hold(local)
+{
+       struct bio *bio;
+       struct page *page;
+       sector_t on_disk_sector = enr + mdev->ldev->md.md_offset
+                                     + mdev->ldev->md.bm_offset;
+       unsigned int page_offset = PAGE_SIZE;
+       int offset;
+       int i = 0;
+       int err = -ENOMEM;
+
+       /* Check if that enr is already covered by an already created bio.
+        * Caution, bios[] is not NULL terminated,
+        * but only initialized to all NULL.
+        * For completely scattered activity log,
+        * the last invocation iterates over all bios,
+        * and finds the last NULL entry.
+        */
+       while ((bio = bios[i])) {
+               if (bio->bi_sector == on_disk_sector)
+                       return 0;
+               i++;
+       }
+       /* bios[i] == NULL, the next not yet used slot */
+
+       /* GFP_KERNEL, we are not in the write-out path */
+       bio = bio_alloc(GFP_KERNEL, 1);
+       if (bio == NULL)
+               return -ENOMEM;
+
+       if (i > 0) {
+               const struct bio_vec *prev_bv = bios[i-1]->bi_io_vec;
+               page_offset = prev_bv->bv_offset + prev_bv->bv_len;
+               page = prev_bv->bv_page;
+       }
+       if (page_offset == PAGE_SIZE) {
+               page = alloc_page(__GFP_HIGHMEM);
+               if (page == NULL)
+                       goto out_bio_put;
+               page_offset = 0;
+       } else {
+               get_page(page);
+       }
+
+       offset = S2W(enr);
+       drbd_bm_get_lel(mdev, offset,
+                       min_t(size_t, S2W(1), drbd_bm_words(mdev) - offset),
+                       kmap(page) + page_offset);
+       kunmap(page);
+
+       bio->bi_private = wc;
+       bio->bi_end_io = atodb_endio;
+       bio->bi_bdev = mdev->ldev->md_bdev;
+       bio->bi_sector = on_disk_sector;
+
+       if (bio_add_page(bio, page, MD_SECTOR_SIZE, page_offset) != MD_SECTOR_SIZE)
+               goto out_put_page;
+
+       atomic_inc(&wc->count);
+       /* we already know that we may do this...
+        * get_ldev_if_state(mdev,D_ATTACHING);
+        * just get the extra reference, so that the local_cnt reflects
+        * the number of pending IO requests DRBD at its backing device.
+        */
+       atomic_inc(&mdev->local_cnt);
+
+       bios[i] = bio;
+
+       return 0;
+
+out_put_page:
+       err = -EINVAL;
+       put_page(page);
+out_bio_put:
+       bio_put(bio);
+       return err;
+}
+
+/**
+ * drbd_al_to_on_disk_bm() -  * Writes bitmap parts covered by active AL extents
+ * @mdev:      DRBD device.
+ *
+ * Called when we detach (unconfigure) local storage,
+ * or when we go from R_PRIMARY to R_SECONDARY role.
+ */
+void drbd_al_to_on_disk_bm(struct drbd_conf *mdev)
+{
+       int i, nr_elements;
+       unsigned int enr;
+       struct bio **bios;
+       struct drbd_atodb_wait wc;
+
+       ERR_IF (!get_ldev_if_state(mdev, D_ATTACHING))
+               return; /* sorry, I don't have any act_log etc... */
+
+       wait_event(mdev->al_wait, lc_try_lock(mdev->act_log));
+
+       nr_elements = mdev->act_log->nr_elements;
+
+       /* GFP_KERNEL, we are not in anyone's write-out path */
+       bios = kzalloc(sizeof(struct bio *) * nr_elements, GFP_KERNEL);
+       if (!bios)
+               goto submit_one_by_one;
+
+       atomic_set(&wc.count, 0);
+       init_completion(&wc.io_done);
+       wc.mdev = mdev;
+       wc.error = 0;
+
+       for (i = 0; i < nr_elements; i++) {
+               enr = lc_element_by_index(mdev->act_log, i)->lc_number;
+               if (enr == LC_FREE)
+                       continue;
+               /* next statement also does atomic_inc wc.count and local_cnt */
+               if (atodb_prepare_unless_covered(mdev, bios,
+                                               enr/AL_EXT_PER_BM_SECT,
+                                               &wc))
+                       goto free_bios_submit_one_by_one;
+       }
+
+       /* unnecessary optimization? */
+       lc_unlock(mdev->act_log);
+       wake_up(&mdev->al_wait);
+
+       /* all prepared, submit them */
+       for (i = 0; i < nr_elements; i++) {
+               if (bios[i] == NULL)
+                       break;
+               if (FAULT_ACTIVE(mdev, DRBD_FAULT_MD_WR)) {
+                       bios[i]->bi_rw = WRITE;
+                       bio_endio(bios[i], -EIO);
+               } else {
+                       submit_bio(WRITE, bios[i]);
+               }
+       }
+
+       drbd_blk_run_queue(bdev_get_queue(mdev->ldev->md_bdev));
+
+       /* always (try to) flush bitmap to stable storage */
+       drbd_md_flush(mdev);
+
+       /* In case we did not submit a single IO do not wait for
+        * them to complete. ( Because we would wait forever here. )
+        *
+        * In case we had IOs and they are already complete, there
+        * is not point in waiting anyways.
+        * Therefore this if () ... */
+       if (atomic_read(&wc.count))
+               wait_for_completion(&wc.io_done);
+
+       put_ldev(mdev);
+
+       kfree(bios);
+       return;
+
+ free_bios_submit_one_by_one:
+       /* free everything by calling the endio callback directly. */
+       for (i = 0; i < nr_elements && bios[i]; i++)
+               bio_endio(bios[i], 0);
+
+       kfree(bios);
+
+ submit_one_by_one:
+       dev_warn(DEV, "Using the slow drbd_al_to_on_disk_bm()\n");
+
+       for (i = 0; i < mdev->act_log->nr_elements; i++) {
+               enr = lc_element_by_index(mdev->act_log, i)->lc_number;
+               if (enr == LC_FREE)
+                       continue;
+               /* Really slow: if we have al-extents 16..19 active,
+                * sector 4 will be written four times! Synchronous! */
+               drbd_bm_write_sect(mdev, enr/AL_EXT_PER_BM_SECT);
+       }
+
+       lc_unlock(mdev->act_log);
+       wake_up(&mdev->al_wait);
+       put_ldev(mdev);
+}
+
+/**
+ * drbd_al_apply_to_bm() - Sets the bitmap to diry(1) where covered ba active AL extents
+ * @mdev:      DRBD device.
+ */
+void drbd_al_apply_to_bm(struct drbd_conf *mdev)
+{
+       unsigned int enr;
+       unsigned long add = 0;
+       char ppb[10];
+       int i;
+
+       wait_event(mdev->al_wait, lc_try_lock(mdev->act_log));
+
+       for (i = 0; i < mdev->act_log->nr_elements; i++) {
+               enr = lc_element_by_index(mdev->act_log, i)->lc_number;
+               if (enr == LC_FREE)
+                       continue;
+               add += drbd_bm_ALe_set_all(mdev, enr);
+       }
+
+       lc_unlock(mdev->act_log);
+       wake_up(&mdev->al_wait);
+
+       dev_info(DEV, "Marked additional %s as out-of-sync based on AL.\n",
+            ppsize(ppb, Bit2KB(add)));
+}
+
+static int _try_lc_del(struct drbd_conf *mdev, struct lc_element *al_ext)
+{
+       int rv;
+
+       spin_lock_irq(&mdev->al_lock);
+       rv = (al_ext->refcnt == 0);
+       if (likely(rv))
+               lc_del(mdev->act_log, al_ext);
+       spin_unlock_irq(&mdev->al_lock);
+
+       return rv;
+}
+
+/**
+ * drbd_al_shrink() - Removes all active extents form the activity log
+ * @mdev:      DRBD device.
+ *
+ * Removes all active extents form the activity log, waiting until
+ * the reference count of each entry dropped to 0 first, of course.
+ *
+ * You need to lock mdev->act_log with lc_try_lock() / lc_unlock()
+ */
+void drbd_al_shrink(struct drbd_conf *mdev)
+{
+       struct lc_element *al_ext;
+       int i;
+
+       D_ASSERT(test_bit(__LC_DIRTY, &mdev->act_log->flags));
+
+       for (i = 0; i < mdev->act_log->nr_elements; i++) {
+               al_ext = lc_element_by_index(mdev->act_log, i);
+               if (al_ext->lc_number == LC_FREE)
+                       continue;
+               wait_event(mdev->al_wait, _try_lc_del(mdev, al_ext));
+       }
+
+       wake_up(&mdev->al_wait);
+}
+
+static int w_update_odbm(struct drbd_conf *mdev, struct drbd_work *w, int unused)
+{
+       struct update_odbm_work *udw = container_of(w, struct update_odbm_work, w);
+
+       if (!get_ldev(mdev)) {
+               if (__ratelimit(&drbd_ratelimit_state))
+                       dev_warn(DEV, "Can not update on disk bitmap, local IO disabled.\n");
+               kfree(udw);
+               return 1;
+       }
+
+       drbd_bm_write_sect(mdev, udw->enr);
+       put_ldev(mdev);
+
+       kfree(udw);
+
+       if (drbd_bm_total_weight(mdev) <= mdev->rs_failed) {
+               switch (mdev->state.conn) {
+               case C_SYNC_SOURCE:  case C_SYNC_TARGET:
+               case C_PAUSED_SYNC_S: case C_PAUSED_SYNC_T:
+                       drbd_resync_finished(mdev);
+               default:
+                       /* nothing to do */
+                       break;
+               }
+       }
+       drbd_bcast_sync_progress(mdev);
+
+       return 1;
+}
+
+
+/* ATTENTION. The AL's extents are 4MB each, while the extents in the
+ * resync LRU-cache are 16MB each.
+ * The caller of this function has to hold an get_ldev() reference.
+ *
+ * TODO will be obsoleted once we have a caching lru of the on disk bitmap
+ */
+static void drbd_try_clear_on_disk_bm(struct drbd_conf *mdev, sector_t sector,
+                                     int count, int success)
+{
+       struct lc_element *e;
+       struct update_odbm_work *udw;
+
+       unsigned int enr;
+
+       D_ASSERT(atomic_read(&mdev->local_cnt));
+
+       /* I simply assume that a sector/size pair never crosses
+        * a 16 MB extent border. (Currently this is true...) */
+       enr = BM_SECT_TO_EXT(sector);
+
+       e = lc_get(mdev->resync, enr);
+       if (e) {
+               struct bm_extent *ext = lc_entry(e, struct bm_extent, lce);
+               if (ext->lce.lc_number == enr) {
+                       if (success)
+                               ext->rs_left -= count;
+                       else
+                               ext->rs_failed += count;
+                       if (ext->rs_left < ext->rs_failed) {
+                               dev_err(DEV, "BAD! sector=%llus enr=%u rs_left=%d "
+                                   "rs_failed=%d count=%d\n",
+                                    (unsigned long long)sector,
+                                    ext->lce.lc_number, ext->rs_left,
+                                    ext->rs_failed, count);
+                               dump_stack();
+
+                               lc_put(mdev->resync, &ext->lce);
+                               drbd_force_state(mdev, NS(conn, C_DISCONNECTING));
+                               return;
+                       }
+               } else {
+                       /* Normally this element should be in the cache,
+                        * since drbd_rs_begin_io() pulled it already in.
+                        *
+                        * But maybe an application write finished, and we set
+                        * something outside the resync lru_cache in sync.
+                        */
+                       int rs_left = drbd_bm_e_weight(mdev, enr);
+                       if (ext->flags != 0) {
+                               dev_warn(DEV, "changing resync lce: %d[%u;%02lx]"
+                                    " -> %d[%u;00]\n",
+                                    ext->lce.lc_number, ext->rs_left,
+                                    ext->flags, enr, rs_left);
+                               ext->flags = 0;
+                       }
+                       if (ext->rs_failed) {
+                               dev_warn(DEV, "Kicking resync_lru element enr=%u "
+                                    "out with rs_failed=%d\n",
+                                    ext->lce.lc_number, ext->rs_failed);
+                               set_bit(WRITE_BM_AFTER_RESYNC, &mdev->flags);
+                       }
+                       ext->rs_left = rs_left;
+                       ext->rs_failed = success ? 0 : count;
+                       lc_changed(mdev->resync, &ext->lce);
+               }
+               lc_put(mdev->resync, &ext->lce);
+               /* no race, we are within the al_lock! */
+
+               if (ext->rs_left == ext->rs_failed) {
+                       ext->rs_failed = 0;
+
+                       udw = kmalloc(sizeof(*udw), GFP_ATOMIC);
+                       if (udw) {
+                               udw->enr = ext->lce.lc_number;
+                               udw->w.cb = w_update_odbm;
+                               drbd_queue_work_front(&mdev->data.work, &udw->w);
+                       } else {
+                               dev_warn(DEV, "Could not kmalloc an udw\n");
+                               set_bit(WRITE_BM_AFTER_RESYNC, &mdev->flags);
+                       }
+               }
+       } else {
+               dev_err(DEV, "lc_get() failed! locked=%d/%d flags=%lu\n",
+                   mdev->resync_locked,
+                   mdev->resync->nr_elements,
+                   mdev->resync->flags);
+       }
+}
+
+/* clear the bit corresponding to the piece of storage in question:
+ * size byte of data starting from sector.  Only clear a bits of the affected
+ * one ore more _aligned_ BM_BLOCK_SIZE blocks.
+ *
+ * called by worker on C_SYNC_TARGET and receiver on SyncSource.
+ *
+ */
+void __drbd_set_in_sync(struct drbd_conf *mdev, sector_t sector, int size,
+                      const char *file, const unsigned int line)
+{
+       /* Is called from worker and receiver context _only_ */
+       unsigned long sbnr, ebnr, lbnr;
+       unsigned long count = 0;
+       sector_t esector, nr_sectors;
+       int wake_up = 0;
+       unsigned long flags;
+
+       if (size <= 0 || (size & 0x1ff) != 0 || size > DRBD_MAX_SEGMENT_SIZE) {
+               dev_err(DEV, "drbd_set_in_sync: sector=%llus size=%d nonsense!\n",
+                               (unsigned long long)sector, size);
+               return;
+       }
+       nr_sectors = drbd_get_capacity(mdev->this_bdev);
+       esector = sector + (size >> 9) - 1;
+
+       ERR_IF(sector >= nr_sectors) return;
+       ERR_IF(esector >= nr_sectors) esector = (nr_sectors-1);
+
+       lbnr = BM_SECT_TO_BIT(nr_sectors-1);
+
+       /* we clear it (in sync).
+        * round up start sector, round down end sector.  we make sure we only
+        * clear full, aligned, BM_BLOCK_SIZE (4K) blocks */
+       if (unlikely(esector < BM_SECT_PER_BIT-1))
+               return;
+       if (unlikely(esector == (nr_sectors-1)))
+               ebnr = lbnr;
+       else
+               ebnr = BM_SECT_TO_BIT(esector - (BM_SECT_PER_BIT-1));
+       sbnr = BM_SECT_TO_BIT(sector + BM_SECT_PER_BIT-1);
+
+       if (sbnr > ebnr)
+               return;
+
+       /*
+        * ok, (capacity & 7) != 0 sometimes, but who cares...
+        * we count rs_{total,left} in bits, not sectors.
+        */
+       spin_lock_irqsave(&mdev->al_lock, flags);
+       count = drbd_bm_clear_bits(mdev, sbnr, ebnr);
+       if (count) {
+               /* we need the lock for drbd_try_clear_on_disk_bm */
+               if (jiffies - mdev->rs_mark_time > HZ*10) {
+                       /* should be rolling marks,
+                        * but we estimate only anyways. */
+                       if (mdev->rs_mark_left != drbd_bm_total_weight(mdev) &&
+                           mdev->state.conn != C_PAUSED_SYNC_T &&
+                           mdev->state.conn != C_PAUSED_SYNC_S) {
+                               mdev->rs_mark_time = jiffies;
+                               mdev->rs_mark_left = drbd_bm_total_weight(mdev);
+                       }
+               }
+               if (get_ldev(mdev)) {
+                       drbd_try_clear_on_disk_bm(mdev, sector, count, TRUE);
+                       put_ldev(mdev);
+               }
+               /* just wake_up unconditional now, various lc_chaged(),
+                * lc_put() in drbd_try_clear_on_disk_bm(). */
+               wake_up = 1;
+       }
+       spin_unlock_irqrestore(&mdev->al_lock, flags);
+       if (wake_up)
+               wake_up(&mdev->al_wait);
+}
+
+/*
+ * this is intended to set one request worth of data out of sync.
+ * affects at least 1 bit,
+ * and at most 1+DRBD_MAX_SEGMENT_SIZE/BM_BLOCK_SIZE bits.
+ *
+ * called by tl_clear and drbd_send_dblock (==drbd_make_request).
+ * so this can be _any_ process.
+ */
+void __drbd_set_out_of_sync(struct drbd_conf *mdev, sector_t sector, int size,
+                           const char *file, const unsigned int line)
+{
+       unsigned long sbnr, ebnr, lbnr, flags;
+       sector_t esector, nr_sectors;
+       unsigned int enr, count;
+       struct lc_element *e;
+
+       if (size <= 0 || (size & 0x1ff) != 0 || size > DRBD_MAX_SEGMENT_SIZE) {
+               dev_err(DEV, "sector: %llus, size: %d\n",
+                       (unsigned long long)sector, size);
+               return;
+       }
+
+       if (!get_ldev(mdev))
+               return; /* no disk, no metadata, no bitmap to set bits in */
+
+       nr_sectors = drbd_get_capacity(mdev->this_bdev);
+       esector = sector + (size >> 9) - 1;
+
+       ERR_IF(sector >= nr_sectors)
+               goto out;
+       ERR_IF(esector >= nr_sectors)
+               esector = (nr_sectors-1);
+
+       lbnr = BM_SECT_TO_BIT(nr_sectors-1);
+
+       /* we set it out of sync,
+        * we do not need to round anything here */
+       sbnr = BM_SECT_TO_BIT(sector);
+       ebnr = BM_SECT_TO_BIT(esector);
+
+       /* ok, (capacity & 7) != 0 sometimes, but who cares...
+        * we count rs_{total,left} in bits, not sectors.  */
+       spin_lock_irqsave(&mdev->al_lock, flags);
+       count = drbd_bm_set_bits(mdev, sbnr, ebnr);
+
+       enr = BM_SECT_TO_EXT(sector);
+       e = lc_find(mdev->resync, enr);
+       if (e)
+               lc_entry(e, struct bm_extent, lce)->rs_left += count;
+       spin_unlock_irqrestore(&mdev->al_lock, flags);
+
+out:
+       put_ldev(mdev);
+}
+
+static
+struct bm_extent *_bme_get(struct drbd_conf *mdev, unsigned int enr)
+{
+       struct lc_element *e;
+       struct bm_extent *bm_ext;
+       int wakeup = 0;
+       unsigned long rs_flags;
+
+       spin_lock_irq(&mdev->al_lock);
+       if (mdev->resync_locked > mdev->resync->nr_elements/2) {
+               spin_unlock_irq(&mdev->al_lock);
+               return NULL;
+       }
+       e = lc_get(mdev->resync, enr);
+       bm_ext = e ? lc_entry(e, struct bm_extent, lce) : NULL;
+       if (bm_ext) {
+               if (bm_ext->lce.lc_number != enr) {
+                       bm_ext->rs_left = drbd_bm_e_weight(mdev, enr);
+                       bm_ext->rs_failed = 0;
+                       lc_changed(mdev->resync, &bm_ext->lce);
+                       wakeup = 1;
+               }
+               if (bm_ext->lce.refcnt == 1)
+                       mdev->resync_locked++;
+               set_bit(BME_NO_WRITES, &bm_ext->flags);
+       }
+       rs_flags = mdev->resync->flags;
+       spin_unlock_irq(&mdev->al_lock);
+       if (wakeup)
+               wake_up(&mdev->al_wait);
+
+       if (!bm_ext) {
+               if (rs_flags & LC_STARVING)
+                       dev_warn(DEV, "Have to wait for element"
+                            " (resync LRU too small?)\n");
+               BUG_ON(rs_flags & LC_DIRTY);
+       }
+
+       return bm_ext;
+}
+
+static int _is_in_al(struct drbd_conf *mdev, unsigned int enr)
+{
+       struct lc_element *al_ext;
+       int rv = 0;
+
+       spin_lock_irq(&mdev->al_lock);
+       if (unlikely(enr == mdev->act_log->new_number))
+               rv = 1;
+       else {
+               al_ext = lc_find(mdev->act_log, enr);
+               if (al_ext) {
+                       if (al_ext->refcnt)
+                               rv = 1;
+               }
+       }
+       spin_unlock_irq(&mdev->al_lock);
+
+       /*
+       if (unlikely(rv)) {
+               dev_info(DEV, "Delaying sync read until app's write is done\n");
+       }
+       */
+       return rv;
+}
+
+/**
+ * drbd_rs_begin_io() - Gets an extent in the resync LRU cache and sets it to BME_LOCKED
+ * @mdev:      DRBD device.
+ * @sector:    The sector number.
+ *
+ * This functions sleeps on al_wait. Returns 1 on success, 0 if interrupted.
+ */
+int drbd_rs_begin_io(struct drbd_conf *mdev, sector_t sector)
+{
+       unsigned int enr = BM_SECT_TO_EXT(sector);
+       struct bm_extent *bm_ext;
+       int i, sig;
+
+       sig = wait_event_interruptible(mdev->al_wait,
+                       (bm_ext = _bme_get(mdev, enr)));
+       if (sig)
+               return 0;
+
+       if (test_bit(BME_LOCKED, &bm_ext->flags))
+               return 1;
+
+       for (i = 0; i < AL_EXT_PER_BM_SECT; i++) {
+               sig = wait_event_interruptible(mdev->al_wait,
+                               !_is_in_al(mdev, enr * AL_EXT_PER_BM_SECT + i));
+               if (sig) {
+                       spin_lock_irq(&mdev->al_lock);
+                       if (lc_put(mdev->resync, &bm_ext->lce) == 0) {
+                               clear_bit(BME_NO_WRITES, &bm_ext->flags);
+                               mdev->resync_locked--;
+                               wake_up(&mdev->al_wait);
+                       }
+                       spin_unlock_irq(&mdev->al_lock);
+                       return 0;
+               }
+       }
+
+       set_bit(BME_LOCKED, &bm_ext->flags);
+
+       return 1;
+}
+
+/**
+ * drbd_try_rs_begin_io() - Gets an extent in the resync LRU cache, does not sleep
+ * @mdev:      DRBD device.
+ * @sector:    The sector number.
+ *
+ * Gets an extent in the resync LRU cache, sets it to BME_NO_WRITES, then
+ * tries to set it to BME_LOCKED. Returns 0 upon success, and -EAGAIN
+ * if there is still application IO going on in this area.
+ */
+int drbd_try_rs_begin_io(struct drbd_conf *mdev, sector_t sector)
+{
+       unsigned int enr = BM_SECT_TO_EXT(sector);
+       const unsigned int al_enr = enr*AL_EXT_PER_BM_SECT;
+       struct lc_element *e;
+       struct bm_extent *bm_ext;
+       int i;
+
+       spin_lock_irq(&mdev->al_lock);
+       if (mdev->resync_wenr != LC_FREE && mdev->resync_wenr != enr) {
+               /* in case you have very heavy scattered io, it may
+                * stall the syncer undefined if we give up the ref count
+                * when we try again and requeue.
+                *
+                * if we don't give up the refcount, but the next time
+                * we are scheduled this extent has been "synced" by new
+                * application writes, we'd miss the lc_put on the
+                * extent we keep the refcount on.
+                * so we remembered which extent we had to try again, and
+                * if the next requested one is something else, we do
+                * the lc_put here...
+                * we also have to wake_up
+                */
+               e = lc_find(mdev->resync, mdev->resync_wenr);
+               bm_ext = e ? lc_entry(e, struct bm_extent, lce) : NULL;
+               if (bm_ext) {
+                       D_ASSERT(!test_bit(BME_LOCKED, &bm_ext->flags));
+                       D_ASSERT(test_bit(BME_NO_WRITES, &bm_ext->flags));
+                       clear_bit(BME_NO_WRITES, &bm_ext->flags);
+                       mdev->resync_wenr = LC_FREE;
+                       if (lc_put(mdev->resync, &bm_ext->lce) == 0)
+                               mdev->resync_locked--;
+                       wake_up(&mdev->al_wait);
+               } else {
+                       dev_alert(DEV, "LOGIC BUG\n");
+               }
+       }
+       /* TRY. */
+       e = lc_try_get(mdev->resync, enr);
+       bm_ext = e ? lc_entry(e, struct bm_extent, lce) : NULL;
+       if (bm_ext) {
+               if (test_bit(BME_LOCKED, &bm_ext->flags))
+                       goto proceed;
+               if (!test_and_set_bit(BME_NO_WRITES, &bm_ext->flags)) {
+                       mdev->resync_locked++;
+               } else {
+                       /* we did set the BME_NO_WRITES,
+                        * but then could not set BME_LOCKED,
+                        * so we tried again.
+                        * drop the extra reference. */
+                       bm_ext->lce.refcnt--;
+                       D_ASSERT(bm_ext->lce.refcnt > 0);
+               }
+               goto check_al;
+       } else {
+               /* do we rather want to try later? */
+               if (mdev->resync_locked > mdev->resync->nr_elements-3)
+                       goto try_again;
+               /* Do or do not. There is no try. -- Yoda */
+               e = lc_get(mdev->resync, enr);
+               bm_ext = e ? lc_entry(e, struct bm_extent, lce) : NULL;
+               if (!bm_ext) {
+                       const unsigned long rs_flags = mdev->resync->flags;
+                       if (rs_flags & LC_STARVING)
+                               dev_warn(DEV, "Have to wait for element"
+                                    " (resync LRU too small?)\n");
+                       BUG_ON(rs_flags & LC_DIRTY);
+                       goto try_again;
+               }
+               if (bm_ext->lce.lc_number != enr) {
+                       bm_ext->rs_left = drbd_bm_e_weight(mdev, enr);
+                       bm_ext->rs_failed = 0;
+                       lc_changed(mdev->resync, &bm_ext->lce);
+                       wake_up(&mdev->al_wait);
+                       D_ASSERT(test_bit(BME_LOCKED, &bm_ext->flags) == 0);
+               }
+               set_bit(BME_NO_WRITES, &bm_ext->flags);
+               D_ASSERT(bm_ext->lce.refcnt == 1);
+               mdev->resync_locked++;
+               goto check_al;
+       }
+check_al:
+       for (i = 0; i < AL_EXT_PER_BM_SECT; i++) {
+               if (unlikely(al_enr+i == mdev->act_log->new_number))
+                       goto try_again;
+               if (lc_is_used(mdev->act_log, al_enr+i))
+                       goto try_again;
+       }
+       set_bit(BME_LOCKED, &bm_ext->flags);
+proceed:
+       mdev->resync_wenr = LC_FREE;
+       spin_unlock_irq(&mdev->al_lock);
+       return 0;
+
+try_again:
+       if (bm_ext)
+               mdev->resync_wenr = enr;
+       spin_unlock_irq(&mdev->al_lock);
+       return -EAGAIN;
+}
+
+void drbd_rs_complete_io(struct drbd_conf *mdev, sector_t sector)
+{
+       unsigned int enr = BM_SECT_TO_EXT(sector);
+       struct lc_element *e;
+       struct bm_extent *bm_ext;
+       unsigned long flags;
+
+       spin_lock_irqsave(&mdev->al_lock, flags);
+       e = lc_find(mdev->resync, enr);
+       bm_ext = e ? lc_entry(e, struct bm_extent, lce) : NULL;
+       if (!bm_ext) {
+               spin_unlock_irqrestore(&mdev->al_lock, flags);
+               if (__ratelimit(&drbd_ratelimit_state))
+                       dev_err(DEV, "drbd_rs_complete_io() called, but extent not found\n");
+               return;
+       }
+
+       if (bm_ext->lce.refcnt == 0) {
+               spin_unlock_irqrestore(&mdev->al_lock, flags);
+               dev_err(DEV, "drbd_rs_complete_io(,%llu [=%u]) called, "
+                   "but refcnt is 0!?\n",
+                   (unsigned long long)sector, enr);
+               return;
+       }
+
+       if (lc_put(mdev->resync, &bm_ext->lce) == 0) {
+               clear_bit(BME_LOCKED, &bm_ext->flags);
+               clear_bit(BME_NO_WRITES, &bm_ext->flags);
+               mdev->resync_locked--;
+               wake_up(&mdev->al_wait);
+       }
+
+       spin_unlock_irqrestore(&mdev->al_lock, flags);
+}
+
+/**
+ * drbd_rs_cancel_all() - Removes all extents from the resync LRU (even BME_LOCKED)
+ * @mdev:      DRBD device.
+ */
+void drbd_rs_cancel_all(struct drbd_conf *mdev)
+{
+       spin_lock_irq(&mdev->al_lock);
+
+       if (get_ldev_if_state(mdev, D_FAILED)) { /* Makes sure ->resync is there. */
+               lc_reset(mdev->resync);
+               put_ldev(mdev);
+       }
+       mdev->resync_locked = 0;
+       mdev->resync_wenr = LC_FREE;
+       spin_unlock_irq(&mdev->al_lock);
+       wake_up(&mdev->al_wait);
+}
+
+/**
+ * drbd_rs_del_all() - Gracefully remove all extents from the resync LRU
+ * @mdev:      DRBD device.
+ *
+ * Returns 0 upon success, -EAGAIN if at least one reference count was
+ * not zero.
+ */
+int drbd_rs_del_all(struct drbd_conf *mdev)
+{
+       struct lc_element *e;
+       struct bm_extent *bm_ext;
+       int i;
+
+       spin_lock_irq(&mdev->al_lock);
+
+       if (get_ldev_if_state(mdev, D_FAILED)) {
+               /* ok, ->resync is there. */
+               for (i = 0; i < mdev->resync->nr_elements; i++) {
+                       e = lc_element_by_index(mdev->resync, i);
+                       bm_ext = e ? lc_entry(e, struct bm_extent, lce) : NULL;
+                       if (bm_ext->lce.lc_number == LC_FREE)
+                               continue;
+                       if (bm_ext->lce.lc_number == mdev->resync_wenr) {
+                               dev_info(DEV, "dropping %u in drbd_rs_del_all, apparently"
+                                    " got 'synced' by application io\n",
+                                    mdev->resync_wenr);
+                               D_ASSERT(!test_bit(BME_LOCKED, &bm_ext->flags));
+                               D_ASSERT(test_bit(BME_NO_WRITES, &bm_ext->flags));
+                               clear_bit(BME_NO_WRITES, &bm_ext->flags);
+                               mdev->resync_wenr = LC_FREE;
+                               lc_put(mdev->resync, &bm_ext->lce);
+                       }
+                       if (bm_ext->lce.refcnt != 0) {
+                               dev_info(DEV, "Retrying drbd_rs_del_all() later. "
+                                    "refcnt=%d\n", bm_ext->lce.refcnt);
+                               put_ldev(mdev);
+                               spin_unlock_irq(&mdev->al_lock);
+                               return -EAGAIN;
+                       }
+                       D_ASSERT(!test_bit(BME_LOCKED, &bm_ext->flags));
+                       D_ASSERT(!test_bit(BME_NO_WRITES, &bm_ext->flags));
+                       lc_del(mdev->resync, &bm_ext->lce);
+               }
+               D_ASSERT(mdev->resync->used == 0);
+               put_ldev(mdev);
+       }
+       spin_unlock_irq(&mdev->al_lock);
+
+       return 0;
+}
+
+/**
+ * drbd_rs_failed_io() - Record information on a failure to resync the specified blocks
+ * @mdev:      DRBD device.
+ * @sector:    The sector number.
+ * @size:      Size of failed IO operation, in byte.
+ */
+void drbd_rs_failed_io(struct drbd_conf *mdev, sector_t sector, int size)
+{
+       /* Is called from worker and receiver context _only_ */
+       unsigned long sbnr, ebnr, lbnr;
+       unsigned long count;
+       sector_t esector, nr_sectors;
+       int wake_up = 0;
+
+       if (size <= 0 || (size & 0x1ff) != 0 || size > DRBD_MAX_SEGMENT_SIZE) {
+               dev_err(DEV, "drbd_rs_failed_io: sector=%llus size=%d nonsense!\n",
+                               (unsigned long long)sector, size);
+               return;
+       }
+       nr_sectors = drbd_get_capacity(mdev->this_bdev);
+       esector = sector + (size >> 9) - 1;
+
+       ERR_IF(sector >= nr_sectors) return;
+       ERR_IF(esector >= nr_sectors) esector = (nr_sectors-1);
+
+       lbnr = BM_SECT_TO_BIT(nr_sectors-1);
+
+       /*
+        * round up start sector, round down end sector.  we make sure we only
+        * handle full, aligned, BM_BLOCK_SIZE (4K) blocks */
+       if (unlikely(esector < BM_SECT_PER_BIT-1))
+               return;
+       if (unlikely(esector == (nr_sectors-1)))
+               ebnr = lbnr;
+       else
+               ebnr = BM_SECT_TO_BIT(esector - (BM_SECT_PER_BIT-1));
+       sbnr = BM_SECT_TO_BIT(sector + BM_SECT_PER_BIT-1);
+
+       if (sbnr > ebnr)
+               return;
+
+       /*
+        * ok, (capacity & 7) != 0 sometimes, but who cares...
+        * we count rs_{total,left} in bits, not sectors.
+        */
+       spin_lock_irq(&mdev->al_lock);
+       count = drbd_bm_count_bits(mdev, sbnr, ebnr);
+       if (count) {
+               mdev->rs_failed += count;
+
+               if (get_ldev(mdev)) {
+                       drbd_try_clear_on_disk_bm(mdev, sector, count, FALSE);
+                       put_ldev(mdev);
+               }
+
+               /* just wake_up unconditional now, various lc_chaged(),
+                * lc_put() in drbd_try_clear_on_disk_bm(). */
+               wake_up = 1;
+       }
+       spin_unlock_irq(&mdev->al_lock);
+       if (wake_up)
+               wake_up(&mdev->al_wait);
+}
diff --git a/drivers/block/drbd/drbd_bitmap.c b/drivers/block/drbd/drbd_bitmap.c
new file mode 100644 (file)
index 0000000..b61057e
--- /dev/null
@@ -0,0 +1,1327 @@
+/*
+   drbd_bitmap.c
+
+   This file is part of DRBD by Philipp Reisner and Lars Ellenberg.
+
+   Copyright (C) 2004-2008, LINBIT Information Technologies GmbH.
+   Copyright (C) 2004-2008, Philipp Reisner <philipp.reisner@linbit.com>.
+   Copyright (C) 2004-2008, Lars Ellenberg <lars.ellenberg@linbit.com>.
+
+   drbd is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   drbd 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 drbd; see the file COPYING.  If not, write to
+   the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/bitops.h>
+#include <linux/vmalloc.h>
+#include <linux/string.h>
+#include <linux/drbd.h>
+#include <asm/kmap_types.h>
+#include "drbd_int.h"
+
+/* OPAQUE outside this file!
+ * interface defined in drbd_int.h
+
+ * convention:
+ * function name drbd_bm_... => used elsewhere, "public".
+ * function name      bm_... => internal to implementation, "private".
+
+ * Note that since find_first_bit returns int, at the current granularity of
+ * the bitmap (4KB per byte), this implementation "only" supports up to
+ * 1<<(32+12) == 16 TB...
+ */
+
+/*
+ * NOTE
+ *  Access to the *bm_pages is protected by bm_lock.
+ *  It is safe to read the other members within the lock.
+ *
+ *  drbd_bm_set_bits is called from bio_endio callbacks,
+ *  We may be called with irq already disabled,
+ *  so we need spin_lock_irqsave().
+ *  And we need the kmap_atomic.
+ */
+struct drbd_bitmap {
+       struct page **bm_pages;
+       spinlock_t bm_lock;
+       /* WARNING unsigned long bm_*:
+        * 32bit number of bit offset is just enough for 512 MB bitmap.
+        * it will blow up if we make the bitmap bigger...
+        * not that it makes much sense to have a bitmap that large,
+        * rather change the granularity to 16k or 64k or something.
+        * (that implies other problems, however...)
+        */
+       unsigned long bm_set;       /* nr of set bits; THINK maybe atomic_t? */
+       unsigned long bm_bits;
+       size_t   bm_words;
+       size_t   bm_number_of_pages;
+       sector_t bm_dev_capacity;
+       struct semaphore bm_change; /* serializes resize operations */
+
+       atomic_t bm_async_io;
+       wait_queue_head_t bm_io_wait;
+
+       unsigned long  bm_flags;
+
+       /* debugging aid, in case we are still racy somewhere */
+       char          *bm_why;
+       struct task_struct *bm_task;
+};
+
+/* definition of bits in bm_flags */
+#define BM_LOCKED       0
+#define BM_MD_IO_ERROR  1
+#define BM_P_VMALLOCED  2
+
+static int bm_is_locked(struct drbd_bitmap *b)
+{
+       return test_bit(BM_LOCKED, &b->bm_flags);
+}
+
+#define bm_print_lock_info(m) __bm_print_lock_info(m, __func__)
+static void __bm_print_lock_info(struct drbd_conf *mdev, const char *func)
+{
+       struct drbd_bitmap *b = mdev->bitmap;
+       if (!__ratelimit(&drbd_ratelimit_state))
+               return;
+       dev_err(DEV, "FIXME %s in %s, bitmap locked for '%s' by %s\n",
+           current == mdev->receiver.task ? "receiver" :
+           current == mdev->asender.task  ? "asender"  :
+           current == mdev->worker.task   ? "worker"   : current->comm,
+           func, b->bm_why ?: "?",
+           b->bm_task == mdev->receiver.task ? "receiver" :
+           b->bm_task == mdev->asender.task  ? "asender"  :
+           b->bm_task == mdev->worker.task   ? "worker"   : "?");
+}
+
+void drbd_bm_lock(struct drbd_conf *mdev, char *why)
+{
+       struct drbd_bitmap *b = mdev->bitmap;
+       int trylock_failed;
+
+       if (!b) {
+               dev_err(DEV, "FIXME no bitmap in drbd_bm_lock!?\n");
+               return;
+       }
+
+       trylock_failed = down_trylock(&b->bm_change);
+
+       if (trylock_failed) {
+               dev_warn(DEV, "%s going to '%s' but bitmap already locked for '%s' by %s\n",
+                   current == mdev->receiver.task ? "receiver" :
+                   current == mdev->asender.task  ? "asender"  :
+                   current == mdev->worker.task   ? "worker"   : current->comm,
+                   why, b->bm_why ?: "?",
+                   b->bm_task == mdev->receiver.task ? "receiver" :
+                   b->bm_task == mdev->asender.task  ? "asender"  :
+                   b->bm_task == mdev->worker.task   ? "worker"   : "?");
+               down(&b->bm_change);
+       }
+       if (__test_and_set_bit(BM_LOCKED, &b->bm_flags))
+               dev_err(DEV, "FIXME bitmap already locked in bm_lock\n");
+
+       b->bm_why  = why;
+       b->bm_task = current;
+}
+
+void drbd_bm_unlock(struct drbd_conf *mdev)
+{
+       struct drbd_bitmap *b = mdev->bitmap;
+       if (!b) {
+               dev_err(DEV, "FIXME no bitmap in drbd_bm_unlock!?\n");
+               return;
+       }
+
+       if (!__test_and_clear_bit(BM_LOCKED, &mdev->bitmap->bm_flags))
+               dev_err(DEV, "FIXME bitmap not locked in bm_unlock\n");
+
+       b->bm_why  = NULL;
+       b->bm_task = NULL;
+       up(&b->bm_change);
+}
+
+/* word offset to long pointer */
+static unsigned long *__bm_map_paddr(struct drbd_bitmap *b, unsigned long offset, const enum km_type km)
+{
+       struct page *page;
+       unsigned long page_nr;
+
+       /* page_nr = (word*sizeof(long)) >> PAGE_SHIFT; */
+       page_nr = offset >> (PAGE_SHIFT - LN2_BPL + 3);
+       BUG_ON(page_nr >= b->bm_number_of_pages);
+       page = b->bm_pages[page_nr];
+
+       return (unsigned long *) kmap_atomic(page, km);
+}
+
+static unsigned long * bm_map_paddr(struct drbd_bitmap *b, unsigned long offset)
+{
+       return __bm_map_paddr(b, offset, KM_IRQ1);
+}
+
+static void __bm_unmap(unsigned long *p_addr, const enum km_type km)
+{
+       kunmap_atomic(p_addr, km);
+};
+
+static void bm_unmap(unsigned long *p_addr)
+{
+       return __bm_unmap(p_addr, KM_IRQ1);
+}
+
+/* long word offset of _bitmap_ sector */
+#define S2W(s) ((s)<<(BM_EXT_SHIFT-BM_BLOCK_SHIFT-LN2_BPL))
+/* word offset from start of bitmap to word number _in_page_
+ * modulo longs per page
+#define MLPP(X) ((X) % (PAGE_SIZE/sizeof(long))
+ hm, well, Philipp thinks gcc might not optimze the % into & (... - 1)
+ so do it explicitly:
+ */
+#define MLPP(X) ((X) & ((PAGE_SIZE/sizeof(long))-1))
+
+/* Long words per page */
+#define LWPP (PAGE_SIZE/sizeof(long))
+
+/*
+ * actually most functions herein should take a struct drbd_bitmap*, not a
+ * struct drbd_conf*, but for the debug macros I like to have the mdev around
+ * to be able to report device specific.
+ */
+
+static void bm_free_pages(struct page **pages, unsigned long number)
+{
+       unsigned long i;
+       if (!pages)
+               return;
+
+       for (i = 0; i < number; i++) {
+               if (!pages[i]) {
+                       printk(KERN_ALERT "drbd: bm_free_pages tried to free "
+                                         "a NULL pointer; i=%lu n=%lu\n",
+                                         i, number);
+                       continue;
+               }
+               __free_page(pages[i]);
+               pages[i] = NULL;
+       }
+}
+
+static void bm_vk_free(void *ptr, int v)
+{
+       if (v)
+               vfree(ptr);
+       else
+               kfree(ptr);
+}
+
+/*
+ * "have" and "want" are NUMBER OF PAGES.
+ */
+static struct page **bm_realloc_pages(struct drbd_bitmap *b, unsigned long want)
+{
+       struct page **old_pages = b->bm_pages;
+       struct page **new_pages, *page;
+       unsigned int i, bytes, vmalloced = 0;
+       unsigned long have = b->bm_number_of_pages;
+
+       BUG_ON(have == 0 && old_pages != NULL);
+       BUG_ON(have != 0 && old_pages == NULL);
+
+       if (have == want)
+               return old_pages;
+
+       /* Trying kmalloc first, falling back to vmalloc.
+        * GFP_KERNEL is ok, as this is done when a lower level disk is
+        * "attached" to the drbd.  Context is receiver thread or cqueue
+        * thread.  As we have no disk yet, we are not in the IO path,
+        * not even the IO path of the peer. */
+       bytes = sizeof(struct page *)*want;
+       new_pages = kmalloc(bytes, GFP_KERNEL);
+       if (!new_pages) {
+               new_pages = vmalloc(bytes);
+               if (!new_pages)
+                       return NULL;
+               vmalloced = 1;
+       }
+
+       memset(new_pages, 0, bytes);
+       if (want >= have) {
+               for (i = 0; i < have; i++)
+                       new_pages[i] = old_pages[i];
+               for (; i < want; i++) {
+                       page = alloc_page(GFP_HIGHUSER);
+                       if (!page) {
+                               bm_free_pages(new_pages + have, i - have);
+                               bm_vk_free(new_pages, vmalloced);
+                               return NULL;
+                       }
+                       new_pages[i] = page;
+               }
+       } else {
+               for (i = 0; i < want; i++)
+                       new_pages[i] = old_pages[i];
+               /* NOT HERE, we are outside the spinlock!
+               bm_free_pages(old_pages + want, have - want);
+               */
+       }
+
+       if (vmalloced)
+               set_bit(BM_P_VMALLOCED, &b->bm_flags);
+       else
+               clear_bit(BM_P_VMALLOCED, &b->bm_flags);
+
+       return new_pages;
+}
+
+/*
+ * called on driver init only. TODO call when a device is created.
+ * allocates the drbd_bitmap, and stores it in mdev->bitmap.
+ */
+int drbd_bm_init(struct drbd_conf *mdev)
+{
+       struct drbd_bitmap *b = mdev->bitmap;
+       WARN_ON(b != NULL);
+       b = kzalloc(sizeof(struct drbd_bitmap), GFP_KERNEL);
+       if (!b)
+               return -ENOMEM;
+       spin_lock_init(&b->bm_lock);
+       init_MUTEX(&b->bm_change);
+       init_waitqueue_head(&b->bm_io_wait);
+
+       mdev->bitmap = b;
+
+       return 0;
+}
+
+sector_t drbd_bm_capacity(struct drbd_conf *mdev)
+{
+       ERR_IF(!mdev->bitmap) return 0;
+       return mdev->bitmap->bm_dev_capacity;
+}
+
+/* called on driver unload. TODO: call when a device is destroyed.
+ */
+void drbd_bm_cleanup(struct drbd_conf *mdev)
+{
+       ERR_IF (!mdev->bitmap) return;
+       bm_free_pages(mdev->bitmap->bm_pages, mdev->bitmap->bm_number_of_pages);
+       bm_vk_free(mdev->bitmap->bm_pages, test_bit(BM_P_VMALLOCED, &mdev->bitmap->bm_flags));
+       kfree(mdev->bitmap);
+       mdev->bitmap = NULL;
+}
+
+/*
+ * since (b->bm_bits % BITS_PER_LONG) != 0,
+ * this masks out the remaining bits.
+ * Returns the number of bits cleared.
+ */
+static int bm_clear_surplus(struct drbd_bitmap *b)
+{
+       const unsigned long mask = (1UL << (b->bm_bits & (BITS_PER_LONG-1))) - 1;
+       size_t w = b->bm_bits >> LN2_BPL;
+       int cleared = 0;
+       unsigned long *p_addr, *bm;
+
+       p_addr = bm_map_paddr(b, w);
+       bm = p_addr + MLPP(w);
+       if (w < b->bm_words) {
+               cleared = hweight_long(*bm & ~mask);
+               *bm &= mask;
+               w++; bm++;
+       }
+
+       if (w < b->bm_words) {
+               cleared += hweight_long(*bm);
+               *bm = 0;
+       }
+       bm_unmap(p_addr);
+       return cleared;
+}
+
+static void bm_set_surplus(struct drbd_bitmap *b)
+{
+       const unsigned long mask = (1UL << (b->bm_bits & (BITS_PER_LONG-1))) - 1;
+       size_t w = b->bm_bits >> LN2_BPL;
+       unsigned long *p_addr, *bm;
+
+       p_addr = bm_map_paddr(b, w);
+       bm = p_addr + MLPP(w);
+       if (w < b->bm_words) {
+               *bm |= ~mask;
+               bm++; w++;
+       }
+
+       if (w < b->bm_words) {
+               *bm = ~(0UL);
+       }
+       bm_unmap(p_addr);
+}
+
+static unsigned long __bm_count_bits(struct drbd_bitmap *b, const int swap_endian)
+{
+       unsigned long *p_addr, *bm, offset = 0;
+       unsigned long bits = 0;
+       unsigned long i, do_now;
+
+       while (offset < b->bm_words) {
+               i = do_now = min_t(size_t, b->bm_words-offset, LWPP);
+               p_addr = __bm_map_paddr(b, offset, KM_USER0);
+               bm = p_addr + MLPP(offset);
+               while (i--) {
+#ifndef __LITTLE_ENDIAN
+                       if (swap_endian)
+                               *bm = lel_to_cpu(*bm);
+#endif
+                       bits += hweight_long(*bm++);
+               }
+               __bm_unmap(p_addr, KM_USER0);
+               offset += do_now;
+               cond_resched();
+       }
+
+       return bits;
+}
+
+static unsigned long bm_count_bits(struct drbd_bitmap *b)
+{
+       return __bm_count_bits(b, 0);
+}
+
+static unsigned long bm_count_bits_swap_endian(struct drbd_bitmap *b)
+{
+       return __bm_count_bits(b, 1);
+}
+
+/* offset and len in long words.*/
+static void bm_memset(struct drbd_bitmap *b, size_t offset, int c, size_t len)
+{
+       unsigned long *p_addr, *bm;
+       size_t do_now, end;
+
+#define BM_SECTORS_PER_BIT (BM_BLOCK_SIZE/512)
+
+       end = offset + len;
+
+       if (end > b->bm_words) {
+               printk(KERN_ALERT "drbd: bm_memset end > bm_words\n");
+               return;
+       }
+
+       while (offset < end) {
+               do_now = min_t(size_t, ALIGN(offset + 1, LWPP), end) - offset;
+               p_addr = bm_map_paddr(b, offset);
+               bm = p_addr + MLPP(offset);
+               if (bm+do_now > p_addr + LWPP) {
+                       printk(KERN_ALERT "drbd: BUG BUG BUG! p_addr:%p bm:%p do_now:%d\n",
+                              p_addr, bm, (int)do_now);
+                       break; /* breaks to after catch_oob_access_end() only! */
+               }
+               memset(bm, c, do_now * sizeof(long));
+               bm_unmap(p_addr);
+               offset += do_now;
+       }
+}
+
+/*
+ * make sure the bitmap has enough room for the attached storage,
+ * if necessary, resize.
+ * called whenever we may have changed the device size.
+ * returns -ENOMEM if we could not allocate enough memory, 0 on success.
+ * In case this is actually a resize, we copy the old bitmap into the new one.
+ * Otherwise, the bitmap is initialized to all bits set.
+ */
+int drbd_bm_resize(struct drbd_conf *mdev, sector_t capacity)
+{
+       struct drbd_bitmap *b = mdev->bitmap;
+       unsigned long bits, words, owords, obits, *p_addr, *bm;
+       unsigned long want, have, onpages; /* number of pages */
+       struct page **npages, **opages = NULL;
+       int err = 0, growing;
+       int opages_vmalloced;
+
+       ERR_IF(!b) return -ENOMEM;
+
+       drbd_bm_lock(mdev, "resize");
+
+       dev_info(DEV, "drbd_bm_resize called with capacity == %llu\n",
+                       (unsigned long long)capacity);
+
+       if (capacity == b->bm_dev_capacity)
+               goto out;
+
+       opages_vmalloced = test_bit(BM_P_VMALLOCED, &b->bm_flags);
+
+       if (capacity == 0) {
+               spin_lock_irq(&b->bm_lock);
+               opages = b->bm_pages;
+               onpages = b->bm_number_of_pages;
+               owords = b->bm_words;
+               b->bm_pages = NULL;
+               b->bm_number_of_pages =
+               b->bm_set   =
+               b->bm_bits  =
+               b->bm_words =
+               b->bm_dev_capacity = 0;
+               spin_unlock_irq(&b->bm_lock);
+               bm_free_pages(opages, onpages);
+               bm_vk_free(opages, opages_vmalloced);
+               goto out;
+       }
+       bits  = BM_SECT_TO_BIT(ALIGN(capacity, BM_SECT_PER_BIT));
+
+       /* if we would use
+          words = ALIGN(bits,BITS_PER_LONG) >> LN2_BPL;
+          a 32bit host could present the wrong number of words
+          to a 64bit host.
+       */
+       words = ALIGN(bits, 64) >> LN2_BPL;
+
+       if (get_ldev(mdev)) {
+               D_ASSERT((u64)bits <= (((u64)mdev->ldev->md.md_size_sect-MD_BM_OFFSET) << 12));
+               put_ldev(mdev);
+       }
+
+       /* one extra long to catch off by one errors */
+       want = ALIGN((words+1)*sizeof(long), PAGE_SIZE) >> PAGE_SHIFT;
+       have = b->bm_number_of_pages;
+       if (want == have) {
+               D_ASSERT(b->bm_pages != NULL);
+               npages = b->bm_pages;
+       } else {
+               if (FAULT_ACTIVE(mdev, DRBD_FAULT_BM_ALLOC))
+                       npages = NULL;
+               else
+                       npages = bm_realloc_pages(b, want);
+       }
+
+       if (!npages) {
+               err = -ENOMEM;
+               goto out;
+       }
+
+       spin_lock_irq(&b->bm_lock);
+       opages = b->bm_pages;
+       owords = b->bm_words;
+       obits  = b->bm_bits;
+
+       growing = bits > obits;
+       if (opages)
+               bm_set_surplus(b);
+
+       b->bm_pages = npages;
+       b->bm_number_of_pages = want;
+       b->bm_bits  = bits;
+       b->bm_words = words;
+       b->bm_dev_capacity = capacity;
+
+       if (growing) {
+               bm_memset(b, owords, 0xff, words-owords);
+               b->bm_set += bits - obits;
+       }
+
+       if (want < have) {
+               /* implicit: (opages != NULL) && (opages != npages) */
+               bm_free_pages(opages + want, have - want);
+       }
+
+       p_addr = bm_map_paddr(b, words);
+       bm = p_addr + MLPP(words);
+       *bm = DRBD_MAGIC;
+       bm_unmap(p_addr);
+
+       (void)bm_clear_surplus(b);
+
+       spin_unlock_irq(&b->bm_lock);
+       if (opages != npages)
+               bm_vk_free(opages, opages_vmalloced);
+       if (!growing)
+               b->bm_set = bm_count_bits(b);
+       dev_info(DEV, "resync bitmap: bits=%lu words=%lu\n", bits, words);
+
+ out:
+       drbd_bm_unlock(mdev);
+       return err;
+}
+
+/* inherently racy:
+ * if not protected by other means, return value may be out of date when
+ * leaving this function...
+ * we still need to lock it, since it is important that this returns
+ * bm_set == 0 precisely.
+ *
+ * maybe bm_set should be atomic_t ?
+ */
+static unsigned long _drbd_bm_total_weight(struct drbd_conf *mdev)
+{
+       struct drbd_bitmap *b = mdev->bitmap;
+       unsigned long s;
+       unsigned long flags;
+
+       ERR_IF(!b) return 0;
+       ERR_IF(!b->bm_pages) return 0;
+
+       spin_lock_irqsave(&b->bm_lock, flags);
+       s = b->bm_set;
+       spin_unlock_irqrestore(&b->bm_lock, flags);
+
+       return s;
+}
+
+unsigned long drbd_bm_total_weight(struct drbd_conf *mdev)
+{
+       unsigned long s;
+       /* if I don't have a disk, I don't know about out-of-sync status */
+       if (!get_ldev_if_state(mdev, D_NEGOTIATING))
+               return 0;
+       s = _drbd_bm_total_weight(mdev);
+       put_ldev(mdev);
+       return s;
+}
+
+size_t drbd_bm_words(struct drbd_conf *mdev)
+{
+       struct drbd_bitmap *b = mdev->bitmap;
+       ERR_IF(!b) return 0;
+       ERR_IF(!b->bm_pages) return 0;
+
+       return b->bm_words;
+}
+
+unsigned long drbd_bm_bits(struct drbd_conf *mdev)
+{
+       struct drbd_bitmap *b = mdev->bitmap;
+       ERR_IF(!b) return 0;
+
+       return b->bm_bits;
+}
+
+/* merge number words from buffer into the bitmap starting at offset.
+ * buffer[i] is expected to be little endian unsigned long.
+ * bitmap must be locked by drbd_bm_lock.
+ * currently only used from receive_bitmap.
+ */
+void drbd_bm_merge_lel(struct drbd_conf *mdev, size_t offset, size_t number,
+                       unsigned long *buffer)
+{
+       struct drbd_bitmap *b = mdev->bitmap;
+       unsigned long *p_addr, *bm;
+       unsigned long word, bits;
+       size_t end, do_now;
+
+       end = offset + number;
+
+       ERR_IF(!b) return;
+       ERR_IF(!b->bm_pages) return;
+       if (number == 0)
+               return;
+       WARN_ON(offset >= b->bm_words);
+       WARN_ON(end    >  b->bm_words);
+
+       spin_lock_irq(&b->bm_lock);
+       while (offset < end) {
+               do_now = min_t(size_t, ALIGN(offset+1, LWPP), end) - offset;
+               p_addr = bm_map_paddr(b, offset);
+               bm = p_addr + MLPP(offset);
+               offset += do_now;
+               while (do_now--) {
+                       bits = hweight_long(*bm);
+                       word = *bm | lel_to_cpu(*buffer++);
+                       *bm++ = word;
+                       b->bm_set += hweight_long(word) - bits;
+               }
+               bm_unmap(p_addr);
+       }
+       /* with 32bit <-> 64bit cross-platform connect
+        * this is only correct for current usage,
+        * where we _know_ that we are 64 bit aligned,
+        * and know that this function is used in this way, too...
+        */
+       if (end == b->bm_words)
+               b->bm_set -= bm_clear_surplus(b);
+
+       spin_unlock_irq(&b->bm_lock);
+}
+
+/* copy number words from the bitmap starting at offset into the buffer.
+ * buffer[i] will be little endian unsigned long.
+ */
+void drbd_bm_get_lel(struct drbd_conf *mdev, size_t offset, size_t number,
+                    unsigned long *buffer)
+{
+       struct drbd_bitmap *b = mdev->bitmap;
+       unsigned long *p_addr, *bm;
+       size_t end, do_now;
+
+       end = offset + number;
+
+       ERR_IF(!b) return;
+       ERR_IF(!b->bm_pages) return;
+
+       spin_lock_irq(&b->bm_lock);
+       if ((offset >= b->bm_words) ||
+           (end    >  b->bm_words) ||
+           (number <= 0))
+               dev_err(DEV, "offset=%lu number=%lu bm_words=%lu\n",
+                       (unsigned long) offset,
+                       (unsigned long) number,
+                       (unsigned long) b->bm_words);
+       else {
+               while (offset < end) {
+                       do_now = min_t(size_t, ALIGN(offset+1, LWPP), end) - offset;
+                       p_addr = bm_map_paddr(b, offset);
+                       bm = p_addr + MLPP(offset);
+                       offset += do_now;
+                       while (do_now--)
+                               *buffer++ = cpu_to_lel(*bm++);
+                       bm_unmap(p_addr);
+               }
+       }
+       spin_unlock_irq(&b->bm_lock);
+}
+
+/* set all bits in the bitmap */
+void drbd_bm_set_all(struct drbd_conf *mdev)
+{
+       struct drbd_bitmap *b = mdev->bitmap;
+       ERR_IF(!b) return;
+       ERR_IF(!b->bm_pages) return;
+
+       spin_lock_irq(&b->bm_lock);
+       bm_memset(b, 0, 0xff, b->bm_words);
+       (void)bm_clear_surplus(b);
+       b->bm_set = b->bm_bits;
+       spin_unlock_irq(&b->bm_lock);
+}
+
+/* clear all bits in the bitmap */
+void drbd_bm_clear_all(struct drbd_conf *mdev)
+{
+       struct drbd_bitmap *b = mdev->bitmap;
+       ERR_IF(!b) return;
+       ERR_IF(!b->bm_pages) return;
+
+       spin_lock_irq(&b->bm_lock);
+       bm_memset(b, 0, 0, b->bm_words);
+       b->bm_set = 0;
+       spin_unlock_irq(&b->bm_lock);
+}
+
+static void bm_async_io_complete(struct bio *bio, int error)
+{
+       struct drbd_bitmap *b = bio->bi_private;
+       int uptodate = bio_flagged(bio, BIO_UPTODATE);
+
+
+       /* strange behavior of some lower level drivers...
+        * fail the request by clearing the uptodate flag,
+        * but do not return any error?!
+        * do we want to WARN() on this? */
+       if (!error && !uptodate)
+               error = -EIO;
+
+       if (error) {
+               /* doh. what now?
+                * for now, set all bits, and flag MD_IO_ERROR */
+               __set_bit(BM_MD_IO_ERROR, &b->bm_flags);
+       }
+       if (atomic_dec_and_test(&b->bm_async_io))
+               wake_up(&b->bm_io_wait);
+
+       bio_put(bio);
+}
+
+static void bm_page_io_async(struct drbd_conf *mdev, struct drbd_bitmap *b, int page_nr, int rw) __must_hold(local)
+{
+       /* we are process context. we always get a bio */
+       struct bio *bio = bio_alloc(GFP_KERNEL, 1);
+       unsigned int len;
+       sector_t on_disk_sector =
+               mdev->ldev->md.md_offset + mdev->ldev->md.bm_offset;
+       on_disk_sector += ((sector_t)page_nr) << (PAGE_SHIFT-9);
+
+       /* this might happen with very small
+        * flexible external meta data device */
+       len = min_t(unsigned int, PAGE_SIZE,
+               (drbd_md_last_sector(mdev->ldev) - on_disk_sector + 1)<<9);
+
+       bio->bi_bdev = mdev->ldev->md_bdev;
+       bio->bi_sector = on_disk_sector;
+       bio_add_page(bio, b->bm_pages[page_nr], len, 0);
+       bio->bi_private = b;
+       bio->bi_end_io = bm_async_io_complete;
+
+       if (FAULT_ACTIVE(mdev, (rw & WRITE) ? DRBD_FAULT_MD_WR : DRBD_FAULT_MD_RD)) {
+               bio->bi_rw |= rw;
+               bio_endio(bio, -EIO);
+       } else {
+               submit_bio(rw, bio);
+       }
+}
+
+# if defined(__LITTLE_ENDIAN)
+       /* nothing to do, on disk == in memory */
+# define bm_cpu_to_lel(x) ((void)0)
+# else
+void bm_cpu_to_lel(struct drbd_bitmap *b)
+{
+       /* need to cpu_to_lel all the pages ...
+        * this may be optimized by using
+        * cpu_to_lel(-1) == -1 and cpu_to_lel(0) == 0;
+        * the following is still not optimal, but better than nothing */
+       unsigned int i;
+       unsigned long *p_addr, *bm;
+       if (b->bm_set == 0) {
+               /* no page at all; avoid swap if all is 0 */
+               i = b->bm_number_of_pages;
+       } else if (b->bm_set == b->bm_bits) {
+               /* only the last page */
+               i = b->bm_number_of_pages - 1;
+       } else {
+               /* all pages */
+               i = 0;
+       }
+       for (; i < b->bm_number_of_pages; i++) {
+               p_addr = kmap_atomic(b->bm_pages[i], KM_USER0);
+               for (bm = p_addr; bm < p_addr + PAGE_SIZE/sizeof(long); bm++)
+                       *bm = cpu_to_lel(*bm);
+               kunmap_atomic(p_addr, KM_USER0);
+       }
+}
+# endif
+/* lel_to_cpu == cpu_to_lel */
+# define bm_lel_to_cpu(x) bm_cpu_to_lel(x)
+
+/*
+ * bm_rw: read/write the whole bitmap from/to its on disk location.
+ */
+static int bm_rw(struct drbd_conf *mdev, int rw) __must_hold(local)
+{
+       struct drbd_bitmap *b = mdev->bitmap;
+       /* sector_t sector; */
+       int bm_words, num_pages, i;
+       unsigned long now;
+       char ppb[10];
+       int err = 0;
+
+       WARN_ON(!bm_is_locked(b));
+
+       /* no spinlock here, the drbd_bm_lock should be enough! */
+
+       bm_words  = drbd_bm_words(mdev);
+       num_pages = (bm_words*sizeof(long) + PAGE_SIZE-1) >> PAGE_SHIFT;
+
+       /* on disk bitmap is little endian */
+       if (rw == WRITE)
+               bm_cpu_to_lel(b);
+
+       now = jiffies;
+       atomic_set(&b->bm_async_io, num_pages);
+       __clear_bit(BM_MD_IO_ERROR, &b->bm_flags);
+
+       /* let the layers below us try to merge these bios... */
+       for (i = 0; i < num_pages; i++)
+               bm_page_io_async(mdev, b, i, rw);
+
+       drbd_blk_run_queue(bdev_get_queue(mdev->ldev->md_bdev));
+       wait_event(b->bm_io_wait, atomic_read(&b->bm_async_io) == 0);
+
+       if (test_bit(BM_MD_IO_ERROR, &b->bm_flags)) {
+               dev_alert(DEV, "we had at least one MD IO ERROR during bitmap IO\n");
+               drbd_chk_io_error(mdev, 1, TRUE);
+               err = -EIO;
+       }
+
+       now = jiffies;
+       if (rw == WRITE) {
+               /* swap back endianness */
+               bm_lel_to_cpu(b);
+               /* flush bitmap to stable storage */
+               drbd_md_flush(mdev);
+       } else /* rw == READ */ {
+               /* just read, if necessary adjust endianness */
+               b->bm_set = bm_count_bits_swap_endian(b);
+               dev_info(DEV, "recounting of set bits took additional %lu jiffies\n",
+                    jiffies - now);
+       }
+       now = b->bm_set;
+
+       dev_info(DEV, "%s (%lu bits) marked out-of-sync by on disk bit-map.\n",
+            ppsize(ppb, now << (BM_BLOCK_SHIFT-10)), now);
+
+       return err;
+}
+
+/**
+ * drbd_bm_read() - Read the whole bitmap from its on disk location.
+ * @mdev:      DRBD device.
+ */
+int drbd_bm_read(struct drbd_conf *mdev) __must_hold(local)
+{
+       return bm_rw(mdev, READ);
+}
+
+/**
+ * drbd_bm_write() - Write the whole bitmap to its on disk location.
+ * @mdev:      DRBD device.
+ */
+int drbd_bm_write(struct drbd_conf *mdev) __must_hold(local)
+{
+       return bm_rw(mdev, WRITE);
+}
+
+/**
+ * drbd_bm_write_sect: Writes a 512 (MD_SECTOR_SIZE) byte piece of the bitmap
+ * @mdev:      DRBD device.
+ * @enr:       Extent number in the resync lru (happens to be sector offset)
+ *
+ * The BM_EXT_SIZE is on purpose exactly the amount of the bitmap covered
+ * by a single sector write. Therefore enr == sector offset from the
+ * start of the bitmap.
+ */
+int drbd_bm_write_sect(struct drbd_conf *mdev, unsigned long enr) __must_hold(local)
+{
+       sector_t on_disk_sector = enr + mdev->ldev->md.md_offset
+                                     + mdev->ldev->md.bm_offset;
+       int bm_words, num_words, offset;
+       int err = 0;
+
+       mutex_lock(&mdev->md_io_mutex);
+       bm_words  = drbd_bm_words(mdev);
+       offset    = S2W(enr);   /* word offset into bitmap */
+       num_words = min(S2W(1), bm_words - offset);
+       if (num_words < S2W(1))
+               memset(page_address(mdev->md_io_page), 0, MD_SECTOR_SIZE);
+       drbd_bm_get_lel(mdev, offset, num_words,
+                       page_address(mdev->md_io_page));
+       if (!drbd_md_sync_page_io(mdev, mdev->ldev, on_disk_sector, WRITE)) {
+               int i;
+               err = -EIO;
+               dev_err(DEV, "IO ERROR writing bitmap sector %lu "
+                   "(meta-disk sector %llus)\n",
+                   enr, (unsigned long long)on_disk_sector);
+               drbd_chk_io_error(mdev, 1, TRUE);
+               for (i = 0; i < AL_EXT_PER_BM_SECT; i++)
+                       drbd_bm_ALe_set_all(mdev, enr*AL_EXT_PER_BM_SECT+i);
+       }
+       mdev->bm_writ_cnt++;
+       mutex_unlock(&mdev->md_io_mutex);
+       return err;
+}
+
+/* NOTE
+ * find_first_bit returns int, we return unsigned long.
+ * should not make much difference anyways, but ...
+ *
+ * this returns a bit number, NOT a sector!
+ */
+#define BPP_MASK ((1UL << (PAGE_SHIFT+3)) - 1)
+static unsigned long __bm_find_next(struct drbd_conf *mdev, unsigned long bm_fo,
+       const int find_zero_bit, const enum km_type km)
+{
+       struct drbd_bitmap *b = mdev->bitmap;
+       unsigned long i = -1UL;
+       unsigned long *p_addr;
+       unsigned long bit_offset; /* bit offset of the mapped page. */
+
+       if (bm_fo > b->bm_bits) {
+               dev_err(DEV, "bm_fo=%lu bm_bits=%lu\n", bm_fo, b->bm_bits);
+       } else {
+               while (bm_fo < b->bm_bits) {
+                       unsigned long offset;
+                       bit_offset = bm_fo & ~BPP_MASK; /* bit offset of the page */
+                       offset = bit_offset >> LN2_BPL;    /* word offset of the page */
+                       p_addr = __bm_map_paddr(b, offset, km);
+
+                       if (find_zero_bit)
+                               i = find_next_zero_bit(p_addr, PAGE_SIZE*8, bm_fo & BPP_MASK);
+                       else
+                               i = find_next_bit(p_addr, PAGE_SIZE*8, bm_fo & BPP_MASK);
+
+                       __bm_unmap(p_addr, km);
+                       if (i < PAGE_SIZE*8) {
+                               i = bit_offset + i;
+                               if (i >= b->bm_bits)
+                                       break;
+                               goto found;
+                       }
+                       bm_fo = bit_offset + PAGE_SIZE*8;
+               }
+               i = -1UL;
+       }
+ found:
+       return i;
+}
+
+static unsigned long bm_find_next(struct drbd_conf *mdev,
+       unsigned long bm_fo, const int find_zero_bit)
+{
+       struct drbd_bitmap *b = mdev->bitmap;
+       unsigned long i = -1UL;
+
+       ERR_IF(!b) return i;
+       ERR_IF(!b->bm_pages) return i;
+
+       spin_lock_irq(&b->bm_lock);
+       if (bm_is_locked(b))
+               bm_print_lock_info(mdev);
+
+       i = __bm_find_next(mdev, bm_fo, find_zero_bit, KM_IRQ1);
+
+       spin_unlock_irq(&b->bm_lock);
+       return i;
+}
+
+unsigned long drbd_bm_find_next(struct drbd_conf *mdev, unsigned long bm_fo)
+{
+       return bm_find_next(mdev, bm_fo, 0);
+}
+
+#if 0
+/* not yet needed for anything. */
+unsigned long drbd_bm_find_next_zero(struct drbd_conf *mdev, unsigned long bm_fo)
+{
+       return bm_find_next(mdev, bm_fo, 1);
+}
+#endif
+
+/* does not spin_lock_irqsave.
+ * you must take drbd_bm_lock() first */
+unsigned long _drbd_bm_find_next(struct drbd_conf *mdev, unsigned long bm_fo)
+{
+       /* WARN_ON(!bm_is_locked(mdev)); */
+       return __bm_find_next(mdev, bm_fo, 0, KM_USER1);
+}
+
+unsigned long _drbd_bm_find_next_zero(struct drbd_conf *mdev, unsigned long bm_fo)
+{
+       /* WARN_ON(!bm_is_locked(mdev)); */
+       return __bm_find_next(mdev, bm_fo, 1, KM_USER1);
+}
+
+/* returns number of bits actually changed.
+ * for val != 0, we change 0 -> 1, return code positive
+ * for val == 0, we change 1 -> 0, return code negative
+ * wants bitnr, not sector.
+ * expected to be called for only a few bits (e - s about BITS_PER_LONG).
+ * Must hold bitmap lock already. */
+int __bm_change_bits_to(struct drbd_conf *mdev, const unsigned long s,
+       unsigned long e, int val, const enum km_type km)
+{
+       struct drbd_bitmap *b = mdev->bitmap;
+       unsigned long *p_addr = NULL;
+       unsigned long bitnr;
+       unsigned long last_page_nr = -1UL;
+       int c = 0;
+
+       if (e >= b->bm_bits) {
+               dev_err(DEV, "ASSERT FAILED: bit_s=%lu bit_e=%lu bm_bits=%lu\n",
+                               s, e, b->bm_bits);
+               e = b->bm_bits ? b->bm_bits -1 : 0;
+       }
+       for (bitnr = s; bitnr <= e; bitnr++) {
+               unsigned long offset = bitnr>>LN2_BPL;
+               unsigned long page_nr = offset >> (PAGE_SHIFT - LN2_BPL + 3);
+               if (page_nr != last_page_nr) {
+                       if (p_addr)
+                               __bm_unmap(p_addr, km);
+                       p_addr = __bm_map_paddr(b, offset, km);
+                       last_page_nr = page_nr;
+               }
+               if (val)
+                       c += (0 == __test_and_set_bit(bitnr & BPP_MASK, p_addr));
+               else
+                       c -= (0 != __test_and_clear_bit(bitnr & BPP_MASK, p_addr));
+       }
+       if (p_addr)
+               __bm_unmap(p_addr, km);
+       b->bm_set += c;
+       return c;
+}
+
+/* returns number of bits actually changed.
+ * for val != 0, we change 0 -> 1, return code positive
+ * for val == 0, we change 1 -> 0, return code negative
+ * wants bitnr, not sector */
+int bm_change_bits_to(struct drbd_conf *mdev, const unsigned long s,
+       const unsigned long e, int val)
+{
+       unsigned long flags;
+       struct drbd_bitmap *b = mdev->bitmap;
+       int c = 0;
+
+       ERR_IF(!b) return 1;
+       ERR_IF(!b->bm_pages) return 0;
+
+       spin_lock_irqsave(&b->bm_lock, flags);
+       if (bm_is_locked(b))
+               bm_print_lock_info(mdev);
+
+       c = __bm_change_bits_to(mdev, s, e, val, KM_IRQ1);
+
+       spin_unlock_irqrestore(&b->bm_lock, flags);
+       return c;
+}
+
+/* returns number of bits changed 0 -> 1 */
+int drbd_bm_set_bits(struct drbd_conf *mdev, const unsigned long s, const unsigned long e)
+{
+       return bm_change_bits_to(mdev, s, e, 1);
+}
+
+/* returns number of bits changed 1 -> 0 */
+int drbd_bm_clear_bits(struct drbd_conf *mdev, const unsigned long s, const unsigned long e)
+{
+       return -bm_change_bits_to(mdev, s, e, 0);
+}
+
+/* sets all bits in full words,
+ * from first_word up to, but not including, last_word */
+static inline void bm_set_full_words_within_one_page(struct drbd_bitmap *b,
+               int page_nr, int first_word, int last_word)
+{
+       int i;
+       int bits;
+       unsigned long *paddr = kmap_atomic(b->bm_pages[page_nr], KM_USER0);
+       for (i = first_word; i < last_word; i++) {
+               bits = hweight_long(paddr[i]);
+               paddr[i] = ~0UL;
+               b->bm_set += BITS_PER_LONG - bits;
+       }
+       kunmap_atomic(paddr, KM_USER0);
+}
+
+/* Same thing as drbd_bm_set_bits, but without taking the spin_lock_irqsave.
+ * You must first drbd_bm_lock().
+ * Can be called to set the whole bitmap in one go.
+ * Sets bits from s to e _inclusive_. */
+void _drbd_bm_set_bits(struct drbd_conf *mdev, const unsigned long s, const unsigned long e)
+{
+       /* First set_bit from the first bit (s)
+        * up to the next long boundary (sl),
+        * then assign full words up to the last long boundary (el),
+        * then set_bit up to and including the last bit (e).
+        *
+        * Do not use memset, because we must account for changes,
+        * so we need to loop over the words with hweight() anyways.
+        */
+       unsigned long sl = ALIGN(s,BITS_PER_LONG);
+       unsigned long el = (e+1) & ~((unsigned long)BITS_PER_LONG-1);
+       int first_page;
+       int last_page;
+       int page_nr;
+       int first_word;
+       int last_word;
+
+       if (e - s <= 3*BITS_PER_LONG) {
+               /* don't bother; el and sl may even be wrong. */
+               __bm_change_bits_to(mdev, s, e, 1, KM_USER0);
+               return;
+       }
+
+       /* difference is large enough that we can trust sl and el */
+
+       /* bits filling the current long */
+       if (sl)
+               __bm_change_bits_to(mdev, s, sl-1, 1, KM_USER0);
+
+       first_page = sl >> (3 + PAGE_SHIFT);
+       last_page = el >> (3 + PAGE_SHIFT);
+
+       /* MLPP: modulo longs per page */
+       /* LWPP: long words per page */
+       first_word = MLPP(sl >> LN2_BPL);
+       last_word = LWPP;
+
+       /* first and full pages, unless first page == last page */
+       for (page_nr = first_page; page_nr < last_page; page_nr++) {
+               bm_set_full_words_within_one_page(mdev->bitmap, page_nr, first_word, last_word);
+               cond_resched();
+               first_word = 0;
+       }
+
+       /* 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);
+
+       /* possibly trailing bits.
+        * example: (e & 63) == 63, el will be e+1.
+        * if that even was the very last bit,
+        * it would trigger an assert in __bm_change_bits_to()
+        */
+       if (el <= e)
+               __bm_change_bits_to(mdev, el, e, 1, KM_USER0);
+}
+
+/* returns bit state
+ * wants bitnr, NOT sector.
+ * inherently racy... area needs to be locked by means of {al,rs}_lru
+ *  1 ... bit set
+ *  0 ... bit not set
+ * -1 ... first out of bounds access, stop testing for bits!
+ */
+int drbd_bm_test_bit(struct drbd_conf *mdev, const unsigned long bitnr)
+{
+       unsigned long flags;
+       struct drbd_bitmap *b = mdev->bitmap;
+       unsigned long *p_addr;
+       int i;
+
+       ERR_IF(!b) return 0;
+       ERR_IF(!b->bm_pages) return 0;
+
+       spin_lock_irqsave(&b->bm_lock, flags);
+       if (bm_is_locked(b))
+               bm_print_lock_info(mdev);
+       if (bitnr < b->bm_bits) {
+               unsigned long offset = bitnr>>LN2_BPL;
+               p_addr = bm_map_paddr(b, offset);
+               i = test_bit(bitnr & BPP_MASK, p_addr) ? 1 : 0;
+               bm_unmap(p_addr);
+       } else if (bitnr == b->bm_bits) {
+               i = -1;
+       } else { /* (bitnr > b->bm_bits) */
+               dev_err(DEV, "bitnr=%lu > bm_bits=%lu\n", bitnr, b->bm_bits);
+               i = 0;
+       }
+
+       spin_unlock_irqrestore(&b->bm_lock, flags);
+       return i;
+}
+
+/* returns number of bits set in the range [s, e] */
+int drbd_bm_count_bits(struct drbd_conf *mdev, const unsigned long s, const unsigned long e)
+{
+       unsigned long flags;
+       struct drbd_bitmap *b = mdev->bitmap;
+       unsigned long *p_addr = NULL, page_nr = -1;
+       unsigned long bitnr;
+       int c = 0;
+       size_t w;
+
+       /* If this is called without a bitmap, that is a bug.  But just to be
+        * robust in case we screwed up elsewhere, in that case pretend there
+        * was one dirty bit in the requested area, so we won't try to do a
+        * local read there (no bitmap probably implies no disk) */
+       ERR_IF(!b) return 1;
+       ERR_IF(!b->bm_pages) return 1;
+
+       spin_lock_irqsave(&b->bm_lock, flags);
+       if (bm_is_locked(b))
+               bm_print_lock_info(mdev);
+       for (bitnr = s; bitnr <= e; bitnr++) {
+               w = bitnr >> LN2_BPL;
+               if (page_nr != w >> (PAGE_SHIFT - LN2_BPL + 3)) {
+                       page_nr = w >> (PAGE_SHIFT - LN2_BPL + 3);
+                       if (p_addr)
+                               bm_unmap(p_addr);
+                       p_addr = bm_map_paddr(b, w);
+               }
+               ERR_IF (bitnr >= b->bm_bits) {
+                       dev_err(DEV, "bitnr=%lu bm_bits=%lu\n", bitnr, b->bm_bits);
+               } else {
+                       c += (0 != test_bit(bitnr - (page_nr << (PAGE_SHIFT+3)), p_addr));
+               }
+       }
+       if (p_addr)
+               bm_unmap(p_addr);
+       spin_unlock_irqrestore(&b->bm_lock, flags);
+       return c;
+}
+
+
+/* inherently racy...
+ * return value may be already out-of-date when this function returns.
+ * but the general usage is that this is only use during a cstate when bits are
+ * only cleared, not set, and typically only care for the case when the return
+ * value is zero, or we already "locked" this "bitmap extent" by other means.
+ *
+ * enr is bm-extent number, since we chose to name one sector (512 bytes)
+ * worth of the bitmap a "bitmap extent".
+ *
+ * TODO
+ * I think since we use it like a reference count, we should use the real
+ * reference count of some bitmap extent element from some lru instead...
+ *
+ */
+int drbd_bm_e_weight(struct drbd_conf *mdev, unsigned long enr)
+{
+       struct drbd_bitmap *b = mdev->bitmap;
+       int count, s, e;
+       unsigned long flags;
+       unsigned long *p_addr, *bm;
+
+       ERR_IF(!b) return 0;
+       ERR_IF(!b->bm_pages) return 0;
+
+       spin_lock_irqsave(&b->bm_lock, flags);
+       if (bm_is_locked(b))
+               bm_print_lock_info(mdev);
+
+       s = S2W(enr);
+       e = min((size_t)S2W(enr+1), b->bm_words);
+       count = 0;
+       if (s < b->bm_words) {
+               int n = e-s;
+               p_addr = bm_map_paddr(b, s);
+               bm = p_addr + MLPP(s);
+               while (n--)
+                       count += hweight_long(*bm++);
+               bm_unmap(p_addr);
+       } else {
+               dev_err(DEV, "start offset (%d) too large in drbd_bm_e_weight\n", s);
+       }
+       spin_unlock_irqrestore(&b->bm_lock, flags);
+       return count;
+}
+
+/* set all bits covered by the AL-extent al_enr */
+unsigned long drbd_bm_ALe_set_all(struct drbd_conf *mdev, unsigned long al_enr)
+{
+       struct drbd_bitmap *b = mdev->bitmap;
+       unsigned long *p_addr, *bm;
+       unsigned long weight;
+       int count, s, e, i, do_now;
+       ERR_IF(!b) return 0;
+       ERR_IF(!b->bm_pages) return 0;
+
+       spin_lock_irq(&b->bm_lock);
+       if (bm_is_locked(b))
+               bm_print_lock_info(mdev);
+       weight = b->bm_set;
+
+       s = al_enr * BM_WORDS_PER_AL_EXT;
+       e = min_t(size_t, s + BM_WORDS_PER_AL_EXT, b->bm_words);
+       /* assert that s and e are on the same page */
+       D_ASSERT((e-1) >> (PAGE_SHIFT - LN2_BPL + 3)
+             ==  s    >> (PAGE_SHIFT - LN2_BPL + 3));
+       count = 0;
+       if (s < b->bm_words) {
+               i = do_now = e-s;
+               p_addr = bm_map_paddr(b, s);
+               bm = p_addr + MLPP(s);
+               while (i--) {
+                       count += hweight_long(*bm);
+                       *bm = -1UL;
+                       bm++;
+               }
+               bm_unmap(p_addr);
+               b->bm_set += do_now*BITS_PER_LONG - count;
+               if (e == b->bm_words)
+                       b->bm_set -= bm_clear_surplus(b);
+       } else {
+               dev_err(DEV, "start offset (%d) too large in drbd_bm_ALe_set_all\n", s);
+       }
+       weight = b->bm_set - weight;
+       spin_unlock_irq(&b->bm_lock);
+       return weight;
+}
diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h
new file mode 100644 (file)
index 0000000..2312d78
--- /dev/null
@@ -0,0 +1,2252 @@
+/*
+  drbd_int.h
+
+  This file is part of DRBD by Philipp Reisner and Lars Ellenberg.
+
+  Copyright (C) 2001-2008, LINBIT Information Technologies GmbH.
+  Copyright (C) 1999-2008, Philipp Reisner <philipp.reisner@linbit.com>.
+  Copyright (C) 2002-2008, Lars Ellenberg <lars.ellenberg@linbit.com>.
+
+  drbd is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2, or (at your option)
+  any later version.
+
+  drbd 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 drbd; see the file COPYING.  If not, write to
+  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef _DRBD_INT_H
+#define _DRBD_INT_H
+
+#include <linux/compiler.h>
+#include <linux/types.h>
+#include <linux/version.h>
+#include <linux/list.h>
+#include <linux/sched.h>
+#include <linux/bitops.h>
+#include <linux/slab.h>
+#include <linux/crypto.h>
+#include <linux/ratelimit.h>
+#include <linux/tcp.h>
+#include <linux/mutex.h>
+#include <linux/major.h>
+#include <linux/blkdev.h>
+#include <linux/genhd.h>
+#include <net/tcp.h>
+#include <linux/lru_cache.h>
+
+#ifdef __CHECKER__
+# define __protected_by(x)       __attribute__((require_context(x,1,999,"rdwr")))
+# define __protected_read_by(x)  __attribute__((require_context(x,1,999,"read")))
+# define __protected_write_by(x) __attribute__((require_context(x,1,999,"write")))
+# define __must_hold(x)       __attribute__((context(x,1,1), require_context(x,1,999,"call")))
+#else
+# define __protected_by(x)
+# define __protected_read_by(x)
+# define __protected_write_by(x)
+# define __must_hold(x)
+#endif
+
+#define __no_warn(lock, stmt) do { __acquire(lock); stmt; __release(lock); } while (0)
+
+/* module parameter, defined in drbd_main.c */
+extern unsigned int minor_count;
+extern int disable_sendpage;
+extern int allow_oos;
+extern unsigned int cn_idx;
+
+#ifdef CONFIG_DRBD_FAULT_INJECTION
+extern int enable_faults;
+extern int fault_rate;
+extern int fault_devs;
+#endif
+
+extern char usermode_helper[];
+
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+/* I don't remember why XCPU ...
+ * This is used to wake the asender,
+ * and to interrupt sending the sending task
+ * on disconnect.
+ */
+#define DRBD_SIG SIGXCPU
+
+/* This is used to stop/restart our threads.
+ * Cannot use SIGTERM nor SIGKILL, since these
+ * are sent out by init on runlevel changes
+ * I choose SIGHUP for now.
+ */
+#define DRBD_SIGKILL SIGHUP
+
+/* All EEs on the free list should have ID_VACANT (== 0)
+ * freshly allocated EEs get !ID_VACANT (== 1)
+ * so if it says "cannot dereference null pointer at adress 0x00000001",
+ * it is most likely one of these :( */
+
+#define ID_IN_SYNC      (4711ULL)
+#define ID_OUT_OF_SYNC  (4712ULL)
+
+#define ID_SYNCER (-1ULL)
+#define ID_VACANT 0
+#define is_syncer_block_id(id) ((id) == ID_SYNCER)
+
+struct drbd_conf;
+
+
+/* to shorten dev_warn(DEV, "msg"); and relatives statements */
+#define DEV (disk_to_dev(mdev->vdisk))
+
+#define D_ASSERT(exp)  if (!(exp)) \
+        dev_err(DEV, "ASSERT( " #exp " ) in %s:%d\n", __FILE__, __LINE__)
+
+#define ERR_IF(exp) if (({                             \
+       int _b = (exp) != 0;                            \
+       if (_b) dev_err(DEV, "%s: (%s) in %s:%d\n",     \
+               __func__, #exp, __FILE__, __LINE__);    \
+        _b;                                            \
+       }))
+
+/* Defines to control fault insertion */
+enum {
+       DRBD_FAULT_MD_WR = 0,   /* meta data write */
+       DRBD_FAULT_MD_RD = 1,   /*           read  */
+       DRBD_FAULT_RS_WR = 2,   /* resync          */
+       DRBD_FAULT_RS_RD = 3,
+       DRBD_FAULT_DT_WR = 4,   /* data            */
+       DRBD_FAULT_DT_RD = 5,
+       DRBD_FAULT_DT_RA = 6,   /* data read ahead */
+       DRBD_FAULT_BM_ALLOC = 7,        /* bitmap allocation */
+       DRBD_FAULT_AL_EE = 8,   /* alloc ee */
+
+       DRBD_FAULT_MAX,
+};
+
+#ifdef CONFIG_DRBD_FAULT_INJECTION
+extern unsigned int
+_drbd_insert_fault(struct drbd_conf *mdev, unsigned int type);
+static inline int
+drbd_insert_fault(struct drbd_conf *mdev, unsigned int type) {
+       return fault_rate &&
+               (enable_faults & (1<<type)) &&
+               _drbd_insert_fault(mdev, type);
+}
+#define FAULT_ACTIVE(_m, _t) (drbd_insert_fault((_m), (_t)))
+
+#else
+#define FAULT_ACTIVE(_m, _t) (0)
+#endif
+
+/* integer division, round _UP_ to the next integer */
+#define div_ceil(A, B) ((A)/(B) + ((A)%(B) ? 1 : 0))
+/* usual integer division */
+#define div_floor(A, B) ((A)/(B))
+
+/* drbd_meta-data.c (still in drbd_main.c) */
+/* 4th incarnation of the disk layout. */
+#define DRBD_MD_MAGIC (DRBD_MAGIC+4)
+
+extern struct drbd_conf **minor_table;
+extern struct ratelimit_state drbd_ratelimit_state;
+
+/* on the wire */
+enum drbd_packets {
+       /* receiver (data socket) */
+       P_DATA                = 0x00,
+       P_DATA_REPLY          = 0x01, /* Response to P_DATA_REQUEST */
+       P_RS_DATA_REPLY       = 0x02, /* Response to P_RS_DATA_REQUEST */
+       P_BARRIER             = 0x03,
+       P_BITMAP              = 0x04,
+       P_BECOME_SYNC_TARGET  = 0x05,
+       P_BECOME_SYNC_SOURCE  = 0x06,
+       P_UNPLUG_REMOTE       = 0x07, /* Used at various times to hint the peer */
+       P_DATA_REQUEST        = 0x08, /* Used to ask for a data block */
+       P_RS_DATA_REQUEST     = 0x09, /* Used to ask for a data block for resync */
+       P_SYNC_PARAM          = 0x0a,
+       P_PROTOCOL            = 0x0b,
+       P_UUIDS               = 0x0c,
+       P_SIZES               = 0x0d,
+       P_STATE               = 0x0e,
+       P_SYNC_UUID           = 0x0f,
+       P_AUTH_CHALLENGE      = 0x10,
+       P_AUTH_RESPONSE       = 0x11,
+       P_STATE_CHG_REQ       = 0x12,
+
+       /* asender (meta socket */
+       P_PING                = 0x13,
+       P_PING_ACK            = 0x14,
+       P_RECV_ACK            = 0x15, /* Used in protocol B */
+       P_WRITE_ACK           = 0x16, /* Used in protocol C */
+       P_RS_WRITE_ACK        = 0x17, /* Is a P_WRITE_ACK, additionally call set_in_sync(). */
+       P_DISCARD_ACK         = 0x18, /* Used in proto C, two-primaries conflict detection */
+       P_NEG_ACK             = 0x19, /* Sent if local disk is unusable */
+       P_NEG_DREPLY          = 0x1a, /* Local disk is broken... */
+       P_NEG_RS_DREPLY       = 0x1b, /* Local disk is broken... */
+       P_BARRIER_ACK         = 0x1c,
+       P_STATE_CHG_REPLY     = 0x1d,
+
+       /* "new" commands, no longer fitting into the ordering scheme above */
+
+       P_OV_REQUEST          = 0x1e, /* data socket */
+       P_OV_REPLY            = 0x1f,
+       P_OV_RESULT           = 0x20, /* meta socket */
+       P_CSUM_RS_REQUEST     = 0x21, /* data socket */
+       P_RS_IS_IN_SYNC       = 0x22, /* meta socket */
+       P_SYNC_PARAM89        = 0x23, /* data socket, protocol version 89 replacement for P_SYNC_PARAM */
+       P_COMPRESSED_BITMAP   = 0x24, /* compressed or otherwise encoded bitmap transfer */
+
+       P_MAX_CMD             = 0x25,
+       P_MAY_IGNORE          = 0x100, /* Flag to test if (cmd > P_MAY_IGNORE) ... */
+       P_MAX_OPT_CMD         = 0x101,
+
+       /* special command ids for handshake */
+
+       P_HAND_SHAKE_M        = 0xfff1, /* First Packet on the MetaSock */
+       P_HAND_SHAKE_S        = 0xfff2, /* First Packet on the Socket */
+
+       P_HAND_SHAKE          = 0xfffe  /* FIXED for the next century! */
+};
+
+static inline const char *cmdname(enum drbd_packets cmd)
+{
+       /* THINK may need to become several global tables
+        * when we want to support more than
+        * one PRO_VERSION */
+       static const char *cmdnames[] = {
+               [P_DATA]                = "Data",
+               [P_DATA_REPLY]          = "DataReply",
+               [P_RS_DATA_REPLY]       = "RSDataReply",
+               [P_BARRIER]             = "Barrier",
+               [P_BITMAP]              = "ReportBitMap",
+               [P_BECOME_SYNC_TARGET]  = "BecomeSyncTarget",
+               [P_BECOME_SYNC_SOURCE]  = "BecomeSyncSource",
+               [P_UNPLUG_REMOTE]       = "UnplugRemote",
+               [P_DATA_REQUEST]        = "DataRequest",
+               [P_RS_DATA_REQUEST]     = "RSDataRequest",
+               [P_SYNC_PARAM]          = "SyncParam",
+               [P_SYNC_PARAM89]        = "SyncParam89",
+               [P_PROTOCOL]            = "ReportProtocol",
+               [P_UUIDS]               = "ReportUUIDs",
+               [P_SIZES]               = "ReportSizes",
+               [P_STATE]               = "ReportState",
+               [P_SYNC_UUID]           = "ReportSyncUUID",
+               [P_AUTH_CHALLENGE]      = "AuthChallenge",
+               [P_AUTH_RESPONSE]       = "AuthResponse",
+               [P_PING]                = "Ping",
+               [P_PING_ACK]            = "PingAck",
+               [P_RECV_ACK]            = "RecvAck",
+               [P_WRITE_ACK]           = "WriteAck",
+               [P_RS_WRITE_ACK]        = "RSWriteAck",
+               [P_DISCARD_ACK]         = "DiscardAck",
+               [P_NEG_ACK]             = "NegAck",
+               [P_NEG_DREPLY]          = "NegDReply",
+               [P_NEG_RS_DREPLY]       = "NegRSDReply",
+               [P_BARRIER_ACK]         = "BarrierAck",
+               [P_STATE_CHG_REQ]       = "StateChgRequest",
+               [P_STATE_CHG_REPLY]     = "StateChgReply",
+               [P_OV_REQUEST]          = "OVRequest",
+               [P_OV_REPLY]            = "OVReply",
+               [P_OV_RESULT]           = "OVResult",
+               [P_MAX_CMD]             = NULL,
+       };
+
+       if (cmd == P_HAND_SHAKE_M)
+               return "HandShakeM";
+       if (cmd == P_HAND_SHAKE_S)
+               return "HandShakeS";
+       if (cmd == P_HAND_SHAKE)
+               return "HandShake";
+       if (cmd >= P_MAX_CMD)
+               return "Unknown";
+       return cmdnames[cmd];
+}
+
+/* for sending/receiving the bitmap,
+ * possibly in some encoding scheme */
+struct bm_xfer_ctx {
+       /* "const"
+        * stores total bits and long words
+        * of the bitmap, so we don't need to
+        * call the accessor functions over and again. */
+       unsigned long bm_bits;
+       unsigned long bm_words;
+       /* during xfer, current position within the bitmap */
+       unsigned long bit_offset;
+       unsigned long word_offset;
+
+       /* statistics; index: (h->command == P_BITMAP) */
+       unsigned packets[2];
+       unsigned bytes[2];
+};
+
+extern void INFO_bm_xfer_stats(struct drbd_conf *mdev,
+               const char *direction, struct bm_xfer_ctx *c);
+
+static inline void bm_xfer_ctx_bit_to_word_offset(struct bm_xfer_ctx *c)
+{
+       /* word_offset counts "native long words" (32 or 64 bit),
+        * aligned at 64 bit.
+        * Encoded packet may end at an unaligned bit offset.
+        * In case a fallback clear text packet is transmitted in
+        * between, we adjust this offset back to the last 64bit
+        * aligned "native long word", which makes coding and decoding
+        * the plain text bitmap much more convenient.  */
+#if BITS_PER_LONG == 64
+       c->word_offset = c->bit_offset >> 6;
+#elif BITS_PER_LONG == 32
+       c->word_offset = c->bit_offset >> 5;
+       c->word_offset &= ~(1UL);
+#else
+# error "unsupported BITS_PER_LONG"
+#endif
+}
+
+#ifndef __packed
+#define __packed __attribute__((packed))
+#endif
+
+/* This is the layout for a packet on the wire.
+ * The byteorder is the network byte order.
+ *     (except block_id and barrier fields.
+ *     these are pointers to local structs
+ *     and have no relevance for the partner,
+ *     which just echoes them as received.)
+ *
+ * NOTE that the payload starts at a long aligned offset,
+ * regardless of 32 or 64 bit arch!
+ */
+struct p_header {
+       u32       magic;
+       u16       command;
+       u16       length;       /* bytes of data after this header */
+       u8        payload[0];
+} __packed;
+/* 8 bytes. packet FIXED for the next century! */
+
+/*
+ * short commands, packets without payload, plain p_header:
+ *   P_PING
+ *   P_PING_ACK
+ *   P_BECOME_SYNC_TARGET
+ *   P_BECOME_SYNC_SOURCE
+ *   P_UNPLUG_REMOTE
+ */
+
+/*
+ * commands with out-of-struct payload:
+ *   P_BITMAP    (no additional fields)
+ *   P_DATA, P_DATA_REPLY (see p_data)
+ *   P_COMPRESSED_BITMAP (see receive_compressed_bitmap)
+ */
+
+/* these defines must not be changed without changing the protocol version */
+#define DP_HARDBARRIER       1
+#define DP_RW_SYNC           2
+#define DP_MAY_SET_IN_SYNC    4
+
+struct p_data {
+       struct p_header head;
+       u64         sector;    /* 64 bits sector number */
+       u64         block_id;  /* to identify the request in protocol B&C */
+       u32         seq_num;
+       u32         dp_flags;
+} __packed;
+
+/*
+ * commands which share a struct:
+ *  p_block_ack:
+ *   P_RECV_ACK (proto B), P_WRITE_ACK (proto C),
+ *   P_DISCARD_ACK (proto C, two-primaries conflict detection)
+ *  p_block_req:
+ *   P_DATA_REQUEST, P_RS_DATA_REQUEST
+ */
+struct p_block_ack {
+       struct p_header head;
+       u64         sector;
+       u64         block_id;
+       u32         blksize;
+       u32         seq_num;
+} __packed;
+
+
+struct p_block_req {
+       struct p_header head;
+       u64 sector;
+       u64 block_id;
+       u32 blksize;
+       u32 pad;        /* to multiple of 8 Byte */
+} __packed;
+
+/*
+ * commands with their own struct for additional fields:
+ *   P_HAND_SHAKE
+ *   P_BARRIER
+ *   P_BARRIER_ACK
+ *   P_SYNC_PARAM
+ *   ReportParams
+ */
+
+struct p_handshake {
+       struct p_header head;   /* 8 bytes */
+       u32 protocol_min;
+       u32 feature_flags;
+       u32 protocol_max;
+
+       /* should be more than enough for future enhancements
+        * for now, feature_flags and the reserverd array shall be zero.
+        */
+
+       u32 _pad;
+       u64 reserverd[7];
+} __packed;
+/* 80 bytes, FIXED for the next century */
+
+struct p_barrier {
+       struct p_header head;
+       u32 barrier;    /* barrier number _handle_ only */
+       u32 pad;        /* to multiple of 8 Byte */
+} __packed;
+
+struct p_barrier_ack {
+       struct p_header head;
+       u32 barrier;
+       u32 set_size;
+} __packed;
+
+struct p_rs_param {
+       struct p_header head;
+       u32 rate;
+
+             /* Since protocol version 88 and higher. */
+       char verify_alg[0];
+} __packed;
+
+struct p_rs_param_89 {
+       struct p_header head;
+       u32 rate;
+        /* protocol version 89: */
+       char verify_alg[SHARED_SECRET_MAX];
+       char csums_alg[SHARED_SECRET_MAX];
+} __packed;
+
+struct p_protocol {
+       struct p_header head;
+       u32 protocol;
+       u32 after_sb_0p;
+       u32 after_sb_1p;
+       u32 after_sb_2p;
+       u32 want_lose;
+       u32 two_primaries;
+
+              /* Since protocol version 87 and higher. */
+       char integrity_alg[0];
+
+} __packed;
+
+struct p_uuids {
+       struct p_header head;
+       u64 uuid[UI_EXTENDED_SIZE];
+} __packed;
+
+struct p_rs_uuid {
+       struct p_header head;
+       u64         uuid;
+} __packed;
+
+struct p_sizes {
+       struct p_header head;
+       u64         d_size;  /* size of disk */
+       u64         u_size;  /* user requested size */
+       u64         c_size;  /* current exported size */
+       u32         max_segment_size;  /* Maximal size of a BIO */
+       u32         queue_order_type;
+} __packed;
+
+struct p_state {
+       struct p_header head;
+       u32         state;
+} __packed;
+
+struct p_req_state {
+       struct p_header head;
+       u32         mask;
+       u32         val;
+} __packed;
+
+struct p_req_state_reply {
+       struct p_header head;
+       u32         retcode;
+} __packed;
+
+struct p_drbd06_param {
+       u64       size;
+       u32       state;
+       u32       blksize;
+       u32       protocol;
+       u32       version;
+       u32       gen_cnt[5];
+       u32       bit_map_gen[5];
+} __packed;
+
+struct p_discard {
+       struct p_header head;
+       u64         block_id;
+       u32         seq_num;
+       u32         pad;
+} __packed;
+
+/* Valid values for the encoding field.
+ * Bump proto version when changing this. */
+enum drbd_bitmap_code {
+       /* RLE_VLI_Bytes = 0,
+        * and other bit variants had been defined during
+        * algorithm evaluation. */
+       RLE_VLI_Bits = 2,
+};
+
+struct p_compressed_bm {
+       struct p_header head;
+       /* (encoding & 0x0f): actual encoding, see enum drbd_bitmap_code
+        * (encoding & 0x80): polarity (set/unset) of first runlength
+        * ((encoding >> 4) & 0x07): pad_bits, number of trailing zero bits
+        * used to pad up to head.length bytes
+        */
+       u8 encoding;
+
+       u8 code[0];
+} __packed;
+
+/* DCBP: Drbd Compressed Bitmap Packet ... */
+static inline enum drbd_bitmap_code
+DCBP_get_code(struct p_compressed_bm *p)
+{
+       return (enum drbd_bitmap_code)(p->encoding & 0x0f);
+}
+
+static inline void
+DCBP_set_code(struct p_compressed_bm *p, enum drbd_bitmap_code code)
+{
+       BUG_ON(code & ~0xf);
+       p->encoding = (p->encoding & ~0xf) | code;
+}
+
+static inline int
+DCBP_get_start(struct p_compressed_bm *p)
+{
+       return (p->encoding & 0x80) != 0;
+}
+
+static inline void
+DCBP_set_start(struct p_compressed_bm *p, int set)
+{
+       p->encoding = (p->encoding & ~0x80) | (set ? 0x80 : 0);
+}
+
+static inline int
+DCBP_get_pad_bits(struct p_compressed_bm *p)
+{
+       return (p->encoding >> 4) & 0x7;
+}
+
+static inline void
+DCBP_set_pad_bits(struct p_compressed_bm *p, int n)
+{
+       BUG_ON(n & ~0x7);
+       p->encoding = (p->encoding & (~0x7 << 4)) | (n << 4);
+}
+
+/* one bitmap packet, including the p_header,
+ * should fit within one _architecture independend_ page.
+ * so we need to use the fixed size 4KiB page size
+ * most architechtures have used for a long time.
+ */
+#define BM_PACKET_PAYLOAD_BYTES (4096 - sizeof(struct p_header))
+#define BM_PACKET_WORDS (BM_PACKET_PAYLOAD_BYTES/sizeof(long))
+#define BM_PACKET_VLI_BYTES_MAX (4096 - sizeof(struct p_compressed_bm))
+#if (PAGE_SIZE < 4096)
+/* drbd_send_bitmap / receive_bitmap would break horribly */
+#error "PAGE_SIZE too small"
+#endif
+
+union p_polymorph {
+        struct p_header          header;
+        struct p_handshake       handshake;
+        struct p_data            data;
+        struct p_block_ack       block_ack;
+        struct p_barrier         barrier;
+        struct p_barrier_ack     barrier_ack;
+        struct p_rs_param_89     rs_param_89;
+        struct p_protocol        protocol;
+        struct p_sizes           sizes;
+        struct p_uuids           uuids;
+        struct p_state           state;
+        struct p_req_state       req_state;
+        struct p_req_state_reply req_state_reply;
+        struct p_block_req       block_req;
+} __packed;
+
+/**********************************************************************/
+enum drbd_thread_state {
+       None,
+       Running,
+       Exiting,
+       Restarting
+};
+
+struct drbd_thread {
+       spinlock_t t_lock;
+       struct task_struct *task;
+       struct completion stop;
+       enum drbd_thread_state t_state;
+       int (*function) (struct drbd_thread *);
+       struct drbd_conf *mdev;
+       int reset_cpu_mask;
+};
+
+static inline enum drbd_thread_state get_t_state(struct drbd_thread *thi)
+{
+       /* THINK testing the t_state seems to be uncritical in all cases
+        * (but thread_{start,stop}), so we can read it *without* the lock.
+        *      --lge */
+
+       smp_rmb();
+       return thi->t_state;
+}
+
+
+/*
+ * Having this as the first member of a struct provides sort of "inheritance".
+ * "derived" structs can be "drbd_queue_work()"ed.
+ * The callback should know and cast back to the descendant struct.
+ * drbd_request and drbd_epoch_entry are descendants of drbd_work.
+ */
+struct drbd_work;
+typedef int (*drbd_work_cb)(struct drbd_conf *, struct drbd_work *, int cancel);
+struct drbd_work {
+       struct list_head list;
+       drbd_work_cb cb;
+};
+
+struct drbd_tl_epoch;
+struct drbd_request {
+       struct drbd_work w;
+       struct drbd_conf *mdev;
+
+       /* if local IO is not allowed, will be NULL.
+        * if local IO _is_ allowed, holds the locally submitted bio clone,
+        * or, after local IO completion, the ERR_PTR(error).
+        * see drbd_endio_pri(). */
+       struct bio *private_bio;
+
+       struct hlist_node colision;
+       sector_t sector;
+       unsigned int size;
+       unsigned int epoch; /* barrier_nr */
+
+       /* barrier_nr: used to check on "completion" whether this req was in
+        * the current epoch, and we therefore have to close it,
+        * starting a new epoch...
+        */
+
+       /* up to here, the struct layout is identical to drbd_epoch_entry;
+        * we might be able to use that to our advantage...  */
+
+       struct list_head tl_requests; /* ring list in the transfer log */
+       struct bio *master_bio;       /* master bio pointer */
+       unsigned long rq_state; /* see comments above _req_mod() */
+       int seq_num;
+       unsigned long start_time;
+};
+
+struct drbd_tl_epoch {
+       struct drbd_work w;
+       struct list_head requests; /* requests before */
+       struct drbd_tl_epoch *next; /* pointer to the next barrier */
+       unsigned int br_number;  /* the barriers identifier. */
+       int n_req;      /* number of requests attached before this barrier */
+};
+
+struct drbd_request;
+
+/* These Tl_epoch_entries may be in one of 6 lists:
+   active_ee .. data packet being written
+   sync_ee   .. syncer block being written
+   done_ee   .. block written, need to send P_WRITE_ACK
+   read_ee   .. [RS]P_DATA_REQUEST being read
+*/
+
+struct drbd_epoch {
+       struct list_head list;
+       unsigned int barrier_nr;
+       atomic_t epoch_size; /* increased on every request added. */
+       atomic_t active;     /* increased on every req. added, and dec on every finished. */
+       unsigned long flags;
+};
+
+/* drbd_epoch flag bits */
+enum {
+       DE_BARRIER_IN_NEXT_EPOCH_ISSUED,
+       DE_BARRIER_IN_NEXT_EPOCH_DONE,
+       DE_CONTAINS_A_BARRIER,
+       DE_HAVE_BARRIER_NUMBER,
+       DE_IS_FINISHING,
+};
+
+enum epoch_event {
+       EV_PUT,
+       EV_GOT_BARRIER_NR,
+       EV_BARRIER_DONE,
+       EV_BECAME_LAST,
+       EV_CLEANUP = 32, /* used as flag */
+};
+
+struct drbd_epoch_entry {
+       struct drbd_work    w;
+       struct drbd_conf *mdev;
+       struct bio *private_bio;
+       struct hlist_node colision;
+       sector_t sector;
+       unsigned int size;
+       struct drbd_epoch *epoch;
+
+       /* up to here, the struct layout is identical to drbd_request;
+        * we might be able to use that to our advantage...  */
+
+       unsigned int flags;
+       u64    block_id;
+};
+
+struct drbd_wq_barrier {
+       struct drbd_work w;
+       struct completion done;
+};
+
+struct digest_info {
+       int digest_size;
+       void *digest;
+};
+
+/* ee flag bits */
+enum {
+       __EE_CALL_AL_COMPLETE_IO,
+       __EE_CONFLICT_PENDING,
+       __EE_MAY_SET_IN_SYNC,
+       __EE_IS_BARRIER,
+};
+#define EE_CALL_AL_COMPLETE_IO (1<<__EE_CALL_AL_COMPLETE_IO)
+#define EE_CONFLICT_PENDING    (1<<__EE_CONFLICT_PENDING)
+#define EE_MAY_SET_IN_SYNC     (1<<__EE_MAY_SET_IN_SYNC)
+#define EE_IS_BARRIER          (1<<__EE_IS_BARRIER)
+
+/* global flag bits */
+enum {
+       CREATE_BARRIER,         /* next P_DATA is preceeded by a P_BARRIER */
+       SIGNAL_ASENDER,         /* whether asender wants to be interrupted */
+       SEND_PING,              /* whether asender should send a ping asap */
+
+       STOP_SYNC_TIMER,        /* tell timer to cancel itself */
+       UNPLUG_QUEUED,          /* only relevant with kernel 2.4 */
+       UNPLUG_REMOTE,          /* sending a "UnplugRemote" could help */
+       MD_DIRTY,               /* current uuids and flags not yet on disk */
+       DISCARD_CONCURRENT,     /* Set on one node, cleared on the peer! */
+       USE_DEGR_WFC_T,         /* degr-wfc-timeout instead of wfc-timeout. */
+       CLUSTER_ST_CHANGE,      /* Cluster wide state change going on... */
+       CL_ST_CHG_SUCCESS,
+       CL_ST_CHG_FAIL,
+       CRASHED_PRIMARY,        /* This node was a crashed primary.
+                                * Gets cleared when the state.conn
+                                * goes into C_CONNECTED state. */
+       WRITE_BM_AFTER_RESYNC,  /* A kmalloc() during resync failed */
+       NO_BARRIER_SUPP,        /* underlying block device doesn't implement barriers */
+       CONSIDER_RESYNC,
+
+       MD_NO_BARRIER,          /* meta data device does not support barriers,
+                                  so don't even try */
+       SUSPEND_IO,             /* suspend application io */
+       BITMAP_IO,              /* suspend application io;
+                                  once no more io in flight, start bitmap io */
+       BITMAP_IO_QUEUED,       /* Started bitmap IO */
+       RESYNC_AFTER_NEG,       /* Resync after online grow after the attach&negotiate finished. */
+       NET_CONGESTED,          /* The data socket is congested */
+
+       CONFIG_PENDING,         /* serialization of (re)configuration requests.
+                                * if set, also prevents the device from dying */
+       DEVICE_DYING,           /* device became unconfigured,
+                                * but worker thread is still handling the cleanup.
+                                * reconfiguring (nl_disk_conf, nl_net_conf) is dissalowed,
+                                * while this is set. */
+       RESIZE_PENDING,         /* Size change detected locally, waiting for the response from
+                                * the peer, if it changed there as well. */
+};
+
+struct drbd_bitmap; /* opaque for drbd_conf */
+
+/* TODO sort members for performance
+ * MAYBE group them further */
+
+/* THINK maybe we actually want to use the default "event/%s" worker threads
+ * or similar in linux 2.6, which uses per cpu data and threads.
+ *
+ * To be general, this might need a spin_lock member.
+ * For now, please use the mdev->req_lock to protect list_head,
+ * see drbd_queue_work below.
+ */
+struct drbd_work_queue {
+       struct list_head q;
+       struct semaphore s; /* producers up it, worker down()s it */
+       spinlock_t q_lock;  /* to protect the list. */
+};
+
+struct drbd_socket {
+       struct drbd_work_queue work;
+       struct mutex mutex;
+       struct socket    *socket;
+       /* this way we get our
+        * send/receive buffers off the stack */
+       union p_polymorph sbuf;
+       union p_polymorph rbuf;
+};
+
+struct drbd_md {
+       u64 md_offset;          /* sector offset to 'super' block */
+
+       u64 la_size_sect;       /* last agreed size, unit sectors */
+       u64 uuid[UI_SIZE];
+       u64 device_uuid;
+       u32 flags;
+       u32 md_size_sect;
+
+       s32 al_offset;  /* signed relative sector offset to al area */
+       s32 bm_offset;  /* signed relative sector offset to bitmap */
+
+       /* u32 al_nr_extents;      important for restoring the AL
+        * is stored into  sync_conf.al_extents, which in turn
+        * gets applied to act_log->nr_elements
+        */
+};
+
+/* for sync_conf and other types... */
+#define NL_PACKET(name, number, fields) struct name { fields };
+#define NL_INTEGER(pn,pr,member) int member;
+#define NL_INT64(pn,pr,member) __u64 member;
+#define NL_BIT(pn,pr,member)   unsigned member:1;
+#define NL_STRING(pn,pr,member,len) unsigned char member[len]; int member ## _len;
+#include "linux/drbd_nl.h"
+
+struct drbd_backing_dev {
+       struct block_device *backing_bdev;
+       struct block_device *md_bdev;
+       struct file *lo_file;
+       struct file *md_file;
+       struct drbd_md md;
+       struct disk_conf dc; /* The user provided config... */
+       sector_t known_size; /* last known size of that backing device */
+};
+
+struct drbd_md_io {
+       struct drbd_conf *mdev;
+       struct completion event;
+       int error;
+};
+
+struct bm_io_work {
+       struct drbd_work w;
+       char *why;
+       int (*io_fn)(struct drbd_conf *mdev);
+       void (*done)(struct drbd_conf *mdev, int rv);
+};
+
+enum write_ordering_e {
+       WO_none,
+       WO_drain_io,
+       WO_bdev_flush,
+       WO_bio_barrier
+};
+
+struct drbd_conf {
+       /* things that are stored as / read from meta data on disk */
+       unsigned long flags;
+
+       /* configured by drbdsetup */
+       struct net_conf *net_conf; /* protected by get_net_conf() and put_net_conf() */
+       struct syncer_conf sync_conf;
+       struct drbd_backing_dev *ldev __protected_by(local);
+
+       sector_t p_size;     /* partner's disk size */
+       struct request_queue *rq_queue;
+       struct block_device *this_bdev;
+       struct gendisk      *vdisk;
+
+       struct drbd_socket data; /* data/barrier/cstate/parameter packets */
+       struct drbd_socket meta; /* ping/ack (metadata) packets */
+       int agreed_pro_version;  /* actually used protocol version */
+       unsigned long last_received; /* in jiffies, either socket */
+       unsigned int ko_count;
+       struct drbd_work  resync_work,
+                         unplug_work,
+                         md_sync_work;
+       struct timer_list resync_timer;
+       struct timer_list md_sync_timer;
+
+       /* Used after attach while negotiating new disk state. */
+       union drbd_state new_state_tmp;
+
+       union drbd_state state;
+       wait_queue_head_t misc_wait;
+       wait_queue_head_t state_wait;  /* upon each state change. */
+       unsigned int send_cnt;
+       unsigned int recv_cnt;
+       unsigned int read_cnt;
+       unsigned int writ_cnt;
+       unsigned int al_writ_cnt;
+       unsigned int bm_writ_cnt;
+       atomic_t ap_bio_cnt;     /* Requests we need to complete */
+       atomic_t ap_pending_cnt; /* AP data packets on the wire, ack expected */
+       atomic_t rs_pending_cnt; /* RS request/data packets on the wire */
+       atomic_t unacked_cnt;    /* Need to send replys for */
+       atomic_t local_cnt;      /* Waiting for local completion */
+       atomic_t net_cnt;        /* Users of net_conf */
+       spinlock_t req_lock;
+       struct drbd_tl_epoch *unused_spare_tle; /* for pre-allocation */
+       struct drbd_tl_epoch *newest_tle;
+       struct drbd_tl_epoch *oldest_tle;
+       struct list_head out_of_sequence_requests;
+       struct hlist_head *tl_hash;
+       unsigned int tl_hash_s;
+
+       /* blocks to sync in this run [unit BM_BLOCK_SIZE] */
+       unsigned long rs_total;
+       /* number of sync IOs that failed in this run */
+       unsigned long rs_failed;
+       /* Syncer's start time [unit jiffies] */
+       unsigned long rs_start;
+       /* cumulated time in PausedSyncX state [unit jiffies] */
+       unsigned long rs_paused;
+       /* block not up-to-date at mark [unit BM_BLOCK_SIZE] */
+       unsigned long rs_mark_left;
+       /* marks's time [unit jiffies] */
+       unsigned long rs_mark_time;
+       /* skipped because csum was equeal [unit BM_BLOCK_SIZE] */
+       unsigned long rs_same_csum;
+
+       /* where does the admin want us to start? (sector) */
+       sector_t ov_start_sector;
+       /* where are we now? (sector) */
+       sector_t ov_position;
+       /* Start sector of out of sync range (to merge printk reporting). */
+       sector_t ov_last_oos_start;
+       /* size of out-of-sync range in sectors. */
+       sector_t ov_last_oos_size;
+       unsigned long ov_left; /* in bits */
+       struct crypto_hash *csums_tfm;
+       struct crypto_hash *verify_tfm;
+
+       struct drbd_thread receiver;
+       struct drbd_thread worker;
+       struct drbd_thread asender;
+       struct drbd_bitmap *bitmap;
+       unsigned long bm_resync_fo; /* bit offset for drbd_bm_find_next */
+
+       /* Used to track operations of resync... */
+       struct lru_cache *resync;
+       /* Number of locked elements in resync LRU */
+       unsigned int resync_locked;
+       /* resync extent number waiting for application requests */
+       unsigned int resync_wenr;
+
+       int open_cnt;
+       u64 *p_uuid;
+       struct drbd_epoch *current_epoch;
+       spinlock_t epoch_lock;
+       unsigned int epochs;
+       enum write_ordering_e write_ordering;
+       struct list_head active_ee; /* IO in progress */
+       struct list_head sync_ee;   /* IO in progress */
+       struct list_head done_ee;   /* send ack */
+       struct list_head read_ee;   /* IO in progress */
+       struct list_head net_ee;    /* zero-copy network send in progress */
+       struct hlist_head *ee_hash; /* is proteced by req_lock! */
+       unsigned int ee_hash_s;
+
+       /* this one is protected by ee_lock, single thread */
+       struct drbd_epoch_entry *last_write_w_barrier;
+
+       int next_barrier_nr;
+       struct hlist_head *app_reads_hash; /* is proteced by req_lock */
+       struct list_head resync_reads;
+       atomic_t pp_in_use;
+       wait_queue_head_t ee_wait;
+       struct page *md_io_page;        /* one page buffer for md_io */
+       struct page *md_io_tmpp;        /* for logical_block_size != 512 */
+       struct mutex md_io_mutex;       /* protects the md_io_buffer */
+       spinlock_t al_lock;
+       wait_queue_head_t al_wait;
+       struct lru_cache *act_log;      /* activity log */
+       unsigned int al_tr_number;
+       int al_tr_cycle;
+       int al_tr_pos;   /* position of the next transaction in the journal */
+       struct crypto_hash *cram_hmac_tfm;
+       struct crypto_hash *integrity_w_tfm; /* to be used by the worker thread */
+       struct crypto_hash *integrity_r_tfm; /* to be used by the receiver thread */
+       void *int_dig_out;
+       void *int_dig_in;
+       void *int_dig_vv;
+       wait_queue_head_t seq_wait;
+       atomic_t packet_seq;
+       unsigned int peer_seq;
+       spinlock_t peer_seq_lock;
+       unsigned int minor;
+       unsigned long comm_bm_set; /* communicated number of set bits. */
+       cpumask_var_t cpu_mask;
+       struct bm_io_work bm_io_work;
+       u64 ed_uuid; /* UUID of the exposed data */
+       struct mutex state_mutex;
+       char congestion_reason;  /* Why we where congested... */
+};
+
+static inline struct drbd_conf *minor_to_mdev(unsigned int minor)
+{
+       struct drbd_conf *mdev;
+
+       mdev = minor < minor_count ? minor_table[minor] : NULL;
+
+       return mdev;
+}
+
+static inline unsigned int mdev_to_minor(struct drbd_conf *mdev)
+{
+       return mdev->minor;
+}
+
+/* returns 1 if it was successfull,
+ * returns 0 if there was no data socket.
+ * so wherever you are going to use the data.socket, e.g. do
+ * if (!drbd_get_data_sock(mdev))
+ *     return 0;
+ *     CODE();
+ * drbd_put_data_sock(mdev);
+ */
+static inline int drbd_get_data_sock(struct drbd_conf *mdev)
+{
+       mutex_lock(&mdev->data.mutex);
+       /* drbd_disconnect() could have called drbd_free_sock()
+        * while we were waiting in down()... */
+       if (unlikely(mdev->data.socket == NULL)) {
+               mutex_unlock(&mdev->data.mutex);
+               return 0;
+       }
+       return 1;
+}
+
+static inline void drbd_put_data_sock(struct drbd_conf *mdev)
+{
+       mutex_unlock(&mdev->data.mutex);
+}
+
+/*
+ * function declarations
+ *************************/
+
+/* drbd_main.c */
+
+enum chg_state_flags {
+       CS_HARD = 1,
+       CS_VERBOSE = 2,
+       CS_WAIT_COMPLETE = 4,
+       CS_SERIALIZE    = 8,
+       CS_ORDERED      = CS_WAIT_COMPLETE + CS_SERIALIZE,
+};
+
+extern void drbd_init_set_defaults(struct drbd_conf *mdev);
+extern int drbd_change_state(struct drbd_conf *mdev, enum chg_state_flags f,
+                       union drbd_state mask, union drbd_state val);
+extern void drbd_force_state(struct drbd_conf *, union drbd_state,
+                       union drbd_state);
+extern int _drbd_request_state(struct drbd_conf *, union drbd_state,
+                       union drbd_state, enum chg_state_flags);
+extern int __drbd_set_state(struct drbd_conf *, union drbd_state,
+                           enum chg_state_flags, struct completion *done);
+extern void print_st_err(struct drbd_conf *, union drbd_state,
+                       union drbd_state, int);
+extern int  drbd_thread_start(struct drbd_thread *thi);
+extern void _drbd_thread_stop(struct drbd_thread *thi, int restart, int wait);
+#ifdef CONFIG_SMP
+extern void drbd_thread_current_set_cpu(struct drbd_conf *mdev);
+extern void drbd_calc_cpu_mask(struct drbd_conf *mdev);
+#else
+#define drbd_thread_current_set_cpu(A) ({})
+#define drbd_calc_cpu_mask(A) ({})
+#endif
+extern void drbd_free_resources(struct drbd_conf *mdev);
+extern void tl_release(struct drbd_conf *mdev, unsigned int barrier_nr,
+                      unsigned int set_size);
+extern void tl_clear(struct drbd_conf *mdev);
+extern void _tl_add_barrier(struct drbd_conf *, struct drbd_tl_epoch *);
+extern void drbd_free_sock(struct drbd_conf *mdev);
+extern int drbd_send(struct drbd_conf *mdev, struct socket *sock,
+                       void *buf, size_t size, unsigned msg_flags);
+extern int drbd_send_protocol(struct drbd_conf *mdev);
+extern int drbd_send_uuids(struct drbd_conf *mdev);
+extern int drbd_send_uuids_skip_initial_sync(struct drbd_conf *mdev);
+extern int drbd_send_sync_uuid(struct drbd_conf *mdev, u64 val);
+extern int drbd_send_sizes(struct drbd_conf *mdev, int trigger_reply);
+extern int _drbd_send_state(struct drbd_conf *mdev);
+extern int drbd_send_state(struct drbd_conf *mdev);
+extern int _drbd_send_cmd(struct drbd_conf *mdev, struct socket *sock,
+                       enum drbd_packets cmd, struct p_header *h,
+                       size_t size, unsigned msg_flags);
+#define USE_DATA_SOCKET 1
+#define USE_META_SOCKET 0
+extern int drbd_send_cmd(struct drbd_conf *mdev, int use_data_socket,
+                       enum drbd_packets cmd, struct p_header *h,
+                       size_t size);
+extern int drbd_send_cmd2(struct drbd_conf *mdev, enum drbd_packets cmd,
+                       char *data, size_t size);
+extern int drbd_send_sync_param(struct drbd_conf *mdev, struct syncer_conf *sc);
+extern int drbd_send_b_ack(struct drbd_conf *mdev, u32 barrier_nr,
+                       u32 set_size);
+extern int drbd_send_ack(struct drbd_conf *mdev, enum drbd_packets cmd,
+                       struct drbd_epoch_entry *e);
+extern int drbd_send_ack_rp(struct drbd_conf *mdev, enum drbd_packets cmd,
+                       struct p_block_req *rp);
+extern int drbd_send_ack_dp(struct drbd_conf *mdev, enum drbd_packets cmd,
+                       struct p_data *dp);
+extern int drbd_send_ack_ex(struct drbd_conf *mdev, enum drbd_packets cmd,
+                           sector_t sector, int blksize, u64 block_id);
+extern int drbd_send_block(struct drbd_conf *mdev, enum drbd_packets cmd,
+                          struct drbd_epoch_entry *e);
+extern int drbd_send_dblock(struct drbd_conf *mdev, struct drbd_request *req);
+extern int _drbd_send_barrier(struct drbd_conf *mdev,
+                       struct drbd_tl_epoch *barrier);
+extern int drbd_send_drequest(struct drbd_conf *mdev, int cmd,
+                             sector_t sector, int size, u64 block_id);
+extern int drbd_send_drequest_csum(struct drbd_conf *mdev,
+                                  sector_t sector,int size,
+                                  void *digest, int digest_size,
+                                  enum drbd_packets cmd);
+extern int drbd_send_ov_request(struct drbd_conf *mdev,sector_t sector,int size);
+
+extern int drbd_send_bitmap(struct drbd_conf *mdev);
+extern int _drbd_send_bitmap(struct drbd_conf *mdev);
+extern int drbd_send_sr_reply(struct drbd_conf *mdev, int retcode);
+extern void drbd_free_bc(struct drbd_backing_dev *ldev);
+extern void drbd_mdev_cleanup(struct drbd_conf *mdev);
+
+/* drbd_meta-data.c (still in drbd_main.c) */
+extern void drbd_md_sync(struct drbd_conf *mdev);
+extern int  drbd_md_read(struct drbd_conf *mdev, struct drbd_backing_dev *bdev);
+/* maybe define them below as inline? */
+extern void drbd_uuid_set(struct drbd_conf *mdev, int idx, u64 val) __must_hold(local);
+extern void _drbd_uuid_set(struct drbd_conf *mdev, int idx, u64 val) __must_hold(local);
+extern void drbd_uuid_new_current(struct drbd_conf *mdev) __must_hold(local);
+extern void _drbd_uuid_new_current(struct drbd_conf *mdev) __must_hold(local);
+extern void drbd_uuid_set_bm(struct drbd_conf *mdev, u64 val) __must_hold(local);
+extern void drbd_md_set_flag(struct drbd_conf *mdev, int flags) __must_hold(local);
+extern void drbd_md_clear_flag(struct drbd_conf *mdev, int flags)__must_hold(local);
+extern int drbd_md_test_flag(struct drbd_backing_dev *, int);
+extern void drbd_md_mark_dirty(struct drbd_conf *mdev);
+extern void drbd_queue_bitmap_io(struct drbd_conf *mdev,
+                                int (*io_fn)(struct drbd_conf *),
+                                void (*done)(struct drbd_conf *, int),
+                                char *why);
+extern int drbd_bmio_set_n_write(struct drbd_conf *mdev);
+extern int drbd_bmio_clear_n_write(struct drbd_conf *mdev);
+extern int drbd_bitmap_io(struct drbd_conf *mdev, int (*io_fn)(struct drbd_conf *), char *why);
+
+
+/* Meta data layout
+   We reserve a 128MB Block (4k aligned)
+   * either at the end of the backing device
+   * or on a seperate meta data device. */
+
+#define MD_RESERVED_SECT (128LU << 11)  /* 128 MB, unit sectors */
+/* The following numbers are sectors */
+#define MD_AL_OFFSET 8     /* 8 Sectors after start of meta area */
+#define MD_AL_MAX_SIZE 64   /* = 32 kb LOG  ~ 3776 extents ~ 14 GB Storage */
+/* Allows up to about 3.8TB */
+#define MD_BM_OFFSET (MD_AL_OFFSET + MD_AL_MAX_SIZE)
+
+/* Since the smalles IO unit is usually 512 byte */
+#define MD_SECTOR_SHIFT         9
+#define MD_SECTOR_SIZE  (1<<MD_SECTOR_SHIFT)
+
+/* activity log */
+#define AL_EXTENTS_PT ((MD_SECTOR_SIZE-12)/8-1) /* 61 ; Extents per 512B sector */
+#define AL_EXTENT_SHIFT 22              /* One extent represents 4M Storage */
+#define AL_EXTENT_SIZE (1<<AL_EXTENT_SHIFT)
+
+#if BITS_PER_LONG == 32
+#define LN2_BPL 5
+#define cpu_to_lel(A) cpu_to_le32(A)
+#define lel_to_cpu(A) le32_to_cpu(A)
+#elif BITS_PER_LONG == 64
+#define LN2_BPL 6
+#define cpu_to_lel(A) cpu_to_le64(A)
+#define lel_to_cpu(A) le64_to_cpu(A)
+#else
+#error "LN2 of BITS_PER_LONG unknown!"
+#endif
+
+/* resync bitmap */
+/* 16MB sized 'bitmap extent' to track syncer usage */
+struct bm_extent {
+       int rs_left; /* number of bits set (out of sync) in this extent. */
+       int rs_failed; /* number of failed resync requests in this extent. */
+       unsigned long flags;
+       struct lc_element lce;
+};
+
+#define BME_NO_WRITES  0  /* bm_extent.flags: no more requests on this one! */
+#define BME_LOCKED     1  /* bm_extent.flags: syncer active on this one. */
+
+/* drbd_bitmap.c */
+/*
+ * We need to store one bit for a block.
+ * Example: 1GB disk @ 4096 byte blocks ==> we need 32 KB bitmap.
+ * Bit 0 ==> local node thinks this block is binary identical on both nodes
+ * Bit 1 ==> local node thinks this block needs to be synced.
+ */
+
+#define BM_BLOCK_SHIFT  12                      /* 4k per bit */
+#define BM_BLOCK_SIZE   (1<<BM_BLOCK_SHIFT)
+/* (9+3) : 512 bytes @ 8 bits; representing 16M storage
+ * per sector of on disk bitmap */
+#define BM_EXT_SHIFT    (BM_BLOCK_SHIFT + MD_SECTOR_SHIFT + 3)  /* = 24 */
+#define BM_EXT_SIZE     (1<<BM_EXT_SHIFT)
+
+#if (BM_EXT_SHIFT != 24) || (BM_BLOCK_SHIFT != 12)
+#error "HAVE YOU FIXED drbdmeta AS WELL??"
+#endif
+
+/* thus many _storage_ sectors are described by one bit */
+#define BM_SECT_TO_BIT(x)   ((x)>>(BM_BLOCK_SHIFT-9))
+#define BM_BIT_TO_SECT(x)   ((sector_t)(x)<<(BM_BLOCK_SHIFT-9))
+#define BM_SECT_PER_BIT     BM_BIT_TO_SECT(1)
+
+/* bit to represented kilo byte conversion */
+#define Bit2KB(bits) ((bits)<<(BM_BLOCK_SHIFT-10))
+
+/* in which _bitmap_ extent (resp. sector) the bit for a certain
+ * _storage_ sector is located in */
+#define BM_SECT_TO_EXT(x)   ((x)>>(BM_EXT_SHIFT-9))
+
+/* how much _storage_ sectors we have per bitmap sector */
+#define BM_EXT_TO_SECT(x)   ((sector_t)(x) << (BM_EXT_SHIFT-9))
+#define BM_SECT_PER_EXT     BM_EXT_TO_SECT(1)
+
+/* in one sector of the bitmap, we have this many activity_log extents. */
+#define AL_EXT_PER_BM_SECT  (1 << (BM_EXT_SHIFT - AL_EXTENT_SHIFT))
+#define BM_WORDS_PER_AL_EXT (1 << (AL_EXTENT_SHIFT-BM_BLOCK_SHIFT-LN2_BPL))
+
+#define BM_BLOCKS_PER_BM_EXT_B (BM_EXT_SHIFT - BM_BLOCK_SHIFT)
+#define BM_BLOCKS_PER_BM_EXT_MASK  ((1<<BM_BLOCKS_PER_BM_EXT_B) - 1)
+
+/* the extent in "PER_EXTENT" below is an activity log extent
+ * we need that many (long words/bytes) to store the bitmap
+ *                  of one AL_EXTENT_SIZE chunk of storage.
+ * we can store the bitmap for that many AL_EXTENTS within
+ * one sector of the _on_disk_ bitmap:
+ * bit  0        bit 37   bit 38            bit (512*8)-1
+ *          ...|........|........|.. // ..|........|
+ * sect. 0      `296     `304                     ^(512*8*8)-1
+ *
+#define BM_WORDS_PER_EXT    ( (AL_EXT_SIZE/BM_BLOCK_SIZE) / BITS_PER_LONG )
+#define BM_BYTES_PER_EXT    ( (AL_EXT_SIZE/BM_BLOCK_SIZE) / 8 )  // 128
+#define BM_EXT_PER_SECT            ( 512 / BM_BYTES_PER_EXTENT )        //   4
+ */
+
+#define DRBD_MAX_SECTORS_32 (0xffffffffLU)
+#define DRBD_MAX_SECTORS_BM \
+         ((MD_RESERVED_SECT - MD_BM_OFFSET) * (1LL<<(BM_EXT_SHIFT-9)))
+#if DRBD_MAX_SECTORS_BM < DRBD_MAX_SECTORS_32
+#define DRBD_MAX_SECTORS      DRBD_MAX_SECTORS_BM
+#define DRBD_MAX_SECTORS_FLEX DRBD_MAX_SECTORS_BM
+#elif !defined(CONFIG_LBD) && BITS_PER_LONG == 32
+#define DRBD_MAX_SECTORS      DRBD_MAX_SECTORS_32
+#define DRBD_MAX_SECTORS_FLEX DRBD_MAX_SECTORS_32
+#else
+#define DRBD_MAX_SECTORS      DRBD_MAX_SECTORS_BM
+/* 16 TB in units of sectors */
+#if BITS_PER_LONG == 32
+/* adjust by one page worth of bitmap,
+ * so we won't wrap around in drbd_bm_find_next_bit.
+ * you should use 64bit OS for that much storage, anyways. */
+#define DRBD_MAX_SECTORS_FLEX BM_BIT_TO_SECT(0xffff7fff)
+#else
+#define DRBD_MAX_SECTORS_FLEX BM_BIT_TO_SECT(0x1LU << 32)
+#endif
+#endif
+
+/* Sector shift value for the "hash" functions of tl_hash and ee_hash tables.
+ * With a value of 6 all IO in one 32K block make it to the same slot of the
+ * hash table. */
+#define HT_SHIFT 6
+#define DRBD_MAX_SEGMENT_SIZE (1U<<(9+HT_SHIFT))
+
+/* Number of elements in the app_reads_hash */
+#define APP_R_HSIZE 15
+
+extern int  drbd_bm_init(struct drbd_conf *mdev);
+extern int  drbd_bm_resize(struct drbd_conf *mdev, sector_t sectors);
+extern void drbd_bm_cleanup(struct drbd_conf *mdev);
+extern void drbd_bm_set_all(struct drbd_conf *mdev);
+extern void drbd_bm_clear_all(struct drbd_conf *mdev);
+extern int  drbd_bm_set_bits(
+               struct drbd_conf *mdev, unsigned long s, unsigned long e);
+extern int  drbd_bm_clear_bits(
+               struct drbd_conf *mdev, unsigned long s, unsigned long e);
+/* bm_set_bits variant for use while holding drbd_bm_lock */
+extern void _drbd_bm_set_bits(struct drbd_conf *mdev,
+               const unsigned long s, const unsigned long e);
+extern int  drbd_bm_test_bit(struct drbd_conf *mdev, unsigned long bitnr);
+extern int  drbd_bm_e_weight(struct drbd_conf *mdev, unsigned long enr);
+extern int  drbd_bm_write_sect(struct drbd_conf *mdev, unsigned long enr) __must_hold(local);
+extern int  drbd_bm_read(struct drbd_conf *mdev) __must_hold(local);
+extern int  drbd_bm_write(struct drbd_conf *mdev) __must_hold(local);
+extern unsigned long drbd_bm_ALe_set_all(struct drbd_conf *mdev,
+               unsigned long al_enr);
+extern size_t       drbd_bm_words(struct drbd_conf *mdev);
+extern unsigned long drbd_bm_bits(struct drbd_conf *mdev);
+extern sector_t      drbd_bm_capacity(struct drbd_conf *mdev);
+extern unsigned long drbd_bm_find_next(struct drbd_conf *mdev, unsigned long bm_fo);
+/* bm_find_next variants for use while you hold drbd_bm_lock() */
+extern unsigned long _drbd_bm_find_next(struct drbd_conf *mdev, unsigned long bm_fo);
+extern unsigned long _drbd_bm_find_next_zero(struct drbd_conf *mdev, unsigned long bm_fo);
+extern unsigned long drbd_bm_total_weight(struct drbd_conf *mdev);
+extern int drbd_bm_rs_done(struct drbd_conf *mdev);
+/* for receive_bitmap */
+extern void drbd_bm_merge_lel(struct drbd_conf *mdev, size_t offset,
+               size_t number, unsigned long *buffer);
+/* for _drbd_send_bitmap and drbd_bm_write_sect */
+extern void drbd_bm_get_lel(struct drbd_conf *mdev, size_t offset,
+               size_t number, unsigned long *buffer);
+
+extern void drbd_bm_lock(struct drbd_conf *mdev, char *why);
+extern void drbd_bm_unlock(struct drbd_conf *mdev);
+
+extern int drbd_bm_count_bits(struct drbd_conf *mdev, const unsigned long s, const unsigned long e);
+/* drbd_main.c */
+
+extern struct kmem_cache *drbd_request_cache;
+extern struct kmem_cache *drbd_ee_cache;       /* epoch entries */
+extern struct kmem_cache *drbd_bm_ext_cache;   /* bitmap extents */
+extern struct kmem_cache *drbd_al_ext_cache;   /* activity log extents */
+extern mempool_t *drbd_request_mempool;
+extern mempool_t *drbd_ee_mempool;
+
+extern struct page *drbd_pp_pool; /* drbd's page pool */
+extern spinlock_t   drbd_pp_lock;
+extern int         drbd_pp_vacant;
+extern wait_queue_head_t drbd_pp_wait;
+
+extern rwlock_t global_state_lock;
+
+extern struct drbd_conf *drbd_new_device(unsigned int minor);
+extern void drbd_free_mdev(struct drbd_conf *mdev);
+
+extern int proc_details;
+
+/* drbd_req */
+extern int drbd_make_request_26(struct request_queue *q, struct bio *bio);
+extern int drbd_read_remote(struct drbd_conf *mdev, struct drbd_request *req);
+extern int drbd_merge_bvec(struct request_queue *q, struct bvec_merge_data *bvm, struct bio_vec *bvec);
+extern int is_valid_ar_handle(struct drbd_request *, sector_t);
+
+
+/* drbd_nl.c */
+extern void drbd_suspend_io(struct drbd_conf *mdev);
+extern void drbd_resume_io(struct drbd_conf *mdev);
+extern char *ppsize(char *buf, unsigned long long size);
+extern sector_t drbd_new_dev_size(struct drbd_conf *,
+               struct drbd_backing_dev *);
+enum determine_dev_size { dev_size_error = -1, unchanged = 0, shrunk = 1, grew = 2 };
+extern enum determine_dev_size drbd_determin_dev_size(struct drbd_conf *) __must_hold(local);
+extern void resync_after_online_grow(struct drbd_conf *);
+extern void drbd_setup_queue_param(struct drbd_conf *mdev, unsigned int) __must_hold(local);
+extern int drbd_set_role(struct drbd_conf *mdev, enum drbd_role new_role,
+               int force);
+enum drbd_disk_state drbd_try_outdate_peer(struct drbd_conf *mdev);
+extern int drbd_khelper(struct drbd_conf *mdev, char *cmd);
+
+/* drbd_worker.c */
+extern int drbd_worker(struct drbd_thread *thi);
+extern int drbd_alter_sa(struct drbd_conf *mdev, int na);
+extern void drbd_start_resync(struct drbd_conf *mdev, enum drbd_conns side);
+extern void resume_next_sg(struct drbd_conf *mdev);
+extern void suspend_other_sg(struct drbd_conf *mdev);
+extern int drbd_resync_finished(struct drbd_conf *mdev);
+/* maybe rather drbd_main.c ? */
+extern int drbd_md_sync_page_io(struct drbd_conf *mdev,
+               struct drbd_backing_dev *bdev, sector_t sector, int rw);
+extern void drbd_ov_oos_found(struct drbd_conf*, sector_t, int);
+
+static inline void ov_oos_print(struct drbd_conf *mdev)
+{
+       if (mdev->ov_last_oos_size) {
+               dev_err(DEV, "Out of sync: start=%llu, size=%lu (sectors)\n",
+                    (unsigned long long)mdev->ov_last_oos_start,
+                    (unsigned long)mdev->ov_last_oos_size);
+       }
+       mdev->ov_last_oos_size=0;
+}
+
+
+extern void drbd_csum(struct drbd_conf *, struct crypto_hash *, struct bio *, void *);
+/* worker callbacks */
+extern int w_req_cancel_conflict(struct drbd_conf *, struct drbd_work *, int);
+extern int w_read_retry_remote(struct drbd_conf *, struct drbd_work *, int);
+extern int w_e_end_data_req(struct drbd_conf *, struct drbd_work *, int);
+extern int w_e_end_rsdata_req(struct drbd_conf *, struct drbd_work *, int);
+extern int w_e_end_csum_rs_req(struct drbd_conf *, struct drbd_work *, int);
+extern int w_e_end_ov_reply(struct drbd_conf *, struct drbd_work *, int);
+extern int w_e_end_ov_req(struct drbd_conf *, struct drbd_work *, int);
+extern int w_ov_finished(struct drbd_conf *, struct drbd_work *, int);
+extern int w_resync_inactive(struct drbd_conf *, struct drbd_work *, int);
+extern int w_resume_next_sg(struct drbd_conf *, struct drbd_work *, int);
+extern int w_io_error(struct drbd_conf *, struct drbd_work *, int);
+extern int w_send_write_hint(struct drbd_conf *, struct drbd_work *, int);
+extern int w_make_resync_request(struct drbd_conf *, struct drbd_work *, int);
+extern int w_send_dblock(struct drbd_conf *, struct drbd_work *, int);
+extern int w_send_barrier(struct drbd_conf *, struct drbd_work *, int);
+extern int w_send_read_req(struct drbd_conf *, struct drbd_work *, int);
+extern int w_prev_work_done(struct drbd_conf *, struct drbd_work *, int);
+extern int w_e_reissue(struct drbd_conf *, struct drbd_work *, int);
+
+extern void resync_timer_fn(unsigned long data);
+
+/* drbd_receiver.c */
+extern int drbd_release_ee(struct drbd_conf *mdev, struct list_head *list);
+extern struct drbd_epoch_entry *drbd_alloc_ee(struct drbd_conf *mdev,
+                                           u64 id,
+                                           sector_t sector,
+                                           unsigned int data_size,
+                                           gfp_t gfp_mask) __must_hold(local);
+extern void drbd_free_ee(struct drbd_conf *mdev, struct drbd_epoch_entry *e);
+extern void drbd_wait_ee_list_empty(struct drbd_conf *mdev,
+               struct list_head *head);
+extern void _drbd_wait_ee_list_empty(struct drbd_conf *mdev,
+               struct list_head *head);
+extern void drbd_set_recv_tcq(struct drbd_conf *mdev, int tcq_enabled);
+extern void _drbd_clear_done_ee(struct drbd_conf *mdev, struct list_head *to_be_freed);
+extern void drbd_flush_workqueue(struct drbd_conf *mdev);
+
+/* yes, there is kernel_setsockopt, but only since 2.6.18. we don't need to
+ * mess with get_fs/set_fs, we know we are KERNEL_DS always. */
+static inline int drbd_setsockopt(struct socket *sock, int level, int optname,
+                       char __user *optval, int optlen)
+{
+       int err;
+       if (level == SOL_SOCKET)
+               err = sock_setsockopt(sock, level, optname, optval, optlen);
+       else
+               err = sock->ops->setsockopt(sock, level, optname, optval,
+                                           optlen);
+       return err;
+}
+
+static inline void drbd_tcp_cork(struct socket *sock)
+{
+       int __user val = 1;
+       (void) drbd_setsockopt(sock, SOL_TCP, TCP_CORK,
+                       (char __user *)&val, sizeof(val));
+}
+
+static inline void drbd_tcp_uncork(struct socket *sock)
+{
+       int __user val = 0;
+       (void) drbd_setsockopt(sock, SOL_TCP, TCP_CORK,
+                       (char __user *)&val, sizeof(val));
+}
+
+static inline void drbd_tcp_nodelay(struct socket *sock)
+{
+       int __user val = 1;
+       (void) drbd_setsockopt(sock, SOL_TCP, TCP_NODELAY,
+                       (char __user *)&val, sizeof(val));
+}
+
+static inline void drbd_tcp_quickack(struct socket *sock)
+{
+       int __user val = 1;
+       (void) drbd_setsockopt(sock, SOL_TCP, TCP_QUICKACK,
+                       (char __user *)&val, sizeof(val));
+}
+
+void drbd_bump_write_ordering(struct drbd_conf *mdev, enum write_ordering_e wo);
+
+/* drbd_proc.c */
+extern struct proc_dir_entry *drbd_proc;
+extern struct file_operations drbd_proc_fops;
+extern const char *drbd_conn_str(enum drbd_conns s);
+extern const char *drbd_role_str(enum drbd_role s);
+
+/* drbd_actlog.c */
+extern void drbd_al_begin_io(struct drbd_conf *mdev, sector_t sector);
+extern void drbd_al_complete_io(struct drbd_conf *mdev, sector_t sector);
+extern void drbd_rs_complete_io(struct drbd_conf *mdev, sector_t sector);
+extern int drbd_rs_begin_io(struct drbd_conf *mdev, sector_t sector);
+extern int drbd_try_rs_begin_io(struct drbd_conf *mdev, sector_t sector);
+extern void drbd_rs_cancel_all(struct drbd_conf *mdev);
+extern int drbd_rs_del_all(struct drbd_conf *mdev);
+extern void drbd_rs_failed_io(struct drbd_conf *mdev,
+               sector_t sector, int size);
+extern int drbd_al_read_log(struct drbd_conf *mdev, struct drbd_backing_dev *);
+extern void __drbd_set_in_sync(struct drbd_conf *mdev, sector_t sector,
+               int size, const char *file, const unsigned int line);
+#define drbd_set_in_sync(mdev, sector, size) \
+       __drbd_set_in_sync(mdev, sector, size, __FILE__, __LINE__)
+extern void __drbd_set_out_of_sync(struct drbd_conf *mdev, sector_t sector,
+               int size, const char *file, const unsigned int line);
+#define drbd_set_out_of_sync(mdev, sector, size) \
+       __drbd_set_out_of_sync(mdev, sector, size, __FILE__, __LINE__)
+extern void drbd_al_apply_to_bm(struct drbd_conf *mdev);
+extern void drbd_al_to_on_disk_bm(struct drbd_conf *mdev);
+extern void drbd_al_shrink(struct drbd_conf *mdev);
+
+
+/* drbd_nl.c */
+
+void drbd_nl_cleanup(void);
+int __init drbd_nl_init(void);
+void drbd_bcast_state(struct drbd_conf *mdev, union drbd_state);
+void drbd_bcast_sync_progress(struct drbd_conf *mdev);
+void drbd_bcast_ee(struct drbd_conf *mdev,
+               const char *reason, const int dgs,
+               const char* seen_hash, const char* calc_hash,
+               const struct drbd_epoch_entry* e);
+
+
+/**
+ * DOC: DRBD State macros
+ *
+ * These macros are used to express state changes in easily readable form.
+ *
+ * The NS macros expand to a mask and a value, that can be bit ored onto the
+ * current state as soon as the spinlock (req_lock) was taken.
+ *
+ * The _NS macros are used for state functions that get called with the
+ * spinlock. These macros expand directly to the new state value.
+ *
+ * Besides the basic forms NS() and _NS() additional _?NS[23] are defined
+ * to express state changes that affect more than one aspect of the state.
+ *
+ * E.g. NS2(conn, C_CONNECTED, peer, R_SECONDARY)
+ * Means that the network connection was established and that the peer
+ * is in secondary role.
+ */
+#define role_MASK R_MASK
+#define peer_MASK R_MASK
+#define disk_MASK D_MASK
+#define pdsk_MASK D_MASK
+#define conn_MASK C_MASK
+#define susp_MASK 1
+#define user_isp_MASK 1
+#define aftr_isp_MASK 1
+
+#define NS(T, S) \
+       ({ union drbd_state mask; mask.i = 0; mask.T = T##_MASK; mask; }), \
+       ({ union drbd_state val; val.i = 0; val.T = (S); val; })
+#define NS2(T1, S1, T2, S2) \
+       ({ union drbd_state mask; mask.i = 0; mask.T1 = T1##_MASK; \
+         mask.T2 = T2##_MASK; mask; }), \
+       ({ union drbd_state val; val.i = 0; val.T1 = (S1); \
+         val.T2 = (S2); val; })
+#define NS3(T1, S1, T2, S2, T3, S3) \
+       ({ union drbd_state mask; mask.i = 0; mask.T1 = T1##_MASK; \
+         mask.T2 = T2##_MASK; mask.T3 = T3##_MASK; mask; }), \
+       ({ union drbd_state val;  val.i = 0; val.T1 = (S1); \
+         val.T2 = (S2); val.T3 = (S3); val; })
+
+#define _NS(D, T, S) \
+       D, ({ union drbd_state __ns; __ns.i = D->state.i; __ns.T = (S); __ns; })
+#define _NS2(D, T1, S1, T2, S2) \
+       D, ({ union drbd_state __ns; __ns.i = D->state.i; __ns.T1 = (S1); \
+       __ns.T2 = (S2); __ns; })
+#define _NS3(D, T1, S1, T2, S2, T3, S3) \
+       D, ({ union drbd_state __ns; __ns.i = D->state.i; __ns.T1 = (S1); \
+       __ns.T2 = (S2); __ns.T3 = (S3); __ns; })
+
+/*
+ * inline helper functions
+ *************************/
+
+static inline void drbd_state_lock(struct drbd_conf *mdev)
+{
+       wait_event(mdev->misc_wait,
+                  !test_and_set_bit(CLUSTER_ST_CHANGE, &mdev->flags));
+}
+
+static inline void drbd_state_unlock(struct drbd_conf *mdev)
+{
+       clear_bit(CLUSTER_ST_CHANGE, &mdev->flags);
+       wake_up(&mdev->misc_wait);
+}
+
+static inline int _drbd_set_state(struct drbd_conf *mdev,
+                                  union drbd_state ns, enum chg_state_flags flags,
+                                  struct completion *done)
+{
+       int rv;
+
+       read_lock(&global_state_lock);
+       rv = __drbd_set_state(mdev, ns, flags, done);
+       read_unlock(&global_state_lock);
+
+       return rv;
+}
+
+/**
+ * drbd_request_state() - Reqest a state change
+ * @mdev:      DRBD device.
+ * @mask:      mask of state bits to change.
+ * @val:       value of new state bits.
+ *
+ * This is the most graceful way of requesting a state change. It is verbose
+ * quite verbose in case the state change is not possible, and all those
+ * state changes are globally serialized.
+ */
+static inline int drbd_request_state(struct drbd_conf *mdev,
+                                    union drbd_state mask,
+                                    union drbd_state val)
+{
+       return _drbd_request_state(mdev, mask, val, CS_VERBOSE + CS_ORDERED);
+}
+
+#define __drbd_chk_io_error(m,f) __drbd_chk_io_error_(m,f, __func__)
+static inline void __drbd_chk_io_error_(struct drbd_conf *mdev, int forcedetach, const char *where)
+{
+       switch (mdev->ldev->dc.on_io_error) {
+       case EP_PASS_ON:
+               if (!forcedetach) {
+                       if (printk_ratelimit())
+                               dev_err(DEV, "Local IO failed in %s."
+                                            "Passing error on...\n", where);
+                       break;
+               }
+               /* NOTE fall through to detach case if forcedetach set */
+       case EP_DETACH:
+       case EP_CALL_HELPER:
+               if (mdev->state.disk > D_FAILED) {
+                       _drbd_set_state(_NS(mdev, disk, D_FAILED), CS_HARD, NULL);
+                       dev_err(DEV, "Local IO failed in %s."
+                                    "Detaching...\n", where);
+               }
+               break;
+       }
+}
+
+/**
+ * drbd_chk_io_error: Handle the on_io_error setting, should be called from all io completion handlers
+ * @mdev:       DRBD device.
+ * @error:      Error code passed to the IO completion callback
+ * @forcedetach: Force detach. I.e. the error happened while accessing the meta data
+ *
+ * See also drbd_main.c:after_state_ch() if (os.disk > D_FAILED && ns.disk == D_FAILED)
+ */
+#define drbd_chk_io_error(m,e,f) drbd_chk_io_error_(m,e,f, __func__)
+static inline void drbd_chk_io_error_(struct drbd_conf *mdev,
+       int error, int forcedetach, const char *where)
+{
+       if (error) {
+               unsigned long flags;
+               spin_lock_irqsave(&mdev->req_lock, flags);
+               __drbd_chk_io_error_(mdev, forcedetach, where);
+               spin_unlock_irqrestore(&mdev->req_lock, flags);
+       }
+}
+
+
+/**
+ * drbd_md_first_sector() - Returns the first sector number of the meta data area
+ * @bdev:      Meta data block device.
+ *
+ * BTW, for internal meta data, this happens to be the maximum capacity
+ * we could agree upon with our peer node.
+ */
+static inline sector_t drbd_md_first_sector(struct drbd_backing_dev *bdev)
+{
+       switch (bdev->dc.meta_dev_idx) {
+       case DRBD_MD_INDEX_INTERNAL:
+       case DRBD_MD_INDEX_FLEX_INT:
+               return bdev->md.md_offset + bdev->md.bm_offset;
+       case DRBD_MD_INDEX_FLEX_EXT:
+       default:
+               return bdev->md.md_offset;
+       }
+}
+
+/**
+ * drbd_md_last_sector() - Return the last sector number of the meta data area
+ * @bdev:      Meta data block device.
+ */
+static inline sector_t drbd_md_last_sector(struct drbd_backing_dev *bdev)
+{
+       switch (bdev->dc.meta_dev_idx) {
+       case DRBD_MD_INDEX_INTERNAL:
+       case DRBD_MD_INDEX_FLEX_INT:
+               return bdev->md.md_offset + MD_AL_OFFSET - 1;
+       case DRBD_MD_INDEX_FLEX_EXT:
+       default:
+               return bdev->md.md_offset + bdev->md.md_size_sect;
+       }
+}
+
+/* Returns the number of 512 byte sectors of the device */
+static inline sector_t drbd_get_capacity(struct block_device *bdev)
+{
+       /* return bdev ? get_capacity(bdev->bd_disk) : 0; */
+       return bdev ? bdev->bd_inode->i_size >> 9 : 0;
+}
+
+/**
+ * drbd_get_max_capacity() - Returns the capacity we announce to out peer
+ * @bdev:      Meta data block device.
+ *
+ * returns the capacity we announce to out peer.  we clip ourselves at the
+ * various MAX_SECTORS, because if we don't, current implementation will
+ * oops sooner or later
+ */
+static inline sector_t drbd_get_max_capacity(struct drbd_backing_dev *bdev)
+{
+       sector_t s;
+       switch (bdev->dc.meta_dev_idx) {
+       case DRBD_MD_INDEX_INTERNAL:
+       case DRBD_MD_INDEX_FLEX_INT:
+               s = drbd_get_capacity(bdev->backing_bdev)
+                       ? min_t(sector_t, DRBD_MAX_SECTORS_FLEX,
+                                       drbd_md_first_sector(bdev))
+                       : 0;
+               break;
+       case DRBD_MD_INDEX_FLEX_EXT:
+               s = min_t(sector_t, DRBD_MAX_SECTORS_FLEX,
+                               drbd_get_capacity(bdev->backing_bdev));
+               /* clip at maximum size the meta device can support */
+               s = min_t(sector_t, s,
+                       BM_EXT_TO_SECT(bdev->md.md_size_sect
+                                    - bdev->md.bm_offset));
+               break;
+       default:
+               s = min_t(sector_t, DRBD_MAX_SECTORS,
+                               drbd_get_capacity(bdev->backing_bdev));
+       }
+       return s;
+}
+
+/**
+ * drbd_md_ss__() - Return the sector number of our meta data super block
+ * @mdev:      DRBD device.
+ * @bdev:      Meta data block device.
+ */
+static inline sector_t drbd_md_ss__(struct drbd_conf *mdev,
+                                   struct drbd_backing_dev *bdev)
+{
+       switch (bdev->dc.meta_dev_idx) {
+       default: /* external, some index */
+               return MD_RESERVED_SECT * bdev->dc.meta_dev_idx;
+       case DRBD_MD_INDEX_INTERNAL:
+               /* with drbd08, internal meta data is always "flexible" */
+       case DRBD_MD_INDEX_FLEX_INT:
+               /* sizeof(struct md_on_disk_07) == 4k
+                * position: last 4k aligned block of 4k size */
+               if (!bdev->backing_bdev) {
+                       if (__ratelimit(&drbd_ratelimit_state)) {
+                               dev_err(DEV, "bdev->backing_bdev==NULL\n");
+                               dump_stack();
+                       }
+                       return 0;
+               }
+               return (drbd_get_capacity(bdev->backing_bdev) & ~7ULL)
+                       - MD_AL_OFFSET;
+       case DRBD_MD_INDEX_FLEX_EXT:
+               return 0;
+       }
+}
+
+static inline void
+_drbd_queue_work(struct drbd_work_queue *q, struct drbd_work *w)
+{
+       list_add_tail(&w->list, &q->q);
+       up(&q->s);
+}
+
+static inline void
+drbd_queue_work_front(struct drbd_work_queue *q, struct drbd_work *w)
+{
+       unsigned long flags;
+       spin_lock_irqsave(&q->q_lock, flags);
+       list_add(&w->list, &q->q);
+       up(&q->s); /* within the spinlock,
+                     see comment near end of drbd_worker() */
+       spin_unlock_irqrestore(&q->q_lock, flags);
+}
+
+static inline void
+drbd_queue_work(struct drbd_work_queue *q, struct drbd_work *w)
+{
+       unsigned long flags;
+       spin_lock_irqsave(&q->q_lock, flags);
+       list_add_tail(&w->list, &q->q);
+       up(&q->s); /* within the spinlock,
+                     see comment near end of drbd_worker() */
+       spin_unlock_irqrestore(&q->q_lock, flags);
+}
+
+static inline void wake_asender(struct drbd_conf *mdev)
+{
+       if (test_bit(SIGNAL_ASENDER, &mdev->flags))
+               force_sig(DRBD_SIG, mdev->asender.task);
+}
+
+static inline void request_ping(struct drbd_conf *mdev)
+{
+       set_bit(SEND_PING, &mdev->flags);
+       wake_asender(mdev);
+}
+
+static inline int drbd_send_short_cmd(struct drbd_conf *mdev,
+       enum drbd_packets cmd)
+{
+       struct p_header h;
+       return drbd_send_cmd(mdev, USE_DATA_SOCKET, cmd, &h, sizeof(h));
+}
+
+static inline int drbd_send_ping(struct drbd_conf *mdev)
+{
+       struct p_header h;
+       return drbd_send_cmd(mdev, USE_META_SOCKET, P_PING, &h, sizeof(h));
+}
+
+static inline int drbd_send_ping_ack(struct drbd_conf *mdev)
+{
+       struct p_header h;
+       return drbd_send_cmd(mdev, USE_META_SOCKET, P_PING_ACK, &h, sizeof(h));
+}
+
+static inline void drbd_thread_stop(struct drbd_thread *thi)
+{
+       _drbd_thread_stop(thi, FALSE, TRUE);
+}
+
+static inline void drbd_thread_stop_nowait(struct drbd_thread *thi)
+{
+       _drbd_thread_stop(thi, FALSE, FALSE);
+}
+
+static inline void drbd_thread_restart_nowait(struct drbd_thread *thi)
+{
+       _drbd_thread_stop(thi, TRUE, FALSE);
+}
+
+/* counts how many answer packets packets we expect from our peer,
+ * for either explicit application requests,
+ * or implicit barrier packets as necessary.
+ * increased:
+ *  w_send_barrier
+ *  _req_mod(req, queue_for_net_write or queue_for_net_read);
+ *    it is much easier and equally valid to count what we queue for the
+ *    worker, even before it actually was queued or send.
+ *    (drbd_make_request_common; recovery path on read io-error)
+ * decreased:
+ *  got_BarrierAck (respective tl_clear, tl_clear_barrier)
+ *  _req_mod(req, data_received)
+ *     [from receive_DataReply]
+ *  _req_mod(req, write_acked_by_peer or recv_acked_by_peer or neg_acked)
+ *     [from got_BlockAck (P_WRITE_ACK, P_RECV_ACK)]
+ *     for some reason it is NOT decreased in got_NegAck,
+ *     but in the resulting cleanup code from report_params.
+ *     we should try to remember the reason for that...
+ *  _req_mod(req, send_failed or send_canceled)
+ *  _req_mod(req, connection_lost_while_pending)
+ *     [from tl_clear_barrier]
+ */
+static inline void inc_ap_pending(struct drbd_conf *mdev)
+{
+       atomic_inc(&mdev->ap_pending_cnt);
+}
+
+#define ERR_IF_CNT_IS_NEGATIVE(which)                          \
+       if (atomic_read(&mdev->which) < 0)                      \
+               dev_err(DEV, "in %s:%d: " #which " = %d < 0 !\n",       \
+                   __func__ , __LINE__ ,                       \
+                   atomic_read(&mdev->which))
+
+#define dec_ap_pending(mdev)   do {                            \
+       typecheck(struct drbd_conf *, mdev);                    \
+       if (atomic_dec_and_test(&mdev->ap_pending_cnt))         \
+               wake_up(&mdev->misc_wait);                      \
+       ERR_IF_CNT_IS_NEGATIVE(ap_pending_cnt); } while (0)
+
+/* counts how many resync-related answers we still expect from the peer
+ *                  increase                   decrease
+ * C_SYNC_TARGET sends P_RS_DATA_REQUEST (and expects P_RS_DATA_REPLY)
+ * C_SYNC_SOURCE sends P_RS_DATA_REPLY   (and expects P_WRITE_ACK whith ID_SYNCER)
+ *                                        (or P_NEG_ACK with ID_SYNCER)
+ */
+static inline void inc_rs_pending(struct drbd_conf *mdev)
+{
+       atomic_inc(&mdev->rs_pending_cnt);
+}
+
+#define dec_rs_pending(mdev)   do {                            \
+       typecheck(struct drbd_conf *, mdev);                    \
+       atomic_dec(&mdev->rs_pending_cnt);                      \
+       ERR_IF_CNT_IS_NEGATIVE(rs_pending_cnt); } while (0)
+
+/* counts how many answers we still need to send to the peer.
+ * increased on
+ *  receive_Data       unless protocol A;
+ *                     we need to send a P_RECV_ACK (proto B)
+ *                     or P_WRITE_ACK (proto C)
+ *  receive_RSDataReply (recv_resync_read) we need to send a P_WRITE_ACK
+ *  receive_DataRequest (receive_RSDataRequest) we need to send back P_DATA
+ *  receive_Barrier_*  we need to send a P_BARRIER_ACK
+ */
+static inline void inc_unacked(struct drbd_conf *mdev)
+{
+       atomic_inc(&mdev->unacked_cnt);
+}
+
+#define dec_unacked(mdev)      do {                            \
+       typecheck(struct drbd_conf *, mdev);                    \
+       atomic_dec(&mdev->unacked_cnt);                         \
+       ERR_IF_CNT_IS_NEGATIVE(unacked_cnt); } while (0)
+
+#define sub_unacked(mdev, n)   do {                            \
+       typecheck(struct drbd_conf *, mdev);                    \
+       atomic_sub(n, &mdev->unacked_cnt);                      \
+       ERR_IF_CNT_IS_NEGATIVE(unacked_cnt); } while (0)
+
+
+static inline void put_net_conf(struct drbd_conf *mdev)
+{
+       if (atomic_dec_and_test(&mdev->net_cnt))
+               wake_up(&mdev->misc_wait);
+}
+
+/**
+ * get_net_conf() - Increase ref count on mdev->net_conf; Returns 0 if nothing there
+ * @mdev:      DRBD device.
+ *
+ * You have to call put_net_conf() when finished working with mdev->net_conf.
+ */
+static inline int get_net_conf(struct drbd_conf *mdev)
+{
+       int have_net_conf;
+
+       atomic_inc(&mdev->net_cnt);
+       have_net_conf = mdev->state.conn >= C_UNCONNECTED;
+       if (!have_net_conf)
+               put_net_conf(mdev);
+       return have_net_conf;
+}
+
+/**
+ * get_ldev() - Increase the ref count on mdev->ldev. Returns 0 if there is no ldev
+ * @M:         DRBD device.
+ *
+ * You have to call put_ldev() when finished working with mdev->ldev.
+ */
+#define get_ldev(M) __cond_lock(local, _get_ldev_if_state(M,D_INCONSISTENT))
+#define get_ldev_if_state(M,MINS) __cond_lock(local, _get_ldev_if_state(M,MINS))
+
+static inline void put_ldev(struct drbd_conf *mdev)
+{
+       __release(local);
+       if (atomic_dec_and_test(&mdev->local_cnt))
+               wake_up(&mdev->misc_wait);
+       D_ASSERT(atomic_read(&mdev->local_cnt) >= 0);
+}
+
+#ifndef __CHECKER__
+static inline int _get_ldev_if_state(struct drbd_conf *mdev, enum drbd_disk_state mins)
+{
+       int io_allowed;
+
+       atomic_inc(&mdev->local_cnt);
+       io_allowed = (mdev->state.disk >= mins);
+       if (!io_allowed)
+               put_ldev(mdev);
+       return io_allowed;
+}
+#else
+extern int _get_ldev_if_state(struct drbd_conf *mdev, enum drbd_disk_state mins);
+#endif
+
+/* you must have an "get_ldev" reference */
+static inline void drbd_get_syncer_progress(struct drbd_conf *mdev,
+               unsigned long *bits_left, unsigned int *per_mil_done)
+{
+       /*
+        * this is to break it at compile time when we change that
+        * (we may feel 4TB maximum storage per drbd is not enough)
+        */
+       typecheck(unsigned long, mdev->rs_total);
+
+       /* note: both rs_total and rs_left are in bits, i.e. in
+        * units of BM_BLOCK_SIZE.
+        * for the percentage, we don't care. */
+
+       *bits_left = drbd_bm_total_weight(mdev) - mdev->rs_failed;
+       /* >> 10 to prevent overflow,
+        * +1 to prevent division by zero */
+       if (*bits_left > mdev->rs_total) {
+               /* doh. maybe a logic bug somewhere.
+                * may also be just a race condition
+                * between this and a disconnect during sync.
+                * for now, just prevent in-kernel buffer overflow.
+                */
+               smp_rmb();
+               dev_warn(DEV, "cs:%s rs_left=%lu > rs_total=%lu (rs_failed %lu)\n",
+                               drbd_conn_str(mdev->state.conn),
+                               *bits_left, mdev->rs_total, mdev->rs_failed);
+               *per_mil_done = 0;
+       } else {
+               /* make sure the calculation happens in long context */
+               unsigned long tmp = 1000UL -
+                               (*bits_left >> 10)*1000UL
+                               / ((mdev->rs_total >> 10) + 1UL);
+               *per_mil_done = tmp;
+       }
+}
+
+
+/* this throttles on-the-fly application requests
+ * according to max_buffers settings;
+ * maybe re-implement using semaphores? */
+static inline int drbd_get_max_buffers(struct drbd_conf *mdev)
+{
+       int mxb = 1000000; /* arbitrary limit on open requests */
+       if (get_net_conf(mdev)) {
+               mxb = mdev->net_conf->max_buffers;
+               put_net_conf(mdev);
+       }
+       return mxb;
+}
+
+static inline int drbd_state_is_stable(union drbd_state s)
+{
+
+       /* DO NOT add a default clause, we want the compiler to warn us
+        * for any newly introduced state we may have forgotten to add here */
+
+       switch ((enum drbd_conns)s.conn) {
+       /* new io only accepted when there is no connection, ... */
+       case C_STANDALONE:
+       case C_WF_CONNECTION:
+       /* ... or there is a well established connection. */
+       case C_CONNECTED:
+       case C_SYNC_SOURCE:
+       case C_SYNC_TARGET:
+       case C_VERIFY_S:
+       case C_VERIFY_T:
+       case C_PAUSED_SYNC_S:
+       case C_PAUSED_SYNC_T:
+               /* maybe stable, look at the disk state */
+               break;
+
+       /* no new io accepted during tansitional states
+        * like handshake or teardown */
+       case C_DISCONNECTING:
+       case C_UNCONNECTED:
+       case C_TIMEOUT:
+       case C_BROKEN_PIPE:
+       case C_NETWORK_FAILURE:
+       case C_PROTOCOL_ERROR:
+       case C_TEAR_DOWN:
+       case C_WF_REPORT_PARAMS:
+       case C_STARTING_SYNC_S:
+       case C_STARTING_SYNC_T:
+       case C_WF_BITMAP_S:
+       case C_WF_BITMAP_T:
+       case C_WF_SYNC_UUID:
+       case C_MASK:
+               /* not "stable" */
+               return 0;
+       }
+
+       switch ((enum drbd_disk_state)s.disk) {
+       case D_DISKLESS:
+       case D_INCONSISTENT:
+       case D_OUTDATED:
+       case D_CONSISTENT:
+       case D_UP_TO_DATE:
+               /* disk state is stable as well. */
+               break;
+
+       /* no new io accepted during tansitional states */
+       case D_ATTACHING:
+       case D_FAILED:
+       case D_NEGOTIATING:
+       case D_UNKNOWN:
+       case D_MASK:
+               /* not "stable" */
+               return 0;
+       }
+
+       return 1;
+}
+
+static inline int __inc_ap_bio_cond(struct drbd_conf *mdev)
+{
+       int mxb = drbd_get_max_buffers(mdev);
+
+       if (mdev->state.susp)
+               return 0;
+       if (test_bit(SUSPEND_IO, &mdev->flags))
+               return 0;
+
+       /* to avoid potential deadlock or bitmap corruption,
+        * in various places, we only allow new application io
+        * to start during "stable" states. */
+
+       /* no new io accepted when attaching or detaching the disk */
+       if (!drbd_state_is_stable(mdev->state))
+               return 0;
+
+       /* since some older kernels don't have atomic_add_unless,
+        * and we are within the spinlock anyways, we have this workaround.  */
+       if (atomic_read(&mdev->ap_bio_cnt) > mxb)
+               return 0;
+       if (test_bit(BITMAP_IO, &mdev->flags))
+               return 0;
+       return 1;
+}
+
+/* I'd like to use wait_event_lock_irq,
+ * but I'm not sure when it got introduced,
+ * and not sure when it has 3 or 4 arguments */
+static inline void inc_ap_bio(struct drbd_conf *mdev, int one_or_two)
+{
+       /* compare with after_state_ch,
+        * os.conn != C_WF_BITMAP_S && ns.conn == C_WF_BITMAP_S */
+       DEFINE_WAIT(wait);
+
+       /* we wait here
+        *    as long as the device is suspended
+        *    until the bitmap is no longer on the fly during connection
+        *    handshake as long as we would exeed the max_buffer limit.
+        *
+        * to avoid races with the reconnect code,
+        * we need to atomic_inc within the spinlock. */
+
+       spin_lock_irq(&mdev->req_lock);
+       while (!__inc_ap_bio_cond(mdev)) {
+               prepare_to_wait(&mdev->misc_wait, &wait, TASK_UNINTERRUPTIBLE);
+               spin_unlock_irq(&mdev->req_lock);
+               schedule();
+               finish_wait(&mdev->misc_wait, &wait);
+               spin_lock_irq(&mdev->req_lock);
+       }
+       atomic_add(one_or_two, &mdev->ap_bio_cnt);
+       spin_unlock_irq(&mdev->req_lock);
+}
+
+static inline void dec_ap_bio(struct drbd_conf *mdev)
+{
+       int mxb = drbd_get_max_buffers(mdev);
+       int ap_bio = atomic_dec_return(&mdev->ap_bio_cnt);
+
+       D_ASSERT(ap_bio >= 0);
+       /* this currently does wake_up for every dec_ap_bio!
+        * maybe rather introduce some type of hysteresis?
+        * e.g. (ap_bio == mxb/2 || ap_bio == 0) ? */
+       if (ap_bio < mxb)
+               wake_up(&mdev->misc_wait);
+       if (ap_bio == 0 && test_bit(BITMAP_IO, &mdev->flags)) {
+               if (!test_and_set_bit(BITMAP_IO_QUEUED, &mdev->flags))
+                       drbd_queue_work(&mdev->data.work, &mdev->bm_io_work.w);
+       }
+}
+
+static inline void drbd_set_ed_uuid(struct drbd_conf *mdev, u64 val)
+{
+       mdev->ed_uuid = val;
+}
+
+static inline int seq_cmp(u32 a, u32 b)
+{
+       /* we assume wrap around at 32bit.
+        * for wrap around at 24bit (old atomic_t),
+        * we'd have to
+        *  a <<= 8; b <<= 8;
+        */
+       return (s32)(a) - (s32)(b);
+}
+#define seq_lt(a, b) (seq_cmp((a), (b)) < 0)
+#define seq_gt(a, b) (seq_cmp((a), (b)) > 0)
+#define seq_ge(a, b) (seq_cmp((a), (b)) >= 0)
+#define seq_le(a, b) (seq_cmp((a), (b)) <= 0)
+/* CAUTION: please no side effects in arguments! */
+#define seq_max(a, b) ((u32)(seq_gt((a), (b)) ? (a) : (b)))
+
+static inline void update_peer_seq(struct drbd_conf *mdev, unsigned int new_seq)
+{
+       unsigned int m;
+       spin_lock(&mdev->peer_seq_lock);
+       m = seq_max(mdev->peer_seq, new_seq);
+       mdev->peer_seq = m;
+       spin_unlock(&mdev->peer_seq_lock);
+       if (m == new_seq)
+               wake_up(&mdev->seq_wait);
+}
+
+static inline void drbd_update_congested(struct drbd_conf *mdev)
+{
+       struct sock *sk = mdev->data.socket->sk;
+       if (sk->sk_wmem_queued > sk->sk_sndbuf * 4 / 5)
+               set_bit(NET_CONGESTED, &mdev->flags);
+}
+
+static inline int drbd_queue_order_type(struct drbd_conf *mdev)
+{
+       /* sorry, we currently have no working implementation
+        * of distributed TCQ stuff */
+#ifndef QUEUE_ORDERED_NONE
+#define QUEUE_ORDERED_NONE 0
+#endif
+       return QUEUE_ORDERED_NONE;
+}
+
+static inline void drbd_blk_run_queue(struct request_queue *q)
+{
+       if (q && q->unplug_fn)
+               q->unplug_fn(q);
+}
+
+static inline void drbd_kick_lo(struct drbd_conf *mdev)
+{
+       if (get_ldev(mdev)) {
+               drbd_blk_run_queue(bdev_get_queue(mdev->ldev->backing_bdev));
+               put_ldev(mdev);
+       }
+}
+
+static inline void drbd_md_flush(struct drbd_conf *mdev)
+{
+       int r;
+
+       if (test_bit(MD_NO_BARRIER, &mdev->flags))
+               return;
+
+       r = blkdev_issue_flush(mdev->ldev->md_bdev, NULL);
+       if (r) {
+               set_bit(MD_NO_BARRIER, &mdev->flags);
+               dev_err(DEV, "meta data flush failed with status %d, disabling md-flushes\n", r);
+       }
+}
+
+#endif
diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c
new file mode 100644 (file)
index 0000000..157d1e4
--- /dev/null
@@ -0,0 +1,3699 @@
+/*
+   drbd.c
+
+   This file is part of DRBD by Philipp Reisner and Lars Ellenberg.
+
+   Copyright (C) 2001-2008, LINBIT Information Technologies GmbH.
+   Copyright (C) 1999-2008, Philipp Reisner <philipp.reisner@linbit.com>.
+   Copyright (C) 2002-2008, Lars Ellenberg <lars.ellenberg@linbit.com>.
+
+   Thanks to Carter Burden, Bart Grantham and Gennadiy Nerubayev
+   from Logicworks, Inc. for making SDP replication support possible.
+
+   drbd is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   drbd 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 drbd; see the file COPYING.  If not, write to
+   the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ */
+
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/drbd.h>
+#include <asm/uaccess.h>
+#include <asm/types.h>
+#include <net/sock.h>
+#include <linux/ctype.h>
+#include <linux/smp_lock.h>
+#include <linux/fs.h>
+#include <linux/file.h>
+#include <linux/proc_fs.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/memcontrol.h>
+#include <linux/mm_inline.h>
+#include <linux/slab.h>
+#include <linux/random.h>
+#include <linux/reboot.h>
+#include <linux/notifier.h>
+#include <linux/kthread.h>
+
+#define __KERNEL_SYSCALLS__
+#include <linux/unistd.h>
+#include <linux/vmalloc.h>
+
+#include <linux/drbd_limits.h>
+#include "drbd_int.h"
+#include "drbd_req.h" /* only for _req_mod in tl_release and tl_clear */
+
+#include "drbd_vli.h"
+
+struct after_state_chg_work {
+       struct drbd_work w;
+       union drbd_state os;
+       union drbd_state ns;
+       enum chg_state_flags flags;
+       struct completion *done;
+};
+
+int drbdd_init(struct drbd_thread *);
+int drbd_worker(struct drbd_thread *);
+int drbd_asender(struct drbd_thread *);
+
+int drbd_init(void);
+static int drbd_open(struct block_device *bdev, fmode_t mode);
+static int drbd_release(struct gendisk *gd, fmode_t mode);
+static int w_after_state_ch(struct drbd_conf *mdev, struct drbd_work *w, int unused);
+static void after_state_ch(struct drbd_conf *mdev, union drbd_state os,
+                          union drbd_state ns, enum chg_state_flags flags);
+static int w_md_sync(struct drbd_conf *mdev, struct drbd_work *w, int unused);
+static void md_sync_timer_fn(unsigned long data);
+static int w_bitmap_io(struct drbd_conf *mdev, struct drbd_work *w, int unused);
+
+MODULE_AUTHOR("Philipp Reisner <phil@linbit.com>, "
+             "Lars Ellenberg <lars@linbit.com>");
+MODULE_DESCRIPTION("drbd - Distributed Replicated Block Device v" REL_VERSION);
+MODULE_VERSION(REL_VERSION);
+MODULE_LICENSE("GPL");
+MODULE_PARM_DESC(minor_count, "Maximum number of drbd devices (1-255)");
+MODULE_ALIAS_BLOCKDEV_MAJOR(DRBD_MAJOR);
+
+#include <linux/moduleparam.h>
+/* allow_open_on_secondary */
+MODULE_PARM_DESC(allow_oos, "DONT USE!");
+/* thanks to these macros, if compiled into the kernel (not-module),
+ * this becomes the boot parameter drbd.minor_count */
+module_param(minor_count, uint, 0444);
+module_param(disable_sendpage, bool, 0644);
+module_param(allow_oos, bool, 0);
+module_param(cn_idx, uint, 0444);
+module_param(proc_details, int, 0644);
+
+#ifdef CONFIG_DRBD_FAULT_INJECTION
+int enable_faults;
+int fault_rate;
+static int fault_count;
+int fault_devs;
+/* bitmap of enabled faults */
+module_param(enable_faults, int, 0664);
+/* fault rate % value - applies to all enabled faults */
+module_param(fault_rate, int, 0664);
+/* count of faults inserted */
+module_param(fault_count, int, 0664);
+/* bitmap of devices to insert faults on */
+module_param(fault_devs, int, 0644);
+#endif
+
+/* module parameter, defined */
+unsigned int minor_count = 32;
+int disable_sendpage;
+int allow_oos;
+unsigned int cn_idx = CN_IDX_DRBD;
+int proc_details;       /* Detail level in proc drbd*/
+
+/* Module parameter for setting the user mode helper program
+ * to run. Default is /sbin/drbdadm */
+char usermode_helper[80] = "/sbin/drbdadm";
+
+module_param_string(usermode_helper, usermode_helper, sizeof(usermode_helper), 0644);
+
+/* in 2.6.x, our device mapping and config info contains our virtual gendisks
+ * as member "struct gendisk *vdisk;"
+ */
+struct drbd_conf **minor_table;
+
+struct kmem_cache *drbd_request_cache;
+struct kmem_cache *drbd_ee_cache;      /* epoch entries */
+struct kmem_cache *drbd_bm_ext_cache;  /* bitmap extents */
+struct kmem_cache *drbd_al_ext_cache;  /* activity log extents */
+mempool_t *drbd_request_mempool;
+mempool_t *drbd_ee_mempool;
+
+/* I do not use a standard mempool, because:
+   1) I want to hand out the pre-allocated objects first.
+   2) I want to be able to interrupt sleeping allocation with a signal.
+   Note: This is a single linked list, the next pointer is the private
+        member of struct page.
+ */
+struct page *drbd_pp_pool;
+spinlock_t   drbd_pp_lock;
+int          drbd_pp_vacant;
+wait_queue_head_t drbd_pp_wait;
+
+DEFINE_RATELIMIT_STATE(drbd_ratelimit_state, 5 * HZ, 5);
+
+static struct block_device_operations drbd_ops = {
+       .owner =   THIS_MODULE,
+       .open =    drbd_open,
+       .release = drbd_release,
+};
+
+#define ARRY_SIZE(A) (sizeof(A)/sizeof(A[0]))
+
+#ifdef __CHECKER__
+/* When checking with sparse, and this is an inline function, sparse will
+   give tons of false positives. When this is a real functions sparse works.
+ */
+int _get_ldev_if_state(struct drbd_conf *mdev, enum drbd_disk_state mins)
+{
+       int io_allowed;
+
+       atomic_inc(&mdev->local_cnt);
+       io_allowed = (mdev->state.disk >= mins);
+       if (!io_allowed) {
+               if (atomic_dec_and_test(&mdev->local_cnt))
+                       wake_up(&mdev->misc_wait);
+       }
+       return io_allowed;
+}
+
+#endif
+
+/**
+ * DOC: The transfer log
+ *
+ * The transfer log is a single linked list of &struct drbd_tl_epoch objects.
+ * mdev->newest_tle points to the head, mdev->oldest_tle points to the tail
+ * of the list. There is always at least one &struct drbd_tl_epoch object.
+ *
+ * Each &struct drbd_tl_epoch has a circular double linked list of requests
+ * attached.
+ */
+static int tl_init(struct drbd_conf *mdev)
+{
+       struct drbd_tl_epoch *b;
+
+       /* during device minor initialization, we may well use GFP_KERNEL */
+       b = kmalloc(sizeof(struct drbd_tl_epoch), GFP_KERNEL);
+       if (!b)
+               return 0;
+       INIT_LIST_HEAD(&b->requests);
+       INIT_LIST_HEAD(&b->w.list);
+       b->next = NULL;
+       b->br_number = 4711;
+       b->n_req = 0;
+       b->w.cb = NULL; /* if this is != NULL, we need to dec_ap_pending in tl_clear */
+
+       mdev->oldest_tle = b;
+       mdev->newest_tle = b;
+       INIT_LIST_HEAD(&mdev->out_of_sequence_requests);
+
+       mdev->tl_hash = NULL;
+       mdev->tl_hash_s = 0;
+
+       return 1;
+}
+
+static void tl_cleanup(struct drbd_conf *mdev)
+{
+       D_ASSERT(mdev->oldest_tle == mdev->newest_tle);
+       D_ASSERT(list_empty(&mdev->out_of_sequence_requests));
+       kfree(mdev->oldest_tle);
+       mdev->oldest_tle = NULL;
+       kfree(mdev->unused_spare_tle);
+       mdev->unused_spare_tle = NULL;
+       kfree(mdev->tl_hash);
+       mdev->tl_hash = NULL;
+       mdev->tl_hash_s = 0;
+}
+
+/**
+ * _tl_add_barrier() - Adds a barrier to the transfer log
+ * @mdev:      DRBD device.
+ * @new:       Barrier to be added before the current head of the TL.
+ *
+ * The caller must hold the req_lock.
+ */
+void _tl_add_barrier(struct drbd_conf *mdev, struct drbd_tl_epoch *new)
+{
+       struct drbd_tl_epoch *newest_before;
+
+       INIT_LIST_HEAD(&new->requests);
+       INIT_LIST_HEAD(&new->w.list);
+       new->w.cb = NULL; /* if this is != NULL, we need to dec_ap_pending in tl_clear */
+       new->next = NULL;
+       new->n_req = 0;
+
+       newest_before = mdev->newest_tle;
+       /* never send a barrier number == 0, because that is special-cased
+        * when using TCQ for our write ordering code */
+       new->br_number = (newest_before->br_number+1) ?: 1;
+       if (mdev->newest_tle != new) {
+               mdev->newest_tle->next = new;
+               mdev->newest_tle = new;
+       }
+}
+
+/**
+ * tl_release() - Free or recycle the oldest &struct drbd_tl_epoch object of the TL
+ * @mdev:      DRBD device.
+ * @barrier_nr:        Expected identifier of the DRBD write barrier packet.
+ * @set_size:  Expected number of requests before that barrier.
+ *
+ * In case the passed barrier_nr or set_size does not match the oldest
+ * &struct drbd_tl_epoch objects this function will cause a termination
+ * of the connection.
+ */
+void tl_release(struct drbd_conf *mdev, unsigned int barrier_nr,
+                      unsigned int set_size)
+{
+       struct drbd_tl_epoch *b, *nob; /* next old barrier */
+       struct list_head *le, *tle;
+       struct drbd_request *r;
+
+       spin_lock_irq(&mdev->req_lock);
+
+       b = mdev->oldest_tle;
+
+       /* first some paranoia code */
+       if (b == NULL) {
+               dev_err(DEV, "BAD! BarrierAck #%u received, but no epoch in tl!?\n",
+                       barrier_nr);
+               goto bail;
+       }
+       if (b->br_number != barrier_nr) {
+               dev_err(DEV, "BAD! BarrierAck #%u received, expected #%u!\n",
+                       barrier_nr, b->br_number);
+               goto bail;
+       }
+       if (b->n_req != set_size) {
+               dev_err(DEV, "BAD! BarrierAck #%u received with n_req=%u, expected n_req=%u!\n",
+                       barrier_nr, set_size, b->n_req);
+               goto bail;
+       }
+
+       /* Clean up list of requests processed during current epoch */
+       list_for_each_safe(le, tle, &b->requests) {
+               r = list_entry(le, struct drbd_request, tl_requests);
+               _req_mod(r, barrier_acked);
+       }
+       /* There could be requests on the list waiting for completion
+          of the write to the local disk. To avoid corruptions of
+          slab's data structures we have to remove the lists head.
+
+          Also there could have been a barrier ack out of sequence, overtaking
+          the write acks - which would be a bug and violating write ordering.
+          To not deadlock in case we lose connection while such requests are
+          still pending, we need some way to find them for the
+          _req_mode(connection_lost_while_pending).
+
+          These have been list_move'd to the out_of_sequence_requests list in
+          _req_mod(, barrier_acked) above.
+          */
+       list_del_init(&b->requests);
+
+       nob = b->next;
+       if (test_and_clear_bit(CREATE_BARRIER, &mdev->flags)) {
+               _tl_add_barrier(mdev, b);
+               if (nob)
+                       mdev->oldest_tle = nob;
+               /* if nob == NULL b was the only barrier, and becomes the new
+                  barrier. Therefore mdev->oldest_tle points already to b */
+       } else {
+               D_ASSERT(nob != NULL);
+               mdev->oldest_tle = nob;
+               kfree(b);
+       }
+
+       spin_unlock_irq(&mdev->req_lock);
+       dec_ap_pending(mdev);
+
+       return;
+
+bail:
+       spin_unlock_irq(&mdev->req_lock);
+       drbd_force_state(mdev, NS(conn, C_PROTOCOL_ERROR));
+}
+
+
+/**
+ * tl_clear() - Clears all requests and &struct drbd_tl_epoch objects out of the TL
+ * @mdev:      DRBD device.
+ *
+ * This is called after the connection to the peer was lost. The storage covered
+ * by the requests on the transfer gets marked as our of sync. Called from the
+ * receiver thread and the worker thread.
+ */
+void tl_clear(struct drbd_conf *mdev)
+{
+       struct drbd_tl_epoch *b, *tmp;
+       struct list_head *le, *tle;
+       struct drbd_request *r;
+       int new_initial_bnr = net_random();
+
+       spin_lock_irq(&mdev->req_lock);
+
+       b = mdev->oldest_tle;
+       while (b) {
+               list_for_each_safe(le, tle, &b->requests) {
+                       r = list_entry(le, struct drbd_request, tl_requests);
+                       /* It would be nice to complete outside of spinlock.
+                        * But this is easier for now. */
+                       _req_mod(r, connection_lost_while_pending);
+               }
+               tmp = b->next;
+
+               /* there could still be requests on that ring list,
+                * in case local io is still pending */
+               list_del(&b->requests);
+
+               /* dec_ap_pending corresponding to queue_barrier.
+                * the newest barrier may not have been queued yet,
+                * in which case w.cb is still NULL. */
+               if (b->w.cb != NULL)
+                       dec_ap_pending(mdev);
+
+               if (b == mdev->newest_tle) {
+                       /* recycle, but reinit! */
+                       D_ASSERT(tmp == NULL);
+                       INIT_LIST_HEAD(&b->requests);
+                       INIT_LIST_HEAD(&b->w.list);
+                       b->w.cb = NULL;
+                       b->br_number = new_initial_bnr;
+                       b->n_req = 0;
+
+                       mdev->oldest_tle = b;
+                       break;
+               }
+               kfree(b);
+               b = tmp;
+       }
+
+       /* we expect this list to be empty. */
+       D_ASSERT(list_empty(&mdev->out_of_sequence_requests));
+
+       /* but just in case, clean it up anyways! */
+       list_for_each_safe(le, tle, &mdev->out_of_sequence_requests) {
+               r = list_entry(le, struct drbd_request, tl_requests);
+               /* It would be nice to complete outside of spinlock.
+                * But this is easier for now. */
+               _req_mod(r, connection_lost_while_pending);
+       }
+
+       /* ensure bit indicating barrier is required is clear */
+       clear_bit(CREATE_BARRIER, &mdev->flags);
+
+       spin_unlock_irq(&mdev->req_lock);
+}
+
+/**
+ * cl_wide_st_chg() - TRUE if the state change is a cluster wide one
+ * @mdev:      DRBD device.
+ * @os:                old (current) state.
+ * @ns:                new (wanted) state.
+ */
+static int cl_wide_st_chg(struct drbd_conf *mdev,
+                         union drbd_state os, union drbd_state ns)
+{
+       return (os.conn >= C_CONNECTED && ns.conn >= C_CONNECTED &&
+                ((os.role != R_PRIMARY && ns.role == R_PRIMARY) ||
+                 (os.conn != C_STARTING_SYNC_T && ns.conn == C_STARTING_SYNC_T) ||
+                 (os.conn != C_STARTING_SYNC_S && ns.conn == C_STARTING_SYNC_S) ||
+                 (os.disk != D_DISKLESS && ns.disk == D_DISKLESS))) ||
+               (os.conn >= C_CONNECTED && ns.conn == C_DISCONNECTING) ||
+               (os.conn == C_CONNECTED && ns.conn == C_VERIFY_S);
+}
+
+int drbd_change_state(struct drbd_conf *mdev, enum chg_state_flags f,
+                     union drbd_state mask, union drbd_state val)
+{
+       unsigned long flags;
+       union drbd_state os, ns;
+       int rv;
+
+       spin_lock_irqsave(&mdev->req_lock, flags);
+       os = mdev->state;
+       ns.i = (os.i & ~mask.i) | val.i;
+       rv = _drbd_set_state(mdev, ns, f, NULL);
+       ns = mdev->state;
+       spin_unlock_irqrestore(&mdev->req_lock, flags);
+
+       return rv;
+}
+
+/**
+ * drbd_force_state() - Impose a change which happens outside our control on our state
+ * @mdev:      DRBD device.
+ * @mask:      mask of state bits to change.
+ * @val:       value of new state bits.
+ */
+void drbd_force_state(struct drbd_conf *mdev,
+       union drbd_state mask, union drbd_state val)
+{
+       drbd_change_state(mdev, CS_HARD, mask, val);
+}
+
+static int is_valid_state(struct drbd_conf *mdev, union drbd_state ns);
+static int is_valid_state_transition(struct drbd_conf *,
+                                    union drbd_state, union drbd_state);
+static union drbd_state sanitize_state(struct drbd_conf *mdev, union drbd_state os,
+                                      union drbd_state ns, int *warn_sync_abort);
+int drbd_send_state_req(struct drbd_conf *,
+                       union drbd_state, union drbd_state);
+
+static enum drbd_state_ret_codes _req_st_cond(struct drbd_conf *mdev,
+                                   union drbd_state mask, union drbd_state val)
+{
+       union drbd_state os, ns;
+       unsigned long flags;
+       int rv;
+
+       if (test_and_clear_bit(CL_ST_CHG_SUCCESS, &mdev->flags))
+               return SS_CW_SUCCESS;
+
+       if (test_and_clear_bit(CL_ST_CHG_FAIL, &mdev->flags))
+               return SS_CW_FAILED_BY_PEER;
+
+       rv = 0;
+       spin_lock_irqsave(&mdev->req_lock, flags);
+       os = mdev->state;
+       ns.i = (os.i & ~mask.i) | val.i;
+       ns = sanitize_state(mdev, os, ns, NULL);
+
+       if (!cl_wide_st_chg(mdev, os, ns))
+               rv = SS_CW_NO_NEED;
+       if (!rv) {
+               rv = is_valid_state(mdev, ns);
+               if (rv == SS_SUCCESS) {
+                       rv = is_valid_state_transition(mdev, ns, os);
+                       if (rv == SS_SUCCESS)
+                               rv = 0; /* cont waiting, otherwise fail. */
+               }
+       }
+       spin_unlock_irqrestore(&mdev->req_lock, flags);
+
+       return rv;
+}
+
+/**
+ * drbd_req_state() - Perform an eventually cluster wide state change
+ * @mdev:      DRBD device.
+ * @mask:      mask of state bits to change.
+ * @val:       value of new state bits.
+ * @f:         flags
+ *
+ * Should not be called directly, use drbd_request_state() or
+ * _drbd_request_state().
+ */
+static int drbd_req_state(struct drbd_conf *mdev,
+                         union drbd_state mask, union drbd_state val,
+                         enum chg_state_flags f)
+{
+       struct completion done;
+       unsigned long flags;
+       union drbd_state os, ns;
+       int rv;
+
+       init_completion(&done);
+
+       if (f & CS_SERIALIZE)
+               mutex_lock(&mdev->state_mutex);
+
+       spin_lock_irqsave(&mdev->req_lock, flags);
+       os = mdev->state;
+       ns.i = (os.i & ~mask.i) | val.i;
+       ns = sanitize_state(mdev, os, ns, NULL);
+
+       if (cl_wide_st_chg(mdev, os, ns)) {
+               rv = is_valid_state(mdev, ns);
+               if (rv == SS_SUCCESS)
+                       rv = is_valid_state_transition(mdev, ns, os);
+               spin_unlock_irqrestore(&mdev->req_lock, flags);
+
+               if (rv < SS_SUCCESS) {
+                       if (f & CS_VERBOSE)
+                               print_st_err(mdev, os, ns, rv);
+                       goto abort;
+               }
+
+               drbd_state_lock(mdev);
+               if (!drbd_send_state_req(mdev, mask, val)) {
+                       drbd_state_unlock(mdev);
+                       rv = SS_CW_FAILED_BY_PEER;
+                       if (f & CS_VERBOSE)
+                               print_st_err(mdev, os, ns, rv);
+                       goto abort;
+               }
+
+               wait_event(mdev->state_wait,
+                       (rv = _req_st_cond(mdev, mask, val)));
+
+               if (rv < SS_SUCCESS) {
+                       drbd_state_unlock(mdev);
+                       if (f & CS_VERBOSE)
+                               print_st_err(mdev, os, ns, rv);
+                       goto abort;
+               }
+               spin_lock_irqsave(&mdev->req_lock, flags);
+               os = mdev->state;
+               ns.i = (os.i & ~mask.i) | val.i;
+               rv = _drbd_set_state(mdev, ns, f, &done);
+               drbd_state_unlock(mdev);
+       } else {
+               rv = _drbd_set_state(mdev, ns, f, &done);
+       }
+
+       spin_unlock_irqrestore(&mdev->req_lock, flags);
+
+       if (f & CS_WAIT_COMPLETE && rv == SS_SUCCESS) {
+               D_ASSERT(current != mdev->worker.task);
+               wait_for_completion(&done);
+       }
+
+abort:
+       if (f & CS_SERIALIZE)
+               mutex_unlock(&mdev->state_mutex);
+
+       return rv;
+}
+
+/**
+ * _drbd_request_state() - Request a state change (with flags)
+ * @mdev:      DRBD device.
+ * @mask:      mask of state bits to change.
+ * @val:       value of new state bits.
+ * @f:         flags
+ *
+ * Cousin of drbd_request_state(), useful with the CS_WAIT_COMPLETE
+ * flag, or when logging of failed state change requests is not desired.
+ */
+int _drbd_request_state(struct drbd_conf *mdev,        union drbd_state mask,
+                       union drbd_state val,   enum chg_state_flags f)
+{
+       int rv;
+
+       wait_event(mdev->state_wait,
+                  (rv = drbd_req_state(mdev, mask, val, f)) != SS_IN_TRANSIENT_STATE);
+
+       return rv;
+}
+
+static void print_st(struct drbd_conf *mdev, char *name, union drbd_state ns)
+{
+       dev_err(DEV, " %s = { cs:%s ro:%s/%s ds:%s/%s %c%c%c%c }\n",
+           name,
+           drbd_conn_str(ns.conn),
+           drbd_role_str(ns.role),
+           drbd_role_str(ns.peer),
+           drbd_disk_str(ns.disk),
+           drbd_disk_str(ns.pdsk),
+           ns.susp ? 's' : 'r',
+           ns.aftr_isp ? 'a' : '-',
+           ns.peer_isp ? 'p' : '-',
+           ns.user_isp ? 'u' : '-'
+           );
+}
+
+void print_st_err(struct drbd_conf *mdev,
+       union drbd_state os, union drbd_state ns, int err)
+{
+       if (err == SS_IN_TRANSIENT_STATE)
+               return;
+       dev_err(DEV, "State change failed: %s\n", drbd_set_st_err_str(err));
+       print_st(mdev, " state", os);
+       print_st(mdev, "wanted", ns);
+}
+
+
+#define drbd_peer_str drbd_role_str
+#define drbd_pdsk_str drbd_disk_str
+
+#define drbd_susp_str(A)     ((A) ? "1" : "0")
+#define drbd_aftr_isp_str(A) ((A) ? "1" : "0")
+#define drbd_peer_isp_str(A) ((A) ? "1" : "0")
+#define drbd_user_isp_str(A) ((A) ? "1" : "0")
+
+#define PSC(A) \
+       ({ if (ns.A != os.A) { \
+               pbp += sprintf(pbp, #A "( %s -> %s ) ", \
+                             drbd_##A##_str(os.A), \
+                             drbd_##A##_str(ns.A)); \
+       } })
+
+/**
+ * is_valid_state() - Returns an SS_ error code if ns is not valid
+ * @mdev:      DRBD device.
+ * @ns:                State to consider.
+ */
+static int is_valid_state(struct drbd_conf *mdev, union drbd_state ns)
+{
+       /* See drbd_state_sw_errors in drbd_strings.c */
+
+       enum drbd_fencing_p fp;
+       int rv = SS_SUCCESS;
+
+       fp = FP_DONT_CARE;
+       if (get_ldev(mdev)) {
+               fp = mdev->ldev->dc.fencing;
+               put_ldev(mdev);
+       }
+
+       if (get_net_conf(mdev)) {
+               if (!mdev->net_conf->two_primaries &&
+                   ns.role == R_PRIMARY && ns.peer == R_PRIMARY)
+                       rv = SS_TWO_PRIMARIES;
+               put_net_conf(mdev);
+       }
+
+       if (rv <= 0)
+               /* already found a reason to abort */;
+       else if (ns.role == R_SECONDARY && mdev->open_cnt)
+               rv = SS_DEVICE_IN_USE;
+
+       else if (ns.role == R_PRIMARY && ns.conn < C_CONNECTED && ns.disk < D_UP_TO_DATE)
+               rv = SS_NO_UP_TO_DATE_DISK;
+
+       else if (fp >= FP_RESOURCE &&
+                ns.role == R_PRIMARY && ns.conn < C_CONNECTED && ns.pdsk >= D_UNKNOWN)
+               rv = SS_PRIMARY_NOP;
+
+       else if (ns.role == R_PRIMARY && ns.disk <= D_INCONSISTENT && ns.pdsk <= D_INCONSISTENT)
+               rv = SS_NO_UP_TO_DATE_DISK;
+
+       else if (ns.conn > C_CONNECTED && ns.disk < D_INCONSISTENT)
+               rv = SS_NO_LOCAL_DISK;
+
+       else if (ns.conn > C_CONNECTED && ns.pdsk < D_INCONSISTENT)
+               rv = SS_NO_REMOTE_DISK;
+
+       else if ((ns.conn == C_CONNECTED ||
+                 ns.conn == C_WF_BITMAP_S ||
+                 ns.conn == C_SYNC_SOURCE ||
+                 ns.conn == C_PAUSED_SYNC_S) &&
+                 ns.disk == D_OUTDATED)
+               rv = SS_CONNECTED_OUTDATES;
+
+       else if ((ns.conn == C_VERIFY_S || ns.conn == C_VERIFY_T) &&
+                (mdev->sync_conf.verify_alg[0] == 0))
+               rv = SS_NO_VERIFY_ALG;
+
+       else if ((ns.conn == C_VERIFY_S || ns.conn == C_VERIFY_T) &&
+                 mdev->agreed_pro_version < 88)
+               rv = SS_NOT_SUPPORTED;
+
+       return rv;
+}
+
+/**
+ * is_valid_state_transition() - Returns an SS_ error code if the state transition is not possible
+ * @mdev:      DRBD device.
+ * @ns:                new state.
+ * @os:                old state.
+ */
+static int is_valid_state_transition(struct drbd_conf *mdev,
+                                    union drbd_state ns, union drbd_state os)
+{
+       int rv = SS_SUCCESS;
+
+       if ((ns.conn == C_STARTING_SYNC_T || ns.conn == C_STARTING_SYNC_S) &&
+           os.conn > C_CONNECTED)
+               rv = SS_RESYNC_RUNNING;
+
+       if (ns.conn == C_DISCONNECTING && os.conn == C_STANDALONE)
+               rv = SS_ALREADY_STANDALONE;
+
+       if (ns.disk > D_ATTACHING && os.disk == D_DISKLESS)
+               rv = SS_IS_DISKLESS;
+
+       if (ns.conn == C_WF_CONNECTION && os.conn < C_UNCONNECTED)
+               rv = SS_NO_NET_CONFIG;
+
+       if (ns.disk == D_OUTDATED && os.disk < D_OUTDATED && os.disk != D_ATTACHING)
+               rv = SS_LOWER_THAN_OUTDATED;
+
+       if (ns.conn == C_DISCONNECTING && os.conn == C_UNCONNECTED)
+               rv = SS_IN_TRANSIENT_STATE;
+
+       if (ns.conn == os.conn && ns.conn == C_WF_REPORT_PARAMS)
+               rv = SS_IN_TRANSIENT_STATE;
+
+       if ((ns.conn == C_VERIFY_S || ns.conn == C_VERIFY_T) && os.conn < C_CONNECTED)
+               rv = SS_NEED_CONNECTION;
+
+       if ((ns.conn == C_VERIFY_S || ns.conn == C_VERIFY_T) &&
+           ns.conn != os.conn && os.conn > C_CONNECTED)
+               rv = SS_RESYNC_RUNNING;
+
+       if ((ns.conn == C_STARTING_SYNC_S || ns.conn == C_STARTING_SYNC_T) &&
+           os.conn < C_CONNECTED)
+               rv = SS_NEED_CONNECTION;
+
+       return rv;
+}
+
+/**
+ * sanitize_state() - Resolves implicitly necessary additional changes to a state transition
+ * @mdev:      DRBD device.
+ * @os:                old state.
+ * @ns:                new state.
+ * @warn_sync_abort:
+ *
+ * When we loose connection, we have to set the state of the peers disk (pdsk)
+ * to D_UNKNOWN. This rule and many more along those lines are in this function.
+ */
+static union drbd_state sanitize_state(struct drbd_conf *mdev, union drbd_state os,
+                                      union drbd_state ns, int *warn_sync_abort)
+{
+       enum drbd_fencing_p fp;
+
+       fp = FP_DONT_CARE;
+       if (get_ldev(mdev)) {
+               fp = mdev->ldev->dc.fencing;
+               put_ldev(mdev);
+       }
+
+       /* Disallow Network errors to configure a device's network part */
+       if ((ns.conn >= C_TIMEOUT && ns.conn <= C_TEAR_DOWN) &&
+           os.conn <= C_DISCONNECTING)
+               ns.conn = os.conn;
+
+       /* After a network error (+C_TEAR_DOWN) only C_UNCONNECTED or C_DISCONNECTING can follow */
+       if (os.conn >= C_TIMEOUT && os.conn <= C_TEAR_DOWN &&
+           ns.conn != C_UNCONNECTED && ns.conn != C_DISCONNECTING)
+               ns.conn = os.conn;
+
+       /* After C_DISCONNECTING only C_STANDALONE may follow */
+       if (os.conn == C_DISCONNECTING && ns.conn != C_STANDALONE)
+               ns.conn = os.conn;
+
+       if (ns.conn < C_CONNECTED) {
+               ns.peer_isp = 0;
+               ns.peer = R_UNKNOWN;
+               if (ns.pdsk > D_UNKNOWN || ns.pdsk < D_INCONSISTENT)
+                       ns.pdsk = D_UNKNOWN;
+       }
+
+       /* Clear the aftr_isp when becoming unconfigured */
+       if (ns.conn == C_STANDALONE && ns.disk == D_DISKLESS && ns.role == R_SECONDARY)
+               ns.aftr_isp = 0;
+
+       if (ns.conn <= C_DISCONNECTING && ns.disk == D_DISKLESS)
+               ns.pdsk = D_UNKNOWN;
+
+       /* Abort resync if a disk fails/detaches */
+       if (os.conn > C_CONNECTED && ns.conn > C_CONNECTED &&
+           (ns.disk <= D_FAILED || ns.pdsk <= D_FAILED)) {
+               if (warn_sync_abort)
+                       *warn_sync_abort = 1;
+               ns.conn = C_CONNECTED;
+       }
+
+       if (ns.conn >= C_CONNECTED &&
+           ((ns.disk == D_CONSISTENT || ns.disk == D_OUTDATED) ||
+            (ns.disk == D_NEGOTIATING && ns.conn == C_WF_BITMAP_T))) {
+               switch (ns.conn) {
+               case C_WF_BITMAP_T:
+               case C_PAUSED_SYNC_T:
+                       ns.disk = D_OUTDATED;
+                       break;
+               case C_CONNECTED:
+               case C_WF_BITMAP_S:
+               case C_SYNC_SOURCE:
+               case C_PAUSED_SYNC_S:
+                       ns.disk = D_UP_TO_DATE;
+                       break;
+               case C_SYNC_TARGET:
+                       ns.disk = D_INCONSISTENT;
+                       dev_warn(DEV, "Implicitly set disk state Inconsistent!\n");
+                       break;
+               }
+               if (os.disk == D_OUTDATED && ns.disk == D_UP_TO_DATE)
+                       dev_warn(DEV, "Implicitly set disk from Outdated to UpToDate\n");
+       }
+
+       if (ns.conn >= C_CONNECTED &&
+           (ns.pdsk == D_CONSISTENT || ns.pdsk == D_OUTDATED)) {
+               switch (ns.conn) {
+               case C_CONNECTED:
+               case C_WF_BITMAP_T:
+               case C_PAUSED_SYNC_T:
+               case C_SYNC_TARGET:
+                       ns.pdsk = D_UP_TO_DATE;
+                       break;
+               case C_WF_BITMAP_S:
+               case C_PAUSED_SYNC_S:
+                       ns.pdsk = D_OUTDATED;
+                       break;
+               case C_SYNC_SOURCE:
+                       ns.pdsk = D_INCONSISTENT;
+                       dev_warn(DEV, "Implicitly set pdsk Inconsistent!\n");
+                       break;
+               }
+               if (os.pdsk == D_OUTDATED && ns.pdsk == D_UP_TO_DATE)
+                       dev_warn(DEV, "Implicitly set pdsk from Outdated to UpToDate\n");
+       }
+
+       /* Connection breaks down before we finished "Negotiating" */
+       if (ns.conn < C_CONNECTED && ns.disk == D_NEGOTIATING &&
+           get_ldev_if_state(mdev, D_NEGOTIATING)) {
+               if (mdev->ed_uuid == mdev->ldev->md.uuid[UI_CURRENT]) {
+                       ns.disk = mdev->new_state_tmp.disk;
+                       ns.pdsk = mdev->new_state_tmp.pdsk;
+               } else {
+                       dev_alert(DEV, "Connection lost while negotiating, no data!\n");
+                       ns.disk = D_DISKLESS;
+                       ns.pdsk = D_UNKNOWN;
+               }
+               put_ldev(mdev);
+       }
+
+       if (fp == FP_STONITH &&
+           (ns.role == R_PRIMARY && ns.conn < C_CONNECTED && ns.pdsk > D_OUTDATED) &&
+           !(os.role == R_PRIMARY && os.conn < C_CONNECTED && os.pdsk > D_OUTDATED))
+               ns.susp = 1;
+
+       if (ns.aftr_isp || ns.peer_isp || ns.user_isp) {
+               if (ns.conn == C_SYNC_SOURCE)
+                       ns.conn = C_PAUSED_SYNC_S;
+               if (ns.conn == C_SYNC_TARGET)
+                       ns.conn = C_PAUSED_SYNC_T;
+       } else {
+               if (ns.conn == C_PAUSED_SYNC_S)
+                       ns.conn = C_SYNC_SOURCE;
+               if (ns.conn == C_PAUSED_SYNC_T)
+                       ns.conn = C_SYNC_TARGET;
+       }
+
+       return ns;
+}
+
+/* helper for __drbd_set_state */
+static void set_ov_position(struct drbd_conf *mdev, enum drbd_conns cs)
+{
+       if (cs == C_VERIFY_T) {
+               /* starting online verify from an arbitrary position
+                * does not fit well into the existing protocol.
+                * on C_VERIFY_T, we initialize ov_left and friends
+                * implicitly in receive_DataRequest once the
+                * first P_OV_REQUEST is received */
+               mdev->ov_start_sector = ~(sector_t)0;
+       } else {
+               unsigned long bit = BM_SECT_TO_BIT(mdev->ov_start_sector);
+               if (bit >= mdev->rs_total)
+                       mdev->ov_start_sector =
+                               BM_BIT_TO_SECT(mdev->rs_total - 1);
+               mdev->ov_position = mdev->ov_start_sector;
+       }
+}
+
+/**
+ * __drbd_set_state() - Set a new DRBD state
+ * @mdev:      DRBD device.
+ * @ns:                new state.
+ * @flags:     Flags
+ * @done:      Optional completion, that will get completed after the after_state_ch() finished
+ *
+ * Caller needs to hold req_lock, and global_state_lock. Do not call directly.
+ */
+int __drbd_set_state(struct drbd_conf *mdev,
+                   union drbd_state ns, enum chg_state_flags flags,
+                   struct completion *done)
+{
+       union drbd_state os;
+       int rv = SS_SUCCESS;
+       int warn_sync_abort = 0;
+       struct after_state_chg_work *ascw;
+
+       os = mdev->state;
+
+       ns = sanitize_state(mdev, os, ns, &warn_sync_abort);
+
+       if (ns.i == os.i)
+               return SS_NOTHING_TO_DO;
+
+       if (!(flags & CS_HARD)) {
+               /*  pre-state-change checks ; only look at ns  */
+               /* See drbd_state_sw_errors in drbd_strings.c */
+
+               rv = is_valid_state(mdev, ns);
+               if (rv < SS_SUCCESS) {
+                       /* If the old state was illegal as well, then let
+                          this happen...*/
+
+                       if (is_valid_state(mdev, os) == rv) {
+                               dev_err(DEV, "Considering state change from bad state. "
+                                   "Error would be: '%s'\n",
+                                   drbd_set_st_err_str(rv));
+                               print_st(mdev, "old", os);
+                               print_st(mdev, "new", ns);
+                               rv = is_valid_state_transition(mdev, ns, os);
+                       }
+               } else
+                       rv = is_valid_state_transition(mdev, ns, os);
+       }
+
+       if (rv < SS_SUCCESS) {
+               if (flags & CS_VERBOSE)
+                       print_st_err(mdev, os, ns, rv);
+               return rv;
+       }
+
+       if (warn_sync_abort)
+               dev_warn(DEV, "Resync aborted.\n");
+
+       {
+               char *pbp, pb[300];
+               pbp = pb;
+               *pbp = 0;
+               PSC(role);
+               PSC(peer);
+               PSC(conn);
+               PSC(disk);
+               PSC(pdsk);
+               PSC(susp);
+               PSC(aftr_isp);
+               PSC(peer_isp);
+               PSC(user_isp);
+               dev_info(DEV, "%s\n", pb);
+       }
+
+       /* solve the race between becoming unconfigured,
+        * worker doing the cleanup, and
+        * admin reconfiguring us:
+        * on (re)configure, first set CONFIG_PENDING,
+        * then wait for a potentially exiting worker,
+        * start the worker, and schedule one no_op.
+        * then proceed with configuration.
+        */
+       if (ns.disk == D_DISKLESS &&
+           ns.conn == C_STANDALONE &&
+           ns.role == R_SECONDARY &&
+           !test_and_set_bit(CONFIG_PENDING, &mdev->flags))
+               set_bit(DEVICE_DYING, &mdev->flags);
+
+       mdev->state.i = ns.i;
+       wake_up(&mdev->misc_wait);
+       wake_up(&mdev->state_wait);
+
+       /*   post-state-change actions   */
+       if (os.conn >= C_SYNC_SOURCE   && ns.conn <= C_CONNECTED) {
+               set_bit(STOP_SYNC_TIMER, &mdev->flags);
+               mod_timer(&mdev->resync_timer, jiffies);
+       }
+
+       /* aborted verify run. log the last position */
+       if ((os.conn == C_VERIFY_S || os.conn == C_VERIFY_T) &&
+           ns.conn < C_CONNECTED) {
+               mdev->ov_start_sector =
+                       BM_BIT_TO_SECT(mdev->rs_total - mdev->ov_left);
+               dev_info(DEV, "Online Verify reached sector %llu\n",
+                       (unsigned long long)mdev->ov_start_sector);
+       }
+
+       if ((os.conn == C_PAUSED_SYNC_T || os.conn == C_PAUSED_SYNC_S) &&
+           (ns.conn == C_SYNC_TARGET  || ns.conn == C_SYNC_SOURCE)) {
+               dev_info(DEV, "Syncer continues.\n");
+               mdev->rs_paused += (long)jiffies-(long)mdev->rs_mark_time;
+               if (ns.conn == C_SYNC_TARGET) {
+                       if (!test_and_clear_bit(STOP_SYNC_TIMER, &mdev->flags))
+                               mod_timer(&mdev->resync_timer, jiffies);
+                       /* This if (!test_bit) is only needed for the case
+                          that a device that has ceased to used its timer,
+                          i.e. it is already in drbd_resync_finished() gets
+                          paused and resumed. */
+               }
+       }
+
+       if ((os.conn == C_SYNC_TARGET  || os.conn == C_SYNC_SOURCE) &&
+           (ns.conn == C_PAUSED_SYNC_T || ns.conn == C_PAUSED_SYNC_S)) {
+               dev_info(DEV, "Resync suspended\n");
+               mdev->rs_mark_time = jiffies;
+               if (ns.conn == C_PAUSED_SYNC_T)
+                       set_bit(STOP_SYNC_TIMER, &mdev->flags);
+       }
+
+       if (os.conn == C_CONNECTED &&
+           (ns.conn == C_VERIFY_S || ns.conn == C_VERIFY_T)) {
+               mdev->ov_position = 0;
+               mdev->rs_total =
+               mdev->rs_mark_left = drbd_bm_bits(mdev);
+               if (mdev->agreed_pro_version >= 90)
+                       set_ov_position(mdev, ns.conn);
+               else
+                       mdev->ov_start_sector = 0;
+               mdev->ov_left = mdev->rs_total
+                             - BM_SECT_TO_BIT(mdev->ov_position);
+               mdev->rs_start     =
+               mdev->rs_mark_time = jiffies;
+               mdev->ov_last_oos_size = 0;
+               mdev->ov_last_oos_start = 0;
+
+               if (ns.conn == C_VERIFY_S) {
+                       dev_info(DEV, "Starting Online Verify from sector %llu\n",
+                                       (unsigned long long)mdev->ov_position);
+                       mod_timer(&mdev->resync_timer, jiffies);
+               }
+       }
+
+       if (get_ldev(mdev)) {
+               u32 mdf = mdev->ldev->md.flags & ~(MDF_CONSISTENT|MDF_PRIMARY_IND|
+                                                MDF_CONNECTED_IND|MDF_WAS_UP_TO_DATE|
+                                                MDF_PEER_OUT_DATED|MDF_CRASHED_PRIMARY);
+
+               if (test_bit(CRASHED_PRIMARY, &mdev->flags))
+                       mdf |= MDF_CRASHED_PRIMARY;
+               if (mdev->state.role == R_PRIMARY ||
+                   (mdev->state.pdsk < D_INCONSISTENT && mdev->state.peer == R_PRIMARY))
+                       mdf |= MDF_PRIMARY_IND;
+               if (mdev->state.conn > C_WF_REPORT_PARAMS)
+                       mdf |= MDF_CONNECTED_IND;
+               if (mdev->state.disk > D_INCONSISTENT)
+                       mdf |= MDF_CONSISTENT;
+               if (mdev->state.disk > D_OUTDATED)
+                       mdf |= MDF_WAS_UP_TO_DATE;
+               if (mdev->state.pdsk <= D_OUTDATED && mdev->state.pdsk >= D_INCONSISTENT)
+                       mdf |= MDF_PEER_OUT_DATED;
+               if (mdf != mdev->ldev->md.flags) {
+                       mdev->ldev->md.flags = mdf;
+                       drbd_md_mark_dirty(mdev);
+               }
+               if (os.disk < D_CONSISTENT && ns.disk >= D_CONSISTENT)
+                       drbd_set_ed_uuid(mdev, mdev->ldev->md.uuid[UI_CURRENT]);
+               put_ldev(mdev);
+       }
+
+       /* Peer was forced D_UP_TO_DATE & R_PRIMARY, consider to resync */
+       if (os.disk == D_INCONSISTENT && os.pdsk == D_INCONSISTENT &&
+           os.peer == R_SECONDARY && ns.peer == R_PRIMARY)
+               set_bit(CONSIDER_RESYNC, &mdev->flags);
+
+       /* Receiver should clean up itself */
+       if (os.conn != C_DISCONNECTING && ns.conn == C_DISCONNECTING)
+               drbd_thread_stop_nowait(&mdev->receiver);
+
+       /* Now the receiver finished cleaning up itself, it should die */
+       if (os.conn != C_STANDALONE && ns.conn == C_STANDALONE)
+               drbd_thread_stop_nowait(&mdev->receiver);
+
+       /* Upon network failure, we need to restart the receiver. */
+       if (os.conn > C_TEAR_DOWN &&
+           ns.conn <= C_TEAR_DOWN && ns.conn >= C_TIMEOUT)
+               drbd_thread_restart_nowait(&mdev->receiver);
+
+       ascw = kmalloc(sizeof(*ascw), GFP_ATOMIC);
+       if (ascw) {
+               ascw->os = os;
+               ascw->ns = ns;
+               ascw->flags = flags;
+               ascw->w.cb = w_after_state_ch;
+               ascw->done = done;
+               drbd_queue_work(&mdev->data.work, &ascw->w);
+       } else {
+               dev_warn(DEV, "Could not kmalloc an ascw\n");
+       }
+
+       return rv;
+}
+
+static int w_after_state_ch(struct drbd_conf *mdev, struct drbd_work *w, int unused)
+{
+       struct after_state_chg_work *ascw =
+               container_of(w, struct after_state_chg_work, w);
+       after_state_ch(mdev, ascw->os, ascw->ns, ascw->flags);
+       if (ascw->flags & CS_WAIT_COMPLETE) {
+               D_ASSERT(ascw->done != NULL);
+               complete(ascw->done);
+       }
+       kfree(ascw);
+
+       return 1;
+}
+
+static void abw_start_sync(struct drbd_conf *mdev, int rv)
+{
+       if (rv) {
+               dev_err(DEV, "Writing the bitmap failed not starting resync.\n");
+               _drbd_request_state(mdev, NS(conn, C_CONNECTED), CS_VERBOSE);
+               return;
+       }
+
+       switch (mdev->state.conn) {
+       case C_STARTING_SYNC_T:
+               _drbd_request_state(mdev, NS(conn, C_WF_SYNC_UUID), CS_VERBOSE);
+               break;
+       case C_STARTING_SYNC_S:
+               drbd_start_resync(mdev, C_SYNC_SOURCE);
+               break;
+       }
+}
+
+/**
+ * after_state_ch() - Perform after state change actions that may sleep
+ * @mdev:      DRBD device.
+ * @os:                old state.
+ * @ns:                new state.
+ * @flags:     Flags
+ */
+static void after_state_ch(struct drbd_conf *mdev, union drbd_state os,
+                          union drbd_state ns, enum chg_state_flags flags)
+{
+       enum drbd_fencing_p fp;
+
+       if (os.conn != C_CONNECTED && ns.conn == C_CONNECTED) {
+               clear_bit(CRASHED_PRIMARY, &mdev->flags);
+               if (mdev->p_uuid)
+                       mdev->p_uuid[UI_FLAGS] &= ~((u64)2);
+       }
+
+       fp = FP_DONT_CARE;
+       if (get_ldev(mdev)) {
+               fp = mdev->ldev->dc.fencing;
+               put_ldev(mdev);
+       }
+
+       /* Inform userspace about the change... */
+       drbd_bcast_state(mdev, ns);
+
+       if (!(os.role == R_PRIMARY && os.disk < D_UP_TO_DATE && os.pdsk < D_UP_TO_DATE) &&
+           (ns.role == R_PRIMARY && ns.disk < D_UP_TO_DATE && ns.pdsk < D_UP_TO_DATE))
+               drbd_khelper(mdev, "pri-on-incon-degr");
+
+       /* Here we have the actions that are performed after a
+          state change. This function might sleep */
+
+       if (fp == FP_STONITH && ns.susp) {
+               /* case1: The outdate peer handler is successful:
+                * case2: The connection was established again: */
+               if ((os.pdsk > D_OUTDATED  && ns.pdsk <= D_OUTDATED) ||
+                   (os.conn < C_CONNECTED && ns.conn >= C_CONNECTED)) {
+                       tl_clear(mdev);
+                       spin_lock_irq(&mdev->req_lock);
+                       _drbd_set_state(_NS(mdev, susp, 0), CS_VERBOSE, NULL);
+                       spin_unlock_irq(&mdev->req_lock);
+               }
+       }
+       /* Do not change the order of the if above and the two below... */
+       if (os.pdsk == D_DISKLESS && ns.pdsk > D_DISKLESS) {      /* attach on the peer */
+               drbd_send_uuids(mdev);
+               drbd_send_state(mdev);
+       }
+       if (os.conn != C_WF_BITMAP_S && ns.conn == C_WF_BITMAP_S)
+               drbd_queue_bitmap_io(mdev, &drbd_send_bitmap, NULL, "send_bitmap (WFBitMapS)");
+
+       /* Lost contact to peer's copy of the data */
+       if ((os.pdsk >= D_INCONSISTENT &&
+            os.pdsk != D_UNKNOWN &&
+            os.pdsk != D_OUTDATED)
+       &&  (ns.pdsk < D_INCONSISTENT ||
+            ns.pdsk == D_UNKNOWN ||
+            ns.pdsk == D_OUTDATED)) {
+               kfree(mdev->p_uuid);
+               mdev->p_uuid = NULL;
+               if (get_ldev(mdev)) {
+                       if ((ns.role == R_PRIMARY || ns.peer == R_PRIMARY) &&
+                           mdev->ldev->md.uuid[UI_BITMAP] == 0 && ns.disk >= D_UP_TO_DATE) {
+                               drbd_uuid_new_current(mdev);
+                               drbd_send_uuids(mdev);
+                       }
+                       put_ldev(mdev);
+               }
+       }
+
+       if (ns.pdsk < D_INCONSISTENT && get_ldev(mdev)) {
+               if (ns.peer == R_PRIMARY && mdev->ldev->md.uuid[UI_BITMAP] == 0)
+                       drbd_uuid_new_current(mdev);
+
+               /* D_DISKLESS Peer becomes secondary */
+               if (os.peer == R_PRIMARY && ns.peer == R_SECONDARY)
+                       drbd_al_to_on_disk_bm(mdev);
+               put_ldev(mdev);
+       }
+
+       /* Last part of the attaching process ... */
+       if (ns.conn >= C_CONNECTED &&
+           os.disk == D_ATTACHING && ns.disk == D_NEGOTIATING) {
+               kfree(mdev->p_uuid); /* We expect to receive up-to-date UUIDs soon. */
+               mdev->p_uuid = NULL; /* ...to not use the old ones in the mean time */
+               drbd_send_sizes(mdev, 0);  /* to start sync... */
+               drbd_send_uuids(mdev);
+               drbd_send_state(mdev);
+       }
+
+       /* We want to pause/continue resync, tell peer. */
+       if (ns.conn >= C_CONNECTED &&
+            ((os.aftr_isp != ns.aftr_isp) ||
+             (os.user_isp != ns.user_isp)))
+               drbd_send_state(mdev);
+
+       /* In case one of the isp bits got set, suspend other devices. */
+       if ((!os.aftr_isp && !os.peer_isp && !os.user_isp) &&
+           (ns.aftr_isp || ns.peer_isp || ns.user_isp))
+               suspend_other_sg(mdev);
+
+       /* Make sure the peer gets informed about eventual state
+          changes (ISP bits) while we were in WFReportParams. */
+       if (os.conn == C_WF_REPORT_PARAMS && ns.conn >= C_CONNECTED)
+               drbd_send_state(mdev);
+
+       /* We are in the progress to start a full sync... */
+       if ((os.conn != C_STARTING_SYNC_T && ns.conn == C_STARTING_SYNC_T) ||
+           (os.conn != C_STARTING_SYNC_S && ns.conn == C_STARTING_SYNC_S))
+               drbd_queue_bitmap_io(mdev, &drbd_bmio_set_n_write, &abw_start_sync, "set_n_write from StartingSync");
+
+       /* We are invalidating our self... */
+       if (os.conn < C_CONNECTED && ns.conn < C_CONNECTED &&
+           os.disk > D_INCONSISTENT && ns.disk == D_INCONSISTENT)
+               drbd_queue_bitmap_io(mdev, &drbd_bmio_set_n_write, NULL, "set_n_write from invalidate");
+
+       if (os.disk > D_FAILED && ns.disk == D_FAILED) {
+               enum drbd_io_error_p eh;
+
+               eh = EP_PASS_ON;
+               if (get_ldev_if_state(mdev, D_FAILED)) {
+                       eh = mdev->ldev->dc.on_io_error;
+                       put_ldev(mdev);
+               }
+
+               drbd_rs_cancel_all(mdev);
+               /* since get_ldev() only works as long as disk>=D_INCONSISTENT,
+                  and it is D_DISKLESS here, local_cnt can only go down, it can
+                  not increase... It will reach zero */
+               wait_event(mdev->misc_wait, !atomic_read(&mdev->local_cnt));
+               mdev->rs_total = 0;
+               mdev->rs_failed = 0;
+               atomic_set(&mdev->rs_pending_cnt, 0);
+
+               spin_lock_irq(&mdev->req_lock);
+               _drbd_set_state(_NS(mdev, disk, D_DISKLESS), CS_HARD, NULL);
+               spin_unlock_irq(&mdev->req_lock);
+
+               if (eh == EP_CALL_HELPER)
+                       drbd_khelper(mdev, "local-io-error");
+       }
+
+       if (os.disk > D_DISKLESS && ns.disk == D_DISKLESS) {
+
+               if (os.disk == D_FAILED) /* && ns.disk == D_DISKLESS*/ {
+                       if (drbd_send_state(mdev))
+                               dev_warn(DEV, "Notified peer that my disk is broken.\n");
+                       else
+                               dev_err(DEV, "Sending state in drbd_io_error() failed\n");
+               }
+
+               lc_destroy(mdev->resync);
+               mdev->resync = NULL;
+               lc_destroy(mdev->act_log);
+               mdev->act_log = NULL;
+               __no_warn(local,
+                       drbd_free_bc(mdev->ldev);
+                       mdev->ldev = NULL;);
+
+               if (mdev->md_io_tmpp)
+                       __free_page(mdev->md_io_tmpp);
+       }
+
+       /* Disks got bigger while they were detached */
+       if (ns.disk > D_NEGOTIATING && ns.pdsk > D_NEGOTIATING &&
+           test_and_clear_bit(RESYNC_AFTER_NEG, &mdev->flags)) {
+               if (ns.conn == C_CONNECTED)
+                       resync_after_online_grow(mdev);
+       }
+
+       /* A resync finished or aborted, wake paused devices... */
+       if ((os.conn > C_CONNECTED && ns.conn <= C_CONNECTED) ||
+           (os.peer_isp && !ns.peer_isp) ||
+           (os.user_isp && !ns.user_isp))
+               resume_next_sg(mdev);
+
+       /* Upon network connection, we need to start the receiver */
+       if (os.conn == C_STANDALONE && ns.conn == C_UNCONNECTED)
+               drbd_thread_start(&mdev->receiver);
+
+       /* Terminate worker thread if we are unconfigured - it will be
+          restarted as needed... */
+       if (ns.disk == D_DISKLESS &&
+           ns.conn == C_STANDALONE &&
+           ns.role == R_SECONDARY) {
+               if (os.aftr_isp != ns.aftr_isp)
+                       resume_next_sg(mdev);
+               /* set in __drbd_set_state, unless CONFIG_PENDING was set */
+               if (test_bit(DEVICE_DYING, &mdev->flags))
+                       drbd_thread_stop_nowait(&mdev->worker);
+       }
+
+       drbd_md_sync(mdev);
+}
+
+
+static int drbd_thread_setup(void *arg)
+{
+       struct drbd_thread *thi = (struct drbd_thread *) arg;
+       struct drbd_conf *mdev = thi->mdev;
+       unsigned long flags;
+       int retval;
+
+restart:
+       retval = thi->function(thi);
+
+       spin_lock_irqsave(&thi->t_lock, flags);
+
+       /* if the receiver has been "Exiting", the last thing it did
+        * was set the conn state to "StandAlone",
+        * if now a re-connect request comes in, conn state goes C_UNCONNECTED,
+        * and receiver thread will be "started".
+        * drbd_thread_start needs to set "Restarting" in that case.
+        * t_state check and assignment needs to be within the same spinlock,
+        * so either thread_start sees Exiting, and can remap to Restarting,
+        * or thread_start see None, and can proceed as normal.
+        */
+
+       if (thi->t_state == Restarting) {
+               dev_info(DEV, "Restarting %s\n", current->comm);
+               thi->t_state = Running;
+               spin_unlock_irqrestore(&thi->t_lock, flags);
+               goto restart;
+       }
+
+       thi->task = NULL;
+       thi->t_state = None;
+       smp_mb();
+       complete(&thi->stop);
+       spin_unlock_irqrestore(&thi->t_lock, flags);
+
+       dev_info(DEV, "Terminating %s\n", current->comm);
+
+       /* Release mod reference taken when thread was started */
+       module_put(THIS_MODULE);
+       return retval;
+}
+
+static void drbd_thread_init(struct drbd_conf *mdev, struct drbd_thread *thi,
+                     int (*func) (struct drbd_thread *))
+{
+       spin_lock_init(&thi->t_lock);
+       thi->task    = NULL;
+       thi->t_state = None;
+       thi->function = func;
+       thi->mdev = mdev;
+}
+
+int drbd_thread_start(struct drbd_thread *thi)
+{
+       struct drbd_conf *mdev = thi->mdev;
+       struct task_struct *nt;
+       unsigned long flags;
+
+       const char *me =
+               thi == &mdev->receiver ? "receiver" :
+               thi == &mdev->asender  ? "asender"  :
+               thi == &mdev->worker   ? "worker"   : "NONSENSE";
+
+       /* is used from state engine doing drbd_thread_stop_nowait,
+        * while holding the req lock irqsave */
+       spin_lock_irqsave(&thi->t_lock, flags);
+
+       switch (thi->t_state) {
+       case None:
+               dev_info(DEV, "Starting %s thread (from %s [%d])\n",
+                               me, current->comm, current->pid);
+
+               /* Get ref on module for thread - this is released when thread exits */
+               if (!try_module_get(THIS_MODULE)) {
+                       dev_err(DEV, "Failed to get module reference in drbd_thread_start\n");
+                       spin_unlock_irqrestore(&thi->t_lock, flags);
+                       return FALSE;
+               }
+
+               init_completion(&thi->stop);
+               D_ASSERT(thi->task == NULL);
+               thi->reset_cpu_mask = 1;
+               thi->t_state = Running;
+               spin_unlock_irqrestore(&thi->t_lock, flags);
+               flush_signals(current); /* otherw. may get -ERESTARTNOINTR */
+
+               nt = kthread_create(drbd_thread_setup, (void *) thi,
+                                   "drbd%d_%s", mdev_to_minor(mdev), me);
+
+               if (IS_ERR(nt)) {
+                       dev_err(DEV, "Couldn't start thread\n");
+
+                       module_put(THIS_MODULE);
+                       return FALSE;
+               }
+               spin_lock_irqsave(&thi->t_lock, flags);
+               thi->task = nt;
+               thi->t_state = Running;
+               spin_unlock_irqrestore(&thi->t_lock, flags);
+               wake_up_process(nt);
+               break;
+       case Exiting:
+               thi->t_state = Restarting;
+               dev_info(DEV, "Restarting %s thread (from %s [%d])\n",
+                               me, current->comm, current->pid);
+               /* fall through */
+       case Running:
+       case Restarting:
+       default:
+               spin_unlock_irqrestore(&thi->t_lock, flags);
+               break;
+       }
+
+       return TRUE;
+}
+
+
+void _drbd_thread_stop(struct drbd_thread *thi, int restart, int wait)
+{
+       unsigned long flags;
+
+       enum drbd_thread_state ns = restart ? Restarting : Exiting;
+
+       /* may be called from state engine, holding the req lock irqsave */
+       spin_lock_irqsave(&thi->t_lock, flags);
+
+       if (thi->t_state == None) {
+               spin_unlock_irqrestore(&thi->t_lock, flags);
+               if (restart)
+                       drbd_thread_start(thi);
+               return;
+       }
+
+       if (thi->t_state != ns) {
+               if (thi->task == NULL) {
+                       spin_unlock_irqrestore(&thi->t_lock, flags);
+                       return;
+               }
+
+               thi->t_state = ns;
+               smp_mb();
+               init_completion(&thi->stop);
+               if (thi->task != current)
+                       force_sig(DRBD_SIGKILL, thi->task);
+
+       }
+
+       spin_unlock_irqrestore(&thi->t_lock, flags);
+
+       if (wait)
+               wait_for_completion(&thi->stop);
+}
+
+#ifdef CONFIG_SMP
+/**
+ * drbd_calc_cpu_mask() - Generate CPU masks, spread over all CPUs
+ * @mdev:      DRBD device.
+ *
+ * Forces all threads of a device onto the same CPU. This is beneficial for
+ * DRBD's performance. May be overwritten by user's configuration.
+ */
+void drbd_calc_cpu_mask(struct drbd_conf *mdev)
+{
+       int ord, cpu;
+
+       /* user override. */
+       if (cpumask_weight(mdev->cpu_mask))
+               return;
+
+       ord = mdev_to_minor(mdev) % cpumask_weight(cpu_online_mask);
+       for_each_online_cpu(cpu) {
+               if (ord-- == 0) {
+                       cpumask_set_cpu(cpu, mdev->cpu_mask);
+                       return;
+               }
+       }
+       /* should not be reached */
+       cpumask_setall(mdev->cpu_mask);
+}
+
+/**
+ * drbd_thread_current_set_cpu() - modifies the cpu mask of the _current_ thread
+ * @mdev:      DRBD device.
+ *
+ * call in the "main loop" of _all_ threads, no need for any mutex, current won't die
+ * prematurely.
+ */
+void drbd_thread_current_set_cpu(struct drbd_conf *mdev)
+{
+       struct task_struct *p = current;
+       struct drbd_thread *thi =
+               p == mdev->asender.task  ? &mdev->asender  :
+               p == mdev->receiver.task ? &mdev->receiver :
+               p == mdev->worker.task   ? &mdev->worker   :
+               NULL;
+       ERR_IF(thi == NULL)
+               return;
+       if (!thi->reset_cpu_mask)
+               return;
+       thi->reset_cpu_mask = 0;
+       set_cpus_allowed_ptr(p, mdev->cpu_mask);
+}
+#endif
+
+/* the appropriate socket mutex must be held already */
+int _drbd_send_cmd(struct drbd_conf *mdev, struct socket *sock,
+                         enum drbd_packets cmd, struct p_header *h,
+                         size_t size, unsigned msg_flags)
+{
+       int sent, ok;
+
+       ERR_IF(!h) return FALSE;
+       ERR_IF(!size) return FALSE;
+
+       h->magic   = BE_DRBD_MAGIC;
+       h->command = cpu_to_be16(cmd);
+       h->length  = cpu_to_be16(size-sizeof(struct p_header));
+
+       sent = drbd_send(mdev, sock, h, size, msg_flags);
+
+       ok = (sent == size);
+       if (!ok)
+               dev_err(DEV, "short sent %s size=%d sent=%d\n",
+                   cmdname(cmd), (int)size, sent);
+       return ok;
+}
+
+/* don't pass the socket. we may only look at it
+ * when we hold the appropriate socket mutex.
+ */
+int drbd_send_cmd(struct drbd_conf *mdev, int use_data_socket,
+                 enum drbd_packets cmd, struct p_header *h, size_t size)
+{
+       int ok = 0;
+       struct socket *sock;
+
+       if (use_data_socket) {
+               mutex_lock(&mdev->data.mutex);
+               sock = mdev->data.socket;
+       } else {
+               mutex_lock(&mdev->meta.mutex);
+               sock = mdev->meta.socket;
+       }
+
+       /* drbd_disconnect() could have called drbd_free_sock()
+        * while we were waiting in down()... */
+       if (likely(sock != NULL))
+               ok = _drbd_send_cmd(mdev, sock, cmd, h, size, 0);
+
+       if (use_data_socket)
+               mutex_unlock(&mdev->data.mutex);
+       else
+               mutex_unlock(&mdev->meta.mutex);
+       return ok;
+}
+
+int drbd_send_cmd2(struct drbd_conf *mdev, enum drbd_packets cmd, char *data,
+                  size_t size)
+{
+       struct p_header h;
+       int ok;
+
+       h.magic   = BE_DRBD_MAGIC;
+       h.command = cpu_to_be16(cmd);
+       h.length  = cpu_to_be16(size);
+
+       if (!drbd_get_data_sock(mdev))
+               return 0;
+
+       ok = (sizeof(h) ==
+               drbd_send(mdev, mdev->data.socket, &h, sizeof(h), 0));
+       ok = ok && (size ==
+               drbd_send(mdev, mdev->data.socket, data, size, 0));
+
+       drbd_put_data_sock(mdev);
+
+       return ok;
+}
+
+int drbd_send_sync_param(struct drbd_conf *mdev, struct syncer_conf *sc)
+{
+       struct p_rs_param_89 *p;
+       struct socket *sock;
+       int size, rv;
+       const int apv = mdev->agreed_pro_version;
+
+       size = apv <= 87 ? sizeof(struct p_rs_param)
+               : apv == 88 ? sizeof(struct p_rs_param)
+                       + strlen(mdev->sync_conf.verify_alg) + 1
+               : /* 89 */    sizeof(struct p_rs_param_89);
+
+       /* used from admin command context and receiver/worker context.
+        * to avoid kmalloc, grab the socket right here,
+        * then use the pre-allocated sbuf there */
+       mutex_lock(&mdev->data.mutex);
+       sock = mdev->data.socket;
+
+       if (likely(sock != NULL)) {
+               enum drbd_packets cmd = apv >= 89 ? P_SYNC_PARAM89 : P_SYNC_PARAM;
+
+               p = &mdev->data.sbuf.rs_param_89;
+
+               /* initialize verify_alg and csums_alg */
+               memset(p->verify_alg, 0, 2 * SHARED_SECRET_MAX);
+
+               p->rate = cpu_to_be32(sc->rate);
+
+               if (apv >= 88)
+                       strcpy(p->verify_alg, mdev->sync_conf.verify_alg);
+               if (apv >= 89)
+                       strcpy(p->csums_alg, mdev->sync_conf.csums_alg);
+
+               rv = _drbd_send_cmd(mdev, sock, cmd, &p->head, size, 0);
+       } else
+               rv = 0; /* not ok */
+
+       mutex_unlock(&mdev->data.mutex);
+
+       return rv;
+}
+
+int drbd_send_protocol(struct drbd_conf *mdev)
+{
+       struct p_protocol *p;
+       int size, rv;
+
+       size = sizeof(struct p_protocol);
+
+       if (mdev->agreed_pro_version >= 87)
+               size += strlen(mdev->net_conf->integrity_alg) + 1;
+
+       /* we must not recurse into our own queue,
+        * as that is blocked during handshake */
+       p = kmalloc(size, GFP_NOIO);
+       if (p == NULL)
+               return 0;
+
+       p->protocol      = cpu_to_be32(mdev->net_conf->wire_protocol);
+       p->after_sb_0p   = cpu_to_be32(mdev->net_conf->after_sb_0p);
+       p->after_sb_1p   = cpu_to_be32(mdev->net_conf->after_sb_1p);
+       p->after_sb_2p   = cpu_to_be32(mdev->net_conf->after_sb_2p);
+       p->want_lose     = cpu_to_be32(mdev->net_conf->want_lose);
+       p->two_primaries = cpu_to_be32(mdev->net_conf->two_primaries);
+
+       if (mdev->agreed_pro_version >= 87)
+               strcpy(p->integrity_alg, mdev->net_conf->integrity_alg);
+
+       rv = drbd_send_cmd(mdev, USE_DATA_SOCKET, P_PROTOCOL,
+                          (struct p_header *)p, size);
+       kfree(p);
+       return rv;
+}
+
+int _drbd_send_uuids(struct drbd_conf *mdev, u64 uuid_flags)
+{
+       struct p_uuids p;
+       int i;
+
+       if (!get_ldev_if_state(mdev, D_NEGOTIATING))
+               return 1;
+
+       for (i = UI_CURRENT; i < UI_SIZE; i++)
+               p.uuid[i] = mdev->ldev ? cpu_to_be64(mdev->ldev->md.uuid[i]) : 0;
+
+       mdev->comm_bm_set = drbd_bm_total_weight(mdev);
+       p.uuid[UI_SIZE] = cpu_to_be64(mdev->comm_bm_set);
+       uuid_flags |= mdev->net_conf->want_lose ? 1 : 0;
+       uuid_flags |= test_bit(CRASHED_PRIMARY, &mdev->flags) ? 2 : 0;
+       uuid_flags |= mdev->new_state_tmp.disk == D_INCONSISTENT ? 4 : 0;
+       p.uuid[UI_FLAGS] = cpu_to_be64(uuid_flags);
+
+       put_ldev(mdev);
+
+       return drbd_send_cmd(mdev, USE_DATA_SOCKET, P_UUIDS,
+                            (struct p_header *)&p, sizeof(p));
+}
+
+int drbd_send_uuids(struct drbd_conf *mdev)
+{
+       return _drbd_send_uuids(mdev, 0);
+}
+
+int drbd_send_uuids_skip_initial_sync(struct drbd_conf *mdev)
+{
+       return _drbd_send_uuids(mdev, 8);
+}
+
+
+int drbd_send_sync_uuid(struct drbd_conf *mdev, u64 val)
+{
+       struct p_rs_uuid p;
+
+       p.uuid = cpu_to_be64(val);
+
+       return drbd_send_cmd(mdev, USE_DATA_SOCKET, P_SYNC_UUID,
+                            (struct p_header *)&p, sizeof(p));
+}
+
+int drbd_send_sizes(struct drbd_conf *mdev, int trigger_reply)
+{
+       struct p_sizes p;
+       sector_t d_size, u_size;
+       int q_order_type;
+       int ok;
+
+       if (get_ldev_if_state(mdev, D_NEGOTIATING)) {
+               D_ASSERT(mdev->ldev->backing_bdev);
+               d_size = drbd_get_max_capacity(mdev->ldev);
+               u_size = mdev->ldev->dc.disk_size;
+               q_order_type = drbd_queue_order_type(mdev);
+               p.queue_order_type = cpu_to_be32(drbd_queue_order_type(mdev));
+               put_ldev(mdev);
+       } else {
+               d_size = 0;
+               u_size = 0;
+               q_order_type = QUEUE_ORDERED_NONE;
+       }
+
+       p.d_size = cpu_to_be64(d_size);
+       p.u_size = cpu_to_be64(u_size);
+       p.c_size = cpu_to_be64(trigger_reply ? 0 : drbd_get_capacity(mdev->this_bdev));
+       p.max_segment_size = cpu_to_be32(queue_max_segment_size(mdev->rq_queue));
+       p.queue_order_type = cpu_to_be32(q_order_type);
+
+       ok = drbd_send_cmd(mdev, USE_DATA_SOCKET, P_SIZES,
+                          (struct p_header *)&p, sizeof(p));
+       return ok;
+}
+
+/**
+ * drbd_send_state() - Sends the drbd state to the peer
+ * @mdev:      DRBD device.
+ */
+int drbd_send_state(struct drbd_conf *mdev)
+{
+       struct socket *sock;
+       struct p_state p;
+       int ok = 0;
+
+       /* Grab state lock so we wont send state if we're in the middle
+        * of a cluster wide state change on another thread */
+       drbd_state_lock(mdev);
+
+       mutex_lock(&mdev->data.mutex);
+
+       p.state = cpu_to_be32(mdev->state.i); /* Within the send mutex */
+       sock = mdev->data.socket;
+
+       if (likely(sock != NULL)) {
+               ok = _drbd_send_cmd(mdev, sock, P_STATE,
+                                   (struct p_header *)&p, sizeof(p), 0);
+       }
+
+       mutex_unlock(&mdev->data.mutex);
+
+       drbd_state_unlock(mdev);
+       return ok;
+}
+
+int drbd_send_state_req(struct drbd_conf *mdev,
+       union drbd_state mask, union drbd_state val)
+{
+       struct p_req_state p;
+
+       p.mask    = cpu_to_be32(mask.i);
+       p.val     = cpu_to_be32(val.i);
+
+       return drbd_send_cmd(mdev, USE_DATA_SOCKET, P_STATE_CHG_REQ,
+                            (struct p_header *)&p, sizeof(p));
+}
+
+int drbd_send_sr_reply(struct drbd_conf *mdev, int retcode)
+{
+       struct p_req_state_reply p;
+
+       p.retcode    = cpu_to_be32(retcode);
+
+       return drbd_send_cmd(mdev, USE_META_SOCKET, P_STATE_CHG_REPLY,
+                            (struct p_header *)&p, sizeof(p));
+}
+
+int fill_bitmap_rle_bits(struct drbd_conf *mdev,
+       struct p_compressed_bm *p,
+       struct bm_xfer_ctx *c)
+{
+       struct bitstream bs;
+       unsigned long plain_bits;
+       unsigned long tmp;
+       unsigned long rl;
+       unsigned len;
+       unsigned toggle;
+       int bits;
+
+       /* may we use this feature? */
+       if ((mdev->sync_conf.use_rle == 0) ||
+               (mdev->agreed_pro_version < 90))
+                       return 0;
+
+       if (c->bit_offset >= c->bm_bits)
+               return 0; /* nothing to do. */
+
+       /* use at most thus many bytes */
+       bitstream_init(&bs, p->code, BM_PACKET_VLI_BYTES_MAX, 0);
+       memset(p->code, 0, BM_PACKET_VLI_BYTES_MAX);
+       /* plain bits covered in this code string */
+       plain_bits = 0;
+
+       /* p->encoding & 0x80 stores whether the first run length is set.
+        * bit offset is implicit.
+        * start with toggle == 2 to be able to tell the first iteration */
+       toggle = 2;
+
+       /* see how much plain bits we can stuff into one packet
+        * using RLE and VLI. */
+       do {
+               tmp = (toggle == 0) ? _drbd_bm_find_next_zero(mdev, c->bit_offset)
+                                   : _drbd_bm_find_next(mdev, c->bit_offset);
+               if (tmp == -1UL)
+                       tmp = c->bm_bits;
+               rl = tmp - c->bit_offset;
+
+               if (toggle == 2) { /* first iteration */
+                       if (rl == 0) {
+                               /* the first checked bit was set,
+                                * store start value, */
+                               DCBP_set_start(p, 1);
+                               /* but skip encoding of zero run length */
+                               toggle = !toggle;
+                               continue;
+                       }
+                       DCBP_set_start(p, 0);
+               }
+
+               /* paranoia: catch zero runlength.
+                * can only happen if bitmap is modified while we scan it. */
+               if (rl == 0) {
+                       dev_err(DEV, "unexpected zero runlength while encoding bitmap "
+                           "t:%u bo:%lu\n", toggle, c->bit_offset);
+                       return -1;
+               }
+
+               bits = vli_encode_bits(&bs, rl);
+               if (bits == -ENOBUFS) /* buffer full */
+                       break;
+               if (bits <= 0) {
+                       dev_err(DEV, "error while encoding bitmap: %d\n", bits);
+                       return 0;
+               }
+
+               toggle = !toggle;
+               plain_bits += rl;
+               c->bit_offset = tmp;
+       } while (c->bit_offset < c->bm_bits);
+
+       len = bs.cur.b - p->code + !!bs.cur.bit;
+
+       if (plain_bits < (len << 3)) {
+               /* incompressible with this method.
+                * we need to rewind both word and bit position. */
+               c->bit_offset -= plain_bits;
+               bm_xfer_ctx_bit_to_word_offset(c);
+               c->bit_offset = c->word_offset * BITS_PER_LONG;
+               return 0;
+       }
+
+       /* RLE + VLI was able to compress it just fine.
+        * update c->word_offset. */
+       bm_xfer_ctx_bit_to_word_offset(c);
+
+       /* store pad_bits */
+       DCBP_set_pad_bits(p, (8 - bs.cur.bit) & 0x7);
+
+       return len;
+}
+
+enum { OK, FAILED, DONE }
+send_bitmap_rle_or_plain(struct drbd_conf *mdev,
+       struct p_header *h, struct bm_xfer_ctx *c)
+{
+       struct p_compressed_bm *p = (void*)h;
+       unsigned long num_words;
+       int len;
+       int ok;
+
+       len = fill_bitmap_rle_bits(mdev, p, c);
+
+       if (len < 0)
+               return FAILED;
+
+       if (len) {
+               DCBP_set_code(p, RLE_VLI_Bits);
+               ok = _drbd_send_cmd(mdev, mdev->data.socket, P_COMPRESSED_BITMAP, h,
+                       sizeof(*p) + len, 0);
+
+               c->packets[0]++;
+               c->bytes[0] += sizeof(*p) + len;
+
+               if (c->bit_offset >= c->bm_bits)
+                       len = 0; /* DONE */
+       } else {
+               /* was not compressible.
+                * send a buffer full of plain text bits instead. */
+               num_words = min_t(size_t, BM_PACKET_WORDS, c->bm_words - c->word_offset);
+               len = num_words * sizeof(long);
+               if (len)
+                       drbd_bm_get_lel(mdev, c->word_offset, num_words, (unsigned long*)h->payload);
+               ok = _drbd_send_cmd(mdev, mdev->data.socket, P_BITMAP,
+                                  h, sizeof(struct p_header) + len, 0);
+               c->word_offset += num_words;
+               c->bit_offset = c->word_offset * BITS_PER_LONG;
+
+               c->packets[1]++;
+               c->bytes[1] += sizeof(struct p_header) + len;
+
+               if (c->bit_offset > c->bm_bits)
+                       c->bit_offset = c->bm_bits;
+       }
+       ok = ok ? ((len == 0) ? DONE : OK) : FAILED;
+
+       if (ok == DONE)
+               INFO_bm_xfer_stats(mdev, "send", c);
+       return ok;
+}
+
+/* See the comment at receive_bitmap() */
+int _drbd_send_bitmap(struct drbd_conf *mdev)
+{
+       struct bm_xfer_ctx c;
+       struct p_header *p;
+       int ret;
+
+       ERR_IF(!mdev->bitmap) return FALSE;
+
+       /* maybe we should use some per thread scratch page,
+        * and allocate that during initial device creation? */
+       p = (struct p_header *) __get_free_page(GFP_NOIO);
+       if (!p) {
+               dev_err(DEV, "failed to allocate one page buffer in %s\n", __func__);
+               return FALSE;
+       }
+
+       if (get_ldev(mdev)) {
+               if (drbd_md_test_flag(mdev->ldev, MDF_FULL_SYNC)) {
+                       dev_info(DEV, "Writing the whole bitmap, MDF_FullSync was set.\n");
+                       drbd_bm_set_all(mdev);
+                       if (drbd_bm_write(mdev)) {
+                               /* write_bm did fail! Leave full sync flag set in Meta P_DATA
+                                * but otherwise process as per normal - need to tell other
+                                * side that a full resync is required! */
+                               dev_err(DEV, "Failed to write bitmap to disk!\n");
+                       } else {
+                               drbd_md_clear_flag(mdev, MDF_FULL_SYNC);
+                               drbd_md_sync(mdev);
+                       }
+               }
+               put_ldev(mdev);
+       }
+
+       c = (struct bm_xfer_ctx) {
+               .bm_bits = drbd_bm_bits(mdev),
+               .bm_words = drbd_bm_words(mdev),
+       };
+
+       do {
+               ret = send_bitmap_rle_or_plain(mdev, p, &c);
+       } while (ret == OK);
+
+       free_page((unsigned long) p);
+       return (ret == DONE);
+}
+
+int drbd_send_bitmap(struct drbd_conf *mdev)
+{
+       int err;
+
+       if (!drbd_get_data_sock(mdev))
+               return -1;
+       err = !_drbd_send_bitmap(mdev);
+       drbd_put_data_sock(mdev);
+       return err;
+}
+
+int drbd_send_b_ack(struct drbd_conf *mdev, u32 barrier_nr, u32 set_size)
+{
+       int ok;
+       struct p_barrier_ack p;
+
+       p.barrier  = barrier_nr;
+       p.set_size = cpu_to_be32(set_size);
+
+       if (mdev->state.conn < C_CONNECTED)
+               return FALSE;
+       ok = drbd_send_cmd(mdev, USE_META_SOCKET, P_BARRIER_ACK,
+                       (struct p_header *)&p, sizeof(p));
+       return ok;
+}
+
+/**
+ * _drbd_send_ack() - Sends an ack packet
+ * @mdev:      DRBD device.
+ * @cmd:       Packet command code.
+ * @sector:    sector, needs to be in big endian byte order
+ * @blksize:   size in byte, needs to be in big endian byte order
+ * @block_id:  Id, big endian byte order
+ */
+static int _drbd_send_ack(struct drbd_conf *mdev, enum drbd_packets cmd,
+                         u64 sector,
+                         u32 blksize,
+                         u64 block_id)
+{
+       int ok;
+       struct p_block_ack p;
+
+       p.sector   = sector;
+       p.block_id = block_id;
+       p.blksize  = blksize;
+       p.seq_num  = cpu_to_be32(atomic_add_return(1, &mdev->packet_seq));
+
+       if (!mdev->meta.socket || mdev->state.conn < C_CONNECTED)
+               return FALSE;
+       ok = drbd_send_cmd(mdev, USE_META_SOCKET, cmd,
+                               (struct p_header *)&p, sizeof(p));
+       return ok;
+}
+
+int drbd_send_ack_dp(struct drbd_conf *mdev, enum drbd_packets cmd,
+                    struct p_data *dp)
+{
+       const int header_size = sizeof(struct p_data)
+                             - sizeof(struct p_header);
+       int data_size  = ((struct p_header *)dp)->length - header_size;
+
+       return _drbd_send_ack(mdev, cmd, dp->sector, cpu_to_be32(data_size),
+                             dp->block_id);
+}
+
+int drbd_send_ack_rp(struct drbd_conf *mdev, enum drbd_packets cmd,
+                    struct p_block_req *rp)
+{
+       return _drbd_send_ack(mdev, cmd, rp->sector, rp->blksize, rp->block_id);
+}
+
+/**
+ * drbd_send_ack() - Sends an ack packet
+ * @mdev:      DRBD device.
+ * @cmd:       Packet command code.
+ * @e:         Epoch entry.
+ */
+int drbd_send_ack(struct drbd_conf *mdev,
+       enum drbd_packets cmd, struct drbd_epoch_entry *e)
+{
+       return _drbd_send_ack(mdev, cmd,
+                             cpu_to_be64(e->sector),
+                             cpu_to_be32(e->size),
+                             e->block_id);
+}
+
+/* This function misuses the block_id field to signal if the blocks
+ * are is sync or not. */
+int drbd_send_ack_ex(struct drbd_conf *mdev, enum drbd_packets cmd,
+                    sector_t sector, int blksize, u64 block_id)
+{
+       return _drbd_send_ack(mdev, cmd,
+                             cpu_to_be64(sector),
+                             cpu_to_be32(blksize),
+                             cpu_to_be64(block_id));
+}
+
+int drbd_send_drequest(struct drbd_conf *mdev, int cmd,
+                      sector_t sector, int size, u64 block_id)
+{
+       int ok;
+       struct p_block_req p;
+
+       p.sector   = cpu_to_be64(sector);
+       p.block_id = block_id;
+       p.blksize  = cpu_to_be32(size);
+
+       ok = drbd_send_cmd(mdev, USE_DATA_SOCKET, cmd,
+                               (struct p_header *)&p, sizeof(p));
+       return ok;
+}
+
+int drbd_send_drequest_csum(struct drbd_conf *mdev,
+                           sector_t sector, int size,
+                           void *digest, int digest_size,
+                           enum drbd_packets cmd)
+{
+       int ok;
+       struct p_block_req p;
+
+       p.sector   = cpu_to_be64(sector);
+       p.block_id = BE_DRBD_MAGIC + 0xbeef;
+       p.blksize  = cpu_to_be32(size);
+
+       p.head.magic   = BE_DRBD_MAGIC;
+       p.head.command = cpu_to_be16(cmd);
+       p.head.length  = cpu_to_be16(sizeof(p) - sizeof(struct p_header) + digest_size);
+
+       mutex_lock(&mdev->data.mutex);
+
+       ok = (sizeof(p) == drbd_send(mdev, mdev->data.socket, &p, sizeof(p), 0));
+       ok = ok && (digest_size == drbd_send(mdev, mdev->data.socket, digest, digest_size, 0));
+
+       mutex_unlock(&mdev->data.mutex);
+
+       return ok;
+}
+
+int drbd_send_ov_request(struct drbd_conf *mdev, sector_t sector, int size)
+{
+       int ok;
+       struct p_block_req p;
+
+       p.sector   = cpu_to_be64(sector);
+       p.block_id = BE_DRBD_MAGIC + 0xbabe;
+       p.blksize  = cpu_to_be32(size);
+
+       ok = drbd_send_cmd(mdev, USE_DATA_SOCKET, P_OV_REQUEST,
+                          (struct p_header *)&p, sizeof(p));
+       return ok;
+}
+
+/* called on sndtimeo
+ * returns FALSE if we should retry,
+ * TRUE if we think connection is dead
+ */
+static int we_should_drop_the_connection(struct drbd_conf *mdev, struct socket *sock)
+{
+       int drop_it;
+       /* long elapsed = (long)(jiffies - mdev->last_received); */
+
+       drop_it =   mdev->meta.socket == sock
+               || !mdev->asender.task
+               || get_t_state(&mdev->asender) != Running
+               || mdev->state.conn < C_CONNECTED;
+
+       if (drop_it)
+               return TRUE;
+
+       drop_it = !--mdev->ko_count;
+       if (!drop_it) {
+               dev_err(DEV, "[%s/%d] sock_sendmsg time expired, ko = %u\n",
+                      current->comm, current->pid, mdev->ko_count);
+               request_ping(mdev);
+       }
+
+       return drop_it; /* && (mdev->state == R_PRIMARY) */;
+}
+
+/* The idea of sendpage seems to be to put some kind of reference
+ * to the page into the skb, and to hand it over to the NIC. In
+ * this process get_page() gets called.
+ *
+ * As soon as the page was really sent over the network put_page()
+ * gets called by some part of the network layer. [ NIC driver? ]
+ *
+ * [ get_page() / put_page() increment/decrement the count. If count
+ *   reaches 0 the page will be freed. ]
+ *
+ * This works nicely with pages from FSs.
+ * But this means that in protocol A we might signal IO completion too early!
+ *
+ * In order not to corrupt data during a resync we must make sure
+ * that we do not reuse our own buffer pages (EEs) to early, therefore
+ * we have the net_ee list.
+ *
+ * XFS seems to have problems, still, it submits pages with page_count == 0!
+ * As a workaround, we disable sendpage on pages
+ * with page_count == 0 or PageSlab.
+ */
+static int _drbd_no_send_page(struct drbd_conf *mdev, struct page *page,
+                  int offset, size_t size)
+{
+       int sent = drbd_send(mdev, mdev->data.socket, kmap(page) + offset, size, 0);
+       kunmap(page);
+       if (sent == size)
+               mdev->send_cnt += size>>9;
+       return sent == size;
+}
+
+static int _drbd_send_page(struct drbd_conf *mdev, struct page *page,
+                   int offset, size_t size)
+{
+       mm_segment_t oldfs = get_fs();
+       int sent, ok;
+       int len = size;
+
+       /* e.g. XFS meta- & log-data is in slab pages, which have a
+        * page_count of 0 and/or have PageSlab() set.
+        * we cannot use send_page for those, as that does get_page();
+        * put_page(); and would cause either a VM_BUG directly, or
+        * __page_cache_release a page that would actually still be referenced
+        * by someone, leading to some obscure delayed Oops somewhere else. */
+       if (disable_sendpage || (page_count(page) < 1) || PageSlab(page))
+               return _drbd_no_send_page(mdev, page, offset, size);
+
+       drbd_update_congested(mdev);
+       set_fs(KERNEL_DS);
+       do {
+               sent = mdev->data.socket->ops->sendpage(mdev->data.socket, page,
+                                                       offset, len,
+                                                       MSG_NOSIGNAL);
+               if (sent == -EAGAIN) {
+                       if (we_should_drop_the_connection(mdev,
+                                                         mdev->data.socket))
+                               break;
+                       else
+                               continue;
+               }
+               if (sent <= 0) {
+                       dev_warn(DEV, "%s: size=%d len=%d sent=%d\n",
+                            __func__, (int)size, len, sent);
+                       break;
+               }
+               len    -= sent;
+               offset += sent;
+       } while (len > 0 /* THINK && mdev->cstate >= C_CONNECTED*/);
+       set_fs(oldfs);
+       clear_bit(NET_CONGESTED, &mdev->flags);
+
+       ok = (len == 0);
+       if (likely(ok))
+               mdev->send_cnt += size>>9;
+       return ok;
+}
+
+static int _drbd_send_bio(struct drbd_conf *mdev, struct bio *bio)
+{
+       struct bio_vec *bvec;
+       int i;
+       __bio_for_each_segment(bvec, bio, i, 0) {
+               if (!_drbd_no_send_page(mdev, bvec->bv_page,
+                                    bvec->bv_offset, bvec->bv_len))
+                       return 0;
+       }
+       return 1;
+}
+
+static int _drbd_send_zc_bio(struct drbd_conf *mdev, struct bio *bio)
+{
+       struct bio_vec *bvec;
+       int i;
+       __bio_for_each_segment(bvec, bio, i, 0) {
+               if (!_drbd_send_page(mdev, bvec->bv_page,
+                                    bvec->bv_offset, bvec->bv_len))
+                       return 0;
+       }
+
+       return 1;
+}
+
+/* Used to send write requests
+ * R_PRIMARY -> Peer   (P_DATA)
+ */
+int drbd_send_dblock(struct drbd_conf *mdev, struct drbd_request *req)
+{
+       int ok = 1;
+       struct p_data p;
+       unsigned int dp_flags = 0;
+       void *dgb;
+       int dgs;
+
+       if (!drbd_get_data_sock(mdev))
+               return 0;
+
+       dgs = (mdev->agreed_pro_version >= 87 && mdev->integrity_w_tfm) ?
+               crypto_hash_digestsize(mdev->integrity_w_tfm) : 0;
+
+       p.head.magic   = BE_DRBD_MAGIC;
+       p.head.command = cpu_to_be16(P_DATA);
+       p.head.length  =
+               cpu_to_be16(sizeof(p) - sizeof(struct p_header) + dgs + req->size);
+
+       p.sector   = cpu_to_be64(req->sector);
+       p.block_id = (unsigned long)req;
+       p.seq_num  = cpu_to_be32(req->seq_num =
+                                atomic_add_return(1, &mdev->packet_seq));
+       dp_flags = 0;
+
+       /* NOTE: no need to check if barriers supported here as we would
+        *       not pass the test in make_request_common in that case
+        */
+       if (bio_rw_flagged(req->master_bio, BIO_RW_BARRIER)) {
+               dev_err(DEV, "ASSERT FAILED would have set DP_HARDBARRIER\n");
+               /* dp_flags |= DP_HARDBARRIER; */
+       }
+       if (bio_rw_flagged(req->master_bio, BIO_RW_SYNCIO))
+               dp_flags |= DP_RW_SYNC;
+       /* for now handle SYNCIO and UNPLUG
+        * as if they still were one and the same flag */
+       if (bio_rw_flagged(req->master_bio, BIO_RW_UNPLUG))
+               dp_flags |= DP_RW_SYNC;
+       if (mdev->state.conn >= C_SYNC_SOURCE &&
+           mdev->state.conn <= C_PAUSED_SYNC_T)
+               dp_flags |= DP_MAY_SET_IN_SYNC;
+
+       p.dp_flags = cpu_to_be32(dp_flags);
+       set_bit(UNPLUG_REMOTE, &mdev->flags);
+       ok = (sizeof(p) ==
+               drbd_send(mdev, mdev->data.socket, &p, sizeof(p), MSG_MORE));
+       if (ok && dgs) {
+               dgb = mdev->int_dig_out;
+               drbd_csum(mdev, mdev->integrity_w_tfm, req->master_bio, dgb);
+               ok = drbd_send(mdev, mdev->data.socket, dgb, dgs, MSG_MORE);
+       }
+       if (ok) {
+               if (mdev->net_conf->wire_protocol == DRBD_PROT_A)
+                       ok = _drbd_send_bio(mdev, req->master_bio);
+               else
+                       ok = _drbd_send_zc_bio(mdev, req->master_bio);
+       }
+
+       drbd_put_data_sock(mdev);
+       return ok;
+}
+
+/* answer packet, used to send data back for read requests:
+ *  Peer       -> (diskless) R_PRIMARY   (P_DATA_REPLY)
+ *  C_SYNC_SOURCE -> C_SYNC_TARGET         (P_RS_DATA_REPLY)
+ */
+int drbd_send_block(struct drbd_conf *mdev, enum drbd_packets cmd,
+                   struct drbd_epoch_entry *e)
+{
+       int ok;
+       struct p_data p;
+       void *dgb;
+       int dgs;
+
+       dgs = (mdev->agreed_pro_version >= 87 && mdev->integrity_w_tfm) ?
+               crypto_hash_digestsize(mdev->integrity_w_tfm) : 0;
+
+       p.head.magic   = BE_DRBD_MAGIC;
+       p.head.command = cpu_to_be16(cmd);
+       p.head.length  =
+               cpu_to_be16(sizeof(p) - sizeof(struct p_header) + dgs + e->size);
+
+       p.sector   = cpu_to_be64(e->sector);
+       p.block_id = e->block_id;
+       /* p.seq_num  = 0;    No sequence numbers here.. */
+
+       /* Only called by our kernel thread.
+        * This one may be interrupted by DRBD_SIG and/or DRBD_SIGKILL
+        * in response to admin command or module unload.
+        */
+       if (!drbd_get_data_sock(mdev))
+               return 0;
+
+       ok = sizeof(p) == drbd_send(mdev, mdev->data.socket, &p,
+                                       sizeof(p), MSG_MORE);
+       if (ok && dgs) {
+               dgb = mdev->int_dig_out;
+               drbd_csum(mdev, mdev->integrity_w_tfm, e->private_bio, dgb);
+               ok = drbd_send(mdev, mdev->data.socket, dgb, dgs, MSG_MORE);
+       }
+       if (ok)
+               ok = _drbd_send_zc_bio(mdev, e->private_bio);
+
+       drbd_put_data_sock(mdev);
+       return ok;
+}
+
+/*
+  drbd_send distinguishes two cases:
+
+  Packets sent via the data socket "sock"
+  and packets sent via the meta data socket "msock"
+
+                   sock                      msock
+  -----------------+-------------------------+------------------------------
+  timeout           conf.timeout / 2          conf.timeout / 2
+  timeout action    send a ping via msock     Abort communication
+                                             and close all sockets
+*/
+
+/*
+ * you must have down()ed the appropriate [m]sock_mutex elsewhere!
+ */
+int drbd_send(struct drbd_conf *mdev, struct socket *sock,
+             void *buf, size_t size, unsigned msg_flags)
+{
+       struct kvec iov;
+       struct msghdr msg;
+       int rv, sent = 0;
+
+       if (!sock)
+               return -1000;
+
+       /* THINK  if (signal_pending) return ... ? */
+
+       iov.iov_base = buf;
+       iov.iov_len  = size;
+
+       msg.msg_name       = NULL;
+       msg.msg_namelen    = 0;
+       msg.msg_control    = NULL;
+       msg.msg_controllen = 0;
+       msg.msg_flags      = msg_flags | MSG_NOSIGNAL;
+
+       if (sock == mdev->data.socket) {
+               mdev->ko_count = mdev->net_conf->ko_count;
+               drbd_update_congested(mdev);
+       }
+       do {
+               /* STRANGE
+                * tcp_sendmsg does _not_ use its size parameter at all ?
+                *
+                * -EAGAIN on timeout, -EINTR on signal.
+                */
+/* THINK
+ * do we need to block DRBD_SIG if sock == &meta.socket ??
+ * otherwise wake_asender() might interrupt some send_*Ack !
+ */
+               rv = kernel_sendmsg(sock, &msg, &iov, 1, size);
+               if (rv == -EAGAIN) {
+                       if (we_should_drop_the_connection(mdev, sock))
+                               break;
+                       else
+                               continue;
+               }
+               D_ASSERT(rv != 0);
+               if (rv == -EINTR) {
+                       flush_signals(current);
+                       rv = 0;
+               }
+               if (rv < 0)
+                       break;
+               sent += rv;
+               iov.iov_base += rv;
+               iov.iov_len  -= rv;
+       } while (sent < size);
+
+       if (sock == mdev->data.socket)
+               clear_bit(NET_CONGESTED, &mdev->flags);
+
+       if (rv <= 0) {
+               if (rv != -EAGAIN) {
+                       dev_err(DEV, "%s_sendmsg returned %d\n",
+                           sock == mdev->meta.socket ? "msock" : "sock",
+                           rv);
+                       drbd_force_state(mdev, NS(conn, C_BROKEN_PIPE));
+               } else
+                       drbd_force_state(mdev, NS(conn, C_TIMEOUT));
+       }
+
+       return sent;
+}
+
+static int drbd_open(struct block_device *bdev, fmode_t mode)
+{
+       struct drbd_conf *mdev = bdev->bd_disk->private_data;
+       unsigned long flags;
+       int rv = 0;
+
+       spin_lock_irqsave(&mdev->req_lock, flags);
+       /* to have a stable mdev->state.role
+        * and no race with updating open_cnt */
+
+       if (mdev->state.role != R_PRIMARY) {
+               if (mode & FMODE_WRITE)
+                       rv = -EROFS;
+               else if (!allow_oos)
+                       rv = -EMEDIUMTYPE;
+       }
+
+       if (!rv)
+               mdev->open_cnt++;
+       spin_unlock_irqrestore(&mdev->req_lock, flags);
+
+       return rv;
+}
+
+static int drbd_release(struct gendisk *gd, fmode_t mode)
+{
+       struct drbd_conf *mdev = gd->private_data;
+       mdev->open_cnt--;
+       return 0;
+}
+
+static void drbd_unplug_fn(struct request_queue *q)
+{
+       struct drbd_conf *mdev = q->queuedata;
+
+       /* unplug FIRST */
+       spin_lock_irq(q->queue_lock);
+       blk_remove_plug(q);
+       spin_unlock_irq(q->queue_lock);
+
+       /* only if connected */
+       spin_lock_irq(&mdev->req_lock);
+       if (mdev->state.pdsk >= D_INCONSISTENT && mdev->state.conn >= C_CONNECTED) {
+               D_ASSERT(mdev->state.role == R_PRIMARY);
+               if (test_and_clear_bit(UNPLUG_REMOTE, &mdev->flags)) {
+                       /* add to the data.work queue,
+                        * unless already queued.
+                        * XXX this might be a good addition to drbd_queue_work
+                        * anyways, to detect "double queuing" ... */
+                       if (list_empty(&mdev->unplug_work.list))
+                               drbd_queue_work(&mdev->data.work,
+                                               &mdev->unplug_work);
+               }
+       }
+       spin_unlock_irq(&mdev->req_lock);
+
+       if (mdev->state.disk >= D_INCONSISTENT)
+               drbd_kick_lo(mdev);
+}
+
+static void drbd_set_defaults(struct drbd_conf *mdev)
+{
+       mdev->sync_conf.after      = DRBD_AFTER_DEF;
+       mdev->sync_conf.rate       = DRBD_RATE_DEF;
+       mdev->sync_conf.al_extents = DRBD_AL_EXTENTS_DEF;
+       mdev->state = (union drbd_state) {
+               { .role = R_SECONDARY,
+                 .peer = R_UNKNOWN,
+                 .conn = C_STANDALONE,
+                 .disk = D_DISKLESS,
+                 .pdsk = D_UNKNOWN,
+                 .susp = 0
+               } };
+}
+
+void drbd_init_set_defaults(struct drbd_conf *mdev)
+{
+       /* the memset(,0,) did most of this.
+        * note: only assignments, no allocation in here */
+
+       drbd_set_defaults(mdev);
+
+       /* for now, we do NOT yet support it,
+        * even though we start some framework
+        * to eventually support barriers */
+       set_bit(NO_BARRIER_SUPP, &mdev->flags);
+
+       atomic_set(&mdev->ap_bio_cnt, 0);
+       atomic_set(&mdev->ap_pending_cnt, 0);
+       atomic_set(&mdev->rs_pending_cnt, 0);
+       atomic_set(&mdev->unacked_cnt, 0);
+       atomic_set(&mdev->local_cnt, 0);
+       atomic_set(&mdev->net_cnt, 0);
+       atomic_set(&mdev->packet_seq, 0);
+       atomic_set(&mdev->pp_in_use, 0);
+
+       mutex_init(&mdev->md_io_mutex);
+       mutex_init(&mdev->data.mutex);
+       mutex_init(&mdev->meta.mutex);
+       sema_init(&mdev->data.work.s, 0);
+       sema_init(&mdev->meta.work.s, 0);
+       mutex_init(&mdev->state_mutex);
+
+       spin_lock_init(&mdev->data.work.q_lock);
+       spin_lock_init(&mdev->meta.work.q_lock);
+
+       spin_lock_init(&mdev->al_lock);
+       spin_lock_init(&mdev->req_lock);
+       spin_lock_init(&mdev->peer_seq_lock);
+       spin_lock_init(&mdev->epoch_lock);
+
+       INIT_LIST_HEAD(&mdev->active_ee);
+       INIT_LIST_HEAD(&mdev->sync_ee);
+       INIT_LIST_HEAD(&mdev->done_ee);
+       INIT_LIST_HEAD(&mdev->read_ee);
+       INIT_LIST_HEAD(&mdev->net_ee);
+       INIT_LIST_HEAD(&mdev->resync_reads);
+       INIT_LIST_HEAD(&mdev->data.work.q);
+       INIT_LIST_HEAD(&mdev->meta.work.q);
+       INIT_LIST_HEAD(&mdev->resync_work.list);
+       INIT_LIST_HEAD(&mdev->unplug_work.list);
+       INIT_LIST_HEAD(&mdev->md_sync_work.list);
+       INIT_LIST_HEAD(&mdev->bm_io_work.w.list);
+       mdev->resync_work.cb  = w_resync_inactive;
+       mdev->unplug_work.cb  = w_send_write_hint;
+       mdev->md_sync_work.cb = w_md_sync;
+       mdev->bm_io_work.w.cb = w_bitmap_io;
+       init_timer(&mdev->resync_timer);
+       init_timer(&mdev->md_sync_timer);
+       mdev->resync_timer.function = resync_timer_fn;
+       mdev->resync_timer.data = (unsigned long) mdev;
+       mdev->md_sync_timer.function = md_sync_timer_fn;
+       mdev->md_sync_timer.data = (unsigned long) mdev;
+
+       init_waitqueue_head(&mdev->misc_wait);
+       init_waitqueue_head(&mdev->state_wait);
+       init_waitqueue_head(&mdev->ee_wait);
+       init_waitqueue_head(&mdev->al_wait);
+       init_waitqueue_head(&mdev->seq_wait);
+
+       drbd_thread_init(mdev, &mdev->receiver, drbdd_init);
+       drbd_thread_init(mdev, &mdev->worker, drbd_worker);
+       drbd_thread_init(mdev, &mdev->asender, drbd_asender);
+
+       mdev->agreed_pro_version = PRO_VERSION_MAX;
+       mdev->write_ordering = WO_bio_barrier;
+       mdev->resync_wenr = LC_FREE;
+}
+
+void drbd_mdev_cleanup(struct drbd_conf *mdev)
+{
+       if (mdev->receiver.t_state != None)
+               dev_err(DEV, "ASSERT FAILED: receiver t_state == %d expected 0.\n",
+                               mdev->receiver.t_state);
+
+       /* no need to lock it, I'm the only thread alive */
+       if (atomic_read(&mdev->current_epoch->epoch_size) !=  0)
+               dev_err(DEV, "epoch_size:%d\n", atomic_read(&mdev->current_epoch->epoch_size));
+       mdev->al_writ_cnt  =
+       mdev->bm_writ_cnt  =
+       mdev->read_cnt     =
+       mdev->recv_cnt     =
+       mdev->send_cnt     =
+       mdev->writ_cnt     =
+       mdev->p_size       =
+       mdev->rs_start     =
+       mdev->rs_total     =
+       mdev->rs_failed    =
+       mdev->rs_mark_left =
+       mdev->rs_mark_time = 0;
+       D_ASSERT(mdev->net_conf == NULL);
+
+       drbd_set_my_capacity(mdev, 0);
+       if (mdev->bitmap) {
+               /* maybe never allocated. */
+               drbd_bm_resize(mdev, 0);
+               drbd_bm_cleanup(mdev);
+       }
+
+       drbd_free_resources(mdev);
+
+       /*
+        * currently we drbd_init_ee only on module load, so
+        * we may do drbd_release_ee only on module unload!
+        */
+       D_ASSERT(list_empty(&mdev->active_ee));
+       D_ASSERT(list_empty(&mdev->sync_ee));
+       D_ASSERT(list_empty(&mdev->done_ee));
+       D_ASSERT(list_empty(&mdev->read_ee));
+       D_ASSERT(list_empty(&mdev->net_ee));
+       D_ASSERT(list_empty(&mdev->resync_reads));
+       D_ASSERT(list_empty(&mdev->data.work.q));
+       D_ASSERT(list_empty(&mdev->meta.work.q));
+       D_ASSERT(list_empty(&mdev->resync_work.list));
+       D_ASSERT(list_empty(&mdev->unplug_work.list));
+
+}
+
+
+static void drbd_destroy_mempools(void)
+{
+       struct page *page;
+
+       while (drbd_pp_pool) {
+               page = drbd_pp_pool;
+               drbd_pp_pool = (struct page *)page_private(page);
+               __free_page(page);
+               drbd_pp_vacant--;
+       }
+
+       /* D_ASSERT(atomic_read(&drbd_pp_vacant)==0); */
+
+       if (drbd_ee_mempool)
+               mempool_destroy(drbd_ee_mempool);
+       if (drbd_request_mempool)
+               mempool_destroy(drbd_request_mempool);
+       if (drbd_ee_cache)
+               kmem_cache_destroy(drbd_ee_cache);
+       if (drbd_request_cache)
+               kmem_cache_destroy(drbd_request_cache);
+       if (drbd_bm_ext_cache)
+               kmem_cache_destroy(drbd_bm_ext_cache);
+       if (drbd_al_ext_cache)
+               kmem_cache_destroy(drbd_al_ext_cache);
+
+       drbd_ee_mempool      = NULL;
+       drbd_request_mempool = NULL;
+       drbd_ee_cache        = NULL;
+       drbd_request_cache   = NULL;
+       drbd_bm_ext_cache    = NULL;
+       drbd_al_ext_cache    = NULL;
+
+       return;
+}
+
+static int drbd_create_mempools(void)
+{
+       struct page *page;
+       const int number = (DRBD_MAX_SEGMENT_SIZE/PAGE_SIZE) * minor_count;
+       int i;
+
+       /* prepare our caches and mempools */
+       drbd_request_mempool = NULL;
+       drbd_ee_cache        = NULL;
+       drbd_request_cache   = NULL;
+       drbd_bm_ext_cache    = NULL;
+       drbd_al_ext_cache    = NULL;
+       drbd_pp_pool         = NULL;
+
+       /* caches */
+       drbd_request_cache = kmem_cache_create(
+               "drbd_req", sizeof(struct drbd_request), 0, 0, NULL);
+       if (drbd_request_cache == NULL)
+               goto Enomem;
+
+       drbd_ee_cache = kmem_cache_create(
+               "drbd_ee", sizeof(struct drbd_epoch_entry), 0, 0, NULL);
+       if (drbd_ee_cache == NULL)
+               goto Enomem;
+
+       drbd_bm_ext_cache = kmem_cache_create(
+               "drbd_bm", sizeof(struct bm_extent), 0, 0, NULL);
+       if (drbd_bm_ext_cache == NULL)
+               goto Enomem;
+
+       drbd_al_ext_cache = kmem_cache_create(
+               "drbd_al", sizeof(struct lc_element), 0, 0, NULL);
+       if (drbd_al_ext_cache == NULL)
+               goto Enomem;
+
+       /* mempools */
+       drbd_request_mempool = mempool_create(number,
+               mempool_alloc_slab, mempool_free_slab, drbd_request_cache);
+       if (drbd_request_mempool == NULL)
+               goto Enomem;
+
+       drbd_ee_mempool = mempool_create(number,
+               mempool_alloc_slab, mempool_free_slab, drbd_ee_cache);
+       if (drbd_request_mempool == NULL)
+               goto Enomem;
+
+       /* drbd's page pool */
+       spin_lock_init(&drbd_pp_lock);
+
+       for (i = 0; i < number; i++) {
+               page = alloc_page(GFP_HIGHUSER);
+               if (!page)
+                       goto Enomem;
+               set_page_private(page, (unsigned long)drbd_pp_pool);
+               drbd_pp_pool = page;
+       }
+       drbd_pp_vacant = number;
+
+       return 0;
+
+Enomem:
+       drbd_destroy_mempools(); /* in case we allocated some */
+       return -ENOMEM;
+}
+
+static int drbd_notify_sys(struct notifier_block *this, unsigned long code,
+       void *unused)
+{
+       /* just so we have it.  you never know what interesting things we
+        * might want to do here some day...
+        */
+
+       return NOTIFY_DONE;
+}
+
+static struct notifier_block drbd_notifier = {
+       .notifier_call = drbd_notify_sys,
+};
+
+static void drbd_release_ee_lists(struct drbd_conf *mdev)
+{
+       int rr;
+
+       rr = drbd_release_ee(mdev, &mdev->active_ee);
+       if (rr)
+               dev_err(DEV, "%d EEs in active list found!\n", rr);
+
+       rr = drbd_release_ee(mdev, &mdev->sync_ee);
+       if (rr)
+               dev_err(DEV, "%d EEs in sync list found!\n", rr);
+
+       rr = drbd_release_ee(mdev, &mdev->read_ee);
+       if (rr)
+               dev_err(DEV, "%d EEs in read list found!\n", rr);
+
+       rr = drbd_release_ee(mdev, &mdev->done_ee);
+       if (rr)
+               dev_err(DEV, "%d EEs in done list found!\n", rr);
+
+       rr = drbd_release_ee(mdev, &mdev->net_ee);
+       if (rr)
+               dev_err(DEV, "%d EEs in net list found!\n", rr);
+}
+
+/* caution. no locking.
+ * currently only used from module cleanup code. */
+static void drbd_delete_device(unsigned int minor)
+{
+       struct drbd_conf *mdev = minor_to_mdev(minor);
+
+       if (!mdev)
+               return;
+
+       /* paranoia asserts */
+       if (mdev->open_cnt != 0)
+               dev_err(DEV, "open_cnt = %d in %s:%u", mdev->open_cnt,
+                               __FILE__ , __LINE__);
+
+       ERR_IF (!list_empty(&mdev->data.work.q)) {
+               struct list_head *lp;
+               list_for_each(lp, &mdev->data.work.q) {
+                       dev_err(DEV, "lp = %p\n", lp);
+               }
+       };
+       /* end paranoia asserts */
+
+       del_gendisk(mdev->vdisk);
+
+       /* cleanup stuff that may have been allocated during
+        * device (re-)configuration or state changes */
+
+       if (mdev->this_bdev)
+               bdput(mdev->this_bdev);
+
+       drbd_free_resources(mdev);
+
+       drbd_release_ee_lists(mdev);
+
+       /* should be free'd on disconnect? */
+       kfree(mdev->ee_hash);
+       /*
+       mdev->ee_hash_s = 0;
+       mdev->ee_hash = NULL;
+       */
+
+       lc_destroy(mdev->act_log);
+       lc_destroy(mdev->resync);
+
+       kfree(mdev->p_uuid);
+       /* mdev->p_uuid = NULL; */
+
+       kfree(mdev->int_dig_out);
+       kfree(mdev->int_dig_in);
+       kfree(mdev->int_dig_vv);
+
+       /* cleanup the rest that has been
+        * allocated from drbd_new_device
+        * and actually free the mdev itself */
+       drbd_free_mdev(mdev);
+}
+
+static void drbd_cleanup(void)
+{
+       unsigned int i;
+
+       unregister_reboot_notifier(&drbd_notifier);
+
+       drbd_nl_cleanup();
+
+       if (minor_table) {
+               if (drbd_proc)
+                       remove_proc_entry("drbd", NULL);
+               i = minor_count;
+               while (i--)
+                       drbd_delete_device(i);
+               drbd_destroy_mempools();
+       }
+
+       kfree(minor_table);
+
+       unregister_blkdev(DRBD_MAJOR, "drbd");
+
+       printk(KERN_INFO "drbd: module cleanup done.\n");
+}
+
+/**
+ * drbd_congested() - Callback for pdflush
+ * @congested_data:    User data
+ * @bdi_bits:          Bits pdflush is currently interested in
+ *
+ * Returns 1<<BDI_async_congested and/or 1<<BDI_sync_congested if we are congested.
+ */
+static int drbd_congested(void *congested_data, int bdi_bits)
+{
+       struct drbd_conf *mdev = congested_data;
+       struct request_queue *q;
+       char reason = '-';
+       int r = 0;
+
+       if (!__inc_ap_bio_cond(mdev)) {
+               /* DRBD has frozen IO */
+               r = bdi_bits;
+               reason = 'd';
+               goto out;
+       }
+
+       if (get_ldev(mdev)) {
+               q = bdev_get_queue(mdev->ldev->backing_bdev);
+               r = bdi_congested(&q->backing_dev_info, bdi_bits);
+               put_ldev(mdev);
+               if (r)
+                       reason = 'b';
+       }
+
+       if (bdi_bits & (1 << BDI_async_congested) && test_bit(NET_CONGESTED, &mdev->flags)) {
+               r |= (1 << BDI_async_congested);
+               reason = reason == 'b' ? 'a' : 'n';
+       }
+
+out:
+       mdev->congestion_reason = reason;
+       return r;
+}
+
+struct drbd_conf *drbd_new_device(unsigned int minor)
+{
+       struct drbd_conf *mdev;
+       struct gendisk *disk;
+       struct request_queue *q;
+
+       /* GFP_KERNEL, we are outside of all write-out paths */
+       mdev = kzalloc(sizeof(struct drbd_conf), GFP_KERNEL);
+       if (!mdev)
+               return NULL;
+       if (!zalloc_cpumask_var(&mdev->cpu_mask, GFP_KERNEL))
+               goto out_no_cpumask;
+
+       mdev->minor = minor;
+
+       drbd_init_set_defaults(mdev);
+
+       q = blk_alloc_queue(GFP_KERNEL);
+       if (!q)
+               goto out_no_q;
+       mdev->rq_queue = q;
+       q->queuedata   = mdev;
+       blk_queue_max_segment_size(q, DRBD_MAX_SEGMENT_SIZE);
+
+       disk = alloc_disk(1);
+       if (!disk)
+               goto out_no_disk;
+       mdev->vdisk = disk;
+
+       set_disk_ro(disk, TRUE);
+
+       disk->queue = q;
+       disk->major = DRBD_MAJOR;
+       disk->first_minor = minor;
+       disk->fops = &drbd_ops;
+       sprintf(disk->disk_name, "drbd%d", minor);
+       disk->private_data = mdev;
+
+       mdev->this_bdev = bdget(MKDEV(DRBD_MAJOR, minor));
+       /* we have no partitions. we contain only ourselves. */
+       mdev->this_bdev->bd_contains = mdev->this_bdev;
+
+       q->backing_dev_info.congested_fn = drbd_congested;
+       q->backing_dev_info.congested_data = mdev;
+
+       blk_queue_make_request(q, drbd_make_request_26);
+       blk_queue_bounce_limit(q, BLK_BOUNCE_ANY);
+       blk_queue_merge_bvec(q, drbd_merge_bvec);
+       q->queue_lock = &mdev->req_lock; /* needed since we use */
+               /* plugging on a queue, that actually has no requests! */
+       q->unplug_fn = drbd_unplug_fn;
+
+       mdev->md_io_page = alloc_page(GFP_KERNEL);
+       if (!mdev->md_io_page)
+               goto out_no_io_page;
+
+       if (drbd_bm_init(mdev))
+               goto out_no_bitmap;
+       /* no need to lock access, we are still initializing this minor device. */
+       if (!tl_init(mdev))
+               goto out_no_tl;
+
+       mdev->app_reads_hash = kzalloc(APP_R_HSIZE*sizeof(void *), GFP_KERNEL);
+       if (!mdev->app_reads_hash)
+               goto out_no_app_reads;
+
+       mdev->current_epoch = kzalloc(sizeof(struct drbd_epoch), GFP_KERNEL);
+       if (!mdev->current_epoch)
+               goto out_no_epoch;
+
+       INIT_LIST_HEAD(&mdev->current_epoch->list);
+       mdev->epochs = 1;
+
+       return mdev;
+
+/* out_whatever_else:
+       kfree(mdev->current_epoch); */
+out_no_epoch:
+       kfree(mdev->app_reads_hash);
+out_no_app_reads:
+       tl_cleanup(mdev);
+out_no_tl:
+       drbd_bm_cleanup(mdev);
+out_no_bitmap:
+       __free_page(mdev->md_io_page);
+out_no_io_page:
+       put_disk(disk);
+out_no_disk:
+       blk_cleanup_queue(q);
+out_no_q:
+       free_cpumask_var(mdev->cpu_mask);
+out_no_cpumask:
+       kfree(mdev);
+       return NULL;
+}
+
+/* counterpart of drbd_new_device.
+ * last part of drbd_delete_device. */
+void drbd_free_mdev(struct drbd_conf *mdev)
+{
+       kfree(mdev->current_epoch);
+       kfree(mdev->app_reads_hash);
+       tl_cleanup(mdev);
+       if (mdev->bitmap) /* should no longer be there. */
+               drbd_bm_cleanup(mdev);
+       __free_page(mdev->md_io_page);
+       put_disk(mdev->vdisk);
+       blk_cleanup_queue(mdev->rq_queue);
+       free_cpumask_var(mdev->cpu_mask);
+       kfree(mdev);
+}
+
+
+int __init drbd_init(void)
+{
+       int err;
+
+       if (sizeof(struct p_handshake) != 80) {
+               printk(KERN_ERR
+                      "drbd: never change the size or layout "
+                      "of the HandShake packet.\n");
+               return -EINVAL;
+       }
+
+       if (1 > minor_count || minor_count > 255) {
+               printk(KERN_ERR
+                       "drbd: invalid minor_count (%d)\n", minor_count);
+#ifdef MODULE
+               return -EINVAL;
+#else
+               minor_count = 8;
+#endif
+       }
+
+       err = drbd_nl_init();
+       if (err)
+               return err;
+
+       err = register_blkdev(DRBD_MAJOR, "drbd");
+       if (err) {
+               printk(KERN_ERR
+                      "drbd: unable to register block device major %d\n",
+                      DRBD_MAJOR);
+               return err;
+       }
+
+       register_reboot_notifier(&drbd_notifier);
+
+       /*
+        * allocate all necessary structs
+        */
+       err = -ENOMEM;
+
+       init_waitqueue_head(&drbd_pp_wait);
+
+       drbd_proc = NULL; /* play safe for drbd_cleanup */
+       minor_table = kzalloc(sizeof(struct drbd_conf *)*minor_count,
+                               GFP_KERNEL);
+       if (!minor_table)
+               goto Enomem;
+
+       err = drbd_create_mempools();
+       if (err)
+               goto Enomem;
+
+       drbd_proc = proc_create("drbd", S_IFREG | S_IRUGO , NULL, &drbd_proc_fops);
+       if (!drbd_proc) {
+               printk(KERN_ERR "drbd: unable to register proc file\n");
+               goto Enomem;
+       }
+
+       rwlock_init(&global_state_lock);
+
+       printk(KERN_INFO "drbd: initialized. "
+              "Version: " REL_VERSION " (api:%d/proto:%d-%d)\n",
+              API_VERSION, PRO_VERSION_MIN, PRO_VERSION_MAX);
+       printk(KERN_INFO "drbd: %s\n", drbd_buildtag());
+       printk(KERN_INFO "drbd: registered as block device major %d\n",
+               DRBD_MAJOR);
+       printk(KERN_INFO "drbd: minor_table @ 0x%p\n", minor_table);
+
+       return 0; /* Success! */
+
+Enomem:
+       drbd_cleanup();
+       if (err == -ENOMEM)
+               /* currently always the case */
+               printk(KERN_ERR "drbd: ran out of memory\n");
+       else
+               printk(KERN_ERR "drbd: initialization failure\n");
+       return err;
+}
+
+void drbd_free_bc(struct drbd_backing_dev *ldev)
+{
+       if (ldev == NULL)
+               return;
+
+       bd_release(ldev->backing_bdev);
+       bd_release(ldev->md_bdev);
+
+       fput(ldev->lo_file);
+       fput(ldev->md_file);
+
+       kfree(ldev);
+}
+
+void drbd_free_sock(struct drbd_conf *mdev)
+{
+       if (mdev->data.socket) {
+               kernel_sock_shutdown(mdev->data.socket, SHUT_RDWR);
+               sock_release(mdev->data.socket);
+               mdev->data.socket = NULL;
+       }
+       if (mdev->meta.socket) {
+               kernel_sock_shutdown(mdev->meta.socket, SHUT_RDWR);
+               sock_release(mdev->meta.socket);
+               mdev->meta.socket = NULL;
+       }
+}
+
+
+void drbd_free_resources(struct drbd_conf *mdev)
+{
+       crypto_free_hash(mdev->csums_tfm);
+       mdev->csums_tfm = NULL;
+       crypto_free_hash(mdev->verify_tfm);
+       mdev->verify_tfm = NULL;
+       crypto_free_hash(mdev->cram_hmac_tfm);
+       mdev->cram_hmac_tfm = NULL;
+       crypto_free_hash(mdev->integrity_w_tfm);
+       mdev->integrity_w_tfm = NULL;
+       crypto_free_hash(mdev->integrity_r_tfm);
+       mdev->integrity_r_tfm = NULL;
+
+       drbd_free_sock(mdev);
+
+       __no_warn(local,
+                 drbd_free_bc(mdev->ldev);
+                 mdev->ldev = NULL;);
+}
+
+/* meta data management */
+
+struct meta_data_on_disk {
+       u64 la_size;           /* last agreed size. */
+       u64 uuid[UI_SIZE];   /* UUIDs. */
+       u64 device_uuid;
+       u64 reserved_u64_1;
+       u32 flags;             /* MDF */
+       u32 magic;
+       u32 md_size_sect;
+       u32 al_offset;         /* offset to this block */
+       u32 al_nr_extents;     /* important for restoring the AL */
+             /* `-- act_log->nr_elements <-- sync_conf.al_extents */
+       u32 bm_offset;         /* offset to the bitmap, from here */
+       u32 bm_bytes_per_bit;  /* BM_BLOCK_SIZE */
+       u32 reserved_u32[4];
+
+} __packed;
+
+/**
+ * drbd_md_sync() - Writes the meta data super block if the MD_DIRTY flag bit is set
+ * @mdev:      DRBD device.
+ */
+void drbd_md_sync(struct drbd_conf *mdev)
+{
+       struct meta_data_on_disk *buffer;
+       sector_t sector;
+       int i;
+
+       if (!test_and_clear_bit(MD_DIRTY, &mdev->flags))
+               return;
+       del_timer(&mdev->md_sync_timer);
+
+       /* We use here D_FAILED and not D_ATTACHING because we try to write
+        * metadata even if we detach due to a disk failure! */
+       if (!get_ldev_if_state(mdev, D_FAILED))
+               return;
+
+       mutex_lock(&mdev->md_io_mutex);
+       buffer = (struct meta_data_on_disk *)page_address(mdev->md_io_page);
+       memset(buffer, 0, 512);
+
+       buffer->la_size = cpu_to_be64(drbd_get_capacity(mdev->this_bdev));
+       for (i = UI_CURRENT; i < UI_SIZE; i++)
+               buffer->uuid[i] = cpu_to_be64(mdev->ldev->md.uuid[i]);
+       buffer->flags = cpu_to_be32(mdev->ldev->md.flags);
+       buffer->magic = cpu_to_be32(DRBD_MD_MAGIC);
+
+       buffer->md_size_sect  = cpu_to_be32(mdev->ldev->md.md_size_sect);
+       buffer->al_offset     = cpu_to_be32(mdev->ldev->md.al_offset);
+       buffer->al_nr_extents = cpu_to_be32(mdev->act_log->nr_elements);
+       buffer->bm_bytes_per_bit = cpu_to_be32(BM_BLOCK_SIZE);
+       buffer->device_uuid = cpu_to_be64(mdev->ldev->md.device_uuid);
+
+       buffer->bm_offset = cpu_to_be32(mdev->ldev->md.bm_offset);
+
+       D_ASSERT(drbd_md_ss__(mdev, mdev->ldev) == mdev->ldev->md.md_offset);
+       sector = mdev->ldev->md.md_offset;
+
+       if (drbd_md_sync_page_io(mdev, mdev->ldev, sector, WRITE)) {
+               clear_bit(MD_DIRTY, &mdev->flags);
+       } else {
+               /* this was a try anyways ... */
+               dev_err(DEV, "meta data update failed!\n");
+
+               drbd_chk_io_error(mdev, 1, TRUE);
+       }
+
+       /* Update mdev->ldev->md.la_size_sect,
+        * since we updated it on metadata. */
+       mdev->ldev->md.la_size_sect = drbd_get_capacity(mdev->this_bdev);
+
+       mutex_unlock(&mdev->md_io_mutex);
+       put_ldev(mdev);
+}
+
+/**
+ * drbd_md_read() - Reads in the meta data super block
+ * @mdev:      DRBD device.
+ * @bdev:      Device from which the meta data should be read in.
+ *
+ * Return 0 (NO_ERROR) on success, and an enum drbd_ret_codes in case
+ * something goes wrong.  Currently only: ERR_IO_MD_DISK, ERR_MD_INVALID.
+ */
+int drbd_md_read(struct drbd_conf *mdev, struct drbd_backing_dev *bdev)
+{
+       struct meta_data_on_disk *buffer;
+       int i, rv = NO_ERROR;
+
+       if (!get_ldev_if_state(mdev, D_ATTACHING))
+               return ERR_IO_MD_DISK;
+
+       mutex_lock(&mdev->md_io_mutex);
+       buffer = (struct meta_data_on_disk *)page_address(mdev->md_io_page);
+
+       if (!drbd_md_sync_page_io(mdev, bdev, bdev->md.md_offset, READ)) {
+               /* NOTE: cant do normal error processing here as this is
+                  called BEFORE disk is attached */
+               dev_err(DEV, "Error while reading metadata.\n");
+               rv = ERR_IO_MD_DISK;
+               goto err;
+       }
+
+       if (be32_to_cpu(buffer->magic) != DRBD_MD_MAGIC) {
+               dev_err(DEV, "Error while reading metadata, magic not found.\n");
+               rv = ERR_MD_INVALID;
+               goto err;
+       }
+       if (be32_to_cpu(buffer->al_offset) != bdev->md.al_offset) {
+               dev_err(DEV, "unexpected al_offset: %d (expected %d)\n",
+                   be32_to_cpu(buffer->al_offset), bdev->md.al_offset);
+               rv = ERR_MD_INVALID;
+               goto err;
+       }
+       if (be32_to_cpu(buffer->bm_offset) != bdev->md.bm_offset) {
+               dev_err(DEV, "unexpected bm_offset: %d (expected %d)\n",
+                   be32_to_cpu(buffer->bm_offset), bdev->md.bm_offset);
+               rv = ERR_MD_INVALID;
+               goto err;
+       }
+       if (be32_to_cpu(buffer->md_size_sect) != bdev->md.md_size_sect) {
+               dev_err(DEV, "unexpected md_size: %u (expected %u)\n",
+                   be32_to_cpu(buffer->md_size_sect), bdev->md.md_size_sect);
+               rv = ERR_MD_INVALID;
+               goto err;
+       }
+
+       if (be32_to_cpu(buffer->bm_bytes_per_bit) != BM_BLOCK_SIZE) {
+               dev_err(DEV, "unexpected bm_bytes_per_bit: %u (expected %u)\n",
+                   be32_to_cpu(buffer->bm_bytes_per_bit), BM_BLOCK_SIZE);
+               rv = ERR_MD_INVALID;
+               goto err;
+       }
+
+       bdev->md.la_size_sect = be64_to_cpu(buffer->la_size);
+       for (i = UI_CURRENT; i < UI_SIZE; i++)
+               bdev->md.uuid[i] = be64_to_cpu(buffer->uuid[i]);
+       bdev->md.flags = be32_to_cpu(buffer->flags);
+       mdev->sync_conf.al_extents = be32_to_cpu(buffer->al_nr_extents);
+       bdev->md.device_uuid = be64_to_cpu(buffer->device_uuid);
+
+       if (mdev->sync_conf.al_extents < 7)
+               mdev->sync_conf.al_extents = 127;
+
+ err:
+       mutex_unlock(&mdev->md_io_mutex);
+       put_ldev(mdev);
+
+       return rv;
+}
+
+/**
+ * drbd_md_mark_dirty() - Mark meta data super block as dirty
+ * @mdev:      DRBD device.
+ *
+ * Call this function if you change anything that should be written to
+ * the meta-data super block. This function sets MD_DIRTY, and starts a
+ * timer that ensures that within five seconds you have to call drbd_md_sync().
+ */
+void drbd_md_mark_dirty(struct drbd_conf *mdev)
+{
+       set_bit(MD_DIRTY, &mdev->flags);
+       mod_timer(&mdev->md_sync_timer, jiffies + 5*HZ);
+}
+
+
+static void drbd_uuid_move_history(struct drbd_conf *mdev) __must_hold(local)
+{
+       int i;
+
+       for (i = UI_HISTORY_START; i < UI_HISTORY_END; i++)
+               mdev->ldev->md.uuid[i+1] = mdev->ldev->md.uuid[i];
+}
+
+void _drbd_uuid_set(struct drbd_conf *mdev, int idx, u64 val) __must_hold(local)
+{
+       if (idx == UI_CURRENT) {
+               if (mdev->state.role == R_PRIMARY)
+                       val |= 1;
+               else
+                       val &= ~((u64)1);
+
+               drbd_set_ed_uuid(mdev, val);
+       }
+
+       mdev->ldev->md.uuid[idx] = val;
+       drbd_md_mark_dirty(mdev);
+}
+
+
+void drbd_uuid_set(struct drbd_conf *mdev, int idx, u64 val) __must_hold(local)
+{
+       if (mdev->ldev->md.uuid[idx]) {
+               drbd_uuid_move_history(mdev);
+               mdev->ldev->md.uuid[UI_HISTORY_START] = mdev->ldev->md.uuid[idx];
+       }
+       _drbd_uuid_set(mdev, idx, val);
+}
+
+/**
+ * drbd_uuid_new_current() - Creates a new current UUID
+ * @mdev:      DRBD device.
+ *
+ * Creates a new current UUID, and rotates the old current UUID into
+ * the bitmap slot. Causes an incremental resync upon next connect.
+ */
+void drbd_uuid_new_current(struct drbd_conf *mdev) __must_hold(local)
+{
+       u64 val;
+
+       dev_info(DEV, "Creating new current UUID\n");
+       D_ASSERT(mdev->ldev->md.uuid[UI_BITMAP] == 0);
+       mdev->ldev->md.uuid[UI_BITMAP] = mdev->ldev->md.uuid[UI_CURRENT];
+
+       get_random_bytes(&val, sizeof(u64));
+       _drbd_uuid_set(mdev, UI_CURRENT, val);
+}
+
+void drbd_uuid_set_bm(struct drbd_conf *mdev, u64 val) __must_hold(local)
+{
+       if (mdev->ldev->md.uuid[UI_BITMAP] == 0 && val == 0)
+               return;
+
+       if (val == 0) {
+               drbd_uuid_move_history(mdev);
+               mdev->ldev->md.uuid[UI_HISTORY_START] = mdev->ldev->md.uuid[UI_BITMAP];
+               mdev->ldev->md.uuid[UI_BITMAP] = 0;
+       } else {
+               if (mdev->ldev->md.uuid[UI_BITMAP])
+                       dev_warn(DEV, "bm UUID already set");
+
+               mdev->ldev->md.uuid[UI_BITMAP] = val;
+               mdev->ldev->md.uuid[UI_BITMAP] &= ~((u64)1);
+
+       }
+       drbd_md_mark_dirty(mdev);
+}
+
+/**
+ * drbd_bmio_set_n_write() - io_fn for drbd_queue_bitmap_io() or drbd_bitmap_io()
+ * @mdev:      DRBD device.
+ *
+ * Sets all bits in the bitmap and writes the whole bitmap to stable storage.
+ */
+int drbd_bmio_set_n_write(struct drbd_conf *mdev)
+{
+       int rv = -EIO;
+
+       if (get_ldev_if_state(mdev, D_ATTACHING)) {
+               drbd_md_set_flag(mdev, MDF_FULL_SYNC);
+               drbd_md_sync(mdev);
+               drbd_bm_set_all(mdev);
+
+               rv = drbd_bm_write(mdev);
+
+               if (!rv) {
+                       drbd_md_clear_flag(mdev, MDF_FULL_SYNC);
+                       drbd_md_sync(mdev);
+               }
+
+               put_ldev(mdev);
+       }
+
+       return rv;
+}
+
+/**
+ * drbd_bmio_clear_n_write() - io_fn for drbd_queue_bitmap_io() or drbd_bitmap_io()
+ * @mdev:      DRBD device.
+ *
+ * Clears all bits in the bitmap and writes the whole bitmap to stable storage.
+ */
+int drbd_bmio_clear_n_write(struct drbd_conf *mdev)
+{
+       int rv = -EIO;
+
+       if (get_ldev_if_state(mdev, D_ATTACHING)) {
+               drbd_bm_clear_all(mdev);
+               rv = drbd_bm_write(mdev);
+               put_ldev(mdev);
+       }
+
+       return rv;
+}
+
+static int w_bitmap_io(struct drbd_conf *mdev, struct drbd_work *w, int unused)
+{
+       struct bm_io_work *work = container_of(w, struct bm_io_work, w);
+       int rv;
+
+       D_ASSERT(atomic_read(&mdev->ap_bio_cnt) == 0);
+
+       drbd_bm_lock(mdev, work->why);
+       rv = work->io_fn(mdev);
+       drbd_bm_unlock(mdev);
+
+       clear_bit(BITMAP_IO, &mdev->flags);
+       wake_up(&mdev->misc_wait);
+
+       if (work->done)
+               work->done(mdev, rv);
+
+       clear_bit(BITMAP_IO_QUEUED, &mdev->flags);
+       work->why = NULL;
+
+       return 1;
+}
+
+/**
+ * drbd_queue_bitmap_io() - Queues an IO operation on the whole bitmap
+ * @mdev:      DRBD device.
+ * @io_fn:     IO callback to be called when bitmap IO is possible
+ * @done:      callback to be called after the bitmap IO was performed
+ * @why:       Descriptive text of the reason for doing the IO
+ *
+ * While IO on the bitmap happens we freeze application IO thus we ensure
+ * that drbd_set_out_of_sync() can not be called. This function MAY ONLY be
+ * called from worker context. It MUST NOT be used while a previous such
+ * work is still pending!
+ */
+void drbd_queue_bitmap_io(struct drbd_conf *mdev,
+                         int (*io_fn)(struct drbd_conf *),
+                         void (*done)(struct drbd_conf *, int),
+                         char *why)
+{
+       D_ASSERT(current == mdev->worker.task);
+
+       D_ASSERT(!test_bit(BITMAP_IO_QUEUED, &mdev->flags));
+       D_ASSERT(!test_bit(BITMAP_IO, &mdev->flags));
+       D_ASSERT(list_empty(&mdev->bm_io_work.w.list));
+       if (mdev->bm_io_work.why)
+               dev_err(DEV, "FIXME going to queue '%s' but '%s' still pending?\n",
+                       why, mdev->bm_io_work.why);
+
+       mdev->bm_io_work.io_fn = io_fn;
+       mdev->bm_io_work.done = done;
+       mdev->bm_io_work.why = why;
+
+       set_bit(BITMAP_IO, &mdev->flags);
+       if (atomic_read(&mdev->ap_bio_cnt) == 0) {
+               if (list_empty(&mdev->bm_io_work.w.list)) {
+                       set_bit(BITMAP_IO_QUEUED, &mdev->flags);
+                       drbd_queue_work(&mdev->data.work, &mdev->bm_io_work.w);
+               } else
+                       dev_err(DEV, "FIXME avoided double queuing bm_io_work\n");
+       }
+}
+
+/**
+ * drbd_bitmap_io() -  Does an IO operation on the whole bitmap
+ * @mdev:      DRBD device.
+ * @io_fn:     IO callback to be called when bitmap IO is possible
+ * @why:       Descriptive text of the reason for doing the IO
+ *
+ * freezes application IO while that the actual IO operations runs. This
+ * functions MAY NOT be called from worker context.
+ */
+int drbd_bitmap_io(struct drbd_conf *mdev, int (*io_fn)(struct drbd_conf *), char *why)
+{
+       int rv;
+
+       D_ASSERT(current != mdev->worker.task);
+
+       drbd_suspend_io(mdev);
+
+       drbd_bm_lock(mdev, why);
+       rv = io_fn(mdev);
+       drbd_bm_unlock(mdev);
+
+       drbd_resume_io(mdev);
+
+       return rv;
+}
+
+void drbd_md_set_flag(struct drbd_conf *mdev, int flag) __must_hold(local)
+{
+       if ((mdev->ldev->md.flags & flag) != flag) {
+               drbd_md_mark_dirty(mdev);
+               mdev->ldev->md.flags |= flag;
+       }
+}
+
+void drbd_md_clear_flag(struct drbd_conf *mdev, int flag) __must_hold(local)
+{
+       if ((mdev->ldev->md.flags & flag) != 0) {
+               drbd_md_mark_dirty(mdev);
+               mdev->ldev->md.flags &= ~flag;
+       }
+}
+int drbd_md_test_flag(struct drbd_backing_dev *bdev, int flag)
+{
+       return (bdev->md.flags & flag) != 0;
+}
+
+static void md_sync_timer_fn(unsigned long data)
+{
+       struct drbd_conf *mdev = (struct drbd_conf *) data;
+
+       drbd_queue_work_front(&mdev->data.work, &mdev->md_sync_work);
+}
+
+static int w_md_sync(struct drbd_conf *mdev, struct drbd_work *w, int unused)
+{
+       dev_warn(DEV, "md_sync_timer expired! Worker calls drbd_md_sync().\n");
+       drbd_md_sync(mdev);
+
+       return 1;
+}
+
+#ifdef CONFIG_DRBD_FAULT_INJECTION
+/* Fault insertion support including random number generator shamelessly
+ * stolen from kernel/rcutorture.c */
+struct fault_random_state {
+       unsigned long state;
+       unsigned long count;
+};
+
+#define FAULT_RANDOM_MULT 39916801  /* prime */
+#define FAULT_RANDOM_ADD       479001701 /* prime */
+#define FAULT_RANDOM_REFRESH 10000
+
+/*
+ * Crude but fast random-number generator.  Uses a linear congruential
+ * generator, with occasional help from get_random_bytes().
+ */
+static unsigned long
+_drbd_fault_random(struct fault_random_state *rsp)
+{
+       long refresh;
+
+       if (--rsp->count < 0) {
+               get_random_bytes(&refresh, sizeof(refresh));
+               rsp->state += refresh;
+               rsp->count = FAULT_RANDOM_REFRESH;
+       }
+       rsp->state = rsp->state * FAULT_RANDOM_MULT + FAULT_RANDOM_ADD;
+       return swahw32(rsp->state);
+}
+
+static char *
+_drbd_fault_str(unsigned int type) {
+       static char *_faults[] = {
+               [DRBD_FAULT_MD_WR] = "Meta-data write",
+               [DRBD_FAULT_MD_RD] = "Meta-data read",
+               [DRBD_FAULT_RS_WR] = "Resync write",
+               [DRBD_FAULT_RS_RD] = "Resync read",
+               [DRBD_FAULT_DT_WR] = "Data write",
+               [DRBD_FAULT_DT_RD] = "Data read",
+               [DRBD_FAULT_DT_RA] = "Data read ahead",
+               [DRBD_FAULT_BM_ALLOC] = "BM allocation",
+               [DRBD_FAULT_AL_EE] = "EE allocation"
+       };
+
+       return (type < DRBD_FAULT_MAX) ? _faults[type] : "**Unknown**";
+}
+
+unsigned int
+_drbd_insert_fault(struct drbd_conf *mdev, unsigned int type)
+{
+       static struct fault_random_state rrs = {0, 0};
+
+       unsigned int ret = (
+               (fault_devs == 0 ||
+                       ((1 << mdev_to_minor(mdev)) & fault_devs) != 0) &&
+               (((_drbd_fault_random(&rrs) % 100) + 1) <= fault_rate));
+
+       if (ret) {
+               fault_count++;
+
+               if (printk_ratelimit())
+                       dev_warn(DEV, "***Simulating %s failure\n",
+                               _drbd_fault_str(type));
+       }
+
+       return ret;
+}
+#endif
+
+const char *drbd_buildtag(void)
+{
+       /* DRBD built from external sources has here a reference to the
+          git hash of the source code. */
+
+       static char buildtag[38] = "\0uilt-in";
+
+       if (buildtag[0] == 0) {
+#ifdef CONFIG_MODULES
+               if (THIS_MODULE != NULL)
+                       sprintf(buildtag, "srcversion: %-24s", THIS_MODULE->srcversion);
+               else
+#endif
+                       buildtag[0] = 'b';
+       }
+
+       return buildtag;
+}
+
+module_init(drbd_init)
+module_exit(drbd_cleanup)
+
+EXPORT_SYMBOL(drbd_conn_str);
+EXPORT_SYMBOL(drbd_role_str);
+EXPORT_SYMBOL(drbd_disk_str);
+EXPORT_SYMBOL(drbd_set_st_err_str);
diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c
new file mode 100644 (file)
index 0000000..436a090
--- /dev/null
@@ -0,0 +1,2364 @@
+/*
+   drbd_nl.c
+
+   This file is part of DRBD by Philipp Reisner and Lars Ellenberg.
+
+   Copyright (C) 2001-2008, LINBIT Information Technologies GmbH.
+   Copyright (C) 1999-2008, Philipp Reisner <philipp.reisner@linbit.com>.
+   Copyright (C) 2002-2008, Lars Ellenberg <lars.ellenberg@linbit.com>.
+
+   drbd is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   drbd 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 drbd; see the file COPYING.  If not, write to
+   the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ */
+
+#include <linux/module.h>
+#include <linux/drbd.h>
+#include <linux/in.h>
+#include <linux/fs.h>
+#include <linux/file.h>
+#include <linux/slab.h>
+#include <linux/connector.h>
+#include <linux/blkpg.h>
+#include <linux/cpumask.h>
+#include "drbd_int.h"
+#include "drbd_wrappers.h"
+#include <asm/unaligned.h>
+#include <linux/drbd_tag_magic.h>
+#include <linux/drbd_limits.h>
+
+static unsigned short *tl_add_blob(unsigned short *, enum drbd_tags, const void *, int);
+static unsigned short *tl_add_str(unsigned short *, enum drbd_tags, const char *);
+static unsigned short *tl_add_int(unsigned short *, enum drbd_tags, const void *);
+
+/* see get_sb_bdev and bd_claim */
+static char *drbd_m_holder = "Hands off! this is DRBD's meta data device.";
+
+/* Generate the tag_list to struct functions */
+#define NL_PACKET(name, number, fields) \
+static int name ## _from_tags(struct drbd_conf *mdev, \
+       unsigned short *tags, struct name *arg) __attribute__ ((unused)); \
+static int name ## _from_tags(struct drbd_conf *mdev, \
+       unsigned short *tags, struct name *arg) \
+{ \
+       int tag; \
+       int dlen; \
+       \
+       while ((tag = get_unaligned(tags++)) != TT_END) {       \
+               dlen = get_unaligned(tags++);                   \
+               switch (tag_number(tag)) { \
+               fields \
+               default: \
+                       if (tag & T_MANDATORY) { \
+                               dev_err(DEV, "Unknown tag: %d\n", tag_number(tag)); \
+                               return 0; \
+                       } \
+               } \
+               tags = (unsigned short *)((char *)tags + dlen); \
+       } \
+       return 1; \
+}
+#define NL_INTEGER(pn, pr, member) \
+       case pn: /* D_ASSERT( tag_type(tag) == TT_INTEGER ); */ \
+               arg->member = get_unaligned((int *)(tags));     \
+               break;
+#define NL_INT64(pn, pr, member) \
+       case pn: /* D_ASSERT( tag_type(tag) == TT_INT64 ); */ \
+               arg->member = get_unaligned((u64 *)(tags));     \
+               break;
+#define NL_BIT(pn, pr, member) \
+       case pn: /* D_ASSERT( tag_type(tag) == TT_BIT ); */ \
+               arg->member = *(char *)(tags) ? 1 : 0; \
+               break;
+#define NL_STRING(pn, pr, member, len) \
+       case pn: /* D_ASSERT( tag_type(tag) == TT_STRING ); */ \
+               if (dlen > len) { \
+                       dev_err(DEV, "arg too long: %s (%u wanted, max len: %u bytes)\n", \
+                               #member, dlen, (unsigned int)len); \
+                       return 0; \
+               } \
+                arg->member ## _len = dlen; \
+                memcpy(arg->member, tags, min_t(size_t, dlen, len)); \
+                break;
+#include "linux/drbd_nl.h"
+
+/* Generate the struct to tag_list functions */
+#define NL_PACKET(name, number, fields) \
+static unsigned short* \
+name ## _to_tags(struct drbd_conf *mdev, \
+       struct name *arg, unsigned short *tags) __attribute__ ((unused)); \
+static unsigned short* \
+name ## _to_tags(struct drbd_conf *mdev, \
+       struct name *arg, unsigned short *tags) \
+{ \
+       fields \
+       return tags; \
+}
+
+#define NL_INTEGER(pn, pr, member) \
+       put_unaligned(pn | pr | TT_INTEGER, tags++);    \
+       put_unaligned(sizeof(int), tags++);             \
+       put_unaligned(arg->member, (int *)tags);        \
+       tags = (unsigned short *)((char *)tags+sizeof(int));
+#define NL_INT64(pn, pr, member) \
+       put_unaligned(pn | pr | TT_INT64, tags++);      \
+       put_unaligned(sizeof(u64), tags++);             \
+       put_unaligned(arg->member, (u64 *)tags);        \
+       tags = (unsigned short *)((char *)tags+sizeof(u64));
+#define NL_BIT(pn, pr, member) \
+       put_unaligned(pn | pr | TT_BIT, tags++);        \
+       put_unaligned(sizeof(char), tags++);            \
+       *(char *)tags = arg->member; \
+       tags = (unsigned short *)((char *)tags+sizeof(char));
+#define NL_STRING(pn, pr, member, len) \
+       put_unaligned(pn | pr | TT_STRING, tags++);     \
+       put_unaligned(arg->member ## _len, tags++);     \
+       memcpy(tags, arg->member, arg->member ## _len); \
+       tags = (unsigned short *)((char *)tags + arg->member ## _len);
+#include "linux/drbd_nl.h"
+
+void drbd_bcast_ev_helper(struct drbd_conf *mdev, char *helper_name);
+void drbd_nl_send_reply(struct cn_msg *, int);
+
+int drbd_khelper(struct drbd_conf *mdev, char *cmd)
+{
+       char *envp[] = { "HOME=/",
+                       "TERM=linux",
+                       "PATH=/sbin:/usr/sbin:/bin:/usr/bin",
+                       NULL, /* Will be set to address family */
+                       NULL, /* Will be set to address */
+                       NULL };
+
+       char mb[12], af[20], ad[60], *afs;
+       char *argv[] = {usermode_helper, cmd, mb, NULL };
+       int ret;
+
+       snprintf(mb, 12, "minor-%d", mdev_to_minor(mdev));
+
+       if (get_net_conf(mdev)) {
+               switch (((struct sockaddr *)mdev->net_conf->peer_addr)->sa_family) {
+               case AF_INET6:
+                       afs = "ipv6";
+                       snprintf(ad, 60, "DRBD_PEER_ADDRESS=%pI6",
+                                &((struct sockaddr_in6 *)mdev->net_conf->peer_addr)->sin6_addr);
+                       break;
+               case AF_INET:
+                       afs = "ipv4";
+                       snprintf(ad, 60, "DRBD_PEER_ADDRESS=%pI4",
+                                &((struct sockaddr_in *)mdev->net_conf->peer_addr)->sin_addr);
+                       break;
+               default:
+                       afs = "ssocks";
+                       snprintf(ad, 60, "DRBD_PEER_ADDRESS=%pI4",
+                                &((struct sockaddr_in *)mdev->net_conf->peer_addr)->sin_addr);
+               }
+               snprintf(af, 20, "DRBD_PEER_AF=%s", afs);
+               envp[3]=af;
+               envp[4]=ad;
+               put_net_conf(mdev);
+       }
+
+       dev_info(DEV, "helper command: %s %s %s\n", usermode_helper, cmd, mb);
+
+       drbd_bcast_ev_helper(mdev, cmd);
+       ret = call_usermodehelper(usermode_helper, argv, envp, 1);
+       if (ret)
+               dev_warn(DEV, "helper command: %s %s %s exit code %u (0x%x)\n",
+                               usermode_helper, cmd, mb,
+                               (ret >> 8) & 0xff, ret);
+       else
+               dev_info(DEV, "helper command: %s %s %s exit code %u (0x%x)\n",
+                               usermode_helper, cmd, mb,
+                               (ret >> 8) & 0xff, ret);
+
+       if (ret < 0) /* Ignore any ERRNOs we got. */
+               ret = 0;
+
+       return ret;
+}
+
+enum drbd_disk_state drbd_try_outdate_peer(struct drbd_conf *mdev)
+{
+       char *ex_to_string;
+       int r;
+       enum drbd_disk_state nps;
+       enum drbd_fencing_p fp;
+
+       D_ASSERT(mdev->state.pdsk == D_UNKNOWN);
+
+       if (get_ldev_if_state(mdev, D_CONSISTENT)) {
+               fp = mdev->ldev->dc.fencing;
+               put_ldev(mdev);
+       } else {
+               dev_warn(DEV, "Not fencing peer, I'm not even Consistent myself.\n");
+               return mdev->state.pdsk;
+       }
+
+       if (fp == FP_STONITH)
+               _drbd_request_state(mdev, NS(susp, 1), CS_WAIT_COMPLETE);
+
+       r = drbd_khelper(mdev, "fence-peer");
+
+       switch ((r>>8) & 0xff) {
+       case 3: /* peer is inconsistent */
+               ex_to_string = "peer is inconsistent or worse";
+               nps = D_INCONSISTENT;
+               break;
+       case 4: /* peer got outdated, or was already outdated */
+               ex_to_string = "peer was fenced";
+               nps = D_OUTDATED;
+               break;
+       case 5: /* peer was down */
+               if (mdev->state.disk == D_UP_TO_DATE) {
+                       /* we will(have) create(d) a new UUID anyways... */
+                       ex_to_string = "peer is unreachable, assumed to be dead";
+                       nps = D_OUTDATED;
+               } else {
+                       ex_to_string = "peer unreachable, doing nothing since disk != UpToDate";
+                       nps = mdev->state.pdsk;
+               }
+               break;
+       case 6: /* Peer is primary, voluntarily outdate myself.
+                * This is useful when an unconnected R_SECONDARY is asked to
+                * become R_PRIMARY, but finds the other peer being active. */
+               ex_to_string = "peer is active";
+               dev_warn(DEV, "Peer is primary, outdating myself.\n");
+               nps = D_UNKNOWN;
+               _drbd_request_state(mdev, NS(disk, D_OUTDATED), CS_WAIT_COMPLETE);
+               break;
+       case 7:
+               if (fp != FP_STONITH)
+                       dev_err(DEV, "fence-peer() = 7 && fencing != Stonith !!!\n");
+               ex_to_string = "peer was stonithed";
+               nps = D_OUTDATED;
+               break;
+       default:
+               /* The script is broken ... */
+               nps = D_UNKNOWN;
+               dev_err(DEV, "fence-peer helper broken, returned %d\n", (r>>8)&0xff);
+               return nps;
+       }
+
+       dev_info(DEV, "fence-peer helper returned %d (%s)\n",
+                       (r>>8) & 0xff, ex_to_string);
+       return nps;
+}
+
+
+int drbd_set_role(struct drbd_conf *mdev, enum drbd_role new_role, int force)
+{
+       const int max_tries = 4;
+       int r = 0;
+       int try = 0;
+       int forced = 0;
+       union drbd_state mask, val;
+       enum drbd_disk_state nps;
+
+       if (new_role == R_PRIMARY)
+               request_ping(mdev); /* Detect a dead peer ASAP */
+
+       mutex_lock(&mdev->state_mutex);
+
+       mask.i = 0; mask.role = R_MASK;
+       val.i  = 0; val.role  = new_role;
+
+       while (try++ < max_tries) {
+               r = _drbd_request_state(mdev, mask, val, CS_WAIT_COMPLETE);
+
+               /* in case we first succeeded to outdate,
+                * but now suddenly could establish a connection */
+               if (r == SS_CW_FAILED_BY_PEER && mask.pdsk != 0) {
+                       val.pdsk = 0;
+                       mask.pdsk = 0;
+                       continue;
+               }
+
+               if (r == SS_NO_UP_TO_DATE_DISK && force &&
+                   (mdev->state.disk == D_INCONSISTENT ||
+                    mdev->state.disk == D_OUTDATED)) {
+                       mask.disk = D_MASK;
+                       val.disk  = D_UP_TO_DATE;
+                       forced = 1;
+                       continue;
+               }
+
+               if (r == SS_NO_UP_TO_DATE_DISK &&
+                   mdev->state.disk == D_CONSISTENT && mask.pdsk == 0) {
+                       D_ASSERT(mdev->state.pdsk == D_UNKNOWN);
+                       nps = drbd_try_outdate_peer(mdev);
+
+                       if (nps == D_OUTDATED || nps == D_INCONSISTENT) {
+                               val.disk = D_UP_TO_DATE;
+                               mask.disk = D_MASK;
+                       }
+
+                       val.pdsk = nps;
+                       mask.pdsk = D_MASK;
+
+                       continue;
+               }
+
+               if (r == SS_NOTHING_TO_DO)
+                       goto fail;
+               if (r == SS_PRIMARY_NOP && mask.pdsk == 0) {
+                       nps = drbd_try_outdate_peer(mdev);
+
+                       if (force && nps > D_OUTDATED) {
+                               dev_warn(DEV, "Forced into split brain situation!\n");
+                               nps = D_OUTDATED;
+                       }
+
+                       mask.pdsk = D_MASK;
+                       val.pdsk  = nps;
+
+                       continue;
+               }
+               if (r == SS_TWO_PRIMARIES) {
+                       /* Maybe the peer is detected as dead very soon...
+                          retry at most once more in this case. */
+                       __set_current_state(TASK_INTERRUPTIBLE);
+                       schedule_timeout((mdev->net_conf->ping_timeo+1)*HZ/10);
+                       if (try < max_tries)
+                               try = max_tries - 1;
+                       continue;
+               }
+               if (r < SS_SUCCESS) {
+                       r = _drbd_request_state(mdev, mask, val,
+                                               CS_VERBOSE + CS_WAIT_COMPLETE);
+                       if (r < SS_SUCCESS)
+                               goto fail;
+               }
+               break;
+       }
+
+       if (r < SS_SUCCESS)
+               goto fail;
+
+       if (forced)
+               dev_warn(DEV, "Forced to consider local data as UpToDate!\n");
+
+       /* Wait until nothing is on the fly :) */
+       wait_event(mdev->misc_wait, atomic_read(&mdev->ap_pending_cnt) == 0);
+
+       if (new_role == R_SECONDARY) {
+               set_disk_ro(mdev->vdisk, TRUE);
+               if (get_ldev(mdev)) {
+                       mdev->ldev->md.uuid[UI_CURRENT] &= ~(u64)1;
+                       put_ldev(mdev);
+               }
+       } else {
+               if (get_net_conf(mdev)) {
+                       mdev->net_conf->want_lose = 0;
+                       put_net_conf(mdev);
+               }
+               set_disk_ro(mdev->vdisk, FALSE);
+               if (get_ldev(mdev)) {
+                       if (((mdev->state.conn < C_CONNECTED ||
+                              mdev->state.pdsk <= D_FAILED)
+                             && mdev->ldev->md.uuid[UI_BITMAP] == 0) || forced)
+                               drbd_uuid_new_current(mdev);
+
+                       mdev->ldev->md.uuid[UI_CURRENT] |=  (u64)1;
+                       put_ldev(mdev);
+               }
+       }
+
+       if ((new_role == R_SECONDARY) && get_ldev(mdev)) {
+               drbd_al_to_on_disk_bm(mdev);
+               put_ldev(mdev);
+       }
+
+       if (mdev->state.conn >= C_WF_REPORT_PARAMS) {
+               /* if this was forced, we should consider sync */
+               if (forced)
+                       drbd_send_uuids(mdev);
+               drbd_send_state(mdev);
+       }
+
+       drbd_md_sync(mdev);
+
+       kobject_uevent(&disk_to_dev(mdev->vdisk)->kobj, KOBJ_CHANGE);
+ fail:
+       mutex_unlock(&mdev->state_mutex);
+       return r;
+}
+
+
+static int drbd_nl_primary(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp,
+                          struct drbd_nl_cfg_reply *reply)
+{
+       struct primary primary_args;
+
+       memset(&primary_args, 0, sizeof(struct primary));
+       if (!primary_from_tags(mdev, nlp->tag_list, &primary_args)) {
+               reply->ret_code = ERR_MANDATORY_TAG;
+               return 0;
+       }
+
+       reply->ret_code =
+               drbd_set_role(mdev, R_PRIMARY, primary_args.overwrite_peer);
+
+       return 0;
+}
+
+static int drbd_nl_secondary(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp,
+                            struct drbd_nl_cfg_reply *reply)
+{
+       reply->ret_code = drbd_set_role(mdev, R_SECONDARY, 0);
+
+       return 0;
+}
+
+/* initializes the md.*_offset members, so we are able to find
+ * the on disk meta data */
+static void drbd_md_set_sector_offsets(struct drbd_conf *mdev,
+                                      struct drbd_backing_dev *bdev)
+{
+       sector_t md_size_sect = 0;
+       switch (bdev->dc.meta_dev_idx) {
+       default:
+               /* v07 style fixed size indexed meta data */
+               bdev->md.md_size_sect = MD_RESERVED_SECT;
+               bdev->md.md_offset = drbd_md_ss__(mdev, bdev);
+               bdev->md.al_offset = MD_AL_OFFSET;
+               bdev->md.bm_offset = MD_BM_OFFSET;
+               break;
+       case DRBD_MD_INDEX_FLEX_EXT:
+               /* just occupy the full device; unit: sectors */
+               bdev->md.md_size_sect = drbd_get_capacity(bdev->md_bdev);
+               bdev->md.md_offset = 0;
+               bdev->md.al_offset = MD_AL_OFFSET;
+               bdev->md.bm_offset = MD_BM_OFFSET;
+               break;
+       case DRBD_MD_INDEX_INTERNAL:
+       case DRBD_MD_INDEX_FLEX_INT:
+               bdev->md.md_offset = drbd_md_ss__(mdev, bdev);
+               /* al size is still fixed */
+               bdev->md.al_offset = -MD_AL_MAX_SIZE;
+               /* we need (slightly less than) ~ this much bitmap sectors: */
+               md_size_sect = drbd_get_capacity(bdev->backing_bdev);
+               md_size_sect = ALIGN(md_size_sect, BM_SECT_PER_EXT);
+               md_size_sect = BM_SECT_TO_EXT(md_size_sect);
+               md_size_sect = ALIGN(md_size_sect, 8);
+
+               /* plus the "drbd meta data super block",
+                * and the activity log; */
+               md_size_sect += MD_BM_OFFSET;
+
+               bdev->md.md_size_sect = md_size_sect;
+               /* bitmap offset is adjusted by 'super' block size */
+               bdev->md.bm_offset   = -md_size_sect + MD_AL_OFFSET;
+               break;
+       }
+}
+
+char *ppsize(char *buf, unsigned long long size)
+{
+       /* Needs 9 bytes at max. */
+       static char units[] = { 'K', 'M', 'G', 'T', 'P', 'E' };
+       int base = 0;
+       while (size >= 10000) {
+               /* shift + round */
+               size = (size >> 10) + !!(size & (1<<9));
+               base++;
+       }
+       sprintf(buf, "%lu %cB", (long)size, units[base]);
+
+       return buf;
+}
+
+/* there is still a theoretical deadlock when called from receiver
+ * on an D_INCONSISTENT R_PRIMARY:
+ *  remote READ does inc_ap_bio, receiver would need to receive answer
+ *  packet from remote to dec_ap_bio again.
+ *  receiver receive_sizes(), comes here,
+ *  waits for ap_bio_cnt == 0. -> deadlock.
+ * but this cannot happen, actually, because:
+ *  R_PRIMARY D_INCONSISTENT, and peer's disk is unreachable
+ *  (not connected, or bad/no disk on peer):
+ *  see drbd_fail_request_early, ap_bio_cnt is zero.
+ *  R_PRIMARY D_INCONSISTENT, and C_SYNC_TARGET:
+ *  peer may not initiate a resize.
+ */
+void drbd_suspend_io(struct drbd_conf *mdev)
+{
+       set_bit(SUSPEND_IO, &mdev->flags);
+       wait_event(mdev->misc_wait, !atomic_read(&mdev->ap_bio_cnt));
+}
+
+void drbd_resume_io(struct drbd_conf *mdev)
+{
+       clear_bit(SUSPEND_IO, &mdev->flags);
+       wake_up(&mdev->misc_wait);
+}
+
+/**
+ * drbd_determine_dev_size() -  Sets the right device size obeying all constraints
+ * @mdev:      DRBD device.
+ *
+ * Returns 0 on success, negative return values indicate errors.
+ * You should call drbd_md_sync() after calling this function.
+ */
+enum determine_dev_size drbd_determin_dev_size(struct drbd_conf *mdev) __must_hold(local)
+{
+       sector_t prev_first_sect, prev_size; /* previous meta location */
+       sector_t la_size;
+       sector_t size;
+       char ppb[10];
+
+       int md_moved, la_size_changed;
+       enum determine_dev_size rv = unchanged;
+
+       /* race:
+        * application request passes inc_ap_bio,
+        * but then cannot get an AL-reference.
+        * this function later may wait on ap_bio_cnt == 0. -> deadlock.
+        *
+        * to avoid that:
+        * Suspend IO right here.
+        * still lock the act_log to not trigger ASSERTs there.
+        */
+       drbd_suspend_io(mdev);
+
+       /* no wait necessary anymore, actually we could assert that */
+       wait_event(mdev->al_wait, lc_try_lock(mdev->act_log));
+
+       prev_first_sect = drbd_md_first_sector(mdev->ldev);
+       prev_size = mdev->ldev->md.md_size_sect;
+       la_size = mdev->ldev->md.la_size_sect;
+
+       /* TODO: should only be some assert here, not (re)init... */
+       drbd_md_set_sector_offsets(mdev, mdev->ldev);
+
+       size = drbd_new_dev_size(mdev, mdev->ldev);
+
+       if (drbd_get_capacity(mdev->this_bdev) != size ||
+           drbd_bm_capacity(mdev) != size) {
+               int err;
+               err = drbd_bm_resize(mdev, size);
+               if (unlikely(err)) {
+                       /* currently there is only one error: ENOMEM! */
+                       size = drbd_bm_capacity(mdev)>>1;
+                       if (size == 0) {
+                               dev_err(DEV, "OUT OF MEMORY! "
+                                   "Could not allocate bitmap!\n");
+                       } else {
+                               dev_err(DEV, "BM resizing failed. "
+                                   "Leaving size unchanged at size = %lu KB\n",
+                                   (unsigned long)size);
+                       }
+                       rv = dev_size_error;
+               }
+               /* racy, see comments above. */
+               drbd_set_my_capacity(mdev, size);
+               mdev->ldev->md.la_size_sect = size;
+               dev_info(DEV, "size = %s (%llu KB)\n", ppsize(ppb, size>>1),
+                    (unsigned long long)size>>1);
+       }
+       if (rv == dev_size_error)
+               goto out;
+
+       la_size_changed = (la_size != mdev->ldev->md.la_size_sect);
+
+       md_moved = prev_first_sect != drbd_md_first_sector(mdev->ldev)
+               || prev_size       != mdev->ldev->md.md_size_sect;
+
+       if (la_size_changed || md_moved) {
+               drbd_al_shrink(mdev); /* All extents inactive. */
+               dev_info(DEV, "Writing the whole bitmap, %s\n",
+                        la_size_changed && md_moved ? "size changed and md moved" :
+                        la_size_changed ? "size changed" : "md moved");
+               rv = drbd_bitmap_io(mdev, &drbd_bm_write, "size changed"); /* does drbd_resume_io() ! */
+               drbd_md_mark_dirty(mdev);
+       }
+
+       if (size > la_size)
+               rv = grew;
+       if (size < la_size)
+               rv = shrunk;
+out:
+       lc_unlock(mdev->act_log);
+       wake_up(&mdev->al_wait);
+       drbd_resume_io(mdev);
+
+       return rv;
+}
+
+sector_t
+drbd_new_dev_size(struct drbd_conf *mdev, struct drbd_backing_dev *bdev)
+{
+       sector_t p_size = mdev->p_size;   /* partner's disk size. */
+       sector_t la_size = bdev->md.la_size_sect; /* last agreed size. */
+       sector_t m_size; /* my size */
+       sector_t u_size = bdev->dc.disk_size; /* size requested by user. */
+       sector_t size = 0;
+
+       m_size = drbd_get_max_capacity(bdev);
+
+       if (p_size && m_size) {
+               size = min_t(sector_t, p_size, m_size);
+       } else {
+               if (la_size) {
+                       size = la_size;
+                       if (m_size && m_size < size)
+                               size = m_size;
+                       if (p_size && p_size < size)
+                               size = p_size;
+               } else {
+                       if (m_size)
+                               size = m_size;
+                       if (p_size)
+                               size = p_size;
+               }
+       }
+
+       if (size == 0)
+               dev_err(DEV, "Both nodes diskless!\n");
+
+       if (u_size) {
+               if (u_size > size)
+                       dev_err(DEV, "Requested disk size is too big (%lu > %lu)\n",
+                           (unsigned long)u_size>>1, (unsigned long)size>>1);
+               else
+                       size = u_size;
+       }
+
+       return size;
+}
+
+/**
+ * drbd_check_al_size() - Ensures that the AL is of the right size
+ * @mdev:      DRBD device.
+ *
+ * Returns -EBUSY if current al lru is still used, -ENOMEM when allocation
+ * failed, and 0 on success. You should call drbd_md_sync() after you called
+ * this function.
+ */
+static int drbd_check_al_size(struct drbd_conf *mdev)
+{
+       struct lru_cache *n, *t;
+       struct lc_element *e;
+       unsigned int in_use;
+       int i;
+
+       ERR_IF(mdev->sync_conf.al_extents < 7)
+               mdev->sync_conf.al_extents = 127;
+
+       if (mdev->act_log &&
+           mdev->act_log->nr_elements == mdev->sync_conf.al_extents)
+               return 0;
+
+       in_use = 0;
+       t = mdev->act_log;
+       n = lc_create("act_log", drbd_al_ext_cache,
+               mdev->sync_conf.al_extents, sizeof(struct lc_element), 0);
+
+       if (n == NULL) {
+               dev_err(DEV, "Cannot allocate act_log lru!\n");
+               return -ENOMEM;
+       }
+       spin_lock_irq(&mdev->al_lock);
+       if (t) {
+               for (i = 0; i < t->nr_elements; i++) {
+                       e = lc_element_by_index(t, i);
+                       if (e->refcnt)
+                               dev_err(DEV, "refcnt(%d)==%d\n",
+                                   e->lc_number, e->refcnt);
+                       in_use += e->refcnt;
+               }
+       }
+       if (!in_use)
+               mdev->act_log = n;
+       spin_unlock_irq(&mdev->al_lock);
+       if (in_use) {
+               dev_err(DEV, "Activity log still in use!\n");
+               lc_destroy(n);
+               return -EBUSY;
+       } else {
+               if (t)
+                       lc_destroy(t);
+       }
+       drbd_md_mark_dirty(mdev); /* we changed mdev->act_log->nr_elemens */
+       return 0;
+}
+
+void drbd_setup_queue_param(struct drbd_conf *mdev, unsigned int max_seg_s) __must_hold(local)
+{
+       struct request_queue * const q = mdev->rq_queue;
+       struct request_queue * const b = mdev->ldev->backing_bdev->bd_disk->queue;
+       int max_segments = mdev->ldev->dc.max_bio_bvecs;
+
+       if (b->merge_bvec_fn && !mdev->ldev->dc.use_bmbv)
+               max_seg_s = PAGE_SIZE;
+
+       max_seg_s = min(queue_max_sectors(b) * queue_logical_block_size(b), max_seg_s);
+
+       blk_queue_max_sectors(q, max_seg_s >> 9);
+       blk_queue_max_phys_segments(q, max_segments ? max_segments : MAX_PHYS_SEGMENTS);
+       blk_queue_max_hw_segments(q, max_segments ? max_segments : MAX_HW_SEGMENTS);
+       blk_queue_max_segment_size(q, max_seg_s);
+       blk_queue_logical_block_size(q, 512);
+       blk_queue_segment_boundary(q, PAGE_SIZE-1);
+       blk_stack_limits(&q->limits, &b->limits, 0);
+
+       if (b->merge_bvec_fn)
+               dev_warn(DEV, "Backing device's merge_bvec_fn() = %p\n",
+                    b->merge_bvec_fn);
+       dev_info(DEV, "max_segment_size ( = BIO size ) = %u\n", queue_max_segment_size(q));
+
+       if (q->backing_dev_info.ra_pages != b->backing_dev_info.ra_pages) {
+               dev_info(DEV, "Adjusting my ra_pages to backing device's (%lu -> %lu)\n",
+                    q->backing_dev_info.ra_pages,
+                    b->backing_dev_info.ra_pages);
+               q->backing_dev_info.ra_pages = b->backing_dev_info.ra_pages;
+       }
+}
+
+/* serialize deconfig (worker exiting, doing cleanup)
+ * and reconfig (drbdsetup disk, drbdsetup net)
+ *
+ * wait for a potentially exiting worker, then restart it,
+ * or start a new one.
+ */
+static void drbd_reconfig_start(struct drbd_conf *mdev)
+{
+       wait_event(mdev->state_wait, !test_and_set_bit(CONFIG_PENDING, &mdev->flags));
+       wait_event(mdev->state_wait, !test_bit(DEVICE_DYING, &mdev->flags));
+       drbd_thread_start(&mdev->worker);
+}
+
+/* if still unconfigured, stops worker again.
+ * if configured now, clears CONFIG_PENDING.
+ * wakes potential waiters */
+static void drbd_reconfig_done(struct drbd_conf *mdev)
+{
+       spin_lock_irq(&mdev->req_lock);
+       if (mdev->state.disk == D_DISKLESS &&
+           mdev->state.conn == C_STANDALONE &&
+           mdev->state.role == R_SECONDARY) {
+               set_bit(DEVICE_DYING, &mdev->flags);
+               drbd_thread_stop_nowait(&mdev->worker);
+       } else
+               clear_bit(CONFIG_PENDING, &mdev->flags);
+       spin_unlock_irq(&mdev->req_lock);
+       wake_up(&mdev->state_wait);
+}
+
+/* does always return 0;
+ * interesting return code is in reply->ret_code */
+static int drbd_nl_disk_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp,
+                            struct drbd_nl_cfg_reply *reply)
+{
+       enum drbd_ret_codes retcode;
+       enum determine_dev_size dd;
+       sector_t max_possible_sectors;
+       sector_t min_md_device_sectors;
+       struct drbd_backing_dev *nbc = NULL; /* new_backing_conf */
+       struct inode *inode, *inode2;
+       struct lru_cache *resync_lru = NULL;
+       union drbd_state ns, os;
+       int rv;
+       int cp_discovered = 0;
+       int logical_block_size;
+
+       drbd_reconfig_start(mdev);
+
+       /* if you want to reconfigure, please tear down first */
+       if (mdev->state.disk > D_DISKLESS) {
+               retcode = ERR_DISK_CONFIGURED;
+               goto fail;
+       }
+
+       /* allocation not in the IO path, cqueue thread context */
+       nbc = kzalloc(sizeof(struct drbd_backing_dev), GFP_KERNEL);
+       if (!nbc) {
+               retcode = ERR_NOMEM;
+               goto fail;
+       }
+
+       nbc->dc.disk_size     = DRBD_DISK_SIZE_SECT_DEF;
+       nbc->dc.on_io_error   = DRBD_ON_IO_ERROR_DEF;
+       nbc->dc.fencing       = DRBD_FENCING_DEF;
+       nbc->dc.max_bio_bvecs = DRBD_MAX_BIO_BVECS_DEF;
+
+       if (!disk_conf_from_tags(mdev, nlp->tag_list, &nbc->dc)) {
+               retcode = ERR_MANDATORY_TAG;
+               goto fail;
+       }
+
+       if (nbc->dc.meta_dev_idx < DRBD_MD_INDEX_FLEX_INT) {
+               retcode = ERR_MD_IDX_INVALID;
+               goto fail;
+       }
+
+       nbc->lo_file = filp_open(nbc->dc.backing_dev, O_RDWR, 0);
+       if (IS_ERR(nbc->lo_file)) {
+               dev_err(DEV, "open(\"%s\") failed with %ld\n", nbc->dc.backing_dev,
+                   PTR_ERR(nbc->lo_file));
+               nbc->lo_file = NULL;
+               retcode = ERR_OPEN_DISK;
+               goto fail;
+       }
+
+       inode = nbc->lo_file->f_dentry->d_inode;
+
+       if (!S_ISBLK(inode->i_mode)) {
+               retcode = ERR_DISK_NOT_BDEV;
+               goto fail;
+       }
+
+       nbc->md_file = filp_open(nbc->dc.meta_dev, O_RDWR, 0);
+       if (IS_ERR(nbc->md_file)) {
+               dev_err(DEV, "open(\"%s\") failed with %ld\n", nbc->dc.meta_dev,
+                   PTR_ERR(nbc->md_file));
+               nbc->md_file = NULL;
+               retcode = ERR_OPEN_MD_DISK;
+               goto fail;
+       }
+
+       inode2 = nbc->md_file->f_dentry->d_inode;
+
+       if (!S_ISBLK(inode2->i_mode)) {
+               retcode = ERR_MD_NOT_BDEV;
+               goto fail;
+       }
+
+       nbc->backing_bdev = inode->i_bdev;
+       if (bd_claim(nbc->backing_bdev, mdev)) {
+               printk(KERN_ERR "drbd: bd_claim(%p,%p); failed [%p;%p;%u]\n",
+                      nbc->backing_bdev, mdev,
+                      nbc->backing_bdev->bd_holder,
+                      nbc->backing_bdev->bd_contains->bd_holder,
+                      nbc->backing_bdev->bd_holders);
+               retcode = ERR_BDCLAIM_DISK;
+               goto fail;
+       }
+
+       resync_lru = lc_create("resync", drbd_bm_ext_cache,
+                       61, sizeof(struct bm_extent),
+                       offsetof(struct bm_extent, lce));
+       if (!resync_lru) {
+               retcode = ERR_NOMEM;
+               goto release_bdev_fail;
+       }
+
+       /* meta_dev_idx >= 0: external fixed size,
+        * possibly multiple drbd sharing one meta device.
+        * TODO in that case, paranoia check that [md_bdev, meta_dev_idx] is
+        * not yet used by some other drbd minor!
+        * (if you use drbd.conf + drbdadm,
+        * that should check it for you already; but if you don't, or someone
+        * fooled it, we need to double check here) */
+       nbc->md_bdev = inode2->i_bdev;
+       if (bd_claim(nbc->md_bdev, (nbc->dc.meta_dev_idx < 0) ? (void *)mdev
+                               : (void *) drbd_m_holder)) {
+               retcode = ERR_BDCLAIM_MD_DISK;
+               goto release_bdev_fail;
+       }
+
+       if ((nbc->backing_bdev == nbc->md_bdev) !=
+           (nbc->dc.meta_dev_idx == DRBD_MD_INDEX_INTERNAL ||
+            nbc->dc.meta_dev_idx == DRBD_MD_INDEX_FLEX_INT)) {
+               retcode = ERR_MD_IDX_INVALID;
+               goto release_bdev2_fail;
+       }
+
+       /* RT - for drbd_get_max_capacity() DRBD_MD_INDEX_FLEX_INT */
+       drbd_md_set_sector_offsets(mdev, nbc);
+
+       if (drbd_get_max_capacity(nbc) < nbc->dc.disk_size) {
+               dev_err(DEV, "max capacity %llu smaller than disk size %llu\n",
+                       (unsigned long long) drbd_get_max_capacity(nbc),
+                       (unsigned long long) nbc->dc.disk_size);
+               retcode = ERR_DISK_TO_SMALL;
+               goto release_bdev2_fail;
+       }
+
+       if (nbc->dc.meta_dev_idx < 0) {
+               max_possible_sectors = DRBD_MAX_SECTORS_FLEX;
+               /* at least one MB, otherwise it does not make sense */
+               min_md_device_sectors = (2<<10);
+       } else {
+               max_possible_sectors = DRBD_MAX_SECTORS;
+               min_md_device_sectors = MD_RESERVED_SECT * (nbc->dc.meta_dev_idx + 1);
+       }
+
+       if (drbd_get_capacity(nbc->md_bdev) < min_md_device_sectors) {
+               retcode = ERR_MD_DISK_TO_SMALL;
+               dev_warn(DEV, "refusing attach: md-device too small, "
+                    "at least %llu sectors needed for this meta-disk type\n",
+                    (unsigned long long) min_md_device_sectors);
+               goto release_bdev2_fail;
+       }
+
+       /* Make sure the new disk is big enough
+        * (we may currently be R_PRIMARY with no local disk...) */
+       if (drbd_get_max_capacity(nbc) <
+           drbd_get_capacity(mdev->this_bdev)) {
+               retcode = ERR_DISK_TO_SMALL;
+               goto release_bdev2_fail;
+       }
+
+       nbc->known_size = drbd_get_capacity(nbc->backing_bdev);
+
+       if (nbc->known_size > max_possible_sectors) {
+               dev_warn(DEV, "==> truncating very big lower level device "
+                       "to currently maximum possible %llu sectors <==\n",
+                       (unsigned long long) max_possible_sectors);
+               if (nbc->dc.meta_dev_idx >= 0)
+                       dev_warn(DEV, "==>> using internal or flexible "
+                                     "meta data may help <<==\n");
+       }
+
+       drbd_suspend_io(mdev);
+       /* also wait for the last barrier ack. */
+       wait_event(mdev->misc_wait, !atomic_read(&mdev->ap_pending_cnt));
+       /* and for any other previously queued work */
+       drbd_flush_workqueue(mdev);
+
+       retcode = _drbd_request_state(mdev, NS(disk, D_ATTACHING), CS_VERBOSE);
+       drbd_resume_io(mdev);
+       if (retcode < SS_SUCCESS)
+               goto release_bdev2_fail;
+
+       if (!get_ldev_if_state(mdev, D_ATTACHING))
+               goto force_diskless;
+
+       drbd_md_set_sector_offsets(mdev, nbc);
+
+       if (!mdev->bitmap) {
+               if (drbd_bm_init(mdev)) {
+                       retcode = ERR_NOMEM;
+                       goto force_diskless_dec;
+               }
+       }
+
+       retcode = drbd_md_read(mdev, nbc);
+       if (retcode != NO_ERROR)
+               goto force_diskless_dec;
+
+       if (mdev->state.conn < C_CONNECTED &&
+           mdev->state.role == R_PRIMARY &&
+           (mdev->ed_uuid & ~((u64)1)) != (nbc->md.uuid[UI_CURRENT] & ~((u64)1))) {
+               dev_err(DEV, "Can only attach to data with current UUID=%016llX\n",
+                   (unsigned long long)mdev->ed_uuid);
+               retcode = ERR_DATA_NOT_CURRENT;
+               goto force_diskless_dec;
+       }
+
+       /* Since we are diskless, fix the activity log first... */
+       if (drbd_check_al_size(mdev)) {
+               retcode = ERR_NOMEM;
+               goto force_diskless_dec;
+       }
+
+       /* Prevent shrinking of consistent devices ! */
+       if (drbd_md_test_flag(nbc, MDF_CONSISTENT) &&
+          drbd_new_dev_size(mdev, nbc) < nbc->md.la_size_sect) {
+               dev_warn(DEV, "refusing to truncate a consistent device\n");
+               retcode = ERR_DISK_TO_SMALL;
+               goto force_diskless_dec;
+       }
+
+       if (!drbd_al_read_log(mdev, nbc)) {
+               retcode = ERR_IO_MD_DISK;
+               goto force_diskless_dec;
+       }
+
+       /* allocate a second IO page if logical_block_size != 512 */
+       logical_block_size = bdev_logical_block_size(nbc->md_bdev);
+       if (logical_block_size == 0)
+               logical_block_size = MD_SECTOR_SIZE;
+
+       if (logical_block_size != MD_SECTOR_SIZE) {
+               if (!mdev->md_io_tmpp) {
+                       struct page *page = alloc_page(GFP_NOIO);
+                       if (!page)
+                               goto force_diskless_dec;
+
+                       dev_warn(DEV, "Meta data's bdev logical_block_size = %d != %d\n",
+                            logical_block_size, MD_SECTOR_SIZE);
+                       dev_warn(DEV, "Workaround engaged (has performance impact).\n");
+
+                       mdev->md_io_tmpp = page;
+               }
+       }
+
+       /* Reset the "barriers don't work" bits here, then force meta data to
+        * be written, to ensure we determine if barriers are supported. */
+       if (nbc->dc.no_md_flush)
+               set_bit(MD_NO_BARRIER, &mdev->flags);
+       else
+               clear_bit(MD_NO_BARRIER, &mdev->flags);
+
+       /* Point of no return reached.
+        * Devices and memory are no longer released by error cleanup below.
+        * now mdev takes over responsibility, and the state engine should
+        * clean it up somewhere.  */
+       D_ASSERT(mdev->ldev == NULL);
+       mdev->ldev = nbc;
+       mdev->resync = resync_lru;
+       nbc = NULL;
+       resync_lru = NULL;
+
+       mdev->write_ordering = WO_bio_barrier;
+       drbd_bump_write_ordering(mdev, WO_bio_barrier);
+
+       if (drbd_md_test_flag(mdev->ldev, MDF_CRASHED_PRIMARY))
+               set_bit(CRASHED_PRIMARY, &mdev->flags);
+       else
+               clear_bit(CRASHED_PRIMARY, &mdev->flags);
+
+       if (drbd_md_test_flag(mdev->ldev, MDF_PRIMARY_IND)) {
+               set_bit(CRASHED_PRIMARY, &mdev->flags);
+               cp_discovered = 1;
+       }
+
+       mdev->send_cnt = 0;
+       mdev->recv_cnt = 0;
+       mdev->read_cnt = 0;
+       mdev->writ_cnt = 0;
+
+       drbd_setup_queue_param(mdev, DRBD_MAX_SEGMENT_SIZE);
+
+       /* If I am currently not R_PRIMARY,
+        * but meta data primary indicator is set,
+        * I just now recover from a hard crash,
+        * and have been R_PRIMARY before that crash.
+        *
+        * Now, if I had no connection before that crash
+        * (have been degraded R_PRIMARY), chances are that
+        * I won't find my peer now either.
+        *
+        * In that case, and _only_ in that case,
+        * we use the degr-wfc-timeout instead of the default,
+        * so we can automatically recover from a crash of a
+        * degraded but active "cluster" after a certain timeout.
+        */
+       clear_bit(USE_DEGR_WFC_T, &mdev->flags);
+       if (mdev->state.role != R_PRIMARY &&
+            drbd_md_test_flag(mdev->ldev, MDF_PRIMARY_IND) &&
+           !drbd_md_test_flag(mdev->ldev, MDF_CONNECTED_IND))
+               set_bit(USE_DEGR_WFC_T, &mdev->flags);
+
+       dd = drbd_determin_dev_size(mdev);
+       if (dd == dev_size_error) {
+               retcode = ERR_NOMEM_BITMAP;
+               goto force_diskless_dec;
+       } else if (dd == grew)
+               set_bit(RESYNC_AFTER_NEG, &mdev->flags);
+
+       if (drbd_md_test_flag(mdev->ldev, MDF_FULL_SYNC)) {
+               dev_info(DEV, "Assuming that all blocks are out of sync "
+                    "(aka FullSync)\n");
+               if (drbd_bitmap_io(mdev, &drbd_bmio_set_n_write, "set_n_write from attaching")) {
+                       retcode = ERR_IO_MD_DISK;
+                       goto force_diskless_dec;
+               }
+       } else {
+               if (drbd_bitmap_io(mdev, &drbd_bm_read, "read from attaching") < 0) {
+                       retcode = ERR_IO_MD_DISK;
+                       goto force_diskless_dec;
+               }
+       }
+
+       if (cp_discovered) {
+               drbd_al_apply_to_bm(mdev);
+               drbd_al_to_on_disk_bm(mdev);
+       }
+
+       spin_lock_irq(&mdev->req_lock);
+       os = mdev->state;
+       ns.i = os.i;
+       /* If MDF_CONSISTENT is not set go into inconsistent state,
+          otherwise investigate MDF_WasUpToDate...
+          If MDF_WAS_UP_TO_DATE is not set go into D_OUTDATED disk state,
+          otherwise into D_CONSISTENT state.
+       */
+       if (drbd_md_test_flag(mdev->ldev, MDF_CONSISTENT)) {
+               if (drbd_md_test_flag(mdev->ldev, MDF_WAS_UP_TO_DATE))
+                       ns.disk = D_CONSISTENT;
+               else
+                       ns.disk = D_OUTDATED;
+       } else {
+               ns.disk = D_INCONSISTENT;
+       }
+
+       if (drbd_md_test_flag(mdev->ldev, MDF_PEER_OUT_DATED))
+               ns.pdsk = D_OUTDATED;
+
+       if ( ns.disk == D_CONSISTENT &&
+           (ns.pdsk == D_OUTDATED || mdev->ldev->dc.fencing == FP_DONT_CARE))
+               ns.disk = D_UP_TO_DATE;
+
+       /* All tests on MDF_PRIMARY_IND, MDF_CONNECTED_IND,
+          MDF_CONSISTENT and MDF_WAS_UP_TO_DATE must happen before
+          this point, because drbd_request_state() modifies these
+          flags. */
+
+       /* In case we are C_CONNECTED postpone any decision on the new disk
+          state after the negotiation phase. */
+       if (mdev->state.conn == C_CONNECTED) {
+               mdev->new_state_tmp.i = ns.i;
+               ns.i = os.i;
+               ns.disk = D_NEGOTIATING;
+       }
+
+       rv = _drbd_set_state(mdev, ns, CS_VERBOSE, NULL);
+       ns = mdev->state;
+       spin_unlock_irq(&mdev->req_lock);
+
+       if (rv < SS_SUCCESS)
+               goto force_diskless_dec;
+
+       if (mdev->state.role == R_PRIMARY)
+               mdev->ldev->md.uuid[UI_CURRENT] |=  (u64)1;
+       else
+               mdev->ldev->md.uuid[UI_CURRENT] &= ~(u64)1;
+
+       drbd_md_mark_dirty(mdev);
+       drbd_md_sync(mdev);
+
+       kobject_uevent(&disk_to_dev(mdev->vdisk)->kobj, KOBJ_CHANGE);
+       put_ldev(mdev);
+       reply->ret_code = retcode;
+       drbd_reconfig_done(mdev);
+       return 0;
+
+ force_diskless_dec:
+       put_ldev(mdev);
+ force_diskless:
+       drbd_force_state(mdev, NS(disk, D_DISKLESS));
+       drbd_md_sync(mdev);
+ release_bdev2_fail:
+       if (nbc)
+               bd_release(nbc->md_bdev);
+ release_bdev_fail:
+       if (nbc)
+               bd_release(nbc->backing_bdev);
+ fail:
+       if (nbc) {
+               if (nbc->lo_file)
+                       fput(nbc->lo_file);
+               if (nbc->md_file)
+                       fput(nbc->md_file);
+               kfree(nbc);
+       }
+       lc_destroy(resync_lru);
+
+       reply->ret_code = retcode;
+       drbd_reconfig_done(mdev);
+       return 0;
+}
+
+static int drbd_nl_detach(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp,
+                         struct drbd_nl_cfg_reply *reply)
+{
+       reply->ret_code = drbd_request_state(mdev, NS(disk, D_DISKLESS));
+       return 0;
+}
+
+static int drbd_nl_net_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp,
+                           struct drbd_nl_cfg_reply *reply)
+{
+       int i, ns;
+       enum drbd_ret_codes retcode;
+       struct net_conf *new_conf = NULL;
+       struct crypto_hash *tfm = NULL;
+       struct crypto_hash *integrity_w_tfm = NULL;
+       struct crypto_hash *integrity_r_tfm = NULL;
+       struct hlist_head *new_tl_hash = NULL;
+       struct hlist_head *new_ee_hash = NULL;
+       struct drbd_conf *odev;
+       char hmac_name[CRYPTO_MAX_ALG_NAME];
+       void *int_dig_out = NULL;
+       void *int_dig_in = NULL;
+       void *int_dig_vv = NULL;
+       struct sockaddr *new_my_addr, *new_peer_addr, *taken_addr;
+
+       drbd_reconfig_start(mdev);
+
+       if (mdev->state.conn > C_STANDALONE) {
+               retcode = ERR_NET_CONFIGURED;
+               goto fail;
+       }
+
+       /* allocation not in the IO path, cqueue thread context */
+       new_conf = kmalloc(sizeof(struct net_conf), GFP_KERNEL);
+       if (!new_conf) {
+               retcode = ERR_NOMEM;
+               goto fail;
+       }
+
+       memset(new_conf, 0, sizeof(struct net_conf));
+       new_conf->timeout          = DRBD_TIMEOUT_DEF;
+       new_conf->try_connect_int  = DRBD_CONNECT_INT_DEF;
+       new_conf->ping_int         = DRBD_PING_INT_DEF;
+       new_conf->max_epoch_size   = DRBD_MAX_EPOCH_SIZE_DEF;
+       new_conf->max_buffers      = DRBD_MAX_BUFFERS_DEF;
+       new_conf->unplug_watermark = DRBD_UNPLUG_WATERMARK_DEF;
+       new_conf->sndbuf_size      = DRBD_SNDBUF_SIZE_DEF;
+       new_conf->rcvbuf_size      = DRBD_RCVBUF_SIZE_DEF;
+       new_conf->ko_count         = DRBD_KO_COUNT_DEF;
+       new_conf->after_sb_0p      = DRBD_AFTER_SB_0P_DEF;
+       new_conf->after_sb_1p      = DRBD_AFTER_SB_1P_DEF;
+       new_conf->after_sb_2p      = DRBD_AFTER_SB_2P_DEF;
+       new_conf->want_lose        = 0;
+       new_conf->two_primaries    = 0;
+       new_conf->wire_protocol    = DRBD_PROT_C;
+       new_conf->ping_timeo       = DRBD_PING_TIMEO_DEF;
+       new_conf->rr_conflict      = DRBD_RR_CONFLICT_DEF;
+
+       if (!net_conf_from_tags(mdev, nlp->tag_list, new_conf)) {
+               retcode = ERR_MANDATORY_TAG;
+               goto fail;
+       }
+
+       if (new_conf->two_primaries
+           && (new_conf->wire_protocol != DRBD_PROT_C)) {
+               retcode = ERR_NOT_PROTO_C;
+               goto fail;
+       };
+
+       if (mdev->state.role == R_PRIMARY && new_conf->want_lose) {
+               retcode = ERR_DISCARD;
+               goto fail;
+       }
+
+       retcode = NO_ERROR;
+
+       new_my_addr = (struct sockaddr *)&new_conf->my_addr;
+       new_peer_addr = (struct sockaddr *)&new_conf->peer_addr;
+       for (i = 0; i < minor_count; i++) {
+               odev = minor_to_mdev(i);
+               if (!odev || odev == mdev)
+                       continue;
+               if (get_net_conf(odev)) {
+                       taken_addr = (struct sockaddr *)&odev->net_conf->my_addr;
+                       if (new_conf->my_addr_len == odev->net_conf->my_addr_len &&
+                           !memcmp(new_my_addr, taken_addr, new_conf->my_addr_len))
+                               retcode = ERR_LOCAL_ADDR;
+
+                       taken_addr = (struct sockaddr *)&odev->net_conf->peer_addr;
+                       if (new_conf->peer_addr_len == odev->net_conf->peer_addr_len &&
+                           !memcmp(new_peer_addr, taken_addr, new_conf->peer_addr_len))
+                               retcode = ERR_PEER_ADDR;
+
+                       put_net_conf(odev);
+                       if (retcode != NO_ERROR)
+                               goto fail;
+               }
+       }
+
+       if (new_conf->cram_hmac_alg[0] != 0) {
+               snprintf(hmac_name, CRYPTO_MAX_ALG_NAME, "hmac(%s)",
+                       new_conf->cram_hmac_alg);
+               tfm = crypto_alloc_hash(hmac_name, 0, CRYPTO_ALG_ASYNC);
+               if (IS_ERR(tfm)) {
+                       tfm = NULL;
+                       retcode = ERR_AUTH_ALG;
+                       goto fail;
+               }
+
+               if (crypto_tfm_alg_type(crypto_hash_tfm(tfm))
+                                               != CRYPTO_ALG_TYPE_HASH) {
+                       retcode = ERR_AUTH_ALG_ND;
+                       goto fail;
+               }
+       }
+
+       if (new_conf->integrity_alg[0]) {
+               integrity_w_tfm = crypto_alloc_hash(new_conf->integrity_alg, 0, CRYPTO_ALG_ASYNC);
+               if (IS_ERR(integrity_w_tfm)) {
+                       integrity_w_tfm = NULL;
+                       retcode=ERR_INTEGRITY_ALG;
+                       goto fail;
+               }
+
+               if (!drbd_crypto_is_hash(crypto_hash_tfm(integrity_w_tfm))) {
+                       retcode=ERR_INTEGRITY_ALG_ND;
+                       goto fail;
+               }
+
+               integrity_r_tfm = crypto_alloc_hash(new_conf->integrity_alg, 0, CRYPTO_ALG_ASYNC);
+               if (IS_ERR(integrity_r_tfm)) {
+                       integrity_r_tfm = NULL;
+                       retcode=ERR_INTEGRITY_ALG;
+                       goto fail;
+               }
+       }
+
+       ns = new_conf->max_epoch_size/8;
+       if (mdev->tl_hash_s != ns) {
+               new_tl_hash = kzalloc(ns*sizeof(void *), GFP_KERNEL);
+               if (!new_tl_hash) {
+                       retcode = ERR_NOMEM;
+                       goto fail;
+               }
+       }
+
+       ns = new_conf->max_buffers/8;
+       if (new_conf->two_primaries && (mdev->ee_hash_s != ns)) {
+               new_ee_hash = kzalloc(ns*sizeof(void *), GFP_KERNEL);
+               if (!new_ee_hash) {
+                       retcode = ERR_NOMEM;
+                       goto fail;
+               }
+       }
+
+       ((char *)new_conf->shared_secret)[SHARED_SECRET_MAX-1] = 0;
+
+       if (integrity_w_tfm) {
+               i = crypto_hash_digestsize(integrity_w_tfm);
+               int_dig_out = kmalloc(i, GFP_KERNEL);
+               if (!int_dig_out) {
+                       retcode = ERR_NOMEM;
+                       goto fail;
+               }
+               int_dig_in = kmalloc(i, GFP_KERNEL);
+               if (!int_dig_in) {
+                       retcode = ERR_NOMEM;
+                       goto fail;
+               }
+               int_dig_vv = kmalloc(i, GFP_KERNEL);
+               if (!int_dig_vv) {
+                       retcode = ERR_NOMEM;
+                       goto fail;
+               }
+       }
+
+       if (!mdev->bitmap) {
+               if(drbd_bm_init(mdev)) {
+                       retcode = ERR_NOMEM;
+                       goto fail;
+               }
+       }
+
+       spin_lock_irq(&mdev->req_lock);
+       if (mdev->net_conf != NULL) {
+               retcode = ERR_NET_CONFIGURED;
+               spin_unlock_irq(&mdev->req_lock);
+               goto fail;
+       }
+       mdev->net_conf = new_conf;
+
+       mdev->send_cnt = 0;
+       mdev->recv_cnt = 0;
+
+       if (new_tl_hash) {
+               kfree(mdev->tl_hash);
+               mdev->tl_hash_s = mdev->net_conf->max_epoch_size/8;
+               mdev->tl_hash = new_tl_hash;
+       }
+
+       if (new_ee_hash) {
+               kfree(mdev->ee_hash);
+               mdev->ee_hash_s = mdev->net_conf->max_buffers/8;
+               mdev->ee_hash = new_ee_hash;
+       }
+
+       crypto_free_hash(mdev->cram_hmac_tfm);
+       mdev->cram_hmac_tfm = tfm;
+
+       crypto_free_hash(mdev->integrity_w_tfm);
+       mdev->integrity_w_tfm = integrity_w_tfm;
+
+       crypto_free_hash(mdev->integrity_r_tfm);
+       mdev->integrity_r_tfm = integrity_r_tfm;
+
+       kfree(mdev->int_dig_out);
+       kfree(mdev->int_dig_in);
+       kfree(mdev->int_dig_vv);
+       mdev->int_dig_out=int_dig_out;
+       mdev->int_dig_in=int_dig_in;
+       mdev->int_dig_vv=int_dig_vv;
+       spin_unlock_irq(&mdev->req_lock);
+
+       retcode = _drbd_request_state(mdev, NS(conn, C_UNCONNECTED), CS_VERBOSE);
+
+       kobject_uevent(&disk_to_dev(mdev->vdisk)->kobj, KOBJ_CHANGE);
+       reply->ret_code = retcode;
+       drbd_reconfig_done(mdev);
+       return 0;
+
+fail:
+       kfree(int_dig_out);
+       kfree(int_dig_in);
+       kfree(int_dig_vv);
+       crypto_free_hash(tfm);
+       crypto_free_hash(integrity_w_tfm);
+       crypto_free_hash(integrity_r_tfm);
+       kfree(new_tl_hash);
+       kfree(new_ee_hash);
+       kfree(new_conf);
+
+       reply->ret_code = retcode;
+       drbd_reconfig_done(mdev);
+       return 0;
+}
+
+static int drbd_nl_disconnect(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp,
+                             struct drbd_nl_cfg_reply *reply)
+{
+       int retcode;
+
+       retcode = _drbd_request_state(mdev, NS(conn, C_DISCONNECTING), CS_ORDERED);
+
+       if (retcode == SS_NOTHING_TO_DO)
+               goto done;
+       else if (retcode == SS_ALREADY_STANDALONE)
+               goto done;
+       else if (retcode == SS_PRIMARY_NOP) {
+               /* Our statche checking code wants to see the peer outdated. */
+               retcode = drbd_request_state(mdev, NS2(conn, C_DISCONNECTING,
+                                                     pdsk, D_OUTDATED));
+       } else if (retcode == SS_CW_FAILED_BY_PEER) {
+               /* The peer probably wants to see us outdated. */
+               retcode = _drbd_request_state(mdev, NS2(conn, C_DISCONNECTING,
+                                                       disk, D_OUTDATED),
+                                             CS_ORDERED);
+               if (retcode == SS_IS_DISKLESS || retcode == SS_LOWER_THAN_OUTDATED) {
+                       drbd_force_state(mdev, NS(conn, C_DISCONNECTING));
+                       retcode = SS_SUCCESS;
+               }
+       }
+
+       if (retcode < SS_SUCCESS)
+               goto fail;
+
+       if (wait_event_interruptible(mdev->state_wait,
+                                    mdev->state.conn != C_DISCONNECTING)) {
+               /* Do not test for mdev->state.conn == C_STANDALONE, since
+                  someone else might connect us in the mean time! */
+               retcode = ERR_INTR;
+               goto fail;
+       }
+
+ done:
+       retcode = NO_ERROR;
+ fail:
+       drbd_md_sync(mdev);
+       reply->ret_code = retcode;
+       return 0;
+}
+
+void resync_after_online_grow(struct drbd_conf *mdev)
+{
+       int iass; /* I am sync source */
+
+       dev_info(DEV, "Resync of new storage after online grow\n");
+       if (mdev->state.role != mdev->state.peer)
+               iass = (mdev->state.role == R_PRIMARY);
+       else
+               iass = test_bit(DISCARD_CONCURRENT, &mdev->flags);
+
+       if (iass)
+               drbd_start_resync(mdev, C_SYNC_SOURCE);
+       else
+               _drbd_request_state(mdev, NS(conn, C_WF_SYNC_UUID), CS_VERBOSE + CS_SERIALIZE);
+}
+
+static int drbd_nl_resize(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp,
+                         struct drbd_nl_cfg_reply *reply)
+{
+       struct resize rs;
+       int retcode = NO_ERROR;
+       int ldsc = 0; /* local disk size changed */
+       enum determine_dev_size dd;
+
+       memset(&rs, 0, sizeof(struct resize));
+       if (!resize_from_tags(mdev, nlp->tag_list, &rs)) {
+               retcode = ERR_MANDATORY_TAG;
+               goto fail;
+       }
+
+       if (mdev->state.conn > C_CONNECTED) {
+               retcode = ERR_RESIZE_RESYNC;
+               goto fail;
+       }
+
+       if (mdev->state.role == R_SECONDARY &&
+           mdev->state.peer == R_SECONDARY) {
+               retcode = ERR_NO_PRIMARY;
+               goto fail;
+       }
+
+       if (!get_ldev(mdev)) {
+               retcode = ERR_NO_DISK;
+               goto fail;
+       }
+
+       if (mdev->ldev->known_size != drbd_get_capacity(mdev->ldev->backing_bdev)) {
+               mdev->ldev->known_size = drbd_get_capacity(mdev->ldev->backing_bdev);
+               ldsc = 1;
+       }
+
+       mdev->ldev->dc.disk_size = (sector_t)rs.resize_size;
+       dd = drbd_determin_dev_size(mdev);
+       drbd_md_sync(mdev);
+       put_ldev(mdev);
+       if (dd == dev_size_error) {
+               retcode = ERR_NOMEM_BITMAP;
+               goto fail;
+       }
+
+       if (mdev->state.conn == C_CONNECTED && (dd != unchanged || ldsc)) {
+               if (dd == grew)
+                       set_bit(RESIZE_PENDING, &mdev->flags);
+
+               drbd_send_uuids(mdev);
+               drbd_send_sizes(mdev, 1);
+       }
+
+ fail:
+       reply->ret_code = retcode;
+       return 0;
+}
+
+static int drbd_nl_syncer_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp,
+                              struct drbd_nl_cfg_reply *reply)
+{
+       int retcode = NO_ERROR;
+       int err;
+       int ovr; /* online verify running */
+       int rsr; /* re-sync running */
+       struct crypto_hash *verify_tfm = NULL;
+       struct crypto_hash *csums_tfm = NULL;
+       struct syncer_conf sc;
+       cpumask_var_t new_cpu_mask;
+
+       if (!zalloc_cpumask_var(&new_cpu_mask, GFP_KERNEL)) {
+               retcode = ERR_NOMEM;
+               goto fail;
+       }
+
+       if (nlp->flags & DRBD_NL_SET_DEFAULTS) {
+               memset(&sc, 0, sizeof(struct syncer_conf));
+               sc.rate       = DRBD_RATE_DEF;
+               sc.after      = DRBD_AFTER_DEF;
+               sc.al_extents = DRBD_AL_EXTENTS_DEF;
+       } else
+               memcpy(&sc, &mdev->sync_conf, sizeof(struct syncer_conf));
+
+       if (!syncer_conf_from_tags(mdev, nlp->tag_list, &sc)) {
+               retcode = ERR_MANDATORY_TAG;
+               goto fail;
+       }
+
+       /* re-sync running */
+       rsr = ( mdev->state.conn == C_SYNC_SOURCE ||
+               mdev->state.conn == C_SYNC_TARGET ||
+               mdev->state.conn == C_PAUSED_SYNC_S ||
+               mdev->state.conn == C_PAUSED_SYNC_T );
+
+       if (rsr && strcmp(sc.csums_alg, mdev->sync_conf.csums_alg)) {
+               retcode = ERR_CSUMS_RESYNC_RUNNING;
+               goto fail;
+       }
+
+       if (!rsr && sc.csums_alg[0]) {
+               csums_tfm = crypto_alloc_hash(sc.csums_alg, 0, CRYPTO_ALG_ASYNC);
+               if (IS_ERR(csums_tfm)) {
+                       csums_tfm = NULL;
+                       retcode = ERR_CSUMS_ALG;
+                       goto fail;
+               }
+
+               if (!drbd_crypto_is_hash(crypto_hash_tfm(csums_tfm))) {
+                       retcode = ERR_CSUMS_ALG_ND;
+                       goto fail;
+               }
+       }
+
+       /* online verify running */
+       ovr = (mdev->state.conn == C_VERIFY_S || mdev->state.conn == C_VERIFY_T);
+
+       if (ovr) {
+               if (strcmp(sc.verify_alg, mdev->sync_conf.verify_alg)) {
+                       retcode = ERR_VERIFY_RUNNING;
+                       goto fail;
+               }
+       }
+
+       if (!ovr && sc.verify_alg[0]) {
+               verify_tfm = crypto_alloc_hash(sc.verify_alg, 0, CRYPTO_ALG_ASYNC);
+               if (IS_ERR(verify_tfm)) {
+                       verify_tfm = NULL;
+                       retcode = ERR_VERIFY_ALG;
+                       goto fail;
+               }
+
+               if (!drbd_crypto_is_hash(crypto_hash_tfm(verify_tfm))) {
+                       retcode = ERR_VERIFY_ALG_ND;
+                       goto fail;
+               }
+       }
+
+       /* silently ignore cpu mask on UP kernel */
+       if (nr_cpu_ids > 1 && sc.cpu_mask[0] != 0) {
+               err = __bitmap_parse(sc.cpu_mask, 32, 0,
+                               cpumask_bits(new_cpu_mask), nr_cpu_ids);
+               if (err) {
+                       dev_warn(DEV, "__bitmap_parse() failed with %d\n", err);
+                       retcode = ERR_CPU_MASK_PARSE;
+                       goto fail;
+               }
+       }
+
+       ERR_IF (sc.rate < 1) sc.rate = 1;
+       ERR_IF (sc.al_extents < 7) sc.al_extents = 127; /* arbitrary minimum */
+#define AL_MAX ((MD_AL_MAX_SIZE-1) * AL_EXTENTS_PT)
+       if (sc.al_extents > AL_MAX) {
+               dev_err(DEV, "sc.al_extents > %d\n", AL_MAX);
+               sc.al_extents = AL_MAX;
+       }
+#undef AL_MAX
+
+       /* most sanity checks done, try to assign the new sync-after
+        * dependency.  need to hold the global lock in there,
+        * to avoid a race in the dependency loop check. */
+       retcode = drbd_alter_sa(mdev, sc.after);
+       if (retcode != NO_ERROR)
+               goto fail;
+
+       /* ok, assign the rest of it as well.
+        * lock against receive_SyncParam() */
+       spin_lock(&mdev->peer_seq_lock);
+       mdev->sync_conf = sc;
+
+       if (!rsr) {
+               crypto_free_hash(mdev->csums_tfm);
+               mdev->csums_tfm = csums_tfm;
+               csums_tfm = NULL;
+       }
+
+       if (!ovr) {
+               crypto_free_hash(mdev->verify_tfm);
+               mdev->verify_tfm = verify_tfm;
+               verify_tfm = NULL;
+       }
+       spin_unlock(&mdev->peer_seq_lock);
+
+       if (get_ldev(mdev)) {
+               wait_event(mdev->al_wait, lc_try_lock(mdev->act_log));
+               drbd_al_shrink(mdev);
+               err = drbd_check_al_size(mdev);
+               lc_unlock(mdev->act_log);
+               wake_up(&mdev->al_wait);
+
+               put_ldev(mdev);
+               drbd_md_sync(mdev);
+
+               if (err) {
+                       retcode = ERR_NOMEM;
+                       goto fail;
+               }
+       }
+
+       if (mdev->state.conn >= C_CONNECTED)
+               drbd_send_sync_param(mdev, &sc);
+
+       if (!cpumask_equal(mdev->cpu_mask, new_cpu_mask)) {
+               cpumask_copy(mdev->cpu_mask, new_cpu_mask);
+               drbd_calc_cpu_mask(mdev);
+               mdev->receiver.reset_cpu_mask = 1;
+               mdev->asender.reset_cpu_mask = 1;
+               mdev->worker.reset_cpu_mask = 1;
+       }
+
+       kobject_uevent(&disk_to_dev(mdev->vdisk)->kobj, KOBJ_CHANGE);
+fail:
+       free_cpumask_var(new_cpu_mask);
+       crypto_free_hash(csums_tfm);
+       crypto_free_hash(verify_tfm);
+       reply->ret_code = retcode;
+       return 0;
+}
+
+static int drbd_nl_invalidate(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp,
+                             struct drbd_nl_cfg_reply *reply)
+{
+       int retcode;
+
+       retcode = _drbd_request_state(mdev, NS(conn, C_STARTING_SYNC_T), CS_ORDERED);
+
+       if (retcode < SS_SUCCESS && retcode != SS_NEED_CONNECTION)
+               retcode = drbd_request_state(mdev, NS(conn, C_STARTING_SYNC_T));
+
+       while (retcode == SS_NEED_CONNECTION) {
+               spin_lock_irq(&mdev->req_lock);
+               if (mdev->state.conn < C_CONNECTED)
+                       retcode = _drbd_set_state(_NS(mdev, disk, D_INCONSISTENT), CS_VERBOSE, NULL);
+               spin_unlock_irq(&mdev->req_lock);
+
+               if (retcode != SS_NEED_CONNECTION)
+                       break;
+
+               retcode = drbd_request_state(mdev, NS(conn, C_STARTING_SYNC_T));
+       }
+
+       reply->ret_code = retcode;
+       return 0;
+}
+
+static int drbd_nl_invalidate_peer(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp,
+                                  struct drbd_nl_cfg_reply *reply)
+{
+
+       reply->ret_code = drbd_request_state(mdev, NS(conn, C_STARTING_SYNC_S));
+
+       return 0;
+}
+
+static int drbd_nl_pause_sync(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp,
+                             struct drbd_nl_cfg_reply *reply)
+{
+       int retcode = NO_ERROR;
+
+       if (drbd_request_state(mdev, NS(user_isp, 1)) == SS_NOTHING_TO_DO)
+               retcode = ERR_PAUSE_IS_SET;
+
+       reply->ret_code = retcode;
+       return 0;
+}
+
+static int drbd_nl_resume_sync(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp,
+                              struct drbd_nl_cfg_reply *reply)
+{
+       int retcode = NO_ERROR;
+
+       if (drbd_request_state(mdev, NS(user_isp, 0)) == SS_NOTHING_TO_DO)
+               retcode = ERR_PAUSE_IS_CLEAR;
+
+       reply->ret_code = retcode;
+       return 0;
+}
+
+static int drbd_nl_suspend_io(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp,
+                             struct drbd_nl_cfg_reply *reply)
+{
+       reply->ret_code = drbd_request_state(mdev, NS(susp, 1));
+
+       return 0;
+}
+
+static int drbd_nl_resume_io(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp,
+                            struct drbd_nl_cfg_reply *reply)
+{
+       reply->ret_code = drbd_request_state(mdev, NS(susp, 0));
+       return 0;
+}
+
+static int drbd_nl_outdate(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp,
+                          struct drbd_nl_cfg_reply *reply)
+{
+       reply->ret_code = drbd_request_state(mdev, NS(disk, D_OUTDATED));
+       return 0;
+}
+
+static int drbd_nl_get_config(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp,
+                          struct drbd_nl_cfg_reply *reply)
+{
+       unsigned short *tl;
+
+       tl = reply->tag_list;
+
+       if (get_ldev(mdev)) {
+               tl = disk_conf_to_tags(mdev, &mdev->ldev->dc, tl);
+               put_ldev(mdev);
+       }
+
+       if (get_net_conf(mdev)) {
+               tl = net_conf_to_tags(mdev, mdev->net_conf, tl);
+               put_net_conf(mdev);
+       }
+       tl = syncer_conf_to_tags(mdev, &mdev->sync_conf, tl);
+
+       put_unaligned(TT_END, tl++); /* Close the tag list */
+
+       return (int)((char *)tl - (char *)reply->tag_list);
+}
+
+static int drbd_nl_get_state(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp,
+                            struct drbd_nl_cfg_reply *reply)
+{
+       unsigned short *tl = reply->tag_list;
+       union drbd_state s = mdev->state;
+       unsigned long rs_left;
+       unsigned int res;
+
+       tl = get_state_to_tags(mdev, (struct get_state *)&s, tl);
+
+       /* no local ref, no bitmap, no syncer progress. */
+       if (s.conn >= C_SYNC_SOURCE && s.conn <= C_PAUSED_SYNC_T) {
+               if (get_ldev(mdev)) {
+                       drbd_get_syncer_progress(mdev, &rs_left, &res);
+                       tl = tl_add_int(tl, T_sync_progress, &res);
+                       put_ldev(mdev);
+               }
+       }
+       put_unaligned(TT_END, tl++); /* Close the tag list */
+
+       return (int)((char *)tl - (char *)reply->tag_list);
+}
+
+static int drbd_nl_get_uuids(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp,
+                            struct drbd_nl_cfg_reply *reply)
+{
+       unsigned short *tl;
+
+       tl = reply->tag_list;
+
+       if (get_ldev(mdev)) {
+               tl = tl_add_blob(tl, T_uuids, mdev->ldev->md.uuid, UI_SIZE*sizeof(u64));
+               tl = tl_add_int(tl, T_uuids_flags, &mdev->ldev->md.flags);
+               put_ldev(mdev);
+       }
+       put_unaligned(TT_END, tl++); /* Close the tag list */
+
+       return (int)((char *)tl - (char *)reply->tag_list);
+}
+
+/**
+ * drbd_nl_get_timeout_flag() - Used by drbdsetup to find out which timeout value to use
+ * @mdev:      DRBD device.
+ * @nlp:       Netlink/connector packet from drbdsetup
+ * @reply:     Reply packet for drbdsetup
+ */
+static int drbd_nl_get_timeout_flag(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp,
+                                   struct drbd_nl_cfg_reply *reply)
+{
+       unsigned short *tl;
+       char rv;
+
+       tl = reply->tag_list;
+
+       rv = mdev->state.pdsk == D_OUTDATED        ? UT_PEER_OUTDATED :
+         test_bit(USE_DEGR_WFC_T, &mdev->flags) ? UT_DEGRADED : UT_DEFAULT;
+
+       tl = tl_add_blob(tl, T_use_degraded, &rv, sizeof(rv));
+       put_unaligned(TT_END, tl++); /* Close the tag list */
+
+       return (int)((char *)tl - (char *)reply->tag_list);
+}
+
+static int drbd_nl_start_ov(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp,
+                                   struct drbd_nl_cfg_reply *reply)
+{
+       /* default to resume from last known position, if possible */
+       struct start_ov args =
+               { .start_sector = mdev->ov_start_sector };
+
+       if (!start_ov_from_tags(mdev, nlp->tag_list, &args)) {
+               reply->ret_code = ERR_MANDATORY_TAG;
+               return 0;
+       }
+       /* w_make_ov_request expects position to be aligned */
+       mdev->ov_start_sector = args.start_sector & ~BM_SECT_PER_BIT;
+       reply->ret_code = drbd_request_state(mdev,NS(conn,C_VERIFY_S));
+       return 0;
+}
+
+
+static int drbd_nl_new_c_uuid(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp,
+                             struct drbd_nl_cfg_reply *reply)
+{
+       int retcode = NO_ERROR;
+       int skip_initial_sync = 0;
+       int err;
+
+       struct new_c_uuid args;
+
+       memset(&args, 0, sizeof(struct new_c_uuid));
+       if (!new_c_uuid_from_tags(mdev, nlp->tag_list, &args)) {
+               reply->ret_code = ERR_MANDATORY_TAG;
+               return 0;
+       }
+
+       mutex_lock(&mdev->state_mutex); /* Protects us against serialized state changes. */
+
+       if (!get_ldev(mdev)) {
+               retcode = ERR_NO_DISK;
+               goto out;
+       }
+
+       /* this is "skip initial sync", assume to be clean */
+       if (mdev->state.conn == C_CONNECTED && mdev->agreed_pro_version >= 90 &&
+           mdev->ldev->md.uuid[UI_CURRENT] == UUID_JUST_CREATED && args.clear_bm) {
+               dev_info(DEV, "Preparing to skip initial sync\n");
+               skip_initial_sync = 1;
+       } else if (mdev->state.conn != C_STANDALONE) {
+               retcode = ERR_CONNECTED;
+               goto out_dec;
+       }
+
+       drbd_uuid_set(mdev, UI_BITMAP, 0); /* Rotate UI_BITMAP to History 1, etc... */
+       drbd_uuid_new_current(mdev); /* New current, previous to UI_BITMAP */
+
+       if (args.clear_bm) {
+               err = drbd_bitmap_io(mdev, &drbd_bmio_clear_n_write, "clear_n_write from new_c_uuid");
+               if (err) {
+                       dev_err(DEV, "Writing bitmap failed with %d\n",err);
+                       retcode = ERR_IO_MD_DISK;
+               }
+               if (skip_initial_sync) {
+                       drbd_send_uuids_skip_initial_sync(mdev);
+                       _drbd_uuid_set(mdev, UI_BITMAP, 0);
+                       spin_lock_irq(&mdev->req_lock);
+                       _drbd_set_state(_NS2(mdev, disk, D_UP_TO_DATE, pdsk, D_UP_TO_DATE),
+                                       CS_VERBOSE, NULL);
+                       spin_unlock_irq(&mdev->req_lock);
+               }
+       }
+
+       drbd_md_sync(mdev);
+out_dec:
+       put_ldev(mdev);
+out:
+       mutex_unlock(&mdev->state_mutex);
+
+       reply->ret_code = retcode;
+       return 0;
+}
+
+static struct drbd_conf *ensure_mdev(struct drbd_nl_cfg_req *nlp)
+{
+       struct drbd_conf *mdev;
+
+       if (nlp->drbd_minor >= minor_count)
+               return NULL;
+
+       mdev = minor_to_mdev(nlp->drbd_minor);
+
+       if (!mdev && (nlp->flags & DRBD_NL_CREATE_DEVICE)) {
+               struct gendisk *disk = NULL;
+               mdev = drbd_new_device(nlp->drbd_minor);
+
+               spin_lock_irq(&drbd_pp_lock);
+               if (minor_table[nlp->drbd_minor] == NULL) {
+                       minor_table[nlp->drbd_minor] = mdev;
+                       disk = mdev->vdisk;
+                       mdev = NULL;
+               } /* else: we lost the race */
+               spin_unlock_irq(&drbd_pp_lock);
+
+               if (disk) /* we won the race above */
+                       /* in case we ever add a drbd_delete_device(),
+                        * don't forget the del_gendisk! */
+                       add_disk(disk);
+               else /* we lost the race above */
+                       drbd_free_mdev(mdev);
+
+               mdev = minor_to_mdev(nlp->drbd_minor);
+       }
+
+       return mdev;
+}
+
+struct cn_handler_struct {
+       int (*function)(struct drbd_conf *,
+                        struct drbd_nl_cfg_req *,
+                        struct drbd_nl_cfg_reply *);
+       int reply_body_size;
+};
+
+static struct cn_handler_struct cnd_table[] = {
+       [ P_primary ]           = { &drbd_nl_primary,           0 },
+       [ P_secondary ]         = { &drbd_nl_secondary,         0 },
+       [ P_disk_conf ]         = { &drbd_nl_disk_conf,         0 },
+       [ P_detach ]            = { &drbd_nl_detach,            0 },
+       [ P_net_conf ]          = { &drbd_nl_net_conf,          0 },
+       [ P_disconnect ]        = { &drbd_nl_disconnect,        0 },
+       [ P_resize ]            = { &drbd_nl_resize,            0 },
+       [ P_syncer_conf ]       = { &drbd_nl_syncer_conf,       0 },
+       [ P_invalidate ]        = { &drbd_nl_invalidate,        0 },
+       [ P_invalidate_peer ]   = { &drbd_nl_invalidate_peer,   0 },
+       [ P_pause_sync ]        = { &drbd_nl_pause_sync,        0 },
+       [ P_resume_sync ]       = { &drbd_nl_resume_sync,       0 },
+       [ P_suspend_io ]        = { &drbd_nl_suspend_io,        0 },
+       [ P_resume_io ]         = { &drbd_nl_resume_io,         0 },
+       [ P_outdate ]           = { &drbd_nl_outdate,           0 },
+       [ P_get_config ]        = { &drbd_nl_get_config,
+                                   sizeof(struct syncer_conf_tag_len_struct) +
+                                   sizeof(struct disk_conf_tag_len_struct) +
+                                   sizeof(struct net_conf_tag_len_struct) },
+       [ P_get_state ]         = { &drbd_nl_get_state,
+                                   sizeof(struct get_state_tag_len_struct) +
+                                   sizeof(struct sync_progress_tag_len_struct) },
+       [ P_get_uuids ]         = { &drbd_nl_get_uuids,
+                                   sizeof(struct get_uuids_tag_len_struct) },
+       [ P_get_timeout_flag ]  = { &drbd_nl_get_timeout_flag,
+                                   sizeof(struct get_timeout_flag_tag_len_struct)},
+       [ P_start_ov ]          = { &drbd_nl_start_ov,          0 },
+       [ P_new_c_uuid ]        = { &drbd_nl_new_c_uuid,        0 },
+};
+
+static void drbd_connector_callback(struct cn_msg *req, struct netlink_skb_parms *nsp)
+{
+       struct drbd_nl_cfg_req *nlp = (struct drbd_nl_cfg_req *)req->data;
+       struct cn_handler_struct *cm;
+       struct cn_msg *cn_reply;
+       struct drbd_nl_cfg_reply *reply;
+       struct drbd_conf *mdev;
+       int retcode, rr;
+       int reply_size = sizeof(struct cn_msg)
+               + sizeof(struct drbd_nl_cfg_reply)
+               + sizeof(short int);
+
+       if (!try_module_get(THIS_MODULE)) {
+               printk(KERN_ERR "drbd: try_module_get() failed!\n");
+               return;
+       }
+
+       if (!cap_raised(nsp->eff_cap, CAP_SYS_ADMIN)) {
+               retcode = ERR_PERM;
+               goto fail;
+       }
+
+       mdev = ensure_mdev(nlp);
+       if (!mdev) {
+               retcode = ERR_MINOR_INVALID;
+               goto fail;
+       }
+
+       if (nlp->packet_type >= P_nl_after_last_packet) {
+               retcode = ERR_PACKET_NR;
+               goto fail;
+       }
+
+       cm = cnd_table + nlp->packet_type;
+
+       /* This may happen if packet number is 0: */
+       if (cm->function == NULL) {
+               retcode = ERR_PACKET_NR;
+               goto fail;
+       }
+
+       reply_size += cm->reply_body_size;
+
+       /* allocation not in the IO path, cqueue thread context */
+       cn_reply = kmalloc(reply_size, GFP_KERNEL);
+       if (!cn_reply) {
+               retcode = ERR_NOMEM;
+               goto fail;
+       }
+       reply = (struct drbd_nl_cfg_reply *) cn_reply->data;
+
+       reply->packet_type =
+               cm->reply_body_size ? nlp->packet_type : P_nl_after_last_packet;
+       reply->minor = nlp->drbd_minor;
+       reply->ret_code = NO_ERROR; /* Might by modified by cm->function. */
+       /* reply->tag_list; might be modified by cm->function. */
+
+       rr = cm->function(mdev, nlp, reply);
+
+       cn_reply->id = req->id;
+       cn_reply->seq = req->seq;
+       cn_reply->ack = req->ack  + 1;
+       cn_reply->len = sizeof(struct drbd_nl_cfg_reply) + rr;
+       cn_reply->flags = 0;
+
+       rr = cn_netlink_send(cn_reply, CN_IDX_DRBD, GFP_KERNEL);
+       if (rr && rr != -ESRCH)
+               printk(KERN_INFO "drbd: cn_netlink_send()=%d\n", rr);
+
+       kfree(cn_reply);
+       module_put(THIS_MODULE);
+       return;
+ fail:
+       drbd_nl_send_reply(req, retcode);
+       module_put(THIS_MODULE);
+}
+
+static atomic_t drbd_nl_seq = ATOMIC_INIT(2); /* two. */
+
+static unsigned short *
+__tl_add_blob(unsigned short *tl, enum drbd_tags tag, const void *data,
+       unsigned short len, int nul_terminated)
+{
+       unsigned short l = tag_descriptions[tag_number(tag)].max_len;
+       len = (len < l) ? len :  l;
+       put_unaligned(tag, tl++);
+       put_unaligned(len, tl++);
+       memcpy(tl, data, len);
+       tl = (unsigned short*)((char*)tl + len);
+       if (nul_terminated)
+               *((char*)tl - 1) = 0;
+       return tl;
+}
+
+static unsigned short *
+tl_add_blob(unsigned short *tl, enum drbd_tags tag, const void *data, int len)
+{
+       return __tl_add_blob(tl, tag, data, len, 0);
+}
+
+static unsigned short *
+tl_add_str(unsigned short *tl, enum drbd_tags tag, const char *str)
+{
+       return __tl_add_blob(tl, tag, str, strlen(str)+1, 0);
+}
+
+static unsigned short *
+tl_add_int(unsigned short *tl, enum drbd_tags tag, const void *val)
+{
+       put_unaligned(tag, tl++);
+       switch(tag_type(tag)) {
+       case TT_INTEGER:
+               put_unaligned(sizeof(int), tl++);
+               put_unaligned(*(int *)val, (int *)tl);
+               tl = (unsigned short*)((char*)tl+sizeof(int));
+               break;
+       case TT_INT64:
+               put_unaligned(sizeof(u64), tl++);
+               put_unaligned(*(u64 *)val, (u64 *)tl);
+               tl = (unsigned short*)((char*)tl+sizeof(u64));
+               break;
+       default:
+               /* someone did something stupid. */
+               ;
+       }
+       return tl;
+}
+
+void drbd_bcast_state(struct drbd_conf *mdev, union drbd_state state)
+{
+       char buffer[sizeof(struct cn_msg)+
+                   sizeof(struct drbd_nl_cfg_reply)+
+                   sizeof(struct get_state_tag_len_struct)+
+                   sizeof(short int)];
+       struct cn_msg *cn_reply = (struct cn_msg *) buffer;
+       struct drbd_nl_cfg_reply *reply =
+               (struct drbd_nl_cfg_reply *)cn_reply->data;
+       unsigned short *tl = reply->tag_list;
+
+       /* dev_warn(DEV, "drbd_bcast_state() got called\n"); */
+
+       tl = get_state_to_tags(mdev, (struct get_state *)&state, tl);
+
+       put_unaligned(TT_END, tl++); /* Close the tag list */
+
+       cn_reply->id.idx = CN_IDX_DRBD;
+       cn_reply->id.val = CN_VAL_DRBD;
+
+       cn_reply->seq = atomic_add_return(1, &drbd_nl_seq);
+       cn_reply->ack = 0; /* not used here. */
+       cn_reply->len = sizeof(struct drbd_nl_cfg_reply) +
+               (int)((char *)tl - (char *)reply->tag_list);
+       cn_reply->flags = 0;
+
+       reply->packet_type = P_get_state;
+       reply->minor = mdev_to_minor(mdev);
+       reply->ret_code = NO_ERROR;
+
+       cn_netlink_send(cn_reply, CN_IDX_DRBD, GFP_NOIO);
+}
+
+void drbd_bcast_ev_helper(struct drbd_conf *mdev, char *helper_name)
+{
+       char buffer[sizeof(struct cn_msg)+
+                   sizeof(struct drbd_nl_cfg_reply)+
+                   sizeof(struct call_helper_tag_len_struct)+
+                   sizeof(short int)];
+       struct cn_msg *cn_reply = (struct cn_msg *) buffer;
+       struct drbd_nl_cfg_reply *reply =
+               (struct drbd_nl_cfg_reply *)cn_reply->data;
+       unsigned short *tl = reply->tag_list;
+
+       /* dev_warn(DEV, "drbd_bcast_state() got called\n"); */
+
+       tl = tl_add_str(tl, T_helper, helper_name);
+       put_unaligned(TT_END, tl++); /* Close the tag list */
+
+       cn_reply->id.idx = CN_IDX_DRBD;
+       cn_reply->id.val = CN_VAL_DRBD;
+
+       cn_reply->seq = atomic_add_return(1, &drbd_nl_seq);
+       cn_reply->ack = 0; /* not used here. */
+       cn_reply->len = sizeof(struct drbd_nl_cfg_reply) +
+               (int)((char *)tl - (char *)reply->tag_list);
+       cn_reply->flags = 0;
+
+       reply->packet_type = P_call_helper;
+       reply->minor = mdev_to_minor(mdev);
+       reply->ret_code = NO_ERROR;
+
+       cn_netlink_send(cn_reply, CN_IDX_DRBD, GFP_NOIO);
+}
+
+void drbd_bcast_ee(struct drbd_conf *mdev,
+               const char *reason, const int dgs,
+               const char* seen_hash, const char* calc_hash,
+               const struct drbd_epoch_entry* e)
+{
+       struct cn_msg *cn_reply;
+       struct drbd_nl_cfg_reply *reply;
+       struct bio_vec *bvec;
+       unsigned short *tl;
+       int i;
+
+       if (!e)
+               return;
+       if (!reason || !reason[0])
+               return;
+
+       /* apparently we have to memcpy twice, first to prepare the data for the
+        * struct cn_msg, then within cn_netlink_send from the cn_msg to the
+        * netlink skb. */
+       /* receiver thread context, which is not in the writeout path (of this node),
+        * but may be in the writeout path of the _other_ node.
+        * GFP_NOIO to avoid potential "distributed deadlock". */
+       cn_reply = kmalloc(
+               sizeof(struct cn_msg)+
+               sizeof(struct drbd_nl_cfg_reply)+
+               sizeof(struct dump_ee_tag_len_struct)+
+               sizeof(short int),
+               GFP_NOIO);
+
+       if (!cn_reply) {
+               dev_err(DEV, "could not kmalloc buffer for drbd_bcast_ee, sector %llu, size %u\n",
+                               (unsigned long long)e->sector, e->size);
+               return;
+       }
+
+       reply = (struct drbd_nl_cfg_reply*)cn_reply->data;
+       tl = reply->tag_list;
+
+       tl = tl_add_str(tl, T_dump_ee_reason, reason);
+       tl = tl_add_blob(tl, T_seen_digest, seen_hash, dgs);
+       tl = tl_add_blob(tl, T_calc_digest, calc_hash, dgs);
+       tl = tl_add_int(tl, T_ee_sector, &e->sector);
+       tl = tl_add_int(tl, T_ee_block_id, &e->block_id);
+
+       put_unaligned(T_ee_data, tl++);
+       put_unaligned(e->size, tl++);
+
+       __bio_for_each_segment(bvec, e->private_bio, i, 0) {
+               void *d = kmap(bvec->bv_page);
+               memcpy(tl, d + bvec->bv_offset, bvec->bv_len);
+               kunmap(bvec->bv_page);
+               tl=(unsigned short*)((char*)tl + bvec->bv_len);
+       }
+       put_unaligned(TT_END, tl++); /* Close the tag list */
+
+       cn_reply->id.idx = CN_IDX_DRBD;
+       cn_reply->id.val = CN_VAL_DRBD;
+
+       cn_reply->seq = atomic_add_return(1,&drbd_nl_seq);
+       cn_reply->ack = 0; // not used here.
+       cn_reply->len = sizeof(struct drbd_nl_cfg_reply) +
+               (int)((char*)tl - (char*)reply->tag_list);
+       cn_reply->flags = 0;
+
+       reply->packet_type = P_dump_ee;
+       reply->minor = mdev_to_minor(mdev);
+       reply->ret_code = NO_ERROR;
+
+       cn_netlink_send(cn_reply, CN_IDX_DRBD, GFP_NOIO);
+       kfree(cn_reply);
+}
+
+void drbd_bcast_sync_progress(struct drbd_conf *mdev)
+{
+       char buffer[sizeof(struct cn_msg)+
+                   sizeof(struct drbd_nl_cfg_reply)+
+                   sizeof(struct sync_progress_tag_len_struct)+
+                   sizeof(short int)];
+       struct cn_msg *cn_reply = (struct cn_msg *) buffer;
+       struct drbd_nl_cfg_reply *reply =
+               (struct drbd_nl_cfg_reply *)cn_reply->data;
+       unsigned short *tl = reply->tag_list;
+       unsigned long rs_left;
+       unsigned int res;
+
+       /* no local ref, no bitmap, no syncer progress, no broadcast. */
+       if (!get_ldev(mdev))
+               return;
+       drbd_get_syncer_progress(mdev, &rs_left, &res);
+       put_ldev(mdev);
+
+       tl = tl_add_int(tl, T_sync_progress, &res);
+       put_unaligned(TT_END, tl++); /* Close the tag list */
+
+       cn_reply->id.idx = CN_IDX_DRBD;
+       cn_reply->id.val = CN_VAL_DRBD;
+
+       cn_reply->seq = atomic_add_return(1, &drbd_nl_seq);
+       cn_reply->ack = 0; /* not used here. */
+       cn_reply->len = sizeof(struct drbd_nl_cfg_reply) +
+               (int)((char *)tl - (char *)reply->tag_list);
+       cn_reply->flags = 0;
+
+       reply->packet_type = P_sync_progress;
+       reply->minor = mdev_to_minor(mdev);
+       reply->ret_code = NO_ERROR;
+
+       cn_netlink_send(cn_reply, CN_IDX_DRBD, GFP_NOIO);
+}
+
+int __init drbd_nl_init(void)
+{
+       static struct cb_id cn_id_drbd;
+       int err, try=10;
+
+       cn_id_drbd.val = CN_VAL_DRBD;
+       do {
+               cn_id_drbd.idx = cn_idx;
+               err = cn_add_callback(&cn_id_drbd, "cn_drbd", &drbd_connector_callback);
+               if (!err)
+                       break;
+               cn_idx = (cn_idx + CN_IDX_STEP);
+       } while (try--);
+
+       if (err) {
+               printk(KERN_ERR "drbd: cn_drbd failed to register\n");
+               return err;
+       }
+
+       return 0;
+}
+
+void drbd_nl_cleanup(void)
+{
+       static struct cb_id cn_id_drbd;
+
+       cn_id_drbd.idx = cn_idx;
+       cn_id_drbd.val = CN_VAL_DRBD;
+
+       cn_del_callback(&cn_id_drbd);
+}
+
+void drbd_nl_send_reply(struct cn_msg *req, int ret_code)
+{
+       char buffer[sizeof(struct cn_msg)+sizeof(struct drbd_nl_cfg_reply)];
+       struct cn_msg *cn_reply = (struct cn_msg *) buffer;
+       struct drbd_nl_cfg_reply *reply =
+               (struct drbd_nl_cfg_reply *)cn_reply->data;
+       int rr;
+
+       cn_reply->id = req->id;
+
+       cn_reply->seq = req->seq;
+       cn_reply->ack = req->ack  + 1;
+       cn_reply->len = sizeof(struct drbd_nl_cfg_reply);
+       cn_reply->flags = 0;
+
+       reply->minor = ((struct drbd_nl_cfg_req *)req->data)->drbd_minor;
+       reply->ret_code = ret_code;
+
+       rr = cn_netlink_send(cn_reply, CN_IDX_DRBD, GFP_NOIO);
+       if (rr && rr != -ESRCH)
+               printk(KERN_INFO "drbd: cn_netlink_send()=%d\n", rr);
+}
+
diff --git a/drivers/block/drbd/drbd_proc.c b/drivers/block/drbd/drbd_proc.c
new file mode 100644 (file)
index 0000000..bdd0b49
--- /dev/null
@@ -0,0 +1,265 @@
+/*
+   drbd_proc.c
+
+   This file is part of DRBD by Philipp Reisner and Lars Ellenberg.
+
+   Copyright (C) 2001-2008, LINBIT Information Technologies GmbH.
+   Copyright (C) 1999-2008, Philipp Reisner <philipp.reisner@linbit.com>.
+   Copyright (C) 2002-2008, Lars Ellenberg <lars.ellenberg@linbit.com>.
+
+   drbd is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   drbd 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 drbd; see the file COPYING.  If not, write to
+   the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ */
+
+#include <linux/module.h>
+
+#include <asm/uaccess.h>
+#include <linux/fs.h>
+#include <linux/file.h>
+#include <linux/slab.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+#include <linux/drbd.h>
+#include "drbd_int.h"
+
+static int drbd_proc_open(struct inode *inode, struct file *file);
+
+
+struct proc_dir_entry *drbd_proc;
+struct file_operations drbd_proc_fops = {
+       .owner          = THIS_MODULE,
+       .open           = drbd_proc_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
+
+/*lge
+ * progress bars shamelessly adapted from driver/md/md.c
+ * output looks like
+ *     [=====>..............] 33.5% (23456/123456)
+ *     finish: 2:20:20 speed: 6,345 (6,456) K/sec
+ */
+static void drbd_syncer_progress(struct drbd_conf *mdev, struct seq_file *seq)
+{
+       unsigned long db, dt, dbdt, rt, rs_left;
+       unsigned int res;
+       int i, x, y;
+
+       drbd_get_syncer_progress(mdev, &rs_left, &res);
+
+       x = res/50;
+       y = 20-x;
+       seq_printf(seq, "\t[");
+       for (i = 1; i < x; i++)
+               seq_printf(seq, "=");
+       seq_printf(seq, ">");
+       for (i = 0; i < y; i++)
+               seq_printf(seq, ".");
+       seq_printf(seq, "] ");
+
+       seq_printf(seq, "sync'ed:%3u.%u%% ", res / 10, res % 10);
+       /* if more than 1 GB display in MB */
+       if (mdev->rs_total > 0x100000L)
+               seq_printf(seq, "(%lu/%lu)M\n\t",
+                           (unsigned long) Bit2KB(rs_left >> 10),
+                           (unsigned long) Bit2KB(mdev->rs_total >> 10));
+       else
+               seq_printf(seq, "(%lu/%lu)K\n\t",
+                           (unsigned long) Bit2KB(rs_left),
+                           (unsigned long) Bit2KB(mdev->rs_total));
+
+       /* see drivers/md/md.c
+        * We do not want to overflow, so the order of operands and
+        * the * 100 / 100 trick are important. We do a +1 to be
+        * safe against division by zero. We only estimate anyway.
+        *
+        * dt: time from mark until now
+        * db: blocks written from mark until now
+        * rt: remaining time
+        */
+       dt = (jiffies - mdev->rs_mark_time) / HZ;
+
+       if (dt > 20) {
+               /* if we made no update to rs_mark_time for too long,
+                * we are stalled. show that. */
+               seq_printf(seq, "stalled\n");
+               return;
+       }
+
+       if (!dt)
+               dt++;
+       db = mdev->rs_mark_left - rs_left;
+       rt = (dt * (rs_left / (db/100+1)))/100; /* seconds */
+
+       seq_printf(seq, "finish: %lu:%02lu:%02lu",
+               rt / 3600, (rt % 3600) / 60, rt % 60);
+
+       /* current speed average over (SYNC_MARKS * SYNC_MARK_STEP) jiffies */
+       dbdt = Bit2KB(db/dt);
+       if (dbdt > 1000)
+               seq_printf(seq, " speed: %ld,%03ld",
+                       dbdt/1000, dbdt % 1000);
+       else
+               seq_printf(seq, " speed: %ld", dbdt);
+
+       /* mean speed since syncer started
+        * we do account for PausedSync periods */
+       dt = (jiffies - mdev->rs_start - mdev->rs_paused) / HZ;
+       if (dt <= 0)
+               dt = 1;
+       db = mdev->rs_total - rs_left;
+       dbdt = Bit2KB(db/dt);
+       if (dbdt > 1000)
+               seq_printf(seq, " (%ld,%03ld)",
+                       dbdt/1000, dbdt % 1000);
+       else
+               seq_printf(seq, " (%ld)", dbdt);
+
+       seq_printf(seq, " K/sec\n");
+}
+
+static void resync_dump_detail(struct seq_file *seq, struct lc_element *e)
+{
+       struct bm_extent *bme = lc_entry(e, struct bm_extent, lce);
+
+       seq_printf(seq, "%5d %s %s\n", bme->rs_left,
+                  bme->flags & BME_NO_WRITES ? "NO_WRITES" : "---------",
+                  bme->flags & BME_LOCKED ? "LOCKED" : "------"
+                  );
+}
+
+static int drbd_seq_show(struct seq_file *seq, void *v)
+{
+       int i, hole = 0;
+       const char *sn;
+       struct drbd_conf *mdev;
+
+       static char write_ordering_chars[] = {
+               [WO_none] = 'n',
+               [WO_drain_io] = 'd',
+               [WO_bdev_flush] = 'f',
+               [WO_bio_barrier] = 'b',
+       };
+
+       seq_printf(seq, "version: " REL_VERSION " (api:%d/proto:%d-%d)\n%s\n",
+                  API_VERSION, PRO_VERSION_MIN, PRO_VERSION_MAX, drbd_buildtag());
+
+       /*
+         cs .. connection state
+         ro .. node role (local/remote)
+         ds .. disk state (local/remote)
+            protocol
+            various flags
+         ns .. network send
+         nr .. network receive
+         dw .. disk write
+         dr .. disk read
+         al .. activity log write count
+         bm .. bitmap update write count
+         pe .. pending (waiting for ack or data reply)
+         ua .. unack'd (still need to send ack or data reply)
+         ap .. application requests accepted, but not yet completed
+         ep .. number of epochs currently "on the fly", P_BARRIER_ACK pending
+         wo .. write ordering mode currently in use
+        oos .. known out-of-sync kB
+       */
+
+       for (i = 0; i < minor_count; i++) {
+               mdev = minor_to_mdev(i);
+               if (!mdev) {
+                       hole = 1;
+                       continue;
+               }
+               if (hole) {
+                       hole = 0;
+                       seq_printf(seq, "\n");
+               }
+
+               sn = drbd_conn_str(mdev->state.conn);
+
+               if (mdev->state.conn == C_STANDALONE &&
+                   mdev->state.disk == D_DISKLESS &&
+                   mdev->state.role == R_SECONDARY) {
+                       seq_printf(seq, "%2d: cs:Unconfigured\n", i);
+               } else {
+                       seq_printf(seq,
+                          "%2d: cs:%s ro:%s/%s ds:%s/%s %c %c%c%c%c%c\n"
+                          "    ns:%u nr:%u dw:%u dr:%u al:%u bm:%u "
+                          "lo:%d pe:%d ua:%d ap:%d ep:%d wo:%c",
+                          i, sn,
+                          drbd_role_str(mdev->state.role),
+                          drbd_role_str(mdev->state.peer),
+                          drbd_disk_str(mdev->state.disk),
+                          drbd_disk_str(mdev->state.pdsk),
+                          (mdev->net_conf == NULL ? ' ' :
+                           (mdev->net_conf->wire_protocol - DRBD_PROT_A+'A')),
+                          mdev->state.susp ? 's' : 'r',
+                          mdev->state.aftr_isp ? 'a' : '-',
+                          mdev->state.peer_isp ? 'p' : '-',
+                          mdev->state.user_isp ? 'u' : '-',
+                          mdev->congestion_reason ?: '-',
+                          mdev->send_cnt/2,
+                          mdev->recv_cnt/2,
+                          mdev->writ_cnt/2,
+                          mdev->read_cnt/2,
+                          mdev->al_writ_cnt,
+                          mdev->bm_writ_cnt,
+                          atomic_read(&mdev->local_cnt),
+                          atomic_read(&mdev->ap_pending_cnt) +
+                          atomic_read(&mdev->rs_pending_cnt),
+                          atomic_read(&mdev->unacked_cnt),
+                          atomic_read(&mdev->ap_bio_cnt),
+                          mdev->epochs,
+                          write_ordering_chars[mdev->write_ordering]
+                       );
+                       seq_printf(seq, " oos:%lu\n",
+                                  Bit2KB(drbd_bm_total_weight(mdev)));
+               }
+               if (mdev->state.conn == C_SYNC_SOURCE ||
+                   mdev->state.conn == C_SYNC_TARGET)
+                       drbd_syncer_progress(mdev, seq);
+
+               if (mdev->state.conn == C_VERIFY_S || mdev->state.conn == C_VERIFY_T)
+                       seq_printf(seq, "\t%3d%%      %lu/%lu\n",
+                                  (int)((mdev->rs_total-mdev->ov_left) /
+                                        (mdev->rs_total/100+1)),
+                                  mdev->rs_total - mdev->ov_left,
+                                  mdev->rs_total);
+
+               if (proc_details >= 1 && get_ldev_if_state(mdev, D_FAILED)) {
+                       lc_seq_printf_stats(seq, mdev->resync);
+                       lc_seq_printf_stats(seq, mdev->act_log);
+                       put_ldev(mdev);
+               }
+
+               if (proc_details >= 2) {
+                       if (mdev->resync) {
+                               lc_seq_dump_details(seq, mdev->resync, "rs_left",
+                                       resync_dump_detail);
+                       }
+               }
+       }
+
+       return 0;
+}
+
+static int drbd_proc_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, drbd_seq_show, PDE(inode)->data);
+}
+
+/* PROC FS stuff end */
diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c
new file mode 100644 (file)
index 0000000..c548f24
--- /dev/null
@@ -0,0 +1,4426 @@
+/*
+   drbd_receiver.c
+
+   This file is part of DRBD by Philipp Reisner and Lars Ellenberg.
+
+   Copyright (C) 2001-2008, LINBIT Information Technologies GmbH.
+   Copyright (C) 1999-2008, Philipp Reisner <philipp.reisner@linbit.com>.
+   Copyright (C) 2002-2008, Lars Ellenberg <lars.ellenberg@linbit.com>.
+
+   drbd is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   drbd 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 drbd; see the file COPYING.  If not, write to
+   the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+#include <linux/module.h>
+
+#include <asm/uaccess.h>
+#include <net/sock.h>
+
+#include <linux/version.h>
+#include <linux/drbd.h>
+#include <linux/fs.h>
+#include <linux/file.h>
+#include <linux/in.h>
+#include <linux/mm.h>
+#include <linux/memcontrol.h>
+#include <linux/mm_inline.h>
+#include <linux/slab.h>
+#include <linux/smp_lock.h>
+#include <linux/pkt_sched.h>
+#define __KERNEL_SYSCALLS__
+#include <linux/unistd.h>
+#include <linux/vmalloc.h>
+#include <linux/random.h>
+#include <linux/mm.h>
+#include <linux/string.h>
+#include <linux/scatterlist.h>
+#include "drbd_int.h"
+#include "drbd_req.h"
+
+#include "drbd_vli.h"
+
+struct flush_work {
+       struct drbd_work w;
+       struct drbd_epoch *epoch;
+};
+
+enum finish_epoch {
+       FE_STILL_LIVE,
+       FE_DESTROYED,
+       FE_RECYCLED,
+};
+
+static int drbd_do_handshake(struct drbd_conf *mdev);
+static int drbd_do_auth(struct drbd_conf *mdev);
+
+static enum finish_epoch drbd_may_finish_epoch(struct drbd_conf *, struct drbd_epoch *, enum epoch_event);
+static int e_end_block(struct drbd_conf *, struct drbd_work *, int);
+
+static struct drbd_epoch *previous_epoch(struct drbd_conf *mdev, struct drbd_epoch *epoch)
+{
+       struct drbd_epoch *prev;
+       spin_lock(&mdev->epoch_lock);
+       prev = list_entry(epoch->list.prev, struct drbd_epoch, list);
+       if (prev == epoch || prev == mdev->current_epoch)
+               prev = NULL;
+       spin_unlock(&mdev->epoch_lock);
+       return prev;
+}
+
+#define GFP_TRY        (__GFP_HIGHMEM | __GFP_NOWARN)
+
+static struct page *drbd_pp_first_page_or_try_alloc(struct drbd_conf *mdev)
+{
+       struct page *page = NULL;
+
+       /* Yes, testing drbd_pp_vacant outside the lock is racy.
+        * So what. It saves a spin_lock. */
+       if (drbd_pp_vacant > 0) {
+               spin_lock(&drbd_pp_lock);
+               page = drbd_pp_pool;
+               if (page) {
+                       drbd_pp_pool = (struct page *)page_private(page);
+                       set_page_private(page, 0); /* just to be polite */
+                       drbd_pp_vacant--;
+               }
+               spin_unlock(&drbd_pp_lock);
+       }
+       /* GFP_TRY, because we must not cause arbitrary write-out: in a DRBD
+        * "criss-cross" setup, that might cause write-out on some other DRBD,
+        * which in turn might block on the other node at this very place.  */
+       if (!page)
+               page = alloc_page(GFP_TRY);
+       if (page)
+               atomic_inc(&mdev->pp_in_use);
+       return page;
+}
+
+/* kick lower level device, if we have more than (arbitrary number)
+ * reference counts on it, which typically are locally submitted io
+ * requests.  don't use unacked_cnt, so we speed up proto A and B, too. */
+static void maybe_kick_lo(struct drbd_conf *mdev)
+{
+       if (atomic_read(&mdev->local_cnt) >= mdev->net_conf->unplug_watermark)
+               drbd_kick_lo(mdev);
+}
+
+static void reclaim_net_ee(struct drbd_conf *mdev, struct list_head *to_be_freed)
+{
+       struct drbd_epoch_entry *e;
+       struct list_head *le, *tle;
+
+       /* The EEs are always appended to the end of the list. Since
+          they are sent in order over the wire, they have to finish
+          in order. As soon as we see the first not finished we can
+          stop to examine the list... */
+
+       list_for_each_safe(le, tle, &mdev->net_ee) {
+               e = list_entry(le, struct drbd_epoch_entry, w.list);
+               if (drbd_bio_has_active_page(e->private_bio))
+                       break;
+               list_move(le, to_be_freed);
+       }
+}
+
+static void drbd_kick_lo_and_reclaim_net(struct drbd_conf *mdev)
+{
+       LIST_HEAD(reclaimed);
+       struct drbd_epoch_entry *e, *t;
+
+       maybe_kick_lo(mdev);
+       spin_lock_irq(&mdev->req_lock);
+       reclaim_net_ee(mdev, &reclaimed);
+       spin_unlock_irq(&mdev->req_lock);
+
+       list_for_each_entry_safe(e, t, &reclaimed, w.list)
+               drbd_free_ee(mdev, e);
+}
+
+/**
+ * drbd_pp_alloc() - Returns a page, fails only if a signal comes in
+ * @mdev:      DRBD device.
+ * @retry:     whether or not to retry allocation forever (or until signalled)
+ *
+ * Tries to allocate a page, first from our own page pool, then from the
+ * kernel, unless this allocation would exceed the max_buffers setting.
+ * If @retry is non-zero, retry until DRBD frees a page somewhere else.
+ */
+static struct page *drbd_pp_alloc(struct drbd_conf *mdev, int retry)
+{
+       struct page *page = NULL;
+       DEFINE_WAIT(wait);
+
+       if (atomic_read(&mdev->pp_in_use) < mdev->net_conf->max_buffers) {
+               page = drbd_pp_first_page_or_try_alloc(mdev);
+               if (page)
+                       return page;
+       }
+
+       for (;;) {
+               prepare_to_wait(&drbd_pp_wait, &wait, TASK_INTERRUPTIBLE);
+
+               drbd_kick_lo_and_reclaim_net(mdev);
+
+               if (atomic_read(&mdev->pp_in_use) < mdev->net_conf->max_buffers) {
+                       page = drbd_pp_first_page_or_try_alloc(mdev);
+                       if (page)
+                               break;
+               }
+
+               if (!retry)
+                       break;
+
+               if (signal_pending(current)) {
+                       dev_warn(DEV, "drbd_pp_alloc interrupted!\n");
+                       break;
+               }
+
+               schedule();
+       }
+       finish_wait(&drbd_pp_wait, &wait);
+
+       return page;
+}
+
+/* Must not be used from irq, as that may deadlock: see drbd_pp_alloc.
+ * Is also used from inside an other spin_lock_irq(&mdev->req_lock) */
+static void drbd_pp_free(struct drbd_conf *mdev, struct page *page)
+{
+       int free_it;
+
+       spin_lock(&drbd_pp_lock);
+       if (drbd_pp_vacant > (DRBD_MAX_SEGMENT_SIZE/PAGE_SIZE)*minor_count) {
+               free_it = 1;
+       } else {
+               set_page_private(page, (unsigned long)drbd_pp_pool);
+               drbd_pp_pool = page;
+               drbd_pp_vacant++;
+               free_it = 0;
+       }
+       spin_unlock(&drbd_pp_lock);
+
+       atomic_dec(&mdev->pp_in_use);
+
+       if (free_it)
+               __free_page(page);
+
+       wake_up(&drbd_pp_wait);
+}
+
+static void drbd_pp_free_bio_pages(struct drbd_conf *mdev, struct bio *bio)
+{
+       struct page *p_to_be_freed = NULL;
+       struct page *page;
+       struct bio_vec *bvec;
+       int i;
+
+       spin_lock(&drbd_pp_lock);
+       __bio_for_each_segment(bvec, bio, i, 0) {
+               if (drbd_pp_vacant > (DRBD_MAX_SEGMENT_SIZE/PAGE_SIZE)*minor_count) {
+                       set_page_private(bvec->bv_page, (unsigned long)p_to_be_freed);
+                       p_to_be_freed = bvec->bv_page;
+               } else {
+                       set_page_private(bvec->bv_page, (unsigned long)drbd_pp_pool);
+                       drbd_pp_pool = bvec->bv_page;
+                       drbd_pp_vacant++;
+               }
+       }
+       spin_unlock(&drbd_pp_lock);
+       atomic_sub(bio->bi_vcnt, &mdev->pp_in_use);
+
+       while (p_to_be_freed) {
+               page = p_to_be_freed;
+               p_to_be_freed = (struct page *)page_private(page);
+               set_page_private(page, 0); /* just to be polite */
+               put_page(page);
+       }
+
+       wake_up(&drbd_pp_wait);
+}
+
+/*
+You need to hold the req_lock:
+ _drbd_wait_ee_list_empty()
+
+You must not have the req_lock:
+ drbd_free_ee()
+ drbd_alloc_ee()
+ drbd_init_ee()
+ drbd_release_ee()
+ drbd_ee_fix_bhs()
+ drbd_process_done_ee()
+ drbd_clear_done_ee()
+ drbd_wait_ee_list_empty()
+*/
+
+struct drbd_epoch_entry *drbd_alloc_ee(struct drbd_conf *mdev,
+                                    u64 id,
+                                    sector_t sector,
+                                    unsigned int data_size,
+                                    gfp_t gfp_mask) __must_hold(local)
+{
+       struct request_queue *q;
+       struct drbd_epoch_entry *e;
+       struct page *page;
+       struct bio *bio;
+       unsigned int ds;
+
+       if (FAULT_ACTIVE(mdev, DRBD_FAULT_AL_EE))
+               return NULL;
+
+       e = mempool_alloc(drbd_ee_mempool, gfp_mask & ~__GFP_HIGHMEM);
+       if (!e) {
+               if (!(gfp_mask & __GFP_NOWARN))
+                       dev_err(DEV, "alloc_ee: Allocation of an EE failed\n");
+               return NULL;
+       }
+
+       bio = bio_alloc(gfp_mask & ~__GFP_HIGHMEM, div_ceil(data_size, PAGE_SIZE));
+       if (!bio) {
+               if (!(gfp_mask & __GFP_NOWARN))
+                       dev_err(DEV, "alloc_ee: Allocation of a bio failed\n");
+               goto fail1;
+       }
+
+       bio->bi_bdev = mdev->ldev->backing_bdev;
+       bio->bi_sector = sector;
+
+       ds = data_size;
+       while (ds) {
+               page = drbd_pp_alloc(mdev, (gfp_mask & __GFP_WAIT));
+               if (!page) {
+                       if (!(gfp_mask & __GFP_NOWARN))
+                               dev_err(DEV, "alloc_ee: Allocation of a page failed\n");
+                       goto fail2;
+               }
+               if (!bio_add_page(bio, page, min_t(int, ds, PAGE_SIZE), 0)) {
+                       drbd_pp_free(mdev, page);
+                       dev_err(DEV, "alloc_ee: bio_add_page(s=%llu,"
+                           "data_size=%u,ds=%u) failed\n",
+                           (unsigned long long)sector, data_size, ds);
+
+                       q = bdev_get_queue(bio->bi_bdev);
+                       if (q->merge_bvec_fn) {
+                               struct bvec_merge_data bvm = {
+                                       .bi_bdev = bio->bi_bdev,
+                                       .bi_sector = bio->bi_sector,
+                                       .bi_size = bio->bi_size,
+                                       .bi_rw = bio->bi_rw,
+                               };
+                               int l = q->merge_bvec_fn(q, &bvm,
+                                               &bio->bi_io_vec[bio->bi_vcnt]);
+                               dev_err(DEV, "merge_bvec_fn() = %d\n", l);
+                       }
+
+                       /* dump more of the bio. */
+                       dev_err(DEV, "bio->bi_max_vecs = %d\n", bio->bi_max_vecs);
+                       dev_err(DEV, "bio->bi_vcnt = %d\n", bio->bi_vcnt);
+                       dev_err(DEV, "bio->bi_size = %d\n", bio->bi_size);
+                       dev_err(DEV, "bio->bi_phys_segments = %d\n", bio->bi_phys_segments);
+
+                       goto fail2;
+                       break;
+               }
+               ds -= min_t(int, ds, PAGE_SIZE);
+       }
+
+       D_ASSERT(data_size == bio->bi_size);
+
+       bio->bi_private = e;
+       e->mdev = mdev;
+       e->sector = sector;
+       e->size = bio->bi_size;
+
+       e->private_bio = bio;
+       e->block_id = id;
+       INIT_HLIST_NODE(&e->colision);
+       e->epoch = NULL;
+       e->flags = 0;
+
+       return e;
+
+ fail2:
+       drbd_pp_free_bio_pages(mdev, bio);
+       bio_put(bio);
+ fail1:
+       mempool_free(e, drbd_ee_mempool);
+
+       return NULL;
+}
+
+void drbd_free_ee(struct drbd_conf *mdev, struct drbd_epoch_entry *e)
+{
+       struct bio *bio = e->private_bio;
+       drbd_pp_free_bio_pages(mdev, bio);
+       bio_put(bio);
+       D_ASSERT(hlist_unhashed(&e->colision));
+       mempool_free(e, drbd_ee_mempool);
+}
+
+int drbd_release_ee(struct drbd_conf *mdev, struct list_head *list)
+{
+       LIST_HEAD(work_list);
+       struct drbd_epoch_entry *e, *t;
+       int count = 0;
+
+       spin_lock_irq(&mdev->req_lock);
+       list_splice_init(list, &work_list);
+       spin_unlock_irq(&mdev->req_lock);
+
+       list_for_each_entry_safe(e, t, &work_list, w.list) {
+               drbd_free_ee(mdev, e);
+               count++;
+       }
+       return count;
+}
+
+
+/*
+ * This function is called from _asender only_
+ * but see also comments in _req_mod(,barrier_acked)
+ * and receive_Barrier.
+ *
+ * Move entries from net_ee to done_ee, if ready.
+ * Grab done_ee, call all callbacks, free the entries.
+ * The callbacks typically send out ACKs.
+ */
+static int drbd_process_done_ee(struct drbd_conf *mdev)
+{
+       LIST_HEAD(work_list);
+       LIST_HEAD(reclaimed);
+       struct drbd_epoch_entry *e, *t;
+       int ok = (mdev->state.conn >= C_WF_REPORT_PARAMS);
+
+       spin_lock_irq(&mdev->req_lock);
+       reclaim_net_ee(mdev, &reclaimed);
+       list_splice_init(&mdev->done_ee, &work_list);
+       spin_unlock_irq(&mdev->req_lock);
+
+       list_for_each_entry_safe(e, t, &reclaimed, w.list)
+               drbd_free_ee(mdev, e);
+
+       /* possible callbacks here:
+        * e_end_block, and e_end_resync_block, e_send_discard_ack.
+        * all ignore the last argument.
+        */
+       list_for_each_entry_safe(e, t, &work_list, w.list) {
+               /* list_del not necessary, next/prev members not touched */
+               ok = e->w.cb(mdev, &e->w, !ok) && ok;
+               drbd_free_ee(mdev, e);
+       }
+       wake_up(&mdev->ee_wait);
+
+       return ok;
+}
+
+void _drbd_wait_ee_list_empty(struct drbd_conf *mdev, struct list_head *head)
+{
+       DEFINE_WAIT(wait);
+
+       /* avoids spin_lock/unlock
+        * and calling prepare_to_wait in the fast path */
+       while (!list_empty(head)) {
+               prepare_to_wait(&mdev->ee_wait, &wait, TASK_UNINTERRUPTIBLE);
+               spin_unlock_irq(&mdev->req_lock);
+               drbd_kick_lo(mdev);
+               schedule();
+               finish_wait(&mdev->ee_wait, &wait);
+               spin_lock_irq(&mdev->req_lock);
+       }
+}
+
+void drbd_wait_ee_list_empty(struct drbd_conf *mdev, struct list_head *head)
+{
+       spin_lock_irq(&mdev->req_lock);
+       _drbd_wait_ee_list_empty(mdev, head);
+       spin_unlock_irq(&mdev->req_lock);
+}
+
+/* see also kernel_accept; which is only present since 2.6.18.
+ * also we want to log which part of it failed, exactly */
+static int drbd_accept(struct drbd_conf *mdev, const char **what,
+               struct socket *sock, struct socket **newsock)
+{
+       struct sock *sk = sock->sk;
+       int err = 0;
+
+       *what = "listen";
+       err = sock->ops->listen(sock, 5);
+       if (err < 0)
+               goto out;
+
+       *what = "sock_create_lite";
+       err = sock_create_lite(sk->sk_family, sk->sk_type, sk->sk_protocol,
+                              newsock);
+       if (err < 0)
+               goto out;
+
+       *what = "accept";
+       err = sock->ops->accept(sock, *newsock, 0);
+       if (err < 0) {
+               sock_release(*newsock);
+               *newsock = NULL;
+               goto out;
+       }
+       (*newsock)->ops  = sock->ops;
+
+out:
+       return err;
+}
+
+static int drbd_recv_short(struct drbd_conf *mdev, struct socket *sock,
+                   void *buf, size_t size, int flags)
+{
+       mm_segment_t oldfs;
+       struct kvec iov = {
+               .iov_base = buf,
+               .iov_len = size,
+       };
+       struct msghdr msg = {
+               .msg_iovlen = 1,
+               .msg_iov = (struct iovec *)&iov,
+               .msg_flags = (flags ? flags : MSG_WAITALL | MSG_NOSIGNAL)
+       };
+       int rv;
+
+       oldfs = get_fs();
+       set_fs(KERNEL_DS);
+       rv = sock_recvmsg(sock, &msg, size, msg.msg_flags);
+       set_fs(oldfs);
+
+       return rv;
+}
+
+static int drbd_recv(struct drbd_conf *mdev, void *buf, size_t size)
+{
+       mm_segment_t oldfs;
+       struct kvec iov = {
+               .iov_base = buf,
+               .iov_len = size,
+       };
+       struct msghdr msg = {
+               .msg_iovlen = 1,
+               .msg_iov = (struct iovec *)&iov,
+               .msg_flags = MSG_WAITALL | MSG_NOSIGNAL
+       };
+       int rv;
+
+       oldfs = get_fs();
+       set_fs(KERNEL_DS);
+
+       for (;;) {
+               rv = sock_recvmsg(mdev->data.socket, &msg, size, msg.msg_flags);
+               if (rv == size)
+                       break;
+
+               /* Note:
+                * ECONNRESET   other side closed the connection
+                * ERESTARTSYS  (on  sock) we got a signal
+                */
+
+               if (rv < 0) {
+                       if (rv == -ECONNRESET)
+                               dev_info(DEV, "sock was reset by peer\n");
+                       else if (rv != -ERESTARTSYS)
+                               dev_err(DEV, "sock_recvmsg returned %d\n", rv);
+                       break;
+               } else if (rv == 0) {
+                       dev_info(DEV, "sock was shut down by peer\n");
+                       break;
+               } else  {
+                       /* signal came in, or peer/link went down,
+                        * after we read a partial message
+                        */
+                       /* D_ASSERT(signal_pending(current)); */
+                       break;
+               }
+       };
+
+       set_fs(oldfs);
+
+       if (rv != size)
+               drbd_force_state(mdev, NS(conn, C_BROKEN_PIPE));
+
+       return rv;
+}
+
+static struct socket *drbd_try_connect(struct drbd_conf *mdev)
+{
+       const char *what;
+       struct socket *sock;
+       struct sockaddr_in6 src_in6;
+       int err;
+       int disconnect_on_error = 1;
+
+       if (!get_net_conf(mdev))
+               return NULL;
+
+       what = "sock_create_kern";
+       err = sock_create_kern(((struct sockaddr *)mdev->net_conf->my_addr)->sa_family,
+               SOCK_STREAM, IPPROTO_TCP, &sock);
+       if (err < 0) {
+               sock = NULL;
+               goto out;
+       }
+
+       sock->sk->sk_rcvtimeo =
+       sock->sk->sk_sndtimeo =  mdev->net_conf->try_connect_int*HZ;
+
+       /* explicitly bind to the configured IP as source IP
+       *  for the outgoing connections.
+       *  This is needed for multihomed hosts and to be
+       *  able to use lo: interfaces for drbd.
+       * Make sure to use 0 as port number, so linux selects
+       *  a free one dynamically.
+       */
+       memcpy(&src_in6, mdev->net_conf->my_addr,
+              min_t(int, mdev->net_conf->my_addr_len, sizeof(src_in6)));
+       if (((struct sockaddr *)mdev->net_conf->my_addr)->sa_family == AF_INET6)
+               src_in6.sin6_port = 0;
+       else
+               ((struct sockaddr_in *)&src_in6)->sin_port = 0; /* AF_INET & AF_SCI */
+
+       what = "bind before connect";
+       err = sock->ops->bind(sock,
+                             (struct sockaddr *) &src_in6,
+                             mdev->net_conf->my_addr_len);
+       if (err < 0)
+               goto out;
+
+       /* connect may fail, peer not yet available.
+        * stay C_WF_CONNECTION, don't go Disconnecting! */
+       disconnect_on_error = 0;
+       what = "connect";
+       err = sock->ops->connect(sock,
+                                (struct sockaddr *)mdev->net_conf->peer_addr,
+                                mdev->net_conf->peer_addr_len, 0);
+
+out:
+       if (err < 0) {
+               if (sock) {
+                       sock_release(sock);
+                       sock = NULL;
+               }
+               switch (-err) {
+                       /* timeout, busy, signal pending */
+               case ETIMEDOUT: case EAGAIN: case EINPROGRESS:
+               case EINTR: case ERESTARTSYS:
+                       /* peer not (yet) available, network problem */
+               case ECONNREFUSED: case ENETUNREACH:
+               case EHOSTDOWN:    case EHOSTUNREACH:
+                       disconnect_on_error = 0;
+                       break;
+               default:
+                       dev_err(DEV, "%s failed, err = %d\n", what, err);
+               }
+               if (disconnect_on_error)
+                       drbd_force_state(mdev, NS(conn, C_DISCONNECTING));
+       }
+       put_net_conf(mdev);
+       return sock;
+}
+
+static struct socket *drbd_wait_for_connect(struct drbd_conf *mdev)
+{
+       int timeo, err;
+       struct socket *s_estab = NULL, *s_listen;
+       const char *what;
+
+       if (!get_net_conf(mdev))
+               return NULL;
+
+       what = "sock_create_kern";
+       err = sock_create_kern(((struct sockaddr *)mdev->net_conf->my_addr)->sa_family,
+               SOCK_STREAM, IPPROTO_TCP, &s_listen);
+       if (err) {
+               s_listen = NULL;
+               goto out;
+       }
+
+       timeo = mdev->net_conf->try_connect_int * HZ;
+       timeo += (random32() & 1) ? timeo / 7 : -timeo / 7; /* 28.5% random jitter */
+
+       s_listen->sk->sk_reuse    = 1; /* SO_REUSEADDR */
+       s_listen->sk->sk_rcvtimeo = timeo;
+       s_listen->sk->sk_sndtimeo = timeo;
+
+       what = "bind before listen";
+       err = s_listen->ops->bind(s_listen,
+                             (struct sockaddr *) mdev->net_conf->my_addr,
+                             mdev->net_conf->my_addr_len);
+       if (err < 0)
+               goto out;
+
+       err = drbd_accept(mdev, &what, s_listen, &s_estab);
+
+out:
+       if (s_listen)
+               sock_release(s_listen);
+       if (err < 0) {
+               if (err != -EAGAIN && err != -EINTR && err != -ERESTARTSYS) {
+                       dev_err(DEV, "%s failed, err = %d\n", what, err);
+                       drbd_force_state(mdev, NS(conn, C_DISCONNECTING));
+               }
+       }
+       put_net_conf(mdev);
+
+       return s_estab;
+}
+
+static int drbd_send_fp(struct drbd_conf *mdev,
+       struct socket *sock, enum drbd_packets cmd)
+{
+       struct p_header *h = (struct p_header *) &mdev->data.sbuf.header;
+
+       return _drbd_send_cmd(mdev, sock, cmd, h, sizeof(*h), 0);
+}
+
+static enum drbd_packets drbd_recv_fp(struct drbd_conf *mdev, struct socket *sock)
+{
+       struct p_header *h = (struct p_header *) &mdev->data.sbuf.header;
+       int rr;
+
+       rr = drbd_recv_short(mdev, sock, h, sizeof(*h), 0);
+
+       if (rr == sizeof(*h) && h->magic == BE_DRBD_MAGIC)
+               return be16_to_cpu(h->command);
+
+       return 0xffff;
+}
+
+/**
+ * drbd_socket_okay() - Free the socket if its connection is not okay
+ * @mdev:      DRBD device.
+ * @sock:      pointer to the pointer to the socket.
+ */
+static int drbd_socket_okay(struct drbd_conf *mdev, struct socket **sock)
+{
+       int rr;
+       char tb[4];
+
+       if (!*sock)
+               return FALSE;
+
+       rr = drbd_recv_short(mdev, *sock, tb, 4, MSG_DONTWAIT | MSG_PEEK);
+
+       if (rr > 0 || rr == -EAGAIN) {
+               return TRUE;
+       } else {
+               sock_release(*sock);
+               *sock = NULL;
+               return FALSE;
+       }
+}
+
+/*
+ * return values:
+ *   1 yes, we have a valid connection
+ *   0 oops, did not work out, please try again
+ *  -1 peer talks different language,
+ *     no point in trying again, please go standalone.
+ *  -2 We do not have a network config...
+ */
+static int drbd_connect(struct drbd_conf *mdev)
+{
+       struct socket *s, *sock, *msock;
+       int try, h, ok;
+
+       D_ASSERT(!mdev->data.socket);
+
+       if (test_and_clear_bit(CREATE_BARRIER, &mdev->flags))
+               dev_err(DEV, "CREATE_BARRIER flag was set in drbd_connect - now cleared!\n");
+
+       if (drbd_request_state(mdev, NS(conn, C_WF_CONNECTION)) < SS_SUCCESS)
+               return -2;
+
+       clear_bit(DISCARD_CONCURRENT, &mdev->flags);
+
+       sock  = NULL;
+       msock = NULL;
+
+       do {
+               for (try = 0;;) {
+                       /* 3 tries, this should take less than a second! */
+                       s = drbd_try_connect(mdev);
+                       if (s || ++try >= 3)
+                               break;
+                       /* give the other side time to call bind() & listen() */
+                       __set_current_state(TASK_INTERRUPTIBLE);
+                       schedule_timeout(HZ / 10);
+               }
+
+               if (s) {
+                       if (!sock) {
+                               drbd_send_fp(mdev, s, P_HAND_SHAKE_S);
+                               sock = s;
+                               s = NULL;
+                       } else if (!msock) {
+                               drbd_send_fp(mdev, s, P_HAND_SHAKE_M);
+                               msock = s;
+                               s = NULL;
+                       } else {
+                               dev_err(DEV, "Logic error in drbd_connect()\n");
+                               goto out_release_sockets;
+                       }
+               }
+
+               if (sock && msock) {
+                       __set_current_state(TASK_INTERRUPTIBLE);
+                       schedule_timeout(HZ / 10);
+                       ok = drbd_socket_okay(mdev, &sock);
+                       ok = drbd_socket_okay(mdev, &msock) && ok;
+                       if (ok)
+                               break;
+               }
+
+retry:
+               s = drbd_wait_for_connect(mdev);
+               if (s) {
+                       try = drbd_recv_fp(mdev, s);
+                       drbd_socket_okay(mdev, &sock);
+                       drbd_socket_okay(mdev, &msock);
+                       switch (try) {
+                       case P_HAND_SHAKE_S:
+                               if (sock) {
+                                       dev_warn(DEV, "initial packet S crossed\n");
+                                       sock_release(sock);
+                               }
+                               sock = s;
+                               break;
+                       case P_HAND_SHAKE_M:
+                               if (msock) {
+                                       dev_warn(DEV, "initial packet M crossed\n");
+                                       sock_release(msock);
+                               }
+                               msock = s;
+                               set_bit(DISCARD_CONCURRENT, &mdev->flags);
+                               break;
+                       default:
+                               dev_warn(DEV, "Error receiving initial packet\n");
+                               sock_release(s);
+                               if (random32() & 1)
+                                       goto retry;
+                       }
+               }
+
+               if (mdev->state.conn <= C_DISCONNECTING)
+                       goto out_release_sockets;
+               if (signal_pending(current)) {
+                       flush_signals(current);
+                       smp_rmb();
+                       if (get_t_state(&mdev->receiver) == Exiting)
+                               goto out_release_sockets;
+               }
+
+               if (sock && msock) {
+                       ok = drbd_socket_okay(mdev, &sock);
+                       ok = drbd_socket_okay(mdev, &msock) && ok;
+                       if (ok)
+                               break;
+               }
+       } while (1);
+
+       msock->sk->sk_reuse = 1; /* SO_REUSEADDR */
+       sock->sk->sk_reuse = 1; /* SO_REUSEADDR */
+
+       sock->sk->sk_allocation = GFP_NOIO;
+       msock->sk->sk_allocation = GFP_NOIO;
+
+       sock->sk->sk_priority = TC_PRIO_INTERACTIVE_BULK;
+       msock->sk->sk_priority = TC_PRIO_INTERACTIVE;
+
+       if (mdev->net_conf->sndbuf_size) {
+               sock->sk->sk_sndbuf = mdev->net_conf->sndbuf_size;
+               sock->sk->sk_userlocks |= SOCK_SNDBUF_LOCK;
+       }
+
+       if (mdev->net_conf->rcvbuf_size) {
+               sock->sk->sk_rcvbuf = mdev->net_conf->rcvbuf_size;
+               sock->sk->sk_userlocks |= SOCK_RCVBUF_LOCK;
+       }
+
+       /* NOT YET ...
+        * sock->sk->sk_sndtimeo = mdev->net_conf->timeout*HZ/10;
+        * sock->sk->sk_rcvtimeo = MAX_SCHEDULE_TIMEOUT;
+        * first set it to the P_HAND_SHAKE timeout,
+        * which we set to 4x the configured ping_timeout. */
+       sock->sk->sk_sndtimeo =
+       sock->sk->sk_rcvtimeo = mdev->net_conf->ping_timeo*4*HZ/10;
+
+       msock->sk->sk_sndtimeo = mdev->net_conf->timeout*HZ/10;
+       msock->sk->sk_rcvtimeo = mdev->net_conf->ping_int*HZ;
+
+       /* we don't want delays.
+        * we use TCP_CORK where apropriate, though */
+       drbd_tcp_nodelay(sock);
+       drbd_tcp_nodelay(msock);
+
+       mdev->data.socket = sock;
+       mdev->meta.socket = msock;
+       mdev->last_received = jiffies;
+
+       D_ASSERT(mdev->asender.task == NULL);
+
+       h = drbd_do_handshake(mdev);
+       if (h <= 0)
+               return h;
+
+       if (mdev->cram_hmac_tfm) {
+               /* drbd_request_state(mdev, NS(conn, WFAuth)); */
+               if (!drbd_do_auth(mdev)) {
+                       dev_err(DEV, "Authentication of peer failed\n");
+                       return -1;
+               }
+       }
+
+       if (drbd_request_state(mdev, NS(conn, C_WF_REPORT_PARAMS)) < SS_SUCCESS)
+               return 0;
+
+       sock->sk->sk_sndtimeo = mdev->net_conf->timeout*HZ/10;
+       sock->sk->sk_rcvtimeo = MAX_SCHEDULE_TIMEOUT;
+
+       atomic_set(&mdev->packet_seq, 0);
+       mdev->peer_seq = 0;
+
+       drbd_thread_start(&mdev->asender);
+
+       drbd_send_protocol(mdev);
+       drbd_send_sync_param(mdev, &mdev->sync_conf);
+       drbd_send_sizes(mdev, 0);
+       drbd_send_uuids(mdev);
+       drbd_send_state(mdev);
+       clear_bit(USE_DEGR_WFC_T, &mdev->flags);
+       clear_bit(RESIZE_PENDING, &mdev->flags);
+
+       return 1;
+
+out_release_sockets:
+       if (sock)
+               sock_release(sock);
+       if (msock)
+               sock_release(msock);
+       return -1;
+}
+
+static int drbd_recv_header(struct drbd_conf *mdev, struct p_header *h)
+{
+       int r;
+
+       r = drbd_recv(mdev, h, sizeof(*h));
+
+       if (unlikely(r != sizeof(*h))) {
+               dev_err(DEV, "short read expecting header on sock: r=%d\n", r);
+               return FALSE;
+       };
+       h->command = be16_to_cpu(h->command);
+       h->length  = be16_to_cpu(h->length);
+       if (unlikely(h->magic != BE_DRBD_MAGIC)) {
+               dev_err(DEV, "magic?? on data m: 0x%lx c: %d l: %d\n",
+                   (long)be32_to_cpu(h->magic),
+                   h->command, h->length);
+               return FALSE;
+       }
+       mdev->last_received = jiffies;
+
+       return TRUE;
+}
+
+static enum finish_epoch drbd_flush_after_epoch(struct drbd_conf *mdev, struct drbd_epoch *epoch)
+{
+       int rv;
+
+       if (mdev->write_ordering >= WO_bdev_flush && get_ldev(mdev)) {
+               rv = blkdev_issue_flush(mdev->ldev->backing_bdev, NULL);
+               if (rv) {
+                       dev_err(DEV, "local disk flush failed with status %d\n", rv);
+                       /* would rather check on EOPNOTSUPP, but that is not reliable.
+                        * don't try again for ANY return value != 0
+                        * if (rv == -EOPNOTSUPP) */
+                       drbd_bump_write_ordering(mdev, WO_drain_io);
+               }
+               put_ldev(mdev);
+       }
+
+       return drbd_may_finish_epoch(mdev, epoch, EV_BARRIER_DONE);
+}
+
+static int w_flush(struct drbd_conf *mdev, struct drbd_work *w, int cancel)
+{
+       struct flush_work *fw = (struct flush_work *)w;
+       struct drbd_epoch *epoch = fw->epoch;
+
+       kfree(w);
+
+       if (!test_and_set_bit(DE_BARRIER_IN_NEXT_EPOCH_ISSUED, &epoch->flags))
+               drbd_flush_after_epoch(mdev, epoch);
+
+       drbd_may_finish_epoch(mdev, epoch, EV_PUT |
+                             (mdev->state.conn < C_CONNECTED ? EV_CLEANUP : 0));
+
+       return 1;
+}
+
+/**
+ * drbd_may_finish_epoch() - Applies an epoch_event to the epoch's state, eventually finishes it.
+ * @mdev:      DRBD device.
+ * @epoch:     Epoch object.
+ * @ev:                Epoch event.
+ */
+static enum finish_epoch drbd_may_finish_epoch(struct drbd_conf *mdev,
+                                              struct drbd_epoch *epoch,
+                                              enum epoch_event ev)
+{
+       int finish, epoch_size;
+       struct drbd_epoch *next_epoch;
+       int schedule_flush = 0;
+       enum finish_epoch rv = FE_STILL_LIVE;
+
+       spin_lock(&mdev->epoch_lock);
+       do {
+               next_epoch = NULL;
+               finish = 0;
+
+               epoch_size = atomic_read(&epoch->epoch_size);
+
+               switch (ev & ~EV_CLEANUP) {
+               case EV_PUT:
+                       atomic_dec(&epoch->active);
+                       break;
+               case EV_GOT_BARRIER_NR:
+                       set_bit(DE_HAVE_BARRIER_NUMBER, &epoch->flags);
+
+                       /* Special case: If we just switched from WO_bio_barrier to
+                          WO_bdev_flush we should not finish the current epoch */
+                       if (test_bit(DE_CONTAINS_A_BARRIER, &epoch->flags) && epoch_size == 1 &&
+                           mdev->write_ordering != WO_bio_barrier &&
+                           epoch == mdev->current_epoch)
+                               clear_bit(DE_CONTAINS_A_BARRIER, &epoch->flags);
+                       break;
+               case EV_BARRIER_DONE:
+                       set_bit(DE_BARRIER_IN_NEXT_EPOCH_DONE, &epoch->flags);
+                       break;
+               case EV_BECAME_LAST:
+                       /* nothing to do*/
+                       break;
+               }
+
+               if (epoch_size != 0 &&
+                   atomic_read(&epoch->active) == 0 &&
+                   test_bit(DE_HAVE_BARRIER_NUMBER, &epoch->flags) &&
+                   epoch->list.prev == &mdev->current_epoch->list &&
+                   !test_bit(DE_IS_FINISHING, &epoch->flags)) {
+                       /* Nearly all conditions are met to finish that epoch... */
+                       if (test_bit(DE_BARRIER_IN_NEXT_EPOCH_DONE, &epoch->flags) ||
+                           mdev->write_ordering == WO_none ||
+                           (epoch_size == 1 && test_bit(DE_CONTAINS_A_BARRIER, &epoch->flags)) ||
+                           ev & EV_CLEANUP) {
+                               finish = 1;
+                               set_bit(DE_IS_FINISHING, &epoch->flags);
+                       } else if (!test_bit(DE_BARRIER_IN_NEXT_EPOCH_ISSUED, &epoch->flags) &&
+                                mdev->write_ordering == WO_bio_barrier) {
+                               atomic_inc(&epoch->active);
+                               schedule_flush = 1;
+                       }
+               }
+               if (finish) {
+                       if (!(ev & EV_CLEANUP)) {
+                               spin_unlock(&mdev->epoch_lock);
+                               drbd_send_b_ack(mdev, epoch->barrier_nr, epoch_size);
+                               spin_lock(&mdev->epoch_lock);
+                       }
+                       dec_unacked(mdev);
+
+                       if (mdev->current_epoch != epoch) {
+                               next_epoch = list_entry(epoch->list.next, struct drbd_epoch, list);
+                               list_del(&epoch->list);
+                               ev = EV_BECAME_LAST | (ev & EV_CLEANUP);
+                               mdev->epochs--;
+                               kfree(epoch);
+
+                               if (rv == FE_STILL_LIVE)
+                                       rv = FE_DESTROYED;
+                       } else {
+                               epoch->flags = 0;
+                               atomic_set(&epoch->epoch_size, 0);
+                               /* atomic_set(&epoch->active, 0); is alrady zero */
+                               if (rv == FE_STILL_LIVE)
+                                       rv = FE_RECYCLED;
+                       }
+               }
+
+               if (!next_epoch)
+                       break;
+
+               epoch = next_epoch;
+       } while (1);
+
+       spin_unlock(&mdev->epoch_lock);
+
+       if (schedule_flush) {
+               struct flush_work *fw;
+               fw = kmalloc(sizeof(*fw), GFP_ATOMIC);
+               if (fw) {
+                       fw->w.cb = w_flush;
+                       fw->epoch = epoch;
+                       drbd_queue_work(&mdev->data.work, &fw->w);
+               } else {
+                       dev_warn(DEV, "Could not kmalloc a flush_work obj\n");
+                       set_bit(DE_BARRIER_IN_NEXT_EPOCH_ISSUED, &epoch->flags);
+                       /* That is not a recursion, only one level */
+                       drbd_may_finish_epoch(mdev, epoch, EV_BARRIER_DONE);
+                       drbd_may_finish_epoch(mdev, epoch, EV_PUT);
+               }
+       }
+
+       return rv;
+}
+
+/**
+ * drbd_bump_write_ordering() - Fall back to an other write ordering method
+ * @mdev:      DRBD device.
+ * @wo:                Write ordering method to try.
+ */
+void drbd_bump_write_ordering(struct drbd_conf *mdev, enum write_ordering_e wo) __must_hold(local)
+{
+       enum write_ordering_e pwo;
+       static char *write_ordering_str[] = {
+               [WO_none] = "none",
+               [WO_drain_io] = "drain",
+               [WO_bdev_flush] = "flush",
+               [WO_bio_barrier] = "barrier",
+       };
+
+       pwo = mdev->write_ordering;
+       wo = min(pwo, wo);
+       if (wo == WO_bio_barrier && mdev->ldev->dc.no_disk_barrier)
+               wo = WO_bdev_flush;
+       if (wo == WO_bdev_flush && mdev->ldev->dc.no_disk_flush)
+               wo = WO_drain_io;
+       if (wo == WO_drain_io && mdev->ldev->dc.no_disk_drain)
+               wo = WO_none;
+       mdev->write_ordering = wo;
+       if (pwo != mdev->write_ordering || wo == WO_bio_barrier)
+               dev_info(DEV, "Method to ensure write ordering: %s\n", write_ordering_str[mdev->write_ordering]);
+}
+
+/**
+ * w_e_reissue() - Worker callback; Resubmit a bio, without BIO_RW_BARRIER set
+ * @mdev:      DRBD device.
+ * @w:         work object.
+ * @cancel:    The connection will be closed anyways (unused in this callback)
+ */
+int w_e_reissue(struct drbd_conf *mdev, struct drbd_work *w, int cancel) __releases(local)
+{
+       struct drbd_epoch_entry *e = (struct drbd_epoch_entry *)w;
+       struct bio *bio = e->private_bio;
+
+       /* We leave DE_CONTAINS_A_BARRIER and EE_IS_BARRIER in place,
+          (and DE_BARRIER_IN_NEXT_EPOCH_ISSUED in the previous Epoch)
+          so that we can finish that epoch in drbd_may_finish_epoch().
+          That is necessary if we already have a long chain of Epochs, before
+          we realize that BIO_RW_BARRIER is actually not supported */
+
+       /* As long as the -ENOTSUPP on the barrier is reported immediately
+          that will never trigger. If it is reported late, we will just
+          print that warning and continue correctly for all future requests
+          with WO_bdev_flush */
+       if (previous_epoch(mdev, e->epoch))
+               dev_warn(DEV, "Write ordering was not enforced (one time event)\n");
+
+       /* prepare bio for re-submit,
+        * re-init volatile members */
+       /* we still have a local reference,
+        * get_ldev was done in receive_Data. */
+       bio->bi_bdev = mdev->ldev->backing_bdev;
+       bio->bi_sector = e->sector;
+       bio->bi_size = e->size;
+       bio->bi_idx = 0;
+
+       bio->bi_flags &= ~(BIO_POOL_MASK - 1);
+       bio->bi_flags |= 1 << BIO_UPTODATE;
+
+       /* don't know whether this is necessary: */
+       bio->bi_phys_segments = 0;
+       bio->bi_next = NULL;
+
+       /* these should be unchanged: */
+       /* bio->bi_end_io = drbd_endio_write_sec; */
+       /* bio->bi_vcnt = whatever; */
+
+       e->w.cb = e_end_block;
+
+       /* This is no longer a barrier request. */
+       bio->bi_rw &= ~(1UL << BIO_RW_BARRIER);
+
+       drbd_generic_make_request(mdev, DRBD_FAULT_DT_WR, bio);
+
+       return 1;
+}
+
+static int receive_Barrier(struct drbd_conf *mdev, struct p_header *h)
+{
+       int rv, issue_flush;
+       struct p_barrier *p = (struct p_barrier *)h;
+       struct drbd_epoch *epoch;
+
+       ERR_IF(h->length != (sizeof(*p)-sizeof(*h))) return FALSE;
+
+       rv = drbd_recv(mdev, h->payload, h->length);
+       ERR_IF(rv != h->length) return FALSE;
+
+       inc_unacked(mdev);
+
+       if (mdev->net_conf->wire_protocol != DRBD_PROT_C)
+               drbd_kick_lo(mdev);
+
+       mdev->current_epoch->barrier_nr = p->barrier;
+       rv = drbd_may_finish_epoch(mdev, mdev->current_epoch, EV_GOT_BARRIER_NR);
+
+       /* P_BARRIER_ACK may imply that the corresponding extent is dropped from
+        * the activity log, which means it would not be resynced in case the
+        * R_PRIMARY crashes now.
+        * Therefore we must send the barrier_ack after the barrier request was
+        * completed. */
+       switch (mdev->write_ordering) {
+       case WO_bio_barrier:
+       case WO_none:
+               if (rv == FE_RECYCLED)
+                       return TRUE;
+               break;
+
+       case WO_bdev_flush:
+       case WO_drain_io:
+               D_ASSERT(rv == FE_STILL_LIVE);
+               set_bit(DE_BARRIER_IN_NEXT_EPOCH_ISSUED, &mdev->current_epoch->flags);
+               drbd_wait_ee_list_empty(mdev, &mdev->active_ee);
+               rv = drbd_flush_after_epoch(mdev, mdev->current_epoch);
+               if (rv == FE_RECYCLED)
+                       return TRUE;
+
+               /* The asender will send all the ACKs and barrier ACKs out, since
+                  all EEs moved from the active_ee to the done_ee. We need to
+                  provide a new epoch object for the EEs that come in soon */
+               break;
+       }
+
+       /* receiver context, in the writeout path of the other node.
+        * avoid potential distributed deadlock */
+       epoch = kmalloc(sizeof(struct drbd_epoch), GFP_NOIO);
+       if (!epoch) {
+               dev_warn(DEV, "Allocation of an epoch failed, slowing down\n");
+               issue_flush = !test_and_set_bit(DE_BARRIER_IN_NEXT_EPOCH_ISSUED, &epoch->flags);
+               drbd_wait_ee_list_empty(mdev, &mdev->active_ee);
+               if (issue_flush) {
+                       rv = drbd_flush_after_epoch(mdev, mdev->current_epoch);
+                       if (rv == FE_RECYCLED)
+                               return TRUE;
+               }
+
+               drbd_wait_ee_list_empty(mdev, &mdev->done_ee);
+
+               return TRUE;
+       }
+
+       epoch->flags = 0;
+       atomic_set(&epoch->epoch_size, 0);
+       atomic_set(&epoch->active, 0);
+
+       spin_lock(&mdev->epoch_lock);
+       if (atomic_read(&mdev->current_epoch->epoch_size)) {
+               list_add(&epoch->list, &mdev->current_epoch->list);
+               mdev->current_epoch = epoch;
+               mdev->epochs++;
+       } else {
+               /* The current_epoch got recycled while we allocated this one... */
+               kfree(epoch);
+       }
+       spin_unlock(&mdev->epoch_lock);
+
+       return TRUE;
+}
+
+/* used from receive_RSDataReply (recv_resync_read)
+ * and from receive_Data */
+static struct drbd_epoch_entry *
+read_in_block(struct drbd_conf *mdev, u64 id, sector_t sector, int data_size) __must_hold(local)
+{
+       struct drbd_epoch_entry *e;
+       struct bio_vec *bvec;
+       struct page *page;
+       struct bio *bio;
+       int dgs, ds, i, rr;
+       void *dig_in = mdev->int_dig_in;
+       void *dig_vv = mdev->int_dig_vv;
+
+       dgs = (mdev->agreed_pro_version >= 87 && mdev->integrity_r_tfm) ?
+               crypto_hash_digestsize(mdev->integrity_r_tfm) : 0;
+
+       if (dgs) {
+               rr = drbd_recv(mdev, dig_in, dgs);
+               if (rr != dgs) {
+                       dev_warn(DEV, "short read receiving data digest: read %d expected %d\n",
+                            rr, dgs);
+                       return NULL;
+               }
+       }
+
+       data_size -= dgs;
+
+       ERR_IF(data_size &  0x1ff) return NULL;
+       ERR_IF(data_size >  DRBD_MAX_SEGMENT_SIZE) return NULL;
+
+       /* GFP_NOIO, because we must not cause arbitrary write-out: in a DRBD
+        * "criss-cross" setup, that might cause write-out on some other DRBD,
+        * which in turn might block on the other node at this very place.  */
+       e = drbd_alloc_ee(mdev, id, sector, data_size, GFP_NOIO);
+       if (!e)
+               return NULL;
+       bio = e->private_bio;
+       ds = data_size;
+       bio_for_each_segment(bvec, bio, i) {
+               page = bvec->bv_page;
+               rr = drbd_recv(mdev, kmap(page), min_t(int, ds, PAGE_SIZE));
+               kunmap(page);
+               if (rr != min_t(int, ds, PAGE_SIZE)) {
+                       drbd_free_ee(mdev, e);
+                       dev_warn(DEV, "short read receiving data: read %d expected %d\n",
+                            rr, min_t(int, ds, PAGE_SIZE));
+                       return NULL;
+               }
+               ds -= rr;
+       }
+
+       if (dgs) {
+               drbd_csum(mdev, mdev->integrity_r_tfm, bio, dig_vv);
+               if (memcmp(dig_in, dig_vv, dgs)) {
+                       dev_err(DEV, "Digest integrity check FAILED.\n");
+                       drbd_bcast_ee(mdev, "digest failed",
+                                       dgs, dig_in, dig_vv, e);
+                       drbd_free_ee(mdev, e);
+                       return NULL;
+               }
+       }
+       mdev->recv_cnt += data_size>>9;
+       return e;
+}
+
+/* drbd_drain_block() just takes a data block
+ * out of the socket input buffer, and discards it.
+ */
+static int drbd_drain_block(struct drbd_conf *mdev, int data_size)
+{
+       struct page *page;
+       int rr, rv = 1;
+       void *data;
+
+       page = drbd_pp_alloc(mdev, 1);
+
+       data = kmap(page);
+       while (data_size) {
+               rr = drbd_recv(mdev, data, min_t(int, data_size, PAGE_SIZE));
+               if (rr != min_t(int, data_size, PAGE_SIZE)) {
+                       rv = 0;
+                       dev_warn(DEV, "short read receiving data: read %d expected %d\n",
+                            rr, min_t(int, data_size, PAGE_SIZE));
+                       break;
+               }
+               data_size -= rr;
+       }
+       kunmap(page);
+       drbd_pp_free(mdev, page);
+       return rv;
+}
+
+static int recv_dless_read(struct drbd_conf *mdev, struct drbd_request *req,
+                          sector_t sector, int data_size)
+{
+       struct bio_vec *bvec;
+       struct bio *bio;
+       int dgs, rr, i, expect;
+       void *dig_in = mdev->int_dig_in;
+       void *dig_vv = mdev->int_dig_vv;
+
+       dgs = (mdev->agreed_pro_version >= 87 && mdev->integrity_r_tfm) ?
+               crypto_hash_digestsize(mdev->integrity_r_tfm) : 0;
+
+       if (dgs) {
+               rr = drbd_recv(mdev, dig_in, dgs);
+               if (rr != dgs) {
+                       dev_warn(DEV, "short read receiving data reply digest: read %d expected %d\n",
+                            rr, dgs);
+                       return 0;
+               }
+       }
+
+       data_size -= dgs;
+
+       /* optimistically update recv_cnt.  if receiving fails below,
+        * we disconnect anyways, and counters will be reset. */
+       mdev->recv_cnt += data_size>>9;
+
+       bio = req->master_bio;
+       D_ASSERT(sector == bio->bi_sector);
+
+       bio_for_each_segment(bvec, bio, i) {
+               expect = min_t(int, data_size, bvec->bv_len);
+               rr = drbd_recv(mdev,
+                            kmap(bvec->bv_page)+bvec->bv_offset,
+                            expect);
+               kunmap(bvec->bv_page);
+               if (rr != expect) {
+                       dev_warn(DEV, "short read receiving data reply: "
+                            "read %d expected %d\n",
+                            rr, expect);
+                       return 0;
+               }
+               data_size -= rr;
+       }
+
+       if (dgs) {
+               drbd_csum(mdev, mdev->integrity_r_tfm, bio, dig_vv);
+               if (memcmp(dig_in, dig_vv, dgs)) {
+                       dev_err(DEV, "Digest integrity check FAILED. Broken NICs?\n");
+                       return 0;
+               }
+       }
+
+       D_ASSERT(data_size == 0);
+       return 1;
+}
+
+/* e_end_resync_block() is called via
+ * drbd_process_done_ee() by asender only */
+static int e_end_resync_block(struct drbd_conf *mdev, struct drbd_work *w, int unused)
+{
+       struct drbd_epoch_entry *e = (struct drbd_epoch_entry *)w;
+       sector_t sector = e->sector;
+       int ok;
+
+       D_ASSERT(hlist_unhashed(&e->colision));
+
+       if (likely(drbd_bio_uptodate(e->private_bio))) {
+               drbd_set_in_sync(mdev, sector, e->size);
+               ok = drbd_send_ack(mdev, P_RS_WRITE_ACK, e);
+       } else {
+               /* Record failure to sync */
+               drbd_rs_failed_io(mdev, sector, e->size);
+
+               ok  = drbd_send_ack(mdev, P_NEG_ACK, e);
+       }
+       dec_unacked(mdev);
+
+       return ok;
+}
+
+static int recv_resync_read(struct drbd_conf *mdev, sector_t sector, int data_size) __releases(local)
+{
+       struct drbd_epoch_entry *e;
+
+       e = read_in_block(mdev, ID_SYNCER, sector, data_size);
+       if (!e) {
+               put_ldev(mdev);
+               return FALSE;
+       }
+
+       dec_rs_pending(mdev);
+
+       e->private_bio->bi_end_io = drbd_endio_write_sec;
+       e->private_bio->bi_rw = WRITE;
+       e->w.cb = e_end_resync_block;
+
+       inc_unacked(mdev);
+       /* corresponding dec_unacked() in e_end_resync_block()
+        * respective _drbd_clear_done_ee */
+
+       spin_lock_irq(&mdev->req_lock);
+       list_add(&e->w.list, &mdev->sync_ee);
+       spin_unlock_irq(&mdev->req_lock);
+
+       drbd_generic_make_request(mdev, DRBD_FAULT_RS_WR, e->private_bio);
+       /* accounting done in endio */
+
+       maybe_kick_lo(mdev);
+       return TRUE;
+}
+
+static int receive_DataReply(struct drbd_conf *mdev, struct p_header *h)
+{
+       struct drbd_request *req;
+       sector_t sector;
+       unsigned int header_size, data_size;
+       int ok;
+       struct p_data *p = (struct p_data *)h;
+
+       header_size = sizeof(*p) - sizeof(*h);
+       data_size   = h->length  - header_size;
+
+       ERR_IF(data_size == 0) return FALSE;
+
+       if (drbd_recv(mdev, h->payload, header_size) != header_size)
+               return FALSE;
+
+       sector = be64_to_cpu(p->sector);
+
+       spin_lock_irq(&mdev->req_lock);
+       req = _ar_id_to_req(mdev, p->block_id, sector);
+       spin_unlock_irq(&mdev->req_lock);
+       if (unlikely(!req)) {
+               dev_err(DEV, "Got a corrupt block_id/sector pair(1).\n");
+               return FALSE;
+       }
+
+       /* hlist_del(&req->colision) is done in _req_may_be_done, to avoid
+        * special casing it there for the various failure cases.
+        * still no race with drbd_fail_pending_reads */
+       ok = recv_dless_read(mdev, req, sector, data_size);
+
+       if (ok)
+               req_mod(req, data_received);
+       /* else: nothing. handled from drbd_disconnect...
+        * I don't think we may complete this just yet
+        * in case we are "on-disconnect: freeze" */
+
+       return ok;
+}
+
+static int receive_RSDataReply(struct drbd_conf *mdev, struct p_header *h)
+{
+       sector_t sector;
+       unsigned int header_size, data_size;
+       int ok;
+       struct p_data *p = (struct p_data *)h;
+
+       header_size = sizeof(*p) - sizeof(*h);
+       data_size   = h->length  - header_size;
+
+       ERR_IF(data_size == 0) return FALSE;
+
+       if (drbd_recv(mdev, h->payload, header_size) != header_size)
+               return FALSE;
+
+       sector = be64_to_cpu(p->sector);
+       D_ASSERT(p->block_id == ID_SYNCER);
+
+       if (get_ldev(mdev)) {
+               /* data is submitted to disk within recv_resync_read.
+                * corresponding put_ldev done below on error,
+                * or in drbd_endio_write_sec. */
+               ok = recv_resync_read(mdev, sector, data_size);
+       } else {
+               if (__ratelimit(&drbd_ratelimit_state))
+                       dev_err(DEV, "Can not write resync data to local disk.\n");
+
+               ok = drbd_drain_block(mdev, data_size);
+
+               drbd_send_ack_dp(mdev, P_NEG_ACK, p);
+       }
+
+       return ok;
+}
+
+/* e_end_block() is called via drbd_process_done_ee().
+ * this means this function only runs in the asender thread
+ */
+static int e_end_block(struct drbd_conf *mdev, struct drbd_work *w, int cancel)
+{
+       struct drbd_epoch_entry *e = (struct drbd_epoch_entry *)w;
+       sector_t sector = e->sector;
+       struct drbd_epoch *epoch;
+       int ok = 1, pcmd;
+
+       if (e->flags & EE_IS_BARRIER) {
+               epoch = previous_epoch(mdev, e->epoch);
+               if (epoch)
+                       drbd_may_finish_epoch(mdev, epoch, EV_BARRIER_DONE + (cancel ? EV_CLEANUP : 0));
+       }
+
+       if (mdev->net_conf->wire_protocol == DRBD_PROT_C) {
+               if (likely(drbd_bio_uptodate(e->private_bio))) {
+                       pcmd = (mdev->state.conn >= C_SYNC_SOURCE &&
+                               mdev->state.conn <= C_PAUSED_SYNC_T &&
+                               e->flags & EE_MAY_SET_IN_SYNC) ?
+                               P_RS_WRITE_ACK : P_WRITE_ACK;
+                       ok &= drbd_send_ack(mdev, pcmd, e);
+                       if (pcmd == P_RS_WRITE_ACK)
+                               drbd_set_in_sync(mdev, sector, e->size);
+               } else {
+                       ok  = drbd_send_ack(mdev, P_NEG_ACK, e);
+                       /* we expect it to be marked out of sync anyways...
+                        * maybe assert this?  */
+               }
+               dec_unacked(mdev);
+       }
+       /* we delete from the conflict detection hash _after_ we sent out the
+        * P_WRITE_ACK / P_NEG_ACK, to get the sequence number right.  */
+       if (mdev->net_conf->two_primaries) {
+               spin_lock_irq(&mdev->req_lock);
+               D_ASSERT(!hlist_unhashed(&e->colision));
+               hlist_del_init(&e->colision);
+               spin_unlock_irq(&mdev->req_lock);
+       } else {
+               D_ASSERT(hlist_unhashed(&e->colision));
+       }
+
+       drbd_may_finish_epoch(mdev, e->epoch, EV_PUT + (cancel ? EV_CLEANUP : 0));
+
+       return ok;
+}
+
+static int e_send_discard_ack(struct drbd_conf *mdev, struct drbd_work *w, int unused)
+{
+       struct drbd_epoch_entry *e = (struct drbd_epoch_entry *)w;
+       int ok = 1;
+
+       D_ASSERT(mdev->net_conf->wire_protocol == DRBD_PROT_C);
+       ok = drbd_send_ack(mdev, P_DISCARD_ACK, e);
+
+       spin_lock_irq(&mdev->req_lock);
+       D_ASSERT(!hlist_unhashed(&e->colision));
+       hlist_del_init(&e->colision);
+       spin_unlock_irq(&mdev->req_lock);
+
+       dec_unacked(mdev);
+
+       return ok;
+}
+
+/* Called from receive_Data.
+ * Synchronize packets on sock with packets on msock.
+ *
+ * This is here so even when a P_DATA packet traveling via sock overtook an Ack
+ * packet traveling on msock, they are still processed in the order they have
+ * been sent.
+ *
+ * Note: we don't care for Ack packets overtaking P_DATA packets.
+ *
+ * In case packet_seq is larger than mdev->peer_seq number, there are
+ * outstanding packets on the msock. We wait for them to arrive.
+ * In case we are the logically next packet, we update mdev->peer_seq
+ * ourselves. Correctly handles 32bit wrap around.
+ *
+ * Assume we have a 10 GBit connection, that is about 1<<30 byte per second,
+ * about 1<<21 sectors per second. So "worst" case, we have 1<<3 == 8 seconds
+ * for the 24bit wrap (historical atomic_t guarantee on some archs), and we have
+ * 1<<9 == 512 seconds aka ages for the 32bit wrap around...
+ *
+ * returns 0 if we may process the packet,
+ * -ERESTARTSYS if we were interrupted (by disconnect signal). */
+static int drbd_wait_peer_seq(struct drbd_conf *mdev, const u32 packet_seq)
+{
+       DEFINE_WAIT(wait);
+       unsigned int p_seq;
+       long timeout;
+       int ret = 0;
+       spin_lock(&mdev->peer_seq_lock);
+       for (;;) {
+               prepare_to_wait(&mdev->seq_wait, &wait, TASK_INTERRUPTIBLE);
+               if (seq_le(packet_seq, mdev->peer_seq+1))
+                       break;
+               if (signal_pending(current)) {
+                       ret = -ERESTARTSYS;
+                       break;
+               }
+               p_seq = mdev->peer_seq;
+               spin_unlock(&mdev->peer_seq_lock);
+               timeout = schedule_timeout(30*HZ);
+               spin_lock(&mdev->peer_seq_lock);
+               if (timeout == 0 && p_seq == mdev->peer_seq) {
+                       ret = -ETIMEDOUT;
+                       dev_err(DEV, "ASSERT FAILED waited 30 seconds for sequence update, forcing reconnect\n");
+                       break;
+               }
+       }
+       finish_wait(&mdev->seq_wait, &wait);
+       if (mdev->peer_seq+1 == packet_seq)
+               mdev->peer_seq++;
+       spin_unlock(&mdev->peer_seq_lock);
+       return ret;
+}
+
+/* mirrored write */
+static int receive_Data(struct drbd_conf *mdev, struct p_header *h)
+{
+       sector_t sector;
+       struct drbd_epoch_entry *e;
+       struct p_data *p = (struct p_data *)h;
+       int header_size, data_size;
+       int rw = WRITE;
+       u32 dp_flags;
+
+       header_size = sizeof(*p) - sizeof(*h);
+       data_size   = h->length  - header_size;
+
+       ERR_IF(data_size == 0) return FALSE;
+
+       if (drbd_recv(mdev, h->payload, header_size) != header_size)
+               return FALSE;
+
+       if (!get_ldev(mdev)) {
+               if (__ratelimit(&drbd_ratelimit_state))
+                       dev_err(DEV, "Can not write mirrored data block "
+                           "to local disk.\n");
+               spin_lock(&mdev->peer_seq_lock);
+               if (mdev->peer_seq+1 == be32_to_cpu(p->seq_num))
+                       mdev->peer_seq++;
+               spin_unlock(&mdev->peer_seq_lock);
+
+               drbd_send_ack_dp(mdev, P_NEG_ACK, p);
+               atomic_inc(&mdev->current_epoch->epoch_size);
+               return drbd_drain_block(mdev, data_size);
+       }
+
+       /* get_ldev(mdev) successful.
+        * Corresponding put_ldev done either below (on various errors),
+        * or in drbd_endio_write_sec, if we successfully submit the data at
+        * the end of this function. */
+
+       sector = be64_to_cpu(p->sector);
+       e = read_in_block(mdev, p->block_id, sector, data_size);
+       if (!e) {
+               put_ldev(mdev);
+               return FALSE;
+       }
+
+       e->private_bio->bi_end_io = drbd_endio_write_sec;
+       e->w.cb = e_end_block;
+
+       spin_lock(&mdev->epoch_lock);
+       e->epoch = mdev->current_epoch;
+       atomic_inc(&e->epoch->epoch_size);
+       atomic_inc(&e->epoch->active);
+
+       if (mdev->write_ordering == WO_bio_barrier && atomic_read(&e->epoch->epoch_size) == 1) {
+               struct drbd_epoch *epoch;
+               /* Issue a barrier if we start a new epoch, and the previous epoch
+                  was not a epoch containing a single request which already was
+                  a Barrier. */
+               epoch = list_entry(e->epoch->list.prev, struct drbd_epoch, list);
+               if (epoch == e->epoch) {
+                       set_bit(DE_CONTAINS_A_BARRIER, &e->epoch->flags);
+                       rw |= (1<<BIO_RW_BARRIER);
+                       e->flags |= EE_IS_BARRIER;
+               } else {
+                       if (atomic_read(&epoch->epoch_size) > 1 ||
+                           !test_bit(DE_CONTAINS_A_BARRIER, &epoch->flags)) {
+                               set_bit(DE_BARRIER_IN_NEXT_EPOCH_ISSUED, &epoch->flags);
+                               set_bit(DE_CONTAINS_A_BARRIER, &e->epoch->flags);
+                               rw |= (1<<BIO_RW_BARRIER);
+                               e->flags |= EE_IS_BARRIER;
+                       }
+               }
+       }
+       spin_unlock(&mdev->epoch_lock);
+
+       dp_flags = be32_to_cpu(p->dp_flags);
+       if (dp_flags & DP_HARDBARRIER) {
+               dev_err(DEV, "ASSERT FAILED would have submitted barrier request\n");
+               /* rw |= (1<<BIO_RW_BARRIER); */
+       }
+       if (dp_flags & DP_RW_SYNC)
+               rw |= (1<<BIO_RW_SYNCIO) | (1<<BIO_RW_UNPLUG);
+       if (dp_flags & DP_MAY_SET_IN_SYNC)
+               e->flags |= EE_MAY_SET_IN_SYNC;
+
+       /* I'm the receiver, I do hold a net_cnt reference. */
+       if (!mdev->net_conf->two_primaries) {
+               spin_lock_irq(&mdev->req_lock);
+       } else {
+               /* don't get the req_lock yet,
+                * we may sleep in drbd_wait_peer_seq */
+               const int size = e->size;
+               const int discard = test_bit(DISCARD_CONCURRENT, &mdev->flags);
+               DEFINE_WAIT(wait);
+               struct drbd_request *i;
+               struct hlist_node *n;
+               struct hlist_head *slot;
+               int first;
+
+               D_ASSERT(mdev->net_conf->wire_protocol == DRBD_PROT_C);
+               BUG_ON(mdev->ee_hash == NULL);
+               BUG_ON(mdev->tl_hash == NULL);
+
+               /* conflict detection and handling:
+                * 1. wait on the sequence number,
+                *    in case this data packet overtook ACK packets.
+                * 2. check our hash tables for conflicting requests.
+                *    we only need to walk the tl_hash, since an ee can not
+                *    have a conflict with an other ee: on the submitting
+                *    node, the corresponding req had already been conflicting,
+                *    and a conflicting req is never sent.
+                *
+                * Note: for two_primaries, we are protocol C,
+                * so there cannot be any request that is DONE
+                * but still on the transfer log.
+                *
+                * unconditionally add to the ee_hash.
+                *
+                * if no conflicting request is found:
+                *    submit.
+                *
+                * if any conflicting request is found
+                * that has not yet been acked,
+                * AND I have the "discard concurrent writes" flag:
+                *       queue (via done_ee) the P_DISCARD_ACK; OUT.
+                *
+                * if any conflicting request is found:
+                *       block the receiver, waiting on misc_wait
+                *       until no more conflicting requests are there,
+                *       or we get interrupted (disconnect).
+                *
+                *       we do not just write after local io completion of those
+                *       requests, but only after req is done completely, i.e.
+                *       we wait for the P_DISCARD_ACK to arrive!
+                *
+                *       then proceed normally, i.e. submit.
+                */
+               if (drbd_wait_peer_seq(mdev, be32_to_cpu(p->seq_num)))
+                       goto out_interrupted;
+
+               spin_lock_irq(&mdev->req_lock);
+
+               hlist_add_head(&e->colision, ee_hash_slot(mdev, sector));
+
+#define OVERLAPS overlaps(i->sector, i->size, sector, size)
+               slot = tl_hash_slot(mdev, sector);
+               first = 1;
+               for (;;) {
+                       int have_unacked = 0;
+                       int have_conflict = 0;
+                       prepare_to_wait(&mdev->misc_wait, &wait,
+                               TASK_INTERRUPTIBLE);
+                       hlist_for_each_entry(i, n, slot, colision) {
+                               if (OVERLAPS) {
+                                       /* only ALERT on first iteration,
+                                        * we may be woken up early... */
+                                       if (first)
+                                               dev_alert(DEV, "%s[%u] Concurrent local write detected!"
+                                                     " new: %llus +%u; pending: %llus +%u\n",
+                                                     current->comm, current->pid,
+                                                     (unsigned long long)sector, size,
+                                                     (unsigned long long)i->sector, i->size);
+                                       if (i->rq_state & RQ_NET_PENDING)
+                                               ++have_unacked;
+                                       ++have_conflict;
+                               }
+                       }
+#undef OVERLAPS
+                       if (!have_conflict)
+                               break;
+
+                       /* Discard Ack only for the _first_ iteration */
+                       if (first && discard && have_unacked) {
+                               dev_alert(DEV, "Concurrent write! [DISCARD BY FLAG] sec=%llus\n",
+                                    (unsigned long long)sector);
+                               inc_unacked(mdev);
+                               e->w.cb = e_send_discard_ack;
+                               list_add_tail(&e->w.list, &mdev->done_ee);
+
+                               spin_unlock_irq(&mdev->req_lock);
+
+                               /* we could probably send that P_DISCARD_ACK ourselves,
+                                * but I don't like the receiver using the msock */
+
+                               put_ldev(mdev);
+                               wake_asender(mdev);
+                               finish_wait(&mdev->misc_wait, &wait);
+                               return TRUE;
+                       }
+
+                       if (signal_pending(current)) {
+                               hlist_del_init(&e->colision);
+
+                               spin_unlock_irq(&mdev->req_lock);
+
+                               finish_wait(&mdev->misc_wait, &wait);
+                               goto out_interrupted;
+                       }
+
+                       spin_unlock_irq(&mdev->req_lock);
+                       if (first) {
+                               first = 0;
+                               dev_alert(DEV, "Concurrent write! [W AFTERWARDS] "
+                                    "sec=%llus\n", (unsigned long long)sector);
+                       } else if (discard) {
+                               /* we had none on the first iteration.
+                                * there must be none now. */
+                               D_ASSERT(have_unacked == 0);
+                       }
+                       schedule();
+                       spin_lock_irq(&mdev->req_lock);
+               }
+               finish_wait(&mdev->misc_wait, &wait);
+       }
+
+       list_add(&e->w.list, &mdev->active_ee);
+       spin_unlock_irq(&mdev->req_lock);
+
+       switch (mdev->net_conf->wire_protocol) {
+       case DRBD_PROT_C:
+               inc_unacked(mdev);
+               /* corresponding dec_unacked() in e_end_block()
+                * respective _drbd_clear_done_ee */
+               break;
+       case DRBD_PROT_B:
+               /* I really don't like it that the receiver thread
+                * sends on the msock, but anyways */
+               drbd_send_ack(mdev, P_RECV_ACK, e);
+               break;
+       case DRBD_PROT_A:
+               /* nothing to do */
+               break;
+       }
+
+       if (mdev->state.pdsk == D_DISKLESS) {
+               /* In case we have the only disk of the cluster, */
+               drbd_set_out_of_sync(mdev, e->sector, e->size);
+               e->flags |= EE_CALL_AL_COMPLETE_IO;
+               drbd_al_begin_io(mdev, e->sector);
+       }
+
+       e->private_bio->bi_rw = rw;
+       drbd_generic_make_request(mdev, DRBD_FAULT_DT_WR, e->private_bio);
+       /* accounting done in endio */
+
+       maybe_kick_lo(mdev);
+       return TRUE;
+
+out_interrupted:
+       /* yes, the epoch_size now is imbalanced.
+        * but we drop the connection anyways, so we don't have a chance to
+        * receive a barrier... atomic_inc(&mdev->epoch_size); */
+       put_ldev(mdev);
+       drbd_free_ee(mdev, e);
+       return FALSE;
+}
+
+static int receive_DataRequest(struct drbd_conf *mdev, struct p_header *h)
+{
+       sector_t sector;
+       const sector_t capacity = drbd_get_capacity(mdev->this_bdev);
+       struct drbd_epoch_entry *e;
+       struct digest_info *di = NULL;
+       int size, digest_size;
+       unsigned int fault_type;
+       struct p_block_req *p =
+               (struct p_block_req *)h;
+       const int brps = sizeof(*p)-sizeof(*h);
+
+       if (drbd_recv(mdev, h->payload, brps) != brps)
+               return FALSE;
+
+       sector = be64_to_cpu(p->sector);
+       size   = be32_to_cpu(p->blksize);
+
+       if (size <= 0 || (size & 0x1ff) != 0 || size > DRBD_MAX_SEGMENT_SIZE) {
+               dev_err(DEV, "%s:%d: sector: %llus, size: %u\n", __FILE__, __LINE__,
+                               (unsigned long long)sector, size);
+               return FALSE;
+       }
+       if (sector + (size>>9) > capacity) {
+               dev_err(DEV, "%s:%d: sector: %llus, size: %u\n", __FILE__, __LINE__,
+                               (unsigned long long)sector, size);
+               return FALSE;
+       }
+
+       if (!get_ldev_if_state(mdev, D_UP_TO_DATE)) {
+               if (__ratelimit(&drbd_ratelimit_state))
+                       dev_err(DEV, "Can not satisfy peer's read request, "
+                           "no local data.\n");
+               drbd_send_ack_rp(mdev, h->command == P_DATA_REQUEST ? P_NEG_DREPLY :
+                                P_NEG_RS_DREPLY , p);
+               return TRUE;
+       }
+
+       /* GFP_NOIO, because we must not cause arbitrary write-out: in a DRBD
+        * "criss-cross" setup, that might cause write-out on some other DRBD,
+        * which in turn might block on the other node at this very place.  */
+       e = drbd_alloc_ee(mdev, p->block_id, sector, size, GFP_NOIO);
+       if (!e) {
+               put_ldev(mdev);
+               return FALSE;
+       }
+
+       e->private_bio->bi_rw = READ;
+       e->private_bio->bi_end_io = drbd_endio_read_sec;
+
+       switch (h->command) {
+       case P_DATA_REQUEST:
+               e->w.cb = w_e_end_data_req;
+               fault_type = DRBD_FAULT_DT_RD;
+               break;
+       case P_RS_DATA_REQUEST:
+               e->w.cb = w_e_end_rsdata_req;
+               fault_type = DRBD_FAULT_RS_RD;
+               /* Eventually this should become asynchronously. Currently it
+                * blocks the whole receiver just to delay the reading of a
+                * resync data block.
+                * the drbd_work_queue mechanism is made for this...
+                */
+               if (!drbd_rs_begin_io(mdev, sector)) {
+                       /* we have been interrupted,
+                        * probably connection lost! */
+                       D_ASSERT(signal_pending(current));
+                       goto out_free_e;
+               }
+               break;
+
+       case P_OV_REPLY:
+       case P_CSUM_RS_REQUEST:
+               fault_type = DRBD_FAULT_RS_RD;
+               digest_size = h->length - brps ;
+               di = kmalloc(sizeof(*di) + digest_size, GFP_NOIO);
+               if (!di)
+                       goto out_free_e;
+
+               di->digest_size = digest_size;
+               di->digest = (((char *)di)+sizeof(struct digest_info));
+
+               if (drbd_recv(mdev, di->digest, digest_size) != digest_size)
+                       goto out_free_e;
+
+               e->block_id = (u64)(unsigned long)di;
+               if (h->command == P_CSUM_RS_REQUEST) {
+                       D_ASSERT(mdev->agreed_pro_version >= 89);
+                       e->w.cb = w_e_end_csum_rs_req;
+               } else if (h->command == P_OV_REPLY) {
+                       e->w.cb = w_e_end_ov_reply;
+                       dec_rs_pending(mdev);
+                       break;
+               }
+
+               if (!drbd_rs_begin_io(mdev, sector)) {
+                       /* we have been interrupted, probably connection lost! */
+                       D_ASSERT(signal_pending(current));
+                       goto out_free_e;
+               }
+               break;
+
+       case P_OV_REQUEST:
+               if (mdev->state.conn >= C_CONNECTED &&
+                   mdev->state.conn != C_VERIFY_T)
+                       dev_warn(DEV, "ASSERT FAILED: got P_OV_REQUEST while being %s\n",
+                               drbd_conn_str(mdev->state.conn));
+               if (mdev->ov_start_sector == ~(sector_t)0 &&
+                   mdev->agreed_pro_version >= 90) {
+                       mdev->ov_start_sector = sector;
+                       mdev->ov_position = sector;
+                       mdev->ov_left = mdev->rs_total - BM_SECT_TO_BIT(sector);
+                       dev_info(DEV, "Online Verify start sector: %llu\n",
+                                       (unsigned long long)sector);
+               }
+               e->w.cb = w_e_end_ov_req;
+               fault_type = DRBD_FAULT_RS_RD;
+               /* Eventually this should become asynchronous. Currently it
+                * blocks the whole receiver just to delay the reading of a
+                * resync data block.
+                * the drbd_work_queue mechanism is made for this...
+                */
+               if (!drbd_rs_begin_io(mdev, sector)) {
+                       /* we have been interrupted,
+                        * probably connection lost! */
+                       D_ASSERT(signal_pending(current));
+                       goto out_free_e;
+               }
+               break;
+
+
+       default:
+               dev_err(DEV, "unexpected command (%s) in receive_DataRequest\n",
+                   cmdname(h->command));
+               fault_type = DRBD_FAULT_MAX;
+       }
+
+       spin_lock_irq(&mdev->req_lock);
+       list_add(&e->w.list, &mdev->read_ee);
+       spin_unlock_irq(&mdev->req_lock);
+
+       inc_unacked(mdev);
+
+       drbd_generic_make_request(mdev, fault_type, e->private_bio);
+       maybe_kick_lo(mdev);
+
+       return TRUE;
+
+out_free_e:
+       kfree(di);
+       put_ldev(mdev);
+       drbd_free_ee(mdev, e);
+       return FALSE;
+}
+
+static int drbd_asb_recover_0p(struct drbd_conf *mdev) __must_hold(local)
+{
+       int self, peer, rv = -100;
+       unsigned long ch_self, ch_peer;
+
+       self = mdev->ldev->md.uuid[UI_BITMAP] & 1;
+       peer = mdev->p_uuid[UI_BITMAP] & 1;
+
+       ch_peer = mdev->p_uuid[UI_SIZE];
+       ch_self = mdev->comm_bm_set;
+
+       switch (mdev->net_conf->after_sb_0p) {
+       case ASB_CONSENSUS:
+       case ASB_DISCARD_SECONDARY:
+       case ASB_CALL_HELPER:
+               dev_err(DEV, "Configuration error.\n");
+               break;
+       case ASB_DISCONNECT:
+               break;
+       case ASB_DISCARD_YOUNGER_PRI:
+               if (self == 0 && peer == 1) {
+                       rv = -1;
+                       break;
+               }
+               if (self == 1 && peer == 0) {
+                       rv =  1;
+                       break;
+               }
+               /* Else fall through to one of the other strategies... */
+       case ASB_DISCARD_OLDER_PRI:
+               if (self == 0 && peer == 1) {
+                       rv = 1;
+                       break;
+               }
+               if (self == 1 && peer == 0) {
+                       rv = -1;
+                       break;
+               }
+               /* Else fall through to one of the other strategies... */
+               dev_warn(DEV, "Discard younger/older primary did not find a decision\n"
+                    "Using discard-least-changes instead\n");
+       case ASB_DISCARD_ZERO_CHG:
+               if (ch_peer == 0 && ch_self == 0) {
+                       rv = test_bit(DISCARD_CONCURRENT, &mdev->flags)
+                               ? -1 : 1;
+                       break;
+               } else {
+                       if (ch_peer == 0) { rv =  1; break; }
+                       if (ch_self == 0) { rv = -1; break; }
+               }
+               if (mdev->net_conf->after_sb_0p == ASB_DISCARD_ZERO_CHG)
+                       break;
+       case ASB_DISCARD_LEAST_CHG:
+               if      (ch_self < ch_peer)
+                       rv = -1;
+               else if (ch_self > ch_peer)
+                       rv =  1;
+               else /* ( ch_self == ch_peer ) */
+                    /* Well, then use something else. */
+                       rv = test_bit(DISCARD_CONCURRENT, &mdev->flags)
+                               ? -1 : 1;
+               break;
+       case ASB_DISCARD_LOCAL:
+               rv = -1;
+               break;
+       case ASB_DISCARD_REMOTE:
+               rv =  1;
+       }
+
+       return rv;
+}
+
+static int drbd_asb_recover_1p(struct drbd_conf *mdev) __must_hold(local)
+{
+       int self, peer, hg, rv = -100;
+
+       self = mdev->ldev->md.uuid[UI_BITMAP] & 1;
+       peer = mdev->p_uuid[UI_BITMAP] & 1;
+
+       switch (mdev->net_conf->after_sb_1p) {
+       case ASB_DISCARD_YOUNGER_PRI:
+       case ASB_DISCARD_OLDER_PRI:
+       case ASB_DISCARD_LEAST_CHG:
+       case ASB_DISCARD_LOCAL:
+       case ASB_DISCARD_REMOTE:
+               dev_err(DEV, "Configuration error.\n");
+               break;
+       case ASB_DISCONNECT:
+               break;
+       case ASB_CONSENSUS:
+               hg = drbd_asb_recover_0p(mdev);
+               if (hg == -1 && mdev->state.role == R_SECONDARY)
+                       rv = hg;
+               if (hg == 1  && mdev->state.role == R_PRIMARY)
+                       rv = hg;
+               break;
+       case ASB_VIOLENTLY:
+               rv = drbd_asb_recover_0p(mdev);
+               break;
+       case ASB_DISCARD_SECONDARY:
+               return mdev->state.role == R_PRIMARY ? 1 : -1;
+       case ASB_CALL_HELPER:
+               hg = drbd_asb_recover_0p(mdev);
+               if (hg == -1 && mdev->state.role == R_PRIMARY) {
+                       self = drbd_set_role(mdev, R_SECONDARY, 0);
+                        /* drbd_change_state() does not sleep while in SS_IN_TRANSIENT_STATE,
+                         * we might be here in C_WF_REPORT_PARAMS which is transient.
+                         * we do not need to wait for the after state change work either. */
+                       self = drbd_change_state(mdev, CS_VERBOSE, NS(role, R_SECONDARY));
+                       if (self != SS_SUCCESS) {
+                               drbd_khelper(mdev, "pri-lost-after-sb");
+                       } else {
+                               dev_warn(DEV, "Successfully gave up primary role.\n");
+                               rv = hg;
+                       }
+               } else
+                       rv = hg;
+       }
+
+       return rv;
+}
+
+static int drbd_asb_recover_2p(struct drbd_conf *mdev) __must_hold(local)
+{
+       int self, peer, hg, rv = -100;
+
+       self = mdev->ldev->md.uuid[UI_BITMAP] & 1;
+       peer = mdev->p_uuid[UI_BITMAP] & 1;
+
+       switch (mdev->net_conf->after_sb_2p) {
+       case ASB_DISCARD_YOUNGER_PRI:
+       case ASB_DISCARD_OLDER_PRI:
+       case ASB_DISCARD_LEAST_CHG:
+       case ASB_DISCARD_LOCAL:
+       case ASB_DISCARD_REMOTE:
+       case ASB_CONSENSUS:
+       case ASB_DISCARD_SECONDARY:
+               dev_err(DEV, "Configuration error.\n");
+               break;
+       case ASB_VIOLENTLY:
+               rv = drbd_asb_recover_0p(mdev);
+               break;
+       case ASB_DISCONNECT:
+               break;
+       case ASB_CALL_HELPER:
+               hg = drbd_asb_recover_0p(mdev);
+               if (hg == -1) {
+                        /* drbd_change_state() does not sleep while in SS_IN_TRANSIENT_STATE,
+                         * we might be here in C_WF_REPORT_PARAMS which is transient.
+                         * we do not need to wait for the after state change work either. */
+                       self = drbd_change_state(mdev, CS_VERBOSE, NS(role, R_SECONDARY));
+                       if (self != SS_SUCCESS) {
+                               drbd_khelper(mdev, "pri-lost-after-sb");
+                       } else {
+                               dev_warn(DEV, "Successfully gave up primary role.\n");
+                               rv = hg;
+                       }
+               } else
+                       rv = hg;
+       }
+
+       return rv;
+}
+
+static void drbd_uuid_dump(struct drbd_conf *mdev, char *text, u64 *uuid,
+                          u64 bits, u64 flags)
+{
+       if (!uuid) {
+               dev_info(DEV, "%s uuid info vanished while I was looking!\n", text);
+               return;
+       }
+       dev_info(DEV, "%s %016llX:%016llX:%016llX:%016llX bits:%llu flags:%llX\n",
+            text,
+            (unsigned long long)uuid[UI_CURRENT],
+            (unsigned long long)uuid[UI_BITMAP],
+            (unsigned long long)uuid[UI_HISTORY_START],
+            (unsigned long long)uuid[UI_HISTORY_END],
+            (unsigned long long)bits,
+            (unsigned long long)flags);
+}
+
+/*
+  100  after split brain try auto recover
+    2  C_SYNC_SOURCE set BitMap
+    1  C_SYNC_SOURCE use BitMap
+    0  no Sync
+   -1  C_SYNC_TARGET use BitMap
+   -2  C_SYNC_TARGET set BitMap
+ -100  after split brain, disconnect
+-1000  unrelated data
+ */
+static int drbd_uuid_compare(struct drbd_conf *mdev, int *rule_nr) __must_hold(local)
+{
+       u64 self, peer;
+       int i, j;
+
+       self = mdev->ldev->md.uuid[UI_CURRENT] & ~((u64)1);
+       peer = mdev->p_uuid[UI_CURRENT] & ~((u64)1);
+
+       *rule_nr = 10;
+       if (self == UUID_JUST_CREATED && peer == UUID_JUST_CREATED)
+               return 0;
+
+       *rule_nr = 20;
+       if ((self == UUID_JUST_CREATED || self == (u64)0) &&
+            peer != UUID_JUST_CREATED)
+               return -2;
+
+       *rule_nr = 30;
+       if (self != UUID_JUST_CREATED &&
+           (peer == UUID_JUST_CREATED || peer == (u64)0))
+               return 2;
+
+       if (self == peer) {
+               int rct, dc; /* roles at crash time */
+
+               if (mdev->p_uuid[UI_BITMAP] == (u64)0 && mdev->ldev->md.uuid[UI_BITMAP] != (u64)0) {
+
+                       if (mdev->agreed_pro_version < 91)
+                               return -1001;
+
+                       if ((mdev->ldev->md.uuid[UI_BITMAP] & ~((u64)1)) == (mdev->p_uuid[UI_HISTORY_START] & ~((u64)1)) &&
+                           (mdev->ldev->md.uuid[UI_HISTORY_START] & ~((u64)1)) == (mdev->p_uuid[UI_HISTORY_START + 1] & ~((u64)1))) {
+                               dev_info(DEV, "was SyncSource, missed the resync finished event, corrected myself:\n");
+                               drbd_uuid_set_bm(mdev, 0UL);
+
+                               drbd_uuid_dump(mdev, "self", mdev->ldev->md.uuid,
+                                              mdev->state.disk >= D_NEGOTIATING ? drbd_bm_total_weight(mdev) : 0, 0);
+                               *rule_nr = 34;
+                       } else {
+                               dev_info(DEV, "was SyncSource (peer failed to write sync_uuid)\n");
+                               *rule_nr = 36;
+                       }
+
+                       return 1;
+               }
+
+               if (mdev->ldev->md.uuid[UI_BITMAP] == (u64)0 && mdev->p_uuid[UI_BITMAP] != (u64)0) {
+
+                       if (mdev->agreed_pro_version < 91)
+                               return -1001;
+
+                       if ((mdev->ldev->md.uuid[UI_HISTORY_START] & ~((u64)1)) == (mdev->p_uuid[UI_BITMAP] & ~((u64)1)) &&
+                           (mdev->ldev->md.uuid[UI_HISTORY_START + 1] & ~((u64)1)) == (mdev->p_uuid[UI_HISTORY_START] & ~((u64)1))) {
+                               dev_info(DEV, "was SyncTarget, peer missed the resync finished event, corrected peer:\n");
+
+                               mdev->p_uuid[UI_HISTORY_START + 1] = mdev->p_uuid[UI_HISTORY_START];
+                               mdev->p_uuid[UI_HISTORY_START] = mdev->p_uuid[UI_BITMAP];
+                               mdev->p_uuid[UI_BITMAP] = 0UL;
+
+                               drbd_uuid_dump(mdev, "peer", mdev->p_uuid, mdev->p_uuid[UI_SIZE], mdev->p_uuid[UI_FLAGS]);
+                               *rule_nr = 35;
+                       } else {
+                               dev_info(DEV, "was SyncTarget (failed to write sync_uuid)\n");
+                               *rule_nr = 37;
+                       }
+
+                       return -1;
+               }
+
+               /* Common power [off|failure] */
+               rct = (test_bit(CRASHED_PRIMARY, &mdev->flags) ? 1 : 0) +
+                       (mdev->p_uuid[UI_FLAGS] & 2);
+               /* lowest bit is set when we were primary,
+                * next bit (weight 2) is set when peer was primary */
+               *rule_nr = 40;
+
+               switch (rct) {
+               case 0: /* !self_pri && !peer_pri */ return 0;
+               case 1: /*  self_pri && !peer_pri */ return 1;
+               case 2: /* !self_pri &&  peer_pri */ return -1;
+               case 3: /*  self_pri &&  peer_pri */
+                       dc = test_bit(DISCARD_CONCURRENT, &mdev->flags);
+                       return dc ? -1 : 1;
+               }
+       }
+
+       *rule_nr = 50;
+       peer = mdev->p_uuid[UI_BITMAP] & ~((u64)1);
+       if (self == peer)
+               return -1;
+
+       *rule_nr = 51;
+       peer = mdev->p_uuid[UI_HISTORY_START] & ~((u64)1);
+       if (self == peer) {
+               self = mdev->ldev->md.uuid[UI_HISTORY_START] & ~((u64)1);
+               peer = mdev->p_uuid[UI_HISTORY_START + 1] & ~((u64)1);
+               if (self == peer) {
+                       /* The last P_SYNC_UUID did not get though. Undo the last start of
+                          resync as sync source modifications of the peer's UUIDs. */
+
+                       if (mdev->agreed_pro_version < 91)
+                               return -1001;
+
+                       mdev->p_uuid[UI_BITMAP] = mdev->p_uuid[UI_HISTORY_START];
+                       mdev->p_uuid[UI_HISTORY_START] = mdev->p_uuid[UI_HISTORY_START + 1];
+                       return -1;
+               }
+       }
+
+       *rule_nr = 60;
+       self = mdev->ldev->md.uuid[UI_CURRENT] & ~((u64)1);
+       for (i = UI_HISTORY_START; i <= UI_HISTORY_END; i++) {
+               peer = mdev->p_uuid[i] & ~((u64)1);
+               if (self == peer)
+                       return -2;
+       }
+
+       *rule_nr = 70;
+       self = mdev->ldev->md.uuid[UI_BITMAP] & ~((u64)1);
+       peer = mdev->p_uuid[UI_CURRENT] & ~((u64)1);
+       if (self == peer)
+               return 1;
+
+       *rule_nr = 71;
+       self = mdev->ldev->md.uuid[UI_HISTORY_START] & ~((u64)1);
+       if (self == peer) {
+               self = mdev->ldev->md.uuid[UI_HISTORY_START + 1] & ~((u64)1);
+               peer = mdev->p_uuid[UI_HISTORY_START] & ~((u64)1);
+               if (self == peer) {
+                       /* The last P_SYNC_UUID did not get though. Undo the last start of
+                          resync as sync source modifications of our UUIDs. */
+
+                       if (mdev->agreed_pro_version < 91)
+                               return -1001;
+
+                       _drbd_uuid_set(mdev, UI_BITMAP, mdev->ldev->md.uuid[UI_HISTORY_START]);
+                       _drbd_uuid_set(mdev, UI_HISTORY_START, mdev->ldev->md.uuid[UI_HISTORY_START + 1]);
+
+                       dev_info(DEV, "Undid last start of resync:\n");
+
+                       drbd_uuid_dump(mdev, "self", mdev->ldev->md.uuid,
+                                      mdev->state.disk >= D_NEGOTIATING ? drbd_bm_total_weight(mdev) : 0, 0);
+
+                       return 1;
+               }
+       }
+
+
+       *rule_nr = 80;
+       peer = mdev->p_uuid[UI_CURRENT] & ~((u64)1);
+       for (i = UI_HISTORY_START; i <= UI_HISTORY_END; i++) {
+               self = mdev->ldev->md.uuid[i] & ~((u64)1);
+               if (self == peer)
+                       return 2;
+       }
+
+       *rule_nr = 90;
+       self = mdev->ldev->md.uuid[UI_BITMAP] & ~((u64)1);
+       peer = mdev->p_uuid[UI_BITMAP] & ~((u64)1);
+       if (self == peer && self != ((u64)0))
+               return 100;
+
+       *rule_nr = 100;
+       for (i = UI_HISTORY_START; i <= UI_HISTORY_END; i++) {
+               self = mdev->ldev->md.uuid[i] & ~((u64)1);
+               for (j = UI_HISTORY_START; j <= UI_HISTORY_END; j++) {
+                       peer = mdev->p_uuid[j] & ~((u64)1);
+                       if (self == peer)
+                               return -100;
+               }
+       }
+
+       return -1000;
+}
+
+/* drbd_sync_handshake() returns the new conn state on success, or
+   CONN_MASK (-1) on failure.
+ */
+static enum drbd_conns drbd_sync_handshake(struct drbd_conf *mdev, enum drbd_role peer_role,
+                                          enum drbd_disk_state peer_disk) __must_hold(local)
+{
+       int hg, rule_nr;
+       enum drbd_conns rv = C_MASK;
+       enum drbd_disk_state mydisk;
+
+       mydisk = mdev->state.disk;
+       if (mydisk == D_NEGOTIATING)
+               mydisk = mdev->new_state_tmp.disk;
+
+       dev_info(DEV, "drbd_sync_handshake:\n");
+       drbd_uuid_dump(mdev, "self", mdev->ldev->md.uuid, mdev->comm_bm_set, 0);
+       drbd_uuid_dump(mdev, "peer", mdev->p_uuid,
+                      mdev->p_uuid[UI_SIZE], mdev->p_uuid[UI_FLAGS]);
+
+       hg = drbd_uuid_compare(mdev, &rule_nr);
+
+       dev_info(DEV, "uuid_compare()=%d by rule %d\n", hg, rule_nr);
+
+       if (hg == -1000) {
+               dev_alert(DEV, "Unrelated data, aborting!\n");
+               return C_MASK;
+       }
+       if (hg == -1001) {
+               dev_alert(DEV, "To resolve this both sides have to support at least protocol\n");
+               return C_MASK;
+       }
+
+       if    ((mydisk == D_INCONSISTENT && peer_disk > D_INCONSISTENT) ||
+           (peer_disk == D_INCONSISTENT && mydisk    > D_INCONSISTENT)) {
+               int f = (hg == -100) || abs(hg) == 2;
+               hg = mydisk > D_INCONSISTENT ? 1 : -1;
+               if (f)
+                       hg = hg*2;
+               dev_info(DEV, "Becoming sync %s due to disk states.\n",
+                    hg > 0 ? "source" : "target");
+       }
+
+       if (hg == 100 || (hg == -100 && mdev->net_conf->always_asbp)) {
+               int pcount = (mdev->state.role == R_PRIMARY)
+                          + (peer_role == R_PRIMARY);
+               int forced = (hg == -100);
+
+               switch (pcount) {
+               case 0:
+                       hg = drbd_asb_recover_0p(mdev);
+                       break;
+               case 1:
+                       hg = drbd_asb_recover_1p(mdev);
+                       break;
+               case 2:
+                       hg = drbd_asb_recover_2p(mdev);
+                       break;
+               }
+               if (abs(hg) < 100) {
+                       dev_warn(DEV, "Split-Brain detected, %d primaries, "
+                            "automatically solved. Sync from %s node\n",
+                            pcount, (hg < 0) ? "peer" : "this");
+                       if (forced) {
+                               dev_warn(DEV, "Doing a full sync, since"
+                                    " UUIDs where ambiguous.\n");
+                               hg = hg*2;
+                       }
+               }
+       }
+
+       if (hg == -100) {
+               if (mdev->net_conf->want_lose && !(mdev->p_uuid[UI_FLAGS]&1))
+                       hg = -1;
+               if (!mdev->net_conf->want_lose && (mdev->p_uuid[UI_FLAGS]&1))
+                       hg = 1;
+
+               if (abs(hg) < 100)
+                       dev_warn(DEV, "Split-Brain detected, manually solved. "
+                            "Sync from %s node\n",
+                            (hg < 0) ? "peer" : "this");
+       }
+
+       if (hg == -100) {
+               dev_alert(DEV, "Split-Brain detected, dropping connection!\n");
+               drbd_khelper(mdev, "split-brain");
+               return C_MASK;
+       }
+
+       if (hg > 0 && mydisk <= D_INCONSISTENT) {
+               dev_err(DEV, "I shall become SyncSource, but I am inconsistent!\n");
+               return C_MASK;
+       }
+
+       if (hg < 0 && /* by intention we do not use mydisk here. */
+           mdev->state.role == R_PRIMARY && mdev->state.disk >= D_CONSISTENT) {
+               switch (mdev->net_conf->rr_conflict) {
+               case ASB_CALL_HELPER:
+                       drbd_khelper(mdev, "pri-lost");
+                       /* fall through */
+               case ASB_DISCONNECT:
+                       dev_err(DEV, "I shall become SyncTarget, but I am primary!\n");
+                       return C_MASK;
+               case ASB_VIOLENTLY:
+                       dev_warn(DEV, "Becoming SyncTarget, violating the stable-data"
+                            "assumption\n");
+               }
+       }
+
+       if (abs(hg) >= 2) {
+               dev_info(DEV, "Writing the whole bitmap, full sync required after drbd_sync_handshake.\n");
+               if (drbd_bitmap_io(mdev, &drbd_bmio_set_n_write, "set_n_write from sync_handshake"))
+                       return C_MASK;
+       }
+
+       if (hg > 0) { /* become sync source. */
+               rv = C_WF_BITMAP_S;
+       } else if (hg < 0) { /* become sync target */
+               rv = C_WF_BITMAP_T;
+       } else {
+               rv = C_CONNECTED;
+               if (drbd_bm_total_weight(mdev)) {
+                       dev_info(DEV, "No resync, but %lu bits in bitmap!\n",
+                            drbd_bm_total_weight(mdev));
+               }
+       }
+
+       return rv;
+}
+
+/* returns 1 if invalid */
+static int cmp_after_sb(enum drbd_after_sb_p peer, enum drbd_after_sb_p self)
+{
+       /* ASB_DISCARD_REMOTE - ASB_DISCARD_LOCAL is valid */
+       if ((peer == ASB_DISCARD_REMOTE && self == ASB_DISCARD_LOCAL) ||
+           (self == ASB_DISCARD_REMOTE && peer == ASB_DISCARD_LOCAL))
+               return 0;
+
+       /* any other things with ASB_DISCARD_REMOTE or ASB_DISCARD_LOCAL are invalid */
+       if (peer == ASB_DISCARD_REMOTE || peer == ASB_DISCARD_LOCAL ||
+           self == ASB_DISCARD_REMOTE || self == ASB_DISCARD_LOCAL)
+               return 1;
+
+       /* everything else is valid if they are equal on both sides. */
+       if (peer == self)
+               return 0;
+
+       /* everything es is invalid. */
+       return 1;
+}
+
+static int receive_protocol(struct drbd_conf *mdev, struct p_header *h)
+{
+       struct p_protocol *p = (struct p_protocol *)h;
+       int header_size, data_size;
+       int p_proto, p_after_sb_0p, p_after_sb_1p, p_after_sb_2p;
+       int p_want_lose, p_two_primaries;
+       char p_integrity_alg[SHARED_SECRET_MAX] = "";
+
+       header_size = sizeof(*p) - sizeof(*h);
+       data_size   = h->length  - header_size;
+
+       if (drbd_recv(mdev, h->payload, header_size) != header_size)
+               return FALSE;
+
+       p_proto         = be32_to_cpu(p->protocol);
+       p_after_sb_0p   = be32_to_cpu(p->after_sb_0p);
+       p_after_sb_1p   = be32_to_cpu(p->after_sb_1p);
+       p_after_sb_2p   = be32_to_cpu(p->after_sb_2p);
+       p_want_lose     = be32_to_cpu(p->want_lose);
+       p_two_primaries = be32_to_cpu(p->two_primaries);
+
+       if (p_proto != mdev->net_conf->wire_protocol) {
+               dev_err(DEV, "incompatible communication protocols\n");
+               goto disconnect;
+       }
+
+       if (cmp_after_sb(p_after_sb_0p, mdev->net_conf->after_sb_0p)) {
+               dev_err(DEV, "incompatible after-sb-0pri settings\n");
+               goto disconnect;
+       }
+
+       if (cmp_after_sb(p_after_sb_1p, mdev->net_conf->after_sb_1p)) {
+               dev_err(DEV, "incompatible after-sb-1pri settings\n");
+               goto disconnect;
+       }
+
+       if (cmp_after_sb(p_after_sb_2p, mdev->net_conf->after_sb_2p)) {
+               dev_err(DEV, "incompatible after-sb-2pri settings\n");
+               goto disconnect;
+       }
+
+       if (p_want_lose && mdev->net_conf->want_lose) {
+               dev_err(DEV, "both sides have the 'want_lose' flag set\n");
+               goto disconnect;
+       }
+
+       if (p_two_primaries != mdev->net_conf->two_primaries) {
+               dev_err(DEV, "incompatible setting of the two-primaries options\n");
+               goto disconnect;
+       }
+
+       if (mdev->agreed_pro_version >= 87) {
+               unsigned char *my_alg = mdev->net_conf->integrity_alg;
+
+               if (drbd_recv(mdev, p_integrity_alg, data_size) != data_size)
+                       return FALSE;
+
+               p_integrity_alg[SHARED_SECRET_MAX-1] = 0;
+               if (strcmp(p_integrity_alg, my_alg)) {
+                       dev_err(DEV, "incompatible setting of the data-integrity-alg\n");
+                       goto disconnect;
+               }
+               dev_info(DEV, "data-integrity-alg: %s\n",
+                    my_alg[0] ? my_alg : (unsigned char *)"<not-used>");
+       }
+
+       return TRUE;
+
+disconnect:
+       drbd_force_state(mdev, NS(conn, C_DISCONNECTING));
+       return FALSE;
+}
+
+/* helper function
+ * input: alg name, feature name
+ * return: NULL (alg name was "")
+ *         ERR_PTR(error) if something goes wrong
+ *         or the crypto hash ptr, if it worked out ok. */
+struct crypto_hash *drbd_crypto_alloc_digest_safe(const struct drbd_conf *mdev,
+               const char *alg, const char *name)
+{
+       struct crypto_hash *tfm;
+
+       if (!alg[0])
+               return NULL;
+
+       tfm = crypto_alloc_hash(alg, 0, CRYPTO_ALG_ASYNC);
+       if (IS_ERR(tfm)) {
+               dev_err(DEV, "Can not allocate \"%s\" as %s (reason: %ld)\n",
+                       alg, name, PTR_ERR(tfm));
+               return tfm;
+       }
+       if (!drbd_crypto_is_hash(crypto_hash_tfm(tfm))) {
+               crypto_free_hash(tfm);
+               dev_err(DEV, "\"%s\" is not a digest (%s)\n", alg, name);
+               return ERR_PTR(-EINVAL);
+       }
+       return tfm;
+}
+
+static int receive_SyncParam(struct drbd_conf *mdev, struct p_header *h)
+{
+       int ok = TRUE;
+       struct p_rs_param_89 *p = (struct p_rs_param_89 *)h;
+       unsigned int header_size, data_size, exp_max_sz;
+       struct crypto_hash *verify_tfm = NULL;
+       struct crypto_hash *csums_tfm = NULL;
+       const int apv = mdev->agreed_pro_version;
+
+       exp_max_sz  = apv <= 87 ? sizeof(struct p_rs_param)
+                   : apv == 88 ? sizeof(struct p_rs_param)
+                                       + SHARED_SECRET_MAX
+                   : /* 89 */    sizeof(struct p_rs_param_89);
+
+       if (h->length > exp_max_sz) {
+               dev_err(DEV, "SyncParam packet too long: received %u, expected <= %u bytes\n",
+                   h->length, exp_max_sz);
+               return FALSE;
+       }
+
+       if (apv <= 88) {
+               header_size = sizeof(struct p_rs_param) - sizeof(*h);
+               data_size   = h->length  - header_size;
+       } else /* apv >= 89 */ {
+               header_size = sizeof(struct p_rs_param_89) - sizeof(*h);
+               data_size   = h->length  - header_size;
+               D_ASSERT(data_size == 0);
+       }
+
+       /* initialize verify_alg and csums_alg */
+       memset(p->verify_alg, 0, 2 * SHARED_SECRET_MAX);
+
+       if (drbd_recv(mdev, h->payload, header_size) != header_size)
+               return FALSE;
+
+       mdev->sync_conf.rate      = be32_to_cpu(p->rate);
+
+       if (apv >= 88) {
+               if (apv == 88) {
+                       if (data_size > SHARED_SECRET_MAX) {
+                               dev_err(DEV, "verify-alg too long, "
+                                   "peer wants %u, accepting only %u byte\n",
+                                               data_size, SHARED_SECRET_MAX);
+                               return FALSE;
+                       }
+
+                       if (drbd_recv(mdev, p->verify_alg, data_size) != data_size)
+                               return FALSE;
+
+                       /* we expect NUL terminated string */
+                       /* but just in case someone tries to be evil */
+                       D_ASSERT(p->verify_alg[data_size-1] == 0);
+                       p->verify_alg[data_size-1] = 0;
+
+               } else /* apv >= 89 */ {
+                       /* we still expect NUL terminated strings */
+                       /* but just in case someone tries to be evil */
+                       D_ASSERT(p->verify_alg[SHARED_SECRET_MAX-1] == 0);
+                       D_ASSERT(p->csums_alg[SHARED_SECRET_MAX-1] == 0);
+                       p->verify_alg[SHARED_SECRET_MAX-1] = 0;
+                       p->csums_alg[SHARED_SECRET_MAX-1] = 0;
+               }
+
+               if (strcmp(mdev->sync_conf.verify_alg, p->verify_alg)) {
+                       if (mdev->state.conn == C_WF_REPORT_PARAMS) {
+                               dev_err(DEV, "Different verify-alg settings. me=\"%s\" peer=\"%s\"\n",
+                                   mdev->sync_conf.verify_alg, p->verify_alg);
+                               goto disconnect;
+                       }
+                       verify_tfm = drbd_crypto_alloc_digest_safe(mdev,
+                                       p->verify_alg, "verify-alg");
+                       if (IS_ERR(verify_tfm)) {
+                               verify_tfm = NULL;
+                               goto disconnect;
+                       }
+               }
+
+               if (apv >= 89 && strcmp(mdev->sync_conf.csums_alg, p->csums_alg)) {
+                       if (mdev->state.conn == C_WF_REPORT_PARAMS) {
+                               dev_err(DEV, "Different csums-alg settings. me=\"%s\" peer=\"%s\"\n",
+                                   mdev->sync_conf.csums_alg, p->csums_alg);
+                               goto disconnect;
+                       }
+                       csums_tfm = drbd_crypto_alloc_digest_safe(mdev,
+                                       p->csums_alg, "csums-alg");
+                       if (IS_ERR(csums_tfm)) {
+                               csums_tfm = NULL;
+                               goto disconnect;
+                       }
+               }
+
+
+               spin_lock(&mdev->peer_seq_lock);
+               /* lock against drbd_nl_syncer_conf() */
+               if (verify_tfm) {
+                       strcpy(mdev->sync_conf.verify_alg, p->verify_alg);
+                       mdev->sync_conf.verify_alg_len = strlen(p->verify_alg) + 1;
+                       crypto_free_hash(mdev->verify_tfm);
+                       mdev->verify_tfm = verify_tfm;
+                       dev_info(DEV, "using verify-alg: \"%s\"\n", p->verify_alg);
+               }
+               if (csums_tfm) {
+                       strcpy(mdev->sync_conf.csums_alg, p->csums_alg);
+                       mdev->sync_conf.csums_alg_len = strlen(p->csums_alg) + 1;
+                       crypto_free_hash(mdev->csums_tfm);
+                       mdev->csums_tfm = csums_tfm;
+                       dev_info(DEV, "using csums-alg: \"%s\"\n", p->csums_alg);
+               }
+               spin_unlock(&mdev->peer_seq_lock);
+       }
+
+       return ok;
+disconnect:
+       /* just for completeness: actually not needed,
+        * as this is not reached if csums_tfm was ok. */
+       crypto_free_hash(csums_tfm);
+       /* but free the verify_tfm again, if csums_tfm did not work out */
+       crypto_free_hash(verify_tfm);
+       drbd_force_state(mdev, NS(conn, C_DISCONNECTING));
+       return FALSE;
+}
+
+static void drbd_setup_order_type(struct drbd_conf *mdev, int peer)
+{
+       /* sorry, we currently have no working implementation
+        * of distributed TCQ */
+}
+
+/* warn if the arguments differ by more than 12.5% */
+static void warn_if_differ_considerably(struct drbd_conf *mdev,
+       const char *s, sector_t a, sector_t b)
+{
+       sector_t d;
+       if (a == 0 || b == 0)
+               return;
+       d = (a > b) ? (a - b) : (b - a);
+       if (d > (a>>3) || d > (b>>3))
+               dev_warn(DEV, "Considerable difference in %s: %llus vs. %llus\n", s,
+                    (unsigned long long)a, (unsigned long long)b);
+}
+
+static int receive_sizes(struct drbd_conf *mdev, struct p_header *h)
+{
+       struct p_sizes *p = (struct p_sizes *)h;
+       enum determine_dev_size dd = unchanged;
+       unsigned int max_seg_s;
+       sector_t p_size, p_usize, my_usize;
+       int ldsc = 0; /* local disk size changed */
+       enum drbd_conns nconn;
+
+       ERR_IF(h->length != (sizeof(*p)-sizeof(*h))) return FALSE;
+       if (drbd_recv(mdev, h->payload, h->length) != h->length)
+               return FALSE;
+
+       p_size = be64_to_cpu(p->d_size);
+       p_usize = be64_to_cpu(p->u_size);
+
+       if (p_size == 0 && mdev->state.disk == D_DISKLESS) {
+               dev_err(DEV, "some backing storage is needed\n");
+               drbd_force_state(mdev, NS(conn, C_DISCONNECTING));
+               return FALSE;
+       }
+
+       /* just store the peer's disk size for now.
+        * we still need to figure out whether we accept that. */
+       mdev->p_size = p_size;
+
+#define min_not_zero(l, r) (l == 0) ? r : ((r == 0) ? l : min(l, r))
+       if (get_ldev(mdev)) {
+               warn_if_differ_considerably(mdev, "lower level device sizes",
+                          p_size, drbd_get_max_capacity(mdev->ldev));
+               warn_if_differ_considerably(mdev, "user requested size",
+                                           p_usize, mdev->ldev->dc.disk_size);
+
+               /* if this is the first connect, or an otherwise expected
+                * param exchange, choose the minimum */
+               if (mdev->state.conn == C_WF_REPORT_PARAMS)
+                       p_usize = min_not_zero((sector_t)mdev->ldev->dc.disk_size,
+                                            p_usize);
+
+               my_usize = mdev->ldev->dc.disk_size;
+
+               if (mdev->ldev->dc.disk_size != p_usize) {
+                       mdev->ldev->dc.disk_size = p_usize;
+                       dev_info(DEV, "Peer sets u_size to %lu sectors\n",
+                            (unsigned long)mdev->ldev->dc.disk_size);
+               }
+
+               /* Never shrink a device with usable data during connect.
+                  But allow online shrinking if we are connected. */
+               if (drbd_new_dev_size(mdev, mdev->ldev) <
+                  drbd_get_capacity(mdev->this_bdev) &&
+                  mdev->state.disk >= D_OUTDATED &&
+                  mdev->state.conn < C_CONNECTED) {
+                       dev_err(DEV, "The peer's disk size is too small!\n");
+                       drbd_force_state(mdev, NS(conn, C_DISCONNECTING));
+                       mdev->ldev->dc.disk_size = my_usize;
+                       put_ldev(mdev);
+                       return FALSE;
+               }
+               put_ldev(mdev);
+       }
+#undef min_not_zero
+
+       if (get_ldev(mdev)) {
+               dd = drbd_determin_dev_size(mdev);
+               put_ldev(mdev);
+               if (dd == dev_size_error)
+                       return FALSE;
+               drbd_md_sync(mdev);
+       } else {
+               /* I am diskless, need to accept the peer's size. */
+               drbd_set_my_capacity(mdev, p_size);
+       }
+
+       if (mdev->p_uuid && mdev->state.conn <= C_CONNECTED && get_ldev(mdev)) {
+               nconn = drbd_sync_handshake(mdev,
+                               mdev->state.peer, mdev->state.pdsk);
+               put_ldev(mdev);
+
+               if (nconn == C_MASK) {
+                       drbd_force_state(mdev, NS(conn, C_DISCONNECTING));
+                       return FALSE;
+               }
+
+               if (drbd_request_state(mdev, NS(conn, nconn)) < SS_SUCCESS) {
+                       drbd_force_state(mdev, NS(conn, C_DISCONNECTING));
+                       return FALSE;
+               }
+       }
+
+       if (get_ldev(mdev)) {
+               if (mdev->ldev->known_size != drbd_get_capacity(mdev->ldev->backing_bdev)) {
+                       mdev->ldev->known_size = drbd_get_capacity(mdev->ldev->backing_bdev);
+                       ldsc = 1;
+               }
+
+               max_seg_s = be32_to_cpu(p->max_segment_size);
+               if (max_seg_s != queue_max_segment_size(mdev->rq_queue))
+                       drbd_setup_queue_param(mdev, max_seg_s);
+
+               drbd_setup_order_type(mdev, be32_to_cpu(p->queue_order_type));
+               put_ldev(mdev);
+       }
+
+       if (mdev->state.conn > C_WF_REPORT_PARAMS) {
+               if (be64_to_cpu(p->c_size) !=
+                   drbd_get_capacity(mdev->this_bdev) || ldsc) {
+                       /* we have different sizes, probably peer
+                        * needs to know my new size... */
+                       drbd_send_sizes(mdev, 0);
+               }
+               if (test_and_clear_bit(RESIZE_PENDING, &mdev->flags) ||
+                   (dd == grew && mdev->state.conn == C_CONNECTED)) {
+                       if (mdev->state.pdsk >= D_INCONSISTENT &&
+                           mdev->state.disk >= D_INCONSISTENT)
+                               resync_after_online_grow(mdev);
+                       else
+                               set_bit(RESYNC_AFTER_NEG, &mdev->flags);
+               }
+       }
+
+       return TRUE;
+}
+
+static int receive_uuids(struct drbd_conf *mdev, struct p_header *h)
+{
+       struct p_uuids *p = (struct p_uuids *)h;
+       u64 *p_uuid;
+       int i;
+
+       ERR_IF(h->length != (sizeof(*p)-sizeof(*h))) return FALSE;
+       if (drbd_recv(mdev, h->payload, h->length) != h->length)
+               return FALSE;
+
+       p_uuid = kmalloc(sizeof(u64)*UI_EXTENDED_SIZE, GFP_NOIO);
+
+       for (i = UI_CURRENT; i < UI_EXTENDED_SIZE; i++)
+               p_uuid[i] = be64_to_cpu(p->uuid[i]);
+
+       kfree(mdev->p_uuid);
+       mdev->p_uuid = p_uuid;
+
+       if (mdev->state.conn < C_CONNECTED &&
+           mdev->state.disk < D_INCONSISTENT &&
+           mdev->state.role == R_PRIMARY &&
+           (mdev->ed_uuid & ~((u64)1)) != (p_uuid[UI_CURRENT] & ~((u64)1))) {
+               dev_err(DEV, "Can only connect to data with current UUID=%016llX\n",
+                   (unsigned long long)mdev->ed_uuid);
+               drbd_force_state(mdev, NS(conn, C_DISCONNECTING));
+               return FALSE;
+       }
+
+       if (get_ldev(mdev)) {
+               int skip_initial_sync =
+                       mdev->state.conn == C_CONNECTED &&
+                       mdev->agreed_pro_version >= 90 &&
+                       mdev->ldev->md.uuid[UI_CURRENT] == UUID_JUST_CREATED &&
+                       (p_uuid[UI_FLAGS] & 8);
+               if (skip_initial_sync) {
+                       dev_info(DEV, "Accepted new current UUID, preparing to skip initial sync\n");
+                       drbd_bitmap_io(mdev, &drbd_bmio_clear_n_write,
+                                       "clear_n_write from receive_uuids");
+                       _drbd_uuid_set(mdev, UI_CURRENT, p_uuid[UI_CURRENT]);
+                       _drbd_uuid_set(mdev, UI_BITMAP, 0);
+                       _drbd_set_state(_NS2(mdev, disk, D_UP_TO_DATE, pdsk, D_UP_TO_DATE),
+                                       CS_VERBOSE, NULL);
+                       drbd_md_sync(mdev);
+               }
+               put_ldev(mdev);
+       }
+
+       /* Before we test for the disk state, we should wait until an eventually
+          ongoing cluster wide state change is finished. That is important if
+          we are primary and are detaching from our disk. We need to see the
+          new disk state... */
+       wait_event(mdev->misc_wait, !test_bit(CLUSTER_ST_CHANGE, &mdev->flags));
+       if (mdev->state.conn >= C_CONNECTED && mdev->state.disk < D_INCONSISTENT)
+               drbd_set_ed_uuid(mdev, p_uuid[UI_CURRENT]);
+
+       return TRUE;
+}
+
+/**
+ * convert_state() - Converts the peer's view of the cluster state to our point of view
+ * @ps:                The state as seen by the peer.
+ */
+static union drbd_state convert_state(union drbd_state ps)
+{
+       union drbd_state ms;
+
+       static enum drbd_conns c_tab[] = {
+               [C_CONNECTED] = C_CONNECTED,
+
+               [C_STARTING_SYNC_S] = C_STARTING_SYNC_T,
+               [C_STARTING_SYNC_T] = C_STARTING_SYNC_S,
+               [C_DISCONNECTING] = C_TEAR_DOWN, /* C_NETWORK_FAILURE, */
+               [C_VERIFY_S]       = C_VERIFY_T,
+               [C_MASK]   = C_MASK,
+       };
+
+       ms.i = ps.i;
+
+       ms.conn = c_tab[ps.conn];
+       ms.peer = ps.role;
+       ms.role = ps.peer;
+       ms.pdsk = ps.disk;
+       ms.disk = ps.pdsk;
+       ms.peer_isp = (ps.aftr_isp | ps.user_isp);
+
+       return ms;
+}
+
+static int receive_req_state(struct drbd_conf *mdev, struct p_header *h)
+{
+       struct p_req_state *p = (struct p_req_state *)h;
+       union drbd_state mask, val;
+       int rv;
+
+       ERR_IF(h->length != (sizeof(*p)-sizeof(*h))) return FALSE;
+       if (drbd_recv(mdev, h->payload, h->length) != h->length)
+               return FALSE;
+
+       mask.i = be32_to_cpu(p->mask);
+       val.i = be32_to_cpu(p->val);
+
+       if (test_bit(DISCARD_CONCURRENT, &mdev->flags) &&
+           test_bit(CLUSTER_ST_CHANGE, &mdev->flags)) {
+               drbd_send_sr_reply(mdev, SS_CONCURRENT_ST_CHG);
+               return TRUE;
+       }
+
+       mask = convert_state(mask);
+       val = convert_state(val);
+
+       rv = drbd_change_state(mdev, CS_VERBOSE, mask, val);
+
+       drbd_send_sr_reply(mdev, rv);
+       drbd_md_sync(mdev);
+
+       return TRUE;
+}
+
+static int receive_state(struct drbd_conf *mdev, struct p_header *h)
+{
+       struct p_state *p = (struct p_state *)h;
+       enum drbd_conns nconn, oconn;
+       union drbd_state ns, peer_state;
+       enum drbd_disk_state real_peer_disk;
+       int rv;
+
+       ERR_IF(h->length != (sizeof(*p)-sizeof(*h)))
+               return FALSE;
+
+       if (drbd_recv(mdev, h->payload, h->length) != h->length)
+               return FALSE;
+
+       peer_state.i = be32_to_cpu(p->state);
+
+       real_peer_disk = peer_state.disk;
+       if (peer_state.disk == D_NEGOTIATING) {
+               real_peer_disk = mdev->p_uuid[UI_FLAGS] & 4 ? D_INCONSISTENT : D_CONSISTENT;
+               dev_info(DEV, "real peer disk state = %s\n", drbd_disk_str(real_peer_disk));
+       }
+
+       spin_lock_irq(&mdev->req_lock);
+ retry:
+       oconn = nconn = mdev->state.conn;
+       spin_unlock_irq(&mdev->req_lock);
+
+       if (nconn == C_WF_REPORT_PARAMS)
+               nconn = C_CONNECTED;
+
+       if (mdev->p_uuid && peer_state.disk >= D_NEGOTIATING &&
+           get_ldev_if_state(mdev, D_NEGOTIATING)) {
+               int cr; /* consider resync */
+
+               /* if we established a new connection */
+               cr  = (oconn < C_CONNECTED);
+               /* if we had an established connection
+                * and one of the nodes newly attaches a disk */
+               cr |= (oconn == C_CONNECTED &&
+                      (peer_state.disk == D_NEGOTIATING ||
+                       mdev->state.disk == D_NEGOTIATING));
+               /* if we have both been inconsistent, and the peer has been
+                * forced to be UpToDate with --overwrite-data */
+               cr |= test_bit(CONSIDER_RESYNC, &mdev->flags);
+               /* if we had been plain connected, and the admin requested to
+                * start a sync by "invalidate" or "invalidate-remote" */
+               cr |= (oconn == C_CONNECTED &&
+                               (peer_state.conn >= C_STARTING_SYNC_S &&
+                                peer_state.conn <= C_WF_BITMAP_T));
+
+               if (cr)
+                       nconn = drbd_sync_handshake(mdev, peer_state.role, real_peer_disk);
+
+               put_ldev(mdev);
+               if (nconn == C_MASK) {
+                       if (mdev->state.disk == D_NEGOTIATING) {
+                               drbd_force_state(mdev, NS(disk, D_DISKLESS));
+                               nconn = C_CONNECTED;
+                       } else if (peer_state.disk == D_NEGOTIATING) {
+                               dev_err(DEV, "Disk attach process on the peer node was aborted.\n");
+                               peer_state.disk = D_DISKLESS;
+                       } else {
+                               D_ASSERT(oconn == C_WF_REPORT_PARAMS);
+                               drbd_force_state(mdev, NS(conn, C_DISCONNECTING));
+                               return FALSE;
+                       }
+               }
+       }
+
+       spin_lock_irq(&mdev->req_lock);
+       if (mdev->state.conn != oconn)
+               goto retry;
+       clear_bit(CONSIDER_RESYNC, &mdev->flags);
+       ns.i = mdev->state.i;
+       ns.conn = nconn;
+       ns.peer = peer_state.role;
+       ns.pdsk = real_peer_disk;
+       ns.peer_isp = (peer_state.aftr_isp | peer_state.user_isp);
+       if ((nconn == C_CONNECTED || nconn == C_WF_BITMAP_S) && ns.disk == D_NEGOTIATING)
+               ns.disk = mdev->new_state_tmp.disk;
+
+       rv = _drbd_set_state(mdev, ns, CS_VERBOSE | CS_HARD, NULL);
+       ns = mdev->state;
+       spin_unlock_irq(&mdev->req_lock);
+
+       if (rv < SS_SUCCESS) {
+               drbd_force_state(mdev, NS(conn, C_DISCONNECTING));
+               return FALSE;
+       }
+
+       if (oconn > C_WF_REPORT_PARAMS) {
+               if (nconn > C_CONNECTED && peer_state.conn <= C_CONNECTED &&
+                   peer_state.disk != D_NEGOTIATING ) {
+                       /* we want resync, peer has not yet decided to sync... */
+                       /* Nowadays only used when forcing a node into primary role and
+                          setting its disk to UpToDate with that */
+                       drbd_send_uuids(mdev);
+                       drbd_send_state(mdev);
+               }
+       }
+
+       mdev->net_conf->want_lose = 0;
+
+       drbd_md_sync(mdev); /* update connected indicator, la_size, ... */
+
+       return TRUE;
+}
+
+static int receive_sync_uuid(struct drbd_conf *mdev, struct p_header *h)
+{
+       struct p_rs_uuid *p = (struct p_rs_uuid *)h;
+
+       wait_event(mdev->misc_wait,
+                  mdev->state.conn == C_WF_SYNC_UUID ||
+                  mdev->state.conn < C_CONNECTED ||
+                  mdev->state.disk < D_NEGOTIATING);
+
+       /* D_ASSERT( mdev->state.conn == C_WF_SYNC_UUID ); */
+
+       ERR_IF(h->length != (sizeof(*p)-sizeof(*h))) return FALSE;
+       if (drbd_recv(mdev, h->payload, h->length) != h->length)
+               return FALSE;
+
+       /* Here the _drbd_uuid_ functions are right, current should
+          _not_ be rotated into the history */
+       if (get_ldev_if_state(mdev, D_NEGOTIATING)) {
+               _drbd_uuid_set(mdev, UI_CURRENT, be64_to_cpu(p->uuid));
+               _drbd_uuid_set(mdev, UI_BITMAP, 0UL);
+
+               drbd_start_resync(mdev, C_SYNC_TARGET);
+
+               put_ldev(mdev);
+       } else
+               dev_err(DEV, "Ignoring SyncUUID packet!\n");
+
+       return TRUE;
+}
+
+enum receive_bitmap_ret { OK, DONE, FAILED };
+
+static enum receive_bitmap_ret
+receive_bitmap_plain(struct drbd_conf *mdev, struct p_header *h,
+       unsigned long *buffer, struct bm_xfer_ctx *c)
+{
+       unsigned num_words = min_t(size_t, BM_PACKET_WORDS, c->bm_words - c->word_offset);
+       unsigned want = num_words * sizeof(long);
+
+       if (want != h->length) {
+               dev_err(DEV, "%s:want (%u) != h->length (%u)\n", __func__, want, h->length);
+               return FAILED;
+       }
+       if (want == 0)
+               return DONE;
+       if (drbd_recv(mdev, buffer, want) != want)
+               return FAILED;
+
+       drbd_bm_merge_lel(mdev, c->word_offset, num_words, buffer);
+
+       c->word_offset += num_words;
+       c->bit_offset = c->word_offset * BITS_PER_LONG;
+       if (c->bit_offset > c->bm_bits)
+               c->bit_offset = c->bm_bits;
+
+       return OK;
+}
+
+static enum receive_bitmap_ret
+recv_bm_rle_bits(struct drbd_conf *mdev,
+               struct p_compressed_bm *p,
+               struct bm_xfer_ctx *c)
+{
+       struct bitstream bs;
+       u64 look_ahead;
+       u64 rl;
+       u64 tmp;
+       unsigned long s = c->bit_offset;
+       unsigned long e;
+       int len = p->head.length - (sizeof(*p) - sizeof(p->head));
+       int toggle = DCBP_get_start(p);
+       int have;
+       int bits;
+
+       bitstream_init(&bs, p->code, len, DCBP_get_pad_bits(p));
+
+       bits = bitstream_get_bits(&bs, &look_ahead, 64);
+       if (bits < 0)
+               return FAILED;
+
+       for (have = bits; have > 0; s += rl, toggle = !toggle) {
+               bits = vli_decode_bits(&rl, look_ahead);
+               if (bits <= 0)
+                       return FAILED;
+
+               if (toggle) {
+                       e = s + rl -1;
+                       if (e >= c->bm_bits) {
+                               dev_err(DEV, "bitmap overflow (e:%lu) while decoding bm RLE packet\n", e);
+                               return FAILED;
+                       }
+                       _drbd_bm_set_bits(mdev, s, e);
+               }
+
+               if (have < bits) {
+                       dev_err(DEV, "bitmap decoding error: h:%d b:%d la:0x%08llx l:%u/%u\n",
+                               have, bits, look_ahead,
+                               (unsigned int)(bs.cur.b - p->code),
+                               (unsigned int)bs.buf_len);
+                       return FAILED;
+               }
+               look_ahead >>= bits;
+               have -= bits;
+
+               bits = bitstream_get_bits(&bs, &tmp, 64 - have);
+               if (bits < 0)
+                       return FAILED;
+               look_ahead |= tmp << have;
+               have += bits;
+       }
+
+       c->bit_offset = s;
+       bm_xfer_ctx_bit_to_word_offset(c);
+
+       return (s == c->bm_bits) ? DONE : OK;
+}
+
+static enum receive_bitmap_ret
+decode_bitmap_c(struct drbd_conf *mdev,
+               struct p_compressed_bm *p,
+               struct bm_xfer_ctx *c)
+{
+       if (DCBP_get_code(p) == RLE_VLI_Bits)
+               return recv_bm_rle_bits(mdev, p, c);
+
+       /* other variants had been implemented for evaluation,
+        * but have been dropped as this one turned out to be "best"
+        * during all our tests. */
+
+       dev_err(DEV, "receive_bitmap_c: unknown encoding %u\n", p->encoding);
+       drbd_force_state(mdev, NS(conn, C_PROTOCOL_ERROR));
+       return FAILED;
+}
+
+void INFO_bm_xfer_stats(struct drbd_conf *mdev,
+               const char *direction, struct bm_xfer_ctx *c)
+{
+       /* what would it take to transfer it "plaintext" */
+       unsigned plain = sizeof(struct p_header) *
+               ((c->bm_words+BM_PACKET_WORDS-1)/BM_PACKET_WORDS+1)
+               + c->bm_words * sizeof(long);
+       unsigned total = c->bytes[0] + c->bytes[1];
+       unsigned r;
+
+       /* total can not be zero. but just in case: */
+       if (total == 0)
+               return;
+
+       /* don't report if not compressed */
+       if (total >= plain)
+               return;
+
+       /* total < plain. check for overflow, still */
+       r = (total > UINT_MAX/1000) ? (total / (plain/1000))
+                                   : (1000 * total / plain);
+
+       if (r > 1000)
+               r = 1000;
+
+       r = 1000 - r;
+       dev_info(DEV, "%s bitmap stats [Bytes(packets)]: plain %u(%u), RLE %u(%u), "
+            "total %u; compression: %u.%u%%\n",
+                       direction,
+                       c->bytes[1], c->packets[1],
+                       c->bytes[0], c->packets[0],
+                       total, r/10, r % 10);
+}
+
+/* Since we are processing the bitfield from lower addresses to higher,
+   it does not matter if the process it in 32 bit chunks or 64 bit
+   chunks as long as it is little endian. (Understand it as byte stream,
+   beginning with the lowest byte...) If we would use big endian
+   we would need to process it from the highest address to the lowest,
+   in order to be agnostic to the 32 vs 64 bits issue.
+
+   returns 0 on failure, 1 if we successfully received it. */
+static int receive_bitmap(struct drbd_conf *mdev, struct p_header *h)
+{
+       struct bm_xfer_ctx c;
+       void *buffer;
+       enum receive_bitmap_ret ret;
+       int ok = FALSE;
+
+       wait_event(mdev->misc_wait, !atomic_read(&mdev->ap_bio_cnt));
+
+       drbd_bm_lock(mdev, "receive bitmap");
+
+       /* maybe we should use some per thread scratch page,
+        * and allocate that during initial device creation? */
+       buffer   = (unsigned long *) __get_free_page(GFP_NOIO);
+       if (!buffer) {
+               dev_err(DEV, "failed to allocate one page buffer in %s\n", __func__);
+               goto out;
+       }
+
+       c = (struct bm_xfer_ctx) {
+               .bm_bits = drbd_bm_bits(mdev),
+               .bm_words = drbd_bm_words(mdev),
+       };
+
+       do {
+               if (h->command == P_BITMAP) {
+                       ret = receive_bitmap_plain(mdev, h, buffer, &c);
+               } else if (h->command == P_COMPRESSED_BITMAP) {
+                       /* MAYBE: sanity check that we speak proto >= 90,
+                        * and the feature is enabled! */
+                       struct p_compressed_bm *p;
+
+                       if (h->length > BM_PACKET_PAYLOAD_BYTES) {
+                               dev_err(DEV, "ReportCBitmap packet too large\n");
+                               goto out;
+                       }
+                       /* use the page buff */
+                       p = buffer;
+                       memcpy(p, h, sizeof(*h));
+                       if (drbd_recv(mdev, p->head.payload, h->length) != h->length)
+                               goto out;
+                       if (p->head.length <= (sizeof(*p) - sizeof(p->head))) {
+                               dev_err(DEV, "ReportCBitmap packet too small (l:%u)\n", p->head.length);
+                               return FAILED;
+                       }
+                       ret = decode_bitmap_c(mdev, p, &c);
+               } else {
+                       dev_warn(DEV, "receive_bitmap: h->command neither ReportBitMap nor ReportCBitMap (is 0x%x)", h->command);
+                       goto out;
+               }
+
+               c.packets[h->command == P_BITMAP]++;
+               c.bytes[h->command == P_BITMAP] += sizeof(struct p_header) + h->length;
+
+               if (ret != OK)
+                       break;
+
+               if (!drbd_recv_header(mdev, h))
+                       goto out;
+       } while (ret == OK);
+       if (ret == FAILED)
+               goto out;
+
+       INFO_bm_xfer_stats(mdev, "receive", &c);
+
+       if (mdev->state.conn == C_WF_BITMAP_T) {
+               ok = !drbd_send_bitmap(mdev);
+               if (!ok)
+                       goto out;
+               /* Omit CS_ORDERED with this state transition to avoid deadlocks. */
+               ok = _drbd_request_state(mdev, NS(conn, C_WF_SYNC_UUID), CS_VERBOSE);
+               D_ASSERT(ok == SS_SUCCESS);
+       } else if (mdev->state.conn != C_WF_BITMAP_S) {
+               /* admin may have requested C_DISCONNECTING,
+                * other threads may have noticed network errors */
+               dev_info(DEV, "unexpected cstate (%s) in receive_bitmap\n",
+                   drbd_conn_str(mdev->state.conn));
+       }
+
+       ok = TRUE;
+ out:
+       drbd_bm_unlock(mdev);
+       if (ok && mdev->state.conn == C_WF_BITMAP_S)
+               drbd_start_resync(mdev, C_SYNC_SOURCE);
+       free_page((unsigned long) buffer);
+       return ok;
+}
+
+static int receive_skip(struct drbd_conf *mdev, struct p_header *h)
+{
+       /* TODO zero copy sink :) */
+       static char sink[128];
+       int size, want, r;
+
+       dev_warn(DEV, "skipping unknown optional packet type %d, l: %d!\n",
+            h->command, h->length);
+
+       size = h->length;
+       while (size > 0) {
+               want = min_t(int, size, sizeof(sink));
+               r = drbd_recv(mdev, sink, want);
+               ERR_IF(r <= 0) break;
+               size -= r;
+       }
+       return size == 0;
+}
+
+static int receive_UnplugRemote(struct drbd_conf *mdev, struct p_header *h)
+{
+       if (mdev->state.disk >= D_INCONSISTENT)
+               drbd_kick_lo(mdev);
+
+       /* Make sure we've acked all the TCP data associated
+        * with the data requests being unplugged */
+       drbd_tcp_quickack(mdev->data.socket);
+
+       return TRUE;
+}
+
+typedef int (*drbd_cmd_handler_f)(struct drbd_conf *, struct p_header *);
+
+static drbd_cmd_handler_f drbd_default_handler[] = {
+       [P_DATA]            = receive_Data,
+       [P_DATA_REPLY]      = receive_DataReply,
+       [P_RS_DATA_REPLY]   = receive_RSDataReply,
+       [P_BARRIER]         = receive_Barrier,
+       [P_BITMAP]          = receive_bitmap,
+       [P_COMPRESSED_BITMAP]    = receive_bitmap,
+       [P_UNPLUG_REMOTE]   = receive_UnplugRemote,
+       [P_DATA_REQUEST]    = receive_DataRequest,
+       [P_RS_DATA_REQUEST] = receive_DataRequest,
+       [P_SYNC_PARAM]      = receive_SyncParam,
+       [P_SYNC_PARAM89]           = receive_SyncParam,
+       [P_PROTOCOL]        = receive_protocol,
+       [P_UUIDS]           = receive_uuids,
+       [P_SIZES]           = receive_sizes,
+       [P_STATE]           = receive_state,
+       [P_STATE_CHG_REQ]   = receive_req_state,
+       [P_SYNC_UUID]       = receive_sync_uuid,
+       [P_OV_REQUEST]      = receive_DataRequest,
+       [P_OV_REPLY]        = receive_DataRequest,
+       [P_CSUM_RS_REQUEST]    = receive_DataRequest,
+       /* anything missing from this table is in
+        * the asender_tbl, see get_asender_cmd */
+       [P_MAX_CMD]         = NULL,
+};
+
+static drbd_cmd_handler_f *drbd_cmd_handler = drbd_default_handler;
+static drbd_cmd_handler_f *drbd_opt_cmd_handler;
+
+static void drbdd(struct drbd_conf *mdev)
+{
+       drbd_cmd_handler_f handler;
+       struct p_header *header = &mdev->data.rbuf.header;
+
+       while (get_t_state(&mdev->receiver) == Running) {
+               drbd_thread_current_set_cpu(mdev);
+               if (!drbd_recv_header(mdev, header)) {
+                       drbd_force_state(mdev, NS(conn, C_PROTOCOL_ERROR));
+                       break;
+               }
+
+               if (header->command < P_MAX_CMD)
+                       handler = drbd_cmd_handler[header->command];
+               else if (P_MAY_IGNORE < header->command
+                    && header->command < P_MAX_OPT_CMD)
+                       handler = drbd_opt_cmd_handler[header->command-P_MAY_IGNORE];
+               else if (header->command > P_MAX_OPT_CMD)
+                       handler = receive_skip;
+               else
+                       handler = NULL;
+
+               if (unlikely(!handler)) {
+                       dev_err(DEV, "unknown packet type %d, l: %d!\n",
+                           header->command, header->length);
+                       drbd_force_state(mdev, NS(conn, C_PROTOCOL_ERROR));
+                       break;
+               }
+               if (unlikely(!handler(mdev, header))) {
+                       dev_err(DEV, "error receiving %s, l: %d!\n",
+                           cmdname(header->command), header->length);
+                       drbd_force_state(mdev, NS(conn, C_PROTOCOL_ERROR));
+                       break;
+               }
+       }
+}
+
+static void drbd_fail_pending_reads(struct drbd_conf *mdev)
+{
+       struct hlist_head *slot;
+       struct hlist_node *pos;
+       struct hlist_node *tmp;
+       struct drbd_request *req;
+       int i;
+
+       /*
+        * Application READ requests
+        */
+       spin_lock_irq(&mdev->req_lock);
+       for (i = 0; i < APP_R_HSIZE; i++) {
+               slot = mdev->app_reads_hash+i;
+               hlist_for_each_entry_safe(req, pos, tmp, slot, colision) {
+                       /* it may (but should not any longer!)
+                        * be on the work queue; if that assert triggers,
+                        * we need to also grab the
+                        * spin_lock_irq(&mdev->data.work.q_lock);
+                        * and list_del_init here. */
+                       D_ASSERT(list_empty(&req->w.list));
+                       /* It would be nice to complete outside of spinlock.
+                        * But this is easier for now. */
+                       _req_mod(req, connection_lost_while_pending);
+               }
+       }
+       for (i = 0; i < APP_R_HSIZE; i++)
+               if (!hlist_empty(mdev->app_reads_hash+i))
+                       dev_warn(DEV, "ASSERT FAILED: app_reads_hash[%d].first: "
+                               "%p, should be NULL\n", i, mdev->app_reads_hash[i].first);
+
+       memset(mdev->app_reads_hash, 0, APP_R_HSIZE*sizeof(void *));
+       spin_unlock_irq(&mdev->req_lock);
+}
+
+void drbd_flush_workqueue(struct drbd_conf *mdev)
+{
+       struct drbd_wq_barrier barr;
+
+       barr.w.cb = w_prev_work_done;
+       init_completion(&barr.done);
+       drbd_queue_work(&mdev->data.work, &barr.w);
+       wait_for_completion(&barr.done);
+}
+
+static void drbd_disconnect(struct drbd_conf *mdev)
+{
+       enum drbd_fencing_p fp;
+       union drbd_state os, ns;
+       int rv = SS_UNKNOWN_ERROR;
+       unsigned int i;
+
+       if (mdev->state.conn == C_STANDALONE)
+               return;
+       if (mdev->state.conn >= C_WF_CONNECTION)
+               dev_err(DEV, "ASSERT FAILED cstate = %s, expected < WFConnection\n",
+                               drbd_conn_str(mdev->state.conn));
+
+       /* asender does not clean up anything. it must not interfere, either */
+       drbd_thread_stop(&mdev->asender);
+
+       mutex_lock(&mdev->data.mutex);
+       drbd_free_sock(mdev);
+       mutex_unlock(&mdev->data.mutex);
+
+       spin_lock_irq(&mdev->req_lock);
+       _drbd_wait_ee_list_empty(mdev, &mdev->active_ee);
+       _drbd_wait_ee_list_empty(mdev, &mdev->sync_ee);
+       _drbd_wait_ee_list_empty(mdev, &mdev->read_ee);
+       spin_unlock_irq(&mdev->req_lock);
+
+       /* We do not have data structures that would allow us to
+        * get the rs_pending_cnt down to 0 again.
+        *  * On C_SYNC_TARGET we do not have any data structures describing
+        *    the pending RSDataRequest's we have sent.
+        *  * On C_SYNC_SOURCE there is no data structure that tracks
+        *    the P_RS_DATA_REPLY blocks that we sent to the SyncTarget.
+        *  And no, it is not the sum of the reference counts in the
+        *  resync_LRU. The resync_LRU tracks the whole operation including
+        *  the disk-IO, while the rs_pending_cnt only tracks the blocks
+        *  on the fly. */
+       drbd_rs_cancel_all(mdev);
+       mdev->rs_total = 0;
+       mdev->rs_failed = 0;
+       atomic_set(&mdev->rs_pending_cnt, 0);
+       wake_up(&mdev->misc_wait);
+
+       /* make sure syncer is stopped and w_resume_next_sg queued */
+       del_timer_sync(&mdev->resync_timer);
+       set_bit(STOP_SYNC_TIMER, &mdev->flags);
+       resync_timer_fn((unsigned long)mdev);
+
+       /* wait for all w_e_end_data_req, w_e_end_rsdata_req, w_send_barrier,
+        * w_make_resync_request etc. which may still be on the worker queue
+        * to be "canceled" */
+       drbd_flush_workqueue(mdev);
+
+       /* This also does reclaim_net_ee().  If we do this too early, we might
+        * miss some resync ee and pages.*/
+       drbd_process_done_ee(mdev);
+
+       kfree(mdev->p_uuid);
+       mdev->p_uuid = NULL;
+
+       if (!mdev->state.susp)
+               tl_clear(mdev);
+
+       drbd_fail_pending_reads(mdev);
+
+       dev_info(DEV, "Connection closed\n");
+
+       drbd_md_sync(mdev);
+
+       fp = FP_DONT_CARE;
+       if (get_ldev(mdev)) {
+               fp = mdev->ldev->dc.fencing;
+               put_ldev(mdev);
+       }
+
+       if (mdev->state.role == R_PRIMARY) {
+               if (fp >= FP_RESOURCE && mdev->state.pdsk >= D_UNKNOWN) {
+                       enum drbd_disk_state nps = drbd_try_outdate_peer(mdev);
+                       drbd_request_state(mdev, NS(pdsk, nps));
+               }
+       }
+
+       spin_lock_irq(&mdev->req_lock);
+       os = mdev->state;
+       if (os.conn >= C_UNCONNECTED) {
+               /* Do not restart in case we are C_DISCONNECTING */
+               ns = os;
+               ns.conn = C_UNCONNECTED;
+               rv = _drbd_set_state(mdev, ns, CS_VERBOSE, NULL);
+       }
+       spin_unlock_irq(&mdev->req_lock);
+
+       if (os.conn == C_DISCONNECTING) {
+               struct hlist_head *h;
+               wait_event(mdev->misc_wait, atomic_read(&mdev->net_cnt) == 0);
+
+               /* we must not free the tl_hash
+                * while application io is still on the fly */
+               wait_event(mdev->misc_wait, atomic_read(&mdev->ap_bio_cnt) == 0);
+
+               spin_lock_irq(&mdev->req_lock);
+               /* paranoia code */
+               for (h = mdev->ee_hash; h < mdev->ee_hash + mdev->ee_hash_s; h++)
+                       if (h->first)
+                               dev_err(DEV, "ASSERT FAILED ee_hash[%u].first == %p, expected NULL\n",
+                                               (int)(h - mdev->ee_hash), h->first);
+               kfree(mdev->ee_hash);
+               mdev->ee_hash = NULL;
+               mdev->ee_hash_s = 0;
+
+               /* paranoia code */
+               for (h = mdev->tl_hash; h < mdev->tl_hash + mdev->tl_hash_s; h++)
+                       if (h->first)
+                               dev_err(DEV, "ASSERT FAILED tl_hash[%u] == %p, expected NULL\n",
+                                               (int)(h - mdev->tl_hash), h->first);
+               kfree(mdev->tl_hash);
+               mdev->tl_hash = NULL;
+               mdev->tl_hash_s = 0;
+               spin_unlock_irq(&mdev->req_lock);
+
+               crypto_free_hash(mdev->cram_hmac_tfm);
+               mdev->cram_hmac_tfm = NULL;
+
+               kfree(mdev->net_conf);
+               mdev->net_conf = NULL;
+               drbd_request_state(mdev, NS(conn, C_STANDALONE));
+       }
+
+       /* tcp_close and release of sendpage pages can be deferred.  I don't
+        * want to use SO_LINGER, because apparently it can be deferred for
+        * more than 20 seconds (longest time I checked).
+        *
+        * Actually we don't care for exactly when the network stack does its
+        * put_page(), but release our reference on these pages right here.
+        */
+       i = drbd_release_ee(mdev, &mdev->net_ee);
+       if (i)
+               dev_info(DEV, "net_ee not empty, killed %u entries\n", i);
+       i = atomic_read(&mdev->pp_in_use);
+       if (i)
+               dev_info(DEV, "pp_in_use = %u, expected 0\n", i);
+
+       D_ASSERT(list_empty(&mdev->read_ee));
+       D_ASSERT(list_empty(&mdev->active_ee));
+       D_ASSERT(list_empty(&mdev->sync_ee));
+       D_ASSERT(list_empty(&mdev->done_ee));
+
+       /* ok, no more ee's on the fly, it is safe to reset the epoch_size */
+       atomic_set(&mdev->current_epoch->epoch_size, 0);
+       D_ASSERT(list_empty(&mdev->current_epoch->list));
+}
+
+/*
+ * We support PRO_VERSION_MIN to PRO_VERSION_MAX. The protocol version
+ * we can agree on is stored in agreed_pro_version.
+ *
+ * feature flags and the reserved array should be enough room for future
+ * enhancements of the handshake protocol, and possible plugins...
+ *
+ * for now, they are expected to be zero, but ignored.
+ */
+static int drbd_send_handshake(struct drbd_conf *mdev)
+{
+       /* ASSERT current == mdev->receiver ... */
+       struct p_handshake *p = &mdev->data.sbuf.handshake;
+       int ok;
+
+       if (mutex_lock_interruptible(&mdev->data.mutex)) {
+               dev_err(DEV, "interrupted during initial handshake\n");
+               return 0; /* interrupted. not ok. */
+       }
+
+       if (mdev->data.socket == NULL) {
+               mutex_unlock(&mdev->data.mutex);
+               return 0;
+       }
+
+       memset(p, 0, sizeof(*p));
+       p->protocol_min = cpu_to_be32(PRO_VERSION_MIN);
+       p->protocol_max = cpu_to_be32(PRO_VERSION_MAX);
+       ok = _drbd_send_cmd( mdev, mdev->data.socket, P_HAND_SHAKE,
+                            (struct p_header *)p, sizeof(*p), 0 );
+       mutex_unlock(&mdev->data.mutex);
+       return ok;
+}
+
+/*
+ * return values:
+ *   1 yes, we have a valid connection
+ *   0 oops, did not work out, please try again
+ *  -1 peer talks different language,
+ *     no point in trying again, please go standalone.
+ */
+static int drbd_do_handshake(struct drbd_conf *mdev)
+{
+       /* ASSERT current == mdev->receiver ... */
+       struct p_handshake *p = &mdev->data.rbuf.handshake;
+       const int expect = sizeof(struct p_handshake)
+                         -sizeof(struct p_header);
+       int rv;
+
+       rv = drbd_send_handshake(mdev);
+       if (!rv)
+               return 0;
+
+       rv = drbd_recv_header(mdev, &p->head);
+       if (!rv)
+               return 0;
+
+       if (p->head.command != P_HAND_SHAKE) {
+               dev_err(DEV, "expected HandShake packet, received: %s (0x%04x)\n",
+                    cmdname(p->head.command), p->head.command);
+               return -1;
+       }
+
+       if (p->head.length != expect) {
+               dev_err(DEV, "expected HandShake length: %u, received: %u\n",
+                    expect, p->head.length);
+               return -1;
+       }
+
+       rv = drbd_recv(mdev, &p->head.payload, expect);
+
+       if (rv != expect) {
+               dev_err(DEV, "short read receiving handshake packet: l=%u\n", rv);
+               return 0;
+       }
+
+       p->protocol_min = be32_to_cpu(p->protocol_min);
+       p->protocol_max = be32_to_cpu(p->protocol_max);
+       if (p->protocol_max == 0)
+               p->protocol_max = p->protocol_min;
+
+       if (PRO_VERSION_MAX < p->protocol_min ||
+           PRO_VERSION_MIN > p->protocol_max)
+               goto incompat;
+
+       mdev->agreed_pro_version = min_t(int, PRO_VERSION_MAX, p->protocol_max);
+
+       dev_info(DEV, "Handshake successful: "
+            "Agreed network protocol version %d\n", mdev->agreed_pro_version);
+
+       return 1;
+
+ incompat:
+       dev_err(DEV, "incompatible DRBD dialects: "
+           "I support %d-%d, peer supports %d-%d\n",
+           PRO_VERSION_MIN, PRO_VERSION_MAX,
+           p->protocol_min, p->protocol_max);
+       return -1;
+}
+
+#if !defined(CONFIG_CRYPTO_HMAC) && !defined(CONFIG_CRYPTO_HMAC_MODULE)
+static int drbd_do_auth(struct drbd_conf *mdev)
+{
+       dev_err(DEV, "This kernel was build without CONFIG_CRYPTO_HMAC.\n");
+       dev_err(DEV, "You need to disable 'cram-hmac-alg' in drbd.conf.\n");
+       return 0;
+}
+#else
+#define CHALLENGE_LEN 64
+static int drbd_do_auth(struct drbd_conf *mdev)
+{
+       char my_challenge[CHALLENGE_LEN];  /* 64 Bytes... */
+       struct scatterlist sg;
+       char *response = NULL;
+       char *right_response = NULL;
+       char *peers_ch = NULL;
+       struct p_header p;
+       unsigned int key_len = strlen(mdev->net_conf->shared_secret);
+       unsigned int resp_size;
+       struct hash_desc desc;
+       int rv;
+
+       desc.tfm = mdev->cram_hmac_tfm;
+       desc.flags = 0;
+
+       rv = crypto_hash_setkey(mdev->cram_hmac_tfm,
+                               (u8 *)mdev->net_conf->shared_secret, key_len);
+       if (rv) {
+               dev_err(DEV, "crypto_hash_setkey() failed with %d\n", rv);
+               rv = 0;
+               goto fail;
+       }
+
+       get_random_bytes(my_challenge, CHALLENGE_LEN);
+
+       rv = drbd_send_cmd2(mdev, P_AUTH_CHALLENGE, my_challenge, CHALLENGE_LEN);
+       if (!rv)
+               goto fail;
+
+       rv = drbd_recv_header(mdev, &p);
+       if (!rv)
+               goto fail;
+
+       if (p.command != P_AUTH_CHALLENGE) {
+               dev_err(DEV, "expected AuthChallenge packet, received: %s (0x%04x)\n",
+                   cmdname(p.command), p.command);
+               rv = 0;
+               goto fail;
+       }
+
+       if (p.length > CHALLENGE_LEN*2) {
+               dev_err(DEV, "expected AuthChallenge payload too big.\n");
+               rv = 0;
+               goto fail;
+       }
+
+       peers_ch = kmalloc(p.length, GFP_NOIO);
+       if (peers_ch == NULL) {
+               dev_err(DEV, "kmalloc of peers_ch failed\n");
+               rv = 0;
+               goto fail;
+       }
+
+       rv = drbd_recv(mdev, peers_ch, p.length);
+
+       if (rv != p.length) {
+               dev_err(DEV, "short read AuthChallenge: l=%u\n", rv);
+               rv = 0;
+               goto fail;
+       }
+
+       resp_size = crypto_hash_digestsize(mdev->cram_hmac_tfm);
+       response = kmalloc(resp_size, GFP_NOIO);
+       if (response == NULL) {
+               dev_err(DEV, "kmalloc of response failed\n");
+               rv = 0;
+               goto fail;
+       }
+
+       sg_init_table(&sg, 1);
+       sg_set_buf(&sg, peers_ch, p.length);
+
+       rv = crypto_hash_digest(&desc, &sg, sg.length, response);
+       if (rv) {
+               dev_err(DEV, "crypto_hash_digest() failed with %d\n", rv);
+               rv = 0;
+               goto fail;
+       }
+
+       rv = drbd_send_cmd2(mdev, P_AUTH_RESPONSE, response, resp_size);
+       if (!rv)
+               goto fail;
+
+       rv = drbd_recv_header(mdev, &p);
+       if (!rv)
+               goto fail;
+
+       if (p.command != P_AUTH_RESPONSE) {
+               dev_err(DEV, "expected AuthResponse packet, received: %s (0x%04x)\n",
+                   cmdname(p.command), p.command);
+               rv = 0;
+               goto fail;
+       }
+
+       if (p.length != resp_size) {
+               dev_err(DEV, "expected AuthResponse payload of wrong size\n");
+               rv = 0;
+               goto fail;
+       }
+
+       rv = drbd_recv(mdev, response , resp_size);
+
+       if (rv != resp_size) {
+               dev_err(DEV, "short read receiving AuthResponse: l=%u\n", rv);
+               rv = 0;
+               goto fail;
+       }
+
+       right_response = kmalloc(resp_size, GFP_NOIO);
+       if (response == NULL) {
+               dev_err(DEV, "kmalloc of right_response failed\n");
+               rv = 0;
+               goto fail;
+       }
+
+       sg_set_buf(&sg, my_challenge, CHALLENGE_LEN);
+
+       rv = crypto_hash_digest(&desc, &sg, sg.length, right_response);
+       if (rv) {
+               dev_err(DEV, "crypto_hash_digest() failed with %d\n", rv);
+               rv = 0;
+               goto fail;
+       }
+
+       rv = !memcmp(response, right_response, resp_size);
+
+       if (rv)
+               dev_info(DEV, "Peer authenticated using %d bytes of '%s' HMAC\n",
+                    resp_size, mdev->net_conf->cram_hmac_alg);
+
+ fail:
+       kfree(peers_ch);
+       kfree(response);
+       kfree(right_response);
+
+       return rv;
+}
+#endif
+
+int drbdd_init(struct drbd_thread *thi)
+{
+       struct drbd_conf *mdev = thi->mdev;
+       unsigned int minor = mdev_to_minor(mdev);
+       int h;
+
+       sprintf(current->comm, "drbd%d_receiver", minor);
+
+       dev_info(DEV, "receiver (re)started\n");
+
+       do {
+               h = drbd_connect(mdev);
+               if (h == 0) {
+                       drbd_disconnect(mdev);
+                       __set_current_state(TASK_INTERRUPTIBLE);
+                       schedule_timeout(HZ);
+               }
+               if (h == -1) {
+                       dev_warn(DEV, "Discarding network configuration.\n");
+                       drbd_force_state(mdev, NS(conn, C_DISCONNECTING));
+               }
+       } while (h == 0);
+
+       if (h > 0) {
+               if (get_net_conf(mdev)) {
+                       drbdd(mdev);
+                       put_net_conf(mdev);
+               }
+       }
+
+       drbd_disconnect(mdev);
+
+       dev_info(DEV, "receiver terminated\n");
+       return 0;
+}
+
+/* ********* acknowledge sender ******** */
+
+static int got_RqSReply(struct drbd_conf *mdev, struct p_header *h)
+{
+       struct p_req_state_reply *p = (struct p_req_state_reply *)h;
+
+       int retcode = be32_to_cpu(p->retcode);
+
+       if (retcode >= SS_SUCCESS) {
+               set_bit(CL_ST_CHG_SUCCESS, &mdev->flags);
+       } else {
+               set_bit(CL_ST_CHG_FAIL, &mdev->flags);
+               dev_err(DEV, "Requested state change failed by peer: %s (%d)\n",
+                   drbd_set_st_err_str(retcode), retcode);
+       }
+       wake_up(&mdev->state_wait);
+
+       return TRUE;
+}
+
+static int got_Ping(struct drbd_conf *mdev, struct p_header *h)
+{
+       return drbd_send_ping_ack(mdev);
+
+}
+
+static int got_PingAck(struct drbd_conf *mdev, struct p_header *h)
+{
+       /* restore idle timeout */
+       mdev->meta.socket->sk->sk_rcvtimeo = mdev->net_conf->ping_int*HZ;
+
+       return TRUE;
+}
+
+static int got_IsInSync(struct drbd_conf *mdev, struct p_header *h)
+{
+       struct p_block_ack *p = (struct p_block_ack *)h;
+       sector_t sector = be64_to_cpu(p->sector);
+       int blksize = be32_to_cpu(p->blksize);
+
+       D_ASSERT(mdev->agreed_pro_version >= 89);
+
+       update_peer_seq(mdev, be32_to_cpu(p->seq_num));
+
+       drbd_rs_complete_io(mdev, sector);
+       drbd_set_in_sync(mdev, sector, blksize);
+       /* rs_same_csums is supposed to count in units of BM_BLOCK_SIZE */
+       mdev->rs_same_csum += (blksize >> BM_BLOCK_SHIFT);
+       dec_rs_pending(mdev);
+
+       return TRUE;
+}
+
+/* when we receive the ACK for a write request,
+ * verify that we actually know about it */
+static struct drbd_request *_ack_id_to_req(struct drbd_conf *mdev,
+       u64 id, sector_t sector)
+{
+       struct hlist_head *slot = tl_hash_slot(mdev, sector);
+       struct hlist_node *n;
+       struct drbd_request *req;
+
+       hlist_for_each_entry(req, n, slot, colision) {
+               if ((unsigned long)req == (unsigned long)id) {
+                       if (req->sector != sector) {
+                               dev_err(DEV, "_ack_id_to_req: found req %p but it has "
+                                   "wrong sector (%llus versus %llus)\n", req,
+                                   (unsigned long long)req->sector,
+                                   (unsigned long long)sector);
+                               break;
+                       }
+                       return req;
+               }
+       }
+       dev_err(DEV, "_ack_id_to_req: failed to find req %p, sector %llus in list\n",
+               (void *)(unsigned long)id, (unsigned long long)sector);
+       return NULL;
+}
+
+typedef struct drbd_request *(req_validator_fn)
+       (struct drbd_conf *mdev, u64 id, sector_t sector);
+
+static int validate_req_change_req_state(struct drbd_conf *mdev,
+       u64 id, sector_t sector, req_validator_fn validator,
+       const char *func, enum drbd_req_event what)
+{
+       struct drbd_request *req;
+       struct bio_and_error m;
+
+       spin_lock_irq(&mdev->req_lock);
+       req = validator(mdev, id, sector);
+       if (unlikely(!req)) {
+               spin_unlock_irq(&mdev->req_lock);
+               dev_err(DEV, "%s: got a corrupt block_id/sector pair\n", func);
+               return FALSE;
+       }
+       __req_mod(req, what, &m);
+       spin_unlock_irq(&mdev->req_lock);
+
+       if (m.bio)
+               complete_master_bio(mdev, &m);
+       return TRUE;
+}
+
+static int got_BlockAck(struct drbd_conf *mdev, struct p_header *h)
+{
+       struct p_block_ack *p = (struct p_block_ack *)h;
+       sector_t sector = be64_to_cpu(p->sector);
+       int blksize = be32_to_cpu(p->blksize);
+       enum drbd_req_event what;
+
+       update_peer_seq(mdev, be32_to_cpu(p->seq_num));
+
+       if (is_syncer_block_id(p->block_id)) {
+               drbd_set_in_sync(mdev, sector, blksize);
+               dec_rs_pending(mdev);
+               return TRUE;
+       }
+       switch (be16_to_cpu(h->command)) {
+       case P_RS_WRITE_ACK:
+               D_ASSERT(mdev->net_conf->wire_protocol == DRBD_PROT_C);
+               what = write_acked_by_peer_and_sis;
+               break;
+       case P_WRITE_ACK:
+               D_ASSERT(mdev->net_conf->wire_protocol == DRBD_PROT_C);
+               what = write_acked_by_peer;
+               break;
+       case P_RECV_ACK:
+               D_ASSERT(mdev->net_conf->wire_protocol == DRBD_PROT_B);
+               what = recv_acked_by_peer;
+               break;
+       case P_DISCARD_ACK:
+               D_ASSERT(mdev->net_conf->wire_protocol == DRBD_PROT_C);
+               what = conflict_discarded_by_peer;
+               break;
+       default:
+               D_ASSERT(0);
+               return FALSE;
+       }
+
+       return validate_req_change_req_state(mdev, p->block_id, sector,
+               _ack_id_to_req, __func__ , what);
+}
+
+static int got_NegAck(struct drbd_conf *mdev, struct p_header *h)
+{
+       struct p_block_ack *p = (struct p_block_ack *)h;
+       sector_t sector = be64_to_cpu(p->sector);
+
+       if (__ratelimit(&drbd_ratelimit_state))
+               dev_warn(DEV, "Got NegAck packet. Peer is in troubles?\n");
+
+       update_peer_seq(mdev, be32_to_cpu(p->seq_num));
+
+       if (is_syncer_block_id(p->block_id)) {
+               int size = be32_to_cpu(p->blksize);
+               dec_rs_pending(mdev);
+               drbd_rs_failed_io(mdev, sector, size);
+               return TRUE;
+       }
+       return validate_req_change_req_state(mdev, p->block_id, sector,
+               _ack_id_to_req, __func__ , neg_acked);
+}
+
+static int got_NegDReply(struct drbd_conf *mdev, struct p_header *h)
+{
+       struct p_block_ack *p = (struct p_block_ack *)h;
+       sector_t sector = be64_to_cpu(p->sector);
+
+       update_peer_seq(mdev, be32_to_cpu(p->seq_num));
+       dev_err(DEV, "Got NegDReply; Sector %llus, len %u; Fail original request.\n",
+           (unsigned long long)sector, be32_to_cpu(p->blksize));
+
+       return validate_req_change_req_state(mdev, p->block_id, sector,
+               _ar_id_to_req, __func__ , neg_acked);
+}
+
+static int got_NegRSDReply(struct drbd_conf *mdev, struct p_header *h)
+{
+       sector_t sector;
+       int size;
+       struct p_block_ack *p = (struct p_block_ack *)h;
+
+       sector = be64_to_cpu(p->sector);
+       size = be32_to_cpu(p->blksize);
+       D_ASSERT(p->block_id == ID_SYNCER);
+
+       update_peer_seq(mdev, be32_to_cpu(p->seq_num));
+
+       dec_rs_pending(mdev);
+
+       if (get_ldev_if_state(mdev, D_FAILED)) {
+               drbd_rs_complete_io(mdev, sector);
+               drbd_rs_failed_io(mdev, sector, size);
+               put_ldev(mdev);
+       }
+
+       return TRUE;
+}
+
+static int got_BarrierAck(struct drbd_conf *mdev, struct p_header *h)
+{
+       struct p_barrier_ack *p = (struct p_barrier_ack *)h;
+
+       tl_release(mdev, p->barrier, be32_to_cpu(p->set_size));
+
+       return TRUE;
+}
+
+static int got_OVResult(struct drbd_conf *mdev, struct p_header *h)
+{
+       struct p_block_ack *p = (struct p_block_ack *)h;
+       struct drbd_work *w;
+       sector_t sector;
+       int size;
+
+       sector = be64_to_cpu(p->sector);
+       size = be32_to_cpu(p->blksize);
+
+       update_peer_seq(mdev, be32_to_cpu(p->seq_num));
+
+       if (be64_to_cpu(p->block_id) == ID_OUT_OF_SYNC)
+               drbd_ov_oos_found(mdev, sector, size);
+       else
+               ov_oos_print(mdev);
+
+       drbd_rs_complete_io(mdev, sector);
+       dec_rs_pending(mdev);
+
+       if (--mdev->ov_left == 0) {
+               w = kmalloc(sizeof(*w), GFP_NOIO);
+               if (w) {
+                       w->cb = w_ov_finished;
+                       drbd_queue_work_front(&mdev->data.work, w);
+               } else {
+                       dev_err(DEV, "kmalloc(w) failed.");
+                       ov_oos_print(mdev);
+                       drbd_resync_finished(mdev);
+               }
+       }
+       return TRUE;
+}
+
+struct asender_cmd {
+       size_t pkt_size;
+       int (*process)(struct drbd_conf *mdev, struct p_header *h);
+};
+
+static struct asender_cmd *get_asender_cmd(int cmd)
+{
+       static struct asender_cmd asender_tbl[] = {
+               /* anything missing from this table is in
+                * the drbd_cmd_handler (drbd_default_handler) table,
+                * see the beginning of drbdd() */
+       [P_PING]            = { sizeof(struct p_header), got_Ping },
+       [P_PING_ACK]        = { sizeof(struct p_header), got_PingAck },
+       [P_RECV_ACK]        = { sizeof(struct p_block_ack), got_BlockAck },
+       [P_WRITE_ACK]       = { sizeof(struct p_block_ack), got_BlockAck },
+       [P_RS_WRITE_ACK]    = { sizeof(struct p_block_ack), got_BlockAck },
+       [P_DISCARD_ACK]     = { sizeof(struct p_block_ack), got_BlockAck },
+       [P_NEG_ACK]         = { sizeof(struct p_block_ack), got_NegAck },
+       [P_NEG_DREPLY]      = { sizeof(struct p_block_ack), got_NegDReply },
+       [P_NEG_RS_DREPLY]   = { sizeof(struct p_block_ack), got_NegRSDReply},
+       [P_OV_RESULT]       = { sizeof(struct p_block_ack), got_OVResult },
+       [P_BARRIER_ACK]     = { sizeof(struct p_barrier_ack), got_BarrierAck },
+       [P_STATE_CHG_REPLY] = { sizeof(struct p_req_state_reply), got_RqSReply },
+       [P_RS_IS_IN_SYNC]   = { sizeof(struct p_block_ack), got_IsInSync },
+       [P_MAX_CMD]         = { 0, NULL },
+       };
+       if (cmd > P_MAX_CMD || asender_tbl[cmd].process == NULL)
+               return NULL;
+       return &asender_tbl[cmd];
+}
+
+int drbd_asender(struct drbd_thread *thi)
+{
+       struct drbd_conf *mdev = thi->mdev;
+       struct p_header *h = &mdev->meta.rbuf.header;
+       struct asender_cmd *cmd = NULL;
+
+       int rv, len;
+       void *buf    = h;
+       int received = 0;
+       int expect   = sizeof(struct p_header);
+       int empty;
+
+       sprintf(current->comm, "drbd%d_asender", mdev_to_minor(mdev));
+
+       current->policy = SCHED_RR;  /* Make this a realtime task! */
+       current->rt_priority = 2;    /* more important than all other tasks */
+
+       while (get_t_state(thi) == Running) {
+               drbd_thread_current_set_cpu(mdev);
+               if (test_and_clear_bit(SEND_PING, &mdev->flags)) {
+                       ERR_IF(!drbd_send_ping(mdev)) goto reconnect;
+                       mdev->meta.socket->sk->sk_rcvtimeo =
+                               mdev->net_conf->ping_timeo*HZ/10;
+               }
+
+               /* conditionally cork;
+                * it may hurt latency if we cork without much to send */
+               if (!mdev->net_conf->no_cork &&
+                       3 < atomic_read(&mdev->unacked_cnt))
+                       drbd_tcp_cork(mdev->meta.socket);
+               while (1) {
+                       clear_bit(SIGNAL_ASENDER, &mdev->flags);
+                       flush_signals(current);
+                       if (!drbd_process_done_ee(mdev)) {
+                               dev_err(DEV, "process_done_ee() = NOT_OK\n");
+                               goto reconnect;
+                       }
+                       /* to avoid race with newly queued ACKs */
+                       set_bit(SIGNAL_ASENDER, &mdev->flags);
+                       spin_lock_irq(&mdev->req_lock);
+                       empty = list_empty(&mdev->done_ee);
+                       spin_unlock_irq(&mdev->req_lock);
+                       /* new ack may have been queued right here,
+                        * but then there is also a signal pending,
+                        * and we start over... */
+                       if (empty)
+                               break;
+               }
+               /* but unconditionally uncork unless disabled */
+               if (!mdev->net_conf->no_cork)
+                       drbd_tcp_uncork(mdev->meta.socket);
+
+               /* short circuit, recv_msg would return EINTR anyways. */
+               if (signal_pending(current))
+                       continue;
+
+               rv = drbd_recv_short(mdev, mdev->meta.socket,
+                                    buf, expect-received, 0);
+               clear_bit(SIGNAL_ASENDER, &mdev->flags);
+
+               flush_signals(current);
+
+               /* Note:
+                * -EINTR        (on meta) we got a signal
+                * -EAGAIN       (on meta) rcvtimeo expired
+                * -ECONNRESET   other side closed the connection
+                * -ERESTARTSYS  (on data) we got a signal
+                * rv <  0       other than above: unexpected error!
+                * rv == expected: full header or command
+                * rv <  expected: "woken" by signal during receive
+                * rv == 0       : "connection shut down by peer"
+                */
+               if (likely(rv > 0)) {
+                       received += rv;
+                       buf      += rv;
+               } else if (rv == 0) {
+                       dev_err(DEV, "meta connection shut down by peer.\n");
+                       goto reconnect;
+               } else if (rv == -EAGAIN) {
+                       if (mdev->meta.socket->sk->sk_rcvtimeo ==
+                           mdev->net_conf->ping_timeo*HZ/10) {
+                               dev_err(DEV, "PingAck did not arrive in time.\n");
+                               goto reconnect;
+                       }
+                       set_bit(SEND_PING, &mdev->flags);
+                       continue;
+               } else if (rv == -EINTR) {
+                       continue;
+               } else {
+                       dev_err(DEV, "sock_recvmsg returned %d\n", rv);
+                       goto reconnect;
+               }
+
+               if (received == expect && cmd == NULL) {
+                       if (unlikely(h->magic != BE_DRBD_MAGIC)) {
+                               dev_err(DEV, "magic?? on meta m: 0x%lx c: %d l: %d\n",
+                                   (long)be32_to_cpu(h->magic),
+                                   h->command, h->length);
+                               goto reconnect;
+                       }
+                       cmd = get_asender_cmd(be16_to_cpu(h->command));
+                       len = be16_to_cpu(h->length);
+                       if (unlikely(cmd == NULL)) {
+                               dev_err(DEV, "unknown command?? on meta m: 0x%lx c: %d l: %d\n",
+                                   (long)be32_to_cpu(h->magic),
+                                   h->command, h->length);
+                               goto disconnect;
+                       }
+                       expect = cmd->pkt_size;
+                       ERR_IF(len != expect-sizeof(struct p_header))
+                               goto reconnect;
+               }
+               if (received == expect) {
+                       D_ASSERT(cmd != NULL);
+                       if (!cmd->process(mdev, h))
+                               goto reconnect;
+
+                       buf      = h;
+                       received = 0;
+                       expect   = sizeof(struct p_header);
+                       cmd      = NULL;
+               }
+       }
+
+       if (0) {
+reconnect:
+               drbd_force_state(mdev, NS(conn, C_NETWORK_FAILURE));
+       }
+       if (0) {
+disconnect:
+               drbd_force_state(mdev, NS(conn, C_DISCONNECTING));
+       }
+       clear_bit(SIGNAL_ASENDER, &mdev->flags);
+
+       D_ASSERT(mdev->state.conn < C_CONNECTED);
+       dev_info(DEV, "asender terminated\n");
+
+       return 0;
+}
diff --git a/drivers/block/drbd/drbd_req.c b/drivers/block/drbd/drbd_req.c
new file mode 100644 (file)
index 0000000..de81ab7
--- /dev/null
@@ -0,0 +1,1125 @@
+/*
+   drbd_req.c
+
+   This file is part of DRBD by Philipp Reisner and Lars Ellenberg.
+
+   Copyright (C) 2001-2008, LINBIT Information Technologies GmbH.
+   Copyright (C) 1999-2008, Philipp Reisner <philipp.reisner@linbit.com>.
+   Copyright (C) 2002-2008, Lars Ellenberg <lars.ellenberg@linbit.com>.
+
+   drbd is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   drbd 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 drbd; see the file COPYING.  If not, write to
+   the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ */
+
+#include <linux/module.h>
+
+#include <linux/slab.h>
+#include <linux/drbd.h>
+#include "drbd_int.h"
+#include "drbd_req.h"
+
+
+/* Update disk stats at start of I/O request */
+static void _drbd_start_io_acct(struct drbd_conf *mdev, struct drbd_request *req, struct bio *bio)
+{
+       const int rw = bio_data_dir(bio);
+       int cpu;
+       cpu = part_stat_lock();
+       part_stat_inc(cpu, &mdev->vdisk->part0, ios[rw]);
+       part_stat_add(cpu, &mdev->vdisk->part0, sectors[rw], bio_sectors(bio));
+       part_inc_in_flight(&mdev->vdisk->part0, rw);
+       part_stat_unlock();
+}
+
+/* Update disk stats when completing request upwards */
+static void _drbd_end_io_acct(struct drbd_conf *mdev, struct drbd_request *req)
+{
+       int rw = bio_data_dir(req->master_bio);
+       unsigned long duration = jiffies - req->start_time;
+       int cpu;
+       cpu = part_stat_lock();
+       part_stat_add(cpu, &mdev->vdisk->part0, ticks[rw], duration);
+       part_round_stats(cpu, &mdev->vdisk->part0);
+       part_dec_in_flight(&mdev->vdisk->part0, rw);
+       part_stat_unlock();
+}
+
+static void _req_is_done(struct drbd_conf *mdev, struct drbd_request *req, const int rw)
+{
+       const unsigned long s = req->rq_state;
+       /* if it was a write, we may have to set the corresponding
+        * bit(s) out-of-sync first. If it had a local part, we need to
+        * release the reference to the activity log. */
+       if (rw == WRITE) {
+               /* remove it from the transfer log.
+                * well, only if it had been there in the first
+                * place... if it had not (local only or conflicting
+                * and never sent), it should still be "empty" as
+                * initialized in drbd_req_new(), so we can list_del() it
+                * here unconditionally */
+               list_del(&req->tl_requests);
+               /* Set out-of-sync unless both OK flags are set
+                * (local only or remote failed).
+                * Other places where we set out-of-sync:
+                * READ with local io-error */
+               if (!(s & RQ_NET_OK) || !(s & RQ_LOCAL_OK))
+                       drbd_set_out_of_sync(mdev, req->sector, req->size);
+
+               if ((s & RQ_NET_OK) && (s & RQ_LOCAL_OK) && (s & RQ_NET_SIS))
+                       drbd_set_in_sync(mdev, req->sector, req->size);
+
+               /* one might be tempted to move the drbd_al_complete_io
+                * to the local io completion callback drbd_endio_pri.
+                * but, if this was a mirror write, we may only
+                * drbd_al_complete_io after this is RQ_NET_DONE,
+                * otherwise the extent could be dropped from the al
+                * before it has actually been written on the peer.
+                * if we crash before our peer knows about the request,
+                * but after the extent has been dropped from the al,
+                * we would forget to resync the corresponding extent.
+                */
+               if (s & RQ_LOCAL_MASK) {
+                       if (get_ldev_if_state(mdev, D_FAILED)) {
+                               drbd_al_complete_io(mdev, req->sector);
+                               put_ldev(mdev);
+                       } else if (__ratelimit(&drbd_ratelimit_state)) {
+                               dev_warn(DEV, "Should have called drbd_al_complete_io(, %llu), "
+                                    "but my Disk seems to have failed :(\n",
+                                    (unsigned long long) req->sector);
+                       }
+               }
+       }
+
+       /* if it was a local io error, we want to notify our
+        * peer about that, and see if we need to
+        * detach the disk and stuff.
+        * to avoid allocating some special work
+        * struct, reuse the request. */
+
+       /* THINK
+        * why do we do this not when we detect the error,
+        * but delay it until it is "done", i.e. possibly
+        * until the next barrier ack? */
+
+       if (rw == WRITE &&
+           ((s & RQ_LOCAL_MASK) && !(s & RQ_LOCAL_OK))) {
+               if (!(req->w.list.next == LIST_POISON1 ||
+                     list_empty(&req->w.list))) {
+                       /* DEBUG ASSERT only; if this triggers, we
+                        * probably corrupt the worker list here */
+                       dev_err(DEV, "req->w.list.next = %p\n", req->w.list.next);
+                       dev_err(DEV, "req->w.list.prev = %p\n", req->w.list.prev);
+               }
+               req->w.cb = w_io_error;
+               drbd_queue_work(&mdev->data.work, &req->w);
+               /* drbd_req_free() is done in w_io_error */
+       } else {
+               drbd_req_free(req);
+       }
+}
+
+static void queue_barrier(struct drbd_conf *mdev)
+{
+       struct drbd_tl_epoch *b;
+
+       /* We are within the req_lock. Once we queued the barrier for sending,
+        * we set the CREATE_BARRIER bit. It is cleared as soon as a new
+        * barrier/epoch object is added. This is the only place this bit is
+        * set. It indicates that the barrier for this epoch is already queued,
+        * and no new epoch has been created yet. */
+       if (test_bit(CREATE_BARRIER, &mdev->flags))
+               return;
+
+       b = mdev->newest_tle;
+       b->w.cb = w_send_barrier;
+       /* inc_ap_pending done here, so we won't
+        * get imbalanced on connection loss.
+        * dec_ap_pending will be done in got_BarrierAck
+        * or (on connection loss) in tl_clear.  */
+       inc_ap_pending(mdev);
+       drbd_queue_work(&mdev->data.work, &b->w);
+       set_bit(CREATE_BARRIER, &mdev->flags);
+}
+
+static void _about_to_complete_local_write(struct drbd_conf *mdev,
+       struct drbd_request *req)
+{
+       const unsigned long s = req->rq_state;
+       struct drbd_request *i;
+       struct drbd_epoch_entry *e;
+       struct hlist_node *n;
+       struct hlist_head *slot;
+
+       /* before we can signal completion to the upper layers,
+        * we may need to close the current epoch */
+       if (mdev->state.conn >= C_CONNECTED &&
+           req->epoch == mdev->newest_tle->br_number)
+               queue_barrier(mdev);
+
+       /* we need to do the conflict detection stuff,
+        * if we have the ee_hash (two_primaries) and
+        * this has been on the network */
+       if ((s & RQ_NET_DONE) && mdev->ee_hash != NULL) {
+               const sector_t sector = req->sector;
+               const int size = req->size;
+
+               /* ASSERT:
+                * there must be no conflicting requests, since
+                * they must have been failed on the spot */
+#define OVERLAPS overlaps(sector, size, i->sector, i->size)
+               slot = tl_hash_slot(mdev, sector);
+               hlist_for_each_entry(i, n, slot, colision) {
+                       if (OVERLAPS) {
+                               dev_alert(DEV, "LOGIC BUG: completed: %p %llus +%u; "
+                                     "other: %p %llus +%u\n",
+                                     req, (unsigned long long)sector, size,
+                                     i, (unsigned long long)i->sector, i->size);
+                       }
+               }
+
+               /* maybe "wake" those conflicting epoch entries
+                * that wait for this request to finish.
+                *
+                * currently, there can be only _one_ such ee
+                * (well, or some more, which would be pending
+                * P_DISCARD_ACK not yet sent by the asender...),
+                * since we block the receiver thread upon the
+                * first conflict detection, which will wait on
+                * misc_wait.  maybe we want to assert that?
+                *
+                * anyways, if we found one,
+                * we just have to do a wake_up.  */
+#undef OVERLAPS
+#define OVERLAPS overlaps(sector, size, e->sector, e->size)
+               slot = ee_hash_slot(mdev, req->sector);
+               hlist_for_each_entry(e, n, slot, colision) {
+                       if (OVERLAPS) {
+                               wake_up(&mdev->misc_wait);
+                               break;
+                       }
+               }
+       }
+#undef OVERLAPS
+}
+
+void complete_master_bio(struct drbd_conf *mdev,
+               struct bio_and_error *m)
+{
+       bio_endio(m->bio, m->error);
+       dec_ap_bio(mdev);
+}
+
+/* Helper for __req_mod().
+ * Set m->bio to the master bio, if it is fit to be completed,
+ * or leave it alone (it is initialized to NULL in __req_mod),
+ * if it has already been completed, or cannot be completed yet.
+ * If m->bio is set, the error status to be returned is placed in m->error.
+ */
+void _req_may_be_done(struct drbd_request *req, struct bio_and_error *m)
+{
+       const unsigned long s = req->rq_state;
+       struct drbd_conf *mdev = req->mdev;
+       /* only WRITES may end up here without a master bio (on barrier ack) */
+       int rw = req->master_bio ? bio_data_dir(req->master_bio) : WRITE;
+
+       /* we must not complete the master bio, while it is
+        *      still being processed by _drbd_send_zc_bio (drbd_send_dblock)
+        *      not yet acknowledged by the peer
+        *      not yet completed by the local io subsystem
+        * these flags may get cleared in any order by
+        *      the worker,
+        *      the receiver,
+        *      the bio_endio completion callbacks.
+        */
+       if (s & RQ_NET_QUEUED)
+               return;
+       if (s & RQ_NET_PENDING)
+               return;
+       if (s & RQ_LOCAL_PENDING)
+               return;
+
+       if (req->master_bio) {
+               /* this is data_received (remote read)
+                * or protocol C P_WRITE_ACK
+                * or protocol B P_RECV_ACK
+                * or protocol A "handed_over_to_network" (SendAck)
+                * or canceled or failed,
+                * or killed from the transfer log due to connection loss.
+                */
+
+               /*
+                * figure out whether to report success or failure.
+                *
+                * report success when at least one of the operations succeeded.
+                * or, to put the other way,
+                * only report failure, when both operations failed.
+                *
+                * what to do about the failures is handled elsewhere.
+                * what we need to do here is just: complete the master_bio.
+                *
+                * local completion error, if any, has been stored as ERR_PTR
+                * in private_bio within drbd_endio_pri.
+                */
+               int ok = (s & RQ_LOCAL_OK) || (s & RQ_NET_OK);
+               int error = PTR_ERR(req->private_bio);
+
+               /* remove the request from the conflict detection
+                * respective block_id verification hash */
+               if (!hlist_unhashed(&req->colision))
+                       hlist_del(&req->colision);
+               else
+                       D_ASSERT((s & RQ_NET_MASK) == 0);
+
+               /* for writes we need to do some extra housekeeping */
+               if (rw == WRITE)
+                       _about_to_complete_local_write(mdev, req);
+
+               /* Update disk stats */
+               _drbd_end_io_acct(mdev, req);
+
+               m->error = ok ? 0 : (error ?: -EIO);
+               m->bio = req->master_bio;
+               req->master_bio = NULL;
+       }
+
+       if ((s & RQ_NET_MASK) == 0 || (s & RQ_NET_DONE)) {
+               /* this is disconnected (local only) operation,
+                * or protocol C P_WRITE_ACK,
+                * or protocol A or B P_BARRIER_ACK,
+                * or killed from the transfer log due to connection loss. */
+               _req_is_done(mdev, req, rw);
+       }
+       /* else: network part and not DONE yet. that is
+        * protocol A or B, barrier ack still pending... */
+}
+
+/*
+ * checks whether there was an overlapping request
+ * or ee already registered.
+ *
+ * if so, return 1, in which case this request is completed on the spot,
+ * without ever being submitted or send.
+ *
+ * return 0 if it is ok to submit this request.
+ *
+ * NOTE:
+ * paranoia: assume something above us is broken, and issues different write
+ * requests for the same block simultaneously...
+ *
+ * To ensure these won't be reordered differently on both nodes, resulting in
+ * diverging data sets, we discard the later one(s). Not that this is supposed
+ * to happen, but this is the rationale why we also have to check for
+ * conflicting requests with local origin, and why we have to do so regardless
+ * of whether we allowed multiple primaries.
+ *
+ * BTW, in case we only have one primary, the ee_hash is empty anyways, and the
+ * second hlist_for_each_entry becomes a noop. This is even simpler than to
+ * grab a reference on the net_conf, and check for the two_primaries flag...
+ */
+static int _req_conflicts(struct drbd_request *req)
+{
+       struct drbd_conf *mdev = req->mdev;
+       const sector_t sector = req->sector;
+       const int size = req->size;
+       struct drbd_request *i;
+       struct drbd_epoch_entry *e;
+       struct hlist_node *n;
+       struct hlist_head *slot;
+
+       D_ASSERT(hlist_unhashed(&req->colision));
+
+       if (!get_net_conf(mdev))
+               return 0;
+
+       /* BUG_ON */
+       ERR_IF (mdev->tl_hash_s == 0)
+               goto out_no_conflict;
+       BUG_ON(mdev->tl_hash == NULL);
+
+#define OVERLAPS overlaps(i->sector, i->size, sector, size)
+       slot = tl_hash_slot(mdev, sector);
+       hlist_for_each_entry(i, n, slot, colision) {
+               if (OVERLAPS) {
+                       dev_alert(DEV, "%s[%u] Concurrent local write detected! "
+                             "[DISCARD L] new: %llus +%u; "
+                             "pending: %llus +%u\n",
+                             current->comm, current->pid,
+                             (unsigned long long)sector, size,
+                             (unsigned long long)i->sector, i->size);
+                       goto out_conflict;
+               }
+       }
+
+       if (mdev->ee_hash_s) {
+               /* now, check for overlapping requests with remote origin */
+               BUG_ON(mdev->ee_hash == NULL);
+#undef OVERLAPS
+#define OVERLAPS overlaps(e->sector, e->size, sector, size)
+               slot = ee_hash_slot(mdev, sector);
+               hlist_for_each_entry(e, n, slot, colision) {
+                       if (OVERLAPS) {
+                               dev_alert(DEV, "%s[%u] Concurrent remote write detected!"
+                                     " [DISCARD L] new: %llus +%u; "
+                                     "pending: %llus +%u\n",
+                                     current->comm, current->pid,
+                                     (unsigned long long)sector, size,
+                                     (unsigned long long)e->sector, e->size);
+                               goto out_conflict;
+                       }
+               }
+       }
+#undef OVERLAPS
+
+out_no_conflict:
+       /* this is like it should be, and what we expected.
+        * our users do behave after all... */
+       put_net_conf(mdev);
+       return 0;
+
+out_conflict:
+       put_net_conf(mdev);
+       return 1;
+}
+
+/* obviously this could be coded as many single functions
+ * instead of one huge switch,
+ * or by putting the code directly in the respective locations
+ * (as it has been before).
+ *
+ * but having it this way
+ *  enforces that it is all in this one place, where it is easier to audit,
+ *  it makes it obvious that whatever "event" "happens" to a request should
+ *  happen "atomically" within the req_lock,
+ *  and it enforces that we have to think in a very structured manner
+ *  about the "events" that may happen to a request during its life time ...
+ */
+void __req_mod(struct drbd_request *req, enum drbd_req_event what,
+               struct bio_and_error *m)
+{
+       struct drbd_conf *mdev = req->mdev;
+       m->bio = NULL;
+
+       switch (what) {
+       default:
+               dev_err(DEV, "LOGIC BUG in %s:%u\n", __FILE__ , __LINE__);
+               break;
+
+       /* does not happen...
+        * initialization done in drbd_req_new
+       case created:
+               break;
+               */
+
+       case to_be_send: /* via network */
+               /* reached via drbd_make_request_common
+                * and from w_read_retry_remote */
+               D_ASSERT(!(req->rq_state & RQ_NET_MASK));
+               req->rq_state |= RQ_NET_PENDING;
+               inc_ap_pending(mdev);
+               break;
+
+       case to_be_submitted: /* locally */
+               /* reached via drbd_make_request_common */
+               D_ASSERT(!(req->rq_state & RQ_LOCAL_MASK));
+               req->rq_state |= RQ_LOCAL_PENDING;
+               break;
+
+       case completed_ok:
+               if (bio_data_dir(req->master_bio) == WRITE)
+                       mdev->writ_cnt += req->size>>9;
+               else
+                       mdev->read_cnt += req->size>>9;
+
+               req->rq_state |= (RQ_LOCAL_COMPLETED|RQ_LOCAL_OK);
+               req->rq_state &= ~RQ_LOCAL_PENDING;
+
+               _req_may_be_done(req, m);
+               put_ldev(mdev);
+               break;
+
+       case write_completed_with_error:
+               req->rq_state |= RQ_LOCAL_COMPLETED;
+               req->rq_state &= ~RQ_LOCAL_PENDING;
+
+               dev_alert(DEV, "Local WRITE failed sec=%llus size=%u\n",
+                     (unsigned long long)req->sector, req->size);
+               /* and now: check how to handle local io error. */
+               __drbd_chk_io_error(mdev, FALSE);
+               _req_may_be_done(req, m);
+               put_ldev(mdev);
+               break;
+
+       case read_ahead_completed_with_error:
+               /* it is legal to fail READA */
+               req->rq_state |= RQ_LOCAL_COMPLETED;
+               req->rq_state &= ~RQ_LOCAL_PENDING;
+               _req_may_be_done(req, m);
+               put_ldev(mdev);
+               break;
+
+       case read_completed_with_error:
+               drbd_set_out_of_sync(mdev, req->sector, req->size);
+
+               req->rq_state |= RQ_LOCAL_COMPLETED;
+               req->rq_state &= ~RQ_LOCAL_PENDING;
+
+               dev_alert(DEV, "Local READ failed sec=%llus size=%u\n",
+                     (unsigned long long)req->sector, req->size);
+               /* _req_mod(req,to_be_send); oops, recursion... */
+               D_ASSERT(!(req->rq_state & RQ_NET_MASK));
+               req->rq_state |= RQ_NET_PENDING;
+               inc_ap_pending(mdev);
+
+               __drbd_chk_io_error(mdev, FALSE);
+               put_ldev(mdev);
+               /* NOTE: if we have no connection,
+                * or know the peer has no good data either,
+                * then we don't actually need to "queue_for_net_read",
+                * but we do so anyways, since the drbd_io_error()
+                * and the potential state change to "Diskless"
+                * needs to be done from process context */
+
+               /* fall through: _req_mod(req,queue_for_net_read); */
+
+       case queue_for_net_read:
+               /* READ or READA, and
+                * no local disk,
+                * or target area marked as invalid,
+                * or just got an io-error. */
+               /* from drbd_make_request_common
+                * or from bio_endio during read io-error recovery */
+
+               /* so we can verify the handle in the answer packet
+                * corresponding hlist_del is in _req_may_be_done() */
+               hlist_add_head(&req->colision, ar_hash_slot(mdev, req->sector));
+
+               set_bit(UNPLUG_REMOTE, &mdev->flags);
+
+               D_ASSERT(req->rq_state & RQ_NET_PENDING);
+               req->rq_state |= RQ_NET_QUEUED;
+               req->w.cb = (req->rq_state & RQ_LOCAL_MASK)
+                       ? w_read_retry_remote
+                       : w_send_read_req;
+               drbd_queue_work(&mdev->data.work, &req->w);
+               break;
+
+       case queue_for_net_write:
+               /* assert something? */
+               /* from drbd_make_request_common only */
+
+               hlist_add_head(&req->colision, tl_hash_slot(mdev, req->sector));
+               /* corresponding hlist_del is in _req_may_be_done() */
+
+               /* NOTE
+                * In case the req ended up on the transfer log before being
+                * queued on the worker, it could lead to this request being
+                * missed during cleanup after connection loss.
+                * So we have to do both operations here,
+                * within the same lock that protects the transfer log.
+                *
+                * _req_add_to_epoch(req); this has to be after the
+                * _maybe_start_new_epoch(req); which happened in
+                * drbd_make_request_common, because we now may set the bit
+                * again ourselves to close the current epoch.
+                *
+                * Add req to the (now) current epoch (barrier). */
+
+               /* otherwise we may lose an unplug, which may cause some remote
+                * io-scheduler timeout to expire, increasing maximum latency,
+                * hurting performance. */
+               set_bit(UNPLUG_REMOTE, &mdev->flags);
+
+               /* see drbd_make_request_common,
+                * just after it grabs the req_lock */
+               D_ASSERT(test_bit(CREATE_BARRIER, &mdev->flags) == 0);
+
+               req->epoch = mdev->newest_tle->br_number;
+               list_add_tail(&req->tl_requests,
+                               &mdev->newest_tle->requests);
+
+               /* increment size of current epoch */
+               mdev->newest_tle->n_req++;
+
+               /* queue work item to send data */
+               D_ASSERT(req->rq_state & RQ_NET_PENDING);
+               req->rq_state |= RQ_NET_QUEUED;
+               req->w.cb =  w_send_dblock;
+               drbd_queue_work(&mdev->data.work, &req->w);
+
+               /* close the epoch, in case it outgrew the limit */
+               if (mdev->newest_tle->n_req >= mdev->net_conf->max_epoch_size)
+                       queue_barrier(mdev);
+
+               break;
+
+       case send_canceled:
+               /* treat it the same */
+       case send_failed:
+               /* real cleanup will be done from tl_clear.  just update flags
+                * so it is no longer marked as on the worker queue */
+               req->rq_state &= ~RQ_NET_QUEUED;
+               /* if we did it right, tl_clear should be scheduled only after
+                * this, so this should not be necessary! */
+               _req_may_be_done(req, m);
+               break;
+
+       case handed_over_to_network:
+               /* assert something? */
+               if (bio_data_dir(req->master_bio) == WRITE &&
+                   mdev->net_conf->wire_protocol == DRBD_PROT_A) {
+                       /* this is what is dangerous about protocol A:
+                        * pretend it was successfully written on the peer. */
+                       if (req->rq_state & RQ_NET_PENDING) {
+                               dec_ap_pending(mdev);
+                               req->rq_state &= ~RQ_NET_PENDING;
+                               req->rq_state |= RQ_NET_OK;
+                       } /* else: neg-ack was faster... */
+                       /* it is still not yet RQ_NET_DONE until the
+                        * corresponding epoch barrier got acked as well,
+                        * so we know what to dirty on connection loss */
+               }
+               req->rq_state &= ~RQ_NET_QUEUED;
+               req->rq_state |= RQ_NET_SENT;
+               /* because _drbd_send_zc_bio could sleep, and may want to
+                * dereference the bio even after the "write_acked_by_peer" and
+                * "completed_ok" events came in, once we return from
+                * _drbd_send_zc_bio (drbd_send_dblock), we have to check
+                * whether it is done already, and end it.  */
+               _req_may_be_done(req, m);
+               break;
+
+       case connection_lost_while_pending:
+               /* transfer log cleanup after connection loss */
+               /* assert something? */
+               if (req->rq_state & RQ_NET_PENDING)
+                       dec_ap_pending(mdev);
+               req->rq_state &= ~(RQ_NET_OK|RQ_NET_PENDING);
+               req->rq_state |= RQ_NET_DONE;
+               /* if it is still queued, we may not complete it here.
+                * it will be canceled soon. */
+               if (!(req->rq_state & RQ_NET_QUEUED))
+                       _req_may_be_done(req, m);
+               break;
+
+       case write_acked_by_peer_and_sis:
+               req->rq_state |= RQ_NET_SIS;
+       case conflict_discarded_by_peer:
+               /* for discarded conflicting writes of multiple primaries,
+                * there is no need to keep anything in the tl, potential
+                * node crashes are covered by the activity log. */
+               if (what == conflict_discarded_by_peer)
+                       dev_alert(DEV, "Got DiscardAck packet %llus +%u!"
+                             " DRBD is not a random data generator!\n",
+                             (unsigned long long)req->sector, req->size);
+               req->rq_state |= RQ_NET_DONE;
+               /* fall through */
+       case write_acked_by_peer:
+               /* protocol C; successfully written on peer.
+                * Nothing to do here.
+                * We want to keep the tl in place for all protocols, to cater
+                * for volatile write-back caches on lower level devices.
+                *
+                * A barrier request is expected to have forced all prior
+                * requests onto stable storage, so completion of a barrier
+                * request could set NET_DONE right here, and not wait for the
+                * P_BARRIER_ACK, but that is an unnecessary optimization. */
+
+               /* this makes it effectively the same as for: */
+       case recv_acked_by_peer:
+               /* protocol B; pretends to be successfully written on peer.
+                * see also notes above in handed_over_to_network about
+                * protocol != C */
+               req->rq_state |= RQ_NET_OK;
+               D_ASSERT(req->rq_state & RQ_NET_PENDING);
+               dec_ap_pending(mdev);
+               req->rq_state &= ~RQ_NET_PENDING;
+               _req_may_be_done(req, m);
+               break;
+
+       case neg_acked:
+               /* assert something? */
+               if (req->rq_state & RQ_NET_PENDING)
+                       dec_ap_pending(mdev);
+               req->rq_state &= ~(RQ_NET_OK|RQ_NET_PENDING);
+
+               req->rq_state |= RQ_NET_DONE;
+               _req_may_be_done(req, m);
+               /* else: done by handed_over_to_network */
+               break;
+
+       case barrier_acked:
+               if (req->rq_state & RQ_NET_PENDING) {
+                       /* barrier came in before all requests have been acked.
+                        * this is bad, because if the connection is lost now,
+                        * we won't be able to clean them up... */
+                       dev_err(DEV, "FIXME (barrier_acked but pending)\n");
+                       list_move(&req->tl_requests, &mdev->out_of_sequence_requests);
+               }
+               D_ASSERT(req->rq_state & RQ_NET_SENT);
+               req->rq_state |= RQ_NET_DONE;
+               _req_may_be_done(req, m);
+               break;
+
+       case data_received:
+               D_ASSERT(req->rq_state & RQ_NET_PENDING);
+               dec_ap_pending(mdev);
+               req->rq_state &= ~RQ_NET_PENDING;
+               req->rq_state |= (RQ_NET_OK|RQ_NET_DONE);
+               _req_may_be_done(req, m);
+               break;
+       };
+}
+
+/* we may do a local read if:
+ * - we are consistent (of course),
+ * - or we are generally inconsistent,
+ *   BUT we are still/already IN SYNC for this area.
+ *   since size may be bigger than BM_BLOCK_SIZE,
+ *   we may need to check several bits.
+ */
+static int drbd_may_do_local_read(struct drbd_conf *mdev, sector_t sector, int size)
+{
+       unsigned long sbnr, ebnr;
+       sector_t esector, nr_sectors;
+
+       if (mdev->state.disk == D_UP_TO_DATE)
+               return 1;
+       if (mdev->state.disk >= D_OUTDATED)
+               return 0;
+       if (mdev->state.disk <  D_INCONSISTENT)
+               return 0;
+       /* state.disk == D_INCONSISTENT   We will have a look at the BitMap */
+       nr_sectors = drbd_get_capacity(mdev->this_bdev);
+       esector = sector + (size >> 9) - 1;
+
+       D_ASSERT(sector  < nr_sectors);
+       D_ASSERT(esector < nr_sectors);
+
+       sbnr = BM_SECT_TO_BIT(sector);
+       ebnr = BM_SECT_TO_BIT(esector);
+
+       return 0 == drbd_bm_count_bits(mdev, sbnr, ebnr);
+}
+
+static int drbd_make_request_common(struct drbd_conf *mdev, struct bio *bio)
+{
+       const int rw = bio_rw(bio);
+       const int size = bio->bi_size;
+       const sector_t sector = bio->bi_sector;
+       struct drbd_tl_epoch *b = NULL;
+       struct drbd_request *req;
+       int local, remote;
+       int err = -EIO;
+
+       /* allocate outside of all locks; */
+       req = drbd_req_new(mdev, bio);
+       if (!req) {
+               dec_ap_bio(mdev);
+               /* only pass the error to the upper layers.
+                * if user cannot handle io errors, that's not our business. */
+               dev_err(DEV, "could not kmalloc() req\n");
+               bio_endio(bio, -ENOMEM);
+               return 0;
+       }
+
+       local = get_ldev(mdev);
+       if (!local) {
+               bio_put(req->private_bio); /* or we get a bio leak */
+               req->private_bio = NULL;
+       }
+       if (rw == WRITE) {
+               remote = 1;
+       } else {
+               /* READ || READA */
+               if (local) {
+                       if (!drbd_may_do_local_read(mdev, sector, size)) {
+                               /* we could kick the syncer to
+                                * sync this extent asap, wait for
+                                * it, then continue locally.
+                                * Or just issue the request remotely.
+                                */
+                               local = 0;
+                               bio_put(req->private_bio);
+                               req->private_bio = NULL;
+                               put_ldev(mdev);
+                       }
+               }
+               remote = !local && mdev->state.pdsk >= D_UP_TO_DATE;
+       }
+
+       /* If we have a disk, but a READA request is mapped to remote,
+        * we are R_PRIMARY, D_INCONSISTENT, SyncTarget.
+        * Just fail that READA request right here.
+        *
+        * THINK: maybe fail all READA when not local?
+        *        or make this configurable...
+        *        if network is slow, READA won't do any good.
+        */
+       if (rw == READA && mdev->state.disk >= D_INCONSISTENT && !local) {
+               err = -EWOULDBLOCK;
+               goto fail_and_free_req;
+       }
+
+       /* For WRITES going to the local disk, grab a reference on the target
+        * extent.  This waits for any resync activity in the corresponding
+        * resync extent to finish, and, if necessary, pulls in the target
+        * extent into the activity log, which involves further disk io because
+        * of transactional on-disk meta data updates. */
+       if (rw == WRITE && local)
+               drbd_al_begin_io(mdev, sector);
+
+       remote = remote && (mdev->state.pdsk == D_UP_TO_DATE ||
+                           (mdev->state.pdsk == D_INCONSISTENT &&
+                            mdev->state.conn >= C_CONNECTED));
+
+       if (!(local || remote)) {
+               dev_err(DEV, "IO ERROR: neither local nor remote disk\n");
+               goto fail_free_complete;
+       }
+
+       /* For WRITE request, we have to make sure that we have an
+        * unused_spare_tle, in case we need to start a new epoch.
+        * I try to be smart and avoid to pre-allocate always "just in case",
+        * but there is a race between testing the bit and pointer outside the
+        * spinlock, and grabbing the spinlock.
+        * if we lost that race, we retry.  */
+       if (rw == WRITE && remote &&
+           mdev->unused_spare_tle == NULL &&
+           test_bit(CREATE_BARRIER, &mdev->flags)) {
+allocate_barrier:
+               b = kmalloc(sizeof(struct drbd_tl_epoch), GFP_NOIO);
+               if (!b) {
+                       dev_err(DEV, "Failed to alloc barrier.\n");
+                       err = -ENOMEM;
+                       goto fail_free_complete;
+               }
+       }
+
+       /* GOOD, everything prepared, grab the spin_lock */
+       spin_lock_irq(&mdev->req_lock);
+
+       if (remote) {
+               remote = (mdev->state.pdsk == D_UP_TO_DATE ||
+                           (mdev->state.pdsk == D_INCONSISTENT &&
+                            mdev->state.conn >= C_CONNECTED));
+               if (!remote)
+                       dev_warn(DEV, "lost connection while grabbing the req_lock!\n");
+               if (!(local || remote)) {
+                       dev_err(DEV, "IO ERROR: neither local nor remote disk\n");
+                       spin_unlock_irq(&mdev->req_lock);
+                       goto fail_free_complete;
+               }
+       }
+
+       if (b && mdev->unused_spare_tle == NULL) {
+               mdev->unused_spare_tle = b;
+               b = NULL;
+       }
+       if (rw == WRITE && remote &&
+           mdev->unused_spare_tle == NULL &&
+           test_bit(CREATE_BARRIER, &mdev->flags)) {
+               /* someone closed the current epoch
+                * while we were grabbing the spinlock */
+               spin_unlock_irq(&mdev->req_lock);
+               goto allocate_barrier;
+       }
+
+
+       /* Update disk stats */
+       _drbd_start_io_acct(mdev, req, bio);
+
+       /* _maybe_start_new_epoch(mdev);
+        * If we need to generate a write barrier packet, we have to add the
+        * new epoch (barrier) object, and queue the barrier packet for sending,
+        * and queue the req's data after it _within the same lock_, otherwise
+        * we have race conditions were the reorder domains could be mixed up.
+        *
+        * Even read requests may start a new epoch and queue the corresponding
+        * barrier packet.  To get the write ordering right, we only have to
+        * make sure that, if this is a write request and it triggered a
+        * barrier packet, this request is queued within the same spinlock. */
+       if (remote && mdev->unused_spare_tle &&
+           test_and_clear_bit(CREATE_BARRIER, &mdev->flags)) {
+               _tl_add_barrier(mdev, mdev->unused_spare_tle);
+               mdev->unused_spare_tle = NULL;
+       } else {
+               D_ASSERT(!(remote && rw == WRITE &&
+                          test_bit(CREATE_BARRIER, &mdev->flags)));
+       }
+
+       /* NOTE
+        * Actually, 'local' may be wrong here already, since we may have failed
+        * to write to the meta data, and may become wrong anytime because of
+        * local io-error for some other request, which would lead to us
+        * "detaching" the local disk.
+        *
+        * 'remote' may become wrong any time because the network could fail.
+        *
+        * This is a harmless race condition, though, since it is handled
+        * correctly at the appropriate places; so it just defers the failure
+        * of the respective operation.
+        */
+
+       /* mark them early for readability.
+        * this just sets some state flags. */
+       if (remote)
+               _req_mod(req, to_be_send);
+       if (local)
+               _req_mod(req, to_be_submitted);
+
+       /* check this request on the collision detection hash tables.
+        * if we have a conflict, just complete it here.
+        * THINK do we want to check reads, too? (I don't think so...) */
+       if (rw == WRITE && _req_conflicts(req)) {
+               /* this is a conflicting request.
+                * even though it may have been only _partially_
+                * overlapping with one of the currently pending requests,
+                * without even submitting or sending it, we will
+                * pretend that it was successfully served right now.
+                */
+               if (local) {
+                       bio_put(req->private_bio);
+                       req->private_bio = NULL;
+                       drbd_al_complete_io(mdev, req->sector);
+                       put_ldev(mdev);
+                       local = 0;
+               }
+               if (remote)
+                       dec_ap_pending(mdev);
+               _drbd_end_io_acct(mdev, req);
+               /* THINK: do we want to fail it (-EIO), or pretend success? */
+               bio_endio(req->master_bio, 0);
+               req->master_bio = NULL;
+               dec_ap_bio(mdev);
+               drbd_req_free(req);
+               remote = 0;
+       }
+
+       /* NOTE remote first: to get the concurrent write detection right,
+        * we must register the request before start of local IO.  */
+       if (remote) {
+               /* either WRITE and C_CONNECTED,
+                * or READ, and no local disk,
+                * or READ, but not in sync.
+                */
+               _req_mod(req, (rw == WRITE)
+                               ? queue_for_net_write
+                               : queue_for_net_read);
+       }
+       spin_unlock_irq(&mdev->req_lock);
+       kfree(b); /* if someone else has beaten us to it... */
+
+       if (local) {
+               req->private_bio->bi_bdev = mdev->ldev->backing_bdev;
+
+               if (FAULT_ACTIVE(mdev, rw == WRITE ? DRBD_FAULT_DT_WR
+                                    : rw == READ  ? DRBD_FAULT_DT_RD
+                                    :               DRBD_FAULT_DT_RA))
+                       bio_endio(req->private_bio, -EIO);
+               else
+                       generic_make_request(req->private_bio);
+       }
+
+       /* we need to plug ALWAYS since we possibly need to kick lo_dev.
+        * we plug after submit, so we won't miss an unplug event */
+       drbd_plug_device(mdev);
+
+       return 0;
+
+fail_free_complete:
+       if (rw == WRITE && local)
+               drbd_al_complete_io(mdev, sector);
+fail_and_free_req:
+       if (local) {
+               bio_put(req->private_bio);
+               req->private_bio = NULL;
+               put_ldev(mdev);
+       }
+       bio_endio(bio, err);
+       drbd_req_free(req);
+       dec_ap_bio(mdev);
+       kfree(b);
+
+       return 0;
+}
+
+/* helper function for drbd_make_request
+ * if we can determine just by the mdev (state) that this request will fail,
+ * return 1
+ * otherwise return 0
+ */
+static int drbd_fail_request_early(struct drbd_conf *mdev, int is_write)
+{
+       /* Unconfigured */
+       if (mdev->state.conn == C_DISCONNECTING &&
+           mdev->state.disk == D_DISKLESS)
+               return 1;
+
+       if (mdev->state.role != R_PRIMARY &&
+               (!allow_oos || is_write)) {
+               if (__ratelimit(&drbd_ratelimit_state)) {
+                       dev_err(DEV, "Process %s[%u] tried to %s; "
+                           "since we are not in Primary state, "
+                           "we cannot allow this\n",
+                           current->comm, current->pid,
+                           is_write ? "WRITE" : "READ");
+               }
+               return 1;
+       }
+
+       /*
+        * Paranoia: we might have been primary, but sync target, or
+        * even diskless, then lost the connection.
+        * This should have been handled (panic? suspend?) somewhere
+        * else. But maybe it was not, so check again here.
+        * Caution: as long as we do not have a read/write lock on mdev,
+        * to serialize state changes, this is racy, since we may lose
+        * the connection *after* we test for the cstate.
+        */
+       if (mdev->state.disk < D_UP_TO_DATE && mdev->state.pdsk < D_UP_TO_DATE) {
+               if (__ratelimit(&drbd_ratelimit_state))
+                       dev_err(DEV, "Sorry, I have no access to good data anymore.\n");
+               return 1;
+       }
+
+       return 0;
+}
+
+int drbd_make_request_26(struct request_queue *q, struct bio *bio)
+{
+       unsigned int s_enr, e_enr;
+       struct drbd_conf *mdev = (struct drbd_conf *) q->queuedata;
+
+       if (drbd_fail_request_early(mdev, bio_data_dir(bio) & WRITE)) {
+               bio_endio(bio, -EPERM);
+               return 0;
+       }
+
+       /* Reject barrier requests if we know the underlying device does
+        * not support them.
+        * XXX: Need to get this info from peer as well some how so we
+        * XXX: reject if EITHER side/data/metadata area does not support them.
+        *
+        * because of those XXX, this is not yet enabled,
+        * i.e. in drbd_init_set_defaults we set the NO_BARRIER_SUPP bit.
+        */
+       if (unlikely(bio_rw_flagged(bio, BIO_RW_BARRIER) && test_bit(NO_BARRIER_SUPP, &mdev->flags))) {
+               /* dev_warn(DEV, "Rejecting barrier request as underlying device does not support\n"); */
+               bio_endio(bio, -EOPNOTSUPP);
+               return 0;
+       }
+
+       /*
+        * what we "blindly" assume:
+        */
+       D_ASSERT(bio->bi_size > 0);
+       D_ASSERT((bio->bi_size & 0x1ff) == 0);
+       D_ASSERT(bio->bi_idx == 0);
+
+       /* to make some things easier, force alignment of requests within the
+        * granularity of our hash tables */
+       s_enr = bio->bi_sector >> HT_SHIFT;
+       e_enr = (bio->bi_sector+(bio->bi_size>>9)-1) >> HT_SHIFT;
+
+       if (likely(s_enr == e_enr)) {
+               inc_ap_bio(mdev, 1);
+               return drbd_make_request_common(mdev, bio);
+       }
+
+       /* can this bio be split generically?
+        * Maybe add our own split-arbitrary-bios function. */
+       if (bio->bi_vcnt != 1 || bio->bi_idx != 0 || bio->bi_size > DRBD_MAX_SEGMENT_SIZE) {
+               /* rather error out here than BUG in bio_split */
+               dev_err(DEV, "bio would need to, but cannot, be split: "
+                   "(vcnt=%u,idx=%u,size=%u,sector=%llu)\n",
+                   bio->bi_vcnt, bio->bi_idx, bio->bi_size,
+                   (unsigned long long)bio->bi_sector);
+               bio_endio(bio, -EINVAL);
+       } else {
+               /* This bio crosses some boundary, so we have to split it. */
+               struct bio_pair *bp;
+               /* works for the "do not cross hash slot boundaries" case
+                * e.g. sector 262269, size 4096
+                * s_enr = 262269 >> 6 = 4097
+                * e_enr = (262269+8-1) >> 6 = 4098
+                * HT_SHIFT = 6
+                * sps = 64, mask = 63
+                * first_sectors = 64 - (262269 & 63) = 3
+                */
+               const sector_t sect = bio->bi_sector;
+               const int sps = 1 << HT_SHIFT; /* sectors per slot */
+               const int mask = sps - 1;
+               const sector_t first_sectors = sps - (sect & mask);
+               bp = bio_split(bio,
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
+                               bio_split_pool,
+#endif
+                               first_sectors);
+
+               /* we need to get a "reference count" (ap_bio_cnt)
+                * to avoid races with the disconnect/reconnect/suspend code.
+                * In case we need to split the bio here, we need to get two references
+                * atomically, otherwise we might deadlock when trying to submit the
+                * second one! */
+               inc_ap_bio(mdev, 2);
+
+               D_ASSERT(e_enr == s_enr + 1);
+
+               drbd_make_request_common(mdev, &bp->bio1);
+               drbd_make_request_common(mdev, &bp->bio2);
+               bio_pair_release(bp);
+       }
+       return 0;
+}
+
+/* This is called by bio_add_page().  With this function we reduce
+ * the number of BIOs that span over multiple DRBD_MAX_SEGMENT_SIZEs
+ * units (was AL_EXTENTs).
+ *
+ * we do the calculation within the lower 32bit of the byte offsets,
+ * since we don't care for actual offset, but only check whether it
+ * would cross "activity log extent" boundaries.
+ *
+ * As long as the BIO is empty we have to allow at least one bvec,
+ * regardless of size and offset.  so the resulting bio may still
+ * cross extent boundaries.  those are dealt with (bio_split) in
+ * drbd_make_request_26.
+ */
+int drbd_merge_bvec(struct request_queue *q, struct bvec_merge_data *bvm, struct bio_vec *bvec)
+{
+       struct drbd_conf *mdev = (struct drbd_conf *) q->queuedata;
+       unsigned int bio_offset =
+               (unsigned int)bvm->bi_sector << 9; /* 32 bit */
+       unsigned int bio_size = bvm->bi_size;
+       int limit, backing_limit;
+
+       limit = DRBD_MAX_SEGMENT_SIZE
+             - ((bio_offset & (DRBD_MAX_SEGMENT_SIZE-1)) + bio_size);
+       if (limit < 0)
+               limit = 0;
+       if (bio_size == 0) {
+               if (limit <= bvec->bv_len)
+                       limit = bvec->bv_len;
+       } else if (limit && get_ldev(mdev)) {
+               struct request_queue * const b =
+                       mdev->ldev->backing_bdev->bd_disk->queue;
+               if (b->merge_bvec_fn && mdev->ldev->dc.use_bmbv) {
+                       backing_limit = b->merge_bvec_fn(b, bvm, bvec);
+                       limit = min(limit, backing_limit);
+               }
+               put_ldev(mdev);
+       }
+       return limit;
+}
diff --git a/drivers/block/drbd/drbd_req.h b/drivers/block/drbd/drbd_req.h
new file mode 100644 (file)
index 0000000..f22c1bc
--- /dev/null
@@ -0,0 +1,326 @@
+/*
+   drbd_req.h
+
+   This file is part of DRBD by Philipp Reisner and Lars Ellenberg.
+
+   Copyright (C) 2006-2008, LINBIT Information Technologies GmbH.
+   Copyright (C) 2006-2008, Lars Ellenberg <lars.ellenberg@linbit.com>.
+   Copyright (C) 2006-2008, Philipp Reisner <philipp.reisner@linbit.com>.
+
+   DRBD is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   DRBD 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 drbd; see the file COPYING.  If not, write to
+   the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _DRBD_REQ_H
+#define _DRBD_REQ_H
+
+#include <linux/module.h>
+
+#include <linux/slab.h>
+#include <linux/drbd.h>
+#include "drbd_int.h"
+#include "drbd_wrappers.h"
+
+/* The request callbacks will be called in irq context by the IDE drivers,
+   and in Softirqs/Tasklets/BH context by the SCSI drivers,
+   and by the receiver and worker in kernel-thread context.
+   Try to get the locking right :) */
+
+/*
+ * Objects of type struct drbd_request do only exist on a R_PRIMARY node, and are
+ * associated with IO requests originating from the block layer above us.
+ *
+ * There are quite a few things that may happen to a drbd request
+ * during its lifetime.
+ *
+ *  It will be created.
+ *  It will be marked with the intention to be
+ *    submitted to local disk and/or
+ *    send via the network.
+ *
+ *  It has to be placed on the transfer log and other housekeeping lists,
+ *  In case we have a network connection.
+ *
+ *  It may be identified as a concurrent (write) request
+ *    and be handled accordingly.
+ *
+ *  It may me handed over to the local disk subsystem.
+ *  It may be completed by the local disk subsystem,
+ *    either sucessfully or with io-error.
+ *  In case it is a READ request, and it failed locally,
+ *    it may be retried remotely.
+ *
+ *  It may be queued for sending.
+ *  It may be handed over to the network stack,
+ *    which may fail.
+ *  It may be acknowledged by the "peer" according to the wire_protocol in use.
+ *    this may be a negative ack.
+ *  It may receive a faked ack when the network connection is lost and the
+ *  transfer log is cleaned up.
+ *  Sending may be canceled due to network connection loss.
+ *  When it finally has outlived its time,
+ *    corresponding dirty bits in the resync-bitmap may be cleared or set,
+ *    it will be destroyed,
+ *    and completion will be signalled to the originator,
+ *      with or without "success".
+ */
+
+enum drbd_req_event {
+       created,
+       to_be_send,
+       to_be_submitted,
+
+       /* XXX yes, now I am inconsistent...
+        * these two are not "events" but "actions"
+        * oh, well... */
+       queue_for_net_write,
+       queue_for_net_read,
+
+       send_canceled,
+       send_failed,
+       handed_over_to_network,
+       connection_lost_while_pending,
+       recv_acked_by_peer,
+       write_acked_by_peer,
+       write_acked_by_peer_and_sis, /* and set_in_sync */
+       conflict_discarded_by_peer,
+       neg_acked,
+       barrier_acked, /* in protocol A and B */
+       data_received, /* (remote read) */
+
+       read_completed_with_error,
+       read_ahead_completed_with_error,
+       write_completed_with_error,
+       completed_ok,
+       nothing, /* for tracing only */
+};
+
+/* encoding of request states for now.  we don't actually need that many bits.
+ * we don't need to do atomic bit operations either, since most of the time we
+ * need to look at the connection state and/or manipulate some lists at the
+ * same time, so we should hold the request lock anyways.
+ */
+enum drbd_req_state_bits {
+       /* 210
+        * 000: no local possible
+        * 001: to be submitted
+        *    UNUSED, we could map: 011: submitted, completion still pending
+        * 110: completed ok
+        * 010: completed with error
+        */
+       __RQ_LOCAL_PENDING,
+       __RQ_LOCAL_COMPLETED,
+       __RQ_LOCAL_OK,
+
+       /* 76543
+        * 00000: no network possible
+        * 00001: to be send
+        * 00011: to be send, on worker queue
+        * 00101: sent, expecting recv_ack (B) or write_ack (C)
+        * 11101: sent,
+        *        recv_ack (B) or implicit "ack" (A),
+        *        still waiting for the barrier ack.
+        *        master_bio may already be completed and invalidated.
+        * 11100: write_acked (C),
+        *        data_received (for remote read, any protocol)
+        *        or finally the barrier ack has arrived (B,A)...
+        *        request can be freed
+        * 01100: neg-acked (write, protocol C)
+        *        or neg-d-acked (read, any protocol)
+        *        or killed from the transfer log
+        *        during cleanup after connection loss
+        *        request can be freed
+        * 01000: canceled or send failed...
+        *        request can be freed
+        */
+
+       /* if "SENT" is not set, yet, this can still fail or be canceled.
+        * if "SENT" is set already, we still wait for an Ack packet.
+        * when cleared, the master_bio may be completed.
+        * in (B,A) the request object may still linger on the transaction log
+        * until the corresponding barrier ack comes in */
+       __RQ_NET_PENDING,
+
+       /* If it is QUEUED, and it is a WRITE, it is also registered in the
+        * transfer log. Currently we need this flag to avoid conflicts between
+        * worker canceling the request and tl_clear_barrier killing it from
+        * transfer log.  We should restructure the code so this conflict does
+        * no longer occur. */
+       __RQ_NET_QUEUED,
+
+       /* well, actually only "handed over to the network stack".
+        *
+        * TODO can potentially be dropped because of the similar meaning
+        * of RQ_NET_SENT and ~RQ_NET_QUEUED.
+        * however it is not exactly the same. before we drop it
+        * we must ensure that we can tell a request with network part
+        * from a request without, regardless of what happens to it. */
+       __RQ_NET_SENT,
+
+       /* when set, the request may be freed (if RQ_NET_QUEUED is clear).
+        * basically this means the corresponding P_BARRIER_ACK was received */
+       __RQ_NET_DONE,
+
+       /* whether or not we know (C) or pretend (B,A) that the write
+        * was successfully written on the peer.
+        */
+       __RQ_NET_OK,
+
+       /* peer called drbd_set_in_sync() for this write */
+       __RQ_NET_SIS,
+
+       /* keep this last, its for the RQ_NET_MASK */
+       __RQ_NET_MAX,
+};
+
+#define RQ_LOCAL_PENDING   (1UL << __RQ_LOCAL_PENDING)
+#define RQ_LOCAL_COMPLETED (1UL << __RQ_LOCAL_COMPLETED)
+#define RQ_LOCAL_OK        (1UL << __RQ_LOCAL_OK)
+
+#define RQ_LOCAL_MASK      ((RQ_LOCAL_OK << 1)-1) /* 0x07 */
+
+#define RQ_NET_PENDING     (1UL << __RQ_NET_PENDING)
+#define RQ_NET_QUEUED      (1UL << __RQ_NET_QUEUED)
+#define RQ_NET_SENT        (1UL << __RQ_NET_SENT)
+#define RQ_NET_DONE        (1UL << __RQ_NET_DONE)
+#define RQ_NET_OK          (1UL << __RQ_NET_OK)
+#define RQ_NET_SIS         (1UL << __RQ_NET_SIS)
+
+/* 0x1f8 */
+#define RQ_NET_MASK        (((1UL << __RQ_NET_MAX)-1) & ~RQ_LOCAL_MASK)
+
+/* epoch entries */
+static inline
+struct hlist_head *ee_hash_slot(struct drbd_conf *mdev, sector_t sector)
+{
+       BUG_ON(mdev->ee_hash_s == 0);
+       return mdev->ee_hash +
+               ((unsigned int)(sector>>HT_SHIFT) % mdev->ee_hash_s);
+}
+
+/* transfer log (drbd_request objects) */
+static inline
+struct hlist_head *tl_hash_slot(struct drbd_conf *mdev, sector_t sector)
+{
+       BUG_ON(mdev->tl_hash_s == 0);
+       return mdev->tl_hash +
+               ((unsigned int)(sector>>HT_SHIFT) % mdev->tl_hash_s);
+}
+
+/* application reads (drbd_request objects) */
+static struct hlist_head *ar_hash_slot(struct drbd_conf *mdev, sector_t sector)
+{
+       return mdev->app_reads_hash
+               + ((unsigned int)(sector) % APP_R_HSIZE);
+}
+
+/* when we receive the answer for a read request,
+ * verify that we actually know about it */
+static inline struct drbd_request *_ar_id_to_req(struct drbd_conf *mdev,
+       u64 id, sector_t sector)
+{
+       struct hlist_head *slot = ar_hash_slot(mdev, sector);
+       struct hlist_node *n;
+       struct drbd_request *req;
+
+       hlist_for_each_entry(req, n, slot, colision) {
+               if ((unsigned long)req == (unsigned long)id) {
+                       D_ASSERT(req->sector == sector);
+                       return req;
+               }
+       }
+       return NULL;
+}
+
+static inline struct drbd_request *drbd_req_new(struct drbd_conf *mdev,
+       struct bio *bio_src)
+{
+       struct bio *bio;
+       struct drbd_request *req =
+               mempool_alloc(drbd_request_mempool, GFP_NOIO);
+       if (likely(req)) {
+               bio = bio_clone(bio_src, GFP_NOIO); /* XXX cannot fail?? */
+
+               req->rq_state    = 0;
+               req->mdev        = mdev;
+               req->master_bio  = bio_src;
+               req->private_bio = bio;
+               req->epoch       = 0;
+               req->sector      = bio->bi_sector;
+               req->size        = bio->bi_size;
+               req->start_time  = jiffies;
+               INIT_HLIST_NODE(&req->colision);
+               INIT_LIST_HEAD(&req->tl_requests);
+               INIT_LIST_HEAD(&req->w.list);
+
+               bio->bi_private  = req;
+               bio->bi_end_io   = drbd_endio_pri;
+               bio->bi_next     = NULL;
+       }
+       return req;
+}
+
+static inline void drbd_req_free(struct drbd_request *req)
+{
+       mempool_free(req, drbd_request_mempool);
+}
+
+static inline int overlaps(sector_t s1, int l1, sector_t s2, int l2)
+{
+       return !((s1 + (l1>>9) <= s2) || (s1 >= s2 + (l2>>9)));
+}
+
+/* Short lived temporary struct on the stack.
+ * We could squirrel the error to be returned into
+ * bio->bi_size, or similar. But that would be too ugly. */
+struct bio_and_error {
+       struct bio *bio;
+       int error;
+};
+
+extern void _req_may_be_done(struct drbd_request *req,
+               struct bio_and_error *m);
+extern void __req_mod(struct drbd_request *req, enum drbd_req_event what,
+               struct bio_and_error *m);
+extern void complete_master_bio(struct drbd_conf *mdev,
+               struct bio_and_error *m);
+
+/* use this if you don't want to deal with calling complete_master_bio()
+ * outside the spinlock, e.g. when walking some list on cleanup. */
+static inline void _req_mod(struct drbd_request *req, enum drbd_req_event what)
+{
+       struct drbd_conf *mdev = req->mdev;
+       struct bio_and_error m;
+
+       /* __req_mod possibly frees req, do not touch req after that! */
+       __req_mod(req, what, &m);
+       if (m.bio)
+               complete_master_bio(mdev, &m);
+}
+
+/* completion of master bio is outside of spinlock.
+ * If you need it irqsave, do it your self! */
+static inline void req_mod(struct drbd_request *req,
+               enum drbd_req_event what)
+{
+       struct drbd_conf *mdev = req->mdev;
+       struct bio_and_error m;
+       spin_lock_irq(&mdev->req_lock);
+       __req_mod(req, what, &m);
+       spin_unlock_irq(&mdev->req_lock);
+
+       if (m.bio)
+               complete_master_bio(mdev, &m);
+}
+#endif
diff --git a/drivers/block/drbd/drbd_strings.c b/drivers/block/drbd/drbd_strings.c
new file mode 100644 (file)
index 0000000..76863e3
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+  drbd.h
+
+  This file is part of DRBD by Philipp Reisner and Lars Ellenberg.
+
+  Copyright (C) 2003-2008, LINBIT Information Technologies GmbH.
+  Copyright (C) 2003-2008, Philipp Reisner <philipp.reisner@linbit.com>.
+  Copyright (C) 2003-2008, Lars Ellenberg <lars.ellenberg@linbit.com>.
+
+  drbd is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2, or (at your option)
+  any later version.
+
+  drbd 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 drbd; see the file COPYING.  If not, write to
+  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include <linux/drbd.h>
+
+static const char *drbd_conn_s_names[] = {
+       [C_STANDALONE]       = "StandAlone",
+       [C_DISCONNECTING]    = "Disconnecting",
+       [C_UNCONNECTED]      = "Unconnected",
+       [C_TIMEOUT]          = "Timeout",
+       [C_BROKEN_PIPE]      = "BrokenPipe",
+       [C_NETWORK_FAILURE]  = "NetworkFailure",
+       [C_PROTOCOL_ERROR]   = "ProtocolError",
+       [C_WF_CONNECTION]    = "WFConnection",
+       [C_WF_REPORT_PARAMS] = "WFReportParams",
+       [C_TEAR_DOWN]        = "TearDown",
+       [C_CONNECTED]        = "Connected",
+       [C_STARTING_SYNC_S]  = "StartingSyncS",
+       [C_STARTING_SYNC_T]  = "StartingSyncT",
+       [C_WF_BITMAP_S]      = "WFBitMapS",
+       [C_WF_BITMAP_T]      = "WFBitMapT",
+       [C_WF_SYNC_UUID]     = "WFSyncUUID",
+       [C_SYNC_SOURCE]      = "SyncSource",
+       [C_SYNC_TARGET]      = "SyncTarget",
+       [C_PAUSED_SYNC_S]    = "PausedSyncS",
+       [C_PAUSED_SYNC_T]    = "PausedSyncT",
+       [C_VERIFY_S]         = "VerifyS",
+       [C_VERIFY_T]         = "VerifyT",
+};
+
+static const char *drbd_role_s_names[] = {
+       [R_PRIMARY]   = "Primary",
+       [R_SECONDARY] = "Secondary",
+       [R_UNKNOWN]   = "Unknown"
+};
+
+static const char *drbd_disk_s_names[] = {
+       [D_DISKLESS]     = "Diskless",
+       [D_ATTACHING]    = "Attaching",
+       [D_FAILED]       = "Failed",
+       [D_NEGOTIATING]  = "Negotiating",
+       [D_INCONSISTENT] = "Inconsistent",
+       [D_OUTDATED]     = "Outdated",
+       [D_UNKNOWN]      = "DUnknown",
+       [D_CONSISTENT]   = "Consistent",
+       [D_UP_TO_DATE]   = "UpToDate",
+};
+
+static const char *drbd_state_sw_errors[] = {
+       [-SS_TWO_PRIMARIES] = "Multiple primaries not allowed by config",
+       [-SS_NO_UP_TO_DATE_DISK] = "Refusing to be Primary without at least one UpToDate disk",
+       [-SS_NO_LOCAL_DISK] = "Can not resync without local disk",
+       [-SS_NO_REMOTE_DISK] = "Can not resync without remote disk",
+       [-SS_CONNECTED_OUTDATES] = "Refusing to be Outdated while Connected",
+       [-SS_PRIMARY_NOP] = "Refusing to be Primary while peer is not outdated",
+       [-SS_RESYNC_RUNNING] = "Can not start OV/resync since it is already active",
+       [-SS_ALREADY_STANDALONE] = "Can not disconnect a StandAlone device",
+       [-SS_CW_FAILED_BY_PEER] = "State change was refused by peer node",
+       [-SS_IS_DISKLESS] = "Device is diskless, the requested operation requires a disk",
+       [-SS_DEVICE_IN_USE] = "Device is held open by someone",
+       [-SS_NO_NET_CONFIG] = "Have no net/connection configuration",
+       [-SS_NO_VERIFY_ALG] = "Need a verify algorithm to start online verify",
+       [-SS_NEED_CONNECTION] = "Need a connection to start verify or resync",
+       [-SS_NOT_SUPPORTED] = "Peer does not support protocol",
+       [-SS_LOWER_THAN_OUTDATED] = "Disk state is lower than outdated",
+       [-SS_IN_TRANSIENT_STATE] = "In transient state, retry after next state change",
+       [-SS_CONCURRENT_ST_CHG] = "Concurrent state changes detected and aborted",
+};
+
+const char *drbd_conn_str(enum drbd_conns s)
+{
+       /* enums are unsigned... */
+       return s > C_PAUSED_SYNC_T ? "TOO_LARGE" : drbd_conn_s_names[s];
+}
+
+const char *drbd_role_str(enum drbd_role s)
+{
+       return s > R_SECONDARY   ? "TOO_LARGE" : drbd_role_s_names[s];
+}
+
+const char *drbd_disk_str(enum drbd_disk_state s)
+{
+       return s > D_UP_TO_DATE    ? "TOO_LARGE" : drbd_disk_s_names[s];
+}
+
+const char *drbd_set_st_err_str(enum drbd_state_ret_codes err)
+{
+       return err <= SS_AFTER_LAST_ERROR ? "TOO_SMALL" :
+              err > SS_TWO_PRIMARIES ? "TOO_LARGE"
+                       : drbd_state_sw_errors[-err];
+}
diff --git a/drivers/block/drbd/drbd_vli.h b/drivers/block/drbd/drbd_vli.h
new file mode 100644 (file)
index 0000000..fc82400
--- /dev/null
@@ -0,0 +1,351 @@
+/*
+-*- linux-c -*-
+   drbd_receiver.c
+   This file is part of DRBD by Philipp Reisner and Lars Ellenberg.
+
+   Copyright (C) 2001-2008, LINBIT Information Technologies GmbH.
+   Copyright (C) 1999-2008, Philipp Reisner <philipp.reisner@linbit.com>.
+   Copyright (C) 2002-2008, Lars Ellenberg <lars.ellenberg@linbit.com>.
+
+   drbd is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   drbd 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 drbd; see the file COPYING.  If not, write to
+   the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _DRBD_VLI_H
+#define _DRBD_VLI_H
+
+/*
+ * At a granularity of 4KiB storage represented per bit,
+ * and stroage sizes of several TiB,
+ * and possibly small-bandwidth replication,
+ * the bitmap transfer time can take much too long,
+ * if transmitted in plain text.
+ *
+ * We try to reduce the transfered bitmap information
+ * by encoding runlengths of bit polarity.
+ *
+ * We never actually need to encode a "zero" (runlengths are positive).
+ * But then we have to store the value of the first bit.
+ * The first bit of information thus shall encode if the first runlength
+ * gives the number of set or unset bits.
+ *
+ * We assume that large areas are either completely set or unset,
+ * which gives good compression with any runlength method,
+ * even when encoding the runlength as fixed size 32bit/64bit integers.
+ *
+ * Still, there may be areas where the polarity flips every few bits,
+ * and encoding the runlength sequence of those areas with fix size
+ * integers would be much worse than plaintext.
+ *
+ * We want to encode small runlength values with minimum code length,
+ * while still being able to encode a Huge run of all zeros.
+ *
+ * Thus we need a Variable Length Integer encoding, VLI.
+ *
+ * For some cases, we produce more code bits than plaintext input.
+ * We need to send incompressible chunks as plaintext, skip over them
+ * and then see if the next chunk compresses better.
+ *
+ * We don't care too much about "excellent" compression ratio for large
+ * runlengths (all set/all clear): whether we achieve a factor of 100
+ * or 1000 is not that much of an issue.
+ * We do not want to waste too much on short runlengths in the "noisy"
+ * parts of the bitmap, though.
+ *
+ * There are endless variants of VLI, we experimented with:
+ *  * simple byte-based
+ *  * various bit based with different code word length.
+ *
+ * To avoid yet an other configuration parameter (choice of bitmap compression
+ * algorithm) which was difficult to explain and tune, we just chose the one
+ * variant that turned out best in all test cases.
+ * Based on real world usage patterns, with device sizes ranging from a few GiB
+ * to several TiB, file server/mailserver/webserver/mysql/postgress,
+ * mostly idle to really busy, the all time winner (though sometimes only
+ * marginally better) is:
+ */
+
+/*
+ * encoding is "visualised" as
+ * __little endian__ bitstream, least significant bit first (left most)
+ *
+ * this particular encoding is chosen so that the prefix code
+ * starts as unary encoding the level, then modified so that
+ * 10 levels can be described in 8bit, with minimal overhead
+ * for the smaller levels.
+ *
+ * Number of data bits follow fibonacci sequence, with the exception of the
+ * last level (+1 data bit, so it makes 64bit total).  The only worse code when
+ * encoding bit polarity runlength is 1 plain bits => 2 code bits.
+prefix    data bits                                    max val  Nº data bits
+0 x                                                         0x2            1
+10 x                                                        0x4            1
+110 xx                                                      0x8            2
+1110 xxx                                                   0x10            3
+11110 xxx xx                                               0x30            5
+111110 xx xxxxxx                                          0x130            8
+11111100  xxxxxxxx xxxxx                                 0x2130           13
+11111110  xxxxxxxx xxxxxxxx xxxxx                      0x202130           21
+11111101  xxxxxxxx xxxxxxxx xxxxxxxx  xxxxxxxx xx   0x400202130           34
+11111111  xxxxxxxx xxxxxxxx xxxxxxxx  xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx 56
+ * maximum encodable value: 0x100000400202130 == 2**56 + some */
+
+/* compression "table":
+ transmitted   x                                0.29
+ as plaintext x                                  ........................
+             x                                   ........................
+            x                                    ........................
+           x    0.59                         0.21........................
+          x      ........................................................
+         x       .. c ...................................................
+        x    0.44.. o ...................................................
+       x .......... d ...................................................
+      x  .......... e ...................................................
+     X.............   ...................................................
+    x.............. b ...................................................
+2.0x............... i ...................................................
+ #X................ t ...................................................
+ #................. s ...........................  plain bits  ..........
+-+-----------------------------------------------------------------------
+ 1             16              32                              64
+*/
+
+/* LEVEL: (total bits, prefix bits, prefix value),
+ * sorted ascending by number of total bits.
+ * The rest of the code table is calculated at compiletime from this. */
+
+/* fibonacci data 1, 1, ... */
+#define VLI_L_1_1() do { \
+       LEVEL( 2, 1, 0x00); \
+       LEVEL( 3, 2, 0x01); \
+       LEVEL( 5, 3, 0x03); \
+       LEVEL( 7, 4, 0x07); \
+       LEVEL(10, 5, 0x0f); \
+       LEVEL(14, 6, 0x1f); \
+       LEVEL(21, 8, 0x3f); \
+       LEVEL(29, 8, 0x7f); \
+       LEVEL(42, 8, 0xbf); \
+       LEVEL(64, 8, 0xff); \
+       } while (0)
+
+/* finds a suitable level to decode the least significant part of in.
+ * returns number of bits consumed.
+ *
+ * BUG() for bad input, as that would mean a buggy code table. */
+static inline int vli_decode_bits(u64 *out, const u64 in)
+{
+       u64 adj = 1;
+
+#define LEVEL(t,b,v)                                   \
+       do {                                            \
+               if ((in & ((1 << b) -1)) == v) {        \
+                       *out = ((in & ((~0ULL) >> (64-t))) >> b) + adj; \
+                       return t;                       \
+               }                                       \
+               adj += 1ULL << (t - b);                 \
+       } while (0)
+
+       VLI_L_1_1();
+
+       /* NOT REACHED, if VLI_LEVELS code table is defined properly */
+       BUG();
+#undef LEVEL
+}
+
+/* return number of code bits needed,
+ * or negative error number */
+static inline int __vli_encode_bits(u64 *out, const u64 in)
+{
+       u64 max = 0;
+       u64 adj = 1;
+
+       if (in == 0)
+               return -EINVAL;
+
+#define LEVEL(t,b,v) do {              \
+               max += 1ULL << (t - b); \
+               if (in <= max) {        \
+                       if (out)        \
+                               *out = ((in - adj) << b) | v;   \
+                       return t;       \
+               }                       \
+               adj = max + 1;          \
+       } while (0)
+
+       VLI_L_1_1();
+
+       return -EOVERFLOW;
+#undef LEVEL
+}
+
+#undef VLI_L_1_1
+
+/* code from here down is independend of actually used bit code */
+
+/*
+ * Code length is determined by some unique (e.g. unary) prefix.
+ * This encodes arbitrary bit length, not whole bytes: we have a bit-stream,
+ * not a byte stream.
+ */
+
+/* for the bitstream, we need a cursor */
+struct bitstream_cursor {
+       /* the current byte */
+       u8 *b;
+       /* the current bit within *b, nomalized: 0..7 */
+       unsigned int bit;
+};
+
+/* initialize cursor to point to first bit of stream */
+static inline void bitstream_cursor_reset(struct bitstream_cursor *cur, void *s)
+{
+       cur->b = s;
+       cur->bit = 0;
+}
+
+/* advance cursor by that many bits; maximum expected input value: 64,
+ * but depending on VLI implementation, it may be more. */
+static inline void bitstream_cursor_advance(struct bitstream_cursor *cur, unsigned int bits)
+{
+       bits += cur->bit;
+       cur->b = cur->b + (bits >> 3);
+       cur->bit = bits & 7;
+}
+
+/* the bitstream itself knows its length */
+struct bitstream {
+       struct bitstream_cursor cur;
+       unsigned char *buf;
+       size_t buf_len;         /* in bytes */
+
+       /* for input stream:
+        * number of trailing 0 bits for padding
+        * total number of valid bits in stream: buf_len * 8 - pad_bits */
+       unsigned int pad_bits;
+};
+
+static inline void bitstream_init(struct bitstream *bs, void *s, size_t len, unsigned int pad_bits)
+{
+       bs->buf = s;
+       bs->buf_len = len;
+       bs->pad_bits = pad_bits;
+       bitstream_cursor_reset(&bs->cur, bs->buf);
+}
+
+static inline void bitstream_rewind(struct bitstream *bs)
+{
+       bitstream_cursor_reset(&bs->cur, bs->buf);
+       memset(bs->buf, 0, bs->buf_len);
+}
+
+/* Put (at most 64) least significant bits of val into bitstream, and advance cursor.
+ * Ignores "pad_bits".
+ * Returns zero if bits == 0 (nothing to do).
+ * Returns number of bits used if successful.
+ *
+ * If there is not enough room left in bitstream,
+ * leaves bitstream unchanged and returns -ENOBUFS.
+ */
+static inline int bitstream_put_bits(struct bitstream *bs, u64 val, const unsigned int bits)
+{
+       unsigned char *b = bs->cur.b;
+       unsigned int tmp;
+
+       if (bits == 0)
+               return 0;
+
+       if ((bs->cur.b + ((bs->cur.bit + bits -1) >> 3)) - bs->buf >= bs->buf_len)
+               return -ENOBUFS;
+
+       /* paranoia: strip off hi bits; they should not be set anyways. */
+       if (bits < 64)
+               val &= ~0ULL >> (64 - bits);
+
+       *b++ |= (val & 0xff) << bs->cur.bit;
+
+       for (tmp = 8 - bs->cur.bit; tmp < bits; tmp += 8)
+               *b++ |= (val >> tmp) & 0xff;
+
+       bitstream_cursor_advance(&bs->cur, bits);
+       return bits;
+}
+
+/* Fetch (at most 64) bits from bitstream into *out, and advance cursor.
+ *
+ * If more than 64 bits are requested, returns -EINVAL and leave *out unchanged.
+ *
+ * If there are less than the requested number of valid bits left in the
+ * bitstream, still fetches all available bits.
+ *
+ * Returns number of actually fetched bits.
+ */
+static inline int bitstream_get_bits(struct bitstream *bs, u64 *out, int bits)
+{
+       u64 val;
+       unsigned int n;
+
+       if (bits > 64)
+               return -EINVAL;
+
+       if (bs->cur.b + ((bs->cur.bit + bs->pad_bits + bits -1) >> 3) - bs->buf >= bs->buf_len)
+               bits = ((bs->buf_len - (bs->cur.b - bs->buf)) << 3)
+                       - bs->cur.bit - bs->pad_bits;
+
+       if (bits == 0) {
+               *out = 0;
+               return 0;
+       }
+
+       /* get the high bits */
+       val = 0;
+       n = (bs->cur.bit + bits + 7) >> 3;
+       /* n may be at most 9, if cur.bit + bits > 64 */
+       /* which means this copies at most 8 byte */
+       if (n) {
+               memcpy(&val, bs->cur.b+1, n - 1);
+               val = le64_to_cpu(val) << (8 - bs->cur.bit);
+       }
+
+       /* we still need the low bits */
+       val |= bs->cur.b[0] >> bs->cur.bit;
+
+       /* and mask out bits we don't want */
+       val &= ~0ULL >> (64 - bits);
+
+       bitstream_cursor_advance(&bs->cur, bits);
+       *out = val;
+
+       return bits;
+}
+
+/* encodes @in as vli into @bs;
+
+ * return values
+ *  > 0: number of bits successfully stored in bitstream
+ * -ENOBUFS @bs is full
+ * -EINVAL input zero (invalid)
+ * -EOVERFLOW input too large for this vli code (invalid)
+ */
+static inline int vli_encode_bits(struct bitstream *bs, u64 in)
+{
+       u64 code = code;
+       int bits = __vli_encode_bits(&code, in);
+
+       if (bits <= 0)
+               return bits;
+
+       return bitstream_put_bits(bs, code, bits);
+}
+
+#endif
diff --git a/drivers/block/drbd/drbd_worker.c b/drivers/block/drbd/drbd_worker.c
new file mode 100644 (file)
index 0000000..ed8796f
--- /dev/null
@@ -0,0 +1,1512 @@
+/*
+   drbd_worker.c
+
+   This file is part of DRBD by Philipp Reisner and Lars Ellenberg.
+
+   Copyright (C) 2001-2008, LINBIT Information Technologies GmbH.
+   Copyright (C) 1999-2008, Philipp Reisner <philipp.reisner@linbit.com>.
+   Copyright (C) 2002-2008, Lars Ellenberg <lars.ellenberg@linbit.com>.
+
+   drbd is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   drbd 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 drbd; see the file COPYING.  If not, write to
+   the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ */
+
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/drbd.h>
+#include <linux/sched.h>
+#include <linux/smp_lock.h>
+#include <linux/wait.h>
+#include <linux/mm.h>
+#include <linux/memcontrol.h>
+#include <linux/mm_inline.h>
+#include <linux/slab.h>
+#include <linux/random.h>
+#include <linux/mm.h>
+#include <linux/string.h>
+#include <linux/scatterlist.h>
+
+#include "drbd_int.h"
+#include "drbd_req.h"
+
+#define SLEEP_TIME (HZ/10)
+
+static int w_make_ov_request(struct drbd_conf *mdev, struct drbd_work *w, int cancel);
+
+
+
+/* defined here:
+   drbd_md_io_complete
+   drbd_endio_write_sec
+   drbd_endio_read_sec
+   drbd_endio_pri
+
+ * more endio handlers:
+   atodb_endio in drbd_actlog.c
+   drbd_bm_async_io_complete in drbd_bitmap.c
+
+ * For all these callbacks, note the following:
+ * The callbacks will be called in irq context by the IDE drivers,
+ * and in Softirqs/Tasklets/BH context by the SCSI drivers.
+ * Try to get the locking right :)
+ *
+ */
+
+
+/* About the global_state_lock
+   Each state transition on an device holds a read lock. In case we have
+   to evaluate the sync after dependencies, we grab a write lock, because
+   we need stable states on all devices for that.  */
+rwlock_t global_state_lock;
+
+/* used for synchronous meta data and bitmap IO
+ * submitted by drbd_md_sync_page_io()
+ */
+void drbd_md_io_complete(struct bio *bio, int error)
+{
+       struct drbd_md_io *md_io;
+
+       md_io = (struct drbd_md_io *)bio->bi_private;
+       md_io->error = error;
+
+       complete(&md_io->event);
+}
+
+/* reads on behalf of the partner,
+ * "submitted" by the receiver
+ */
+void drbd_endio_read_sec(struct bio *bio, int error) __releases(local)
+{
+       unsigned long flags = 0;
+       struct drbd_epoch_entry *e = NULL;
+       struct drbd_conf *mdev;
+       int uptodate = bio_flagged(bio, BIO_UPTODATE);
+
+       e = bio->bi_private;
+       mdev = e->mdev;
+
+       if (error)
+               dev_warn(DEV, "read: error=%d s=%llus\n", error,
+                               (unsigned long long)e->sector);
+       if (!error && !uptodate) {
+               dev_warn(DEV, "read: setting error to -EIO s=%llus\n",
+                               (unsigned long long)e->sector);
+               /* strange behavior of some lower level drivers...
+                * fail the request by clearing the uptodate flag,
+                * but do not return any error?! */
+               error = -EIO;
+       }
+
+       D_ASSERT(e->block_id != ID_VACANT);
+
+       spin_lock_irqsave(&mdev->req_lock, flags);
+       mdev->read_cnt += e->size >> 9;
+       list_del(&e->w.list);
+       if (list_empty(&mdev->read_ee))
+               wake_up(&mdev->ee_wait);
+       spin_unlock_irqrestore(&mdev->req_lock, flags);
+
+       drbd_chk_io_error(mdev, error, FALSE);
+       drbd_queue_work(&mdev->data.work, &e->w);
+       put_ldev(mdev);
+}
+
+/* writes on behalf of the partner, or resync writes,
+ * "submitted" by the receiver.
+ */
+void drbd_endio_write_sec(struct bio *bio, int error) __releases(local)
+{
+       unsigned long flags = 0;
+       struct drbd_epoch_entry *e = NULL;
+       struct drbd_conf *mdev;
+       sector_t e_sector;
+       int do_wake;
+       int is_syncer_req;
+       int do_al_complete_io;
+       int uptodate = bio_flagged(bio, BIO_UPTODATE);
+       int is_barrier = bio_rw_flagged(bio, BIO_RW_BARRIER);
+
+       e = bio->bi_private;
+       mdev = e->mdev;
+
+       if (error)
+               dev_warn(DEV, "write: error=%d s=%llus\n", error,
+                               (unsigned long long)e->sector);
+       if (!error && !uptodate) {
+               dev_warn(DEV, "write: setting error to -EIO s=%llus\n",
+                               (unsigned long long)e->sector);
+               /* strange behavior of some lower level drivers...
+                * fail the request by clearing the uptodate flag,
+                * but do not return any error?! */
+               error = -EIO;
+       }
+
+       /* error == -ENOTSUPP would be a better test,
+        * alas it is not reliable */
+       if (error && is_barrier && e->flags & EE_IS_BARRIER) {
+               drbd_bump_write_ordering(mdev, WO_bdev_flush);
+               spin_lock_irqsave(&mdev->req_lock, flags);
+               list_del(&e->w.list);
+               e->w.cb = w_e_reissue;
+               /* put_ldev actually happens below, once we come here again. */
+               __release(local);
+               spin_unlock_irqrestore(&mdev->req_lock, flags);
+               drbd_queue_work(&mdev->data.work, &e->w);
+               return;
+       }
+
+       D_ASSERT(e->block_id != ID_VACANT);
+
+       spin_lock_irqsave(&mdev->req_lock, flags);
+       mdev->writ_cnt += e->size >> 9;
+       is_syncer_req = is_syncer_block_id(e->block_id);
+
+       /* after we moved e to done_ee,
+        * we may no longer access it,
+        * it may be freed/reused already!
+        * (as soon as we release the req_lock) */
+       e_sector = e->sector;
+       do_al_complete_io = e->flags & EE_CALL_AL_COMPLETE_IO;
+
+       list_del(&e->w.list); /* has been on active_ee or sync_ee */
+       list_add_tail(&e->w.list, &mdev->done_ee);
+
+       /* No hlist_del_init(&e->colision) here, we did not send the Ack yet,
+        * neither did we wake possibly waiting conflicting requests.
+        * done from "drbd_process_done_ee" within the appropriate w.cb
+        * (e_end_block/e_end_resync_block) or from _drbd_clear_done_ee */
+
+       do_wake = is_syncer_req
+               ? list_empty(&mdev->sync_ee)
+               : list_empty(&mdev->active_ee);
+
+       if (error)
+               __drbd_chk_io_error(mdev, FALSE);
+       spin_unlock_irqrestore(&mdev->req_lock, flags);
+
+       if (is_syncer_req)
+               drbd_rs_complete_io(mdev, e_sector);
+
+       if (do_wake)
+               wake_up(&mdev->ee_wait);
+
+       if (do_al_complete_io)
+               drbd_al_complete_io(mdev, e_sector);
+
+       wake_asender(mdev);
+       put_ldev(mdev);
+
+}
+
+/* read, readA or write requests on R_PRIMARY coming from drbd_make_request
+ */
+void drbd_endio_pri(struct bio *bio, int error)
+{
+       unsigned long flags;
+       struct drbd_request *req = bio->bi_private;
+       struct drbd_conf *mdev = req->mdev;
+       struct bio_and_error m;
+       enum drbd_req_event what;
+       int uptodate = bio_flagged(bio, BIO_UPTODATE);
+
+       if (error)
+               dev_warn(DEV, "p %s: error=%d\n",
+                        bio_data_dir(bio) == WRITE ? "write" : "read", error);
+       if (!error && !uptodate) {
+               dev_warn(DEV, "p %s: setting error to -EIO\n",
+                        bio_data_dir(bio) == WRITE ? "write" : "read");
+               /* strange behavior of some lower level drivers...
+                * fail the request by clearing the uptodate flag,
+                * but do not return any error?! */
+               error = -EIO;
+       }
+
+       /* to avoid recursion in __req_mod */
+       if (unlikely(error)) {
+               what = (bio_data_dir(bio) == WRITE)
+                       ? write_completed_with_error
+                       : (bio_rw(bio) == READA)
+                         ? read_completed_with_error
+                         : read_ahead_completed_with_error;
+       } else
+               what = completed_ok;
+
+       bio_put(req->private_bio);
+       req->private_bio = ERR_PTR(error);
+
+       spin_lock_irqsave(&mdev->req_lock, flags);
+       __req_mod(req, what, &m);
+       spin_unlock_irqrestore(&mdev->req_lock, flags);
+
+       if (m.bio)
+               complete_master_bio(mdev, &m);
+}
+
+int w_io_error(struct drbd_conf *mdev, struct drbd_work *w, int cancel)
+{
+       struct drbd_request *req = container_of(w, struct drbd_request, w);
+
+       /* NOTE: mdev->ldev can be NULL by the time we get here! */
+       /* D_ASSERT(mdev->ldev->dc.on_io_error != EP_PASS_ON); */
+
+       /* the only way this callback is scheduled is from _req_may_be_done,
+        * when it is done and had a local write error, see comments there */
+       drbd_req_free(req);
+
+       return TRUE;
+}
+
+int w_read_retry_remote(struct drbd_conf *mdev, struct drbd_work *w, int cancel)
+{
+       struct drbd_request *req = container_of(w, struct drbd_request, w);
+
+       /* We should not detach for read io-error,
+        * but try to WRITE the P_DATA_REPLY to the failed location,
+        * to give the disk the chance to relocate that block */
+
+       spin_lock_irq(&mdev->req_lock);
+       if (cancel ||
+           mdev->state.conn < C_CONNECTED ||
+           mdev->state.pdsk <= D_INCONSISTENT) {
+               _req_mod(req, send_canceled);
+               spin_unlock_irq(&mdev->req_lock);
+               dev_alert(DEV, "WE ARE LOST. Local IO failure, no peer.\n");
+               return 1;
+       }
+       spin_unlock_irq(&mdev->req_lock);
+
+       return w_send_read_req(mdev, w, 0);
+}
+
+int w_resync_inactive(struct drbd_conf *mdev, struct drbd_work *w, int cancel)
+{
+       ERR_IF(cancel) return 1;
+       dev_err(DEV, "resync inactive, but callback triggered??\n");
+       return 1; /* Simply ignore this! */
+}
+
+void drbd_csum(struct drbd_conf *mdev, struct crypto_hash *tfm, struct bio *bio, void *digest)
+{
+       struct hash_desc desc;
+       struct scatterlist sg;
+       struct bio_vec *bvec;
+       int i;
+
+       desc.tfm = tfm;
+       desc.flags = 0;
+
+       sg_init_table(&sg, 1);
+       crypto_hash_init(&desc);
+
+       __bio_for_each_segment(bvec, bio, i, 0) {
+               sg_set_page(&sg, bvec->bv_page, bvec->bv_len, bvec->bv_offset);
+               crypto_hash_update(&desc, &sg, sg.length);
+       }
+       crypto_hash_final(&desc, digest);
+}
+
+static int w_e_send_csum(struct drbd_conf *mdev, struct drbd_work *w, int cancel)
+{
+       struct drbd_epoch_entry *e = container_of(w, struct drbd_epoch_entry, w);
+       int digest_size;
+       void *digest;
+       int ok;
+
+       D_ASSERT(e->block_id == DRBD_MAGIC + 0xbeef);
+
+       if (unlikely(cancel)) {
+               drbd_free_ee(mdev, e);
+               return 1;
+       }
+
+       if (likely(drbd_bio_uptodate(e->private_bio))) {
+               digest_size = crypto_hash_digestsize(mdev->csums_tfm);
+               digest = kmalloc(digest_size, GFP_NOIO);
+               if (digest) {
+                       drbd_csum(mdev, mdev->csums_tfm, e->private_bio, digest);
+
+                       inc_rs_pending(mdev);
+                       ok = drbd_send_drequest_csum(mdev,
+                                                    e->sector,
+                                                    e->size,
+                                                    digest,
+                                                    digest_size,
+                                                    P_CSUM_RS_REQUEST);
+                       kfree(digest);
+               } else {
+                       dev_err(DEV, "kmalloc() of digest failed.\n");
+                       ok = 0;
+               }
+       } else
+               ok = 1;
+
+       drbd_free_ee(mdev, e);
+
+       if (unlikely(!ok))
+               dev_err(DEV, "drbd_send_drequest(..., csum) failed\n");
+       return ok;
+}
+
+#define GFP_TRY        (__GFP_HIGHMEM | __GFP_NOWARN)
+
+static int read_for_csum(struct drbd_conf *mdev, sector_t sector, int size)
+{
+       struct drbd_epoch_entry *e;
+
+       if (!get_ldev(mdev))
+               return 0;
+
+       /* GFP_TRY, because if there is no memory available right now, this may
+        * be rescheduled for later. It is "only" background resync, after all. */
+       e = drbd_alloc_ee(mdev, DRBD_MAGIC+0xbeef, sector, size, GFP_TRY);
+       if (!e) {
+               put_ldev(mdev);
+               return 2;
+       }
+
+       spin_lock_irq(&mdev->req_lock);
+       list_add(&e->w.list, &mdev->read_ee);
+       spin_unlock_irq(&mdev->req_lock);
+
+       e->private_bio->bi_end_io = drbd_endio_read_sec;
+       e->private_bio->bi_rw = READ;
+       e->w.cb = w_e_send_csum;
+
+       mdev->read_cnt += size >> 9;
+       drbd_generic_make_request(mdev, DRBD_FAULT_RS_RD, e->private_bio);
+
+       return 1;
+}
+
+void resync_timer_fn(unsigned long data)
+{
+       unsigned long flags;
+       struct drbd_conf *mdev = (struct drbd_conf *) data;
+       int queue;
+
+       spin_lock_irqsave(&mdev->req_lock, flags);
+
+       if (likely(!test_and_clear_bit(STOP_SYNC_TIMER, &mdev->flags))) {
+               queue = 1;
+               if (mdev->state.conn == C_VERIFY_S)
+                       mdev->resync_work.cb = w_make_ov_request;
+               else
+                       mdev->resync_work.cb = w_make_resync_request;
+       } else {
+               queue = 0;
+               mdev->resync_work.cb = w_resync_inactive;
+       }
+
+       spin_unlock_irqrestore(&mdev->req_lock, flags);
+
+       /* harmless race: list_empty outside data.work.q_lock */
+       if (list_empty(&mdev->resync_work.list) && queue)
+               drbd_queue_work(&mdev->data.work, &mdev->resync_work);
+}
+
+int w_make_resync_request(struct drbd_conf *mdev,
+               struct drbd_work *w, int cancel)
+{
+       unsigned long bit;
+       sector_t sector;
+       const sector_t capacity = drbd_get_capacity(mdev->this_bdev);
+       int max_segment_size = queue_max_segment_size(mdev->rq_queue);
+       int number, i, size, pe, mx;
+       int align, queued, sndbuf;
+
+       if (unlikely(cancel))
+               return 1;
+
+       if (unlikely(mdev->state.conn < C_CONNECTED)) {
+               dev_err(DEV, "Confused in w_make_resync_request()! cstate < Connected");
+               return 0;
+       }
+
+       if (mdev->state.conn != C_SYNC_TARGET)
+               dev_err(DEV, "%s in w_make_resync_request\n",
+                       drbd_conn_str(mdev->state.conn));
+
+       if (!get_ldev(mdev)) {
+               /* Since we only need to access mdev->rsync a
+                  get_ldev_if_state(mdev,D_FAILED) would be sufficient, but
+                  to continue resync with a broken disk makes no sense at
+                  all */
+               dev_err(DEV, "Disk broke down during resync!\n");
+               mdev->resync_work.cb = w_resync_inactive;
+               return 1;
+       }
+
+       number = SLEEP_TIME * mdev->sync_conf.rate / ((BM_BLOCK_SIZE/1024)*HZ);
+       pe = atomic_read(&mdev->rs_pending_cnt);
+
+       mutex_lock(&mdev->data.mutex);
+       if (mdev->data.socket)
+               mx = mdev->data.socket->sk->sk_rcvbuf / sizeof(struct p_block_req);
+       else
+               mx = 1;
+       mutex_unlock(&mdev->data.mutex);
+
+       /* For resync rates >160MB/sec, allow more pending RS requests */
+       if (number > mx)
+               mx = number;
+
+       /* Limit the number of pending RS requests to no more than the peer's receive buffer */
+       if ((pe + number) > mx) {
+               number = mx - pe;
+       }
+
+       for (i = 0; i < number; i++) {
+               /* Stop generating RS requests, when half of the send buffer is filled */
+               mutex_lock(&mdev->data.mutex);
+               if (mdev->data.socket) {
+                       queued = mdev->data.socket->sk->sk_wmem_queued;
+                       sndbuf = mdev->data.socket->sk->sk_sndbuf;
+               } else {
+                       queued = 1;
+                       sndbuf = 0;
+               }
+               mutex_unlock(&mdev->data.mutex);
+               if (queued > sndbuf / 2)
+                       goto requeue;
+
+next_sector:
+               size = BM_BLOCK_SIZE;
+               bit  = drbd_bm_find_next(mdev, mdev->bm_resync_fo);
+
+               if (bit == -1UL) {
+                       mdev->bm_resync_fo = drbd_bm_bits(mdev);
+                       mdev->resync_work.cb = w_resync_inactive;
+                       put_ldev(mdev);
+                       return 1;
+               }
+
+               sector = BM_BIT_TO_SECT(bit);
+
+               if (drbd_try_rs_begin_io(mdev, sector)) {
+                       mdev->bm_resync_fo = bit;
+                       goto requeue;
+               }
+               mdev->bm_resync_fo = bit + 1;
+
+               if (unlikely(drbd_bm_test_bit(mdev, bit) == 0)) {
+                       drbd_rs_complete_io(mdev, sector);
+                       goto next_sector;
+               }
+
+#if DRBD_MAX_SEGMENT_SIZE > BM_BLOCK_SIZE
+               /* try to find some adjacent bits.
+                * we stop if we have already the maximum req size.
+                *
+                * Additionally always align bigger requests, in order to
+                * be prepared for all stripe sizes of software RAIDs.
+                *
+                * we _do_ care about the agreed-upon q->max_segment_size
+                * here, as splitting up the requests on the other side is more
+                * difficult.  the consequence is, that on lvm and md and other
+                * "indirect" devices, this is dead code, since
+                * q->max_segment_size will be PAGE_SIZE.
+                */
+               align = 1;
+               for (;;) {
+                       if (size + BM_BLOCK_SIZE > max_segment_size)
+                               break;
+
+                       /* Be always aligned */
+                       if (sector & ((1<<(align+3))-1))
+                               break;
+
+                       /* do not cross extent boundaries */
+                       if (((bit+1) & BM_BLOCKS_PER_BM_EXT_MASK) == 0)
+                               break;
+                       /* now, is it actually dirty, after all?
+                        * caution, drbd_bm_test_bit is tri-state for some
+                        * obscure reason; ( b == 0 ) would get the out-of-band
+                        * only accidentally right because of the "oddly sized"
+                        * adjustment below */
+                       if (drbd_bm_test_bit(mdev, bit+1) != 1)
+                               break;
+                       bit++;
+                       size += BM_BLOCK_SIZE;
+                       if ((BM_BLOCK_SIZE << align) <= size)
+                               align++;
+                       i++;
+               }
+               /* if we merged some,
+                * reset the offset to start the next drbd_bm_find_next from */
+               if (size > BM_BLOCK_SIZE)
+                       mdev->bm_resync_fo = bit + 1;
+#endif
+
+               /* adjust very last sectors, in case we are oddly sized */
+               if (sector + (size>>9) > capacity)
+                       size = (capacity-sector)<<9;
+               if (mdev->agreed_pro_version >= 89 && mdev->csums_tfm) {
+                       switch (read_for_csum(mdev, sector, size)) {
+                       case 0: /* Disk failure*/
+                               put_ldev(mdev);
+                               return 0;
+                       case 2: /* Allocation failed */
+                               drbd_rs_complete_io(mdev, sector);
+                               mdev->bm_resync_fo = BM_SECT_TO_BIT(sector);
+                               goto requeue;
+                       /* case 1: everything ok */
+                       }
+               } else {
+                       inc_rs_pending(mdev);
+                       if (!drbd_send_drequest(mdev, P_RS_DATA_REQUEST,
+                                              sector, size, ID_SYNCER)) {
+                               dev_err(DEV, "drbd_send_drequest() failed, aborting...\n");
+                               dec_rs_pending(mdev);
+                               put_ldev(mdev);
+                               return 0;
+                       }
+               }
+       }
+
+       if (mdev->bm_resync_fo >= drbd_bm_bits(mdev)) {
+               /* last syncer _request_ was sent,
+                * but the P_RS_DATA_REPLY not yet received.  sync will end (and
+                * next sync group will resume), as soon as we receive the last
+                * resync data block, and the last bit is cleared.
+                * until then resync "work" is "inactive" ...
+                */
+               mdev->resync_work.cb = w_resync_inactive;
+               put_ldev(mdev);
+               return 1;
+       }
+
+ requeue:
+       mod_timer(&mdev->resync_timer, jiffies + SLEEP_TIME);
+       put_ldev(mdev);
+       return 1;
+}
+
+static int w_make_ov_request(struct drbd_conf *mdev, struct drbd_work *w, int cancel)
+{
+       int number, i, size;
+       sector_t sector;
+       const sector_t capacity = drbd_get_capacity(mdev->this_bdev);
+
+       if (unlikely(cancel))
+               return 1;
+
+       if (unlikely(mdev->state.conn < C_CONNECTED)) {
+               dev_err(DEV, "Confused in w_make_ov_request()! cstate < Connected");
+               return 0;
+       }
+
+       number = SLEEP_TIME*mdev->sync_conf.rate / ((BM_BLOCK_SIZE/1024)*HZ);
+       if (atomic_read(&mdev->rs_pending_cnt) > number)
+               goto requeue;
+
+       number -= atomic_read(&mdev->rs_pending_cnt);
+
+       sector = mdev->ov_position;
+       for (i = 0; i < number; i++) {
+               if (sector >= capacity) {
+                       mdev->resync_work.cb = w_resync_inactive;
+                       return 1;
+               }
+
+               size = BM_BLOCK_SIZE;
+
+               if (drbd_try_rs_begin_io(mdev, sector)) {
+                       mdev->ov_position = sector;
+                       goto requeue;
+               }
+
+               if (sector + (size>>9) > capacity)
+                       size = (capacity-sector)<<9;
+
+               inc_rs_pending(mdev);
+               if (!drbd_send_ov_request(mdev, sector, size)) {
+                       dec_rs_pending(mdev);
+                       return 0;
+               }
+               sector += BM_SECT_PER_BIT;
+       }
+       mdev->ov_position = sector;
+
+ requeue:
+       mod_timer(&mdev->resync_timer, jiffies + SLEEP_TIME);
+       return 1;
+}
+
+
+int w_ov_finished(struct drbd_conf *mdev, struct drbd_work *w, int cancel)
+{
+       kfree(w);
+       ov_oos_print(mdev);
+       drbd_resync_finished(mdev);
+
+       return 1;
+}
+
+static int w_resync_finished(struct drbd_conf *mdev, struct drbd_work *w, int cancel)
+{
+       kfree(w);
+
+       drbd_resync_finished(mdev);
+
+       return 1;
+}
+
+int drbd_resync_finished(struct drbd_conf *mdev)
+{
+       unsigned long db, dt, dbdt;
+       unsigned long n_oos;
+       union drbd_state os, ns;
+       struct drbd_work *w;
+       char *khelper_cmd = NULL;
+
+       /* Remove all elements from the resync LRU. Since future actions
+        * might set bits in the (main) bitmap, then the entries in the
+        * resync LRU would be wrong. */
+       if (drbd_rs_del_all(mdev)) {
+               /* In case this is not possible now, most probably because
+                * there are P_RS_DATA_REPLY Packets lingering on the worker's
+                * queue (or even the read operations for those packets
+                * is not finished by now).   Retry in 100ms. */
+
+               drbd_kick_lo(mdev);
+               __set_current_state(TASK_INTERRUPTIBLE);
+               schedule_timeout(HZ / 10);
+               w = kmalloc(sizeof(struct drbd_work), GFP_ATOMIC);
+               if (w) {
+                       w->cb = w_resync_finished;
+                       drbd_queue_work(&mdev->data.work, w);
+                       return 1;
+               }
+               dev_err(DEV, "Warn failed to drbd_rs_del_all() and to kmalloc(w).\n");
+       }
+
+       dt = (jiffies - mdev->rs_start - mdev->rs_paused) / HZ;
+       if (dt <= 0)
+               dt = 1;
+       db = mdev->rs_total;
+       dbdt = Bit2KB(db/dt);
+       mdev->rs_paused /= HZ;
+
+       if (!get_ldev(mdev))
+               goto out;
+
+       spin_lock_irq(&mdev->req_lock);
+       os = mdev->state;
+
+       /* This protects us against multiple calls (that can happen in the presence
+          of application IO), and against connectivity loss just before we arrive here. */
+       if (os.conn <= C_CONNECTED)
+               goto out_unlock;
+
+       ns = os;
+       ns.conn = C_CONNECTED;
+
+       dev_info(DEV, "%s done (total %lu sec; paused %lu sec; %lu K/sec)\n",
+            (os.conn == C_VERIFY_S || os.conn == C_VERIFY_T) ?
+            "Online verify " : "Resync",
+            dt + mdev->rs_paused, mdev->rs_paused, dbdt);
+
+       n_oos = drbd_bm_total_weight(mdev);
+
+       if (os.conn == C_VERIFY_S || os.conn == C_VERIFY_T) {
+               if (n_oos) {
+                       dev_alert(DEV, "Online verify found %lu %dk block out of sync!\n",
+                             n_oos, Bit2KB(1));
+                       khelper_cmd = "out-of-sync";
+               }
+       } else {
+               D_ASSERT((n_oos - mdev->rs_failed) == 0);
+
+               if (os.conn == C_SYNC_TARGET || os.conn == C_PAUSED_SYNC_T)
+                       khelper_cmd = "after-resync-target";
+
+               if (mdev->csums_tfm && mdev->rs_total) {
+                       const unsigned long s = mdev->rs_same_csum;
+                       const unsigned long t = mdev->rs_total;
+                       const int ratio =
+                               (t == 0)     ? 0 :
+                       (t < 100000) ? ((s*100)/t) : (s/(t/100));
+                       dev_info(DEV, "%u %% had equal check sums, eliminated: %luK; "
+                            "transferred %luK total %luK\n",
+                            ratio,
+                            Bit2KB(mdev->rs_same_csum),
+                            Bit2KB(mdev->rs_total - mdev->rs_same_csum),
+                            Bit2KB(mdev->rs_total));
+               }
+       }
+
+       if (mdev->rs_failed) {
+               dev_info(DEV, "            %lu failed blocks\n", mdev->rs_failed);
+
+               if (os.conn == C_SYNC_TARGET || os.conn == C_PAUSED_SYNC_T) {
+                       ns.disk = D_INCONSISTENT;
+                       ns.pdsk = D_UP_TO_DATE;
+               } else {
+                       ns.disk = D_UP_TO_DATE;
+                       ns.pdsk = D_INCONSISTENT;
+               }
+       } else {
+               ns.disk = D_UP_TO_DATE;
+               ns.pdsk = D_UP_TO_DATE;
+
+               if (os.conn == C_SYNC_TARGET || os.conn == C_PAUSED_SYNC_T) {
+                       if (mdev->p_uuid) {
+                               int i;
+                               for (i = UI_BITMAP ; i <= UI_HISTORY_END ; i++)
+                                       _drbd_uuid_set(mdev, i, mdev->p_uuid[i]);
+                               drbd_uuid_set(mdev, UI_BITMAP, mdev->ldev->md.uuid[UI_CURRENT]);
+                               _drbd_uuid_set(mdev, UI_CURRENT, mdev->p_uuid[UI_CURRENT]);
+                       } else {
+                               dev_err(DEV, "mdev->p_uuid is NULL! BUG\n");
+                       }
+               }
+
+               drbd_uuid_set_bm(mdev, 0UL);
+
+               if (mdev->p_uuid) {
+                       /* Now the two UUID sets are equal, update what we
+                        * know of the peer. */
+                       int i;
+                       for (i = UI_CURRENT ; i <= UI_HISTORY_END ; i++)
+                               mdev->p_uuid[i] = mdev->ldev->md.uuid[i];
+               }
+       }
+
+       _drbd_set_state(mdev, ns, CS_VERBOSE, NULL);
+out_unlock:
+       spin_unlock_irq(&mdev->req_lock);
+       put_ldev(mdev);
+out:
+       mdev->rs_total  = 0;
+       mdev->rs_failed = 0;
+       mdev->rs_paused = 0;
+       mdev->ov_start_sector = 0;
+
+       if (test_and_clear_bit(WRITE_BM_AFTER_RESYNC, &mdev->flags)) {
+               dev_warn(DEV, "Writing the whole bitmap, due to failed kmalloc\n");
+               drbd_queue_bitmap_io(mdev, &drbd_bm_write, NULL, "write from resync_finished");
+       }
+
+       if (khelper_cmd)
+               drbd_khelper(mdev, khelper_cmd);
+
+       return 1;
+}
+
+/* helper */
+static void move_to_net_ee_or_free(struct drbd_conf *mdev, struct drbd_epoch_entry *e)
+{
+       if (drbd_bio_has_active_page(e->private_bio)) {
+               /* This might happen if sendpage() has not finished */
+               spin_lock_irq(&mdev->req_lock);
+               list_add_tail(&e->w.list, &mdev->net_ee);
+               spin_unlock_irq(&mdev->req_lock);
+       } else
+               drbd_free_ee(mdev, e);
+}
+
+/**
+ * w_e_end_data_req() - Worker callback, to send a P_DATA_REPLY packet in response to a P_DATA_REQUEST
+ * @mdev:      DRBD device.
+ * @w:         work object.
+ * @cancel:    The connection will be closed anyways
+ */
+int w_e_end_data_req(struct drbd_conf *mdev, struct drbd_work *w, int cancel)
+{
+       struct drbd_epoch_entry *e = container_of(w, struct drbd_epoch_entry, w);
+       int ok;
+
+       if (unlikely(cancel)) {
+               drbd_free_ee(mdev, e);
+               dec_unacked(mdev);
+               return 1;
+       }
+
+       if (likely(drbd_bio_uptodate(e->private_bio))) {
+               ok = drbd_send_block(mdev, P_DATA_REPLY, e);
+       } else {
+               if (__ratelimit(&drbd_ratelimit_state))
+                       dev_err(DEV, "Sending NegDReply. sector=%llus.\n",
+                           (unsigned long long)e->sector);
+
+               ok = drbd_send_ack(mdev, P_NEG_DREPLY, e);
+       }
+
+       dec_unacked(mdev);
+
+       move_to_net_ee_or_free(mdev, e);
+
+       if (unlikely(!ok))
+               dev_err(DEV, "drbd_send_block() failed\n");
+       return ok;
+}
+
+/**
+ * w_e_end_rsdata_req() - Worker callback to send a P_RS_DATA_REPLY packet in response to a P_RS_DATA_REQUESTRS
+ * @mdev:      DRBD device.
+ * @w:         work object.
+ * @cancel:    The connection will be closed anyways
+ */
+int w_e_end_rsdata_req(struct drbd_conf *mdev, struct drbd_work *w, int cancel)
+{
+       struct drbd_epoch_entry *e = container_of(w, struct drbd_epoch_entry, w);
+       int ok;
+
+       if (unlikely(cancel)) {
+               drbd_free_ee(mdev, e);
+               dec_unacked(mdev);
+               return 1;
+       }
+
+       if (get_ldev_if_state(mdev, D_FAILED)) {
+               drbd_rs_complete_io(mdev, e->sector);
+               put_ldev(mdev);
+       }
+
+       if (likely(drbd_bio_uptodate(e->private_bio))) {
+               if (likely(mdev->state.pdsk >= D_INCONSISTENT)) {
+                       inc_rs_pending(mdev);
+                       ok = drbd_send_block(mdev, P_RS_DATA_REPLY, e);
+               } else {
+                       if (__ratelimit(&drbd_ratelimit_state))
+                               dev_err(DEV, "Not sending RSDataReply, "
+                                   "partner DISKLESS!\n");
+                       ok = 1;
+               }
+       } else {
+               if (__ratelimit(&drbd_ratelimit_state))
+                       dev_err(DEV, "Sending NegRSDReply. sector %llus.\n",
+                           (unsigned long long)e->sector);
+
+               ok = drbd_send_ack(mdev, P_NEG_RS_DREPLY, e);
+
+               /* update resync data with failure */
+               drbd_rs_failed_io(mdev, e->sector, e->size);
+       }
+
+       dec_unacked(mdev);
+
+       move_to_net_ee_or_free(mdev, e);
+
+       if (unlikely(!ok))
+               dev_err(DEV, "drbd_send_block() failed\n");
+       return ok;
+}
+
+int w_e_end_csum_rs_req(struct drbd_conf *mdev, struct drbd_work *w, int cancel)
+{
+       struct drbd_epoch_entry *e = container_of(w, struct drbd_epoch_entry, w);
+       struct digest_info *di;
+       int digest_size;
+       void *digest = NULL;
+       int ok, eq = 0;
+
+       if (unlikely(cancel)) {
+               drbd_free_ee(mdev, e);
+               dec_unacked(mdev);
+               return 1;
+       }
+
+       drbd_rs_complete_io(mdev, e->sector);
+
+       di = (struct digest_info *)(unsigned long)e->block_id;
+
+       if (likely(drbd_bio_uptodate(e->private_bio))) {
+               /* quick hack to try to avoid a race against reconfiguration.
+                * a real fix would be much more involved,
+                * introducing more locking mechanisms */
+               if (mdev->csums_tfm) {
+                       digest_size = crypto_hash_digestsize(mdev->csums_tfm);
+                       D_ASSERT(digest_size == di->digest_size);
+                       digest = kmalloc(digest_size, GFP_NOIO);
+               }
+               if (digest) {
+                       drbd_csum(mdev, mdev->csums_tfm, e->private_bio, digest);
+                       eq = !memcmp(digest, di->digest, digest_size);
+                       kfree(digest);
+               }
+
+               if (eq) {
+                       drbd_set_in_sync(mdev, e->sector, e->size);
+                       mdev->rs_same_csum++;
+                       ok = drbd_send_ack(mdev, P_RS_IS_IN_SYNC, e);
+               } else {
+                       inc_rs_pending(mdev);
+                       e->block_id = ID_SYNCER;
+                       ok = drbd_send_block(mdev, P_RS_DATA_REPLY, e);
+               }
+       } else {
+               ok = drbd_send_ack(mdev, P_NEG_RS_DREPLY, e);
+               if (__ratelimit(&drbd_ratelimit_state))
+                       dev_err(DEV, "Sending NegDReply. I guess it gets messy.\n");
+       }
+
+       dec_unacked(mdev);
+
+       kfree(di);
+
+       move_to_net_ee_or_free(mdev, e);
+
+       if (unlikely(!ok))
+               dev_err(DEV, "drbd_send_block/ack() failed\n");
+       return ok;
+}
+
+int w_e_end_ov_req(struct drbd_conf *mdev, struct drbd_work *w, int cancel)
+{
+       struct drbd_epoch_entry *e = container_of(w, struct drbd_epoch_entry, w);
+       int digest_size;
+       void *digest;
+       int ok = 1;
+
+       if (unlikely(cancel))
+               goto out;
+
+       if (unlikely(!drbd_bio_uptodate(e->private_bio)))
+               goto out;
+
+       digest_size = crypto_hash_digestsize(mdev->verify_tfm);
+       /* FIXME if this allocation fails, online verify will not terminate! */
+       digest = kmalloc(digest_size, GFP_NOIO);
+       if (digest) {
+               drbd_csum(mdev, mdev->verify_tfm, e->private_bio, digest);
+               inc_rs_pending(mdev);
+               ok = drbd_send_drequest_csum(mdev, e->sector, e->size,
+                                            digest, digest_size, P_OV_REPLY);
+               if (!ok)
+                       dec_rs_pending(mdev);
+               kfree(digest);
+       }
+
+out:
+       drbd_free_ee(mdev, e);
+
+       dec_unacked(mdev);
+
+       return ok;
+}
+
+void drbd_ov_oos_found(struct drbd_conf *mdev, sector_t sector, int size)
+{
+       if (mdev->ov_last_oos_start + mdev->ov_last_oos_size == sector) {
+               mdev->ov_last_oos_size += size>>9;
+       } else {
+               mdev->ov_last_oos_start = sector;
+               mdev->ov_last_oos_size = size>>9;
+       }
+       drbd_set_out_of_sync(mdev, sector, size);
+       set_bit(WRITE_BM_AFTER_RESYNC, &mdev->flags);
+}
+
+int w_e_end_ov_reply(struct drbd_conf *mdev, struct drbd_work *w, int cancel)
+{
+       struct drbd_epoch_entry *e = container_of(w, struct drbd_epoch_entry, w);
+       struct digest_info *di;
+       int digest_size;
+       void *digest;
+       int ok, eq = 0;
+
+       if (unlikely(cancel)) {
+               drbd_free_ee(mdev, e);
+               dec_unacked(mdev);
+               return 1;
+       }
+
+       /* after "cancel", because after drbd_disconnect/drbd_rs_cancel_all
+        * the resync lru has been cleaned up already */
+       drbd_rs_complete_io(mdev, e->sector);
+
+       di = (struct digest_info *)(unsigned long)e->block_id;
+
+       if (likely(drbd_bio_uptodate(e->private_bio))) {
+               digest_size = crypto_hash_digestsize(mdev->verify_tfm);
+               digest = kmalloc(digest_size, GFP_NOIO);
+               if (digest) {
+                       drbd_csum(mdev, mdev->verify_tfm, e->private_bio, digest);
+
+                       D_ASSERT(digest_size == di->digest_size);
+                       eq = !memcmp(digest, di->digest, digest_size);
+                       kfree(digest);
+               }
+       } else {
+               ok = drbd_send_ack(mdev, P_NEG_RS_DREPLY, e);
+               if (__ratelimit(&drbd_ratelimit_state))
+                       dev_err(DEV, "Sending NegDReply. I guess it gets messy.\n");
+       }
+
+       dec_unacked(mdev);
+
+       kfree(di);
+
+       if (!eq)
+               drbd_ov_oos_found(mdev, e->sector, e->size);
+       else
+               ov_oos_print(mdev);
+
+       ok = drbd_send_ack_ex(mdev, P_OV_RESULT, e->sector, e->size,
+                             eq ? ID_IN_SYNC : ID_OUT_OF_SYNC);
+
+       drbd_free_ee(mdev, e);
+
+       if (--mdev->ov_left == 0) {
+               ov_oos_print(mdev);
+               drbd_resync_finished(mdev);
+       }
+
+       return ok;
+}
+
+int w_prev_work_done(struct drbd_conf *mdev, struct drbd_work *w, int cancel)
+{
+       struct drbd_wq_barrier *b = container_of(w, struct drbd_wq_barrier, w);
+       complete(&b->done);
+       return 1;
+}
+
+int w_send_barrier(struct drbd_conf *mdev, struct drbd_work *w, int cancel)
+{
+       struct drbd_tl_epoch *b = container_of(w, struct drbd_tl_epoch, w);
+       struct p_barrier *p = &mdev->data.sbuf.barrier;
+       int ok = 1;
+
+       /* really avoid racing with tl_clear.  w.cb may have been referenced
+        * just before it was reassigned and re-queued, so double check that.
+        * actually, this race was harmless, since we only try to send the
+        * barrier packet here, and otherwise do nothing with the object.
+        * but compare with the head of w_clear_epoch */
+       spin_lock_irq(&mdev->req_lock);
+       if (w->cb != w_send_barrier || mdev->state.conn < C_CONNECTED)
+               cancel = 1;
+       spin_unlock_irq(&mdev->req_lock);
+       if (cancel)
+               return 1;
+
+       if (!drbd_get_data_sock(mdev))
+               return 0;
+       p->barrier = b->br_number;
+       /* inc_ap_pending was done where this was queued.
+        * dec_ap_pending will be done in got_BarrierAck
+        * or (on connection loss) in w_clear_epoch.  */
+       ok = _drbd_send_cmd(mdev, mdev->data.socket, P_BARRIER,
+                               (struct p_header *)p, sizeof(*p), 0);
+       drbd_put_data_sock(mdev);
+
+       return ok;
+}
+
+int w_send_write_hint(struct drbd_conf *mdev, struct drbd_work *w, int cancel)
+{
+       if (cancel)
+               return 1;
+       return drbd_send_short_cmd(mdev, P_UNPLUG_REMOTE);
+}
+
+/**
+ * w_send_dblock() - Worker callback to send a P_DATA packet in order to mirror a write request
+ * @mdev:      DRBD device.
+ * @w:         work object.
+ * @cancel:    The connection will be closed anyways
+ */
+int w_send_dblock(struct drbd_conf *mdev, struct drbd_work *w, int cancel)
+{
+       struct drbd_request *req = container_of(w, struct drbd_request, w);
+       int ok;
+
+       if (unlikely(cancel)) {
+               req_mod(req, send_canceled);
+               return 1;
+       }
+
+       ok = drbd_send_dblock(mdev, req);
+       req_mod(req, ok ? handed_over_to_network : send_failed);
+
+       return ok;
+}
+
+/**
+ * w_send_read_req() - Worker callback to send a read request (P_DATA_REQUEST) packet
+ * @mdev:      DRBD device.
+ * @w:         work object.
+ * @cancel:    The connection will be closed anyways
+ */
+int w_send_read_req(struct drbd_conf *mdev, struct drbd_work *w, int cancel)
+{
+       struct drbd_request *req = container_of(w, struct drbd_request, w);
+       int ok;
+
+       if (unlikely(cancel)) {
+               req_mod(req, send_canceled);
+               return 1;
+       }
+
+       ok = drbd_send_drequest(mdev, P_DATA_REQUEST, req->sector, req->size,
+                               (unsigned long)req);
+
+       if (!ok) {
+               /* ?? we set C_TIMEOUT or C_BROKEN_PIPE in drbd_send();
+                * so this is probably redundant */
+               if (mdev->state.conn >= C_CONNECTED)
+                       drbd_force_state(mdev, NS(conn, C_NETWORK_FAILURE));
+       }
+       req_mod(req, ok ? handed_over_to_network : send_failed);
+
+       return ok;
+}
+
+static int _drbd_may_sync_now(struct drbd_conf *mdev)
+{
+       struct drbd_conf *odev = mdev;
+
+       while (1) {
+               if (odev->sync_conf.after == -1)
+                       return 1;
+               odev = minor_to_mdev(odev->sync_conf.after);
+               ERR_IF(!odev) return 1;
+               if ((odev->state.conn >= C_SYNC_SOURCE &&
+                    odev->state.conn <= C_PAUSED_SYNC_T) ||
+                   odev->state.aftr_isp || odev->state.peer_isp ||
+                   odev->state.user_isp)
+                       return 0;
+       }
+}
+
+/**
+ * _drbd_pause_after() - Pause resync on all devices that may not resync now
+ * @mdev:      DRBD device.
+ *
+ * Called from process context only (admin command and after_state_ch).
+ */
+static int _drbd_pause_after(struct drbd_conf *mdev)
+{
+       struct drbd_conf *odev;
+       int i, rv = 0;
+
+       for (i = 0; i < minor_count; i++) {
+               odev = minor_to_mdev(i);
+               if (!odev)
+                       continue;
+               if (odev->state.conn == C_STANDALONE && odev->state.disk == D_DISKLESS)
+                       continue;
+               if (!_drbd_may_sync_now(odev))
+                       rv |= (__drbd_set_state(_NS(odev, aftr_isp, 1), CS_HARD, NULL)
+                              != SS_NOTHING_TO_DO);
+       }
+
+       return rv;
+}
+
+/**
+ * _drbd_resume_next() - Resume resync on all devices that may resync now
+ * @mdev:      DRBD device.
+ *
+ * Called from process context only (admin command and worker).
+ */
+static int _drbd_resume_next(struct drbd_conf *mdev)
+{
+       struct drbd_conf *odev;
+       int i, rv = 0;
+
+       for (i = 0; i < minor_count; i++) {
+               odev = minor_to_mdev(i);
+               if (!odev)
+                       continue;
+               if (odev->state.conn == C_STANDALONE && odev->state.disk == D_DISKLESS)
+                       continue;
+               if (odev->state.aftr_isp) {
+                       if (_drbd_may_sync_now(odev))
+                               rv |= (__drbd_set_state(_NS(odev, aftr_isp, 0),
+                                                       CS_HARD, NULL)
+                                      != SS_NOTHING_TO_DO) ;
+               }
+       }
+       return rv;
+}
+
+void resume_next_sg(struct drbd_conf *mdev)
+{
+       write_lock_irq(&global_state_lock);
+       _drbd_resume_next(mdev);
+       write_unlock_irq(&global_state_lock);
+}
+
+void suspend_other_sg(struct drbd_conf *mdev)
+{
+       write_lock_irq(&global_state_lock);
+       _drbd_pause_after(mdev);
+       write_unlock_irq(&global_state_lock);
+}
+
+static int sync_after_error(struct drbd_conf *mdev, int o_minor)
+{
+       struct drbd_conf *odev;
+
+       if (o_minor == -1)
+               return NO_ERROR;
+       if (o_minor < -1 || minor_to_mdev(o_minor) == NULL)
+               return ERR_SYNC_AFTER;
+
+       /* check for loops */
+       odev = minor_to_mdev(o_minor);
+       while (1) {
+               if (odev == mdev)
+                       return ERR_SYNC_AFTER_CYCLE;
+
+               /* dependency chain ends here, no cycles. */
+               if (odev->sync_conf.after == -1)
+                       return NO_ERROR;
+
+               /* follow the dependency chain */
+               odev = minor_to_mdev(odev->sync_conf.after);
+       }
+}
+
+int drbd_alter_sa(struct drbd_conf *mdev, int na)
+{
+       int changes;
+       int retcode;
+
+       write_lock_irq(&global_state_lock);
+       retcode = sync_after_error(mdev, na);
+       if (retcode == NO_ERROR) {
+               mdev->sync_conf.after = na;
+               do {
+                       changes  = _drbd_pause_after(mdev);
+                       changes |= _drbd_resume_next(mdev);
+               } while (changes);
+       }
+       write_unlock_irq(&global_state_lock);
+       return retcode;
+}
+
+/**
+ * drbd_start_resync() - Start the resync process
+ * @mdev:      DRBD device.
+ * @side:      Either C_SYNC_SOURCE or C_SYNC_TARGET
+ *
+ * This function might bring you directly into one of the
+ * C_PAUSED_SYNC_* states.
+ */
+void drbd_start_resync(struct drbd_conf *mdev, enum drbd_conns side)
+{
+       union drbd_state ns;
+       int r;
+
+       if (mdev->state.conn >= C_SYNC_SOURCE) {
+               dev_err(DEV, "Resync already running!\n");
+               return;
+       }
+
+       /* In case a previous resync run was aborted by an IO error/detach on the peer. */
+       drbd_rs_cancel_all(mdev);
+
+       if (side == C_SYNC_TARGET) {
+               /* Since application IO was locked out during C_WF_BITMAP_T and
+                  C_WF_SYNC_UUID we are still unmodified. Before going to C_SYNC_TARGET
+                  we check that we might make the data inconsistent. */
+               r = drbd_khelper(mdev, "before-resync-target");
+               r = (r >> 8) & 0xff;
+               if (r > 0) {
+                       dev_info(DEV, "before-resync-target handler returned %d, "
+                            "dropping connection.\n", r);
+                       drbd_force_state(mdev, NS(conn, C_DISCONNECTING));
+                       return;
+               }
+       }
+
+       drbd_state_lock(mdev);
+
+       if (!get_ldev_if_state(mdev, D_NEGOTIATING)) {
+               drbd_state_unlock(mdev);
+               return;
+       }
+
+       if (side == C_SYNC_TARGET) {
+               mdev->bm_resync_fo = 0;
+       } else /* side == C_SYNC_SOURCE */ {
+               u64 uuid;
+
+               get_random_bytes(&uuid, sizeof(u64));
+               drbd_uuid_set(mdev, UI_BITMAP, uuid);
+               drbd_send_sync_uuid(mdev, uuid);
+
+               D_ASSERT(mdev->state.disk == D_UP_TO_DATE);
+       }
+
+       write_lock_irq(&global_state_lock);
+       ns = mdev->state;
+
+       ns.aftr_isp = !_drbd_may_sync_now(mdev);
+
+       ns.conn = side;
+
+       if (side == C_SYNC_TARGET)
+               ns.disk = D_INCONSISTENT;
+       else /* side == C_SYNC_SOURCE */
+               ns.pdsk = D_INCONSISTENT;
+
+       r = __drbd_set_state(mdev, ns, CS_VERBOSE, NULL);
+       ns = mdev->state;
+
+       if (ns.conn < C_CONNECTED)
+               r = SS_UNKNOWN_ERROR;
+
+       if (r == SS_SUCCESS) {
+               mdev->rs_total     =
+               mdev->rs_mark_left = drbd_bm_total_weight(mdev);
+               mdev->rs_failed    = 0;
+               mdev->rs_paused    = 0;
+               mdev->rs_start     =
+               mdev->rs_mark_time = jiffies;
+               mdev->rs_same_csum = 0;
+               _drbd_pause_after(mdev);
+       }
+       write_unlock_irq(&global_state_lock);
+       drbd_state_unlock(mdev);
+       put_ldev(mdev);
+
+       if (r == SS_SUCCESS) {
+               dev_info(DEV, "Began resync as %s (will sync %lu KB [%lu bits set]).\n",
+                    drbd_conn_str(ns.conn),
+                    (unsigned long) mdev->rs_total << (BM_BLOCK_SHIFT-10),
+                    (unsigned long) mdev->rs_total);
+
+               if (mdev->rs_total == 0) {
+                       /* Peer still reachable? Beware of failing before-resync-target handlers! */
+                       request_ping(mdev);
+                       __set_current_state(TASK_INTERRUPTIBLE);
+                       schedule_timeout(mdev->net_conf->ping_timeo*HZ/9); /* 9 instead 10 */
+                       drbd_resync_finished(mdev);
+                       return;
+               }
+
+               /* ns.conn may already be != mdev->state.conn,
+                * we may have been paused in between, or become paused until
+                * the timer triggers.
+                * No matter, that is handled in resync_timer_fn() */
+               if (ns.conn == C_SYNC_TARGET)
+                       mod_timer(&mdev->resync_timer, jiffies);
+
+               drbd_md_sync(mdev);
+       }
+}
+
+int drbd_worker(struct drbd_thread *thi)
+{
+       struct drbd_conf *mdev = thi->mdev;
+       struct drbd_work *w = NULL;
+       LIST_HEAD(work_list);
+       int intr = 0, i;
+
+       sprintf(current->comm, "drbd%d_worker", mdev_to_minor(mdev));
+
+       while (get_t_state(thi) == Running) {
+               drbd_thread_current_set_cpu(mdev);
+
+               if (down_trylock(&mdev->data.work.s)) {
+                       mutex_lock(&mdev->data.mutex);
+                       if (mdev->data.socket && !mdev->net_conf->no_cork)
+                               drbd_tcp_uncork(mdev->data.socket);
+                       mutex_unlock(&mdev->data.mutex);
+
+                       intr = down_interruptible(&mdev->data.work.s);
+
+                       mutex_lock(&mdev->data.mutex);
+                       if (mdev->data.socket  && !mdev->net_conf->no_cork)
+                               drbd_tcp_cork(mdev->data.socket);
+                       mutex_unlock(&mdev->data.mutex);
+               }
+
+               if (intr) {
+                       D_ASSERT(intr == -EINTR);
+                       flush_signals(current);
+                       ERR_IF (get_t_state(thi) == Running)
+                               continue;
+                       break;
+               }
+
+               if (get_t_state(thi) != Running)
+                       break;
+               /* With this break, we have done a down() but not consumed
+                  the entry from the list. The cleanup code takes care of
+                  this...   */
+
+               w = NULL;
+               spin_lock_irq(&mdev->data.work.q_lock);
+               ERR_IF(list_empty(&mdev->data.work.q)) {
+                       /* something terribly wrong in our logic.
+                        * we were able to down() the semaphore,
+                        * but the list is empty... doh.
+                        *
+                        * what is the best thing to do now?
+                        * try again from scratch, restarting the receiver,
+                        * asender, whatnot? could break even more ugly,
+                        * e.g. when we are primary, but no good local data.
+                        *
+                        * I'll try to get away just starting over this loop.
+                        */
+                       spin_unlock_irq(&mdev->data.work.q_lock);
+                       continue;
+               }
+               w = list_entry(mdev->data.work.q.next, struct drbd_work, list);
+               list_del_init(&w->list);
+               spin_unlock_irq(&mdev->data.work.q_lock);
+
+               if (!w->cb(mdev, w, mdev->state.conn < C_CONNECTED)) {
+                       /* dev_warn(DEV, "worker: a callback failed! \n"); */
+                       if (mdev->state.conn >= C_CONNECTED)
+                               drbd_force_state(mdev,
+                                               NS(conn, C_NETWORK_FAILURE));
+               }
+       }
+       D_ASSERT(test_bit(DEVICE_DYING, &mdev->flags));
+       D_ASSERT(test_bit(CONFIG_PENDING, &mdev->flags));
+
+       spin_lock_irq(&mdev->data.work.q_lock);
+       i = 0;
+       while (!list_empty(&mdev->data.work.q)) {
+               list_splice_init(&mdev->data.work.q, &work_list);
+               spin_unlock_irq(&mdev->data.work.q_lock);
+
+               while (!list_empty(&work_list)) {
+                       w = list_entry(work_list.next, struct drbd_work, list);
+                       list_del_init(&w->list);
+                       w->cb(mdev, w, 1);
+                       i++; /* dead debugging code */
+               }
+
+               spin_lock_irq(&mdev->data.work.q_lock);
+       }
+       sema_init(&mdev->data.work.s, 0);
+       /* DANGEROUS race: if someone did queue his work within the spinlock,
+        * but up() ed outside the spinlock, we could get an up() on the
+        * semaphore without corresponding list entry.
+        * So don't do that.
+        */
+       spin_unlock_irq(&mdev->data.work.q_lock);
+
+       D_ASSERT(mdev->state.disk == D_DISKLESS && mdev->state.conn == C_STANDALONE);
+       /* _drbd_set_state only uses stop_nowait.
+        * wait here for the Exiting receiver. */
+       drbd_thread_stop(&mdev->receiver);
+       drbd_mdev_cleanup(mdev);
+
+       dev_info(DEV, "worker terminated\n");
+
+       clear_bit(DEVICE_DYING, &mdev->flags);
+       clear_bit(CONFIG_PENDING, &mdev->flags);
+       wake_up(&mdev->state_wait);
+
+       return 0;
+}
diff --git a/drivers/block/drbd/drbd_wrappers.h b/drivers/block/drbd/drbd_wrappers.h
new file mode 100644 (file)
index 0000000..f93fa11
--- /dev/null
@@ -0,0 +1,91 @@
+#ifndef _DRBD_WRAPPERS_H
+#define _DRBD_WRAPPERS_H
+
+#include <linux/ctype.h>
+#include <linux/mm.h>
+
+/* see get_sb_bdev and bd_claim */
+extern char *drbd_sec_holder;
+
+/* sets the number of 512 byte sectors of our virtual device */
+static inline void drbd_set_my_capacity(struct drbd_conf *mdev,
+                                       sector_t size)
+{
+       /* set_capacity(mdev->this_bdev->bd_disk, size); */
+       set_capacity(mdev->vdisk, size);
+       mdev->this_bdev->bd_inode->i_size = (loff_t)size << 9;
+}
+
+#define drbd_bio_uptodate(bio) bio_flagged(bio, BIO_UPTODATE)
+
+static inline int drbd_bio_has_active_page(struct bio *bio)
+{
+       struct bio_vec *bvec;
+       int i;
+
+       __bio_for_each_segment(bvec, bio, i, 0) {
+               if (page_count(bvec->bv_page) > 1)
+                       return 1;
+       }
+
+       return 0;
+}
+
+/* bi_end_io handlers */
+extern void drbd_md_io_complete(struct bio *bio, int error);
+extern void drbd_endio_read_sec(struct bio *bio, int error);
+extern void drbd_endio_write_sec(struct bio *bio, int error);
+extern void drbd_endio_pri(struct bio *bio, int error);
+
+/*
+ * used to submit our private bio
+ */
+static inline void drbd_generic_make_request(struct drbd_conf *mdev,
+                                            int fault_type, struct bio *bio)
+{
+       __release(local);
+       if (!bio->bi_bdev) {
+               printk(KERN_ERR "drbd%d: drbd_generic_make_request: "
+                               "bio->bi_bdev == NULL\n",
+                      mdev_to_minor(mdev));
+               dump_stack();
+               bio_endio(bio, -ENODEV);
+               return;
+       }
+
+       if (FAULT_ACTIVE(mdev, fault_type))
+               bio_endio(bio, -EIO);
+       else
+               generic_make_request(bio);
+}
+
+static inline void drbd_plug_device(struct drbd_conf *mdev)
+{
+       struct request_queue *q;
+       q = bdev_get_queue(mdev->this_bdev);
+
+       spin_lock_irq(q->queue_lock);
+
+/* XXX the check on !blk_queue_plugged is redundant,
+ * implicitly checked in blk_plug_device */
+
+       if (!blk_queue_plugged(q)) {
+               blk_plug_device(q);
+               del_timer(&q->unplug_timer);
+               /* unplugging should not happen automatically... */
+       }
+       spin_unlock_irq(q->queue_lock);
+}
+
+static inline int drbd_crypto_is_hash(struct crypto_tfm *tfm)
+{
+        return (crypto_tfm_alg_type(tfm) & CRYPTO_ALG_TYPE_HASH_MASK)
+                == CRYPTO_ALG_TYPE_HASH;
+}
+
+#ifndef __CHECKER__
+# undef __cond_lock
+# define __cond_lock(x,c) (c)
+#endif
+
+#endif
index 3bb7c47..1fb6c31 100644 (file)
@@ -123,7 +123,15 @@ static int ps3vram_notifier_wait(struct ps3_system_bus_device *dev,
 {
        struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev);
        u32 *notify = ps3vram_get_notifier(priv->reports, NOTIFIER);
-       unsigned long timeout = jiffies + msecs_to_jiffies(timeout_ms);
+       unsigned long timeout;
+
+       for (timeout = 20; timeout; timeout--) {
+               if (!notify[3])
+                       return 0;
+               udelay(10);
+       }
+
+       timeout = jiffies + msecs_to_jiffies(timeout_ms);
 
        do {
                if (!notify[3])
index 614da5b..e3749d0 100644 (file)
@@ -3557,67 +3557,65 @@ static ctl_table cdrom_table[] = {
                .data           = &cdrom_sysctl_settings.info, 
                .maxlen         = CDROM_STR_SIZE,
                .mode           = 0444,
-               .proc_handler   = &cdrom_sysctl_info,
+               .proc_handler   = cdrom_sysctl_info,
        },
        {
                .procname       = "autoclose",
                .data           = &cdrom_sysctl_settings.autoclose,
                .maxlen         = sizeof(int),
                .mode           = 0644,
-               .proc_handler   = &cdrom_sysctl_handler,
+               .proc_handler   = cdrom_sysctl_handler,
        },
        {
                .procname       = "autoeject",
                .data           = &cdrom_sysctl_settings.autoeject,
                .maxlen         = sizeof(int),
                .mode           = 0644,
-               .proc_handler   = &cdrom_sysctl_handler,
+               .proc_handler   = cdrom_sysctl_handler,
        },
        {
                .procname       = "debug",
                .data           = &cdrom_sysctl_settings.debug,
                .maxlen         = sizeof(int),
                .mode           = 0644,
-               .proc_handler   = &cdrom_sysctl_handler,
+               .proc_handler   = cdrom_sysctl_handler,
        },
        {
                .procname       = "lock",
                .data           = &cdrom_sysctl_settings.lock,
                .maxlen         = sizeof(int),
                .mode           = 0644,
-               .proc_handler   = &cdrom_sysctl_handler,
+               .proc_handler   = cdrom_sysctl_handler,
        },
        {
                .procname       = "check_media",
                .data           = &cdrom_sysctl_settings.check,
                .maxlen         = sizeof(int),
                .mode           = 0644,
-               .proc_handler   = &cdrom_sysctl_handler
+               .proc_handler   = cdrom_sysctl_handler
        },
-       { .ctl_name = 0 }
+       { }
 };
 
 static ctl_table cdrom_cdrom_table[] = {
        {
-               .ctl_name       = DEV_CDROM,
                .procname       = "cdrom",
                .maxlen         = 0,
                .mode           = 0555,
                .child          = cdrom_table,
        },
-       { .ctl_name = 0 }
+       { }
 };
 
 /* Make sure that /proc/sys/dev is there */
 static ctl_table cdrom_root_table[] = {
        {
-               .ctl_name       = CTL_DEV,
                .procname       = "dev",
                .maxlen         = 0,
                .mode           = 0555,
                .child          = cdrom_cdrom_table,
        },
-       { .ctl_name = 0 }
+       { }
 };
 static struct ctl_table_header *cdrom_sysctl_header;
 
index 70a770a..e481c59 100644 (file)
@@ -675,36 +675,33 @@ static int hpet_is_known(struct hpet_data *hdp)
 
 static ctl_table hpet_table[] = {
        {
-        .ctl_name = CTL_UNNUMBERED,
         .procname = "max-user-freq",
         .data = &hpet_max_freq,
         .maxlen = sizeof(int),
         .mode = 0644,
-        .proc_handler = &proc_dointvec,
+        .proc_handler = proc_dointvec,
         },
-       {.ctl_name = 0}
+       {}
 };
 
 static ctl_table hpet_root[] = {
        {
-        .ctl_name = CTL_UNNUMBERED,
         .procname = "hpet",
         .maxlen = 0,
         .mode = 0555,
         .child = hpet_table,
         },
-       {.ctl_name = 0}
+       {}
 };
 
 static ctl_table dev_root[] = {
        {
-        .ctl_name = CTL_DEV,
         .procname = "dev",
         .maxlen = 0,
         .mode = 0555,
         .child = hpet_root,
         },
-       {.ctl_name = 0}
+       {}
 };
 
 static struct ctl_table_header *sysctl_header;
index 2e66b5f..0dec5da 100644 (file)
@@ -660,26 +660,23 @@ static struct ipmi_smi_watcher smi_watcher = {
 #include <linux/sysctl.h>
 
 static ctl_table ipmi_table[] = {
-       { .ctl_name     = DEV_IPMI_POWEROFF_POWERCYCLE,
-         .procname     = "poweroff_powercycle",
+       { .procname     = "poweroff_powercycle",
          .data         = &poweroff_powercycle,
          .maxlen       = sizeof(poweroff_powercycle),
          .mode         = 0644,
-         .proc_handler = &proc_dointvec },
+         .proc_handler = proc_dointvec },
        { }
 };
 
 static ctl_table ipmi_dir_table[] = {
-       { .ctl_name     = DEV_IPMI,
-         .procname     = "ipmi",
+       { .procname     = "ipmi",
          .mode         = 0555,
          .child        = ipmi_table },
        { }
 };
 
 static ctl_table ipmi_root_table[] = {
-       { .ctl_name     = CTL_DEV,
-         .procname     = "dev",
+       { .procname     = "dev",
          .mode         = 0555,
          .child        = ipmi_dir_table },
        { }
index 62f282e..d86c0bc 100644 (file)
@@ -431,30 +431,25 @@ static struct cdev ptmx_cdev;
 
 static struct ctl_table pty_table[] = {
        {
-               .ctl_name       = PTY_MAX,
                .procname       = "max",
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .data           = &pty_limit,
-               .proc_handler   = &proc_dointvec_minmax,
-               .strategy       = &sysctl_intvec,
+               .proc_handler   = proc_dointvec_minmax,
                .extra1         = &pty_limit_min,
                .extra2         = &pty_limit_max,
        }, {
-               .ctl_name       = PTY_NR,
                .procname       = "nr",
                .maxlen         = sizeof(int),
                .mode           = 0444,
                .data           = &pty_count,
-               .proc_handler   = &proc_dointvec,
-       }, {
-               .ctl_name       = 0
-       }
+               .proc_handler   = proc_dointvec,
+       }, 
+       {}
 };
 
 static struct ctl_table pty_kern_table[] = {
        {
-               .ctl_name       = KERN_PTY,
                .procname       = "pty",
                .mode           = 0555,
                .child          = pty_table,
@@ -464,7 +459,6 @@ static struct ctl_table pty_kern_table[] = {
 
 static struct ctl_table pty_root_table[] = {
        {
-               .ctl_name       = CTL_KERN,
                .procname       = "kernel",
                .mode           = 0555,
                .child          = pty_kern_table,
index 04b505e..dcd0863 100644 (file)
@@ -1257,94 +1257,54 @@ static int proc_do_uuid(ctl_table *table, int write,
        return proc_dostring(&fake_table, write, buffer, lenp, ppos);
 }
 
-static int uuid_strategy(ctl_table *table,
-                        void __user *oldval, size_t __user *oldlenp,
-                        void __user *newval, size_t newlen)
-{
-       unsigned char tmp_uuid[16], *uuid;
-       unsigned int len;
-
-       if (!oldval || !oldlenp)
-               return 1;
-
-       uuid = table->data;
-       if (!uuid) {
-               uuid = tmp_uuid;
-               uuid[8] = 0;
-       }
-       if (uuid[8] == 0)
-               generate_random_uuid(uuid);
-
-       if (get_user(len, oldlenp))
-               return -EFAULT;
-       if (len) {
-               if (len > 16)
-                       len = 16;
-               if (copy_to_user(oldval, uuid, len) ||
-                   put_user(len, oldlenp))
-                       return -EFAULT;
-       }
-       return 1;
-}
-
 static int sysctl_poolsize = INPUT_POOL_WORDS * 32;
 ctl_table random_table[] = {
        {
-               .ctl_name       = RANDOM_POOLSIZE,
                .procname       = "poolsize",
                .data           = &sysctl_poolsize,
                .maxlen         = sizeof(int),
                .mode           = 0444,
-               .proc_handler   = &proc_dointvec,
+               .proc_handler   = proc_dointvec,
        },
        {
-               .ctl_name       = RANDOM_ENTROPY_COUNT,
                .procname       = "entropy_avail",
                .maxlen         = sizeof(int),
                .mode           = 0444,
-               .proc_handler   = &proc_dointvec,
+               .proc_handler   = proc_dointvec,
                .data           = &input_pool.entropy_count,
        },
        {
-               .ctl_name       = RANDOM_READ_THRESH,
                .procname       = "read_wakeup_threshold",
                .data           = &random_read_wakeup_thresh,
                .maxlen         = sizeof(int),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec_minmax,
-               .strategy       = &sysctl_intvec,
+               .proc_handler   = proc_dointvec_minmax,
                .extra1         = &min_read_thresh,
                .extra2         = &max_read_thresh,
        },
        {
-               .ctl_name       = RANDOM_WRITE_THRESH,
                .procname       = "write_wakeup_threshold",
                .data           = &random_write_wakeup_thresh,
                .maxlen         = sizeof(int),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec_minmax,
-               .strategy       = &sysctl_intvec,
+               .proc_handler   = proc_dointvec_minmax,
                .extra1         = &min_write_thresh,
                .extra2         = &max_write_thresh,
        },
        {
-               .ctl_name       = RANDOM_BOOT_ID,
                .procname       = "boot_id",
                .data           = &sysctl_bootid,
                .maxlen         = 16,
                .mode           = 0444,
-               .proc_handler   = &proc_do_uuid,
-               .strategy       = &uuid_strategy,
+               .proc_handler   = proc_do_uuid,
        },
        {
-               .ctl_name       = RANDOM_UUID,
                .procname       = "uuid",
                .maxlen         = 16,
                .mode           = 0444,
-               .proc_handler   = &proc_do_uuid,
-               .strategy       = &uuid_strategy,
+               .proc_handler   = proc_do_uuid,
        },
-       { .ctl_name = 0 }
+       { }
 };
 #endif         /* CONFIG_SYSCTL */
 
index bc4ab3e..95acb8c 100644 (file)
@@ -282,34 +282,31 @@ static irqreturn_t rtc_interrupt(int irq, void *dev_id)
  */
 static ctl_table rtc_table[] = {
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "max-user-freq",
                .data           = &rtc_max_user_freq,
                .maxlen         = sizeof(int),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec,
+               .proc_handler   = proc_dointvec,
        },
-       { .ctl_name = 0 }
+       { }
 };
 
 static ctl_table rtc_root[] = {
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "rtc",
                .mode           = 0555,
                .child          = rtc_table,
        },
-       { .ctl_name = 0 }
+       { }
 };
 
 static ctl_table dev_root[] = {
        {
-               .ctl_name       = CTL_DEV,
                .procname       = "dev",
                .mode           = 0555,
                .child          = rtc_root,
        },
-       { .ctl_name = 0 }
+       { }
 };
 
 static struct ctl_table_header *sysctl_header;
index 9c0c9af..a7b174e 100644 (file)
@@ -140,5 +140,4 @@ postcore_initcall(dio_driver_init);
 EXPORT_SYMBOL(dio_match_device);
 EXPORT_SYMBOL(dio_register_driver);
 EXPORT_SYMBOL(dio_unregister_driver);
-EXPORT_SYMBOL(dio_dev_driver);
 EXPORT_SYMBOL(dio_bus_type);
index b401dad..eb140ff 100644 (file)
@@ -54,7 +54,7 @@ config DW_DMAC
 
 config AT_HDMAC
        tristate "Atmel AHB DMA support"
-       depends on ARCH_AT91SAM9RL
+       depends on ARCH_AT91SAM9RL || ARCH_AT91SAM9G45
        select DMA_ENGINE
        help
          Support the Atmel AHB DMA controller.  This can be integrated in
index 713ed7d..689cc6a 100644 (file)
@@ -3,7 +3,6 @@
 
 static bool report_gart_errors;
 static void (*nb_bus_decoder)(int node_id, struct err_regs *regs);
-static void (*orig_mce_callback)(struct mce *m);
 
 void amd_report_gart_errors(bool v)
 {
@@ -363,8 +362,10 @@ static inline void amd_decode_err_code(unsigned int ec)
                pr_warning("Huh? Unknown MCE error 0x%x\n", ec);
 }
 
-static void amd_decode_mce(struct mce *m)
+static int amd_decode_mce(struct notifier_block *nb, unsigned long val,
+                          void *data)
 {
+       struct mce *m = (struct mce *)data;
        struct err_regs regs;
        int node, ecc;
 
@@ -420,20 +421,22 @@ static void amd_decode_mce(struct mce *m)
        }
 
        amd_decode_err_code(m->status & 0xffff);
+
+       return NOTIFY_STOP;
 }
 
+static struct notifier_block amd_mce_dec_nb = {
+       .notifier_call  = amd_decode_mce,
+};
+
 static int __init mce_amd_init(void)
 {
        /*
         * We can decode MCEs for Opteron and later CPUs:
         */
        if ((boot_cpu_data.x86_vendor == X86_VENDOR_AMD) &&
-           (boot_cpu_data.x86 >= 0xf)) {
-               /* safe the default decode mce callback */
-               orig_mce_callback = x86_mce_decode_callback;
-
-               x86_mce_decode_callback = amd_decode_mce;
-       }
+           (boot_cpu_data.x86 >= 0xf))
+               atomic_notifier_chain_register(&x86_mce_decoder_chain, &amd_mce_dec_nb);
 
        return 0;
 }
@@ -442,7 +445,7 @@ early_initcall(mce_amd_init);
 #ifdef MODULE
 static void __exit mce_amd_exit(void)
 {
-       x86_mce_decode_callback = orig_mce_callback;
+       atomic_notifier_chain_unregister(&x86_mce_decoder_chain, &amd_mce_dec_nb);
 }
 
 MODULE_DESCRIPTION("AMD MCE decoder");
index e4864e8..7083bcc 100644 (file)
 
 #include "core.h"
 
-int fw_compute_block_crc(u32 *block)
+int fw_compute_block_crc(__be32 *block)
 {
-       __be32 be32_block[256];
-       int i, length;
+       int length;
+       u16 crc;
 
-       length = (*block >> 16) & 0xff;
-       for (i = 0; i < length; i++)
-               be32_block[i] = cpu_to_be32(block[i + 1]);
-       *block |= crc_itu_t(0, (u8 *) be32_block, length * 4);
+       length = (be32_to_cpu(block[0]) >> 16) & 0xff;
+       crc = crc_itu_t(0, (u8 *)&block[1], length * 4);
+       *block |= cpu_to_be32(crc);
 
        return length;
 }
@@ -57,6 +56,8 @@ static LIST_HEAD(card_list);
 static LIST_HEAD(descriptor_list);
 static int descriptor_count;
 
+static __be32 tmp_config_rom[256];
+
 #define BIB_CRC(v)             ((v) <<  0)
 #define BIB_CRC_LENGTH(v)      ((v) << 16)
 #define BIB_INFO_LENGTH(v)     ((v) << 24)
@@ -72,11 +73,10 @@ static int descriptor_count;
 #define BIB_CMC                        ((1) << 30)
 #define BIB_IMC                        ((1) << 31)
 
-static u32 *generate_config_rom(struct fw_card *card, size_t *config_rom_length)
+static size_t generate_config_rom(struct fw_card *card, __be32 *config_rom)
 {
        struct fw_descriptor *desc;
-       static u32 config_rom[256];
-       int i, j, length;
+       int i, j, k, length;
 
        /*
         * Initialize contents of config rom buffer.  On the OHCI
@@ -87,40 +87,39 @@ static u32 *generate_config_rom(struct fw_card *card, size_t *config_rom_length)
         * the version stored in the OHCI registers.
         */
 
-       memset(config_rom, 0, sizeof(config_rom));
-       config_rom[0] = BIB_CRC_LENGTH(4) | BIB_INFO_LENGTH(4) | BIB_CRC(0);
-       config_rom[1] = 0x31333934;
-
-       config_rom[2] =
+       config_rom[0] = cpu_to_be32(
+               BIB_CRC_LENGTH(4) | BIB_INFO_LENGTH(4) | BIB_CRC(0));
+       config_rom[1] = cpu_to_be32(0x31333934);
+       config_rom[2] = cpu_to_be32(
                BIB_LINK_SPEED(card->link_speed) |
                BIB_GENERATION(card->config_rom_generation++ % 14 + 2) |
                BIB_MAX_ROM(2) |
                BIB_MAX_RECEIVE(card->max_receive) |
-               BIB_BMC | BIB_ISC | BIB_CMC | BIB_IMC;
-       config_rom[3] = card->guid >> 32;
-       config_rom[4] = card->guid;
+               BIB_BMC | BIB_ISC | BIB_CMC | BIB_IMC);
+       config_rom[3] = cpu_to_be32(card->guid >> 32);
+       config_rom[4] = cpu_to_be32(card->guid);
 
        /* Generate root directory. */
-       i = 5;
-       config_rom[i++] = 0;
-       config_rom[i++] = 0x0c0083c0; /* node capabilities */
-       j = i + descriptor_count;
+       config_rom[6] = cpu_to_be32(0x0c0083c0); /* node capabilities */
+       i = 7;
+       j = 7 + descriptor_count;
 
        /* Generate root directory entries for descriptors. */
        list_for_each_entry (desc, &descriptor_list, link) {
                if (desc->immediate > 0)
-                       config_rom[i++] = desc->immediate;
-               config_rom[i] = desc->key | (j - i);
+                       config_rom[i++] = cpu_to_be32(desc->immediate);
+               config_rom[i] = cpu_to_be32(desc->key | (j - i));
                i++;
                j += desc->length;
        }
 
        /* Update root directory length. */
-       config_rom[5] = (i - 5 - 1) << 16;
+       config_rom[5] = cpu_to_be32((i - 5 - 1) << 16);
 
        /* End of root directory, now copy in descriptors. */
        list_for_each_entry (desc, &descriptor_list, link) {
-               memcpy(&config_rom[i], desc->data, desc->length * 4);
+               for (k = 0; k < desc->length; k++)
+                       config_rom[i + k] = cpu_to_be32(desc->data[k]);
                i += desc->length;
        }
 
@@ -131,20 +130,17 @@ static u32 *generate_config_rom(struct fw_card *card, size_t *config_rom_length)
        for (i = 0; i < j; i += length + 1)
                length = fw_compute_block_crc(config_rom + i);
 
-       *config_rom_length = j;
-
-       return config_rom;
+       return j;
 }
 
 static void update_config_roms(void)
 {
        struct fw_card *card;
-       u32 *config_rom;
        size_t length;
 
        list_for_each_entry (card, &card_list, link) {
-               config_rom = generate_config_rom(card, &length);
-               card->driver->set_config_rom(card, config_rom, length);
+               length = generate_config_rom(card, tmp_config_rom);
+               card->driver->set_config_rom(card, tmp_config_rom, length);
        }
 }
 
@@ -211,11 +207,8 @@ static const char gap_count_table[] = {
 
 void fw_schedule_bm_work(struct fw_card *card, unsigned long delay)
 {
-       int scheduled;
-
        fw_card_get(card);
-       scheduled = schedule_delayed_work(&card->work, delay);
-       if (!scheduled)
+       if (!schedule_delayed_work(&card->work, delay))
                fw_card_put(card);
 }
 
@@ -435,7 +428,6 @@ EXPORT_SYMBOL(fw_card_initialize);
 int fw_card_add(struct fw_card *card,
                u32 max_receive, u32 link_speed, u64 guid)
 {
-       u32 *config_rom;
        size_t length;
        int ret;
 
@@ -445,8 +437,8 @@ int fw_card_add(struct fw_card *card,
 
        mutex_lock(&card_mutex);
 
-       config_rom = generate_config_rom(card, &length);
-       ret = card->driver->enable(card, config_rom, length);
+       length = generate_config_rom(card, tmp_config_rom);
+       ret = card->driver->enable(card, tmp_config_rom, length);
        if (ret == 0)
                list_add_tail(&card->link, &card_list);
 
@@ -465,7 +457,8 @@ EXPORT_SYMBOL(fw_card_add);
  * shutdown still need to be provided by the card driver.
  */
 
-static int dummy_enable(struct fw_card *card, u32 *config_rom, size_t length)
+static int dummy_enable(struct fw_card *card,
+                       const __be32 *config_rom, size_t length)
 {
        BUG();
        return -1;
@@ -478,7 +471,7 @@ static int dummy_update_phy_reg(struct fw_card *card, int address,
 }
 
 static int dummy_set_config_rom(struct fw_card *card,
-                               u32 *config_rom, size_t length)
+                               const __be32 *config_rom, size_t length)
 {
        /*
         * We take the card out of card_list before setting the dummy
index 5089331..231e6ee 100644 (file)
@@ -130,9 +130,22 @@ struct iso_resource {
        struct iso_resource_event *e_alloc, *e_dealloc;
 };
 
-static void schedule_iso_resource(struct iso_resource *);
 static void release_iso_resource(struct client *, struct client_resource *);
 
+static void schedule_iso_resource(struct iso_resource *r, unsigned long delay)
+{
+       client_get(r->client);
+       if (!schedule_delayed_work(&r->work, delay))
+               client_put(r->client);
+}
+
+static void schedule_if_iso_resource(struct client_resource *resource)
+{
+       if (resource->release == release_iso_resource)
+               schedule_iso_resource(container_of(resource,
+                                       struct iso_resource, resource), 0);
+}
+
 /*
  * dequeue_event() just kfree()'s the event, so the event has to be
  * the first field in a struct XYZ_event.
@@ -166,7 +179,7 @@ struct iso_interrupt_event {
 
 struct iso_resource_event {
        struct event event;
-       struct fw_cdev_event_iso_resource resource;
+       struct fw_cdev_event_iso_resource iso_resource;
 };
 
 static inline void __user *u64_to_uptr(__u64 value)
@@ -314,11 +327,8 @@ static void for_each_client(struct fw_device *device,
 
 static int schedule_reallocations(int id, void *p, void *data)
 {
-       struct client_resource *r = p;
+       schedule_if_iso_resource(p);
 
-       if (r->release == release_iso_resource)
-               schedule_iso_resource(container_of(r,
-                                       struct iso_resource, resource));
        return 0;
 }
 
@@ -414,9 +424,7 @@ static int add_client_resource(struct client *client,
                                  &resource->handle);
        if (ret >= 0) {
                client_get(client);
-               if (resource->release == release_iso_resource)
-                       schedule_iso_resource(container_of(resource,
-                                               struct iso_resource, resource));
+               schedule_if_iso_resource(resource);
        }
        spin_unlock_irqrestore(&client->lock, flags);
 
@@ -428,26 +436,26 @@ static int add_client_resource(struct client *client,
 
 static int release_client_resource(struct client *client, u32 handle,
                                   client_resource_release_fn_t release,
-                                  struct client_resource **resource)
+                                  struct client_resource **return_resource)
 {
-       struct client_resource *r;
+       struct client_resource *resource;
 
        spin_lock_irq(&client->lock);
        if (client->in_shutdown)
-               r = NULL;
+               resource = NULL;
        else
-               r = idr_find(&client->resource_idr, handle);
-       if (r && r->release == release)
+               resource = idr_find(&client->resource_idr, handle);
+       if (resource && resource->release == release)
                idr_remove(&client->resource_idr, handle);
        spin_unlock_irq(&client->lock);
 
-       if (!(r && r->release == release))
+       if (!(resource && resource->release == release))
                return -EINVAL;
 
-       if (resource)
-               *resource = r;
+       if (return_resource)
+               *return_resource = resource;
        else
-               r->release(client, r);
+               resource->release(client, resource);
 
        client_put(client);
 
@@ -699,6 +707,7 @@ static int ioctl_send_response(struct client *client, void *buffer)
        struct fw_cdev_send_response *request = buffer;
        struct client_resource *resource;
        struct inbound_transaction_resource *r;
+       int ret = 0;
 
        if (release_client_resource(client, request->handle,
                                    release_request, &resource) < 0)
@@ -708,13 +717,17 @@ static int ioctl_send_response(struct client *client, void *buffer)
                         resource);
        if (request->length < r->length)
                r->length = request->length;
-       if (copy_from_user(r->data, u64_to_uptr(request->data), r->length))
-               return -EFAULT;
+
+       if (copy_from_user(r->data, u64_to_uptr(request->data), r->length)) {
+               ret = -EFAULT;
+               goto out;
+       }
 
        fw_send_response(client->device->card, r->request, request->rcode);
+ out:
        kfree(r);
 
-       return 0;
+       return ret;
 }
 
 static int ioctl_initiate_bus_reset(struct client *client, void *buffer)
@@ -1028,8 +1041,7 @@ static void iso_resource_work(struct work_struct *work)
        /* Allow 1000ms grace period for other reallocations. */
        if (todo == ISO_RES_ALLOC &&
            time_is_after_jiffies(client->device->card->reset_jiffies + HZ)) {
-               if (schedule_delayed_work(&r->work, DIV_ROUND_UP(HZ, 3)))
-                       client_get(client);
+               schedule_iso_resource(r, DIV_ROUND_UP(HZ, 3));
                skip = true;
        } else {
                /* We could be called twice within the same generation. */
@@ -1097,12 +1109,12 @@ static void iso_resource_work(struct work_struct *work)
                e = r->e_dealloc;
                r->e_dealloc = NULL;
        }
-       e->resource.handle      = r->resource.handle;
-       e->resource.channel     = channel;
-       e->resource.bandwidth   = bandwidth;
+       e->iso_resource.handle    = r->resource.handle;
+       e->iso_resource.channel   = channel;
+       e->iso_resource.bandwidth = bandwidth;
 
        queue_event(client, &e->event,
-                   &e->resource, sizeof(e->resource), NULL, 0);
+                   &e->iso_resource, sizeof(e->iso_resource), NULL, 0);
 
        if (free) {
                cancel_delayed_work(&r->work);
@@ -1114,13 +1126,6 @@ static void iso_resource_work(struct work_struct *work)
        client_put(client);
 }
 
-static void schedule_iso_resource(struct iso_resource *r)
-{
-       client_get(r->client);
-       if (!schedule_delayed_work(&r->work, 0))
-               client_put(r->client);
-}
-
 static void release_iso_resource(struct client *client,
                                 struct client_resource *resource)
 {
@@ -1129,7 +1134,7 @@ static void release_iso_resource(struct client *client,
 
        spin_lock_irq(&client->lock);
        r->todo = ISO_RES_DEALLOC;
-       schedule_iso_resource(r);
+       schedule_iso_resource(r, 0);
        spin_unlock_irq(&client->lock);
 }
 
@@ -1162,10 +1167,10 @@ static int init_iso_resource(struct client *client,
        r->e_alloc      = e1;
        r->e_dealloc    = e2;
 
-       e1->resource.closure    = request->closure;
-       e1->resource.type       = FW_CDEV_EVENT_ISO_RESOURCE_ALLOCATED;
-       e2->resource.closure    = request->closure;
-       e2->resource.type       = FW_CDEV_EVENT_ISO_RESOURCE_DEALLOCATED;
+       e1->iso_resource.closure = request->closure;
+       e1->iso_resource.type    = FW_CDEV_EVENT_ISO_RESOURCE_ALLOCATED;
+       e2->iso_resource.closure = request->closure;
+       e2->iso_resource.type    = FW_CDEV_EVENT_ISO_RESOURCE_DEALLOCATED;
 
        if (todo == ISO_RES_ALLOC) {
                r->resource.release = release_iso_resource;
@@ -1175,7 +1180,7 @@ static int init_iso_resource(struct client *client,
        } else {
                r->resource.release = NULL;
                r->resource.handle = -1;
-               schedule_iso_resource(r);
+               schedule_iso_resource(r, 0);
        }
        request->handle = r->resource.handle;
 
@@ -1295,7 +1300,23 @@ static int (* const ioctl_handlers[])(struct client *client, void *buffer) = {
 static int dispatch_ioctl(struct client *client,
                          unsigned int cmd, void __user *arg)
 {
-       char buffer[256];
+       char buffer[sizeof(union {
+               struct fw_cdev_get_info                 _00;
+               struct fw_cdev_send_request             _01;
+               struct fw_cdev_allocate                 _02;
+               struct fw_cdev_deallocate               _03;
+               struct fw_cdev_send_response            _04;
+               struct fw_cdev_initiate_bus_reset       _05;
+               struct fw_cdev_add_descriptor           _06;
+               struct fw_cdev_remove_descriptor        _07;
+               struct fw_cdev_create_iso_context       _08;
+               struct fw_cdev_queue_iso                _09;
+               struct fw_cdev_start_iso                _0a;
+               struct fw_cdev_stop_iso                 _0b;
+               struct fw_cdev_get_cycle_timer          _0c;
+               struct fw_cdev_allocate_iso_resource    _0d;
+               struct fw_cdev_send_stream_packet       _13;
+       })];
        int ret;
 
        if (_IOC_TYPE(cmd) != '#' ||
@@ -1390,10 +1411,10 @@ static int fw_device_op_mmap(struct file *file, struct vm_area_struct *vma)
 
 static int shutdown_resource(int id, void *p, void *data)
 {
-       struct client_resource *r = p;
+       struct client_resource *resource = p;
        struct client *client = data;
 
-       r->release(client, r);
+       resource->release(client, resource);
        client_put(client);
 
        return 0;
@@ -1402,7 +1423,7 @@ static int shutdown_resource(int id, void *p, void *data)
 static int fw_device_op_release(struct inode *inode, struct file *file)
 {
        struct client *client = file->private_data;
-       struct event *e, *next_e;
+       struct event *event, *next_event;
 
        mutex_lock(&client->device->client_list_mutex);
        list_del(&client->link);
@@ -1423,8 +1444,8 @@ static int fw_device_op_release(struct inode *inode, struct file *file)
        idr_remove_all(&client->resource_idr);
        idr_destroy(&client->resource_idr);
 
-       list_for_each_entry_safe(e, next_e, &client->event_list, link)
-               kfree(e);
+       list_for_each_entry_safe(event, next_event, &client->event_list, link)
+               kfree(event);
 
        client_put(client);
 
index fddf2b3..9a5f38c 100644 (file)
@@ -28,9 +28,9 @@
 #include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/spinlock.h>
-#include <linux/string.h>
 
 #include <asm/atomic.h>
+#include <asm/byteorder.h>
 #include <asm/system.h>
 
 #include "core.h"
@@ -510,13 +510,16 @@ static void update_tree(struct fw_card *card, struct fw_node *root)
 static void update_topology_map(struct fw_card *card,
                                u32 *self_ids, int self_id_count)
 {
-       int node_count;
+       int node_count = (card->root_node->node_id & 0x3f) + 1;
+       __be32 *map = card->topology_map;
+
+       *map++ = cpu_to_be32((self_id_count + 2) << 16);
+       *map++ = cpu_to_be32(be32_to_cpu(card->topology_map[1]) + 1);
+       *map++ = cpu_to_be32((node_count << 16) | self_id_count);
+
+       while (self_id_count--)
+               *map++ = cpu_to_be32p(self_ids++);
 
-       card->topology_map[1]++;
-       node_count = (card->root_node->node_id & 0x3f) + 1;
-       card->topology_map[2] = (node_count << 16) | self_id_count;
-       card->topology_map[0] = (self_id_count + 2) << 16;
-       memcpy(&card->topology_map[3], self_ids, self_id_count * 4);
        fw_compute_block_crc(card->topology_map);
 }
 
index da628c7..842739d 100644 (file)
@@ -218,12 +218,15 @@ static void fw_fill_request(struct fw_packet *packet, int tcode, int tlabel,
                packet->header_length = 16;
                packet->payload_length = 0;
                break;
+
+       default:
+               WARN(1, KERN_ERR "wrong tcode %d", tcode);
        }
  common:
        packet->speed = speed;
        packet->generation = generation;
        packet->ack = 0;
-       packet->payload_bus = 0;
+       packet->payload_mapped = false;
 }
 
 /**
@@ -595,11 +598,10 @@ void fw_fill_response(struct fw_packet *response, u32 *request_header,
                break;
 
        default:
-               BUG();
-               return;
+               WARN(1, KERN_ERR "wrong tcode %d", tcode);
        }
 
-       response->payload_bus = 0;
+       response->payload_mapped = false;
 }
 EXPORT_SYMBOL(fw_fill_response);
 
@@ -810,8 +812,7 @@ static void handle_topology_map(struct fw_card *card, struct fw_request *request
                int speed, unsigned long long offset,
                void *payload, size_t length, void *callback_data)
 {
-       int i, start, end;
-       __be32 *map;
+       int start;
 
        if (!TCODE_IS_READ_REQUEST(tcode)) {
                fw_send_response(card, request, RCODE_TYPE_ERROR);
@@ -824,11 +825,7 @@ static void handle_topology_map(struct fw_card *card, struct fw_request *request
        }
 
        start = (offset - topology_map_region.start) / 4;
-       end = start + length / 4;
-       map = payload;
-
-       for (i = 0; i < length / 4; i++)
-               map[i] = cpu_to_be32(card->topology_map[start + i]);
+       memcpy(payload, &card->topology_map[start], length);
 
        fw_send_response(card, request, RCODE_COMPLETE);
 }
index 7ff6e75..ed3b1a7 100644 (file)
@@ -40,7 +40,8 @@ struct fw_card_driver {
         * enable the PHY or set the link_on bit and initiate a bus
         * reset.
         */
-       int (*enable)(struct fw_card *card, u32 *config_rom, size_t length);
+       int (*enable)(struct fw_card *card,
+                     const __be32 *config_rom, size_t length);
 
        int (*update_phy_reg)(struct fw_card *card, int address,
                              int clear_bits, int set_bits);
@@ -48,10 +49,10 @@ struct fw_card_driver {
        /*
         * Update the config rom for an enabled card.  This function
         * should change the config rom that is presented on the bus
-        * an initiate a bus reset.
+        * and initiate a bus reset.
         */
        int (*set_config_rom)(struct fw_card *card,
-                             u32 *config_rom, size_t length);
+                             const __be32 *config_rom, size_t length);
 
        void (*send_request)(struct fw_card *card, struct fw_packet *packet);
        void (*send_response)(struct fw_card *card, struct fw_packet *packet);
@@ -93,7 +94,7 @@ int fw_card_add(struct fw_card *card,
                u32 max_receive, u32 link_speed, u64 guid);
 void fw_core_remove_card(struct fw_card *card);
 int fw_core_initiate_bus_reset(struct fw_card *card, int short_reset);
-int fw_compute_block_crc(u32 *block);
+int fw_compute_block_crc(__be32 *block);
 void fw_schedule_bm_work(struct fw_card *card, unsigned long delay);
 
 static inline struct fw_card *fw_card_get(struct fw_card *card)
index 94260aa..ae4556f 100644 (file)
@@ -205,7 +205,7 @@ struct fw_ohci {
        dma_addr_t config_rom_bus;
        __be32 *next_config_rom;
        dma_addr_t next_config_rom_bus;
-       u32 next_header;
+       __be32 next_header;
 
        struct ar_context ar_request_ctx;
        struct ar_context ar_response_ctx;
@@ -997,7 +997,8 @@ static int at_context_queue_packet(struct context *ctx,
                        packet->ack = RCODE_SEND_ERROR;
                        return -1;
                }
-               packet->payload_bus = payload_bus;
+               packet->payload_bus     = payload_bus;
+               packet->payload_mapped  = true;
 
                d[2].req_count    = cpu_to_le16(packet->payload_length);
                d[2].data_address = cpu_to_le32(payload_bus);
@@ -1025,7 +1026,7 @@ static int at_context_queue_packet(struct context *ctx,
         */
        if (ohci->generation != packet->generation ||
            reg_read(ohci, OHCI1394_IntEventSet) & OHCI1394_busReset) {
-               if (packet->payload_length > 0)
+               if (packet->payload_mapped)
                        dma_unmap_single(ohci->card.device, payload_bus,
                                         packet->payload_length, DMA_TO_DEVICE);
                packet->ack = RCODE_GENERATION;
@@ -1061,7 +1062,7 @@ static int handle_at_packet(struct context *context,
                /* This packet was cancelled, just continue. */
                return 1;
 
-       if (packet->payload_bus)
+       if (packet->payload_mapped)
                dma_unmap_single(ohci->card.device, packet->payload_bus,
                                 packet->payload_length, DMA_TO_DEVICE);
 
@@ -1357,8 +1358,9 @@ static void bus_reset_tasklet(unsigned long data)
                 */
                reg_write(ohci, OHCI1394_BusOptions,
                          be32_to_cpu(ohci->config_rom[2]));
-               ohci->config_rom[0] = cpu_to_be32(ohci->next_header);
-               reg_write(ohci, OHCI1394_ConfigROMhdr, ohci->next_header);
+               ohci->config_rom[0] = ohci->next_header;
+               reg_write(ohci, OHCI1394_ConfigROMhdr,
+                         be32_to_cpu(ohci->next_header));
        }
 
 #ifdef CONFIG_FIREWIRE_OHCI_REMOTE_DMA
@@ -1477,7 +1479,17 @@ static int software_reset(struct fw_ohci *ohci)
        return -EBUSY;
 }
 
-static int ohci_enable(struct fw_card *card, u32 *config_rom, size_t length)
+static void copy_config_rom(__be32 *dest, const __be32 *src, size_t length)
+{
+       size_t size = length * 4;
+
+       memcpy(dest, src, size);
+       if (size < CONFIG_ROM_SIZE)
+               memset(&dest[length], 0, CONFIG_ROM_SIZE - size);
+}
+
+static int ohci_enable(struct fw_card *card,
+                      const __be32 *config_rom, size_t length)
 {
        struct fw_ohci *ohci = fw_ohci(card);
        struct pci_dev *dev = to_pci_dev(card->device);
@@ -1579,8 +1591,7 @@ static int ohci_enable(struct fw_card *card, u32 *config_rom, size_t length)
                if (ohci->next_config_rom == NULL)
                        return -ENOMEM;
 
-               memset(ohci->next_config_rom, 0, CONFIG_ROM_SIZE);
-               fw_memcpy_to_be32(ohci->next_config_rom, config_rom, length * 4);
+               copy_config_rom(ohci->next_config_rom, config_rom, length);
        } else {
                /*
                 * In the suspend case, config_rom is NULL, which
@@ -1590,7 +1601,7 @@ static int ohci_enable(struct fw_card *card, u32 *config_rom, size_t length)
                ohci->next_config_rom_bus = ohci->config_rom_bus;
        }
 
-       ohci->next_header = be32_to_cpu(ohci->next_config_rom[0]);
+       ohci->next_header = ohci->next_config_rom[0];
        ohci->next_config_rom[0] = 0;
        reg_write(ohci, OHCI1394_ConfigROMhdr, 0);
        reg_write(ohci, OHCI1394_BusOptions,
@@ -1624,7 +1635,7 @@ static int ohci_enable(struct fw_card *card, u32 *config_rom, size_t length)
 }
 
 static int ohci_set_config_rom(struct fw_card *card,
-                              u32 *config_rom, size_t length)
+                              const __be32 *config_rom, size_t length)
 {
        struct fw_ohci *ohci;
        unsigned long flags;
@@ -1673,9 +1684,7 @@ static int ohci_set_config_rom(struct fw_card *card,
                ohci->next_config_rom = next_config_rom;
                ohci->next_config_rom_bus = next_config_rom_bus;
 
-               memset(ohci->next_config_rom, 0, CONFIG_ROM_SIZE);
-               fw_memcpy_to_be32(ohci->next_config_rom, config_rom,
-                                 length * 4);
+               copy_config_rom(ohci->next_config_rom, config_rom, length);
 
                ohci->next_header = config_rom[0];
                ohci->next_config_rom[0] = 0;
@@ -1729,7 +1738,7 @@ static int ohci_cancel_packet(struct fw_card *card, struct fw_packet *packet)
        if (packet->ack != 0)
                goto out;
 
-       if (packet->payload_bus)
+       if (packet->payload_mapped)
                dma_unmap_single(ohci->card.device, packet->payload_bus,
                                 packet->payload_length, DMA_TO_DEVICE);
 
index 98dbbda..d485cdd 100644 (file)
@@ -820,20 +820,25 @@ static void sbp2_release_target(struct kref *kref)
        fw_device_put(device);
 }
 
-static struct workqueue_struct *sbp2_wq;
+static void sbp2_target_get(struct sbp2_target *tgt)
+{
+       kref_get(&tgt->kref);
+}
 
 static void sbp2_target_put(struct sbp2_target *tgt)
 {
        kref_put(&tgt->kref, sbp2_release_target);
 }
 
+static struct workqueue_struct *sbp2_wq;
+
 /*
  * Always get the target's kref when scheduling work on one its units.
  * Each workqueue job is responsible to call sbp2_target_put() upon return.
  */
 static void sbp2_queue_work(struct sbp2_logical_unit *lu, unsigned long delay)
 {
-       kref_get(&lu->tgt->kref);
+       sbp2_target_get(lu->tgt);
        if (!queue_delayed_work(sbp2_wq, &lu->work, delay))
                sbp2_target_put(lu->tgt);
 }
index d7ece13..8d8a00e 100644 (file)
@@ -5,6 +5,7 @@
 menuconfig I2C
        tristate "I2C support"
        depends on HAS_IOMEM
+       select RT_MUTEXES
        ---help---
          I2C (pronounce: I-square-C) is a slow serial bus protocol used in
          many micro controller applications and developed by Philips.  SMBus,
index e8fe7f1..5f318ce 100644 (file)
@@ -640,22 +640,6 @@ config I2C_TINY_USB
          This driver can also be built as a module.  If so, the module
          will be called i2c-tiny-usb.
 
-comment "Graphics adapter I2C/DDC channel drivers"
-       depends on PCI
-
-config I2C_VOODOO3
-       tristate "Voodoo 3 (DEPRECATED)"
-       depends on PCI
-       select I2C_ALGOBIT
-       help
-         If you say yes to this option, support will be included for the
-         Voodoo 3 I2C interface. This driver is deprecated and you should
-         use the tdfxfb driver instead, which additionally provides
-         framebuffer support.
-
-         This driver can also be built as a module.  If so, the module
-         will be called i2c-voodoo3.
-
 comment "Other I2C/SMBus bus drivers"
 
 config I2C_ACORN
index ff937ac..302c551 100644 (file)
@@ -61,9 +61,6 @@ obj-$(CONFIG_I2C_PARPORT_LIGHT)       += i2c-parport-light.o
 obj-$(CONFIG_I2C_TAOS_EVM)     += i2c-taos-evm.o
 obj-$(CONFIG_I2C_TINY_USB)     += i2c-tiny-usb.o
 
-# Graphics adapter I2C/DDC channel drivers
-obj-$(CONFIG_I2C_VOODOO3)      += i2c-voodoo3.o
-
 # Other I2C/SMBus bus drivers
 obj-$(CONFIG_I2C_ACORN)                += i2c-acorn.o
 obj-$(CONFIG_I2C_ELEKTOR)      += i2c-elektor.o
index d108450..8de7d7b 100644 (file)
@@ -138,7 +138,7 @@ static unsigned short ali1535_smba;
    Note the differences between kernels with the old PCI BIOS interface and
    newer kernels with the real PCI interface. In compat.h some things are
    defined to make the transition easier. */
-static int ali1535_setup(struct pci_dev *dev)
+static int __devinit ali1535_setup(struct pci_dev *dev)
 {
        int retval = -ENODEV;
        unsigned char temp;
index d627fce..e7e3205 100644 (file)
@@ -131,7 +131,7 @@ MODULE_PARM_DESC(force_addr,
 static struct pci_driver ali15x3_driver;
 static unsigned short ali15x3_smba;
 
-static int ali15x3_setup(struct pci_dev *ALI15X3_dev)
+static int __devinit ali15x3_setup(struct pci_dev *ALI15X3_dev)
 {
        u16 a;
        unsigned char temp;
index 55edcfe..df6ab55 100644 (file)
@@ -767,6 +767,9 @@ static int __devinit i801_probe(struct pci_dev *dev, const struct pci_device_id
        /* set up the sysfs linkage to our parent device */
        i801_adapter.dev.parent = &dev->dev;
 
+       /* Retry up to 3 times on lost arbitration */
+       i801_adapter.retries = 3;
+
        snprintf(i801_adapter.name, sizeof(i801_adapter.name),
                "SMBus I801 adapter at %04lx", i801_smba);
        err = i2c_add_adapter(&i801_adapter);
index a75c75e..5901707 100644 (file)
@@ -56,12 +56,6 @@ iic_cook_addr(struct i2c_msg *msg)
        if (msg->flags & I2C_M_RD)
                addr |= 1;
 
-       /*
-        * Read or Write?
-        */
-       if (msg->flags & I2C_M_REV_DIR_ADDR)
-               addr ^= 1;
-
        return addr;   
 }
 
index bbab0e1..ed387ff 100644 (file)
@@ -338,9 +338,6 @@ mv64xxx_i2c_prepare_for_io(struct mv64xxx_i2c_data *drv_data,
        if (msg->flags & I2C_M_RD)
                dir = 1;
 
-       if (msg->flags & I2C_M_REV_DIR_ADDR)
-               dir ^= 1;
-
        if (msg->flags & I2C_M_TEN) {
                drv_data->addr1 = 0xf0 | (((u32)msg->addr & 0x300) >> 7) | dir;
                drv_data->addr2 = (u32)msg->addr & 0xff;
index 3c9d71f..1c440a7 100644 (file)
@@ -49,48 +49,38 @@ static s32 i2c_powermac_smbus_xfer( struct i2c_adapter*     adap,
        int                     rc = 0;
        int                     read = (read_write == I2C_SMBUS_READ);
        int                     addrdir = (addr << 1) | read;
+       int                     mode, subsize, len;
+       u32                     subaddr;
+       u8                      *buf;
        u8                      local[2];
 
-       rc = pmac_i2c_open(bus, 0);
-       if (rc)
-               return rc;
+       if (size == I2C_SMBUS_QUICK || size == I2C_SMBUS_BYTE) {
+               mode = pmac_i2c_mode_std;
+               subsize = 0;
+               subaddr = 0;
+       } else {
+               mode = read ? pmac_i2c_mode_combined : pmac_i2c_mode_stdsub;
+               subsize = 1;
+               subaddr = command;
+       }
 
        switch (size) {
         case I2C_SMBUS_QUICK:
-               rc = pmac_i2c_setmode(bus, pmac_i2c_mode_std);
-               if (rc)
-                       goto bail;
-               rc = pmac_i2c_xfer(bus, addrdir, 0, 0, NULL, 0);
+               buf = NULL;
+               len = 0;
                break;
         case I2C_SMBUS_BYTE:
-               rc = pmac_i2c_setmode(bus, pmac_i2c_mode_std);
-               if (rc)
-                       goto bail;
-               rc = pmac_i2c_xfer(bus, addrdir, 0, 0, &data->byte, 1);
-               break;
         case I2C_SMBUS_BYTE_DATA:
-               rc = pmac_i2c_setmode(bus, read ?
-                                     pmac_i2c_mode_combined :
-                                     pmac_i2c_mode_stdsub);
-               if (rc)
-                       goto bail;
-               rc = pmac_i2c_xfer(bus, addrdir, 1, command, &data->byte, 1);
+               buf = &data->byte;
+               len = 1;
                break;
         case I2C_SMBUS_WORD_DATA:
-               rc = pmac_i2c_setmode(bus, read ?
-                                     pmac_i2c_mode_combined :
-                                     pmac_i2c_mode_stdsub);
-               if (rc)
-                       goto bail;
                if (!read) {
                        local[0] = data->word & 0xff;
                        local[1] = (data->word >> 8) & 0xff;
                }
-               rc = pmac_i2c_xfer(bus, addrdir, 1, command, local, 2);
-               if (rc == 0 && read) {
-                       data->word = ((u16)local[1]) << 8;
-                       data->word |= local[0];
-               }
+               buf = local;
+               len = 2;
                break;
 
        /* Note that these are broken vs. the expected smbus API where
@@ -105,28 +95,44 @@ static s32 i2c_powermac_smbus_xfer(        struct i2c_adapter*     adap,
         * a repeat start/addr phase (but not stop in between)
         */
         case I2C_SMBUS_BLOCK_DATA:
-               rc = pmac_i2c_setmode(bus, read ?
-                                     pmac_i2c_mode_combined :
-                                     pmac_i2c_mode_stdsub);
-               if (rc)
-                       goto bail;
-               rc = pmac_i2c_xfer(bus, addrdir, 1, command, data->block,
-                                  data->block[0] + 1);
-
+               buf = data->block;
+               len = data->block[0] + 1;
                break;
        case I2C_SMBUS_I2C_BLOCK_DATA:
-               rc = pmac_i2c_setmode(bus, read ?
-                                     pmac_i2c_mode_combined :
-                                     pmac_i2c_mode_stdsub);
-               if (rc)
-                       goto bail;
-               rc = pmac_i2c_xfer(bus, addrdir, 1, command,
-                                  &data->block[1], data->block[0]);
+               buf = &data->block[1];
+               len = data->block[0];
                break;
 
         default:
-               rc = -EINVAL;
+               return -EINVAL;
+       }
+
+       rc = pmac_i2c_open(bus, 0);
+       if (rc) {
+               dev_err(&adap->dev, "Failed to open I2C, err %d\n", rc);
+               return rc;
+       }
+
+       rc = pmac_i2c_setmode(bus, mode);
+       if (rc) {
+               dev_err(&adap->dev, "Failed to set I2C mode %d, err %d\n",
+                       mode, rc);
+               goto bail;
        }
+
+       rc = pmac_i2c_xfer(bus, addrdir, subsize, subaddr, buf, len);
+       if (rc) {
+               dev_err(&adap->dev,
+                       "I2C transfer at 0x%02x failed, size %d, err %d\n",
+                       addrdir >> 1, size, rc);
+               goto bail;
+       }
+
+       if (size == I2C_SMBUS_WORD_DATA && read) {
+               data->word = ((u16)local[1]) << 8;
+               data->word |= local[0];
+       }
+
  bail:
        pmac_i2c_close(bus);
        return rc;
@@ -146,20 +152,33 @@ static int i2c_powermac_master_xfer(      struct i2c_adapter *adap,
        int                     read;
        int                     addrdir;
 
+       if (num != 1) {
+               dev_err(&adap->dev,
+                       "Multi-message I2C transactions not supported\n");
+               return -EOPNOTSUPP;
+       }
+
        if (msgs->flags & I2C_M_TEN)
                return -EINVAL;
        read = (msgs->flags & I2C_M_RD) != 0;
        addrdir = (msgs->addr << 1) | read;
-       if (msgs->flags & I2C_M_REV_DIR_ADDR)
-               addrdir ^= 1;
 
        rc = pmac_i2c_open(bus, 0);
-       if (rc)
+       if (rc) {
+               dev_err(&adap->dev, "Failed to open I2C, err %d\n", rc);
                return rc;
+       }
        rc = pmac_i2c_setmode(bus, pmac_i2c_mode_std);
-       if (rc)
+       if (rc) {
+               dev_err(&adap->dev, "Failed to set I2C mode %d, err %d\n",
+                       pmac_i2c_mode_std, rc);
                goto bail;
+       }
        rc = pmac_i2c_xfer(bus, addrdir, 0, 0, msgs->buf, msgs->len);
+       if (rc < 0)
+               dev_err(&adap->dev, "I2C %s 0x%02x failed, err %d\n",
+                       addrdir & 1 ? "read from" : "write to", addrdir >> 1,
+                       rc);
  bail:
        pmac_i2c_close(bus);
        return rc < 0 ? rc : 1;
@@ -183,19 +202,16 @@ static const struct i2c_algorithm i2c_powermac_algorithm = {
 static int __devexit i2c_powermac_remove(struct platform_device *dev)
 {
        struct i2c_adapter      *adapter = platform_get_drvdata(dev);
-       struct pmac_i2c_bus     *bus = i2c_get_adapdata(adapter);
        int                     rc;
 
        rc = i2c_del_adapter(adapter);
-       pmac_i2c_detach_adapter(bus, adapter);
-       i2c_set_adapdata(adapter, NULL);
        /* We aren't that prepared to deal with this... */
        if (rc)
                printk(KERN_WARNING
                       "i2c-powermac.c: Failed to remove bus %s !\n",
                       adapter->name);
        platform_set_drvdata(dev, NULL);
-       kfree(adapter);
+       memset(adapter, 0, sizeof(*adapter));
 
        return 0;
 }
@@ -206,12 +222,12 @@ static int __devinit i2c_powermac_probe(struct platform_device *dev)
        struct pmac_i2c_bus *bus = dev->dev.platform_data;
        struct device_node *parent = NULL;
        struct i2c_adapter *adapter;
-       char name[32];
        const char *basename;
        int rc;
 
        if (bus == NULL)
                return -EINVAL;
+       adapter = pmac_i2c_get_adapter(bus);
 
        /* Ok, now we need to make up a name for the interface that will
         * match what we used to do in the past, that is basically the
@@ -237,29 +253,22 @@ static int __devinit i2c_powermac_probe(struct platform_device *dev)
        default:
                return -EINVAL;
        }
-       snprintf(name, 32, "%s %d", basename, pmac_i2c_get_channel(bus));
+       snprintf(adapter->name, sizeof(adapter->name), "%s %d", basename,
+                pmac_i2c_get_channel(bus));
        of_node_put(parent);
 
-       adapter = kzalloc(sizeof(struct i2c_adapter), GFP_KERNEL);
-       if (adapter == NULL) {
-               printk(KERN_ERR "i2c-powermac: can't allocate inteface !\n");
-               return -ENOMEM;
-       }
        platform_set_drvdata(dev, adapter);
-       strcpy(adapter->name, name);
        adapter->algo = &i2c_powermac_algorithm;
        i2c_set_adapdata(adapter, bus);
        adapter->dev.parent = &dev->dev;
-       pmac_i2c_attach_adapter(bus, adapter);
        rc = i2c_add_adapter(adapter);
        if (rc) {
                printk(KERN_ERR "i2c-powermac: Adapter %s registration "
-                      "failed\n", name);
-               i2c_set_adapdata(adapter, NULL);
-               pmac_i2c_detach_adapter(bus, adapter);
+                      "failed\n", adapter->name);
+               memset(adapter, 0, sizeof(*adapter));
        }
 
-       printk(KERN_INFO "PowerMac i2c bus %s registered\n", name);
+       printk(KERN_INFO "PowerMac i2c bus %s registered\n", adapter->name);
 
        if (!strncmp(basename, "uni-n", 5)) {
                struct device_node *np;
index 139f0c7..844569f 100644 (file)
@@ -142,7 +142,7 @@ static void sis5595_write(u8 reg, u8 data)
        outb(data, sis5595_base + SMB_DAT);
 }
 
-static int sis5595_setup(struct pci_dev *SIS5595_dev)
+static int __devinit sis5595_setup(struct pci_dev *SIS5595_dev)
 {
        u16 a;
        u8 val;
index 70ca41e..68cff7a 100644 (file)
@@ -389,7 +389,7 @@ static u32 sis630_func(struct i2c_adapter *adapter)
                I2C_FUNC_SMBUS_BLOCK_DATA;
 }
 
-static int sis630_setup(struct pci_dev *sis630_dev)
+static int __devinit sis630_setup(struct pci_dev *sis630_dev)
 {
        unsigned char b;
        struct pci_dev *dummy = NULL;
index 1b7b2af..0c770ea 100644 (file)
@@ -35,6 +35,10 @@ module_param_array(chip_addr, ushort, NULL, S_IRUGO);
 MODULE_PARM_DESC(chip_addr,
                 "Chip addresses (up to 10, between 0x03 and 0x77)");
 
+static unsigned long functionality = ~0UL;
+module_param(functionality, ulong, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(functionality, "Override functionality bitfield");
+
 struct stub_chip {
        u8 pointer;
        u16 words[256];         /* Byte operations use the LSB as per SMBus
@@ -48,7 +52,7 @@ static s32 stub_xfer(struct i2c_adapter * adap, u16 addr, unsigned short flags,
        char read_write, u8 command, int size, union i2c_smbus_data * data)
 {
        s32 ret;
-       int i;
+       int i, len;
        struct stub_chip *chip = NULL;
 
        /* Search for the right chip */
@@ -118,6 +122,29 @@ static s32 stub_xfer(struct i2c_adapter * adap, u16 addr, unsigned short flags,
                ret = 0;
                break;
 
+       case I2C_SMBUS_I2C_BLOCK_DATA:
+               len = data->block[0];
+               if (read_write == I2C_SMBUS_WRITE) {
+                       for (i = 0; i < len; i++) {
+                               chip->words[command + i] &= 0xff00;
+                               chip->words[command + i] |= data->block[1 + i];
+                       }
+                       dev_dbg(&adap->dev, "i2c block data - addr 0x%02x, "
+                                       "wrote %d bytes at 0x%02x.\n",
+                                       addr, len, command);
+               } else {
+                       for (i = 0; i < len; i++) {
+                               data->block[1 + i] =
+                                       chip->words[command + i] & 0xff;
+                       }
+                       dev_dbg(&adap->dev, "i2c block data - addr 0x%02x, "
+                                       "read  %d bytes at 0x%02x.\n",
+                                       addr, len, command);
+               }
+
+               ret = 0;
+               break;
+
        default:
                dev_dbg(&adap->dev, "Unsupported I2C/SMBus command\n");
                ret = -EOPNOTSUPP;
@@ -129,8 +156,9 @@ static s32 stub_xfer(struct i2c_adapter * adap, u16 addr, unsigned short flags,
 
 static u32 stub_func(struct i2c_adapter *adapter)
 {
-       return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
-               I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA;
+       return (I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
+               I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
+               I2C_FUNC_SMBUS_I2C_BLOCK) & functionality;
 }
 
 static const struct i2c_algorithm smbus_algorithm = {
diff --git a/drivers/i2c/busses/i2c-voodoo3.c b/drivers/i2c/busses/i2c-voodoo3.c
deleted file mode 100644 (file)
index 7663d57..0000000
+++ /dev/null
@@ -1,248 +0,0 @@
-/*
-    Copyright (c) 1998, 1999  Frodo Looijaard <frodol@dds.nl>,
-    Philip Edelbrock <phil@netroedge.com>,
-    Ralph Metzler <rjkm@thp.uni-koeln.de>, and
-    Mark D. Studebaker <mdsxyz123@yahoo.com>
-    
-    Based on code written by Ralph Metzler <rjkm@thp.uni-koeln.de> and
-    Simon Vogl
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-/* This interfaces to the I2C bus of the Voodoo3 to gain access to
-    the BT869 and possibly other I2C devices. */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/pci.h>
-#include <linux/i2c.h>
-#include <linux/i2c-algo-bit.h>
-#include <asm/io.h>
-
-/* the only registers we use */
-#define REG            0x78
-#define REG2           0x70
-
-/* bit locations in the register */
-#define DDC_ENAB       0x00040000
-#define DDC_SCL_OUT    0x00080000
-#define DDC_SDA_OUT    0x00100000
-#define DDC_SCL_IN     0x00200000
-#define DDC_SDA_IN     0x00400000
-#define I2C_ENAB       0x00800000
-#define I2C_SCL_OUT    0x01000000
-#define I2C_SDA_OUT    0x02000000
-#define I2C_SCL_IN     0x04000000
-#define I2C_SDA_IN     0x08000000
-
-/* initialization states */
-#define INIT2          0x2
-#define INIT3          0x4
-
-/* delays */
-#define CYCLE_DELAY    10
-#define TIMEOUT                (HZ / 2)
-
-
-static void __iomem *ioaddr;
-
-/* The voo GPIO registers don't have individual masks for each bit
-   so we always have to read before writing. */
-
-static void bit_vooi2c_setscl(void *data, int val)
-{
-       unsigned int r;
-       r = readl(ioaddr + REG);
-       if (val)
-               r |= I2C_SCL_OUT;
-       else
-               r &= ~I2C_SCL_OUT;
-       writel(r, ioaddr + REG);
-       readl(ioaddr + REG);    /* flush posted write */
-}
-
-static void bit_vooi2c_setsda(void *data, int val)
-{
-       unsigned int r;
-       r = readl(ioaddr + REG);
-       if (val)
-               r |= I2C_SDA_OUT;
-       else
-               r &= ~I2C_SDA_OUT;
-       writel(r, ioaddr + REG);
-       readl(ioaddr + REG);    /* flush posted write */
-}
-
-/* The GPIO pins are open drain, so the pins always remain outputs.
-   We rely on the i2c-algo-bit routines to set the pins high before
-   reading the input from other chips. */
-
-static int bit_vooi2c_getscl(void *data)
-{
-       return (0 != (readl(ioaddr + REG) & I2C_SCL_IN));
-}
-
-static int bit_vooi2c_getsda(void *data)
-{
-       return (0 != (readl(ioaddr + REG) & I2C_SDA_IN));
-}
-
-static void bit_vooddc_setscl(void *data, int val)
-{
-       unsigned int r;
-       r = readl(ioaddr + REG);
-       if (val)
-               r |= DDC_SCL_OUT;
-       else
-               r &= ~DDC_SCL_OUT;
-       writel(r, ioaddr + REG);
-       readl(ioaddr + REG);    /* flush posted write */
-}
-
-static void bit_vooddc_setsda(void *data, int val)
-{
-       unsigned int r;
-       r = readl(ioaddr + REG);
-       if (val)
-               r |= DDC_SDA_OUT;
-       else
-               r &= ~DDC_SDA_OUT;
-       writel(r, ioaddr + REG);
-       readl(ioaddr + REG);    /* flush posted write */
-}
-
-static int bit_vooddc_getscl(void *data)
-{
-       return (0 != (readl(ioaddr + REG) & DDC_SCL_IN));
-}
-
-static int bit_vooddc_getsda(void *data)
-{
-       return (0 != (readl(ioaddr + REG) & DDC_SDA_IN));
-}
-
-static int config_v3(struct pci_dev *dev)
-{
-       unsigned long cadr;
-
-       /* map Voodoo3 memory */
-       cadr = dev->resource[0].start;
-       cadr &= PCI_BASE_ADDRESS_MEM_MASK;
-       ioaddr = ioremap_nocache(cadr, 0x1000);
-       if (ioaddr) {
-               writel(0x8160, ioaddr + REG2);
-               writel(0xcffc0020, ioaddr + REG);
-               dev_info(&dev->dev, "Using Banshee/Voodoo3 I2C device at %p\n", ioaddr);
-               return 0;
-       }
-       return -ENODEV;
-}
-
-static struct i2c_algo_bit_data voo_i2c_bit_data = {
-       .setsda         = bit_vooi2c_setsda,
-       .setscl         = bit_vooi2c_setscl,
-       .getsda         = bit_vooi2c_getsda,
-       .getscl         = bit_vooi2c_getscl,
-       .udelay         = CYCLE_DELAY,
-       .timeout        = TIMEOUT
-};
-
-static struct i2c_adapter voodoo3_i2c_adapter = {
-       .owner          = THIS_MODULE,
-       .name           = "I2C Voodoo3/Banshee adapter",
-       .algo_data      = &voo_i2c_bit_data,
-};
-
-static struct i2c_algo_bit_data voo_ddc_bit_data = {
-       .setsda         = bit_vooddc_setsda,
-       .setscl         = bit_vooddc_setscl,
-       .getsda         = bit_vooddc_getsda,
-       .getscl         = bit_vooddc_getscl,
-       .udelay         = CYCLE_DELAY,
-       .timeout        = TIMEOUT
-};
-
-static struct i2c_adapter voodoo3_ddc_adapter = {
-       .owner          = THIS_MODULE,
-       .class          = I2C_CLASS_DDC, 
-       .name           = "DDC Voodoo3/Banshee adapter",
-       .algo_data      = &voo_ddc_bit_data,
-};
-
-static struct pci_device_id voodoo3_ids[] __devinitdata = {
-       { PCI_DEVICE(PCI_VENDOR_ID_3DFX, PCI_DEVICE_ID_3DFX_VOODOO3) },
-       { PCI_DEVICE(PCI_VENDOR_ID_3DFX, PCI_DEVICE_ID_3DFX_BANSHEE) },
-       { 0, }
-};
-
-MODULE_DEVICE_TABLE (pci, voodoo3_ids);
-
-static int __devinit voodoo3_probe(struct pci_dev *dev, const struct pci_device_id *id)
-{
-       int retval;
-
-       retval = config_v3(dev);
-       if (retval)
-               return retval;
-
-       /* set up the sysfs linkage to our parent device */
-       voodoo3_i2c_adapter.dev.parent = &dev->dev;
-       voodoo3_ddc_adapter.dev.parent = &dev->dev;
-
-       retval = i2c_bit_add_bus(&voodoo3_i2c_adapter);
-       if (retval)
-               return retval;
-       retval = i2c_bit_add_bus(&voodoo3_ddc_adapter);
-       if (retval)
-               i2c_del_adapter(&voodoo3_i2c_adapter);
-       return retval;
-}
-
-static void __devexit voodoo3_remove(struct pci_dev *dev)
-{
-       i2c_del_adapter(&voodoo3_i2c_adapter);
-       i2c_del_adapter(&voodoo3_ddc_adapter);
-       iounmap(ioaddr);
-}
-
-static struct pci_driver voodoo3_driver = {
-       .name           = "voodoo3_smbus",
-       .id_table       = voodoo3_ids,
-       .probe          = voodoo3_probe,
-       .remove         = __devexit_p(voodoo3_remove),
-};
-
-static int __init i2c_voodoo3_init(void)
-{
-       return pci_register_driver(&voodoo3_driver);
-}
-
-static void __exit i2c_voodoo3_exit(void)
-{
-       pci_unregister_driver(&voodoo3_driver);
-}
-
-
-MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>, "
-               "Philip Edelbrock <phil@netroedge.com>, "
-               "Ralph Metzler <rjkm@thp.uni-koeln.de>, "
-               "and Mark D. Studebaker <mdsxyz123@yahoo.com>");
-MODULE_DESCRIPTION("Voodoo3 I2C/SMBus driver");
-MODULE_LICENSE("GPL");
-
-module_init(i2c_voodoo3_init);
-module_exit(i2c_voodoo3_exit);
index f9618f4..ae4539d 100644 (file)
@@ -6,16 +6,6 @@
 
 menu "Miscellaneous I2C Chip support"
 
-config DS1682
-       tristate "Dallas DS1682 Total Elapsed Time Recorder with Alarm"
-       depends on EXPERIMENTAL
-       help
-         If you say yes here you get support for Dallas Semiconductor
-         DS1682 Total Elapsed Time Recorder.
-
-         This driver can also be built as a module.  If so, the module
-         will be called ds1682.
-
 config SENSORS_TSL2550
        tristate "Taos TSL2550 ambient light sensor"
        depends on EXPERIMENTAL
index 749cf36..fe0af0f 100644 (file)
@@ -10,7 +10,6 @@
 # * I/O expander drivers go to drivers/gpio
 #
 
-obj-$(CONFIG_DS1682)           += ds1682.o
 obj-$(CONFIG_SENSORS_TSL2550)  += tsl2550.o
 
 ifeq ($(CONFIG_I2C_DEBUG_CHIP),y)
index 2965043..4f34823 100644 (file)
@@ -558,11 +558,9 @@ static void i2c_scan_static_board_info(struct i2c_adapter *adapter)
        up_read(&__i2c_board_lock);
 }
 
-static int i2c_do_add_adapter(struct device_driver *d, void *data)
+static int i2c_do_add_adapter(struct i2c_driver *driver,
+                             struct i2c_adapter *adap)
 {
-       struct i2c_driver *driver = to_i2c_driver(d);
-       struct i2c_adapter *adap = data;
-
        /* Detect supported devices on that bus, and instantiate them */
        i2c_detect(adap, driver);
 
@@ -574,6 +572,11 @@ static int i2c_do_add_adapter(struct device_driver *d, void *data)
        return 0;
 }
 
+static int __process_new_adapter(struct device_driver *d, void *data)
+{
+       return i2c_do_add_adapter(to_i2c_driver(d), data);
+}
+
 static int i2c_register_adapter(struct i2c_adapter *adap)
 {
        int res = 0, dummy;
@@ -584,7 +587,7 @@ static int i2c_register_adapter(struct i2c_adapter *adap)
                goto out_list;
        }
 
-       mutex_init(&adap->bus_lock);
+       rt_mutex_init(&adap->bus_lock);
 
        /* Set default timeout to 1 second if not already set */
        if (adap->timeout == 0)
@@ -614,7 +617,7 @@ static int i2c_register_adapter(struct i2c_adapter *adap)
        /* Notify drivers */
        mutex_lock(&core_lock);
        dummy = bus_for_each_drv(&i2c_bus_type, NULL, adap,
-                                i2c_do_add_adapter);
+                                __process_new_adapter);
        mutex_unlock(&core_lock);
 
        return 0;
@@ -715,10 +718,9 @@ retry:
 }
 EXPORT_SYMBOL_GPL(i2c_add_numbered_adapter);
 
-static int i2c_do_del_adapter(struct device_driver *d, void *data)
+static int i2c_do_del_adapter(struct i2c_driver *driver,
+                             struct i2c_adapter *adapter)
 {
-       struct i2c_driver *driver = to_i2c_driver(d);
-       struct i2c_adapter *adapter = data;
        struct i2c_client *client, *_n;
        int res;
 
@@ -750,6 +752,11 @@ static int __unregister_client(struct device *dev, void *dummy)
        return 0;
 }
 
+static int __process_removed_adapter(struct device_driver *d, void *data)
+{
+       return i2c_do_del_adapter(to_i2c_driver(d), data);
+}
+
 /**
  * i2c_del_adapter - unregister I2C adapter
  * @adap: the adapter being unregistered
@@ -777,7 +784,7 @@ int i2c_del_adapter(struct i2c_adapter *adap)
        /* Tell drivers about this removal */
        mutex_lock(&core_lock);
        res = bus_for_each_drv(&i2c_bus_type, NULL, adap,
-                              i2c_do_del_adapter);
+                              __process_removed_adapter);
        mutex_unlock(&core_lock);
        if (res)
                return res;
@@ -826,22 +833,11 @@ EXPORT_SYMBOL(i2c_del_adapter);
 
 /* ------------------------------------------------------------------------- */
 
-static int __attach_adapter(struct device *dev, void *data)
+static int __process_new_driver(struct device *dev, void *data)
 {
-       struct i2c_adapter *adapter;
-       struct i2c_driver *driver = data;
-
        if (dev->type != &i2c_adapter_type)
                return 0;
-       adapter = to_i2c_adapter(dev);
-
-       i2c_detect(adapter, driver);
-
-       /* Legacy drivers scan i2c busses directly */
-       if (driver->attach_adapter)
-               driver->attach_adapter(adapter);
-
-       return 0;
+       return i2c_do_add_adapter(data, to_i2c_adapter(dev));
 }
 
 /*
@@ -873,40 +869,18 @@ int i2c_register_driver(struct module *owner, struct i2c_driver *driver)
        INIT_LIST_HEAD(&driver->clients);
        /* Walk the adapters that are already present */
        mutex_lock(&core_lock);
-       bus_for_each_dev(&i2c_bus_type, NULL, driver, __attach_adapter);
+       bus_for_each_dev(&i2c_bus_type, NULL, driver, __process_new_driver);
        mutex_unlock(&core_lock);
 
        return 0;
 }
 EXPORT_SYMBOL(i2c_register_driver);
 
-static int __detach_adapter(struct device *dev, void *data)
+static int __process_removed_driver(struct device *dev, void *data)
 {
-       struct i2c_adapter *adapter;
-       struct i2c_driver *driver = data;
-       struct i2c_client *client, *_n;
-
        if (dev->type != &i2c_adapter_type)
                return 0;
-       adapter = to_i2c_adapter(dev);
-
-       /* Remove the devices we created ourselves as the result of hardware
-        * probing (using a driver's detect method) */
-       list_for_each_entry_safe(client, _n, &driver->clients, detected) {
-               dev_dbg(&adapter->dev, "Removing %s at 0x%x\n",
-                       client->name, client->addr);
-               list_del(&client->detected);
-               i2c_unregister_device(client);
-       }
-
-       if (driver->detach_adapter) {
-               if (driver->detach_adapter(adapter))
-                       dev_err(&adapter->dev,
-                               "detach_adapter failed for driver [%s]\n",
-                               driver->driver.name);
-       }
-
-       return 0;
+       return i2c_do_del_adapter(data, to_i2c_adapter(dev));
 }
 
 /**
@@ -917,7 +891,7 @@ static int __detach_adapter(struct device *dev, void *data)
 void i2c_del_driver(struct i2c_driver *driver)
 {
        mutex_lock(&core_lock);
-       bus_for_each_dev(&i2c_bus_type, NULL, driver, __detach_adapter);
+       bus_for_each_dev(&i2c_bus_type, NULL, driver, __process_removed_driver);
        mutex_unlock(&core_lock);
 
        driver_unregister(&driver->driver);
@@ -1092,12 +1066,12 @@ int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
 #endif
 
                if (in_atomic() || irqs_disabled()) {
-                       ret = mutex_trylock(&adap->bus_lock);
+                       ret = rt_mutex_trylock(&adap->bus_lock);
                        if (!ret)
                                /* I2C activity is ongoing. */
                                return -EAGAIN;
                } else {
-                       mutex_lock_nested(&adap->bus_lock, adap->level);
+                       rt_mutex_lock(&adap->bus_lock);
                }
 
                /* Retry automatically on arbitration loss */
@@ -1109,7 +1083,7 @@ int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
                        if (time_after(jiffies, orig_jiffies + adap->timeout))
                                break;
                }
-               mutex_unlock(&adap->bus_lock);
+               rt_mutex_unlock(&adap->bus_lock);
 
                return ret;
        } else {
@@ -1180,7 +1154,7 @@ EXPORT_SYMBOL(i2c_master_recv);
  * ----------------------------------------------------
  */
 
-static int i2c_detect_address(struct i2c_client *temp_client, int kind,
+static int i2c_detect_address(struct i2c_client *temp_client,
                              struct i2c_driver *driver)
 {
        struct i2c_board_info info;
@@ -1199,22 +1173,18 @@ static int i2c_detect_address(struct i2c_client *temp_client, int kind,
        if (i2c_check_addr(adapter, addr))
                return 0;
 
-       /* Make sure there is something at this address, unless forced */
-       if (kind < 0) {
-               if (i2c_smbus_xfer(adapter, addr, 0, 0, 0,
-                                  I2C_SMBUS_QUICK, NULL) < 0)
-                       return 0;
+       /* Make sure there is something at this address */
+       if (i2c_smbus_xfer(adapter, addr, 0, 0, 0, I2C_SMBUS_QUICK, NULL) < 0)
+               return 0;
 
-               /* prevent 24RF08 corruption */
-               if ((addr & ~0x0f) == 0x50)
-                       i2c_smbus_xfer(adapter, addr, 0, 0, 0,
-                                      I2C_SMBUS_QUICK, NULL);
-       }
+       /* Prevent 24RF08 corruption */
+       if ((addr & ~0x0f) == 0x50)
+               i2c_smbus_xfer(adapter, addr, 0, 0, 0, I2C_SMBUS_QUICK, NULL);
 
        /* Finally call the custom detection function */
        memset(&info, 0, sizeof(struct i2c_board_info));
        info.addr = addr;
-       err = driver->detect(temp_client, kind, &info);
+       err = driver->detect(temp_client, -1, &info);
        if (err) {
                /* -ENODEV is returned if the detection fails. We catch it
                   here as this isn't an error. */
@@ -1259,40 +1229,13 @@ static int i2c_detect(struct i2c_adapter *adapter, struct i2c_driver *driver)
                return -ENOMEM;
        temp_client->adapter = adapter;
 
-       /* Force entries are done first, and are not affected by ignore
-          entries */
-       if (address_data->forces) {
-               const unsigned short * const *forces = address_data->forces;
-               int kind;
-
-               for (kind = 0; forces[kind]; kind++) {
-                       for (i = 0; forces[kind][i] != I2C_CLIENT_END;
-                            i += 2) {
-                               if (forces[kind][i] == adap_id
-                                || forces[kind][i] == ANY_I2C_BUS) {
-                                       dev_dbg(&adapter->dev, "found force "
-                                               "parameter for adapter %d, "
-                                               "addr 0x%02x, kind %d\n",
-                                               adap_id, forces[kind][i + 1],
-                                               kind);
-                                       temp_client->addr = forces[kind][i + 1];
-                                       err = i2c_detect_address(temp_client,
-                                               kind, driver);
-                                       if (err)
-                                               goto exit_free;
-                               }
-                       }
-               }
-       }
-
        /* Stop here if the classes do not match */
        if (!(adapter->class & driver->class))
                goto exit_free;
 
        /* Stop here if we can't use SMBUS_QUICK */
        if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_QUICK)) {
-               if (address_data->probe[0] == I2C_CLIENT_END
-                && address_data->normal_i2c[0] == I2C_CLIENT_END)
+               if (address_data->normal_i2c[0] == I2C_CLIENT_END)
                        goto exit_free;
 
                dev_warn(&adapter->dev, "SMBus Quick command not supported, "
@@ -1301,48 +1244,12 @@ static int i2c_detect(struct i2c_adapter *adapter, struct i2c_driver *driver)
                goto exit_free;
        }
 
-       /* Probe entries are done second, and are not affected by ignore
-          entries either */
-       for (i = 0; address_data->probe[i] != I2C_CLIENT_END; i += 2) {
-               if (address_data->probe[i] == adap_id
-                || address_data->probe[i] == ANY_I2C_BUS) {
-                       dev_dbg(&adapter->dev, "found probe parameter for "
-                               "adapter %d, addr 0x%02x\n", adap_id,
-                               address_data->probe[i + 1]);
-                       temp_client->addr = address_data->probe[i + 1];
-                       err = i2c_detect_address(temp_client, -1, driver);
-                       if (err)
-                               goto exit_free;
-               }
-       }
-
-       /* Normal entries are done last, unless shadowed by an ignore entry */
        for (i = 0; address_data->normal_i2c[i] != I2C_CLIENT_END; i += 1) {
-               int j, ignore;
-
-               ignore = 0;
-               for (j = 0; address_data->ignore[j] != I2C_CLIENT_END;
-                    j += 2) {
-                       if ((address_data->ignore[j] == adap_id ||
-                            address_data->ignore[j] == ANY_I2C_BUS)
-                        && address_data->ignore[j + 1]
-                           == address_data->normal_i2c[i]) {
-                               dev_dbg(&adapter->dev, "found ignore "
-                                       "parameter for adapter %d, "
-                                       "addr 0x%02x\n", adap_id,
-                                       address_data->ignore[j + 1]);
-                               ignore = 1;
-                               break;
-                       }
-               }
-               if (ignore)
-                       continue;
-
                dev_dbg(&adapter->dev, "found normal entry for adapter %d, "
                        "addr 0x%02x\n", adap_id,
                        address_data->normal_i2c[i]);
                temp_client->addr = address_data->normal_i2c[i];
-               err = i2c_detect_address(temp_client, -1, driver);
+               err = i2c_detect_address(temp_client, driver);
                if (err)
                        goto exit_free;
        }
@@ -1913,7 +1820,7 @@ s32 i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, unsigned short flags,
        flags &= I2C_M_TEN | I2C_CLIENT_PEC;
 
        if (adapter->algo->smbus_xfer) {
-               mutex_lock(&adapter->bus_lock);
+               rt_mutex_lock(&adapter->bus_lock);
 
                /* Retry automatically on arbitration loss */
                orig_jiffies = jiffies;
@@ -1927,7 +1834,7 @@ s32 i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, unsigned short flags,
                                       orig_jiffies + adapter->timeout))
                                break;
                }
-               mutex_unlock(&adapter->bus_lock);
+               rt_mutex_unlock(&adapter->bus_lock);
        } else
                res = i2c_smbus_xfer_emulated(adapter,addr,flags,read_write,
                                              command, protocol, data);
index 7e13d2d..f4110aa 100644 (file)
@@ -34,7 +34,6 @@
 #include <linux/list.h>
 #include <linux/i2c.h>
 #include <linux/i2c-dev.h>
-#include <linux/smp_lock.h>
 #include <linux/jiffies.h>
 #include <asm/uaccess.h>
 
@@ -445,20 +444,14 @@ static int i2cdev_open(struct inode *inode, struct file *file)
        struct i2c_client *client;
        struct i2c_adapter *adap;
        struct i2c_dev *i2c_dev;
-       int ret = 0;
 
-       lock_kernel();
        i2c_dev = i2c_dev_get_by_minor(minor);
-       if (!i2c_dev) {
-               ret = -ENODEV;
-               goto out;
-       }
+       if (!i2c_dev)
+               return -ENODEV;
 
        adap = i2c_get_adapter(i2c_dev->adap->nr);
-       if (!adap) {
-               ret = -ENODEV;
-               goto out;
-       }
+       if (!adap)
+               return -ENODEV;
 
        /* This creates an anonymous i2c_client, which may later be
         * pointed to some address using I2C_SLAVE or I2C_SLAVE_FORCE.
@@ -470,8 +463,7 @@ static int i2cdev_open(struct inode *inode, struct file *file)
        client = kzalloc(sizeof(*client), GFP_KERNEL);
        if (!client) {
                i2c_put_adapter(adap);
-               ret = -ENOMEM;
-               goto out;
+               return -ENOMEM;
        }
        snprintf(client->name, I2C_NAME_SIZE, "i2c-dev %d", adap->nr);
        client->driver = &i2cdev_driver;
@@ -479,9 +471,7 @@ static int i2cdev_open(struct inode *inode, struct file *file)
        client->adapter = adap;
        file->private_data = client;
 
-out:
-       unlock_kernel();
-       return ret;
+       return 0;
 }
 
 static int i2cdev_release(struct inode *inode, struct file *file)
index 39d4e01..a743e68 100644 (file)
@@ -162,9 +162,10 @@ static const struct pci_device_id generic_pci_tbl[] = {
 #ifdef CONFIG_BLK_DEV_IDE_SATA
        { PCI_VDEVICE(VIA,      PCI_DEVICE_ID_VIA_8237_SATA),            5 },
 #endif
-       { PCI_VDEVICE(TOSHIBA,  PCI_DEVICE_ID_TOSHIBA_PICCOLO),          4 },
        { PCI_VDEVICE(TOSHIBA,  PCI_DEVICE_ID_TOSHIBA_PICCOLO_1),        4 },
        { PCI_VDEVICE(TOSHIBA,  PCI_DEVICE_ID_TOSHIBA_PICCOLO_2),        4 },
+       { PCI_VDEVICE(TOSHIBA,  PCI_DEVICE_ID_TOSHIBA_PICCOLO_3),        4 },
+       { PCI_VDEVICE(TOSHIBA,  PCI_DEVICE_ID_TOSHIBA_PICCOLO_5),        4 },
        { PCI_VDEVICE(NETCELL,  PCI_DEVICE_ID_REVOLUTION),               6 },
        /*
         * Must come last.  If you add entries adjust
index 65c1429..d0dc1db 100644 (file)
@@ -82,6 +82,7 @@
  *
  */
 
+#include <linux/bitops.h>
 #include <linux/kernel.h>
 #include <linux/list.h>
 #include <linux/slab.h>
@@ -434,7 +435,6 @@ static void initialize_dma_trm_ctx(struct dma_trm_ctx *d)
 /* Count the number of available iso contexts */
 static int get_nb_iso_ctx(struct ti_ohci *ohci, int reg)
 {
-       int i,ctx=0;
        u32 tmp;
 
        reg_write(ohci, reg, 0xffffffff);
@@ -443,11 +443,7 @@ static int get_nb_iso_ctx(struct ti_ohci *ohci, int reg)
        DBGMSG("Iso contexts reg: %08x implemented: %08x", reg, tmp);
 
        /* Count the number of contexts */
-       for (i=0; i<32; i++) {
-               if (tmp & 1) ctx++;
-               tmp >>= 1;
-       }
-       return ctx;
+       return hweight32(tmp);
 }
 
 /* Global initialization */
index bba85ad..1a494d5 100644 (file)
 #include <linux/mutex.h>
 #include <linux/errno.h>
 #include <mach/gpio.h>
-#include <mach/keypad.h>
-#include <mach/menelaus.h>
+#include <plat/keypad.h>
+#include <plat/menelaus.h>
 #include <asm/irq.h>
 #include <mach/hardware.h>
 #include <asm/io.h>
-#include <mach/mux.h>
+#include <plat/mux.h>
 
 #undef NEW_BOARD_LEARNING_MODE
 
index 4460507..b982603 100644 (file)
@@ -12,7 +12,7 @@
 #include <linux/init.h>
 #include <linux/platform_device.h>
 #include <linux/leds.h>
-#include <mach/board-ams-delta.h>
+#include <plat/board-ams-delta.h>
 
 /*
  * Our context
index 5d91362..1f7c10f 100644 (file)
@@ -44,7 +44,7 @@ static void locomoled_brightness_set1(struct led_classdev *led_cdev,
 
 static struct led_classdev locomo_led0 = {
        .name                   = "locomo:amber:charge",
-       .default_trigger        = "sharpsl-charge",
+       .default_trigger        = "main-battery-charging",
        .brightness_set         = locomoled_brightness_set0,
 };
 
index cc9f275..7b4ef5b 100644 (file)
@@ -27,54 +27,49 @@ static int mouse_last_keycode;
 /* file(s) in /proc/sys/dev/mac_hid */
 static ctl_table mac_hid_files[] = {
        {
-               .ctl_name       = DEV_MAC_HID_MOUSE_BUTTON_EMULATION,
                .procname       = "mouse_button_emulation",
                .data           = &mouse_emulate_buttons,
                .maxlen         = sizeof(int),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec,
+               .proc_handler   = proc_dointvec,
        },
        {
-               .ctl_name       = DEV_MAC_HID_MOUSE_BUTTON2_KEYCODE,
                .procname       = "mouse_button2_keycode",
                .data           = &mouse_button2_keycode,
                .maxlen         = sizeof(int),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec,
+               .proc_handler   = proc_dointvec,
        },
        {
-               .ctl_name       = DEV_MAC_HID_MOUSE_BUTTON3_KEYCODE,
                .procname       = "mouse_button3_keycode",
                .data           = &mouse_button3_keycode,
                .maxlen         = sizeof(int),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec,
+               .proc_handler   = proc_dointvec,
        },
-       { .ctl_name = 0 }
+       { }
 };
 
 /* dir in /proc/sys/dev */
 static ctl_table mac_hid_dir[] = {
        {
-               .ctl_name       = DEV_MAC_HID,
                .procname       = "mac_hid",
                .maxlen         = 0,
                .mode           = 0555,
                .child          = mac_hid_files,
        },
-       { .ctl_name = 0 }
+       { }
 };
 
 /* /proc/sys/dev itself, in case that is not there yet */
 static ctl_table mac_hid_root_dir[] = {
        {
-               .ctl_name       = CTL_DEV,
                .procname       = "dev",
                .maxlen         = 0,
                .mode           = 0555,
                .child          = mac_hid_dir,
        },
-       { .ctl_name = 0 }
+       { }
 };
 
 static struct ctl_table_header *mac_hid_sysctl_header;
index b182f86..5f154ef 100644 (file)
@@ -98,44 +98,40 @@ static struct ctl_table_header *raid_table_header;
 
 static ctl_table raid_table[] = {
        {
-               .ctl_name       = DEV_RAID_SPEED_LIMIT_MIN,
                .procname       = "speed_limit_min",
                .data           = &sysctl_speed_limit_min,
                .maxlen         = sizeof(int),
                .mode           = S_IRUGO|S_IWUSR,
-               .proc_handler   = &proc_dointvec,
+               .proc_handler   = proc_dointvec,
        },
        {
-               .ctl_name       = DEV_RAID_SPEED_LIMIT_MAX,
                .procname       = "speed_limit_max",
                .data           = &sysctl_speed_limit_max,
                .maxlen         = sizeof(int),
                .mode           = S_IRUGO|S_IWUSR,
-               .proc_handler   = &proc_dointvec,
+               .proc_handler   = proc_dointvec,
        },
-       { .ctl_name = 0 }
+       { }
 };
 
 static ctl_table raid_dir_table[] = {
        {
-               .ctl_name       = DEV_RAID,
                .procname       = "raid",
                .maxlen         = 0,
                .mode           = S_IRUGO|S_IXUGO,
                .child          = raid_table,
        },
-       { .ctl_name = 0 }
+       { }
 };
 
 static ctl_table raid_root_table[] = {
        {
-               .ctl_name       = CTL_DEV,
                .procname       = "dev",
                .maxlen         = 0,
                .mode           = 0555,
                .child          = raid_dir_table,
        },
-       { .ctl_name = 0 }
+       {  }
 };
 
 static const struct block_device_operations md_fops;
index a87a477..b134553 100644 (file)
@@ -195,6 +195,24 @@ config RADIO_MAESTRO
          To compile this driver as a module, choose M here: the
          module will be called radio-maestro.
 
+config RADIO_MIROPCM20
+       tristate "miroSOUND PCM20 radio"
+       depends on ISA && VIDEO_V4L2
+       select SND_MIRO
+       ---help---
+         Choose Y here if you have this FM radio card. You also need to enable
+         the ALSA sound system. This choice automatically selects the ALSA
+         sound card driver "Miro miroSOUND PCM1pro/PCM12/PCM20radio" as this
+         is required for the radio-miropcm20.
+
+         In order to control your radio card, you will need to use programs
+         that are compatible with the Video For Linux API.  Information on
+         this API and pointers to "v4l" programs may be found at
+         <file:Documentation/video4linux/API.html>.
+
+         To compile this driver as a module, choose M here: the
+         module will be called radio-miropcm20.
+
 config RADIO_SF16FMI
        tristate "SF16FMI Radio"
        depends on ISA && VIDEO_V4L2
index 2a1be3b..8a63d54 100644 (file)
@@ -18,6 +18,7 @@ obj-$(CONFIG_RADIO_TRUST) += radio-trust.o
 obj-$(CONFIG_I2C_SI4713) += si4713-i2c.o
 obj-$(CONFIG_RADIO_SI4713) += radio-si4713.o
 obj-$(CONFIG_RADIO_MAESTRO) += radio-maestro.o
+obj-$(CONFIG_RADIO_MIROPCM20) += radio-miropcm20.o
 obj-$(CONFIG_USB_DSBR) += dsbr100.o
 obj-$(CONFIG_RADIO_SI470X) += si470x/
 obj-$(CONFIG_USB_MR800) += radio-mr800.o
diff --git a/drivers/media/radio/radio-miropcm20.c b/drivers/media/radio/radio-miropcm20.c
new file mode 100644 (file)
index 0000000..4ff8854
--- /dev/null
@@ -0,0 +1,270 @@
+/* Miro PCM20 radio driver for Linux radio support
+ * (c) 1998 Ruurd Reitsma <R.A.Reitsma@wbmt.tudelft.nl>
+ * Thanks to Norberto Pellici for the ACI device interface specification
+ * The API part is based on the radiotrack driver by M. Kirkwood
+ * This driver relies on the aci mixer provided by the snd-miro
+ * ALSA driver.
+ * Look there for further info...
+ */
+
+/* What ever you think about the ACI, version 0x07 is not very well!
+ * I can't get frequency, 'tuner status', 'tuner flags' or mute/mono
+ * conditions...                Robert
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <sound/aci.h>
+
+static int radio_nr = -1;
+module_param(radio_nr, int, 0);
+MODULE_PARM_DESC(radio_nr, "Set radio device number (/dev/radioX).  Default: -1 (autodetect)");
+
+static int mono;
+module_param(mono, bool, 0);
+MODULE_PARM_DESC(mono, "Force tuner into mono mode.");
+
+struct pcm20 {
+       struct v4l2_device v4l2_dev;
+       struct video_device vdev;
+       unsigned long freq;
+       int muted;
+       struct snd_miro_aci *aci;
+};
+
+static struct pcm20 pcm20_card = {
+       .freq   = 87*16000,
+       .muted  = 1,
+};
+
+static int pcm20_mute(struct pcm20 *dev, unsigned char mute)
+{
+       dev->muted = mute;
+       return snd_aci_cmd(dev->aci, ACI_SET_TUNERMUTE, mute, -1);
+}
+
+static int pcm20_stereo(struct pcm20 *dev, unsigned char stereo)
+{
+       return snd_aci_cmd(dev->aci, ACI_SET_TUNERMONO, !stereo, -1);
+}
+
+static int pcm20_setfreq(struct pcm20 *dev, unsigned long freq)
+{
+       unsigned char freql;
+       unsigned char freqh;
+       struct snd_miro_aci *aci = dev->aci;
+
+       dev->freq = freq;
+
+       freq /= 160;
+       if (!(aci->aci_version == 0x07 || aci->aci_version >= 0xb0))
+               freq /= 10;  /* I don't know exactly which version
+                             * needs this hack */
+       freql = freq & 0xff;
+       freqh = freq >> 8;
+
+       pcm20_stereo(dev, !mono);
+       return snd_aci_cmd(aci, ACI_WRITE_TUNE, freql, freqh);
+}
+
+static const struct v4l2_file_operations pcm20_fops = {
+       .owner          = THIS_MODULE,
+       .ioctl          = video_ioctl2,
+};
+
+static int vidioc_querycap(struct file *file, void *priv,
+                               struct v4l2_capability *v)
+{
+       strlcpy(v->driver, "Miro PCM20", sizeof(v->driver));
+       strlcpy(v->card, "Miro PCM20", sizeof(v->card));
+       strlcpy(v->bus_info, "ISA", sizeof(v->bus_info));
+       v->version = 0x1;
+       v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
+       return 0;
+}
+
+static int vidioc_g_tuner(struct file *file, void *priv,
+                               struct v4l2_tuner *v)
+{
+       if (v->index)   /* Only 1 tuner */
+               return -EINVAL;
+       strlcpy(v->name, "FM", sizeof(v->name));
+       v->type = V4L2_TUNER_RADIO;
+       v->rangelow = 87*16000;
+       v->rangehigh = 108*16000;
+       v->signal = 0xffff;
+       v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
+       v->capability = V4L2_TUNER_CAP_LOW;
+       v->audmode = V4L2_TUNER_MODE_MONO;
+       return 0;
+}
+
+static int vidioc_s_tuner(struct file *file, void *priv,
+                               struct v4l2_tuner *v)
+{
+       return v->index ? -EINVAL : 0;
+}
+
+static int vidioc_g_frequency(struct file *file, void *priv,
+                               struct v4l2_frequency *f)
+{
+       struct pcm20 *dev = video_drvdata(file);
+
+       if (f->tuner != 0)
+               return -EINVAL;
+
+       f->type = V4L2_TUNER_RADIO;
+       f->frequency = dev->freq;
+       return 0;
+}
+
+
+static int vidioc_s_frequency(struct file *file, void *priv,
+                               struct v4l2_frequency *f)
+{
+       struct pcm20 *dev = video_drvdata(file);
+
+       if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO)
+               return -EINVAL;
+
+       dev->freq = f->frequency;
+       pcm20_setfreq(dev, f->frequency);
+       return 0;
+}
+
+static int vidioc_queryctrl(struct file *file, void *priv,
+                               struct v4l2_queryctrl *qc)
+{
+       switch (qc->id) {
+       case V4L2_CID_AUDIO_MUTE:
+               return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1);
+       }
+       return -EINVAL;
+}
+
+static int vidioc_g_ctrl(struct file *file, void *priv,
+                               struct v4l2_control *ctrl)
+{
+       struct pcm20 *dev = video_drvdata(file);
+
+       switch (ctrl->id) {
+       case V4L2_CID_AUDIO_MUTE:
+               ctrl->value = dev->muted;
+               break;
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static int vidioc_s_ctrl(struct file *file, void *priv,
+                               struct v4l2_control *ctrl)
+{
+       struct pcm20 *dev = video_drvdata(file);
+
+       switch (ctrl->id) {
+       case V4L2_CID_AUDIO_MUTE:
+               pcm20_mute(dev, ctrl->value);
+               break;
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
+{
+       *i = 0;
+       return 0;
+}
+
+static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
+{
+       return i ? -EINVAL : 0;
+}
+
+static int vidioc_g_audio(struct file *file, void *priv,
+                               struct v4l2_audio *a)
+{
+       a->index = 0;
+       strlcpy(a->name, "Radio", sizeof(a->name));
+       a->capability = V4L2_AUDCAP_STEREO;
+       return 0;
+}
+
+static int vidioc_s_audio(struct file *file, void *priv,
+                               struct v4l2_audio *a)
+{
+       return a->index ? -EINVAL : 0;
+}
+
+static const struct v4l2_ioctl_ops pcm20_ioctl_ops = {
+       .vidioc_querycap    = vidioc_querycap,
+       .vidioc_g_tuner     = vidioc_g_tuner,
+       .vidioc_s_tuner     = vidioc_s_tuner,
+       .vidioc_g_frequency = vidioc_g_frequency,
+       .vidioc_s_frequency = vidioc_s_frequency,
+       .vidioc_queryctrl   = vidioc_queryctrl,
+       .vidioc_g_ctrl      = vidioc_g_ctrl,
+       .vidioc_s_ctrl      = vidioc_s_ctrl,
+       .vidioc_g_audio     = vidioc_g_audio,
+       .vidioc_s_audio     = vidioc_s_audio,
+       .vidioc_g_input     = vidioc_g_input,
+       .vidioc_s_input     = vidioc_s_input,
+};
+
+static int __init pcm20_init(void)
+{
+       struct pcm20 *dev = &pcm20_card;
+       struct v4l2_device *v4l2_dev = &dev->v4l2_dev;
+       int res;
+
+       dev->aci = snd_aci_get_aci();
+       if (dev->aci == NULL) {
+               v4l2_err(v4l2_dev,
+                        "you must load the snd-miro driver first!\n");
+               return -ENODEV;
+       }
+       strlcpy(v4l2_dev->name, "miropcm20", sizeof(v4l2_dev->name));
+
+
+       res = v4l2_device_register(NULL, v4l2_dev);
+       if (res < 0) {
+               v4l2_err(v4l2_dev, "could not register v4l2_device\n");
+               return -EINVAL;
+       }
+
+       strlcpy(dev->vdev.name, v4l2_dev->name, sizeof(dev->vdev.name));
+       dev->vdev.v4l2_dev = v4l2_dev;
+       dev->vdev.fops = &pcm20_fops;
+       dev->vdev.ioctl_ops = &pcm20_ioctl_ops;
+       dev->vdev.release = video_device_release_empty;
+       video_set_drvdata(&dev->vdev, dev);
+
+       if (video_register_device(&dev->vdev, VFL_TYPE_RADIO, radio_nr) < 0)
+               goto fail;
+
+       v4l2_info(v4l2_dev, "Mirosound PCM20 Radio tuner\n");
+       return 0;
+fail:
+       v4l2_device_unregister(v4l2_dev);
+       return -EINVAL;
+}
+
+MODULE_AUTHOR("Ruurd Reitsma, Krzysztof Helt");
+MODULE_DESCRIPTION("A driver for the Miro PCM20 radio card.");
+MODULE_LICENSE("GPL");
+
+static void __exit pcm20_cleanup(void)
+{
+       struct pcm20 *dev = &pcm20_card;
+
+       video_unregister_device(&dev->vdev);
+       v4l2_device_unregister(&dev->v4l2_dev);
+}
+
+module_init(pcm20_init);
+module_exit(pcm20_cleanup);
index 570be13..08f2d07 100644 (file)
@@ -121,6 +121,12 @@ config TWL4030_POWER
          and load scripts controling which resources are switched off/on
          or reset when a sleep, wakeup or warm reset event occurs.
 
+config TWL4030_CODEC
+       bool
+       depends on TWL4030_CORE
+       select MFD_CORE
+       default n
+
 config MFD_TMIO
        bool
        default n
index f3b277b..af0fc90 100644 (file)
@@ -26,6 +26,7 @@ obj-$(CONFIG_MENELAUS)                += menelaus.o
 
 obj-$(CONFIG_TWL4030_CORE)     += twl4030-core.o twl4030-irq.o
 obj-$(CONFIG_TWL4030_POWER)    += twl4030-power.o
+obj-$(CONFIG_TWL4030_CODEC)    += twl4030-codec.o
 
 obj-$(CONFIG_MFD_MC13783)      += mc13783-core.o
 
index 57271cb..84815f9 100644 (file)
 #include <linux/device.h>
 #include <linux/slab.h>
 #include <linux/string.h>
+#include <linux/mfd/mcp.h>
 
 #include <mach/dma.h>
 #include <asm/system.h>
 
-#include "mcp.h"
 
 #define to_mcp(d)              container_of(d, struct mcp, attached_device)
 #define to_mcp_driver(d)       container_of(d, struct mcp_driver, drv)
index 62b32da..2584272 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/spinlock.h>
 #include <linux/slab.h>
 #include <linux/platform_device.h>
+#include <linux/mfd/mcp.h>
 
 #include <mach/dma.h>
 #include <mach/hardware.h>
@@ -28,7 +29,6 @@
 
 #include <mach/assabet.h>
 
-#include "mcp.h"
 
 struct mcp_sa11x0 {
        u32     mccr0;
@@ -163,6 +163,7 @@ static int mcp_sa11x0_probe(struct platform_device *pdev)
        mcp->dma_audio_wr       = DMA_Ser4MCP0Wr;
        mcp->dma_telco_rd       = DMA_Ser4MCP1Rd;
        mcp->dma_telco_wr       = DMA_Ser4MCP1Wr;
+       mcp->gpio_base          = data->gpio_base;
 
        platform_set_drvdata(pdev, mcp);
 
index 4b364ba..970afa1 100644 (file)
@@ -44,7 +44,7 @@
 #include <asm/mach/irq.h>
 
 #include <mach/gpio.h>
-#include <mach/menelaus.h>
+#include <plat/menelaus.h>
 
 #define DRIVER_NAME                    "menelaus"
 
diff --git a/drivers/mfd/twl4030-codec.c b/drivers/mfd/twl4030-codec.c
new file mode 100644 (file)
index 0000000..77b9149
--- /dev/null
@@ -0,0 +1,276 @@
+/*
+ * MFD driver for twl4030 codec submodule
+ *
+ * Author:     Peter Ujfalusi <peter.ujfalusi@nokia.com>
+ *
+ * Copyright:   (C) 2009 Nokia Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/platform_device.h>
+#include <linux/i2c/twl4030.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/twl4030-codec.h>
+
+#define TWL4030_CODEC_CELLS    2
+
+static struct platform_device *twl4030_codec_dev;
+
+struct twl4030_codec_resource {
+       int request_count;
+       u8 reg;
+       u8 mask;
+};
+
+struct twl4030_codec {
+       unsigned int audio_mclk;
+       struct mutex mutex;
+       struct twl4030_codec_resource resource[TWL4030_CODEC_RES_MAX];
+       struct mfd_cell cells[TWL4030_CODEC_CELLS];
+};
+
+/*
+ * Modify the resource, the function returns the content of the register
+ * after the modification.
+ */
+static int twl4030_codec_set_resource(enum twl4030_codec_res id, int enable)
+{
+       struct twl4030_codec *codec = platform_get_drvdata(twl4030_codec_dev);
+       u8 val;
+
+       twl4030_i2c_read_u8(TWL4030_MODULE_AUDIO_VOICE, &val,
+                       codec->resource[id].reg);
+
+       if (enable)
+               val |= codec->resource[id].mask;
+       else
+               val &= ~codec->resource[id].mask;
+
+       twl4030_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE,
+                                       val, codec->resource[id].reg);
+
+       return val;
+}
+
+static inline int twl4030_codec_get_resource(enum twl4030_codec_res id)
+{
+       struct twl4030_codec *codec = platform_get_drvdata(twl4030_codec_dev);
+       u8 val;
+
+       twl4030_i2c_read_u8(TWL4030_MODULE_AUDIO_VOICE, &val,
+                       codec->resource[id].reg);
+
+       return val;
+}
+
+/*
+ * Enable the resource.
+ * The function returns with error or the content of the register
+ */
+int twl4030_codec_enable_resource(enum twl4030_codec_res id)
+{
+       struct twl4030_codec *codec = platform_get_drvdata(twl4030_codec_dev);
+       int val;
+
+       if (id >= TWL4030_CODEC_RES_MAX) {
+               dev_err(&twl4030_codec_dev->dev,
+                               "Invalid resource ID (%u)\n", id);
+               return -EINVAL;
+       }
+
+       mutex_lock(&codec->mutex);
+       if (!codec->resource[id].request_count)
+               /* Resource was disabled, enable it */
+               val = twl4030_codec_set_resource(id, 1);
+       else
+               val = twl4030_codec_get_resource(id);
+
+       codec->resource[id].request_count++;
+       mutex_unlock(&codec->mutex);
+
+       return val;
+}
+EXPORT_SYMBOL_GPL(twl4030_codec_enable_resource);
+
+/*
+ * Disable the resource.
+ * The function returns with error or the content of the register
+ */
+int twl4030_codec_disable_resource(unsigned id)
+{
+       struct twl4030_codec *codec = platform_get_drvdata(twl4030_codec_dev);
+       int val;
+
+       if (id >= TWL4030_CODEC_RES_MAX) {
+               dev_err(&twl4030_codec_dev->dev,
+                               "Invalid resource ID (%u)\n", id);
+               return -EINVAL;
+       }
+
+       mutex_lock(&codec->mutex);
+       if (!codec->resource[id].request_count) {
+               dev_err(&twl4030_codec_dev->dev,
+                       "Resource has been disabled already (%u)\n", id);
+               mutex_unlock(&codec->mutex);
+               return -EPERM;
+       }
+       codec->resource[id].request_count--;
+
+       if (!codec->resource[id].request_count)
+               /* Resource can be disabled now */
+               val = twl4030_codec_set_resource(id, 0);
+       else
+               val = twl4030_codec_get_resource(id);
+
+       mutex_unlock(&codec->mutex);
+
+       return val;
+}
+EXPORT_SYMBOL_GPL(twl4030_codec_disable_resource);
+
+unsigned int twl4030_codec_get_mclk(void)
+{
+       struct twl4030_codec *codec = platform_get_drvdata(twl4030_codec_dev);
+
+       return codec->audio_mclk;
+}
+EXPORT_SYMBOL_GPL(twl4030_codec_get_mclk);
+
+static int __devinit twl4030_codec_probe(struct platform_device *pdev)
+{
+       struct twl4030_codec *codec;
+       struct twl4030_codec_data *pdata = pdev->dev.platform_data;
+       struct mfd_cell *cell = NULL;
+       int ret, childs = 0;
+       u8 val;
+
+       if (!pdata) {
+               dev_err(&pdev->dev, "Platform data is missing\n");
+               return -EINVAL;
+       }
+
+       /* Configure APLL_INFREQ and disable APLL if enabled */
+       val = 0;
+       switch (pdata->audio_mclk) {
+       case 19200000:
+               val |= TWL4030_APLL_INFREQ_19200KHZ;
+               break;
+       case 26000000:
+               val |= TWL4030_APLL_INFREQ_26000KHZ;
+               break;
+       case 38400000:
+               val |= TWL4030_APLL_INFREQ_38400KHZ;
+               break;
+       default:
+               dev_err(&pdev->dev, "Invalid audio_mclk\n");
+               return -EINVAL;
+       }
+       twl4030_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE,
+                                       val, TWL4030_REG_APLL_CTL);
+
+       codec = kzalloc(sizeof(struct twl4030_codec), GFP_KERNEL);
+       if (!codec)
+               return -ENOMEM;
+
+       platform_set_drvdata(pdev, codec);
+
+       twl4030_codec_dev = pdev;
+       mutex_init(&codec->mutex);
+       codec->audio_mclk = pdata->audio_mclk;
+
+       /* Codec power */
+       codec->resource[TWL4030_CODEC_RES_POWER].reg = TWL4030_REG_CODEC_MODE;
+       codec->resource[TWL4030_CODEC_RES_POWER].mask = TWL4030_CODECPDZ;
+
+       /* PLL */
+       codec->resource[TWL4030_CODEC_RES_APLL].reg = TWL4030_REG_APLL_CTL;
+       codec->resource[TWL4030_CODEC_RES_APLL].mask = TWL4030_APLL_EN;
+
+       if (pdata->audio) {
+               cell = &codec->cells[childs];
+               cell->name = "twl4030_codec_audio";
+               cell->platform_data = pdata->audio;
+               cell->data_size = sizeof(*pdata->audio);
+               childs++;
+       }
+       if (pdata->vibra) {
+               cell = &codec->cells[childs];
+               cell->name = "twl4030_codec_vibra";
+               cell->platform_data = pdata->vibra;
+               cell->data_size = sizeof(*pdata->vibra);
+               childs++;
+       }
+
+       if (childs)
+               ret = mfd_add_devices(&pdev->dev, pdev->id, codec->cells,
+                                     childs, NULL, 0);
+       else {
+               dev_err(&pdev->dev, "No platform data found for childs\n");
+               ret = -ENODEV;
+       }
+
+       if (!ret)
+               return 0;
+
+       platform_set_drvdata(pdev, NULL);
+       kfree(codec);
+       twl4030_codec_dev = NULL;
+       return ret;
+}
+
+static int __devexit twl4030_codec_remove(struct platform_device *pdev)
+{
+       struct twl4030_codec *codec = platform_get_drvdata(pdev);
+
+       mfd_remove_devices(&pdev->dev);
+       platform_set_drvdata(pdev, NULL);
+       kfree(codec);
+       twl4030_codec_dev = NULL;
+
+       return 0;
+}
+
+MODULE_ALIAS("platform:twl4030_codec");
+
+static struct platform_driver twl4030_codec_driver = {
+       .probe          = twl4030_codec_probe,
+       .remove         = __devexit_p(twl4030_codec_remove),
+       .driver         = {
+               .owner  = THIS_MODULE,
+               .name   = "twl4030_codec",
+       },
+};
+
+static int __devinit twl4030_codec_init(void)
+{
+       return platform_driver_register(&twl4030_codec_driver);
+}
+module_init(twl4030_codec_init);
+
+static void __devexit twl4030_codec_exit(void)
+{
+       platform_driver_unregister(&twl4030_codec_driver);
+}
+module_exit(twl4030_codec_exit);
+
+MODULE_AUTHOR("Peter Ujfalusi <peter.ujfalusi@nokia.com>");
+MODULE_LICENSE("GPL");
+
index a1c47ee..40449cd 100644 (file)
@@ -39,7 +39,7 @@
 #include <linux/i2c/twl4030.h>
 
 #if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3)
-#include <mach/cpu.h>
+#include <plat/cpu.h>
 #endif
 
 /*
 #define twl_has_watchdog()        false
 #endif
 
+#if defined(CONFIG_TWL4030_CODEC) || defined(CONFIG_TWL4030_CODEC_MODULE)
+#define twl_has_codec()        true
+#else
+#define twl_has_codec()        false
+#endif
+
 /* Triton Core internal information (BEGIN) */
 
 /* Last - for index max*/
@@ -601,6 +607,14 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features)
                        return PTR_ERR(child);
        }
 
+       if (twl_has_codec() && pdata->codec) {
+               child = add_child(1, "twl4030_codec",
+                               pdata->codec, sizeof(*pdata->codec),
+                               false, 0, 0);
+               if (IS_ERR(child))
+                       return PTR_ERR(child);
+       }
+
        if (twl_has_regulator()) {
                /*
                child = add_regulator(TWL4030_REG_VPLL1, pdata->vpll1);
@@ -763,7 +777,7 @@ static int twl4030_remove(struct i2c_client *client)
 }
 
 /* NOTE:  this driver only handles a single twl4030/tps659x0 chip */
-static int
+static int __init
 twl4030_probe(struct i2c_client *client, const struct i2c_device_id *id)
 {
        int                             status;
index 86fed48..cea9da6 100644 (file)
 #include <linux/fs.h>
 #include <linux/proc_fs.h>
 #include <linux/device.h>
+#include <linux/mfd/ucb1x00.h>
 
 #include <mach/dma.h>
 
-#include "ucb1x00.h"
 
 #define UCB1X00_ATTR(name,input)\
 static ssize_t name##_show(struct device *dev, struct device_attribute *attr, \
index 60c3988..252b741 100644 (file)
 #include <linux/interrupt.h>
 #include <linux/device.h>
 #include <linux/mutex.h>
+#include <linux/mfd/ucb1x00.h>
+#include <linux/gpio.h>
 
 #include <mach/dma.h>
 #include <mach/hardware.h>
 
-#include "ucb1x00.h"
-
 static DEFINE_MUTEX(ucb1x00_mutex);
 static LIST_HEAD(ucb1x00_drivers);
 static LIST_HEAD(ucb1x00_devices);
@@ -108,6 +108,60 @@ unsigned int ucb1x00_io_read(struct ucb1x00 *ucb)
        return ucb1x00_reg_read(ucb, UCB_IO_DATA);
 }
 
+static void ucb1x00_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
+{
+       struct ucb1x00 *ucb = container_of(chip, struct ucb1x00, gpio);
+       unsigned long flags;
+
+       spin_lock_irqsave(&ucb->io_lock, flags);
+       if (value)
+               ucb->io_out |= 1 << offset;
+       else
+               ucb->io_out &= ~(1 << offset);
+
+       ucb1x00_reg_write(ucb, UCB_IO_DATA, ucb->io_out);
+       spin_unlock_irqrestore(&ucb->io_lock, flags);
+}
+
+static int ucb1x00_gpio_get(struct gpio_chip *chip, unsigned offset)
+{
+       struct ucb1x00 *ucb = container_of(chip, struct ucb1x00, gpio);
+       return ucb1x00_reg_read(ucb, UCB_IO_DATA) & (1 << offset);
+}
+
+static int ucb1x00_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
+{
+       struct ucb1x00 *ucb = container_of(chip, struct ucb1x00, gpio);
+       unsigned long flags;
+
+       spin_lock_irqsave(&ucb->io_lock, flags);
+       ucb->io_dir &= ~(1 << offset);
+       ucb1x00_reg_write(ucb, UCB_IO_DIR, ucb->io_dir);
+       spin_unlock_irqrestore(&ucb->io_lock, flags);
+
+       return 0;
+}
+
+static int ucb1x00_gpio_direction_output(struct gpio_chip *chip, unsigned offset
+               , int value)
+{
+       struct ucb1x00 *ucb = container_of(chip, struct ucb1x00, gpio);
+       unsigned long flags;
+
+       spin_lock_irqsave(&ucb->io_lock, flags);
+       ucb->io_dir |= (1 << offset);
+       ucb1x00_reg_write(ucb, UCB_IO_DIR, ucb->io_dir);
+
+       if (value)
+               ucb->io_out |= 1 << offset;
+       else
+               ucb->io_out &= ~(1 << offset);
+       ucb1x00_reg_write(ucb, UCB_IO_DATA, ucb->io_out);
+       spin_unlock_irqrestore(&ucb->io_lock, flags);
+
+       return 0;
+}
+
 /*
  * UCB1300 data sheet says we must:
  *  1. enable ADC      => 5us (including reference startup time)
@@ -476,6 +530,7 @@ static int ucb1x00_probe(struct mcp *mcp)
        struct ucb1x00_driver *drv;
        unsigned int id;
        int ret = -ENODEV;
+       int temp;
 
        mcp_enable(mcp);
        id = mcp_reg_read(mcp, UCB_ID);
@@ -508,12 +563,27 @@ static int ucb1x00_probe(struct mcp *mcp)
                goto err_free;
        }
 
+       ucb->gpio.base = -1;
+       if (mcp->gpio_base != 0) {
+               ucb->gpio.label = dev_name(&ucb->dev);
+               ucb->gpio.base = mcp->gpio_base;
+               ucb->gpio.ngpio = 10;
+               ucb->gpio.set = ucb1x00_gpio_set;
+               ucb->gpio.get = ucb1x00_gpio_get;
+               ucb->gpio.direction_input = ucb1x00_gpio_direction_input;
+               ucb->gpio.direction_output = ucb1x00_gpio_direction_output;
+               ret = gpiochip_add(&ucb->gpio);
+               if (ret)
+                       goto err_free;
+       } else
+               dev_info(&ucb->dev, "gpio_base not set so no gpiolib support");
+
        ret = request_irq(ucb->irq, ucb1x00_irq, IRQF_TRIGGER_RISING,
                          "UCB1x00", ucb);
        if (ret) {
                printk(KERN_ERR "ucb1x00: unable to grab irq%d: %d\n",
                        ucb->irq, ret);
-               goto err_free;
+               goto err_gpio;
        }
 
        mcp_set_drvdata(mcp, ucb);
@@ -522,6 +592,7 @@ static int ucb1x00_probe(struct mcp *mcp)
        if (ret)
                goto err_irq;
 
+
        INIT_LIST_HEAD(&ucb->devs);
        mutex_lock(&ucb1x00_mutex);
        list_add(&ucb->node, &ucb1x00_devices);
@@ -529,10 +600,14 @@ static int ucb1x00_probe(struct mcp *mcp)
                ucb1x00_add_dev(ucb, drv);
        }
        mutex_unlock(&ucb1x00_mutex);
+
        goto out;
 
  err_irq:
        free_irq(ucb->irq, ucb);
+ err_gpio:
+       if (ucb->gpio.base != -1)
+               temp = gpiochip_remove(&ucb->gpio);
  err_free:
        kfree(ucb);
  err_disable:
@@ -545,6 +620,7 @@ static void ucb1x00_remove(struct mcp *mcp)
 {
        struct ucb1x00 *ucb = mcp_get_drvdata(mcp);
        struct list_head *l, *n;
+       int ret;
 
        mutex_lock(&ucb1x00_mutex);
        list_del(&ucb->node);
@@ -554,6 +630,12 @@ static void ucb1x00_remove(struct mcp *mcp)
        }
        mutex_unlock(&ucb1x00_mutex);
 
+       if (ucb->gpio.base != -1) {
+               ret = gpiochip_remove(&ucb->gpio);
+               if (ret)
+                       dev_err(&ucb->dev, "Can't remove gpio chip: %d\n", ret);
+       }
+
        free_irq(ucb->irq, ucb);
        device_unregister(&ucb->dev);
 }
@@ -604,6 +686,7 @@ static int ucb1x00_resume(struct mcp *mcp)
        struct ucb1x00 *ucb = mcp_get_drvdata(mcp);
        struct ucb1x00_dev *dev;
 
+       ucb1x00_reg_write(ucb, UCB_IO_DIR, ucb->io_dir);
        mutex_lock(&ucb1x00_mutex);
        list_for_each_entry(dev, &ucb->devs, dev_node) {
                if (dev->drv->resume)
index 61b7d3e..000cb41 100644 (file)
 #include <linux/freezer.h>
 #include <linux/slab.h>
 #include <linux/kthread.h>
+#include <linux/mfd/ucb1x00.h>
 
 #include <mach/dma.h>
 #include <mach/collie.h>
 #include <asm/mach-types.h>
 
-#include "ucb1x00.h"
 
 
 struct ucb1x00_ts {
index a2ea383..2c16ca6 100644 (file)
@@ -246,6 +246,16 @@ config EP93XX_PWM
          To compile this driver as a module, choose M here: the module will
          be called ep93xx_pwm.
 
+config DS1682
+       tristate "Dallas DS1682 Total Elapsed Time Recorder with Alarm"
+       depends on I2C && EXPERIMENTAL
+       help
+         If you say yes here you get support for Dallas Semiconductor
+         DS1682 Total Elapsed Time Recorder.
+
+         This driver can also be built as a module.  If so, the module
+         will be called ds1682.
+
 source "drivers/misc/c2port/Kconfig"
 source "drivers/misc/eeprom/Kconfig"
 source "drivers/misc/cb710/Kconfig"
index e311267..906a0ed 100644 (file)
@@ -20,6 +20,7 @@ obj-$(CONFIG_SGI_GRU)         += sgi-gru/
 obj-$(CONFIG_HP_ILO)           += hpilo.o
 obj-$(CONFIG_ISL29003)         += isl29003.o
 obj-$(CONFIG_EP93XX_PWM)       += ep93xx_pwm.o
+obj-$(CONFIG_DS1682)           += ds1682.o
 obj-$(CONFIG_C2PORT)           += c2port/
 obj-$(CONFIG_IWMC3200TOP)      += iwmc3200top/
 obj-y                          += eeprom/
index 6e43ab4..4bb7a3a 100644 (file)
@@ -417,32 +417,25 @@ static int ics932s401_detect(struct i2c_client *client, int kind,
                          struct i2c_board_info *info)
 {
        struct i2c_adapter *adapter = client->adapter;
+       int vendor, device, revision;
 
        if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
                return -ENODEV;
 
-       if (kind <= 0) {
-               int vendor, device, revision;
-
-               vendor = i2c_smbus_read_word_data(client,
-                                                 ICS932S401_REG_VENDOR_REV);
-               vendor >>= 8;
-               revision = vendor >> ICS932S401_REV_SHIFT;
-               vendor &= ICS932S401_VENDOR_MASK;
-               if (vendor != ICS932S401_VENDOR)
-                       return -ENODEV;
-
-               device = i2c_smbus_read_word_data(client,
-                                                 ICS932S401_REG_DEVICE);
-               device >>= 8;
-               if (device != ICS932S401_DEVICE)
-                       return -ENODEV;
-
-               if (revision != ICS932S401_REV)
-                       dev_info(&adapter->dev, "Unknown revision %d\n",
-                                revision);
-       } else
-               dev_dbg(&adapter->dev, "detection forced\n");
+       vendor = i2c_smbus_read_word_data(client, ICS932S401_REG_VENDOR_REV);
+       vendor >>= 8;
+       revision = vendor >> ICS932S401_REV_SHIFT;
+       vendor &= ICS932S401_VENDOR_MASK;
+       if (vendor != ICS932S401_VENDOR)
+               return -ENODEV;
+
+       device = i2c_smbus_read_word_data(client, ICS932S401_REG_DEVICE);
+       device >>= 8;
+       if (device != ICS932S401_DEVICE)
+               return -ENODEV;
+
+       if (revision != ICS932S401_REV)
+               dev_info(&adapter->dev, "Unknown revision %d\n", revision);
 
        strlcpy(info->type, "ics932s401", I2C_NAME_SIZE);
 
index fd3688a..832ed4c 100644 (file)
@@ -89,48 +89,40 @@ static int xpc_disengage_max_timelimit = 120;
 
 static ctl_table xpc_sys_xpc_hb_dir[] = {
        {
-        .ctl_name = CTL_UNNUMBERED,
         .procname = "hb_interval",
         .data = &xpc_hb_interval,
         .maxlen = sizeof(int),
         .mode = 0644,
-        .proc_handler = &proc_dointvec_minmax,
-        .strategy = &sysctl_intvec,
+        .proc_handler = proc_dointvec_minmax,
         .extra1 = &xpc_hb_min_interval,
         .extra2 = &xpc_hb_max_interval},
        {
-        .ctl_name = CTL_UNNUMBERED,
         .procname = "hb_check_interval",
         .data = &xpc_hb_check_interval,
         .maxlen = sizeof(int),
         .mode = 0644,
-        .proc_handler = &proc_dointvec_minmax,
-        .strategy = &sysctl_intvec,
+        .proc_handler = proc_dointvec_minmax,
         .extra1 = &xpc_hb_check_min_interval,
         .extra2 = &xpc_hb_check_max_interval},
        {}
 };
 static ctl_table xpc_sys_xpc_dir[] = {
        {
-        .ctl_name = CTL_UNNUMBERED,
         .procname = "hb",
         .mode = 0555,
         .child = xpc_sys_xpc_hb_dir},
        {
-        .ctl_name = CTL_UNNUMBERED,
         .procname = "disengage_timelimit",
         .data = &xpc_disengage_timelimit,
         .maxlen = sizeof(int),
         .mode = 0644,
-        .proc_handler = &proc_dointvec_minmax,
-        .strategy = &sysctl_intvec,
+        .proc_handler = proc_dointvec_minmax,
         .extra1 = &xpc_disengage_min_timelimit,
         .extra2 = &xpc_disengage_max_timelimit},
        {}
 };
 static ctl_table xpc_sys_dir[] = {
        {
-        .ctl_name = CTL_UNNUMBERED,
         .procname = "xpc",
         .mode = 0555,
         .child = xpc_sys_xpc_dir},
index c76677a..b5bbe59 100644 (file)
@@ -106,7 +106,8 @@ xpc_get_gru_mq_irq_uv(struct xpc_gru_mq_uv *mq, int cpu, char *irq_name)
        int mmr_pnode = uv_blade_to_pnode(mq->mmr_blade);
 
 #if defined CONFIG_X86_64
-       mq->irq = uv_setup_irq(irq_name, cpu, mq->mmr_blade, mq->mmr_offset);
+       mq->irq = uv_setup_irq(irq_name, cpu, mq->mmr_blade, mq->mmr_offset,
+                       UV_AFFINITY_CPU);
        if (mq->irq < 0) {
                dev_err(xpc_part, "uv_setup_irq() returned error=%d\n",
                        -mq->irq);
@@ -136,7 +137,7 @@ static void
 xpc_release_gru_mq_irq_uv(struct xpc_gru_mq_uv *mq)
 {
 #if defined CONFIG_X86_64
-       uv_teardown_irq(mq->irq, mq->mmr_blade, mq->mmr_offset);
+       uv_teardown_irq(mq->irq);
 
 #elif defined CONFIG_IA64_GENERIC || defined CONFIG_IA64_SGI_UV
        int mmr_pnode;
index 705a589..90d168a 100644 (file)
@@ -56,7 +56,7 @@ static void mmci_set_clkreg(struct mmci_host *host, unsigned int desired)
                                clk = 255;
                        host->cclk = host->mclk / (2 * (clk + 1));
                }
-               if (host->hw_designer == 0x80)
+               if (host->hw_designer == AMBA_VENDOR_ST)
                        clk |= MCI_FCEN; /* Bug fix in ST IP block */
                clk |= MCI_CLK_ENABLE;
                /* This hasn't proven to be worthwhile */
index b8fd7af..5f970e2 100644 (file)
 #include <asm/io.h>
 #include <asm/irq.h>
 
-#include <mach/board.h>
-#include <mach/mmc.h>
+#include <plat/board.h>
+#include <plat/mmc.h>
 #include <mach/gpio.h>
-#include <mach/dma.h>
-#include <mach/mux.h>
-#include <mach/fpga.h>
+#include <plat/dma.h>
+#include <plat/mux.h>
+#include <plat/fpga.h>
 
 #define        OMAP_MMC_REG_CMD        0x00
 #define        OMAP_MMC_REG_ARGL       0x04
index 0aecaae..4b23225 100644 (file)
 #include <linux/mmc/core.h>
 #include <linux/io.h>
 #include <linux/semaphore.h>
-#include <mach/dma.h>
+#include <plat/dma.h>
 #include <mach/hardware.h>
-#include <mach/board.h>
-#include <mach/mmc.h>
-#include <mach/cpu.h>
+#include <plat/board.h>
+#include <plat/mmc.h>
+#include <plat/cpu.h>
 
 /* OMAP HSMMC Host Controller Registers */
 #define OMAP_HSMMC_SYSCONFIG   0x0010
index 9fb480b..bb47ff4 100644 (file)
@@ -43,6 +43,9 @@
 #define NR_SG  1
 #define CLKRT_OFF      (~0)
 
+#define mmc_has_26MHz()                (cpu_is_pxa300() || cpu_is_pxa310() \
+                               || cpu_is_pxa935())
+
 struct pxamci_host {
        struct mmc_host         *mmc;
        spinlock_t              lock;
@@ -457,7 +460,7 @@ static void pxamci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
                        clk_enable(host->clk);
 
                if (ios->clock == 26000000) {
-                       /* to support 26MHz on pxa300/pxa310 */
+                       /* to support 26MHz */
                        host->clkrt = 7;
                } else {
                        /* to handle (19.5MHz, 26MHz) */
@@ -608,8 +611,7 @@ static int pxamci_probe(struct platform_device *pdev)
         * Calculate minimum clock rate, rounding up.
         */
        mmc->f_min = (host->clkrate + 63) / 64;
-       mmc->f_max = (cpu_is_pxa300() || cpu_is_pxa310()) ? 26000000
-                                                         : host->clkrate;
+       mmc->f_max = (mmc_has_26MHz()) ? 26000000 : host->clkrate;
 
        pxamci_init_ocr(host);
 
@@ -618,7 +620,7 @@ static int pxamci_probe(struct platform_device *pdev)
        if (!cpu_is_pxa25x()) {
                mmc->caps |= MMC_CAP_4_BIT_DATA | MMC_CAP_SDIO_IRQ;
                host->cmdat |= CMDAT_SDIO_INT_EN;
-               if (cpu_is_pxa300() || cpu_is_pxa310())
+               if (mmc_has_26MHz())
                        mmc->caps |= MMC_CAP_MMC_HIGHSPEED |
                                     MMC_CAP_SD_HIGHSPEED;
        }
index a244781..ead0b2f 100644 (file)
@@ -45,7 +45,7 @@
 #include <asm/io.h>
 #include <mach/hardware.h>
 #include <asm/mach/flash.h>
-#include <mach/tc.h>
+#include <plat/tc.h>
 
 #ifdef CONFIG_MTD_PARTITIONS
 static const char *part_probes[] = { /* "RedBoot", */ "cmdlinepart", NULL };
index 8ca17a3..64e2b37 100644 (file)
@@ -59,12 +59,14 @@ static int do_blktrans_request(struct mtd_blktrans_ops *tr,
                for (; nsect > 0; nsect--, block++, buf += tr->blksize)
                        if (tr->readsect(dev, block, buf))
                                return -EIO;
+               rq_flush_dcache_pages(req);
                return 0;
 
        case WRITE:
                if (!tr->writesect)
                        return -EIO;
 
+               rq_flush_dcache_pages(req);
                for (; nsect > 0; nsect--, block++, buf += tr->blksize)
                        if (tr->writesect(dev, block, buf))
                                return -EIO;
index 2fda0b6..8f8e87b 100644 (file)
@@ -358,7 +358,7 @@ endchoice
 
 config MTD_NAND_PXA3xx
        tristate "Support for NAND flash devices on PXA3xx"
-       depends on MTD_NAND && PXA3xx
+       depends on MTD_NAND && (PXA3xx || ARCH_MMP)
        help
          This enables the driver for the NAND flash device found on
          PXA3xx processors
index 005b91f..2548e10 100644 (file)
@@ -25,7 +25,7 @@
 #include <mach/hardware.h>
 #include <asm/sizes.h>
 #include <mach/gpio.h>
-#include <mach/board-ams-delta.h>
+#include <plat/board-ams-delta.h>
 
 /*
  * MTD structure for E3 (Delta)
index 090ab87..1bb799f 100644 (file)
@@ -18,9 +18,9 @@
 #include <linux/mtd/partitions.h>
 #include <linux/io.h>
 
-#include <mach/dma.h>
-#include <mach/gpmc.h>
-#include <mach/nand.h>
+#include <plat/dma.h>
+#include <plat/gpmc.h>
+#include <plat/nand.h>
 
 #define GPMC_IRQ_STATUS                0x18
 #define GPMC_ECC_CONFIG                0x1F4
index 6ea520a..1a5a036 100644 (file)
@@ -9,6 +9,7 @@
  * published by the Free Software Foundation.
  */
 
+#include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/interrupt.h>
 #include <linux/platform_device.h>
@@ -22,7 +23,7 @@
 #include <linux/irq.h>
 
 #include <mach/dma.h>
-#include <mach/pxa3xx_nand.h>
+#include <plat/pxa3xx_nand.h>
 
 #define        CHIP_DELAY_TIMEOUT      (2 * HZ/10)
 
 #define NDCB0_CMD1_MASK                (0xff)
 #define NDCB0_ADDR_CYC_SHIFT   (16)
 
-/* dma-able I/O address for the NAND data and commands */
-#define NDCB0_DMA_ADDR         (0x43100048)
-#define NDDB_DMA_ADDR          (0x43100040)
-
 /* macros for registers read/write */
 #define nand_writel(info, off, val)    \
        __raw_writel((val), (info)->mmio_base + (off))
@@ -123,6 +120,7 @@ struct pxa3xx_nand_info {
 
        struct clk              *clk;
        void __iomem            *mmio_base;
+       unsigned long           mmio_phys;
 
        unsigned int            buf_start;
        unsigned int            buf_count;
@@ -228,13 +226,35 @@ static struct pxa3xx_nand_flash samsung512MbX16 = {
        .chip_id        = 0x46ec,
 };
 
+static struct pxa3xx_nand_flash samsung2GbX8 = {
+       .timing         = &samsung512MbX16_timing,
+       .cmdset         = &smallpage_cmdset,
+       .page_per_block = 64,
+       .page_size      = 2048,
+       .flash_width    = 8,
+       .dfc_width      = 8,
+       .num_blocks     = 2048,
+       .chip_id        = 0xdaec,
+};
+
+static struct pxa3xx_nand_flash samsung32GbX8 = {
+       .timing         = &samsung512MbX16_timing,
+       .cmdset         = &smallpage_cmdset,
+       .page_per_block = 128,
+       .page_size      = 4096,
+       .flash_width    = 8,
+       .dfc_width      = 8,
+       .num_blocks     = 8192,
+       .chip_id        = 0xd7ec,
+};
+
 static struct pxa3xx_nand_timing micron_timing = {
        .tCH    = 10,
        .tCS    = 25,
        .tWH    = 15,
        .tWP    = 25,
        .tRH    = 15,
-       .tRP    = 25,
+       .tRP    = 30,
        .tR     = 25000,
        .tWHR   = 60,
        .tAR    = 10,
@@ -262,6 +282,28 @@ static struct pxa3xx_nand_flash micron1GbX16 = {
        .chip_id        = 0xb12c,
 };
 
+static struct pxa3xx_nand_flash micron4GbX8 = {
+       .timing         = &micron_timing,
+       .cmdset         = &largepage_cmdset,
+       .page_per_block = 64,
+       .page_size      = 2048,
+       .flash_width    = 8,
+       .dfc_width      = 8,
+       .num_blocks     = 4096,
+       .chip_id        = 0xdc2c,
+};
+
+static struct pxa3xx_nand_flash micron4GbX16 = {
+       .timing         = &micron_timing,
+       .cmdset         = &largepage_cmdset,
+       .page_per_block = 64,
+       .page_size      = 2048,
+       .flash_width    = 16,
+       .dfc_width      = 16,
+       .num_blocks     = 4096,
+       .chip_id        = 0xcc2c,
+};
+
 static struct pxa3xx_nand_timing stm2GbX16_timing = {
        .tCH = 10,
        .tCS = 35,
@@ -287,8 +329,12 @@ static struct pxa3xx_nand_flash stm2GbX16 = {
 
 static struct pxa3xx_nand_flash *builtin_flash_types[] = {
        &samsung512MbX16,
+       &samsung2GbX8,
+       &samsung32GbX8,
        &micron1GbX8,
        &micron1GbX16,
+       &micron4GbX8,
+       &micron4GbX16,
        &stm2GbX16,
 };
 #endif /* CONFIG_MTD_NAND_PXA3xx_BUILTIN */
@@ -489,7 +535,7 @@ static int handle_data_pio(struct pxa3xx_nand_info *info)
        switch (info->state) {
        case STATE_PIO_WRITING:
                __raw_writesl(info->mmio_base + NDDB, info->data_buff,
-                               info->data_size << 2);
+                               DIV_ROUND_UP(info->data_size, 4));
 
                enable_int(info, NDSR_CS0_BBD | NDSR_CS0_CMDD);
 
@@ -501,7 +547,7 @@ static int handle_data_pio(struct pxa3xx_nand_info *info)
                break;
        case STATE_PIO_READING:
                __raw_readsl(info->mmio_base + NDDB, info->data_buff,
-                               info->data_size << 2);
+                               DIV_ROUND_UP(info->data_size, 4));
                break;
        default:
                printk(KERN_ERR "%s: invalid state %d\n", __func__,
@@ -523,11 +569,11 @@ static void start_data_dma(struct pxa3xx_nand_info *info, int dir_out)
 
        if (dir_out) {
                desc->dsadr = info->data_buff_phys;
-               desc->dtadr = NDDB_DMA_ADDR;
+               desc->dtadr = info->mmio_phys + NDDB;
                desc->dcmd |= DCMD_INCSRCADDR | DCMD_FLOWTRG;
        } else {
                desc->dtadr = info->data_buff_phys;
-               desc->dsadr = NDDB_DMA_ADDR;
+               desc->dsadr = info->mmio_phys + NDDB;
                desc->dcmd |= DCMD_INCTRGADDR | DCMD_FLOWSRC;
        }
 
@@ -669,6 +715,7 @@ static void pxa3xx_nand_cmdfunc(struct mtd_info *mtd, unsigned command,
                /* disable HW ECC to get all the OOB data */
                info->buf_count = mtd->writesize + mtd->oobsize;
                info->buf_start = mtd->writesize + column;
+               memset(info->data_buff, 0xFF, info->buf_count);
 
                if (prepare_read_prog_cmd(info, cmdset->read1, column, page_addr))
                        break;
@@ -1239,13 +1286,17 @@ static int pxa3xx_nand_probe(struct platform_device *pdev)
                ret = -ENODEV;
                goto fail_free_res;
        }
+       info->mmio_phys = r->start;
 
        ret = pxa3xx_nand_init_buff(info);
        if (ret)
                goto fail_free_io;
 
-       ret = request_irq(IRQ_NAND, pxa3xx_nand_irq, IRQF_DISABLED,
-                               pdev->name, info);
+       /* initialize all interrupts to be disabled */
+       disable_int(info, NDSR_MASK);
+
+       ret = request_irq(irq, pxa3xx_nand_irq, IRQF_DISABLED,
+                         pdev->name, info);
        if (ret < 0) {
                dev_err(&pdev->dev, "failed to request IRQ\n");
                goto fail_free_buf;
@@ -1271,7 +1322,7 @@ static int pxa3xx_nand_probe(struct platform_device *pdev)
        return add_mtd_partitions(mtd, pdata->parts, pdata->nr_parts);
 
 fail_free_irq:
-       free_irq(IRQ_NAND, info);
+       free_irq(irq, info);
 fail_free_buf:
        if (use_dma) {
                pxa_free_dma(info->data_dma_ch);
@@ -1296,12 +1347,15 @@ static int pxa3xx_nand_remove(struct platform_device *pdev)
        struct mtd_info *mtd = platform_get_drvdata(pdev);
        struct pxa3xx_nand_info *info = mtd->priv;
        struct resource *r;
+       int irq;
 
        platform_set_drvdata(pdev, NULL);
 
        del_mtd_device(mtd);
        del_mtd_partitions(mtd);
-       free_irq(IRQ_NAND, info);
+       irq = platform_get_irq(pdev, 0);
+       if (irq >= 0)
+               free_irq(irq, info);
        if (use_dma) {
                pxa_free_dma(info->data_dma_ch);
                dma_free_writecombine(&pdev->dev, info->data_buff_size,
index 0108ed4..86c4f6d 100644 (file)
 #include <linux/io.h>
 
 #include <asm/mach/flash.h>
-#include <mach/gpmc.h>
-#include <mach/onenand.h>
+#include <plat/gpmc.h>
+#include <plat/onenand.h>
 #include <mach/gpio.h>
 
-#include <mach/dma.h>
+#include <plat/dma.h>
 
-#include <mach/board.h>
+#include <plat/board.h>
 
 #define DRIVER_NAME "omap2-onenand"
 
index ddf224d..e6627b2 100644 (file)
@@ -9,7 +9,8 @@
  *
  *  Adapted for sparc and sparc64 by David S. Miller davem@davemloft.net
  *
- *  Reconsolidated from arch/x/kernel/prom.c by Stephen Rothwell.
+ *  Reconsolidated from arch/x/kernel/prom.c by Stephen Rothwell and
+ *  Grant Likely.
  *
  *      This program is free software; you can redistribute it and/or
  *      modify it under the terms of the GNU General Public License
@@ -82,6 +83,29 @@ struct property *of_find_property(const struct device_node *np,
 }
 EXPORT_SYMBOL(of_find_property);
 
+/**
+ * of_find_all_nodes - Get next node in global list
+ * @prev:      Previous node or NULL to start iteration
+ *             of_node_put() will be called on it
+ *
+ * Returns a node pointer with refcount incremented, use
+ * of_node_put() on it when done.
+ */
+struct device_node *of_find_all_nodes(struct device_node *prev)
+{
+       struct device_node *np;
+
+       read_lock(&devtree_lock);
+       np = prev ? prev->allnext : allnodes;
+       for (; np != NULL; np = np->allnext)
+               if (of_node_get(np))
+                       break;
+       of_node_put(prev);
+       read_unlock(&devtree_lock);
+       return np;
+}
+EXPORT_SYMBOL(of_find_all_nodes);
+
 /*
  * Find a property with a given name for a given node
  * and return the value.
index 6dec9ba..362db31 100644 (file)
@@ -386,7 +386,7 @@ static void __exit parport_mfc3_exit(void)
                if (!this_port[i])
                        continue;
                parport_remove_port(this_port[i]);
-               if (!this_port[i]->irq != PARPORT_IRQ_NONE) {
+               if (this_port[i]->irq != PARPORT_IRQ_NONE) {
                        if (--use_cnt == 0) 
                                free_irq(IRQ_AMIGA_PORTS, &pp_mfc3_ops);
                }
index 8eefe56..3f56bc0 100644 (file)
@@ -233,10 +233,10 @@ static int do_hardware_modes (ctl_table *table, int write,
        return copy_to_user(result, buffer, len) ? -EFAULT : 0;
 }
 
-#define PARPORT_PORT_DIR(CHILD) { .ctl_name = 0, .procname = NULL, .mode = 0555, .child = CHILD }
-#define PARPORT_PARPORT_DIR(CHILD) { .ctl_name = DEV_PARPORT, .procname = "parport", \
+#define PARPORT_PORT_DIR(CHILD) { .procname = NULL, .mode = 0555, .child = CHILD }
+#define PARPORT_PARPORT_DIR(CHILD) { .procname = "parport", \
                                      .mode = 0555, .child = CHILD }
-#define PARPORT_DEV_DIR(CHILD) { .ctl_name = CTL_DEV, .procname = "dev", .mode = 0555, .child = CHILD }
+#define PARPORT_DEV_DIR(CHILD) { .procname = "dev", .mode = 0555, .child = CHILD }
 #define PARPORT_DEVICES_ROOT_DIR  {  .procname = "devices", \
                                     .mode = 0555, .child = NULL }
 
@@ -270,7 +270,7 @@ static const struct parport_sysctl_table parport_sysctl_template = {
                        .data           = NULL,
                        .maxlen         = sizeof(int),
                        .mode           = 0644,
-                       .proc_handler   = &proc_dointvec_minmax,
+                       .proc_handler   = proc_dointvec_minmax,
                        .extra1         = (void*) &parport_min_spintime_value,
                        .extra2         = (void*) &parport_max_spintime_value
                },
@@ -279,28 +279,28 @@ static const struct parport_sysctl_table parport_sysctl_template = {
                        .data           = NULL,
                        .maxlen         = 0,
                        .mode           = 0444,
-                       .proc_handler   = &do_hardware_base_addr
+                       .proc_handler   = do_hardware_base_addr
                },
                {
                        .procname       = "irq",
                        .data           = NULL,
                        .maxlen         = 0,
                        .mode           = 0444,
-                       .proc_handler   = &do_hardware_irq
+                       .proc_handler   = do_hardware_irq
                },
                {
                        .procname       = "dma",
                        .data           = NULL,
                        .maxlen         = 0,
                        .mode           = 0444,
-                       .proc_handler   = &do_hardware_dma
+                       .proc_handler   = do_hardware_dma
                },
                {
                        .procname       = "modes",
                        .data           = NULL,
                        .maxlen         = 0,
                        .mode           = 0444,
-                       .proc_handler   = &do_hardware_modes
+                       .proc_handler   = do_hardware_modes
                },
                PARPORT_DEVICES_ROOT_DIR,
 #ifdef CONFIG_PARPORT_1284
@@ -309,35 +309,35 @@ static const struct parport_sysctl_table parport_sysctl_template = {
                        .data           = NULL,
                        .maxlen         = 0,
                        .mode           = 0444,
-                       .proc_handler   = &do_autoprobe
+                       .proc_handler   = do_autoprobe
                },
                {
                        .procname       = "autoprobe0",
                        .data           = NULL,
                        .maxlen         = 0,
                        .mode           = 0444,
-                       .proc_handler   =  &do_autoprobe
+                       .proc_handler   = do_autoprobe
                },
                {
                        .procname       = "autoprobe1",
                        .data           = NULL,
                        .maxlen         = 0,
                        .mode           = 0444,
-                       .proc_handler   = &do_autoprobe
+                       .proc_handler   = do_autoprobe
                },
                {
                        .procname       = "autoprobe2",
                        .data           = NULL,
                        .maxlen         = 0,
                        .mode           = 0444,
-                       .proc_handler   = &do_autoprobe
+                       .proc_handler   = do_autoprobe
                },
                {
                        .procname       = "autoprobe3",
                        .data           = NULL,
                        .maxlen         = 0,
                        .mode           = 0444,
-                       .proc_handler   = &do_autoprobe
+                       .proc_handler   = do_autoprobe
                },
 #endif /* IEEE 1284 support */
                {}
@@ -348,7 +348,7 @@ static const struct parport_sysctl_table parport_sysctl_template = {
                        .data           = NULL,
                        .maxlen         = 0,
                        .mode           = 0444,
-                       .proc_handler   = &do_active_device
+                       .proc_handler   = do_active_device
                },
                {}
        },
@@ -386,14 +386,13 @@ parport_device_sysctl_template = {
                        .data           = NULL,
                        .maxlen         = sizeof(unsigned long),
                        .mode           = 0644,
-                       .proc_handler   = &proc_doulongvec_ms_jiffies_minmax,
+                       .proc_handler   = proc_doulongvec_ms_jiffies_minmax,
                        .extra1         = (void*) &parport_min_timeslice_value,
                        .extra2         = (void*) &parport_max_timeslice_value
                },
        },
        {
                {
-                       .ctl_name       = 0,
                        .procname       = NULL,
                        .data           = NULL,
                        .maxlen         = 0,
@@ -438,7 +437,7 @@ parport_default_sysctl_table = {
                        .data           = &parport_default_timeslice,
                        .maxlen         = sizeof(parport_default_timeslice),
                        .mode           = 0644,
-                       .proc_handler   = &proc_doulongvec_ms_jiffies_minmax,
+                       .proc_handler   = proc_doulongvec_ms_jiffies_minmax,
                        .extra1         = (void*) &parport_min_timeslice_value,
                        .extra2         = (void*) &parport_max_timeslice_value
                },
@@ -447,7 +446,7 @@ parport_default_sysctl_table = {
                        .data           = &parport_default_spintime,
                        .maxlen         = sizeof(parport_default_spintime),
                        .mode           = 0644,
-                       .proc_handler   = &proc_dointvec_minmax,
+                       .proc_handler   = proc_dointvec_minmax,
                        .extra1         = (void*) &parport_min_spintime_value,
                        .extra2         = (void*) &parport_max_spintime_value
                },
@@ -455,7 +454,6 @@ parport_default_sysctl_table = {
        },
        {
                {
-                       .ctl_name       = DEV_PARPORT_DEFAULT,
                        .procname       = "default",
                        .mode           = 0555,
                        .child          = parport_default_sysctl_table.vars
@@ -495,7 +493,6 @@ int parport_proc_register(struct parport *port)
                t->vars[6 + i].extra2 = &port->probe_info[i];
 
        t->port_dir[0].procname = port->name;
-       t->port_dir[0].ctl_name = 0;
 
        t->port_dir[0].child = t->vars;
        t->parport_dir[0].child = t->port_dir;
@@ -534,11 +531,9 @@ int parport_device_proc_register(struct pardevice *device)
        t->dev_dir[0].child = t->parport_dir;
        t->parport_dir[0].child = t->port_dir;
        t->port_dir[0].procname = port->name;
-       t->port_dir[0].ctl_name = 0;
        t->port_dir[0].child = t->devices_root_dir;
        t->devices_root_dir[0].child = t->device_dir;
 
-       t->device_dir[0].ctl_name = 0;
        t->device_dir[0].procname = device->name;
        t->device_dir[0].child = t->vars;
        t->vars[0].data = &device->timeslice;
index f3ccbcc..cd5082d 100644 (file)
@@ -179,7 +179,7 @@ config PCMCIA_BCM63XX
        depends on BCM63XX && PCMCIA
 
 config PCMCIA_SOC_COMMON
-       bool
+       tristate
 
 config PCMCIA_SA1100
        tristate "SA1100 support"
index 68570bc..663781d 100644 (file)
@@ -23,8 +23,8 @@
 #include <asm/io.h>
 #include <asm/sizes.h>
 
-#include <mach/mux.h>
-#include <mach/tc.h>
+#include <plat/mux.h>
+#include <plat/tc.h>
 
 
 /* NOTE:  don't expect this to support many I/O cards.  The 16xx chips have
index 11cc3ba..8db86b9 100644 (file)
@@ -51,7 +51,7 @@ static int (*sa11x0_pcmcia_hw_init[])(struct device *dev) = {
 #ifdef CONFIG_SA1100_CERF
        pcmcia_cerf_init,
 #endif
-#ifdef CONFIG_SA1100_H3600
+#if defined(CONFIG_SA1100_H3100) || defined(CONFIG_SA1100_H3600)
        pcmcia_h3600_init,
 #endif
 #ifdef CONFIG_SA1100_SHANNON
index 3a121ac..56329ad 100644 (file)
 #include <linux/interrupt.h>
 #include <linux/init.h>
 #include <linux/delay.h>
+#include <linux/gpio.h>
 
 #include <mach/hardware.h>
 #include <asm/irq.h>
 #include <asm/mach-types.h>
-#include <mach/h3600.h>
+#include <mach/h3xxx.h>
 
 #include "sa1100_generic.h"
 
 static struct pcmcia_irqs irqs[] = {
-       { 0, IRQ_GPIO_H3600_PCMCIA_CD0, "PCMCIA CD0" },
-       { 1, IRQ_GPIO_H3600_PCMCIA_CD1, "PCMCIA CD1" }
+       { .sock = 0, .str = "PCMCIA CD0" }, /* .irq will be filled later */
+       { .sock = 1, .str = "PCMCIA CD1" }
 };
 
 static int h3600_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
 {
-       skt->socket.pci_irq = skt->nr ? IRQ_GPIO_H3600_PCMCIA_IRQ1
-                                     : IRQ_GPIO_H3600_PCMCIA_IRQ0;
+       int err;
 
+       switch (skt->nr) {
+       case 0:
+               err = gpio_request(H3XXX_GPIO_PCMCIA_IRQ0, "PCMCIA IRQ0");
+               if (err)
+                       goto err00;
+               err = gpio_direction_input(H3XXX_GPIO_PCMCIA_IRQ0);
+               if (err)
+                       goto err01;
+               skt->socket.pci_irq = gpio_to_irq(H3XXX_GPIO_PCMCIA_IRQ0);
+
+               err = gpio_request(H3XXX_GPIO_PCMCIA_CD0, "PCMCIA CD0");
+               if (err)
+                       goto err01;
+               err = gpio_direction_input(H3XXX_GPIO_PCMCIA_CD0);
+               if (err)
+                       goto err02;
+               irqs[0].irq = gpio_to_irq(H3XXX_GPIO_PCMCIA_CD0);
+
+               err = gpio_request(H3XXX_EGPIO_OPT_NVRAM_ON, "OPT NVRAM ON");
+               if (err)
+                       goto err02;
+               err = gpio_direction_output(H3XXX_EGPIO_OPT_NVRAM_ON, 0);
+               if (err)
+                       goto err03;
+               err = gpio_request(H3XXX_EGPIO_OPT_ON, "OPT ON");
+               if (err)
+                       goto err03;
+               err = gpio_direction_output(H3XXX_EGPIO_OPT_ON, 0);
+               if (err)
+                       goto err04;
+               err = gpio_request(H3XXX_EGPIO_OPT_RESET, "OPT RESET");
+               if (err)
+                       goto err04;
+               err = gpio_direction_output(H3XXX_EGPIO_OPT_RESET, 0);
+               if (err)
+                       goto err05;
+               err = gpio_request(H3XXX_EGPIO_CARD_RESET, "PCMCIA CARD RESET");
+               if (err)
+                       goto err05;
+               err = gpio_direction_output(H3XXX_EGPIO_CARD_RESET, 0);
+               if (err)
+                       goto err06;
+               err = soc_pcmcia_request_irqs(skt, irqs, ARRAY_SIZE(irqs));
+               if (err)
+                       goto err06;
+               break;
+       case 1:
+               err = gpio_request(H3XXX_GPIO_PCMCIA_IRQ1, "PCMCIA IRQ1");
+               if (err)
+                       goto err10;
+               err = gpio_direction_input(H3XXX_GPIO_PCMCIA_IRQ1);
+               if (err)
+                       goto err11;
+               skt->socket.pci_irq = gpio_to_irq(H3XXX_GPIO_PCMCIA_IRQ1);
+
+               err = gpio_request(H3XXX_GPIO_PCMCIA_CD1, "PCMCIA CD1");
+               if (err)
+                       goto err11;
+               err = gpio_direction_input(H3XXX_GPIO_PCMCIA_CD1);
+               if (err)
+                       goto err12;
+               irqs[1].irq = gpio_to_irq(H3XXX_GPIO_PCMCIA_CD1);
+
+               err = soc_pcmcia_request_irqs(skt, irqs, ARRAY_SIZE(irqs));
+               if (err)
+                       goto err12;
+               break;
+       }
+       return 0;
 
-       return soc_pcmcia_request_irqs(skt, irqs, ARRAY_SIZE(irqs));
+err06: gpio_free(H3XXX_EGPIO_CARD_RESET);
+err05: gpio_free(H3XXX_EGPIO_OPT_RESET);
+err04: gpio_free(H3XXX_EGPIO_OPT_ON);
+err03: gpio_free(H3XXX_EGPIO_OPT_NVRAM_ON);
+err02: gpio_free(H3XXX_GPIO_PCMCIA_CD0);
+err01: gpio_free(H3XXX_GPIO_PCMCIA_IRQ0);
+err00: return err;
+
+err12: gpio_free(H3XXX_GPIO_PCMCIA_CD0);
+err11: gpio_free(H3XXX_GPIO_PCMCIA_IRQ0);
+err10: return err;
 }
 
 static void h3600_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt)
 {
        soc_pcmcia_free_irqs(skt, irqs, ARRAY_SIZE(irqs));
   
-       /* Disable CF bus: */
-       assign_h3600_egpio(IPAQ_EGPIO_OPT_NVRAM_ON, 0);
-       assign_h3600_egpio(IPAQ_EGPIO_OPT_ON, 0);
-       assign_h3600_egpio(IPAQ_EGPIO_OPT_RESET, 1);
+       switch (skt->nr) {
+       case 0:
+               /* Disable CF bus: */
+               gpio_set_value(H3XXX_EGPIO_OPT_NVRAM_ON, 0);
+               gpio_set_value(H3XXX_EGPIO_OPT_ON, 0);
+               gpio_set_value(H3XXX_EGPIO_OPT_RESET, 1);
+
+               gpio_free(H3XXX_EGPIO_CARD_RESET);
+               gpio_free(H3XXX_EGPIO_OPT_RESET);
+               gpio_free(H3XXX_EGPIO_OPT_ON);
+               gpio_free(H3XXX_EGPIO_OPT_NVRAM_ON);
+               gpio_free(H3XXX_GPIO_PCMCIA_CD0);
+               gpio_free(H3XXX_GPIO_PCMCIA_IRQ0);
+               break;
+       case 1:
+               gpio_free(H3XXX_GPIO_PCMCIA_CD1);
+               gpio_free(H3XXX_GPIO_PCMCIA_IRQ1);
+               break;
+       }
 }
 
 static void
 h3600_pcmcia_socket_state(struct soc_pcmcia_socket *skt, struct pcmcia_state *state)
 {
-       unsigned long levels = GPLR;
-
        switch (skt->nr) {
        case 0:
-               state->detect = levels & GPIO_H3600_PCMCIA_CD0 ? 0 : 1;
-               state->ready = levels & GPIO_H3600_PCMCIA_IRQ0 ? 1 : 0;
+               state->detect = !gpio_get_value(H3XXX_GPIO_PCMCIA_CD0);
+               state->ready = !!gpio_get_value(H3XXX_GPIO_PCMCIA_IRQ0);
                state->bvd1 = 0;
                state->bvd2 = 0;
                state->wrprot = 0; /* Not available on H3600. */
@@ -59,8 +151,8 @@ h3600_pcmcia_socket_state(struct soc_pcmcia_socket *skt, struct pcmcia_state *st
                break;
 
        case 1:
-               state->detect = levels & GPIO_H3600_PCMCIA_CD1 ? 0 : 1;
-               state->ready = levels & GPIO_H3600_PCMCIA_IRQ1 ? 1 : 0;
+               state->detect = !gpio_get_value(H3XXX_GPIO_PCMCIA_CD1);
+               state->ready = !!gpio_get_value(H3XXX_GPIO_PCMCIA_IRQ1);
                state->bvd1 = 0;
                state->bvd2 = 0;
                state->wrprot = 0; /* Not available on H3600. */
@@ -79,7 +171,7 @@ h3600_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, const socket_state_
                return -1;
        }
 
-       assign_h3600_egpio(IPAQ_EGPIO_CARD_RESET, !!(state->flags & SS_RESET));
+       gpio_set_value(H3XXX_EGPIO_CARD_RESET, !!(state->flags & SS_RESET));
 
        /* Silently ignore Vpp, output enable, speaker enable. */
 
@@ -89,9 +181,9 @@ h3600_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, const socket_state_
 static void h3600_pcmcia_socket_init(struct soc_pcmcia_socket *skt)
 {
        /* Enable CF bus: */
-       assign_h3600_egpio(IPAQ_EGPIO_OPT_NVRAM_ON, 1);
-       assign_h3600_egpio(IPAQ_EGPIO_OPT_ON, 1);
-       assign_h3600_egpio(IPAQ_EGPIO_OPT_RESET, 0);
+       gpio_set_value(H3XXX_EGPIO_OPT_NVRAM_ON, 1);
+       gpio_set_value(H3XXX_EGPIO_OPT_ON, 1);
+       gpio_set_value(H3XXX_EGPIO_OPT_RESET, 0);
 
        msleep(10);
 
@@ -109,10 +201,10 @@ static void h3600_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt)
         * socket 0 then socket 1.
         */
        if (skt->nr == 1) {
-               assign_h3600_egpio(IPAQ_EGPIO_OPT_ON, 0);
-               assign_h3600_egpio(IPAQ_EGPIO_OPT_NVRAM_ON, 0);
+               gpio_set_value(H3XXX_EGPIO_OPT_ON, 0);
+               gpio_set_value(H3XXX_EGPIO_OPT_NVRAM_ON, 0);
                /* hmm, does this suck power? */
-               assign_h3600_egpio(IPAQ_EGPIO_OPT_RESET, 1);
+               gpio_set_value(H3XXX_EGPIO_OPT_RESET, 1);
        }
 }
 
@@ -131,7 +223,7 @@ int __init pcmcia_h3600_init(struct device *dev)
 {
        int ret = -ENODEV;
 
-       if (machine_is_h3600())
+       if (machine_is_h3600() || machine_is_h3100())
                ret = sa11xx_drv_pcmcia_probe(dev, &h3600_pcmcia_ops, 0, 2);
 
        return ret;
index cea6cef..1186749 100644 (file)
@@ -77,6 +77,13 @@ config BATTERY_TOSA
          Say Y to enable support for the battery on the Sharp Zaurus
          SL-6000 (tosa) models.
 
+config BATTERY_COLLIE
+       tristate "Sharp SL-5500 (collie) battery"
+       depends on SA1100_COLLIE && MCP_UCB1200
+       help
+         Say Y to enable support for the battery on the Sharp Zaurus
+         SL-5500 (collie) models.
+
 config BATTERY_WM97XX
        bool "WM97xx generic battery driver"
        depends on TOUCHSCREEN_WM97XX=y
index b96f29d..356cdfd 100644 (file)
@@ -24,6 +24,7 @@ obj-$(CONFIG_BATTERY_DS2782)  += ds2782_battery.o
 obj-$(CONFIG_BATTERY_PMU)      += pmu_battery.o
 obj-$(CONFIG_BATTERY_OLPC)     += olpc_battery.o
 obj-$(CONFIG_BATTERY_TOSA)     += tosa_battery.o
+obj-$(CONFIG_BATTERY_COLLIE)   += collie_battery.o
 obj-$(CONFIG_BATTERY_WM97XX)   += wm97xx_battery.o
 obj-$(CONFIG_BATTERY_BQ27x00)  += bq27x00_battery.o
 obj-$(CONFIG_BATTERY_DA9030)   += da9030_battery.o
diff --git a/drivers/power/collie_battery.c b/drivers/power/collie_battery.c
new file mode 100644 (file)
index 0000000..039f41a
--- /dev/null
@@ -0,0 +1,418 @@
+/*
+ * Battery and Power Management code for the Sharp SL-5x00
+ *
+ * Copyright (C) 2009 Thomas Kunze
+ *
+ * based on tosa_battery.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.
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/power_supply.h>
+#include <linux/delay.h>
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+#include <linux/gpio.h>
+#include <linux/mfd/ucb1x00.h>
+
+#include <asm/mach/sharpsl_param.h>
+#include <asm/mach-types.h>
+#include <mach/collie.h>
+
+static DEFINE_MUTEX(bat_lock); /* protects gpio pins */
+static struct work_struct bat_work;
+static struct ucb1x00 *ucb;
+
+struct collie_bat {
+       int status;
+       struct power_supply psy;
+       int full_chrg;
+
+       struct mutex work_lock; /* protects data */
+
+       bool (*is_present)(struct collie_bat *bat);
+       int gpio_full;
+       int gpio_charge_on;
+
+       int technology;
+
+       int gpio_bat;
+       int adc_bat;
+       int adc_bat_divider;
+       int bat_max;
+       int bat_min;
+
+       int gpio_temp;
+       int adc_temp;
+       int adc_temp_divider;
+};
+
+static struct collie_bat collie_bat_main;
+
+static unsigned long collie_read_bat(struct collie_bat *bat)
+{
+       unsigned long value = 0;
+
+       if (bat->gpio_bat < 0 || bat->adc_bat < 0)
+               return 0;
+       mutex_lock(&bat_lock);
+       gpio_set_value(bat->gpio_bat, 1);
+       msleep(5);
+       ucb1x00_adc_enable(ucb);
+       value = ucb1x00_adc_read(ucb, bat->adc_bat, UCB_SYNC);
+       ucb1x00_adc_disable(ucb);
+       gpio_set_value(bat->gpio_bat, 0);
+       mutex_unlock(&bat_lock);
+       value = value * 1000000 / bat->adc_bat_divider;
+
+       return value;
+}
+
+static unsigned long collie_read_temp(struct collie_bat *bat)
+{
+       unsigned long value = 0;
+       if (bat->gpio_temp < 0 || bat->adc_temp < 0)
+               return 0;
+
+       mutex_lock(&bat_lock);
+       gpio_set_value(bat->gpio_temp, 1);
+       msleep(5);
+       ucb1x00_adc_enable(ucb);
+       value = ucb1x00_adc_read(ucb, bat->adc_temp, UCB_SYNC);
+       ucb1x00_adc_disable(ucb);
+       gpio_set_value(bat->gpio_temp, 0);
+       mutex_unlock(&bat_lock);
+
+       value = value * 10000 / bat->adc_temp_divider;
+
+       return value;
+}
+
+static int collie_bat_get_property(struct power_supply *psy,
+                           enum power_supply_property psp,
+                           union power_supply_propval *val)
+{
+       int ret = 0;
+       struct collie_bat *bat = container_of(psy, struct collie_bat, psy);
+
+       if (bat->is_present && !bat->is_present(bat)
+                       && psp != POWER_SUPPLY_PROP_PRESENT) {
+               return -ENODEV;
+       }
+
+       switch (psp) {
+       case POWER_SUPPLY_PROP_STATUS:
+               val->intval = bat->status;
+               break;
+       case POWER_SUPPLY_PROP_TECHNOLOGY:
+               val->intval = bat->technology;
+               break;
+       case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+               val->intval = collie_read_bat(bat);
+               break;
+       case POWER_SUPPLY_PROP_VOLTAGE_MAX:
+               if (bat->full_chrg == -1)
+                       val->intval = bat->bat_max;
+               else
+                       val->intval = bat->full_chrg;
+               break;
+       case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
+               val->intval = bat->bat_max;
+               break;
+       case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
+               val->intval = bat->bat_min;
+               break;
+       case POWER_SUPPLY_PROP_TEMP:
+               val->intval = collie_read_temp(bat);
+               break;
+       case POWER_SUPPLY_PROP_PRESENT:
+               val->intval = bat->is_present ? bat->is_present(bat) : 1;
+               break;
+       default:
+               ret = -EINVAL;
+               break;
+       }
+       return ret;
+}
+
+static void collie_bat_external_power_changed(struct power_supply *psy)
+{
+       schedule_work(&bat_work);
+}
+
+static irqreturn_t collie_bat_gpio_isr(int irq, void *data)
+{
+       pr_info("collie_bat_gpio irq: %d\n", gpio_get_value(irq_to_gpio(irq)));
+       schedule_work(&bat_work);
+       return IRQ_HANDLED;
+}
+
+static void collie_bat_update(struct collie_bat *bat)
+{
+       int old;
+       struct power_supply *psy = &bat->psy;
+
+       mutex_lock(&bat->work_lock);
+
+       old = bat->status;
+
+       if (bat->is_present && !bat->is_present(bat)) {
+               printk(KERN_NOTICE "%s not present\n", psy->name);
+               bat->status = POWER_SUPPLY_STATUS_UNKNOWN;
+               bat->full_chrg = -1;
+       } else if (power_supply_am_i_supplied(psy)) {
+               if (bat->status == POWER_SUPPLY_STATUS_DISCHARGING) {
+                       gpio_set_value(bat->gpio_charge_on, 1);
+                       mdelay(15);
+               }
+
+               if (gpio_get_value(bat->gpio_full)) {
+                       if (old == POWER_SUPPLY_STATUS_CHARGING ||
+                                       bat->full_chrg == -1)
+                               bat->full_chrg = collie_read_bat(bat);
+
+                       gpio_set_value(bat->gpio_charge_on, 0);
+                       bat->status = POWER_SUPPLY_STATUS_FULL;
+               } else {
+                       gpio_set_value(bat->gpio_charge_on, 1);
+                       bat->status = POWER_SUPPLY_STATUS_CHARGING;
+               }
+       } else {
+               gpio_set_value(bat->gpio_charge_on, 0);
+               bat->status = POWER_SUPPLY_STATUS_DISCHARGING;
+       }
+
+       if (old != bat->status)
+               power_supply_changed(psy);
+
+       mutex_unlock(&bat->work_lock);
+}
+
+static void collie_bat_work(struct work_struct *work)
+{
+       collie_bat_update(&collie_bat_main);
+}
+
+
+static enum power_supply_property collie_bat_main_props[] = {
+       POWER_SUPPLY_PROP_STATUS,
+       POWER_SUPPLY_PROP_TECHNOLOGY,
+       POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
+       POWER_SUPPLY_PROP_VOLTAGE_NOW,
+       POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
+       POWER_SUPPLY_PROP_VOLTAGE_MAX,
+       POWER_SUPPLY_PROP_PRESENT,
+       POWER_SUPPLY_PROP_TEMP,
+};
+
+static enum power_supply_property collie_bat_bu_props[] = {
+       POWER_SUPPLY_PROP_STATUS,
+       POWER_SUPPLY_PROP_TECHNOLOGY,
+       POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
+       POWER_SUPPLY_PROP_VOLTAGE_NOW,
+       POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
+       POWER_SUPPLY_PROP_VOLTAGE_MAX,
+       POWER_SUPPLY_PROP_PRESENT,
+};
+
+static struct collie_bat collie_bat_main = {
+       .status = POWER_SUPPLY_STATUS_DISCHARGING,
+       .full_chrg = -1,
+       .psy = {
+               .name           = "main-battery",
+               .type           = POWER_SUPPLY_TYPE_BATTERY,
+               .properties     = collie_bat_main_props,
+               .num_properties = ARRAY_SIZE(collie_bat_main_props),
+               .get_property   = collie_bat_get_property,
+               .external_power_changed = collie_bat_external_power_changed,
+               .use_for_apm    = 1,
+       },
+
+       .gpio_full = COLLIE_GPIO_CO,
+       .gpio_charge_on = COLLIE_GPIO_CHARGE_ON,
+
+       .technology = POWER_SUPPLY_TECHNOLOGY_LIPO,
+
+       .gpio_bat = COLLIE_GPIO_MBAT_ON,
+       .adc_bat = UCB_ADC_INP_AD1,
+       .adc_bat_divider = 155,
+       .bat_max = 4310000,
+       .bat_min = 1551 * 1000000 / 414,
+
+       .gpio_temp = COLLIE_GPIO_TMP_ON,
+       .adc_temp = UCB_ADC_INP_AD0,
+       .adc_temp_divider = 10000,
+};
+
+static struct collie_bat collie_bat_bu = {
+       .status = POWER_SUPPLY_STATUS_UNKNOWN,
+       .full_chrg = -1,
+
+       .psy = {
+               .name           = "backup-battery",
+               .type           = POWER_SUPPLY_TYPE_BATTERY,
+               .properties     = collie_bat_bu_props,
+               .num_properties = ARRAY_SIZE(collie_bat_bu_props),
+               .get_property   = collie_bat_get_property,
+               .external_power_changed = collie_bat_external_power_changed,
+       },
+
+       .gpio_full = -1,
+       .gpio_charge_on = -1,
+
+       .technology = POWER_SUPPLY_TECHNOLOGY_LiMn,
+
+       .gpio_bat = COLLIE_GPIO_BBAT_ON,
+       .adc_bat = UCB_ADC_INP_AD1,
+       .adc_bat_divider = 155,
+       .bat_max = 3000000,
+       .bat_min = 1900000,
+
+       .gpio_temp = -1,
+       .adc_temp = -1,
+       .adc_temp_divider = -1,
+};
+
+static struct {
+       int gpio;
+       char *name;
+       bool output;
+       int value;
+} gpios[] = {
+       { COLLIE_GPIO_CO,               "main battery full",    0, 0 },
+       { COLLIE_GPIO_MAIN_BAT_LOW,     "main battery low",     0, 0 },
+       { COLLIE_GPIO_CHARGE_ON,        "main charge on",       1, 0 },
+       { COLLIE_GPIO_MBAT_ON,          "main battery",         1, 0 },
+       { COLLIE_GPIO_TMP_ON,           "main battery temp",    1, 0 },
+       { COLLIE_GPIO_BBAT_ON,          "backup battery",       1, 0 },
+};
+
+#ifdef CONFIG_PM
+static int collie_bat_suspend(struct ucb1x00_dev *dev, pm_message_t state)
+{
+       /* flush all pending status updates */
+       flush_scheduled_work();
+       return 0;
+}
+
+static int collie_bat_resume(struct ucb1x00_dev *dev)
+{
+       /* things may have changed while we were away */
+       schedule_work(&bat_work);
+       return 0;
+}
+#else
+#define collie_bat_suspend NULL
+#define collie_bat_resume NULL
+#endif
+
+static int __devinit collie_bat_probe(struct ucb1x00_dev *dev)
+{
+       int ret;
+       int i;
+
+       if (!machine_is_collie())
+               return -ENODEV;
+
+       ucb = dev->ucb;
+
+       for (i = 0; i < ARRAY_SIZE(gpios); i++) {
+               ret = gpio_request(gpios[i].gpio, gpios[i].name);
+               if (ret) {
+                       i--;
+                       goto err_gpio;
+               }
+
+               if (gpios[i].output)
+                       ret = gpio_direction_output(gpios[i].gpio,
+                                       gpios[i].value);
+               else
+                       ret = gpio_direction_input(gpios[i].gpio);
+
+               if (ret)
+                       goto err_gpio;
+       }
+
+       mutex_init(&collie_bat_main.work_lock);
+
+       INIT_WORK(&bat_work, collie_bat_work);
+
+       ret = power_supply_register(&dev->ucb->dev, &collie_bat_main.psy);
+       if (ret)
+               goto err_psy_reg_main;
+       ret = power_supply_register(&dev->ucb->dev, &collie_bat_bu.psy);
+       if (ret)
+               goto err_psy_reg_bu;
+
+       ret = request_irq(gpio_to_irq(COLLIE_GPIO_CO),
+                               collie_bat_gpio_isr,
+                               IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+                               "main full", &collie_bat_main);
+       if (!ret) {
+               schedule_work(&bat_work);
+               return 0;
+       }
+       power_supply_unregister(&collie_bat_bu.psy);
+err_psy_reg_bu:
+       power_supply_unregister(&collie_bat_main.psy);
+err_psy_reg_main:
+
+       /* see comment in collie_bat_remove */
+       flush_scheduled_work();
+
+       i--;
+err_gpio:
+       for (; i >= 0; i--)
+               gpio_free(gpios[i].gpio);
+
+       return ret;
+}
+
+static void __devexit collie_bat_remove(struct ucb1x00_dev *dev)
+{
+       int i;
+
+       free_irq(gpio_to_irq(COLLIE_GPIO_CO), &collie_bat_main);
+
+       power_supply_unregister(&collie_bat_bu.psy);
+       power_supply_unregister(&collie_bat_main.psy);
+
+       /*
+        * now flush all pending work.
+        * we won't get any more schedules, since all
+        * sources (isr and external_power_changed)
+        * are unregistered now.
+        */
+       flush_scheduled_work();
+
+       for (i = ARRAY_SIZE(gpios) - 1; i >= 0; i--)
+               gpio_free(gpios[i].gpio);
+}
+
+static struct ucb1x00_driver collie_bat_driver = {
+       .add            = collie_bat_probe,
+       .remove         = __devexit_p(collie_bat_remove),
+       .suspend        = collie_bat_suspend,
+       .resume         = collie_bat_resume,
+};
+
+static int __init collie_bat_init(void)
+{
+       return ucb1x00_register_driver(&collie_bat_driver);
+}
+
+static void __exit collie_bat_exit(void)
+{
+       ucb1x00_unregister_driver(&collie_bat_driver);
+}
+
+module_init(collie_bat_init);
+module_exit(collie_bat_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Thomas Kunze");
+MODULE_DESCRIPTION("Collie battery driver");
index 3c20dae..f2e1004 100644 (file)
@@ -509,6 +509,15 @@ config RTC_DRV_M48T59
          This driver can also be built as a module, if so, the module
          will be called "rtc-m48t59".
 
+config RTC_DRV_MSM6242
+       tristate "Oki MSM6242"
+       help
+         If you say yes here you get support for the Oki MSM6242
+         timekeeping chip. It is used in some Amiga models (e.g. A2000).
+
+         This driver can also be built as a module. If so, the module
+         will be called rtc-msm6242.
+
 config RTC_MXC
        tristate "Freescale MXC Real Time Clock"
        depends on ARCH_MXC
@@ -529,6 +538,16 @@ config RTC_DRV_BQ4802
          This driver can also be built as a module. If so, the module
          will be called rtc-bq4802.
 
+config RTC_DRV_RP5C01
+       tristate "Ricoh RP5C01"
+       help
+         If you say yes here you get support for the Ricoh RP5C01
+         timekeeping chip. It is used in some Amiga models (e.g. A3000
+         and A4000).
+
+         This driver can also be built as a module. If so, the module
+         will be called rtc-rp5c01.
+
 config RTC_DRV_V3020
        tristate "EM Microelectronic V3020"
        help
@@ -780,7 +799,7 @@ config RTC_DRV_TX4939
 
 config RTC_DRV_MV
        tristate "Marvell SoC RTC"
-       depends on ARCH_KIRKWOOD
+       depends on ARCH_KIRKWOOD || ARCH_DOVE
        help
          If you say yes here you will get support for the in-chip RTC
          that can be found in some of Marvell's SoC devices, such as
index aa3fbd5..af1ba7a 100644 (file)
@@ -52,6 +52,7 @@ obj-$(CONFIG_RTC_DRV_M48T86)  += rtc-m48t86.o
 obj-$(CONFIG_RTC_MXC)          += rtc-mxc.o
 obj-$(CONFIG_RTC_DRV_MAX6900)  += rtc-max6900.o
 obj-$(CONFIG_RTC_DRV_MAX6902)  += rtc-max6902.o
+obj-$(CONFIG_RTC_DRV_MSM6242)  += rtc-msm6242.o
 obj-$(CONFIG_RTC_DRV_MV)       += rtc-mv.o
 obj-$(CONFIG_RTC_DRV_OMAP)     += rtc-omap.o
 obj-$(CONFIG_RTC_DRV_PCAP)     += rtc-pcap.o
@@ -64,6 +65,7 @@ obj-$(CONFIG_RTC_DRV_PL031)   += rtc-pl031.o
 obj-$(CONFIG_RTC_DRV_PS3)      += rtc-ps3.o
 obj-$(CONFIG_RTC_DRV_PXA)      += rtc-pxa.o
 obj-$(CONFIG_RTC_DRV_R9701)    += rtc-r9701.o
+obj-$(CONFIG_RTC_DRV_RP5C01)   += rtc-rp5c01.o
 obj-$(CONFIG_RTC_DRV_RS5C313)  += rtc-rs5c313.o
 obj-$(CONFIG_RTC_DRV_RS5C348)  += rtc-rs5c348.o
 obj-$(CONFIG_RTC_DRV_RS5C372)  += rtc-rs5c372.o
diff --git a/drivers/rtc/rtc-msm6242.c b/drivers/rtc/rtc-msm6242.c
new file mode 100644 (file)
index 0000000..5f5968a
--- /dev/null
@@ -0,0 +1,269 @@
+/*
+ *  Oki MSM6242 RTC Driver
+ *
+ *  Copyright 2009 Geert Uytterhoeven
+ *
+ *  Based on the A2000 TOD code in arch/m68k/amiga/config.c
+ *  Copyright (C) 1993 Hamish Macdonald
+ */
+
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/rtc.h>
+
+
+enum {
+       MSM6242_SECOND1         = 0x0,  /* 1-second digit register */
+       MSM6242_SECOND10        = 0x1,  /* 10-second digit register */
+       MSM6242_MINUTE1         = 0x2,  /* 1-minute digit register */
+       MSM6242_MINUTE10        = 0x3,  /* 10-minute digit register */
+       MSM6242_HOUR1           = 0x4,  /* 1-hour digit register */
+       MSM6242_HOUR10          = 0x5,  /* PM/AM, 10-hour digit register */
+       MSM6242_DAY1            = 0x6,  /* 1-day digit register */
+       MSM6242_DAY10           = 0x7,  /* 10-day digit register */
+       MSM6242_MONTH1          = 0x8,  /* 1-month digit register */
+       MSM6242_MONTH10         = 0x9,  /* 10-month digit register */
+       MSM6242_YEAR1           = 0xa,  /* 1-year digit register */
+       MSM6242_YEAR10          = 0xb,  /* 10-year digit register */
+       MSM6242_WEEK            = 0xc,  /* Week register */
+       MSM6242_CD              = 0xd,  /* Control Register D */
+       MSM6242_CE              = 0xe,  /* Control Register E */
+       MSM6242_CF              = 0xf,  /* Control Register F */
+};
+
+#define MSM6242_HOUR10_AM      (0 << 2)
+#define MSM6242_HOUR10_PM      (1 << 2)
+#define MSM6242_HOUR10_HR_MASK (3 << 0)
+
+#define MSM6242_WEEK_SUNDAY    0
+#define MSM6242_WEEK_MONDAY    1
+#define MSM6242_WEEK_TUESDAY   2
+#define MSM6242_WEEK_WEDNESDAY 3
+#define MSM6242_WEEK_THURSDAY  4
+#define MSM6242_WEEK_FRIDAY    5
+#define MSM6242_WEEK_SATURDAY  6
+
+#define MSM6242_CD_30_S_ADJ    (1 << 3)        /* 30-second adjustment */
+#define MSM6242_CD_IRQ_FLAG    (1 << 2)
+#define MSM6242_CD_BUSY                (1 << 1)
+#define MSM6242_CD_HOLD                (1 << 0)
+
+#define MSM6242_CE_T_MASK      (3 << 2)
+#define MSM6242_CE_T_64HZ      (0 << 2)        /* period 1/64 second */
+#define MSM6242_CE_T_1HZ       (1 << 2)        /* period 1 second */
+#define MSM6242_CE_T_1MINUTE   (2 << 2)        /* period 1 minute */
+#define MSM6242_CE_T_1HOUR     (3 << 2)        /* period 1 hour */
+
+#define MSM6242_CE_ITRPT_STND  (1 << 1)
+#define MSM6242_CE_MASK                (1 << 0)        /* STD.P output control */
+
+#define MSM6242_CF_TEST                (1 << 3)
+#define MSM6242_CF_12H         (0 << 2)
+#define MSM6242_CF_24H         (1 << 2)
+#define MSM6242_CF_STOP                (1 << 1)
+#define MSM6242_CF_REST                (1 << 0)        /* reset */
+
+
+struct msm6242_priv {
+       u32 __iomem *regs;
+       struct rtc_device *rtc;
+};
+
+static inline unsigned int msm6242_read(struct msm6242_priv *priv,
+                                      unsigned int reg)
+{
+       return __raw_readl(&priv->regs[reg]) & 0xf;
+}
+
+static inline void msm6242_write(struct msm6242_priv *priv, unsigned int val,
+                               unsigned int reg)
+{
+       return __raw_writel(val, &priv->regs[reg]);
+}
+
+static inline void msm6242_set(struct msm6242_priv *priv, unsigned int val,
+                              unsigned int reg)
+{
+       msm6242_write(priv, msm6242_read(priv, reg) | val, reg);
+}
+
+static inline void msm6242_clear(struct msm6242_priv *priv, unsigned int val,
+                                unsigned int reg)
+{
+       msm6242_write(priv, msm6242_read(priv, reg) & ~val, reg);
+}
+
+static void msm6242_lock(struct msm6242_priv *priv)
+{
+       int cnt = 5;
+
+       msm6242_set(priv, MSM6242_CD_HOLD, MSM6242_CD);
+
+       while ((msm6242_read(priv, MSM6242_CD) & MSM6242_CD_BUSY) && cnt) {
+               msm6242_clear(priv, MSM6242_CD_HOLD, MSM6242_CD);
+               udelay(70);
+               msm6242_set(priv, MSM6242_CD_HOLD, MSM6242_CD);
+               cnt--;
+       }
+
+       if (!cnt)
+               pr_warning("msm6242: timed out waiting for RTC (0x%x)\n",
+                          msm6242_read(priv, MSM6242_CD));
+}
+
+static void msm6242_unlock(struct msm6242_priv *priv)
+{
+       msm6242_clear(priv, MSM6242_CD_HOLD, MSM6242_CD);
+}
+
+static int msm6242_read_time(struct device *dev, struct rtc_time *tm)
+{
+       struct msm6242_priv *priv = dev_get_drvdata(dev);
+
+       msm6242_lock(priv);
+
+       tm->tm_sec  = msm6242_read(priv, MSM6242_SECOND10) * 10 +
+                     msm6242_read(priv, MSM6242_SECOND1);
+       tm->tm_min  = msm6242_read(priv, MSM6242_MINUTE10) * 10 +
+                     msm6242_read(priv, MSM6242_MINUTE1);
+       tm->tm_hour = (msm6242_read(priv, MSM6242_HOUR10 & 3)) * 10 +
+                     msm6242_read(priv, MSM6242_HOUR1);
+       tm->tm_mday = msm6242_read(priv, MSM6242_DAY10) * 10 +
+                     msm6242_read(priv, MSM6242_DAY1);
+       tm->tm_wday = msm6242_read(priv, MSM6242_WEEK);
+       tm->tm_mon  = msm6242_read(priv, MSM6242_MONTH10) * 10 +
+                     msm6242_read(priv, MSM6242_MONTH1) - 1;
+       tm->tm_year = msm6242_read(priv, MSM6242_YEAR10) * 10 +
+                     msm6242_read(priv, MSM6242_YEAR1);
+       if (tm->tm_year <= 69)
+               tm->tm_year += 100;
+
+       if (!(msm6242_read(priv, MSM6242_CF) & MSM6242_CF_24H)) {
+               unsigned int pm = msm6242_read(priv, MSM6242_HOUR10) &
+                                 MSM6242_HOUR10_PM;
+               if (!pm && tm->tm_hour == 12)
+                       tm->tm_hour = 0;
+               else if (pm && tm->tm_hour != 12)
+                       tm->tm_hour += 12;
+       }
+
+       msm6242_unlock(priv);
+
+       return rtc_valid_tm(tm);
+}
+
+static int msm6242_set_time(struct device *dev, struct rtc_time *tm)
+{
+       struct msm6242_priv *priv = dev_get_drvdata(dev);
+
+       msm6242_lock(priv);
+
+       msm6242_write(priv, tm->tm_sec / 10, MSM6242_SECOND10);
+       msm6242_write(priv, tm->tm_sec % 10, MSM6242_SECOND1);
+       msm6242_write(priv, tm->tm_min / 10, MSM6242_MINUTE10);
+       msm6242_write(priv, tm->tm_min % 10, MSM6242_MINUTE1);
+       if (msm6242_read(priv, MSM6242_CF) & MSM6242_CF_24H)
+               msm6242_write(priv, tm->tm_hour / 10, MSM6242_HOUR10);
+       else if (tm->tm_hour >= 12)
+               msm6242_write(priv, MSM6242_HOUR10_PM + (tm->tm_hour - 12) / 10,
+                             MSM6242_HOUR10);
+       else
+               msm6242_write(priv, tm->tm_hour / 10, MSM6242_HOUR10);
+       msm6242_write(priv, tm->tm_hour % 10, MSM6242_HOUR1);
+       msm6242_write(priv, tm->tm_mday / 10, MSM6242_DAY10);
+       msm6242_write(priv, tm->tm_mday % 10, MSM6242_DAY1);
+       if (tm->tm_wday != -1)
+               msm6242_write(priv, tm->tm_wday, MSM6242_WEEK);
+       msm6242_write(priv, (tm->tm_mon + 1) / 10, MSM6242_MONTH10);
+       msm6242_write(priv, (tm->tm_mon + 1) % 10, MSM6242_MONTH1);
+       if (tm->tm_year >= 100)
+               tm->tm_year -= 100;
+       msm6242_write(priv, tm->tm_year / 10, MSM6242_YEAR10);
+       msm6242_write(priv, tm->tm_year % 10, MSM6242_YEAR1);
+
+       msm6242_unlock(priv);
+       return 0;
+}
+
+static const struct rtc_class_ops msm6242_rtc_ops = {
+       .read_time      = msm6242_read_time,
+       .set_time       = msm6242_set_time,
+};
+
+static int __init msm6242_rtc_probe(struct platform_device *dev)
+{
+       struct resource *res;
+       struct msm6242_priv *priv;
+       struct rtc_device *rtc;
+       int error;
+
+       res = platform_get_resource(dev, IORESOURCE_MEM, 0);
+       if (!res)
+               return -ENODEV;
+
+       priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       priv->regs = ioremap(res->start, resource_size(res));
+       if (!priv->regs) {
+               error = -ENOMEM;
+               goto out_free_priv;
+       }
+
+       rtc = rtc_device_register("rtc-msm6242", &dev->dev, &msm6242_rtc_ops,
+                                 THIS_MODULE);
+       if (IS_ERR(rtc)) {
+               error = PTR_ERR(rtc);
+               goto out_unmap;
+       }
+
+       priv->rtc = rtc;
+       platform_set_drvdata(dev, priv);
+       return 0;
+
+out_unmap:
+       iounmap(priv->regs);
+out_free_priv:
+       kfree(priv);
+       return error;
+}
+
+static int __exit msm6242_rtc_remove(struct platform_device *dev)
+{
+       struct msm6242_priv *priv = platform_get_drvdata(dev);
+
+       rtc_device_unregister(priv->rtc);
+       iounmap(priv->regs);
+       kfree(priv);
+       return 0;
+}
+
+static struct platform_driver msm6242_rtc_driver = {
+       .driver = {
+               .name   = "rtc-msm6242",
+               .owner  = THIS_MODULE,
+       },
+       .remove = __exit_p(msm6242_rtc_remove),
+};
+
+static int __init msm6242_rtc_init(void)
+{
+       return platform_driver_probe(&msm6242_rtc_driver, msm6242_rtc_probe);
+}
+
+static void __exit msm6242_rtc_fini(void)
+{
+       platform_driver_unregister(&msm6242_rtc_driver);
+}
+
+module_init(msm6242_rtc_init);
+module_exit(msm6242_rtc_fini);
+
+MODULE_AUTHOR("Geert Uytterhoeven <geert@linux-m68k.org>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Oki MSM6242 RTC driver");
+MODULE_ALIAS("platform:rtc-msm6242");
diff --git a/drivers/rtc/rtc-rp5c01.c b/drivers/rtc/rtc-rp5c01.c
new file mode 100644 (file)
index 0000000..e1313fe
--- /dev/null
@@ -0,0 +1,222 @@
+/*
+ *  Ricoh RP5C01 RTC Driver
+ *
+ *  Copyright 2009 Geert Uytterhoeven
+ *
+ *  Based on the A3000 TOD code in arch/m68k/amiga/config.c
+ *  Copyright (C) 1993 Hamish Macdonald
+ */
+
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/rtc.h>
+
+
+enum {
+       RP5C01_1_SECOND         = 0x0,  /* MODE 00 */
+       RP5C01_10_SECOND        = 0x1,  /* MODE 00 */
+       RP5C01_1_MINUTE         = 0x2,  /* MODE 00 and MODE 01 */
+       RP5C01_10_MINUTE        = 0x3,  /* MODE 00 and MODE 01 */
+       RP5C01_1_HOUR           = 0x4,  /* MODE 00 and MODE 01 */
+       RP5C01_10_HOUR          = 0x5,  /* MODE 00 and MODE 01 */
+       RP5C01_DAY_OF_WEEK      = 0x6,  /* MODE 00 and MODE 01 */
+       RP5C01_1_DAY            = 0x7,  /* MODE 00 and MODE 01 */
+       RP5C01_10_DAY           = 0x8,  /* MODE 00 and MODE 01 */
+       RP5C01_1_MONTH          = 0x9,  /* MODE 00 */
+       RP5C01_10_MONTH         = 0xa,  /* MODE 00 */
+       RP5C01_1_YEAR           = 0xb,  /* MODE 00 */
+       RP5C01_10_YEAR          = 0xc,  /* MODE 00 */
+
+       RP5C01_12_24_SELECT     = 0xa,  /* MODE 01 */
+       RP5C01_LEAP_YEAR        = 0xb,  /* MODE 01 */
+
+       RP5C01_MODE             = 0xd,  /* all modes */
+       RP5C01_TEST             = 0xe,  /* all modes */
+       RP5C01_RESET            = 0xf,  /* all modes */
+};
+
+#define RP5C01_12_24_SELECT_12 (0 << 0)
+#define RP5C01_12_24_SELECT_24 (1 << 0)
+
+#define RP5C01_10_HOUR_AM      (0 << 1)
+#define RP5C01_10_HOUR_PM      (1 << 1)
+
+#define RP5C01_MODE_TIMER_EN   (1 << 3)        /* timer enable */
+#define RP5C01_MODE_ALARM_EN   (1 << 2)        /* alarm enable */
+
+#define RP5C01_MODE_MODE_MASK  (3 << 0)
+#define RP5C01_MODE_MODE00     (0 << 0)        /* time */
+#define RP5C01_MODE_MODE01     (1 << 0)        /* alarm, 12h/24h, leap year */
+#define RP5C01_MODE_RAM_BLOCK10        (2 << 0)        /* RAM 4 bits x 13 */
+#define RP5C01_MODE_RAM_BLOCK11        (3 << 0)        /* RAM 4 bits x 13 */
+
+#define RP5C01_RESET_1HZ_PULSE (1 << 3)
+#define RP5C01_RESET_16HZ_PULSE        (1 << 2)
+#define RP5C01_RESET_SECOND    (1 << 1)        /* reset divider stages for */
+                                               /* seconds or smaller units */
+#define RP5C01_RESET_ALARM     (1 << 0)        /* reset all alarm registers */
+
+
+struct rp5c01_priv {
+       u32 __iomem *regs;
+       struct rtc_device *rtc;
+};
+
+static inline unsigned int rp5c01_read(struct rp5c01_priv *priv,
+                                      unsigned int reg)
+{
+       return __raw_readl(&priv->regs[reg]) & 0xf;
+}
+
+static inline void rp5c01_write(struct rp5c01_priv *priv, unsigned int val,
+                               unsigned int reg)
+{
+       return __raw_writel(val, &priv->regs[reg]);
+}
+
+static void rp5c01_lock(struct rp5c01_priv *priv)
+{
+       rp5c01_write(priv, RP5C01_MODE_MODE00, RP5C01_MODE);
+}
+
+static void rp5c01_unlock(struct rp5c01_priv *priv)
+{
+       rp5c01_write(priv, RP5C01_MODE_TIMER_EN | RP5C01_MODE_MODE01,
+                    RP5C01_MODE);
+}
+
+static int rp5c01_read_time(struct device *dev, struct rtc_time *tm)
+{
+       struct rp5c01_priv *priv = dev_get_drvdata(dev);
+
+       rp5c01_lock(priv);
+
+       tm->tm_sec  = rp5c01_read(priv, RP5C01_10_SECOND) * 10 +
+                     rp5c01_read(priv, RP5C01_1_SECOND);
+       tm->tm_min  = rp5c01_read(priv, RP5C01_10_MINUTE) * 10 +
+                     rp5c01_read(priv, RP5C01_1_MINUTE);
+       tm->tm_hour = rp5c01_read(priv, RP5C01_10_HOUR) * 10 +
+                     rp5c01_read(priv, RP5C01_1_HOUR);
+       tm->tm_mday = rp5c01_read(priv, RP5C01_10_DAY) * 10 +
+                     rp5c01_read(priv, RP5C01_1_DAY);
+       tm->tm_wday = rp5c01_read(priv, RP5C01_DAY_OF_WEEK);
+       tm->tm_mon  = rp5c01_read(priv, RP5C01_10_MONTH) * 10 +
+                     rp5c01_read(priv, RP5C01_1_MONTH) - 1;
+       tm->tm_year = rp5c01_read(priv, RP5C01_10_YEAR) * 10 +
+                     rp5c01_read(priv, RP5C01_1_YEAR);
+       if (tm->tm_year <= 69)
+               tm->tm_year += 100;
+
+       rp5c01_unlock(priv);
+
+       return rtc_valid_tm(tm);
+}
+
+static int rp5c01_set_time(struct device *dev, struct rtc_time *tm)
+{
+       struct rp5c01_priv *priv = dev_get_drvdata(dev);
+
+       rp5c01_lock(priv);
+
+       rp5c01_write(priv, tm->tm_sec / 10, RP5C01_10_SECOND);
+       rp5c01_write(priv, tm->tm_sec % 10, RP5C01_1_SECOND);
+       rp5c01_write(priv, tm->tm_min / 10, RP5C01_10_MINUTE);
+       rp5c01_write(priv, tm->tm_min % 10, RP5C01_1_MINUTE);
+       rp5c01_write(priv, tm->tm_hour / 10, RP5C01_10_HOUR);
+       rp5c01_write(priv, tm->tm_hour % 10, RP5C01_1_HOUR);
+       rp5c01_write(priv, tm->tm_mday / 10, RP5C01_10_DAY);
+       rp5c01_write(priv, tm->tm_mday % 10, RP5C01_1_DAY);
+       if (tm->tm_wday != -1)
+               rp5c01_write(priv, tm->tm_wday, RP5C01_DAY_OF_WEEK);
+       rp5c01_write(priv, (tm->tm_mon + 1) / 10, RP5C01_10_MONTH);
+       rp5c01_write(priv, (tm->tm_mon + 1) % 10, RP5C01_1_MONTH);
+       if (tm->tm_year >= 100)
+               tm->tm_year -= 100;
+       rp5c01_write(priv, tm->tm_year / 10, RP5C01_10_YEAR);
+       rp5c01_write(priv, tm->tm_year % 10, RP5C01_1_YEAR);
+
+       rp5c01_unlock(priv);
+       return 0;
+}
+
+static const struct rtc_class_ops rp5c01_rtc_ops = {
+       .read_time      = rp5c01_read_time,
+       .set_time       = rp5c01_set_time,
+};
+
+static int __init rp5c01_rtc_probe(struct platform_device *dev)
+{
+       struct resource *res;
+       struct rp5c01_priv *priv;
+       struct rtc_device *rtc;
+       int error;
+
+       res = platform_get_resource(dev, IORESOURCE_MEM, 0);
+       if (!res)
+               return -ENODEV;
+
+       priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       priv->regs = ioremap(res->start, resource_size(res));
+       if (!priv->regs) {
+               error = -ENOMEM;
+               goto out_free_priv;
+       }
+
+       rtc = rtc_device_register("rtc-rp5c01", &dev->dev, &rp5c01_rtc_ops,
+                                 THIS_MODULE);
+       if (IS_ERR(rtc)) {
+               error = PTR_ERR(rtc);
+               goto out_unmap;
+       }
+
+       priv->rtc = rtc;
+       platform_set_drvdata(dev, priv);
+       return 0;
+
+out_unmap:
+       iounmap(priv->regs);
+out_free_priv:
+       kfree(priv);
+       return error;
+}
+
+static int __exit rp5c01_rtc_remove(struct platform_device *dev)
+{
+       struct rp5c01_priv *priv = platform_get_drvdata(dev);
+
+       rtc_device_unregister(priv->rtc);
+       iounmap(priv->regs);
+       kfree(priv);
+       return 0;
+}
+
+static struct platform_driver rp5c01_rtc_driver = {
+       .driver = {
+               .name   = "rtc-rp5c01",
+               .owner  = THIS_MODULE,
+       },
+       .remove = __exit_p(rp5c01_rtc_remove),
+};
+
+static int __init rp5c01_rtc_init(void)
+{
+       return platform_driver_probe(&rp5c01_rtc_driver, rp5c01_rtc_probe);
+}
+
+static void __exit rp5c01_rtc_fini(void)
+{
+       platform_driver_unregister(&rp5c01_rtc_driver);
+}
+
+module_init(rp5c01_rtc_init);
+module_exit(rp5c01_rtc_fini);
+
+MODULE_AUTHOR("Geert Uytterhoeven <geert@linux-m68k.org>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Ricoh RP5C01 RTC driver");
+MODULE_ALIAS("platform:rtc-rp5c01");
index b44462a..740fe40 100644 (file)
@@ -101,18 +101,17 @@ static struct ctl_table callhome_table[] = {
                .mode           = 0644,
                .proc_handler   = proc_handler_callhome,
        },
-       { .ctl_name = 0 }
+       {}
 };
 
 static struct ctl_table kern_dir_table[] = {
        {
-               .ctl_name       = CTL_KERN,
                .procname       = "kernel",
                .maxlen         = 0,
                .mode           = 0555,
                .child          = callhome_table,
        },
-       { .ctl_name = 0 }
+       {}
 };
 
 /*
index 63a30f5..2b6b93f 100644 (file)
 
 
 static ctl_table scsi_table[] = {
-       { .ctl_name     = DEV_SCSI_LOGGING_LEVEL,
-         .procname     = "logging_level",
+       { .procname     = "logging_level",
          .data         = &scsi_logging_level,
          .maxlen       = sizeof(scsi_logging_level),
          .mode         = 0644,
-         .proc_handler = &proc_dointvec },
+         .proc_handler = proc_dointvec },
        { }
 };
 
 static ctl_table scsi_dir_table[] = {
-       { .ctl_name     = DEV_SCSI,
-         .procname     = "scsi",
+       { .procname     = "scsi",
          .mode         = 0555,
          .child        = scsi_table },
        { }
 };
 
 static ctl_table scsi_root_table[] = {
-       { .ctl_name     = CTL_DEV,
-         .procname     = "dev",
+       { .procname     = "dev",
          .mode         = 0555,
          .child        = scsi_dir_table },
        { }
index e522572..50943ff 100644 (file)
@@ -1477,4 +1477,17 @@ config SERIAL_BCM63XX_CONSOLE
          If you have enabled the serial port on the bcm63xx CPU
          you can make it the console by answering Y to this option.
 
+config SERIAL_GRLIB_GAISLER_APBUART
+       tristate "GRLIB APBUART serial support"
+       depends on OF
+       ---help---
+       Add support for the GRLIB APBUART serial port.
+
+config SERIAL_GRLIB_GAISLER_APBUART_CONSOLE
+       bool "Console on GRLIB APBUART serial port"
+       depends on SERIAL_GRLIB_GAISLER_APBUART=y
+       select SERIAL_CORE_CONSOLE
+       help
+       Support for running a console on the GRLIB APBUART
+
 endmenu
index d21d5dd..5548fe7 100644 (file)
@@ -81,3 +81,4 @@ obj-$(CONFIG_SERIAL_KS8695) += serial_ks8695.o
 obj-$(CONFIG_KGDB_SERIAL_CONSOLE) += kgdboc.o
 obj-$(CONFIG_SERIAL_QE) += ucc_uart.o
 obj-$(CONFIG_SERIAL_TIMBERDALE)        += timbuart.o
+obj-$(CONFIG_SERIAL_GRLIB_GAISLER_APBUART) += apbuart.o
diff --git a/drivers/serial/apbuart.c b/drivers/serial/apbuart.c
new file mode 100644 (file)
index 0000000..fe91319
--- /dev/null
@@ -0,0 +1,710 @@
+/*
+ *  Driver for GRLIB serial ports (APBUART)
+ *
+ *  Based on linux/drivers/serial/amba.c
+ *
+ *  Copyright (C) 2000 Deep Blue Solutions Ltd.
+ *  Copyright (C) 2003 Konrad Eisele <eiselekd@web.de>
+ *  Copyright (C) 2006 Daniel Hellstrom <daniel@gaisler.com>, Aeroflex Gaisler AB
+ *  Copyright (C) 2008 Gilead Kutnick <kutnickg@zin-tech.com>
+ *  Copyright (C) 2009 Kristoffer Glembo <kristoffer@gaisler.com>, Aeroflex Gaisler AB
+ */
+
+#if defined(CONFIG_SERIAL_GRLIB_GAISLER_APBUART_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
+#include <linux/module.h>
+#include <linux/tty.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/serial.h>
+#include <linux/console.h>
+#include <linux/sysrq.h>
+#include <linux/kthread.h>
+#include <linux/device.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/serial_core.h>
+#include <asm/irq.h>
+
+#include "apbuart.h"
+
+#define SERIAL_APBUART_MAJOR   TTY_MAJOR
+#define SERIAL_APBUART_MINOR   64
+#define UART_DUMMY_RSR_RX      0x8000  /* for ignore all read */
+
+static void apbuart_tx_chars(struct uart_port *port);
+
+static void apbuart_stop_tx(struct uart_port *port)
+{
+       unsigned int cr;
+
+       cr = UART_GET_CTRL(port);
+       cr &= ~UART_CTRL_TI;
+       UART_PUT_CTRL(port, cr);
+}
+
+static void apbuart_start_tx(struct uart_port *port)
+{
+       unsigned int cr;
+
+       cr = UART_GET_CTRL(port);
+       cr |= UART_CTRL_TI;
+       UART_PUT_CTRL(port, cr);
+
+       if (UART_GET_STATUS(port) & UART_STATUS_THE)
+               apbuart_tx_chars(port);
+}
+
+static void apbuart_stop_rx(struct uart_port *port)
+{
+       unsigned int cr;
+
+       cr = UART_GET_CTRL(port);
+       cr &= ~(UART_CTRL_RI);
+       UART_PUT_CTRL(port, cr);
+}
+
+static void apbuart_enable_ms(struct uart_port *port)
+{
+       /* No modem status change interrupts for APBUART */
+}
+
+static void apbuart_rx_chars(struct uart_port *port)
+{
+       struct tty_struct *tty = port->state->port.tty;
+       unsigned int status, ch, rsr, flag;
+       unsigned int max_chars = port->fifosize;
+
+       status = UART_GET_STATUS(port);
+
+       while (UART_RX_DATA(status) && (max_chars--)) {
+
+               ch = UART_GET_CHAR(port);
+               flag = TTY_NORMAL;
+
+               port->icount.rx++;
+
+               rsr = UART_GET_STATUS(port) | UART_DUMMY_RSR_RX;
+               UART_PUT_STATUS(port, 0);
+               if (rsr & UART_STATUS_ERR) {
+
+                       if (rsr & UART_STATUS_BR) {
+                               rsr &= ~(UART_STATUS_FE | UART_STATUS_PE);
+                               port->icount.brk++;
+                               if (uart_handle_break(port))
+                                       goto ignore_char;
+                       } else if (rsr & UART_STATUS_PE) {
+                               port->icount.parity++;
+                       } else if (rsr & UART_STATUS_FE) {
+                               port->icount.frame++;
+                       }
+                       if (rsr & UART_STATUS_OE)
+                               port->icount.overrun++;
+
+                       rsr &= port->read_status_mask;
+
+                       if (rsr & UART_STATUS_PE)
+                               flag = TTY_PARITY;
+                       else if (rsr & UART_STATUS_FE)
+                               flag = TTY_FRAME;
+               }
+
+               if (uart_handle_sysrq_char(port, ch))
+                       goto ignore_char;
+
+               uart_insert_char(port, rsr, UART_STATUS_OE, ch, flag);
+
+
+             ignore_char:
+               status = UART_GET_STATUS(port);
+       }
+
+       tty_flip_buffer_push(tty);
+}
+
+static void apbuart_tx_chars(struct uart_port *port)
+{
+       struct circ_buf *xmit = &port->state->xmit;
+       int count;
+
+       if (port->x_char) {
+               UART_PUT_CHAR(port, port->x_char);
+               port->icount.tx++;
+               port->x_char = 0;
+               return;
+       }
+
+       if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
+               apbuart_stop_tx(port);
+               return;
+       }
+
+       /* amba: fill FIFO */
+       count = port->fifosize >> 1;
+       do {
+               UART_PUT_CHAR(port, xmit->buf[xmit->tail]);
+               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+               port->icount.tx++;
+               if (uart_circ_empty(xmit))
+                       break;
+       } while (--count > 0);
+
+       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+               uart_write_wakeup(port);
+
+       if (uart_circ_empty(xmit))
+               apbuart_stop_tx(port);
+}
+
+static irqreturn_t apbuart_int(int irq, void *dev_id)
+{
+       struct uart_port *port = dev_id;
+       unsigned int status;
+
+       spin_lock(&port->lock);
+
+       status = UART_GET_STATUS(port);
+       if (status & UART_STATUS_DR)
+               apbuart_rx_chars(port);
+       if (status & UART_STATUS_THE)
+               apbuart_tx_chars(port);
+
+       spin_unlock(&port->lock);
+
+       return IRQ_HANDLED;
+}
+
+static unsigned int apbuart_tx_empty(struct uart_port *port)
+{
+       unsigned int status = UART_GET_STATUS(port);
+       return status & UART_STATUS_THE ? TIOCSER_TEMT : 0;
+}
+
+static unsigned int apbuart_get_mctrl(struct uart_port *port)
+{
+       /* The GRLIB APBUART handles flow control in hardware */
+       return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS;
+}
+
+static void apbuart_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+       /* The GRLIB APBUART handles flow control in hardware */
+}
+
+static void apbuart_break_ctl(struct uart_port *port, int break_state)
+{
+       /* We don't support sending break */
+}
+
+static int apbuart_startup(struct uart_port *port)
+{
+       int retval;
+       unsigned int cr;
+
+       /* Allocate the IRQ */
+       retval = request_irq(port->irq, apbuart_int, 0, "apbuart", port);
+       if (retval)
+               return retval;
+
+       /* Finally, enable interrupts */
+       cr = UART_GET_CTRL(port);
+       UART_PUT_CTRL(port,
+                     cr | UART_CTRL_RE | UART_CTRL_TE |
+                     UART_CTRL_RI | UART_CTRL_TI);
+
+       return 0;
+}
+
+static void apbuart_shutdown(struct uart_port *port)
+{
+       unsigned int cr;
+
+       /* disable all interrupts, disable the port */
+       cr = UART_GET_CTRL(port);
+       UART_PUT_CTRL(port,
+                     cr & ~(UART_CTRL_RE | UART_CTRL_TE |
+                            UART_CTRL_RI | UART_CTRL_TI));
+
+       /* Free the interrupt */
+       free_irq(port->irq, port);
+}
+
+static void apbuart_set_termios(struct uart_port *port,
+                               struct ktermios *termios, struct ktermios *old)
+{
+       unsigned int cr;
+       unsigned long flags;
+       unsigned int baud, quot;
+
+       /* Ask the core to calculate the divisor for us. */
+       baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16);
+       if (baud == 0)
+               panic("invalid baudrate %i\n", port->uartclk / 16);
+
+       /* uart_get_divisor calc a *16 uart freq, apbuart is *8 */
+       quot = (uart_get_divisor(port, baud)) * 2;
+       cr = UART_GET_CTRL(port);
+       cr &= ~(UART_CTRL_PE | UART_CTRL_PS);
+
+       if (termios->c_cflag & PARENB) {
+               cr |= UART_CTRL_PE;
+               if ((termios->c_cflag & PARODD))
+                       cr |= UART_CTRL_PS;
+       }
+
+       /* Enable flow control. */
+       if (termios->c_cflag & CRTSCTS)
+               cr |= UART_CTRL_FL;
+
+       spin_lock_irqsave(&port->lock, flags);
+
+       /* Update the per-port timeout. */
+       uart_update_timeout(port, termios->c_cflag, baud);
+
+       port->read_status_mask = UART_STATUS_OE;
+       if (termios->c_iflag & INPCK)
+               port->read_status_mask |= UART_STATUS_FE | UART_STATUS_PE;
+
+       /* Characters to ignore */
+       port->ignore_status_mask = 0;
+       if (termios->c_iflag & IGNPAR)
+               port->ignore_status_mask |= UART_STATUS_FE | UART_STATUS_PE;
+
+       /* Ignore all characters if CREAD is not set. */
+       if ((termios->c_cflag & CREAD) == 0)
+               port->ignore_status_mask |= UART_DUMMY_RSR_RX;
+
+       /* Set baud rate */
+       quot -= 1;
+       UART_PUT_SCAL(port, quot);
+       UART_PUT_CTRL(port, cr);
+
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static const char *apbuart_type(struct uart_port *port)
+{
+       return port->type == PORT_APBUART ? "GRLIB/APBUART" : NULL;
+}
+
+static void apbuart_release_port(struct uart_port *port)
+{
+       release_mem_region(port->mapbase, 0x100);
+}
+
+static int apbuart_request_port(struct uart_port *port)
+{
+       return request_mem_region(port->mapbase, 0x100, "grlib-apbuart")
+           != NULL ? 0 : -EBUSY;
+       return 0;
+}
+
+/* Configure/autoconfigure the port */
+static void apbuart_config_port(struct uart_port *port, int flags)
+{
+       if (flags & UART_CONFIG_TYPE) {
+               port->type = PORT_APBUART;
+               apbuart_request_port(port);
+       }
+}
+
+/* Verify the new serial_struct (for TIOCSSERIAL) */
+static int apbuart_verify_port(struct uart_port *port,
+                              struct serial_struct *ser)
+{
+       int ret = 0;
+       if (ser->type != PORT_UNKNOWN && ser->type != PORT_APBUART)
+               ret = -EINVAL;
+       if (ser->irq < 0 || ser->irq >= NR_IRQS)
+               ret = -EINVAL;
+       if (ser->baud_base < 9600)
+               ret = -EINVAL;
+       return ret;
+}
+
+static struct uart_ops grlib_apbuart_ops = {
+       .tx_empty = apbuart_tx_empty,
+       .set_mctrl = apbuart_set_mctrl,
+       .get_mctrl = apbuart_get_mctrl,
+       .stop_tx = apbuart_stop_tx,
+       .start_tx = apbuart_start_tx,
+       .stop_rx = apbuart_stop_rx,
+       .enable_ms = apbuart_enable_ms,
+       .break_ctl = apbuart_break_ctl,
+       .startup = apbuart_startup,
+       .shutdown = apbuart_shutdown,
+       .set_termios = apbuart_set_termios,
+       .type = apbuart_type,
+       .release_port = apbuart_release_port,
+       .request_port = apbuart_request_port,
+       .config_port = apbuart_config_port,
+       .verify_port = apbuart_verify_port,
+};
+
+static struct uart_port grlib_apbuart_ports[UART_NR];
+static struct device_node *grlib_apbuart_nodes[UART_NR];
+
+static int apbuart_scan_fifo_size(struct uart_port *port, int portnumber)
+{
+       int ctrl, loop = 0;
+       int status;
+       int fifosize;
+       unsigned long flags;
+
+       ctrl = UART_GET_CTRL(port);
+
+       /*
+        * Enable the transceiver and wait for it to be ready to send data.
+        * Clear interrupts so that this process will not be externally
+        * interrupted in the middle (which can cause the transceiver to
+        * drain prematurely).
+        */
+
+       local_irq_save(flags);
+
+       UART_PUT_CTRL(port, ctrl | UART_CTRL_TE);
+
+       while (!UART_TX_READY(UART_GET_STATUS(port)))
+               loop++;
+
+       /*
+        * Disable the transceiver so data isn't actually sent during the
+        * actual test.
+        */
+
+       UART_PUT_CTRL(port, ctrl & ~(UART_CTRL_TE));
+
+       fifosize = 1;
+       UART_PUT_CHAR(port, 0);
+
+       /*
+        * So long as transmitting a character increments the tranceivier FIFO
+        * length the FIFO must be at least that big. These bytes will
+        * automatically drain off of the FIFO.
+        */
+
+       status = UART_GET_STATUS(port);
+       while (((status >> 20) & 0x3F) == fifosize) {
+               fifosize++;
+               UART_PUT_CHAR(port, 0);
+               status = UART_GET_STATUS(port);
+       }
+
+       fifosize--;
+
+       UART_PUT_CTRL(port, ctrl);
+       local_irq_restore(flags);
+
+       if (fifosize == 0)
+               fifosize = 1;
+
+       return fifosize;
+}
+
+static void apbuart_flush_fifo(struct uart_port *port)
+{
+       int i;
+
+       for (i = 0; i < port->fifosize; i++)
+               UART_GET_CHAR(port);
+}
+
+
+/* ======================================================================== */
+/* Console driver, if enabled                                               */
+/* ======================================================================== */
+
+#ifdef CONFIG_SERIAL_GRLIB_GAISLER_APBUART_CONSOLE
+
+static void apbuart_console_putchar(struct uart_port *port, int ch)
+{
+       unsigned int status;
+       do {
+               status = UART_GET_STATUS(port);
+       } while (!UART_TX_READY(status));
+       UART_PUT_CHAR(port, ch);
+}
+
+static void
+apbuart_console_write(struct console *co, const char *s, unsigned int count)
+{
+       struct uart_port *port = &grlib_apbuart_ports[co->index];
+       unsigned int status, old_cr, new_cr;
+
+       /* First save the CR then disable the interrupts */
+       old_cr = UART_GET_CTRL(port);
+       new_cr = old_cr & ~(UART_CTRL_RI | UART_CTRL_TI);
+       UART_PUT_CTRL(port, new_cr);
+
+       uart_console_write(port, s, count, apbuart_console_putchar);
+
+       /*
+        *      Finally, wait for transmitter to become empty
+        *      and restore the TCR
+        */
+       do {
+               status = UART_GET_STATUS(port);
+       } while (!UART_TX_READY(status));
+       UART_PUT_CTRL(port, old_cr);
+}
+
+static void __init
+apbuart_console_get_options(struct uart_port *port, int *baud,
+                           int *parity, int *bits)
+{
+       if (UART_GET_CTRL(port) & (UART_CTRL_RE | UART_CTRL_TE)) {
+
+               unsigned int quot, status;
+               status = UART_GET_STATUS(port);
+
+               *parity = 'n';
+               if (status & UART_CTRL_PE) {
+                       if ((status & UART_CTRL_PS) == 0)
+                               *parity = 'e';
+                       else
+                               *parity = 'o';
+               }
+
+               *bits = 8;
+               quot = UART_GET_SCAL(port) / 8;
+               *baud = port->uartclk / (16 * (quot + 1));
+       }
+}
+
+static int __init apbuart_console_setup(struct console *co, char *options)
+{
+       struct uart_port *port;
+       int baud = 38400;
+       int bits = 8;
+       int parity = 'n';
+       int flow = 'n';
+
+       pr_debug("apbuart_console_setup co=%p, co->index=%i, options=%s\n",
+                co, co->index, options);
+
+       /*
+        * Check whether an invalid uart number has been specified, and
+        * if so, search for the first available port that does have
+        * console support.
+        */
+       if (co->index >= grlib_apbuart_port_nr)
+               co->index = 0;
+
+       port = &grlib_apbuart_ports[co->index];
+
+       spin_lock_init(&port->lock);
+
+       if (options)
+               uart_parse_options(options, &baud, &parity, &bits, &flow);
+       else
+               apbuart_console_get_options(port, &baud, &parity, &bits);
+
+       return uart_set_options(port, co, baud, parity, bits, flow);
+}
+
+static struct uart_driver grlib_apbuart_driver;
+
+static struct console grlib_apbuart_console = {
+       .name = "ttyS",
+       .write = apbuart_console_write,
+       .device = uart_console_device,
+       .setup = apbuart_console_setup,
+       .flags = CON_PRINTBUFFER,
+       .index = -1,
+       .data = &grlib_apbuart_driver,
+};
+
+
+static void grlib_apbuart_configure(void);
+
+static int __init apbuart_console_init(void)
+{
+       grlib_apbuart_configure();
+       register_console(&grlib_apbuart_console);
+       return 0;
+}
+
+console_initcall(apbuart_console_init);
+
+#define APBUART_CONSOLE        (&grlib_apbuart_console)
+#else
+#define APBUART_CONSOLE        NULL
+#endif
+
+static struct uart_driver grlib_apbuart_driver = {
+       .owner = THIS_MODULE,
+       .driver_name = "serial",
+       .dev_name = "ttyS",
+       .major = SERIAL_APBUART_MAJOR,
+       .minor = SERIAL_APBUART_MINOR,
+       .nr = UART_NR,
+       .cons = APBUART_CONSOLE,
+};
+
+
+/* ======================================================================== */
+/* OF Platform Driver                                                       */
+/* ======================================================================== */
+
+static int __devinit apbuart_probe(struct of_device *op,
+                                  const struct of_device_id *match)
+{
+       int i = -1;
+       struct uart_port *port = NULL;
+
+       i = 0;
+       for (i = 0; i < grlib_apbuart_port_nr; i++) {
+               if (op->node == grlib_apbuart_nodes[i])
+                       break;
+       }
+
+       port = &grlib_apbuart_ports[i];
+       port->dev = &op->dev;
+
+       uart_add_one_port(&grlib_apbuart_driver, (struct uart_port *) port);
+
+       apbuart_flush_fifo((struct uart_port *) port);
+
+       printk(KERN_INFO "grlib-apbuart at 0x%llx, irq %d\n",
+              (unsigned long long) port->mapbase, port->irq);
+       return 0;
+
+}
+
+static struct of_device_id __initdata apbuart_match[] = {
+       {
+        .name = "GAISLER_APBUART",
+        },
+       {},
+};
+
+static struct of_platform_driver grlib_apbuart_of_driver = {
+       .match_table = apbuart_match,
+       .probe = apbuart_probe,
+       .driver = {
+                  .owner = THIS_MODULE,
+                  .name = "grlib-apbuart",
+                  },
+};
+
+
+static void grlib_apbuart_configure(void)
+{
+       static int enum_done;
+       struct device_node *np, *rp;
+       struct uart_port *port = NULL;
+       const u32 *prop;
+       int freq_khz;
+       int v = 0, d = 0;
+       unsigned int addr;
+       int irq, line;
+       struct amba_prom_registers *regs;
+
+       if (enum_done)
+               return;
+
+       /* Get bus frequency */
+       rp = of_find_node_by_path("/");
+       rp = of_get_next_child(rp, NULL);
+       prop = of_get_property(rp, "clock-frequency", NULL);
+       freq_khz = *prop;
+
+       line = 0;
+       for_each_matching_node(np, apbuart_match) {
+
+               int *vendor = (int *) of_get_property(np, "vendor", NULL);
+               int *device = (int *) of_get_property(np, "device", NULL);
+               int *irqs = (int *) of_get_property(np, "interrupts", NULL);
+               regs = (struct amba_prom_registers *)
+                   of_get_property(np, "reg", NULL);
+
+               if (vendor)
+                       v = *vendor;
+               if (device)
+                       d = *device;
+
+               if (!irqs || !regs)
+                       return;
+
+               grlib_apbuart_nodes[line] = np;
+
+               addr = regs->phys_addr;
+               irq = *irqs;
+
+               port = &grlib_apbuart_ports[line];
+
+               port->mapbase = addr;
+               port->membase = ioremap(addr, sizeof(struct grlib_apbuart_regs_map));
+               port->irq = irq;
+               port->iotype = UPIO_MEM;
+               port->ops = &grlib_apbuart_ops;
+               port->flags = UPF_BOOT_AUTOCONF;
+               port->line = line;
+               port->uartclk = freq_khz * 1000;
+               port->fifosize = apbuart_scan_fifo_size((struct uart_port *) port, line);
+               line++;
+
+               /* We support maximum UART_NR uarts ... */
+               if (line == UART_NR)
+                       break;
+
+       }
+
+       enum_done = 1;
+
+       grlib_apbuart_driver.nr = grlib_apbuart_port_nr = line;
+}
+
+static int __init grlib_apbuart_init(void)
+{
+       int ret;
+
+       /* Find all APBUARTS in device the tree and initialize their ports */
+       grlib_apbuart_configure();
+
+       printk(KERN_INFO "Serial: GRLIB APBUART driver\n");
+
+       ret = uart_register_driver(&grlib_apbuart_driver);
+
+       if (ret) {
+               printk(KERN_ERR "%s: uart_register_driver failed (%i)\n",
+                      __FILE__, ret);
+               return ret;
+       }
+
+       ret = of_register_platform_driver(&grlib_apbuart_of_driver);
+       if (ret) {
+               printk(KERN_ERR
+                      "%s: of_register_platform_driver failed (%i)\n",
+                      __FILE__, ret);
+               uart_unregister_driver(&grlib_apbuart_driver);
+               return ret;
+       }
+
+       return ret;
+}
+
+static void __exit grlib_apbuart_exit(void)
+{
+       int i;
+
+       for (i = 0; i < grlib_apbuart_port_nr; i++)
+               uart_remove_one_port(&grlib_apbuart_driver,
+                                    &grlib_apbuart_ports[i]);
+
+       uart_unregister_driver(&grlib_apbuart_driver);
+       of_unregister_platform_driver(&grlib_apbuart_of_driver);
+}
+
+module_init(grlib_apbuart_init);
+module_exit(grlib_apbuart_exit);
+
+MODULE_AUTHOR("Aeroflex Gaisler AB");
+MODULE_DESCRIPTION("GRLIB APBUART serial driver");
+MODULE_VERSION("2.1");
+MODULE_LICENSE("GPL");
diff --git a/drivers/serial/apbuart.h b/drivers/serial/apbuart.h
new file mode 100644 (file)
index 0000000..5faf87c
--- /dev/null
@@ -0,0 +1,64 @@
+#ifndef __GRLIB_APBUART_H__
+#define __GRLIB_APBUART_H__
+
+#include <asm/io.h>
+
+#define UART_NR                8
+static int grlib_apbuart_port_nr;
+
+struct grlib_apbuart_regs_map {
+       u32 data;
+       u32 status;
+       u32 ctrl;
+       u32 scaler;
+};
+
+struct amba_prom_registers {
+       unsigned int phys_addr;
+       unsigned int reg_size;
+};
+
+/*
+ *  The following defines the bits in the APBUART Status Registers.
+ */
+#define UART_STATUS_DR   0x00000001    /* Data Ready */
+#define UART_STATUS_TSE  0x00000002    /* TX Send Register Empty */
+#define UART_STATUS_THE  0x00000004    /* TX Hold Register Empty */
+#define UART_STATUS_BR   0x00000008    /* Break Error */
+#define UART_STATUS_OE   0x00000010    /* RX Overrun Error */
+#define UART_STATUS_PE   0x00000020    /* RX Parity Error */
+#define UART_STATUS_FE   0x00000040    /* RX Framing Error */
+#define UART_STATUS_ERR  0x00000078    /* Error Mask */
+
+/*
+ *  The following defines the bits in the APBUART Ctrl Registers.
+ */
+#define UART_CTRL_RE     0x00000001    /* Receiver enable */
+#define UART_CTRL_TE     0x00000002    /* Transmitter enable */
+#define UART_CTRL_RI     0x00000004    /* Receiver interrupt enable */
+#define UART_CTRL_TI     0x00000008    /* Transmitter irq */
+#define UART_CTRL_PS     0x00000010    /* Parity select */
+#define UART_CTRL_PE     0x00000020    /* Parity enable */
+#define UART_CTRL_FL     0x00000040    /* Flow control enable */
+#define UART_CTRL_LB     0x00000080    /* Loopback enable */
+
+#define APBBASE(port) ((struct grlib_apbuart_regs_map *)((port)->membase))
+
+#define APBBASE_DATA_P(port)   (&(APBBASE(port)->data))
+#define APBBASE_STATUS_P(port) (&(APBBASE(port)->status))
+#define APBBASE_CTRL_P(port)   (&(APBBASE(port)->ctrl))
+#define APBBASE_SCALAR_P(port) (&(APBBASE(port)->scaler))
+
+#define UART_GET_CHAR(port)    (__raw_readl(APBBASE_DATA_P(port)))
+#define UART_PUT_CHAR(port, v) (__raw_writel(v, APBBASE_DATA_P(port)))
+#define UART_GET_STATUS(port)  (__raw_readl(APBBASE_STATUS_P(port)))
+#define UART_PUT_STATUS(port, v)(__raw_writel(v, APBBASE_STATUS_P(port)))
+#define UART_GET_CTRL(port)    (__raw_readl(APBBASE_CTRL_P(port)))
+#define UART_PUT_CTRL(port, v) (__raw_writel(v, APBBASE_CTRL_P(port)))
+#define UART_GET_SCAL(port)    (__raw_readl(APBBASE_SCALAR_P(port)))
+#define UART_PUT_SCAL(port, v) (__raw_writel(v, APBBASE_SCALAR_P(port)))
+
+#define UART_RX_DATA(s)                (((s) & UART_STATUS_DR) != 0)
+#define UART_TX_READY(s)       (((s) & UART_STATUS_THE) != 0)
+
+#endif /* __GRLIB_APBUART_H__ */
index c99f082..73f089d 100644 (file)
@@ -2,7 +2,7 @@
  *
  * Driver for Samsung S3C2410 SoC onboard UARTs.
  *
- * Ben Dooks, Copyright (c) 2003-2005,2008 Simtec Electronics
+ * Ben Dooks, Copyright (c) 2003-2008 Simtec Electronics
  *     http://armlinux.simtec.co.uk/
  *
  * This program is free software; you can redistribute it and/or modify
index 6e057d8..ce75e28 100644 (file)
@@ -2,7 +2,7 @@
  *
  * Driver for Samsung S3C2412 and S3C2413 SoC onboard UARTs.
  *
- * Ben Dooks, Copyright (c) 2003-2005,2008 Simtec Electronics
+ * Ben Dooks, Copyright (c) 2003-2008 Simtec Electronics
  *     http://armlinux.simtec.co.uk/
  *
  * This program is free software; you can redistribute it and/or modify
index 69ff5d3..094cc39 100644 (file)
@@ -2,7 +2,7 @@
  *
  * Driver for Samsung S3C2440 and S3C2442 SoC onboard UARTs.
  *
- * Ben Dooks, Copyright (c) 2003-2005,2008 Simtec Electronics
+ * Ben Dooks, Copyright (c) 2003-2008 Simtec Electronics
  *     http://armlinux.simtec.co.uk/
  *
  * This program is free software; you can redistribute it and/or modify
index 26c49e1..fad6083 100644 (file)
@@ -6,7 +6,7 @@
  *
  * Author: Sandeep Patil <sandeep.patil@azingo.com>
  *
- * Ben Dooks, Copyright (c) 2003-2005,2008 Simtec Electronics
+ * Ben Dooks, Copyright (c) 2003-2008 Simtec Electronics
  *     http://armlinux.simtec.co.uk/
  *
  * This program is free software; you can redistribute it and/or modify
index 1523e8d..52e3df1 100644 (file)
@@ -2,7 +2,7 @@
  *
  * Driver core for Samsung SoC onboard UARTs.
  *
- * Ben Dooks, Copyright (c) 2003-2005,2008 Simtec Electronics
+ * Ben Dooks, Copyright (c) 2003-2008 Simtec Electronics
  *     http://armlinux.simtec.co.uk/
  *
  * This program is free software; you can redistribute it and/or modify
index d3fe315..1fb2234 100644 (file)
@@ -2,7 +2,7 @@
  *
  * Driver for Samsung SoC onboard UARTs.
  *
- * Ben Dooks, Copyright (c) 2003-2005,2008 Simtec Electronics
+ * Ben Dooks, Copyright (c) 2003-2008 Simtec Electronics
  *     http://armlinux.simtec.co.uk/
  *
  * This program is free software; you can redistribute it and/or modify
index ba1a872..bf5f95a 100644 (file)
@@ -35,8 +35,8 @@
 
 #include <linux/spi/spi.h>
 
-#include <mach/dma.h>
-#include <mach/clock.h>
+#include <plat/dma.h>
+#include <plat/clock.h>
 
 
 #define OMAP2_MCSPI_MAX_FREQ           48000000
index e75ba9b..6c3a855 100644 (file)
@@ -51,8 +51,8 @@
 #include <asm/io.h>
 #include <asm/mach-types.h>
 
-#include <mach/mux.h>
-#include <mach/omap730.h>      /* OMAP730_IO_CONF registers */
+#include <plat/mux.h>
+#include <plat/omap7xx.h>      /* OMAP7XX_IO_CONF registers */
 
 
 /* FIXME address is now a platform device resource,
@@ -504,7 +504,7 @@ static int __init uwire_probe(struct platform_device *pdev)
        }
        clk_enable(uwire->ck);
 
-       if (cpu_is_omap730())
+       if (cpu_is_omap7xx())
                uwire_idx_shift = 1;
        else
                uwire_idx_shift = 2;
@@ -573,8 +573,8 @@ static int __init omap_uwire_init(void)
        }
        if (machine_is_omap_perseus2()) {
                /* configure pins: MPU_UW_nSCS1, MPU_UW_SDO, MPU_UW_SCLK */
-               int val = omap_readl(OMAP730_IO_CONF_9) & ~0x00EEE000;
-               omap_writel(val | 0x00AAA000, OMAP730_IO_CONF_9);
+               int val = omap_readl(OMAP7XX_IO_CONF_9) & ~0x00EEE000;
+               omap_writel(val | 0x00AAA000, OMAP7XX_IO_CONF_9);
        }
 
        return platform_driver_probe(&uwire_driver, uwire_probe);
index a8b6896..b22983e 100644 (file)
@@ -816,84 +816,83 @@ static int arlan_sysctl_reset(ctl_table * ctl, int write,
 
 
 /* Place files in /proc/sys/dev/arlan */
-#define CTBLN(num,card,nam) \
-        { .ctl_name = num,\
-          .procname = #nam,\
+#define CTBLN(card,nam) \
+        { .procname = #nam,\
           .data = &(arlan_conf[card].nam),\
-          .maxlen = sizeof(int), .mode = 0600, .proc_handler = &proc_dointvec}
+          .maxlen = sizeof(int), .mode = 0600, .proc_handler = proc_dointvec}
 #ifdef ARLAN_DEBUGGING
 
 #define ARLAN_PROC_DEBUG_ENTRIES \
-        { .ctl_name = 48, .procname = "entry_exit_debug",\
+        { .procname = "entry_exit_debug",\
           .data = &arlan_entry_and_exit_debug,\
-          .maxlen = sizeof(int), .mode = 0600, .proc_handler = &proc_dointvec},\
-       { .ctl_name = 49, .procname = "debug", .data = &arlan_debug,\
-          .maxlen = sizeof(int), .mode = 0600, .proc_handler = &proc_dointvec},
+          .maxlen = sizeof(int), .mode = 0600, .proc_handler = proc_dointvec},\
+       { .procname = "debug", .data = &arlan_debug,\
+          .maxlen = sizeof(int), .mode = 0600, .proc_handler = proc_dointvec},
 #else 
 #define ARLAN_PROC_DEBUG_ENTRIES
 #endif
 
 #define ARLAN_SYSCTL_TABLE_TOTAL(cardNo)\
-       CTBLN(1,cardNo,spreadingCode),\
-       CTBLN(2,cardNo, channelNumber),\
-       CTBLN(3,cardNo, scramblingDisable),\
-       CTBLN(4,cardNo, txAttenuation),\
-       CTBLN(5,cardNo, systemId), \
-       CTBLN(6,cardNo, maxDatagramSize),\
-       CTBLN(7,cardNo, maxFrameSize),\
-       CTBLN(8,cardNo, maxRetries),\
-       CTBLN(9,cardNo, receiveMode),\
-       CTBLN(10,cardNo, priority),\
-       CTBLN(11,cardNo, rootOrRepeater),\
-       CTBLN(12,cardNo, SID),\
-       CTBLN(13,cardNo, registrationMode),\
-       CTBLN(14,cardNo, registrationFill),\
-       CTBLN(15,cardNo, localTalkAddress),\
-       CTBLN(16,cardNo, codeFormat),\
-       CTBLN(17,cardNo, numChannels),\
-       CTBLN(18,cardNo, channel1),\
-       CTBLN(19,cardNo, channel2),\
-       CTBLN(20,cardNo, channel3),\
-       CTBLN(21,cardNo, channel4),\
-       CTBLN(22,cardNo, txClear),\
-       CTBLN(23,cardNo, txRetries),\
-       CTBLN(24,cardNo, txRouting),\
-       CTBLN(25,cardNo, txScrambled),\
-       CTBLN(26,cardNo, rxParameter),\
-       CTBLN(27,cardNo, txTimeoutMs),\
-       CTBLN(28,cardNo, waitCardTimeout),\
-       CTBLN(29,cardNo, channelSet), \
-       {.ctl_name = 30, .procname = "name",\
+       CTBLN(cardNo,spreadingCode),\
+       CTBLN(cardNo, channelNumber),\
+       CTBLN(cardNo, scramblingDisable),\
+       CTBLN(cardNo, txAttenuation),\
+       CTBLN(cardNo, systemId), \
+       CTBLN(cardNo, maxDatagramSize),\
+       CTBLN(cardNo, maxFrameSize),\
+       CTBLN(cardNo, maxRetries),\
+       CTBLN(cardNo, receiveMode),\
+       CTBLN(cardNo, priority),\
+       CTBLN(cardNo, rootOrRepeater),\
+       CTBLN(cardNo, SID),\
+       CTBLN(cardNo, registrationMode),\
+       CTBLN(cardNo, registrationFill),\
+       CTBLN(cardNo, localTalkAddress),\
+       CTBLN(cardNo, codeFormat),\
+       CTBLN(cardNo, numChannels),\
+       CTBLN(cardNo, channel1),\
+       CTBLN(cardNo, channel2),\
+       CTBLN(cardNo, channel3),\
+       CTBLN(cardNo, channel4),\
+       CTBLN(cardNo, txClear),\
+       CTBLN(cardNo, txRetries),\
+       CTBLN(cardNo, txRouting),\
+       CTBLN(cardNo, txScrambled),\
+       CTBLN(cardNo, rxParameter),\
+       CTBLN(cardNo, txTimeoutMs),\
+       CTBLN(cardNo, waitCardTimeout),\
+       CTBLN(cardNo, channelSet), \
+       { .procname = "name",\
         .data = arlan_conf[cardNo].siteName,\
-        .maxlen = 16, .mode = 0600, .proc_handler = &proc_dostring},\
-       CTBLN(31,cardNo,waitTime),\
-       CTBLN(32,cardNo,lParameter),\
-       CTBLN(33,cardNo,_15),\
-       CTBLN(34,cardNo,headerSize),\
-       CTBLN(36,cardNo,tx_delay_ms),\
-       CTBLN(37,cardNo,retries),\
-       CTBLN(38,cardNo,ReTransmitPacketMaxSize),\
-       CTBLN(39,cardNo,waitReTransmitPacketMaxSize),\
-       CTBLN(40,cardNo,fastReTransCount),\
-       CTBLN(41,cardNo,driverRetransmissions),\
-       CTBLN(42,cardNo,txAckTimeoutMs),\
-       CTBLN(43,cardNo,registrationInterrupts),\
-       CTBLN(44,cardNo,hardwareType),\
-       CTBLN(45,cardNo,radioType),\
-       CTBLN(46,cardNo,writeEEPROM),\
-       CTBLN(47,cardNo,writeRadioType),\
+        .maxlen = 16, .mode = 0600, .proc_handler = proc_dostring},\
+       CTBLN(cardNo,waitTime),\
+       CTBLN(cardNo,lParameter),\
+       CTBLN(cardNo,_15),\
+       CTBLN(cardNo,headerSize),\
+       CTBLN(cardNo,tx_delay_ms),\
+       CTBLN(cardNo,retries),\
+       CTBLN(cardNo,ReTransmitPacketMaxSize),\
+       CTBLN(cardNo,waitReTransmitPacketMaxSize),\
+       CTBLN(cardNo,fastReTransCount),\
+       CTBLN(cardNo,driverRetransmissions),\
+       CTBLN(cardNo,txAckTimeoutMs),\
+       CTBLN(cardNo,registrationInterrupts),\
+       CTBLN(cardNo,hardwareType),\
+       CTBLN(cardNo,radioType),\
+       CTBLN(cardNo,writeEEPROM),\
+       CTBLN(cardNo,writeRadioType),\
        ARLAN_PROC_DEBUG_ENTRIES\
-       CTBLN(50,cardNo,in_speed),\
-       CTBLN(51,cardNo,out_speed),\
-       CTBLN(52,cardNo,in_speed10),\
-       CTBLN(53,cardNo,out_speed10),\
-       CTBLN(54,cardNo,in_speed_max),\
-       CTBLN(55,cardNo,out_speed_max),\
-       CTBLN(56,cardNo,measure_rate),\
-       CTBLN(57,cardNo,pre_Command_Wait),\
-       CTBLN(58,cardNo,rx_tweak1),\
-       CTBLN(59,cardNo,rx_tweak2),\
-       CTBLN(60,cardNo,tx_queue_len),\
+       CTBLN(cardNo,in_speed),\
+       CTBLN(cardNo,out_speed),\
+       CTBLN(cardNo,in_speed10),\
+       CTBLN(cardNo,out_speed10),\
+       CTBLN(cardNo,in_speed_max),\
+       CTBLN(cardNo,out_speed_max),\
+       CTBLN(cardNo,measure_rate),\
+       CTBLN(cardNo,pre_Command_Wait),\
+       CTBLN(cardNo,rx_tweak1),\
+       CTBLN(cardNo,rx_tweak2),\
+       CTBLN(cardNo,tx_queue_len),\
 
 
 
@@ -903,63 +902,56 @@ static ctl_table arlan_conf_table0[] =
 
 #ifdef ARLAN_PROC_SHM_DUMP
        {
-               .ctl_name       = 150,
                .procname       = "arlan0-txRing",
                .data           = &arlan_drive_info,
                .maxlen         = ARLAN_STR_SIZE,
                .mode           = 0400,
-               .proc_handler   = &arlan_sysctl_infotxRing,
+               .proc_handler   = arlan_sysctl_infotxRing,
        },
        {
-               .ctl_name       = 151,
                .procname       = "arlan0-rxRing",
                .data           = &arlan_drive_info,
                .maxlen         = ARLAN_STR_SIZE,
                .mode           = 0400,
-               .proc_handler   = &arlan_sysctl_inforxRing,
+               .proc_handler   = arlan_sysctl_inforxRing,
        },
        {
-               .ctl_name       = 152,
                .procname       = "arlan0-18",
                .data           = &arlan_drive_info,
                .maxlen         = ARLAN_STR_SIZE,
                .mode           = 0400,
-               .proc_handler   = &arlan_sysctl_info18,
+               .proc_handler   = arlan_sysctl_info18,
        },
        {
-               .ctl_name       = 153,
                .procname       = "arlan0-ring",
                .data           = &arlan_drive_info,
                .maxlen         = ARLAN_STR_SIZE,
                .mode           = 0400,
-               .proc_handler   = &arlan_sysctl_info161719,
+               .proc_handler   = arlan_sysctl_info161719,
        },
        {
-               .ctl_name       = 154,
                .procname       = "arlan0-shm-cpy",
                .data           = &arlan_drive_info,
                .maxlen         = ARLAN_STR_SIZE,
                .mode           = 0400,
-               .proc_handler   = &arlan_sysctl_info,
+               .proc_handler   = arlan_sysctl_info,
        },
 #endif
        {
-               .ctl_name       = 155,
                .procname       = "config0",
                .data           = &conf_reset_result,
                .maxlen         = 100,
                .mode           = 0400,
-               .proc_handler   = &arlan_configure
+               .proc_handler   = arlan_configure
        },
        {
-               .ctl_name       = 156,
                .procname       = "reset0",
                .data           = &conf_reset_result,
                .maxlen         = 100,
                .mode           = 0400,
-               .proc_handler   = &arlan_sysctl_reset,
+               .proc_handler   = arlan_sysctl_reset,
        },
-       { .ctl_name = 0 }
+       {  }
 };
 
 static ctl_table arlan_conf_table1[] =
@@ -969,63 +961,56 @@ static ctl_table arlan_conf_table1[] =
 
 #ifdef ARLAN_PROC_SHM_DUMP
        {
-               .ctl_name       = 150,
                .procname       = "arlan1-txRing",
                .data           = &arlan_drive_info,
                .maxlen         = ARLAN_STR_SIZE,
                .mode           = 0400,
-               .proc_handler   = &arlan_sysctl_infotxRing,
+               .proc_handler   = arlan_sysctl_infotxRing,
        },
        {
-               .ctl_name       = 151,
                .procname       = "arlan1-rxRing",
                .data           = &arlan_drive_info,
                .maxlen         = ARLAN_STR_SIZE,
                .mode           = 0400,
-               .proc_handler   = &arlan_sysctl_inforxRing,
+               .proc_handler   = arlan_sysctl_inforxRing,
        },
        {
-               .ctl_name       = 152,
                .procname       = "arlan1-18",
                .data           = &arlan_drive_info,
                .maxlen         = ARLAN_STR_SIZE,
                .mode           = 0400,
-               .proc_handler   = &arlan_sysctl_info18,
+               .proc_handler   = arlan_sysctl_info18,
        },
        {
-               .ctl_name       = 153,
                .procname       = "arlan1-ring",
                .data           = &arlan_drive_info,
                .maxlen         = ARLAN_STR_SIZE,
                .mode           = 0400,
-               .proc_handler   = &arlan_sysctl_info161719,
+               .proc_handler   = arlan_sysctl_info161719,
        },
        {
-               .ctl_name       = 154,
                .procname       = "arlan1-shm-cpy",
                .data           = &arlan_drive_info,
                .maxlen         = ARLAN_STR_SIZE,
                .mode           = 0400,
-               .proc_handler   = &arlan_sysctl_info,
+               .proc_handler   = arlan_sysctl_info,
        },
 #endif
        {
-               .ctl_name       = 155,
                .procname       = "config1",
                .data           = &conf_reset_result,
                .maxlen         = 100,
                .mode           = 0400,
-               .proc_handler   = &arlan_configure,
+               .proc_handler   = arlan_configure,
        },
        {
-               .ctl_name       = 156,
                .procname       = "reset1",
                .data           = &conf_reset_result,
                .maxlen         = 100,
                .mode           = 0400,
-               .proc_handler   = &arlan_sysctl_reset,
+               .proc_handler   = arlan_sysctl_reset,
        },
-       { .ctl_name = 0 }
+       { }
 };
 
 static ctl_table arlan_conf_table2[] =
@@ -1035,63 +1020,56 @@ static ctl_table arlan_conf_table2[] =
 
 #ifdef ARLAN_PROC_SHM_DUMP
        {
-               .ctl_name       = 150,
                .procname       = "arlan2-txRing",
                .data           = &arlan_drive_info,
                .maxlen         = ARLAN_STR_SIZE,
                .mode           = 0400,
-               .proc_handler   = &arlan_sysctl_infotxRing,
+               .proc_handler   = arlan_sysctl_infotxRing,
        },
        {
-               .ctl_name       = 151,
                .procname       = "arlan2-rxRing",
                .data           = &arlan_drive_info,
                .maxlen         = ARLAN_STR_SIZE,
                .mode           = 0400,
-               .proc_handler   = &arlan_sysctl_inforxRing,
+               .proc_handler   = arlan_sysctl_inforxRing,
        },
        {
-               .ctl_name       = 152,
                .procname       = "arlan2-18",
                .data           = &arlan_drive_info,
                .maxlen         = ARLAN_STR_SIZE,
                .mode           = 0400,
-               .proc_handler   = &arlan_sysctl_info18,
+               .proc_handler   = arlan_sysctl_info18,
        },
        {
-               .ctl_name       = 153,
                .procname       = "arlan2-ring",
                .data           = &arlan_drive_info,
                .maxlen         = ARLAN_STR_SIZE,
                .mode           = 0400,
-               .proc_handler   = &arlan_sysctl_info161719,
+               .proc_handler   = arlan_sysctl_info161719,
        },
        {
-               .ctl_name       = 154,
                .procname       = "arlan2-shm-cpy",
                .data           = &arlan_drive_info,
                .maxlen         = ARLAN_STR_SIZE,
                .mode           = 0400,
-               .proc_handler   = &arlan_sysctl_info,
+               .proc_handler   = arlan_sysctl_info,
        },
 #endif
        {
-               .ctl_name       = 155,
                .procname       = "config2",
                .data           = &conf_reset_result,
                .maxlen         = 100,
                .mode           = 0400,
-               .proc_handler   = &arlan_configure,
+               .proc_handler   = arlan_configure,
        },
        {
-               .ctl_name       = 156,
                .procname       = "reset2",
                .data           = &conf_reset_result,
                .maxlen         = 100,
                .mode           = 0400,
-               .proc_handler   = &arlan_sysctl_reset,
+               .proc_handler   = arlan_sysctl_reset,
        },
-       { .ctl_name = 0 }
+       { }
 };
 
 static ctl_table arlan_conf_table3[] =
@@ -1101,63 +1079,56 @@ static ctl_table arlan_conf_table3[] =
 
 #ifdef ARLAN_PROC_SHM_DUMP
        {
-               .ctl_name       = 150,
                .procname       = "arlan3-txRing",
                .data           = &arlan_drive_info,
                .maxlen         = ARLAN_STR_SIZE,
                .mode           = 0400,
-               .proc_handler   = &arlan_sysctl_infotxRing,
+               .proc_handler   = arlan_sysctl_infotxRing,
        },
        {
-               .ctl_name       = 151,
                .procname       = "arlan3-rxRing",
                .data           = &arlan_drive_info,
                .maxlen         = ARLAN_STR_SIZE,
                .mode           = 0400,
-               .proc_handler   = &arlan_sysctl_inforxRing,
+               .proc_handler   = arlan_sysctl_inforxRing,
        },
        {
-               .ctl_name       = 152,
                .procname       = "arlan3-18",
                .data           = &arlan_drive_info,
                .maxlen         = ARLAN_STR_SIZE,
                .mode           = 0400,
-               .proc_handler   = &arlan_sysctl_info18,
+               .proc_handler   = arlan_sysctl_info18,
        },
        {
-               .ctl_name       = 153,
                .procname       = "arlan3-ring",
                .data           = &arlan_drive_info,
                .maxlen         = ARLAN_STR_SIZE,
                .mode           = 0400,
-               .proc_handler   = &arlan_sysctl_info161719,
+               .proc_handler   = arlan_sysctl_info161719,
        },
        {
-               .ctl_name       = 154,
                .procname       = "arlan3-shm-cpy",
                .data           = &arlan_drive_info,
                .maxlen         = ARLAN_STR_SIZE,
                .mode           = 0400,
-               .proc_handler   = &arlan_sysctl_info,
+               .proc_handler   = arlan_sysctl_info,
        },
 #endif
        {
-               .ctl_name       = 155,
                .procname       = "config3",
                .data           = &conf_reset_result,
                .maxlen         = 100,
                .mode           = 0400,
-               .proc_handler   = &arlan_configure,
+               .proc_handler   = arlan_configure,
        },
        {
-               .ctl_name       = 156,
                .procname       = "reset3",
                .data           = &conf_reset_result,
                .maxlen         = 100,
                .mode           = 0400,
-               .proc_handler   = &arlan_sysctl_reset,
+               .proc_handler   = arlan_sysctl_reset,
        },
-       { .ctl_name = 0 }
+       { }
 };
 
 
@@ -1165,41 +1136,37 @@ static ctl_table arlan_conf_table3[] =
 static ctl_table arlan_table[] =
 {
        {
-               .ctl_name       = 0,
                .procname       = "arlan0",
                .maxlen         = 0,
                .mode           = 0600,
                .child          = arlan_conf_table0,
        },
        {
-               .ctl_name       = 0,
                .procname       = "arlan1",
                .maxlen         = 0,
                .mode           = 0600,
                .child          = arlan_conf_table1,
        },
        {
-               .ctl_name       = 0,
                .procname       = "arlan2",
                .maxlen         = 0,
                .mode           = 0600,
                .child          = arlan_conf_table2,
        },
        {
-               .ctl_name       = 0,
                .procname       = "arlan3",
                .maxlen         = 0,
                .mode           = 0600,
                .child          = arlan_conf_table3,
        },
-       { .ctl_name = 0 }
+       { }
 };
 
 #else
 
-static ctl_table arlan_table[MAX_ARLANS + 1] =
+static ctl_table arlan_table[] =
 {
-       { .ctl_name = 0 }
+       { }
 };
 #endif
 
@@ -1209,22 +1176,14 @@ static ctl_table arlan_table[MAX_ARLANS + 1] =
 static ctl_table arlan_root_table[] =
 {
        {
-               .ctl_name       = CTL_ARLAN,
                .procname       = "arlan",
                .maxlen         = 0,
                .mode           = 0555,
                .child          = arlan_table,
        },
-       { .ctl_name = 0 }
+       {  }
 };
 
-/* Make sure that /proc/sys/dev is there */
-//static ctl_table arlan_device_root_table[] =
-//{
-//     {CTL_DEV, "dev", NULL, 0, 0555, arlan_root_table},
-//     {0}
-//};
-
 
 static struct ctl_table_header *arlan_device_sysctl_header;
 
@@ -1234,8 +1193,6 @@ int __init init_arlan_proc(void)
        int i = 0;
        if (arlan_device_sysctl_header)
                return 0;
-       for (i = 0; i < MAX_ARLANS && arlan_device[i]; i++)
-               arlan_table[i].ctl_name = i + 1;
        arlan_device_sysctl_header = register_sysctl_table(arlan_root_table);
        if (!arlan_device_sysctl_header)
                return -1;
index c94de31..f69b778 100644 (file)
@@ -143,7 +143,6 @@ static int pohmelfs_writepages(struct address_space *mapping, struct writeback_c
        struct inode *inode = mapping->host;
        struct pohmelfs_inode *pi = POHMELFS_I(inode);
        struct pohmelfs_sb *psb = POHMELFS_SB(inode->i_sb);
-       struct backing_dev_info *bdi = mapping->backing_dev_info;
        int err = 0;
        int done = 0;
        int nr_pages;
@@ -152,11 +151,6 @@ static int pohmelfs_writepages(struct address_space *mapping, struct writeback_c
        int scanned = 0;
        int range_whole = 0;
 
-       if (wbc->nonblocking && bdi_write_congested(bdi)) {
-               wbc->encountered_congestion = 1;
-               return 0;
-       }
-
        if (wbc->range_cyclic) {
                index = mapping->writeback_index; /* Start from prev offset */
                end = -1;
@@ -248,10 +242,6 @@ retry:
 
                        if (wbc->nr_to_write <= 0)
                                done = 1;
-                       if (wbc->nonblocking && bdi_write_congested(bdi)) {
-                               wbc->encountered_congestion = 1;
-                               done = 1;
-                       }
 
                        continue;
 out_continue:
index a2db0e1..f81e4f0 100644 (file)
@@ -52,9 +52,9 @@
 #include <asm/unaligned.h>
 #include <asm/mach-types.h>
 
-#include <mach/dma.h>
-#include <mach/usb.h>
-#include <mach/control.h>
+#include <plat/dma.h>
+#include <plat/usb.h>
+#include <plat/control.h>
 
 #include "omap_udc.h"
 
@@ -2098,6 +2098,7 @@ static inline int machine_without_vbus_sense(void)
                || machine_is_omap_h4()
 #endif
                || machine_is_sx1()
+               || cpu_is_omap7xx() /* No known omap7xx boards with vbus sense */
                );
 }
 
@@ -2838,6 +2839,16 @@ static int __init omap_udc_probe(struct platform_device *pdev)
                udelay(100);
        }
 
+       if (cpu_is_omap7xx()) {
+               dc_clk = clk_get(&pdev->dev, "usb_dc_ck");
+               hhc_clk = clk_get(&pdev->dev, "l3_ocpi_ck");
+               BUG_ON(IS_ERR(dc_clk) || IS_ERR(hhc_clk));
+               /* can't use omap_udc_enable_clock yet */
+               clk_enable(dc_clk);
+               clk_enable(hhc_clk);
+               udelay(100);
+       }
+
        INFO("OMAP UDC rev %d.%d%s\n",
                omap_readw(UDC_REV) >> 4, omap_readw(UDC_REV) & 0xf,
                config->otg ? ", Mini-AB" : "");
@@ -2970,7 +2981,7 @@ known:
                goto cleanup3;
        }
 #endif
-       if (cpu_is_omap16xx()) {
+       if (cpu_is_omap16xx() || cpu_is_omap7xx()) {
                udc->dc_clk = dc_clk;
                udc->hhc_clk = hhc_clk;
                clk_disable(hhc_clk);
@@ -3008,7 +3019,7 @@ cleanup0:
        if (xceiv)
                otg_put_transceiver(xceiv);
 
-       if (cpu_is_omap16xx() || cpu_is_omap24xx()) {
+       if (cpu_is_omap16xx() || cpu_is_omap24xx() || cpu_is_omap7xx()) {
                clk_disable(hhc_clk);
                clk_disable(dc_clk);
                clk_put(hhc_clk);
@@ -3115,6 +3126,10 @@ static struct platform_driver udc_driver = {
 
 static int __init udc_init(void)
 {
+       /* Disable DMA for omap7xx -- it doesn't work right. */
+       if (cpu_is_omap7xx())
+               use_dma = 0;
+
        INFO("%s, version: " DRIVER_VERSION
 #ifdef USE_ISO
                " (iso)"
index 83cbecd..5645f70 100644 (file)
 #include <asm/io.h>
 #include <asm/mach-types.h>
 
-#include <mach/mux.h>
+#include <plat/mux.h>
 #include <mach/irqs.h>
-#include <mach/fpga.h>
-#include <mach/usb.h>
+#include <plat/fpga.h>
+#include <plat/usb.h>
 
 
 /* OMAP-1510 OHCI has its own MMU for DMA */
index 3487520..6761d20 100644 (file)
@@ -35,7 +35,7 @@
 
 #include <asm/mach-types.h>
 #include <mach/hardware.h>
-#include <mach/mux.h>
+#include <plat/mux.h>
 
 #include "musb_core.h"
 #include "omap2430.h"
index dc76707..fbede77 100644 (file)
@@ -12,7 +12,7 @@
 
 #if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP3430)
 #include <mach/hardware.h>
-#include <mach/usb.h>
+#include <plat/usb.h>
 
 /*
  * OMAP2430-specific definitions
index 7e073a0..e13c770 100644 (file)
@@ -15,8 +15,8 @@
 #include <linux/usb.h>
 #include <linux/platform_device.h>
 #include <linux/dma-mapping.h>
-#include <mach/dma.h>
-#include <mach/mux.h>
+#include <plat/dma.h>
+#include <plat/mux.h>
 
 #include "musb_core.h"
 
index 77a5f41..d54460a 100644 (file)
@@ -36,8 +36,8 @@
 #include <asm/irq.h>
 #include <asm/mach-types.h>
 
-#include <mach/usb.h>
-#include <mach/mux.h>
+#include <plat/usb.h>
+#include <plat/mux.h>
 
 
 #ifndef        DEBUG
index 188e1ba..6b89eb5 100644 (file)
@@ -5,6 +5,9 @@
 menu "Graphics support"
        depends on HAS_IOMEM
 
+config HAVE_FB_ATMEL
+       bool
+
 source "drivers/char/agp/Kconfig"
 
 source "drivers/gpu/vga/Kconfig"
@@ -937,7 +940,7 @@ config FB_S1D13XXX
 
 config FB_ATMEL
        tristate "AT91/AT32 LCD Controller support"
-       depends on FB && (ARCH_AT91SAM9261 || ARCH_AT91SAM9G10 || ARCH_AT91SAM9263 || ARCH_AT91SAM9RL || ARCH_AT91SAM9G45 || ARCH_AT91CAP9 || AVR32)
+       depends on FB && HAVE_FB_ATMEL
        select FB_CFB_FILLRECT
        select FB_CFB_COPYAREA
        select FB_CFB_IMAGEBLIT
index 37624f7..b7687c5 100644 (file)
@@ -2242,6 +2242,9 @@ static int ext_setcolreg(unsigned int regno, unsigned int red,
        if (!external_vgaiobase)
                return 1;
 
+       if (regno > 255)
+               return 1;
+
        switch (external_card_type) {
        case IS_VGA:
                OUTB(0x3c8, regno);
index 701a108..7fcb0eb 100644 (file)
@@ -25,6 +25,7 @@
 
 #define DA9034_WLED_CONTROL1   0x3C
 #define DA9034_WLED_CONTROL2   0x3D
+#define DA9034_WLED_ISET(x)    ((x) & 0x1f)
 
 #define DA9034_WLED_BOOST_EN   (1 << 5)
 
@@ -101,6 +102,7 @@ static struct backlight_ops da903x_backlight_ops = {
 
 static int da903x_backlight_probe(struct platform_device *pdev)
 {
+       struct da9034_backlight_pdata *pdata = pdev->dev.platform_data;
        struct da903x_backlight_data *data;
        struct backlight_device *bl;
        int max_brightness;
@@ -127,6 +129,11 @@ static int da903x_backlight_probe(struct platform_device *pdev)
        data->da903x_dev = pdev->dev.parent;
        data->current_brightness = 0;
 
+       /* adjust the WLED output current */
+       if (pdata)
+               da903x_write(data->da903x_dev, DA9034_WLED_CONTROL2,
+                               DA9034_WLED_ISET(pdata->output_current));
+
        bl = backlight_device_register(pdev->name, data->da903x_dev,
                        data, &da903x_backlight_ops);
        if (IS_ERR(bl)) {
index cbad67e..8693e5f 100644 (file)
@@ -26,8 +26,8 @@
 #include <linux/backlight.h>
 
 #include <mach/hardware.h>
-#include <mach/board.h>
-#include <mach/mux.h>
+#include <plat/board.h>
+#include <plat/mux.h>
 
 #define OMAPBL_MAX_INTENSITY           0xff
 
index bbfb502..4a3d46e 100644 (file)
@@ -367,6 +367,7 @@ static int __devinit tdo24m_probe(struct spi_device *spi)
 
        spi_message_init(m);
 
+       x->cs_change = 1;
        x->tx_buf = &lcd->buf[0];
        spi_message_add_tail(x, m);
 
index b63b198..49226a1 100644 (file)
@@ -35,6 +35,7 @@ objs-y$(CONFIG_MACH_OMAP3EVM) += lcd_omap3evm.o
 objs-y$(CONFIG_MACH_OMAP3_BEAGLE) += lcd_omap3beagle.o
 objs-y$(CONFIG_FB_OMAP_LCD_MIPID) += lcd_mipid.o
 objs-y$(CONFIG_MACH_OVERO) += lcd_overo.o
+objs-y$(CONFIG_MACH_HERALD) += lcd_htcherald.o
 
 omapfb-objs := $(objs-yy)
 
index 70dadf9..f5d75f2 100644 (file)
@@ -26,9 +26,9 @@
 #include <linux/delay.h>
 #include <linux/clk.h>
 
-#include <mach/dma.h>
-#include <mach/omapfb.h>
-#include <mach/blizzard.h>
+#include <plat/dma.h>
+#include <plat/omapfb.h>
+#include <plat/blizzard.h>
 
 #include "dispc.h"
 
index f16e421..7c833db 100644 (file)
@@ -25,9 +25,9 @@
 #include <linux/clk.h>
 #include <linux/io.h>
 
-#include <mach/sram.h>
-#include <mach/omapfb.h>
-#include <mach/board.h>
+#include <plat/sram.h>
+#include <plat/omapfb.h>
+#include <plat/board.h>
 
 #include "dispc.h"
 
@@ -204,6 +204,7 @@ static u32 inline dispc_read_reg(int idx)
 /* Select RFBI or bypass mode */
 static void enable_rfbi_mode(int enable)
 {
+       void __iomem *rfbi_control;
        u32 l;
 
        l = dispc_read_reg(DISPC_CONTROL);
@@ -216,9 +217,15 @@ static void enable_rfbi_mode(int enable)
        dispc_write_reg(DISPC_CONTROL, l);
 
        /* Set bypass mode in RFBI module */
-       l = __raw_readl(OMAP2_IO_ADDRESS(RFBI_CONTROL));
+       rfbi_control = ioremap(RFBI_CONTROL, SZ_1K);
+       if (!rfbi_control) {
+               pr_err("Unable to ioremap rfbi_control\n");
+               return;
+       }
+       l = __raw_readl(rfbi_control);
        l |= enable ? 0 : (1 << 1);
-       __raw_writel(l, OMAP2_IO_ADDRESS(RFBI_CONTROL));
+       __raw_writel(l, rfbi_control);
+       iounmap(rfbi_control);
 }
 
 static void set_lcd_data_lines(int data_lines)
@@ -1367,6 +1374,7 @@ static int omap_dispc_init(struct omapfb_device *fbdev, int ext_mode,
        int r;
        u32 l;
        struct lcd_panel *panel = fbdev->panel;
+       void __iomem *ram_fw_base;
        int tmo = 10000;
        int skip_init = 0;
        int i;
@@ -1441,7 +1449,13 @@ static int omap_dispc_init(struct omapfb_device *fbdev, int ext_mode,
        }
 
        /* L3 firewall setting: enable access to OCM RAM */
-       __raw_writel(0x402000b0, OMAP2_IO_ADDRESS(0x680050a0));
+       ram_fw_base = ioremap(0x68005000, SZ_1K);
+       if (!ram_fw_base) {
+               dev_err(dispc.fbdev->dev, "Cannot ioremap to enable OCM RAM\n");
+               goto fail1;
+       }
+       __raw_writel(0x402000b0, ram_fw_base + 0xa0);
+       iounmap(ram_fw_base);
 
        if ((r = alloc_palette_ram()) < 0)
                goto fail2;
index ca51583..17a975e 100644 (file)
@@ -26,9 +26,9 @@
 #include <linux/delay.h>
 #include <linux/clk.h>
 
-#include <mach/dma.h>
-#include <mach/omapfb.h>
-#include <mach/hwa742.h>
+#include <plat/dma.h>
+#include <plat/omapfb.h>
+#include <plat/hwa742.h>
 
 #define HWA742_REV_CODE_REG       0x0
 #define HWA742_CONFIG_REG         0x2
index 393712b..fea7fee 100644 (file)
@@ -27,8 +27,8 @@
 #include <linux/gpio.h>
 #include <linux/i2c/twl4030.h>
 
-#include <mach/mux.h>
-#include <mach/omapfb.h>
+#include <plat/mux.h>
+#include <plat/omapfb.h>
 #include <asm/mach-types.h>
 
 #define SDP2430_LCD_PANEL_BACKLIGHT_GPIO       91
index 1f74399..3d52772 100644 (file)
@@ -25,9 +25,9 @@
 #include <linux/io.h>
 #include <linux/delay.h>
 
-#include <mach/board-ams-delta.h>
+#include <plat/board-ams-delta.h>
 #include <mach/hardware.h>
-#include <mach/omapfb.h>
+#include <plat/omapfb.h>
 
 #define AMS_DELTA_DEFAULT_CONTRAST     112
 
index 626ae3a..4c5cefc 100644 (file)
@@ -25,8 +25,8 @@
 #include <linux/platform_device.h>
 
 #include <mach/gpio.h>
-#include <mach/mux.h>
-#include <mach/omapfb.h>
+#include <plat/mux.h>
+#include <plat/omapfb.h>
 
 /* #define USE_35INCH_LCD 1 */
 
index 417ae5e..240b4fb 100644 (file)
@@ -24,7 +24,7 @@
 #include <linux/i2c/tps65010.h>
 
 #include <mach/gpio.h>
-#include <mach/omapfb.h>
+#include <plat/omapfb.h>
 
 #define MODULE_NAME    "omapfb-lcd_h3"
 
index 0c398bd..720625d 100644 (file)
@@ -22,7 +22,7 @@
 #include <linux/module.h>
 #include <linux/platform_device.h>
 
-#include <mach/omapfb.h>
+#include <plat/omapfb.h>
 
 static int h4_panel_init(struct lcd_panel *panel, struct omapfb_device *fbdev)
 {
diff --git a/drivers/video/omap/lcd_htcherald.c b/drivers/video/omap/lcd_htcherald.c
new file mode 100644 (file)
index 0000000..2e0c81e
--- /dev/null
@@ -0,0 +1,130 @@
+/*
+ * File: drivers/video/omap/lcd-htcherald.c
+ *
+ * LCD panel support for the HTC Herald
+ *
+ * Copyright (C) 2009 Cory Maccarrone <darkstar6262@gmail.com>
+ * Copyright (C) 2009 Wing Linux
+ *
+ * Based on the lcd_htcwizard.c file from the linwizard project:
+ * Copyright (C) linwizard.sourceforge.net
+ * Author: Angelo Arrifano <miknix@gmail.com>
+ * Based on lcd_h4 by Imre Deak <imre.deak@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#include <plat/omapfb.h>
+
+static int htcherald_panel_init(struct lcd_panel *panel,
+                                       struct omapfb_device *fbdev)
+{
+       return 0;
+}
+
+static void htcherald_panel_cleanup(struct lcd_panel *panel)
+{
+}
+
+static int htcherald_panel_enable(struct lcd_panel *panel)
+{
+       return 0;
+}
+
+static void htcherald_panel_disable(struct lcd_panel *panel)
+{
+}
+
+static unsigned long htcherald_panel_get_caps(struct lcd_panel *panel)
+{
+       return 0;
+}
+
+/* Found on WIZ200 (miknix) and some HERA110 models (darkstar62) */
+struct lcd_panel htcherald_panel_1 = {
+       .name           = "lcd_herald",
+       .config         = OMAP_LCDC_PANEL_TFT |
+                         OMAP_LCDC_INV_HSYNC |
+                         OMAP_LCDC_INV_VSYNC |
+                         OMAP_LCDC_INV_PIX_CLOCK,
+       .bpp            = 16,
+       .data_lines     = 16,
+       .x_res          = 240,
+       .y_res          = 320,
+       .pixel_clock    = 6093,
+       .pcd            = 0, /* 15 */
+       .hsw            = 10,
+       .hfp            = 10,
+       .hbp            = 20,
+       .vsw            = 3,
+       .vfp            = 2,
+       .vbp            = 2,
+
+       .init           = htcherald_panel_init,
+       .cleanup        = htcherald_panel_cleanup,
+       .enable         = htcherald_panel_enable,
+       .disable        = htcherald_panel_disable,
+       .get_caps       = htcherald_panel_get_caps,
+};
+
+static int htcherald_panel_probe(struct platform_device *pdev)
+{
+       omapfb_register_panel(&htcherald_panel_1);
+       return 0;
+}
+
+static int htcherald_panel_remove(struct platform_device *pdev)
+{
+       return 0;
+}
+
+static int htcherald_panel_suspend(struct platform_device *pdev,
+                                               pm_message_t mesg)
+{
+       return 0;
+}
+
+static int htcherald_panel_resume(struct platform_device *pdev)
+{
+       return 0;
+}
+
+struct platform_driver htcherald_panel_driver = {
+       .probe          = htcherald_panel_probe,
+       .remove         = htcherald_panel_remove,
+       .suspend        = htcherald_panel_suspend,
+       .resume         = htcherald_panel_resume,
+       .driver         = {
+               .name   = "lcd_htcherald",
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int htcherald_panel_drv_init(void)
+{
+       return platform_driver_register(&htcherald_panel_driver);
+}
+
+static void htcherald_panel_drv_cleanup(void)
+{
+       platform_driver_unregister(&htcherald_panel_driver);
+}
+
+module_init(htcherald_panel_drv_init);
+module_exit(htcherald_panel_drv_cleanup);
+
index cdbd8bb..aafe9b4 100644 (file)
@@ -23,8 +23,8 @@
 #include <linux/platform_device.h>
 #include <linux/io.h>
 
-#include <mach/fpga.h>
-#include <mach/omapfb.h>
+#include <plat/fpga.h>
+#include <plat/omapfb.h>
 
 static int innovator1510_panel_init(struct lcd_panel *panel,
                                    struct omapfb_device *fbdev)
index 268f7f8..0de3382 100644 (file)
@@ -23,7 +23,7 @@
 #include <linux/platform_device.h>
 
 #include <mach/gpio.h>
-#include <mach/omapfb.h>
+#include <plat/omapfb.h>
 
 #define MODULE_NAME    "omapfb-lcd_h3"
 
index dbfe897..6a260df 100644 (file)
@@ -27,8 +27,8 @@
 #include <linux/i2c/twl4030.h>
 
 #include <mach/gpio.h>
-#include <mach/mux.h>
-#include <mach/omapfb.h>
+#include <plat/mux.h>
+#include <plat/omapfb.h>
 #include <asm/mach-types.h>
 
 #define LCD_PANEL_BACKLIGHT_GPIO       (15 + OMAP_MAX_GPIO_LINES)
index 918ee89..2162eb0 100644 (file)
@@ -23,8 +23,8 @@
 #include <linux/workqueue.h>
 #include <linux/spi/spi.h>
 
-#include <mach/omapfb.h>
-#include <mach/lcd_mipid.h>
+#include <plat/omapfb.h>
+#include <plat/lcd_mipid.h>
 
 #define MIPID_MODULE_NAME              "lcd_mipid"
 
index 7a2bbe2..e1a38ab 100644 (file)
@@ -26,8 +26,8 @@
 #include <linux/gpio.h>
 #include <linux/i2c/twl4030.h>
 
-#include <mach/mux.h>
-#include <mach/omapfb.h>
+#include <plat/mux.h>
+#include <plat/omapfb.h>
 #include <asm/mach-types.h>
 
 #define LCD_PANEL_ENABLE_GPIO  154
index 4011910..ccec084 100644 (file)
@@ -25,8 +25,8 @@
 #include <linux/gpio.h>
 #include <linux/i2c/twl4030.h>
 
-#include <mach/mux.h>
-#include <mach/omapfb.h>
+#include <plat/mux.h>
+#include <plat/omapfb.h>
 #include <asm/mach-types.h>
 
 #define LCD_PANEL_ENABLE_GPIO       170
index b6a4c2c..556eb31 100644 (file)
@@ -25,8 +25,8 @@
 #include <linux/gpio.h>
 #include <linux/i2c/twl4030.h>
 
-#include <mach/mux.h>
-#include <mach/omapfb.h>
+#include <plat/mux.h>
+#include <plat/omapfb.h>
 #include <asm/mach-types.h>
 
 #define LCD_PANEL_ENABLE_GPIO       153
index b3fa88b..bb21d7d 100644 (file)
@@ -24,8 +24,8 @@
 #include <linux/platform_device.h>
 
 #include <mach/gpio.h>
-#include <mach/mux.h>
-#include <mach/omapfb.h>
+#include <plat/mux.h>
+#include <plat/omapfb.h>
 
 static int osk_panel_init(struct lcd_panel *panel, struct omapfb_device *fbdev)
 {
index 2bc5c92..b0f86e5 100644 (file)
@@ -24,8 +24,8 @@
 #include <linux/i2c/twl4030.h>
 
 #include <mach/gpio.h>
-#include <mach/mux.h>
-#include <mach/omapfb.h>
+#include <plat/mux.h>
+#include <plat/omapfb.h>
 #include <asm/mach-types.h>
 
 #define LCD_ENABLE       144
index 4bf3c79..d302896 100644 (file)
@@ -23,8 +23,8 @@
 #include <linux/platform_device.h>
 #include <linux/io.h>
 
-#include <mach/fpga.h>
-#include <mach/omapfb.h>
+#include <plat/fpga.h>
+#include <plat/omapfb.h>
 
 static int palmte_panel_init(struct lcd_panel *panel,
                                struct omapfb_device *fbdev)
index 48ea1f9..557424f 100644 (file)
@@ -30,7 +30,7 @@ GPIO13 - screen blanking
 #include <linux/io.h>
 
 #include <mach/gpio.h>
-#include <mach/omapfb.h>
+#include <plat/omapfb.h>
 
 static int palmtt_panel_init(struct lcd_panel *panel,
        struct omapfb_device *fbdev)
index 0697d29..5f4b5b2 100644 (file)
@@ -24,7 +24,7 @@
 #include <linux/platform_device.h>
 #include <linux/io.h>
 
-#include <mach/omapfb.h>
+#include <plat/omapfb.h>
 
 static int palmz71_panel_init(struct lcd_panel *panel,
                              struct omapfb_device *fbdev)
index ab39492..5f32caf 100644 (file)
@@ -29,8 +29,8 @@
 #include <linux/vmalloc.h>
 #include <linux/clk.h>
 
-#include <mach/dma.h>
-#include <mach/omapfb.h>
+#include <plat/dma.h>
+#include <plat/omapfb.h>
 
 #include <asm/mach-types.h>
 
index 0d0c8c8..f900a43 100644 (file)
@@ -28,8 +28,8 @@
 #include <linux/mm.h>
 #include <linux/uaccess.h>
 
-#include <mach/dma.h>
-#include <mach/omapfb.h>
+#include <plat/dma.h>
+#include <plat/omapfb.h>
 
 #include "lcdc.h"
 #include "dispc.h"
index ee01e84..c90fa39 100644 (file)
@@ -27,7 +27,7 @@
 #include <linux/clk.h>
 #include <linux/io.h>
 
-#include <mach/omapfb.h>
+#include <plat/omapfb.h>
 
 #include "dispc.h"
 
index a769462..79dc84f 100644 (file)
@@ -24,8 +24,8 @@
 #include <linux/irq.h>
 #include <linux/io.h>
 
-#include <mach/dma.h>
-#include <mach/omapfb.h>
+#include <plat/dma.h>
+#include <plat/omapfb.h>
 
 #include "lcdc.h"
 
index 84d8327..75285d3 100644 (file)
@@ -687,6 +687,7 @@ static int __init pxa168fb_probe(struct platform_device *pdev)
        }
 
        info->fix.smem_start = (unsigned long)fbi->fb_start_dma;
+       set_graphics_start(info, 0, 0);
 
        /*
         * Set video mode according to platform data.
index 1820c4a..f58a3aa 100644 (file)
@@ -80,7 +80,8 @@
 static int pxafb_activate_var(struct fb_var_screeninfo *var,
                                struct pxafb_info *);
 static void set_ctrlr_state(struct pxafb_info *fbi, u_int state);
-static void setup_base_frame(struct pxafb_info *fbi, int branch);
+static void setup_base_frame(struct pxafb_info *fbi,
+                             struct fb_var_screeninfo *var, int branch);
 static int setup_frame_dma(struct pxafb_info *fbi, int dma, int pal,
                           unsigned long offset, size_t size);
 
@@ -397,6 +398,7 @@ static void pxafb_setmode(struct fb_var_screeninfo *var,
        var->lower_margin       = mode->lower_margin;
        var->sync               = mode->sync;
        var->grayscale          = mode->cmap_greyscale;
+       var->transp.length      = mode->transparency;
 
        /* set the initial RGBA bitfields */
        pxafb_set_pixfmt(var, mode->depth);
@@ -531,12 +533,22 @@ static int pxafb_pan_display(struct fb_var_screeninfo *var,
                             struct fb_info *info)
 {
        struct pxafb_info *fbi = (struct pxafb_info *)info;
+       struct fb_var_screeninfo newvar;
        int dma = DMA_MAX + DMA_BASE;
 
        if (fbi->state != C_ENABLE)
                return 0;
 
-       setup_base_frame(fbi, 1);
+       /* Only take .xoffset, .yoffset and .vmode & FB_VMODE_YWRAP from what
+        * was passed in and copy the rest from the old screeninfo.
+        */
+       memcpy(&newvar, &fbi->fb.var, sizeof(newvar));
+       newvar.xoffset = var->xoffset;
+       newvar.yoffset = var->yoffset;
+       newvar.vmode &= ~FB_VMODE_YWRAP;
+       newvar.vmode |= var->vmode & FB_VMODE_YWRAP;
+
+       setup_base_frame(fbi, &newvar, 1);
 
        if (fbi->lccr0 & LCCR0_SDS)
                lcd_writel(fbi, FBR1, fbi->fdadr[dma + 1] | 0x1);
@@ -1052,9 +1064,10 @@ static int setup_frame_dma(struct pxafb_info *fbi, int dma, int pal,
        return 0;
 }
 
-static void setup_base_frame(struct pxafb_info *fbi, int branch)
+static void setup_base_frame(struct pxafb_info *fbi,
+                             struct fb_var_screeninfo *var,
+                             int branch)
 {
-       struct fb_var_screeninfo *var = &fbi->fb.var;
        struct fb_fix_screeninfo *fix = &fbi->fb.fix;
        int nbytes, dma, pal, bpp = var->bits_per_pixel;
        unsigned long offset;
@@ -1332,7 +1345,7 @@ static int pxafb_activate_var(struct fb_var_screeninfo *var,
 #endif
                setup_parallel_timing(fbi, var);
 
-       setup_base_frame(fbi, 0);
+       setup_base_frame(fbi, var, 0);
 
        fbi->reg_lccr0 = fbi->lccr0 |
                (LCCR0_LDM | LCCR0_SFM | LCCR0_IUM | LCCR0_EFM |
index 3ed571a..429ea99 100644 (file)
@@ -43,7 +43,7 @@
 #include <linux/io.h>
 #include <linux/uaccess.h>
 #include <mach/hardware.h>
-#include <mach/prcm.h>
+#include <plat/prcm.h>
 
 #include "omap_wdt.h"
 
index d3c824d..c14ae86 100644 (file)
@@ -10,7 +10,6 @@
 #include <linux/errno.h>
 #include <linux/init.h>
 #include <linux/miscdevice.h>
-#include <linux/smp_lock.h>
 #include <linux/watchdog.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
@@ -75,7 +74,6 @@ static void riowd_writereg(struct riowd *p, u8 val, int index)
 
 static int riowd_open(struct inode *inode, struct file *filp)
 {
-       cycle_kernel_lock();
        nonseekable_open(inode, filp);
        return 0;
 }
@@ -194,6 +192,8 @@ static int __devinit riowd_probe(struct of_device *op,
                printk(KERN_ERR PFX "Cannot map registers.\n");
                goto out_free;
        }
+       /* Make miscdev useable right away */
+       riowd_device = p;
 
        err = misc_register(&riowd_miscdev);
        if (err) {
@@ -205,10 +205,10 @@ static int __devinit riowd_probe(struct of_device *op,
               "regs at %p\n", riowd_timeout, p->regs);
 
        dev_set_drvdata(&op->dev, p);
-       riowd_device = p;
        return 0;
 
 out_iounmap:
+       riowd_device = NULL;
        of_iounmap(&op->resource[0], p->regs, 2);
 
 out_free:
index e6c4390..53180a3 100644 (file)
@@ -156,5 +156,4 @@ postcore_initcall(zorro_driver_init);
 EXPORT_SYMBOL(zorro_match_device);
 EXPORT_SYMBOL(zorro_register_driver);
 EXPORT_SYMBOL(zorro_unregister_driver);
-EXPORT_SYMBOL(zorro_dev_driver);
 EXPORT_SYMBOL(zorro_bus_type);
index 02a2c93..c30dfc0 100644 (file)
--- a/fs/aio.c
+++ b/fs/aio.c
@@ -15,6 +15,7 @@
 #include <linux/aio_abi.h>
 #include <linux/module.h>
 #include <linux/syscalls.h>
+#include <linux/backing-dev.h>
 #include <linux/uio.h>
 
 #define DEBUG 0
@@ -32,6 +33,9 @@
 #include <linux/workqueue.h>
 #include <linux/security.h>
 #include <linux/eventfd.h>
+#include <linux/blkdev.h>
+#include <linux/mempool.h>
+#include <linux/hash.h>
 
 #include <asm/kmap_types.h>
 #include <asm/uaccess.h>
@@ -60,6 +64,14 @@ static DECLARE_WORK(fput_work, aio_fput_routine);
 static DEFINE_SPINLOCK(fput_lock);
 static LIST_HEAD(fput_head);
 
+#define AIO_BATCH_HASH_BITS    3 /* allocated on-stack, so don't go crazy */
+#define AIO_BATCH_HASH_SIZE    (1 << AIO_BATCH_HASH_BITS)
+struct aio_batch_entry {
+       struct hlist_node list;
+       struct address_space *mapping;
+};
+mempool_t *abe_pool;
+
 static void aio_kick_handler(struct work_struct *);
 static void aio_queue_work(struct kioctx *);
 
@@ -73,6 +85,8 @@ static int __init aio_setup(void)
        kioctx_cachep = KMEM_CACHE(kioctx,SLAB_HWCACHE_ALIGN|SLAB_PANIC);
 
        aio_wq = create_workqueue("aio");
+       abe_pool = mempool_create_kmalloc_pool(1, sizeof(struct aio_batch_entry));
+       BUG_ON(!abe_pool);
 
        pr_debug("aio_setup: sizeof(struct page) = %d\n", (int)sizeof(struct page));
 
@@ -1531,8 +1545,44 @@ static int aio_wake_function(wait_queue_t *wait, unsigned mode,
        return 1;
 }
 
+static void aio_batch_add(struct address_space *mapping,
+                         struct hlist_head *batch_hash)
+{
+       struct aio_batch_entry *abe;
+       struct hlist_node *pos;
+       unsigned bucket;
+
+       bucket = hash_ptr(mapping, AIO_BATCH_HASH_BITS);
+       hlist_for_each_entry(abe, pos, &batch_hash[bucket], list) {
+               if (abe->mapping == mapping)
+                       return;
+       }
+
+       abe = mempool_alloc(abe_pool, GFP_KERNEL);
+       BUG_ON(!igrab(mapping->host));
+       abe->mapping = mapping;
+       hlist_add_head(&abe->list, &batch_hash[bucket]);
+       return;
+}
+
+static void aio_batch_free(struct hlist_head *batch_hash)
+{
+       struct aio_batch_entry *abe;
+       struct hlist_node *pos, *n;
+       int i;
+
+       for (i = 0; i < AIO_BATCH_HASH_SIZE; i++) {
+               hlist_for_each_entry_safe(abe, pos, n, &batch_hash[i], list) {
+                       blk_run_address_space(abe->mapping);
+                       iput(abe->mapping->host);
+                       hlist_del(&abe->list);
+                       mempool_free(abe, abe_pool);
+               }
+       }
+}
+
 static int io_submit_one(struct kioctx *ctx, struct iocb __user *user_iocb,
-                        struct iocb *iocb)
+                        struct iocb *iocb, struct hlist_head *batch_hash)
 {
        struct kiocb *req;
        struct file *file;
@@ -1608,6 +1658,12 @@ static int io_submit_one(struct kioctx *ctx, struct iocb __user *user_iocb,
                        ;
        }
        spin_unlock_irq(&ctx->ctx_lock);
+       if (req->ki_opcode == IOCB_CMD_PREAD ||
+           req->ki_opcode == IOCB_CMD_PREADV ||
+           req->ki_opcode == IOCB_CMD_PWRITE ||
+           req->ki_opcode == IOCB_CMD_PWRITEV)
+               aio_batch_add(file->f_mapping, batch_hash);
+
        aio_put_req(req);       /* drop extra ref to req */
        return 0;
 
@@ -1635,6 +1691,7 @@ SYSCALL_DEFINE3(io_submit, aio_context_t, ctx_id, long, nr,
        struct kioctx *ctx;
        long ret = 0;
        int i;
+       struct hlist_head batch_hash[AIO_BATCH_HASH_SIZE] = { { 0, }, };
 
        if (unlikely(nr < 0))
                return -EINVAL;
@@ -1666,10 +1723,11 @@ SYSCALL_DEFINE3(io_submit, aio_context_t, ctx_id, long, nr,
                        break;
                }
 
-               ret = io_submit_one(ctx, user_iocb, &tmp);
+               ret = io_submit_one(ctx, user_iocb, &tmp, batch_hash);
                if (ret)
                        break;
        }
+       aio_batch_free(batch_hash);
 
        put_ioctx(ctx);
        return i ? i : ret;
index 12da5db..e23a63f 100644 (file)
--- a/fs/bio.c
+++ b/fs/bio.c
@@ -1393,6 +1393,18 @@ void bio_check_pages_dirty(struct bio *bio)
        }
 }
 
+#if ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE
+void bio_flush_dcache_pages(struct bio *bi)
+{
+       int i;
+       struct bio_vec *bvec;
+
+       bio_for_each_segment(bvec, bi, i)
+               flush_dcache_page(bvec->bv_page);
+}
+EXPORT_SYMBOL(bio_flush_dcache_pages);
+#endif
+
 /**
  * bio_endio - end I/O on a bio
  * @bio:       bio
index 8bed055..73d6a73 100644 (file)
@@ -405,7 +405,17 @@ static loff_t block_llseek(struct file *file, loff_t offset, int origin)
  
 static int block_fsync(struct file *filp, struct dentry *dentry, int datasync)
 {
-       return sync_blockdev(I_BDEV(filp->f_mapping->host));
+       struct block_device *bdev = I_BDEV(filp->f_mapping->host);
+       int error;
+
+       error = sync_blockdev(bdev);
+       if (error)
+               return error;
+       
+       error = blkdev_issue_flush(bdev, NULL);
+       if (error == -EOPNOTSUPP)
+               error = 0;
+       return error;
 }
 
 /*
index 43c96ce..c6405ce 100644 (file)
@@ -17,28 +17,25 @@ static struct ctl_table_header *fs_table_header;
 
 static ctl_table coda_table[] = {
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "timeout",
                .data           = &coda_timeout,
                .maxlen         = sizeof(int),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec
+               .proc_handler   = proc_dointvec
        },
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "hard",
                .data           = &coda_hard,
                .maxlen         = sizeof(int),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec
+               .proc_handler   = proc_dointvec
        },
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "fake_statfs",
                .data           = &coda_fake_statfs,
                .maxlen         = sizeof(int),
                .mode           = 0600,
-               .proc_handler   = &proc_dointvec
+               .proc_handler   = proc_dointvec
        },
        {}
 };
@@ -46,7 +43,6 @@ static ctl_table coda_table[] = {
 #ifdef CONFIG_SYSCTL
 static ctl_table fs_table[] = {
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "coda",
                .mode           = 0555,
                .child          = coda_table
index 8b10b87..b912270 100644 (file)
@@ -1028,9 +1028,6 @@ direct_io_worker(int rw, struct kiocb *iocb, struct inode *inode,
        if (dio->bio)
                dio_bio_submit(dio);
 
-       /* All IO is now issued, send it on its way */
-       blk_run_address_space(inode->i_mapping);
-
        /*
         * It is possible that, we return short IO due to end of file.
         * In that case, we need to release all the pages we got hold on.
@@ -1057,8 +1054,11 @@ direct_io_worker(int rw, struct kiocb *iocb, struct inode *inode,
            ((rw & READ) || (dio->result == dio->size)))
                ret = -EIOCBQUEUED;
 
-       if (ret != -EIOCBQUEUED)
+       if (ret != -EIOCBQUEUED) {
+               /* All IO is now issued, send it on its way */
+               blk_run_address_space(inode->i_mapping);
                dio_await_completion(dio);
+       }
 
        /*
         * Sync will always be dropping the final ref and completing the
@@ -1124,7 +1124,7 @@ __blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode,
        int acquire_i_mutex = 0;
 
        if (rw & WRITE)
-               rw = WRITE_ODIRECT;
+               rw = WRITE_ODIRECT_PLUG;
 
        if (bdev)
                bdev_blkbits = blksize_bits(bdev_logical_block_size(bdev));
index 085c5c0..366c503 100644 (file)
@@ -251,10 +251,10 @@ ctl_table epoll_table[] = {
                .data           = &max_user_watches,
                .maxlen         = sizeof(int),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec_minmax,
+               .proc_handler   = proc_dointvec_minmax,
                .extra1         = &zero,
        },
-       { .ctl_name = 0 }
+       { }
 };
 #endif /* CONFIG_SYSCTL */
 
index 9d5360c..49bc1b8 100644 (file)
@@ -614,7 +614,6 @@ static void writeback_inodes_wb(struct bdi_writeback *wb,
                                struct writeback_control *wbc)
 {
        struct super_block *sb = wbc->sb, *pin_sb = NULL;
-       const int is_blkdev_sb = sb_is_blkdev_sb(sb);
        const unsigned long start = jiffies;    /* livelock avoidance */
 
        spin_lock(&inode_lock);
@@ -635,36 +634,11 @@ static void writeback_inodes_wb(struct bdi_writeback *wb,
                        continue;
                }
 
-               if (!bdi_cap_writeback_dirty(wb->bdi)) {
-                       redirty_tail(inode);
-                       if (is_blkdev_sb) {
-                               /*
-                                * Dirty memory-backed blockdev: the ramdisk
-                                * driver does this.  Skip just this inode
-                                */
-                               continue;
-                       }
-                       /*
-                        * Dirty memory-backed inode against a filesystem other
-                        * than the kernel-internal bdev filesystem.  Skip the
-                        * entire superblock.
-                        */
-                       break;
-               }
-
                if (inode->i_state & (I_NEW | I_WILL_FREE)) {
                        requeue_io(inode);
                        continue;
                }
 
-               if (wbc->nonblocking && bdi_write_congested(wb->bdi)) {
-                       wbc->encountered_congestion = 1;
-                       if (!is_blkdev_sb)
-                               break;          /* Skip a congested fs */
-                       requeue_io(inode);
-                       continue;               /* Skip a congested blockdev */
-               }
-
                /*
                 * Was this inode dirtied after sync_sb_inodes was called?
                 * This keeps sync from extra jobs and livelock.
@@ -756,6 +730,7 @@ static long wb_writeback(struct bdi_writeback *wb,
                .sync_mode              = args->sync_mode,
                .older_than_this        = NULL,
                .for_kupdate            = args->for_kupdate,
+               .for_background         = args->for_background,
                .range_cyclic           = args->range_cyclic,
        };
        unsigned long oldest_jif;
@@ -787,7 +762,6 @@ static long wb_writeback(struct bdi_writeback *wb,
                        break;
 
                wbc.more_io = 0;
-               wbc.encountered_congestion = 0;
                wbc.nr_to_write = MAX_WRITEBACK_PAGES;
                wbc.pages_skipped = 0;
                writeback_inodes_wb(wb, &wbc);
index 1a54ae1..e50cfa3 100644 (file)
@@ -371,82 +371,74 @@ EXPORT_SYMBOL_GPL(lockd_down);
 
 static ctl_table nlm_sysctls[] = {
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "nlm_grace_period",
                .data           = &nlm_grace_period,
                .maxlen         = sizeof(unsigned long),
                .mode           = 0644,
-               .proc_handler   = &proc_doulongvec_minmax,
+               .proc_handler   = proc_doulongvec_minmax,
                .extra1         = (unsigned long *) &nlm_grace_period_min,
                .extra2         = (unsigned long *) &nlm_grace_period_max,
        },
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "nlm_timeout",
                .data           = &nlm_timeout,
                .maxlen         = sizeof(unsigned long),
                .mode           = 0644,
-               .proc_handler   = &proc_doulongvec_minmax,
+               .proc_handler   = proc_doulongvec_minmax,
                .extra1         = (unsigned long *) &nlm_timeout_min,
                .extra2         = (unsigned long *) &nlm_timeout_max,
        },
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "nlm_udpport",
                .data           = &nlm_udpport,
                .maxlen         = sizeof(int),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec_minmax,
+               .proc_handler   = proc_dointvec_minmax,
                .extra1         = (int *) &nlm_port_min,
                .extra2         = (int *) &nlm_port_max,
        },
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "nlm_tcpport",
                .data           = &nlm_tcpport,
                .maxlen         = sizeof(int),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec_minmax,
+               .proc_handler   = proc_dointvec_minmax,
                .extra1         = (int *) &nlm_port_min,
                .extra2         = (int *) &nlm_port_max,
        },
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "nsm_use_hostnames",
                .data           = &nsm_use_hostnames,
                .maxlen         = sizeof(int),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec,
+               .proc_handler   = proc_dointvec,
        },
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "nsm_local_state",
                .data           = &nsm_local_state,
                .maxlen         = sizeof(int),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec,
+               .proc_handler   = proc_dointvec,
        },
-       { .ctl_name = 0 }
+       { }
 };
 
 static ctl_table nlm_sysctl_dir[] = {
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "nfs",
                .mode           = 0555,
                .child          = nlm_sysctls,
        },
-       { .ctl_name = 0 }
+       { }
 };
 
 static ctl_table nlm_sysctl_root[] = {
        {
-               .ctl_name       = CTL_FS,
                .procname       = "fs",
                .mode           = 0555,
                .child          = nlm_sysctl_dir,
        },
-       { .ctl_name = 0 }
+       { }
 };
 
 #endif /* CONFIG_SYSCTL */
index b62481d..70e1fbb 100644 (file)
@@ -22,63 +22,55 @@ static struct ctl_table_header *nfs_callback_sysctl_table;
 static ctl_table nfs_cb_sysctls[] = {
 #ifdef CONFIG_NFS_V4
        {
-               .ctl_name = CTL_UNNUMBERED,
                .procname = "nfs_callback_tcpport",
                .data = &nfs_callback_set_tcpport,
                .maxlen = sizeof(int),
                .mode = 0644,
-               .proc_handler = &proc_dointvec_minmax,
+               .proc_handler = proc_dointvec_minmax,
                .extra1 = (int *)&nfs_set_port_min,
                .extra2 = (int *)&nfs_set_port_max,
        },
        {
-               .ctl_name = CTL_UNNUMBERED,
                .procname = "idmap_cache_timeout",
                .data = &nfs_idmap_cache_timeout,
                .maxlen = sizeof(int),
                .mode = 0644,
-               .proc_handler = &proc_dointvec_jiffies,
-               .strategy = &sysctl_jiffies,
+               .proc_handler = proc_dointvec_jiffies,
        },
 #endif
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "nfs_mountpoint_timeout",
                .data           = &nfs_mountpoint_expiry_timeout,
                .maxlen         = sizeof(nfs_mountpoint_expiry_timeout),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec_jiffies,
-               .strategy       = &sysctl_jiffies,
+               .proc_handler   = proc_dointvec_jiffies,
        },
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "nfs_congestion_kb",
                .data           = &nfs_congestion_kb,
                .maxlen         = sizeof(nfs_congestion_kb),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec,
+               .proc_handler   = proc_dointvec,
        },
-       { .ctl_name = 0 }
+       { }
 };
 
 static ctl_table nfs_cb_sysctl_dir[] = {
        {
-               .ctl_name = CTL_UNNUMBERED,
                .procname = "nfs",
                .mode = 0555,
                .child = nfs_cb_sysctls,
        },
-       { .ctl_name = 0 }
+       { }
 };
 
 static ctl_table nfs_cb_sysctl_root[] = {
        {
-               .ctl_name = CTL_FS,
                .procname = "fs",
                .mode = 0555,
                .child = nfs_cb_sysctl_dir,
        },
-       { .ctl_name = 0 }
+       { }
 };
 
 int nfs_register_sysctl(void)
index 53eb26c..c84b5cc 100644 (file)
@@ -178,7 +178,7 @@ static int wb_priority(struct writeback_control *wbc)
 {
        if (wbc->for_reclaim)
                return FLUSH_HIGHPRI | FLUSH_STABLE;
-       if (wbc->for_kupdate)
+       if (wbc->for_kupdate || wbc->for_background)
                return FLUSH_LOWPRI;
        return 0;
 }
index dcd2040..1d1d1a2 100644 (file)
@@ -69,36 +69,30 @@ static int zero;
 
 ctl_table inotify_table[] = {
        {
-               .ctl_name       = INOTIFY_MAX_USER_INSTANCES,
                .procname       = "max_user_instances",
                .data           = &inotify_max_user_instances,
                .maxlen         = sizeof(int),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec_minmax,
-               .strategy       = &sysctl_intvec,
+               .proc_handler   = proc_dointvec_minmax,
                .extra1         = &zero,
        },
        {
-               .ctl_name       = INOTIFY_MAX_USER_WATCHES,
                .procname       = "max_user_watches",
                .data           = &inotify_max_user_watches,
                .maxlen         = sizeof(int),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec_minmax,
-               .strategy       = &sysctl_intvec,
+               .proc_handler   = proc_dointvec_minmax,
                .extra1         = &zero,
        },
        {
-               .ctl_name       = INOTIFY_MAX_QUEUED_EVENTS,
                .procname       = "max_queued_events",
                .data           = &inotify_max_queued_events,
                .maxlen         = sizeof(int),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec_minmax,
-               .strategy       = &sysctl_intvec,
+               .proc_handler   = proc_dointvec_minmax,
                .extra1         = &zero
        },
-       { .ctl_name = 0 }
+       { }
 };
 #endif /* CONFIG_SYSCTL */
 
index 9ef85e6..79a8918 100644 (file)
 /* Definition of the ntfs sysctl. */
 static ctl_table ntfs_sysctls[] = {
        {
-               .ctl_name       = CTL_UNNUMBERED,       /* Binary and text IDs. */
                .procname       = "ntfs-debug",
                .data           = &debug_msgs,          /* Data pointer and size. */
                .maxlen         = sizeof(debug_msgs),
                .mode           = 0644,                 /* Mode, proc handler. */
-               .proc_handler   = &proc_dointvec
+               .proc_handler   = proc_dointvec
        },
        {}
 };
@@ -49,7 +48,6 @@ static ctl_table ntfs_sysctls[] = {
 /* Define the parent directory /proc/sys/fs. */
 static ctl_table sysctls_root[] = {
        {
-               .ctl_name       = CTL_FS,
                .procname       = "fs",
                .mode           = 0555,
                .child          = ntfs_sysctls
index 3f2f1c4..f3df0ba 100644 (file)
@@ -620,51 +620,46 @@ error:
 
 static ctl_table ocfs2_nm_table[] = {
        {
-               .ctl_name       = 1,
                .procname       = "hb_ctl_path",
                .data           = ocfs2_hb_ctl_path,
                .maxlen         = OCFS2_MAX_HB_CTL_PATH,
                .mode           = 0644,
-               .proc_handler   = &proc_dostring,
-               .strategy       = &sysctl_string,
+               .proc_handler   = proc_dostring,
        },
-       { .ctl_name = 0 }
+       { }
 };
 
 static ctl_table ocfs2_mod_table[] = {
        {
-               .ctl_name       = FS_OCFS2_NM,
                .procname       = "nm",
                .data           = NULL,
                .maxlen         = 0,
                .mode           = 0555,
                .child          = ocfs2_nm_table
        },
-       { .ctl_name = 0}
+       { }
 };
 
 static ctl_table ocfs2_kern_table[] = {
        {
-               .ctl_name       = FS_OCFS2,
                .procname       = "ocfs2",
                .data           = NULL,
                .maxlen         = 0,
                .mode           = 0555,
                .child          = ocfs2_mod_table
        },
-       { .ctl_name = 0}
+       { }
 };
 
 static ctl_table ocfs2_root_table[] = {
        {
-               .ctl_name       = CTL_FS,
                .procname       = "fs",
                .data           = NULL,
                .maxlen         = 0,
                .mode           = 0555,
                .child          = ocfs2_kern_table
        },
-       { .ctl_name = 0 }
+       { }
 };
 
 static struct ctl_table_header *ocfs2_table_header = NULL;
index 7b685e1..64bc899 100644 (file)
@@ -226,6 +226,13 @@ ssize_t part_alignment_offset_show(struct device *dev,
        return sprintf(buf, "%llu\n", (unsigned long long)p->alignment_offset);
 }
 
+ssize_t part_discard_alignment_show(struct device *dev,
+                                  struct device_attribute *attr, char *buf)
+{
+       struct hd_struct *p = dev_to_part(dev);
+       return sprintf(buf, "%u\n", p->discard_alignment);
+}
+
 ssize_t part_stat_show(struct device *dev,
                       struct device_attribute *attr, char *buf)
 {
@@ -288,6 +295,8 @@ static DEVICE_ATTR(partition, S_IRUGO, part_partition_show, NULL);
 static DEVICE_ATTR(start, S_IRUGO, part_start_show, NULL);
 static DEVICE_ATTR(size, S_IRUGO, part_size_show, NULL);
 static DEVICE_ATTR(alignment_offset, S_IRUGO, part_alignment_offset_show, NULL);
+static DEVICE_ATTR(discard_alignment, S_IRUGO, part_discard_alignment_show,
+                  NULL);
 static DEVICE_ATTR(stat, S_IRUGO, part_stat_show, NULL);
 static DEVICE_ATTR(inflight, S_IRUGO, part_inflight_show, NULL);
 #ifdef CONFIG_FAIL_MAKE_REQUEST
@@ -300,6 +309,7 @@ static struct attribute *part_attrs[] = {
        &dev_attr_start.attr,
        &dev_attr_size.attr,
        &dev_attr_alignment_offset.attr,
+       &dev_attr_discard_alignment.attr,
        &dev_attr_stat.attr,
        &dev_attr_inflight.attr,
 #ifdef CONFIG_FAIL_MAKE_REQUEST
@@ -403,6 +413,8 @@ struct hd_struct *add_partition(struct gendisk *disk, int partno,
 
        p->start_sect = start;
        p->alignment_offset = queue_sector_alignment_offset(disk->queue, start);
+       p->discard_alignment = queue_sector_discard_alignment(disk->queue,
+                                                             start);
        p->nr_sects = len;
        p->partno = partno;
        p->policy = get_disk_ro(disk);
index 038a602..49cfd5f 100644 (file)
@@ -1,7 +1,9 @@
 /************************************************************
  * EFI GUID Partition Table handling
- * Per Intel EFI Specification v1.02
- * http://developer.intel.com/technology/efi/efi.htm
+ *
+ * http://www.uefi.org/specs/
+ * http://www.intel.com/technology/efi/
+ *
  * efi.[ch] by Matt Domsch <Matt_Domsch@dell.com>
  *   Copyright 2000,2001,2002,2004 Dell Inc.
  *
@@ -92,6 +94,7 @@
  *
  ************************************************************/
 #include <linux/crc32.h>
+#include <linux/math64.h>
 #include "check.h"
 #include "efi.h"
 
@@ -141,7 +144,8 @@ last_lba(struct block_device *bdev)
 {
        if (!bdev || !bdev->bd_inode)
                return 0;
-       return (bdev->bd_inode->i_size >> 9) - 1ULL;
+       return div_u64(bdev->bd_inode->i_size,
+                      bdev_logical_block_size(bdev)) - 1ULL;
 }
 
 static inline int
@@ -188,6 +192,7 @@ static size_t
 read_lba(struct block_device *bdev, u64 lba, u8 * buffer, size_t count)
 {
        size_t totalreadcount = 0;
+       sector_t n = lba * (bdev_logical_block_size(bdev) / 512);
 
        if (!bdev || !buffer || lba > last_lba(bdev))
                 return 0;
@@ -195,7 +200,7 @@ read_lba(struct block_device *bdev, u64 lba, u8 * buffer, size_t count)
        while (count) {
                int copied = 512;
                Sector sect;
-               unsigned char *data = read_dev_sector(bdev, lba++, &sect);
+               unsigned char *data = read_dev_sector(bdev, n++, &sect);
                if (!data)
                        break;
                if (copied > count)
@@ -257,15 +262,16 @@ static gpt_header *
 alloc_read_gpt_header(struct block_device *bdev, u64 lba)
 {
        gpt_header *gpt;
+       unsigned ssz = bdev_logical_block_size(bdev);
+
        if (!bdev)
                return NULL;
 
-       gpt = kzalloc(sizeof (gpt_header), GFP_KERNEL);
+       gpt = kzalloc(ssz, GFP_KERNEL);
        if (!gpt)
                return NULL;
 
-       if (read_lba(bdev, lba, (u8 *) gpt,
-                    sizeof (gpt_header)) < sizeof (gpt_header)) {
+       if (read_lba(bdev, lba, (u8 *) gpt, ssz) < ssz) {
                kfree(gpt);
                 gpt=NULL;
                return NULL;
@@ -601,6 +607,7 @@ efi_partition(struct parsed_partitions *state, struct block_device *bdev)
        gpt_header *gpt = NULL;
        gpt_entry *ptes = NULL;
        u32 i;
+       unsigned ssz = bdev_logical_block_size(bdev) / 512;
 
        if (!find_valid_gpt(bdev, &gpt, &ptes) || !gpt || !ptes) {
                kfree(gpt);
@@ -611,13 +618,14 @@ efi_partition(struct parsed_partitions *state, struct block_device *bdev)
        pr_debug("GUID Partition Table is valid!  Yea!\n");
 
        for (i = 0; i < le32_to_cpu(gpt->num_partition_entries) && i < state->limit-1; i++) {
+               u64 start = le64_to_cpu(ptes[i].starting_lba);
+               u64 size = le64_to_cpu(ptes[i].ending_lba) -
+                          le64_to_cpu(ptes[i].starting_lba) + 1ULL;
+
                if (!is_pte_valid(&ptes[i], last_lba(bdev)))
                        continue;
 
-               put_partition(state, i+1, le64_to_cpu(ptes[i].starting_lba),
-                                (le64_to_cpu(ptes[i].ending_lba) -
-                                  le64_to_cpu(ptes[i].starting_lba) +
-                                 1ULL));
+               put_partition(state, i+1, start * ssz, size * ssz);
 
                /* If this is a RAID volume, tell md */
                if (!efi_guidcmp(ptes[i].partition_type_guid,
index 2cc89d0..6998b58 100644 (file)
@@ -37,7 +37,6 @@
 #define EFI_PMBR_OSTYPE_EFI 0xEF
 #define EFI_PMBR_OSTYPE_EFI_GPT 0xEE
 
-#define GPT_BLOCK_SIZE 512
 #define GPT_HEADER_SIGNATURE 0x5452415020494645ULL
 #define GPT_HEADER_REVISION_V1 0x00010000
 #define GPT_PRIMARY_PARTITION_TABLE_LBA 1
@@ -79,7 +78,12 @@ typedef struct _gpt_header {
        __le32 num_partition_entries;
        __le32 sizeof_partition_entry;
        __le32 partition_entry_array_crc32;
-       u8 reserved2[GPT_BLOCK_SIZE - 92];
+
+       /* The rest of the logical block is reserved by UEFI and must be zero.
+        * EFI standard handles this by:
+        *
+        * uint8_t              reserved2[ BlockSize - 92 ];
+        */
 } __attribute__ ((packed)) gpt_header;
 
 typedef struct _gpt_entry_attributes {
index 822c2d5..4badde1 100644 (file)
@@ -410,6 +410,16 @@ static void task_show_stack_usage(struct seq_file *m, struct task_struct *task)
 }
 #endif         /* CONFIG_MMU */
 
+static void task_cpus_allowed(struct seq_file *m, struct task_struct *task)
+{
+       seq_printf(m, "Cpus_allowed:\t");
+       seq_cpumask(m, &task->cpus_allowed);
+       seq_printf(m, "\n");
+       seq_printf(m, "Cpus_allowed_list:\t");
+       seq_cpumask_list(m, &task->cpus_allowed);
+       seq_printf(m, "\n");
+}
+
 int proc_pid_status(struct seq_file *m, struct pid_namespace *ns,
                        struct pid *pid, struct task_struct *task)
 {
@@ -424,6 +434,7 @@ int proc_pid_status(struct seq_file *m, struct pid_namespace *ns,
        }
        task_sig(m, task);
        task_cap(m, task);
+       task_cpus_allowed(m, task);
        cpuset_task_status_allowed(m, task);
 #if defined(CONFIG_S390)
        task_show_regs(m, task);
@@ -495,20 +506,17 @@ static int do_task_stat(struct seq_file *m, struct pid_namespace *ns,
 
                /* add up live thread stats at the group level */
                if (whole) {
-                       struct task_cputime cputime;
                        struct task_struct *t = task;
                        do {
                                min_flt += t->min_flt;
                                maj_flt += t->maj_flt;
-                               gtime = cputime_add(gtime, task_gtime(t));
+                               gtime = cputime_add(gtime, t->gtime);
                                t = next_thread(t);
                        } while (t != task);
 
                        min_flt += sig->min_flt;
                        maj_flt += sig->maj_flt;
-                       thread_group_cputime(task, &cputime);
-                       utime = cputime.utime;
-                       stime = cputime.stime;
+                       thread_group_times(task, &utime, &stime);
                        gtime = cputime_add(gtime, sig->gtime);
                }
 
@@ -524,9 +532,8 @@ static int do_task_stat(struct seq_file *m, struct pid_namespace *ns,
        if (!whole) {
                min_flt = task->min_flt;
                maj_flt = task->maj_flt;
-               utime = task_utime(task);
-               stime = task_stime(task);
-               gtime = task_gtime(task);
+               task_times(task, &utime, &stime);
+               gtime = task->gtime;
        }
 
        /* scale priority and nice values from timeslices to -20..20 */
index f667e8a..6ff9981 100644 (file)
@@ -48,7 +48,7 @@ out:
 static struct ctl_table *find_in_table(struct ctl_table *p, struct qstr *name)
 {
        int len;
-       for ( ; p->ctl_name || p->procname; p++) {
+       for ( ; p->procname; p++) {
 
                if (!p->procname)
                        continue;
@@ -218,7 +218,7 @@ static int scan(struct ctl_table_header *head, ctl_table *table,
                void *dirent, filldir_t filldir)
 {
 
-       for (; table->ctl_name || table->procname; table++, (*pos)++) {
+       for (; table->procname; table++, (*pos)++) {
                int res;
 
                /* Can't do anything without a proc name */
index 7cc726c..b9b7aad 100644 (file)
@@ -27,7 +27,7 @@ static int show_stat(struct seq_file *p, void *v)
        int i, j;
        unsigned long jif;
        cputime64_t user, nice, system, idle, iowait, irq, softirq, steal;
-       cputime64_t guest;
+       cputime64_t guest, guest_nice;
        u64 sum = 0;
        u64 sum_softirq = 0;
        unsigned int per_softirq_sums[NR_SOFTIRQS] = {0};
@@ -36,7 +36,7 @@ static int show_stat(struct seq_file *p, void *v)
 
        user = nice = system = idle = iowait =
                irq = softirq = steal = cputime64_zero;
-       guest = cputime64_zero;
+       guest = guest_nice = cputime64_zero;
        getboottime(&boottime);
        jif = boottime.tv_sec;
 
@@ -51,6 +51,8 @@ static int show_stat(struct seq_file *p, void *v)
                softirq = cputime64_add(softirq, kstat_cpu(i).cpustat.softirq);
                steal = cputime64_add(steal, kstat_cpu(i).cpustat.steal);
                guest = cputime64_add(guest, kstat_cpu(i).cpustat.guest);
+               guest_nice = cputime64_add(guest_nice,
+                       kstat_cpu(i).cpustat.guest_nice);
                for_each_irq_nr(j) {
                        sum += kstat_irqs_cpu(j, i);
                }
@@ -65,7 +67,8 @@ static int show_stat(struct seq_file *p, void *v)
        }
        sum += arch_irq_stat();
 
-       seq_printf(p, "cpu  %llu %llu %llu %llu %llu %llu %llu %llu %llu\n",
+       seq_printf(p, "cpu  %llu %llu %llu %llu %llu %llu %llu %llu %llu "
+               "%llu\n",
                (unsigned long long)cputime64_to_clock_t(user),
                (unsigned long long)cputime64_to_clock_t(nice),
                (unsigned long long)cputime64_to_clock_t(system),
@@ -74,7 +77,8 @@ static int show_stat(struct seq_file *p, void *v)
                (unsigned long long)cputime64_to_clock_t(irq),
                (unsigned long long)cputime64_to_clock_t(softirq),
                (unsigned long long)cputime64_to_clock_t(steal),
-               (unsigned long long)cputime64_to_clock_t(guest));
+               (unsigned long long)cputime64_to_clock_t(guest),
+               (unsigned long long)cputime64_to_clock_t(guest_nice));
        for_each_online_cpu(i) {
 
                /* Copy values here to work around gcc-2.95.3, gcc-2.96 */
@@ -88,8 +92,10 @@ static int show_stat(struct seq_file *p, void *v)
                softirq = kstat_cpu(i).cpustat.softirq;
                steal = kstat_cpu(i).cpustat.steal;
                guest = kstat_cpu(i).cpustat.guest;
+               guest_nice = kstat_cpu(i).cpustat.guest_nice;
                seq_printf(p,
-                       "cpu%d %llu %llu %llu %llu %llu %llu %llu %llu %llu\n",
+                       "cpu%d %llu %llu %llu %llu %llu %llu %llu %llu %llu "
+                       "%llu\n",
                        i,
                        (unsigned long long)cputime64_to_clock_t(user),
                        (unsigned long long)cputime64_to_clock_t(nice),
@@ -99,7 +105,8 @@ static int show_stat(struct seq_file *p, void *v)
                        (unsigned long long)cputime64_to_clock_t(irq),
                        (unsigned long long)cputime64_to_clock_t(softirq),
                        (unsigned long long)cputime64_to_clock_t(steal),
-                       (unsigned long long)cputime64_to_clock_t(guest));
+                       (unsigned long long)cputime64_to_clock_t(guest),
+                       (unsigned long long)cputime64_to_clock_t(guest_nice));
        }
        seq_printf(p, "intr %llu", (unsigned long long)sum);
 
index 9b6ad90..eb5a755 100644 (file)
@@ -2404,100 +2404,89 @@ const struct quotactl_ops vfs_quotactl_ops = {
 
 static ctl_table fs_dqstats_table[] = {
        {
-               .ctl_name       = FS_DQ_LOOKUPS,
                .procname       = "lookups",
                .data           = &dqstats.lookups,
                .maxlen         = sizeof(int),
                .mode           = 0444,
-               .proc_handler   = &proc_dointvec,
+               .proc_handler   = proc_dointvec,
        },
        {
-               .ctl_name       = FS_DQ_DROPS,
                .procname       = "drops",
                .data           = &dqstats.drops,
                .maxlen         = sizeof(int),
                .mode           = 0444,
-               .proc_handler   = &proc_dointvec,
+               .proc_handler   = proc_dointvec,
        },
        {
-               .ctl_name       = FS_DQ_READS,
                .procname       = "reads",
                .data           = &dqstats.reads,
                .maxlen         = sizeof(int),
                .mode           = 0444,
-               .proc_handler   = &proc_dointvec,
+               .proc_handler   = proc_dointvec,
        },
        {
-               .ctl_name       = FS_DQ_WRITES,
                .procname       = "writes",
                .data           = &dqstats.writes,
                .maxlen         = sizeof(int),
                .mode           = 0444,
-               .proc_handler   = &proc_dointvec,
+               .proc_handler   = proc_dointvec,
        },
        {
-               .ctl_name       = FS_DQ_CACHE_HITS,
                .procname       = "cache_hits",
                .data           = &dqstats.cache_hits,
                .maxlen         = sizeof(int),
                .mode           = 0444,
-               .proc_handler   = &proc_dointvec,
+               .proc_handler   = proc_dointvec,
        },
        {
-               .ctl_name       = FS_DQ_ALLOCATED,
                .procname       = "allocated_dquots",
                .data           = &dqstats.allocated_dquots,
                .maxlen         = sizeof(int),
                .mode           = 0444,
-               .proc_handler   = &proc_dointvec,
+               .proc_handler   = proc_dointvec,
        },
        {
-               .ctl_name       = FS_DQ_FREE,
                .procname       = "free_dquots",
                .data           = &dqstats.free_dquots,
                .maxlen         = sizeof(int),
                .mode           = 0444,
-               .proc_handler   = &proc_dointvec,
+               .proc_handler   = proc_dointvec,
        },
        {
-               .ctl_name       = FS_DQ_SYNCS,
                .procname       = "syncs",
                .data           = &dqstats.syncs,
                .maxlen         = sizeof(int),
                .mode           = 0444,
-               .proc_handler   = &proc_dointvec,
+               .proc_handler   = proc_dointvec,
        },
 #ifdef CONFIG_PRINT_QUOTA_WARNING
        {
-               .ctl_name       = FS_DQ_WARNINGS,
                .procname       = "warnings",
                .data           = &flag_print_warnings,
                .maxlen         = sizeof(int),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec,
+               .proc_handler   = proc_dointvec,
        },
 #endif
-       { .ctl_name = 0 },
+       { },
 };
 
 static ctl_table fs_table[] = {
        {
-               .ctl_name       = FS_DQSTATS,
                .procname       = "quota",
                .mode           = 0555,
                .child          = fs_dqstats_table,
        },
-       { .ctl_name = 0 },
+       { },
 };
 
 static ctl_table sys_table[] = {
        {
-               .ctl_name       = CTL_FS,
                .procname       = "fs",
                .mode           = 0555,
                .child          = fs_table,
        },
-       { .ctl_name = 0 },
+       { },
 };
 
 static int __init dquot_init(void)
index 3ac2898..b7f4a1f 100644 (file)
@@ -826,8 +826,6 @@ static ssize_t do_sendfile(int out_fd, int in_fd, loff_t *ppos,
        if (!(out_file->f_mode & FMODE_WRITE))
                goto fput_out;
        retval = -EINVAL;
-       if (!out_file->f_op || !out_file->f_op->sendpage)
-               goto fput_out;
        in_inode = in_file->f_path.dentry->d_inode;
        out_inode = out_file->f_path.dentry->d_inode;
        retval = rw_verify_area(WRITE, out_file, &out_file->f_pos, count);
index 7394e9e..3920866 100644 (file)
@@ -648,9 +648,11 @@ static int pipe_to_sendpage(struct pipe_inode_info *pipe,
        ret = buf->ops->confirm(pipe, buf);
        if (!ret) {
                more = (sd->flags & SPLICE_F_MORE) || sd->len < sd->total_len;
-
-               ret = file->f_op->sendpage(file, buf->page, buf->offset,
-                                          sd->len, &pos, more);
+               if (file->f_op && file->f_op->sendpage)
+                       ret = file->f_op->sendpage(file, buf->page, buf->offset,
+                                                  sd->len, &pos, more);
+               else
+                       ret = -EINVAL;
        }
 
        return ret;
@@ -1068,8 +1070,9 @@ static long do_splice_from(struct pipe_inode_info *pipe, struct file *out,
        if (unlikely(ret < 0))
                return ret;
 
-       splice_write = out->f_op->splice_write;
-       if (!splice_write)
+       if (out->f_op && out->f_op->splice_write)
+               splice_write = out->f_op->splice_write;
+       else
                splice_write = default_file_splice_write;
 
        return splice_write(pipe, out, ppos, len, flags);
@@ -1093,8 +1096,9 @@ static long do_splice_to(struct file *in, loff_t *ppos,
        if (unlikely(ret < 0))
                return ret;
 
-       splice_read = in->f_op->splice_read;
-       if (!splice_read)
+       if (in->f_op && in->f_op->splice_read)
+               splice_read = in->f_op->splice_read;
+       else
                splice_read = default_file_splice_read;
 
        return splice_read(in, ppos, pipe, len, flags);
@@ -1316,7 +1320,8 @@ static long do_splice(struct file *in, loff_t __user *off_in,
                if (off_in)
                        return -ESPIPE;
                if (off_out) {
-                       if (out->f_op->llseek == no_llseek)
+                       if (!out->f_op || !out->f_op->llseek ||
+                           out->f_op->llseek == no_llseek)
                                return -EINVAL;
                        if (copy_from_user(&offset, off_out, sizeof(loff_t)))
                                return -EFAULT;
@@ -1336,7 +1341,8 @@ static long do_splice(struct file *in, loff_t __user *off_in,
                if (off_out)
                        return -ESPIPE;
                if (off_in) {
-                       if (in->f_op->llseek == no_llseek)
+                       if (!in->f_op || !in->f_op->llseek ||
+                           in->f_op->llseek == no_llseek)
                                return -EINVAL;
                        if (copy_from_user(&offset, off_in, sizeof(loff_t)))
                                return -EFAULT;
index c2e30ee..70f9898 100644 (file)
@@ -904,16 +904,9 @@ xfs_convert_page(
 
        if (startio) {
                if (count) {
-                       struct backing_dev_info *bdi;
-
-                       bdi = inode->i_mapping->backing_dev_info;
                        wbc->nr_to_write--;
-                       if (bdi_write_congested(bdi)) {
-                               wbc->encountered_congestion = 1;
-                               done = 1;
-                       } else if (wbc->nr_to_write <= 0) {
+                       if (wbc->nr_to_write <= 0)
                                done = 1;
-                       }
                }
                xfs_start_page_writeback(page, !page_dirty, count);
        }
index c5bc67c..7bb5092 100644 (file)
@@ -55,170 +55,140 @@ xfs_stats_clear_proc_handler(
 
 static ctl_table xfs_table[] = {
        {
-               .ctl_name       = XFS_SGID_INHERIT,
                .procname       = "irix_sgid_inherit",
                .data           = &xfs_params.sgid_inherit.val,
                .maxlen         = sizeof(int),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec_minmax,
-               .strategy       = &sysctl_intvec,
+               .proc_handler   = proc_dointvec_minmax,
                .extra1         = &xfs_params.sgid_inherit.min,
                .extra2         = &xfs_params.sgid_inherit.max
        },
        {
-               .ctl_name       = XFS_SYMLINK_MODE,
                .procname       = "irix_symlink_mode",
                .data           = &xfs_params.symlink_mode.val,
                .maxlen         = sizeof(int),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec_minmax,
-               .strategy       = &sysctl_intvec,
+               .proc_handler   = proc_dointvec_minmax,
                .extra1         = &xfs_params.symlink_mode.min,
                .extra2         = &xfs_params.symlink_mode.max
        },
        {
-               .ctl_name       = XFS_PANIC_MASK,
                .procname       = "panic_mask",
                .data           = &xfs_params.panic_mask.val,
                .maxlen         = sizeof(int),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec_minmax,
-               .strategy       = &sysctl_intvec,
+               .proc_handler   = proc_dointvec_minmax,
                .extra1         = &xfs_params.panic_mask.min,
                .extra2         = &xfs_params.panic_mask.max
        },
 
        {
-               .ctl_name       = XFS_ERRLEVEL,
                .procname       = "error_level",
                .data           = &xfs_params.error_level.val,
                .maxlen         = sizeof(int),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec_minmax,
-               .strategy       = &sysctl_intvec,
+               .proc_handler   = proc_dointvec_minmax,
                .extra1         = &xfs_params.error_level.min,
                .extra2         = &xfs_params.error_level.max
        },
        {
-               .ctl_name       = XFS_SYNCD_TIMER,
                .procname       = "xfssyncd_centisecs",
                .data           = &xfs_params.syncd_timer.val,
                .maxlen         = sizeof(int),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec_minmax,
-               .strategy       = &sysctl_intvec,
+               .proc_handler   = proc_dointvec_minmax,
                .extra1         = &xfs_params.syncd_timer.min,
                .extra2         = &xfs_params.syncd_timer.max
        },
        {
-               .ctl_name       = XFS_INHERIT_SYNC,
                .procname       = "inherit_sync",
                .data           = &xfs_params.inherit_sync.val,
                .maxlen         = sizeof(int),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec_minmax,
-               .strategy       = &sysctl_intvec,
+               .proc_handler   = proc_dointvec_minmax,
                .extra1         = &xfs_params.inherit_sync.min,
                .extra2         = &xfs_params.inherit_sync.max
        },
        {
-               .ctl_name       = XFS_INHERIT_NODUMP,
                .procname       = "inherit_nodump",
                .data           = &xfs_params.inherit_nodump.val,
                .maxlen         = sizeof(int),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec_minmax,
-               .strategy       = &sysctl_intvec,
+               .proc_handler   = proc_dointvec_minmax,
                .extra1         = &xfs_params.inherit_nodump.min,
                .extra2         = &xfs_params.inherit_nodump.max
        },
        {
-               .ctl_name       = XFS_INHERIT_NOATIME,
                .procname       = "inherit_noatime",
                .data           = &xfs_params.inherit_noatim.val,
                .maxlen         = sizeof(int),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec_minmax,
-               .strategy       = &sysctl_intvec,
+               .proc_handler   = proc_dointvec_minmax,
                .extra1         = &xfs_params.inherit_noatim.min,
                .extra2         = &xfs_params.inherit_noatim.max
        },
        {
-               .ctl_name       = XFS_BUF_TIMER,
                .procname       = "xfsbufd_centisecs",
                .data           = &xfs_params.xfs_buf_timer.val,
                .maxlen         = sizeof(int),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec_minmax,
-               .strategy       = &sysctl_intvec,
+               .proc_handler   = proc_dointvec_minmax,
                .extra1         = &xfs_params.xfs_buf_timer.min,
                .extra2         = &xfs_params.xfs_buf_timer.max
        },
        {
-               .ctl_name       = XFS_BUF_AGE,
                .procname       = "age_buffer_centisecs",
                .data           = &xfs_params.xfs_buf_age.val,
                .maxlen         = sizeof(int),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec_minmax,
-               .strategy       = &sysctl_intvec,
+               .proc_handler   = proc_dointvec_minmax,
                .extra1         = &xfs_params.xfs_buf_age.min,
                .extra2         = &xfs_params.xfs_buf_age.max
        },
        {
-               .ctl_name       = XFS_INHERIT_NOSYM,
                .procname       = "inherit_nosymlinks",
                .data           = &xfs_params.inherit_nosym.val,
                .maxlen         = sizeof(int),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec_minmax,
-               .strategy       = &sysctl_intvec,
+               .proc_handler   = proc_dointvec_minmax,
                .extra1         = &xfs_params.inherit_nosym.min,
                .extra2         = &xfs_params.inherit_nosym.max
        },
        {
-               .ctl_name       = XFS_ROTORSTEP,
                .procname       = "rotorstep",
                .data           = &xfs_params.rotorstep.val,
                .maxlen         = sizeof(int),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec_minmax,
-               .strategy       = &sysctl_intvec,
+               .proc_handler   = proc_dointvec_minmax,
                .extra1         = &xfs_params.rotorstep.min,
                .extra2         = &xfs_params.rotorstep.max
        },
        {
-               .ctl_name       = XFS_INHERIT_NODFRG,
                .procname       = "inherit_nodefrag",
                .data           = &xfs_params.inherit_nodfrg.val,
                .maxlen         = sizeof(int),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec_minmax,
-               .strategy       = &sysctl_intvec,
+               .proc_handler   = proc_dointvec_minmax,
                .extra1         = &xfs_params.inherit_nodfrg.min,
                .extra2         = &xfs_params.inherit_nodfrg.max
        },
        {
-               .ctl_name       = XFS_FILESTREAM_TIMER,
                .procname       = "filestream_centisecs",
                .data           = &xfs_params.fstrm_timer.val,
                .maxlen         = sizeof(int),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec_minmax,
-               .strategy       = &sysctl_intvec,
+               .proc_handler   = proc_dointvec_minmax,
                .extra1         = &xfs_params.fstrm_timer.min,
                .extra2         = &xfs_params.fstrm_timer.max,
        },
        /* please keep this the last entry */
 #ifdef CONFIG_PROC_FS
        {
-               .ctl_name       = XFS_STATS_CLEAR,
                .procname       = "stats_clear",
                .data           = &xfs_params.stats_clear.val,
                .maxlen         = sizeof(int),
                .mode           = 0644,
-               .proc_handler   = &xfs_stats_clear_proc_handler,
-               .strategy       = &sysctl_intvec,
+               .proc_handler   = xfs_stats_clear_proc_handler,
                .extra1         = &xfs_params.stats_clear.min,
                .extra2         = &xfs_params.stats_clear.max
        },
@@ -229,7 +199,6 @@ static ctl_table xfs_table[] = {
 
 static ctl_table xfs_dir_table[] = {
        {
-               .ctl_name       = FS_XFS,
                .procname       = "xfs",
                .mode           = 0555,
                .child          = xfs_table
@@ -239,7 +208,6 @@ static ctl_table xfs_dir_table[] = {
 
 static ctl_table xfs_root_table[] = {
        {
-               .ctl_name       = CTL_FS,
                .procname       = "fs",
                .mode           = 0555,
                .child          = xfs_dir_table
index ba4ec39..57b5c3c 100644 (file)
@@ -13,6 +13,7 @@
 #define flush_cache_dup_mm(mm)                 do { } while (0)
 #define flush_cache_range(vma, start, end)     do { } while (0)
 #define flush_cache_page(vma, vmaddr, pfn)     do { } while (0)
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 0
 #define flush_dcache_page(page)                        do { } while (0)
 #define flush_dcache_mmap_lock(mapping)                do { } while (0)
 #define flush_dcache_mmap_unlock(mapping)      do { } while (0)
index 4fb3573..38a6948 100644 (file)
@@ -75,6 +75,7 @@ enum {
        ATA_ID_EIDE_DMA_TIME    = 66,
        ATA_ID_EIDE_PIO         = 67,
        ATA_ID_EIDE_PIO_IORDY   = 68,
+       ATA_ID_ADDITIONAL_SUPP  = 69,
        ATA_ID_QUEUE_DEPTH      = 75,
        ATA_ID_MAJOR_VER        = 80,
        ATA_ID_COMMAND_SET_1    = 82,
@@ -87,6 +88,7 @@ enum {
        ATA_ID_HW_CONFIG        = 93,
        ATA_ID_SPG              = 98,
        ATA_ID_LBA_CAPACITY_2   = 100,
+       ATA_ID_SECTOR_SIZE      = 106,
        ATA_ID_LAST_LUN         = 126,
        ATA_ID_DLF              = 128,
        ATA_ID_CSFO             = 129,
@@ -638,6 +640,18 @@ static inline int ata_id_flush_ext_enabled(const u16 *id)
        return (id[ATA_ID_CFS_ENABLE_2] & 0x2400) == 0x2400;
 }
 
+static inline int ata_id_has_large_logical_sectors(const u16 *id)
+{
+       if ((id[ATA_ID_SECTOR_SIZE] & 0xc000) != 0x4000)
+               return 0;
+       return id[ATA_ID_SECTOR_SIZE] & (1 << 13);
+}
+
+static inline u8 ata_id_logical_per_physical_sectors(const u16 *id)
+{
+       return id[ATA_ID_SECTOR_SIZE] & 0xf;
+}
+
 static inline int ata_id_has_lba48(const u16 *id)
 {
        if ((id[ATA_ID_COMMAND_SET_2] & 0xC000) != 0x4000)
@@ -803,6 +817,16 @@ static inline int ata_id_has_trim(const u16 *id)
        return 0;
 }
 
+static inline int ata_id_has_zero_after_trim(const u16 *id)
+{
+       /* DSM supported, deterministic read, and read zero after trim set */
+       if (ata_id_has_trim(id) &&
+           (id[ATA_ID_ADDITIONAL_SUPP] & 0x4020) == 0x4020)
+               return 1;
+
+       return 0;
+}
+
 static inline int ata_id_current_chs_valid(const u16 *id)
 {
        /* For ATA-1 devices, if the INITIALIZE DEVICE PARAMETERS command
@@ -958,17 +982,17 @@ static inline void ata_id_to_hd_driveid(u16 *id)
 }
 
 /*
- * Write up to 'max' LBA Range Entries to the buffer that will cover the
- * extent from sector to sector + count.  This is used for TRIM and for
- * ADD LBA(S) TO NV CACHE PINNED SET.
+ * Write LBA Range Entries to the buffer that will cover the extent from
+ * sector to sector + count.  This is used for TRIM and for ADD LBA(S)
+ * TO NV CACHE PINNED SET.
  */
-static inline unsigned ata_set_lba_range_entries(void *_buffer, unsigned max,
-                                               u64 sector, unsigned long count)
+static inline unsigned ata_set_lba_range_entries(void *_buffer,
+               unsigned buf_size, u64 sector, unsigned long count)
 {
        __le64 *buffer = _buffer;
-       unsigned i = 0;
+       unsigned i = 0, used_bytes;
 
-       while (i < max) {
+       while (i < buf_size / 8 ) { /* 6-byte LBA + 2-byte range per entry */
                u64 entry = sector |
                        ((u64)(count > 0xffff ? 0xffff : count) << 48);
                buffer[i++] = __cpu_to_le64(entry);
@@ -978,9 +1002,9 @@ static inline unsigned ata_set_lba_range_entries(void *_buffer, unsigned max,
                sector += 0xffff;
        }
 
-       max = ALIGN(i * 8, 512);
-       memset(buffer + i, 0, max - i * 8);
-       return max;
+       used_bytes = ALIGN(i * 8, 512);
+       memset(buffer + i, 0, used_bytes - i * 8);
+       return used_bytes;
 }
 
 static inline int is_multi_taskfile(struct ata_taskfile *tf)
index b449e73..fcbc26a 100644 (file)
@@ -331,4 +331,17 @@ static inline int bdi_sched_wait(void *word)
        return 0;
 }
 
+static inline void blk_run_backing_dev(struct backing_dev_info *bdi,
+                                      struct page *page)
+{
+       if (bdi && bdi->unplug_io_fn)
+               bdi->unplug_io_fn(bdi, page);
+}
+
+static inline void blk_run_address_space(struct address_space *mapping)
+{
+       if (mapping)
+               blk_run_backing_dev(mapping->backing_dev_info, NULL);
+}
+
 #endif         /* _LINUX_BACKING_DEV_H */
index 5be93f1..7fc5606 100644 (file)
@@ -391,6 +391,18 @@ extern struct bio *bio_copy_kern(struct request_queue *, void *, unsigned int,
                                 gfp_t, int);
 extern void bio_set_pages_dirty(struct bio *bio);
 extern void bio_check_pages_dirty(struct bio *bio);
+
+#ifndef ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE
+# error        "You should define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE for your platform"
+#endif
+#if ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE
+extern void bio_flush_dcache_pages(struct bio *bi);
+#else
+static inline void bio_flush_dcache_pages(struct bio *bi)
+{
+}
+#endif
+
 extern struct bio *bio_copy_user(struct request_queue *, struct rq_map_data *,
                                 unsigned long, unsigned int, int, gfp_t);
 extern struct bio *bio_copy_user_iov(struct request_queue *,
@@ -450,11 +462,8 @@ extern struct biovec_slab bvec_slabs[BIOVEC_NR_POOLS] __read_mostly;
 /*
  * remember never ever reenable interrupts between a bvec_kmap_irq and
  * bvec_kunmap_irq!
- *
- * This function MUST be inlined - it plays with the CPU interrupt flags.
  */
-static __always_inline char *bvec_kmap_irq(struct bio_vec *bvec,
-               unsigned long *flags)
+static inline char *bvec_kmap_irq(struct bio_vec *bvec, unsigned long *flags)
 {
        unsigned long addr;
 
@@ -470,8 +479,7 @@ static __always_inline char *bvec_kmap_irq(struct bio_vec *bvec,
        return (char *) addr + bvec->bv_offset;
 }
 
-static __always_inline void bvec_kunmap_irq(char *buffer,
-               unsigned long *flags)
+static inline void bvec_kunmap_irq(char *buffer, unsigned long *flags)
 {
        unsigned long ptr = (unsigned long) buffer & PAGE_MASK;
 
index 221cecd..784a919 100644 (file)
@@ -312,13 +312,17 @@ struct queue_limits {
        unsigned int            io_min;
        unsigned int            io_opt;
        unsigned int            max_discard_sectors;
+       unsigned int            discard_granularity;
+       unsigned int            discard_alignment;
 
        unsigned short          logical_block_size;
        unsigned short          max_hw_segments;
        unsigned short          max_phys_segments;
 
        unsigned char           misaligned;
+       unsigned char           discard_misaligned;
        unsigned char           no_cluster;
+       signed char             discard_zeroes_data;
 };
 
 struct request_queue
@@ -749,6 +753,17 @@ struct req_iterator {
 #define rq_iter_last(rq, _iter)                                        \
                (_iter.bio->bi_next == NULL && _iter.i == _iter.bio->bi_vcnt-1)
 
+#ifndef ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE
+# error        "You should define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE for your platform"
+#endif
+#if ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE
+extern void rq_flush_dcache_pages(struct request *rq);
+#else
+static inline void rq_flush_dcache_pages(struct request *rq)
+{
+}
+#endif
+
 extern int blk_register_queue(struct gendisk *disk);
 extern void blk_unregister_queue(struct gendisk *disk);
 extern void register_disk(struct gendisk *dev);
@@ -823,19 +838,6 @@ static inline struct request_queue *bdev_get_queue(struct block_device *bdev)
        return bdev->bd_disk->queue;
 }
 
-static inline void blk_run_backing_dev(struct backing_dev_info *bdi,
-                                      struct page *page)
-{
-       if (bdi && bdi->unplug_io_fn)
-               bdi->unplug_io_fn(bdi, page);
-}
-
-static inline void blk_run_address_space(struct address_space *mapping)
-{
-       if (mapping)
-               blk_run_backing_dev(mapping->backing_dev_info, NULL);
-}
-
 /*
  * blk_rq_pos()                        : the current sector
  * blk_rq_bytes()              : bytes left in the entire request
@@ -1134,6 +1136,34 @@ static inline int bdev_alignment_offset(struct block_device *bdev)
        return q->limits.alignment_offset;
 }
 
+static inline int queue_discard_alignment(struct request_queue *q)
+{
+       if (q->limits.discard_misaligned)
+               return -1;
+
+       return q->limits.discard_alignment;
+}
+
+static inline int queue_sector_discard_alignment(struct request_queue *q,
+                                                sector_t sector)
+{
+       return ((sector << 9) - q->limits.discard_alignment)
+               & (q->limits.discard_granularity - 1);
+}
+
+static inline unsigned int queue_discard_zeroes_data(struct request_queue *q)
+{
+       if (q->limits.discard_zeroes_data == 1)
+               return 1;
+
+       return 0;
+}
+
+static inline unsigned int bdev_discard_zeroes_data(struct block_device *bdev)
+{
+       return queue_discard_zeroes_data(bdev_get_queue(bdev));
+}
+
 static inline int queue_dma_alignment(struct request_queue *q)
 {
        return q ? q->dma_alignment : 511;
index 9c8d31b..ccefff0 100644 (file)
@@ -60,3 +60,9 @@ SUBSYS(net_cls)
 #endif
 
 /* */
+
+#ifdef CONFIG_BLK_CGROUP
+SUBSYS(blkio)
+#endif
+
+/* */
index ab3af40..94dea3f 100644 (file)
 #endif
 
 #endif
+
+#if __GNUC_MINOR__ > 0
+#define __compiletime_object_size(obj) __builtin_object_size(obj, 0)
+#endif
+#if __GNUC_MINOR__ >= 4
+#define __compiletime_warning(message) __attribute__((warning(message)))
+#define __compiletime_error(message) __attribute__((error(message)))
+#endif
index acbd654..5be3dab 100644 (file)
@@ -275,6 +275,17 @@ void ftrace_likely_update(struct ftrace_branch_data *f, int val, int expect);
 # define __same_type(a, b) __builtin_types_compatible_p(typeof(a), typeof(b))
 #endif
 
+/* Compile time object size, -1 for unknown */
+#ifndef __compiletime_object_size
+# define __compiletime_object_size(obj) -1
+#endif
+#ifndef __compiletime_warning
+# define __compiletime_warning(message)
+#endif
+#ifndef __compiletime_error
+# define __compiletime_error(message)
+#endif
+
 /*
  * Prevent the compiler from merging or refetching accesses.  The compiler
  * is also forbidden from reordering successive instances of ACCESS_ONCE(),
index 3a14615..72ba63e 100644 (file)
@@ -43,6 +43,8 @@
 #define CN_DST_VAL                     0x1
 #define CN_IDX_DM                      0x7     /* Device Mapper */
 #define CN_VAL_DM_USERSPACE_LOG                0x1
+#define CN_IDX_DRBD                    0x8
+#define CN_VAL_DRBD                    0x1
 
 #define CN_NETLINK_USERS               8
 
diff --git a/include/linux/drbd.h b/include/linux/drbd.h
new file mode 100644 (file)
index 0000000..e84f473
--- /dev/null
@@ -0,0 +1,343 @@
+/*
+  drbd.h
+  Kernel module for 2.6.x Kernels
+
+  This file is part of DRBD by Philipp Reisner and Lars Ellenberg.
+
+  Copyright (C) 2001-2008, LINBIT Information Technologies GmbH.
+  Copyright (C) 2001-2008, Philipp Reisner <philipp.reisner@linbit.com>.
+  Copyright (C) 2001-2008, Lars Ellenberg <lars.ellenberg@linbit.com>.
+
+  drbd is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2, or (at your option)
+  any later version.
+
+  drbd 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 drbd; see the file COPYING.  If not, write to
+  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+#ifndef DRBD_H
+#define DRBD_H
+#include <linux/connector.h>
+#include <asm/types.h>
+
+#ifdef __KERNEL__
+#include <linux/types.h>
+#include <asm/byteorder.h>
+#else
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <limits.h>
+
+/* Altough the Linux source code makes a difference between
+   generic endianness and the bitfields' endianness, there is no
+   architecture as of Linux-2.6.24-rc4 where the bitfileds' endianness
+   does not match the generic endianness. */
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+#define __LITTLE_ENDIAN_BITFIELD
+#elif __BYTE_ORDER == __BIG_ENDIAN
+#define __BIG_ENDIAN_BITFIELD
+#else
+# error "sorry, weird endianness on this box"
+#endif
+
+#endif
+
+
+extern const char *drbd_buildtag(void);
+#define REL_VERSION "8.3.6"
+#define API_VERSION 88
+#define PRO_VERSION_MIN 86
+#define PRO_VERSION_MAX 91
+
+
+enum drbd_io_error_p {
+       EP_PASS_ON, /* FIXME should the better be named "Ignore"? */
+       EP_CALL_HELPER,
+       EP_DETACH
+};
+
+enum drbd_fencing_p {
+       FP_DONT_CARE,
+       FP_RESOURCE,
+       FP_STONITH
+};
+
+enum drbd_disconnect_p {
+       DP_RECONNECT,
+       DP_DROP_NET_CONF,
+       DP_FREEZE_IO
+};
+
+enum drbd_after_sb_p {
+       ASB_DISCONNECT,
+       ASB_DISCARD_YOUNGER_PRI,
+       ASB_DISCARD_OLDER_PRI,
+       ASB_DISCARD_ZERO_CHG,
+       ASB_DISCARD_LEAST_CHG,
+       ASB_DISCARD_LOCAL,
+       ASB_DISCARD_REMOTE,
+       ASB_CONSENSUS,
+       ASB_DISCARD_SECONDARY,
+       ASB_CALL_HELPER,
+       ASB_VIOLENTLY
+};
+
+/* KEEP the order, do not delete or insert. Only append. */
+enum drbd_ret_codes {
+       ERR_CODE_BASE           = 100,
+       NO_ERROR                = 101,
+       ERR_LOCAL_ADDR          = 102,
+       ERR_PEER_ADDR           = 103,
+       ERR_OPEN_DISK           = 104,
+       ERR_OPEN_MD_DISK        = 105,
+       ERR_DISK_NOT_BDEV       = 107,
+       ERR_MD_NOT_BDEV         = 108,
+       ERR_DISK_TO_SMALL       = 111,
+       ERR_MD_DISK_TO_SMALL    = 112,
+       ERR_BDCLAIM_DISK        = 114,
+       ERR_BDCLAIM_MD_DISK     = 115,
+       ERR_MD_IDX_INVALID      = 116,
+       ERR_IO_MD_DISK          = 118,
+       ERR_MD_INVALID          = 119,
+       ERR_AUTH_ALG            = 120,
+       ERR_AUTH_ALG_ND         = 121,
+       ERR_NOMEM               = 122,
+       ERR_DISCARD             = 123,
+       ERR_DISK_CONFIGURED     = 124,
+       ERR_NET_CONFIGURED      = 125,
+       ERR_MANDATORY_TAG       = 126,
+       ERR_MINOR_INVALID       = 127,
+       ERR_INTR                = 129, /* EINTR */
+       ERR_RESIZE_RESYNC       = 130,
+       ERR_NO_PRIMARY          = 131,
+       ERR_SYNC_AFTER          = 132,
+       ERR_SYNC_AFTER_CYCLE    = 133,
+       ERR_PAUSE_IS_SET        = 134,
+       ERR_PAUSE_IS_CLEAR      = 135,
+       ERR_PACKET_NR           = 137,
+       ERR_NO_DISK             = 138,
+       ERR_NOT_PROTO_C         = 139,
+       ERR_NOMEM_BITMAP        = 140,
+       ERR_INTEGRITY_ALG       = 141, /* DRBD 8.2 only */
+       ERR_INTEGRITY_ALG_ND    = 142, /* DRBD 8.2 only */
+       ERR_CPU_MASK_PARSE      = 143, /* DRBD 8.2 only */
+       ERR_CSUMS_ALG           = 144, /* DRBD 8.2 only */
+       ERR_CSUMS_ALG_ND        = 145, /* DRBD 8.2 only */
+       ERR_VERIFY_ALG          = 146, /* DRBD 8.2 only */
+       ERR_VERIFY_ALG_ND       = 147, /* DRBD 8.2 only */
+       ERR_CSUMS_RESYNC_RUNNING= 148, /* DRBD 8.2 only */
+       ERR_VERIFY_RUNNING      = 149, /* DRBD 8.2 only */
+       ERR_DATA_NOT_CURRENT    = 150,
+       ERR_CONNECTED           = 151, /* DRBD 8.3 only */
+       ERR_PERM                = 152,
+
+       /* insert new ones above this line */
+       AFTER_LAST_ERR_CODE
+};
+
+#define DRBD_PROT_A   1
+#define DRBD_PROT_B   2
+#define DRBD_PROT_C   3
+
+enum drbd_role {
+       R_UNKNOWN = 0,
+       R_PRIMARY = 1,     /* role */
+       R_SECONDARY = 2,   /* role */
+       R_MASK = 3,
+};
+
+/* The order of these constants is important.
+ * The lower ones (<C_WF_REPORT_PARAMS) indicate
+ * that there is no socket!
+ * >=C_WF_REPORT_PARAMS ==> There is a socket
+ */
+enum drbd_conns {
+       C_STANDALONE,
+       C_DISCONNECTING,  /* Temporal state on the way to StandAlone. */
+       C_UNCONNECTED,    /* >= C_UNCONNECTED -> inc_net() succeeds */
+
+       /* These temporal states are all used on the way
+        * from >= C_CONNECTED to Unconnected.
+        * The 'disconnect reason' states
+        * I do not allow to change beween them. */
+       C_TIMEOUT,
+       C_BROKEN_PIPE,
+       C_NETWORK_FAILURE,
+       C_PROTOCOL_ERROR,
+       C_TEAR_DOWN,
+
+       C_WF_CONNECTION,
+       C_WF_REPORT_PARAMS, /* we have a socket */
+       C_CONNECTED,      /* we have introduced each other */
+       C_STARTING_SYNC_S,  /* starting full sync by admin request. */
+       C_STARTING_SYNC_T,  /* stariing full sync by admin request. */
+       C_WF_BITMAP_S,
+       C_WF_BITMAP_T,
+       C_WF_SYNC_UUID,
+
+       /* All SyncStates are tested with this comparison
+        * xx >= C_SYNC_SOURCE && xx <= C_PAUSED_SYNC_T */
+       C_SYNC_SOURCE,
+       C_SYNC_TARGET,
+       C_VERIFY_S,
+       C_VERIFY_T,
+       C_PAUSED_SYNC_S,
+       C_PAUSED_SYNC_T,
+       C_MASK = 31
+};
+
+enum drbd_disk_state {
+       D_DISKLESS,
+       D_ATTACHING,      /* In the process of reading the meta-data */
+       D_FAILED,         /* Becomes D_DISKLESS as soon as we told it the peer */
+                       /* when >= D_FAILED it is legal to access mdev->bc */
+       D_NEGOTIATING,    /* Late attaching state, we need to talk to the peer */
+       D_INCONSISTENT,
+       D_OUTDATED,
+       D_UNKNOWN,       /* Only used for the peer, never for myself */
+       D_CONSISTENT,     /* Might be D_OUTDATED, might be D_UP_TO_DATE ... */
+       D_UP_TO_DATE,       /* Only this disk state allows applications' IO ! */
+       D_MASK = 15
+};
+
+union drbd_state {
+/* According to gcc's docs is the ...
+ * The order of allocation of bit-fields within a unit (C90 6.5.2.1, C99 6.7.2.1).
+ * Determined by ABI.
+ * pointed out by Maxim Uvarov q<muvarov@ru.mvista.com>
+ * even though we transmit as "cpu_to_be32(state)",
+ * the offsets of the bitfields still need to be swapped
+ * on different endianess.
+ */
+       struct {
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+               unsigned role:2 ;   /* 3/4       primary/secondary/unknown */
+               unsigned peer:2 ;   /* 3/4       primary/secondary/unknown */
+               unsigned conn:5 ;   /* 17/32     cstates */
+               unsigned disk:4 ;   /* 8/16      from D_DISKLESS to D_UP_TO_DATE */
+               unsigned pdsk:4 ;   /* 8/16      from D_DISKLESS to D_UP_TO_DATE */
+               unsigned susp:1 ;   /* 2/2       IO suspended  no/yes */
+               unsigned aftr_isp:1 ; /* isp .. imposed sync pause */
+               unsigned peer_isp:1 ;
+               unsigned user_isp:1 ;
+               unsigned _pad:11;   /* 0         unused */
+#elif defined(__BIG_ENDIAN_BITFIELD)
+               unsigned _pad:11;   /* 0         unused */
+               unsigned user_isp:1 ;
+               unsigned peer_isp:1 ;
+               unsigned aftr_isp:1 ; /* isp .. imposed sync pause */
+               unsigned susp:1 ;   /* 2/2       IO suspended  no/yes */
+               unsigned pdsk:4 ;   /* 8/16      from D_DISKLESS to D_UP_TO_DATE */
+               unsigned disk:4 ;   /* 8/16      from D_DISKLESS to D_UP_TO_DATE */
+               unsigned conn:5 ;   /* 17/32     cstates */
+               unsigned peer:2 ;   /* 3/4       primary/secondary/unknown */
+               unsigned role:2 ;   /* 3/4       primary/secondary/unknown */
+#else
+# error "this endianess is not supported"
+#endif
+       };
+       unsigned int i;
+};
+
+enum drbd_state_ret_codes {
+       SS_CW_NO_NEED = 4,
+       SS_CW_SUCCESS = 3,
+       SS_NOTHING_TO_DO = 2,
+       SS_SUCCESS = 1,
+       SS_UNKNOWN_ERROR = 0, /* Used to sleep longer in _drbd_request_state */
+       SS_TWO_PRIMARIES = -1,
+       SS_NO_UP_TO_DATE_DISK = -2,
+       SS_NO_LOCAL_DISK = -4,
+       SS_NO_REMOTE_DISK = -5,
+       SS_CONNECTED_OUTDATES = -6,
+       SS_PRIMARY_NOP = -7,
+       SS_RESYNC_RUNNING = -8,
+       SS_ALREADY_STANDALONE = -9,
+       SS_CW_FAILED_BY_PEER = -10,
+       SS_IS_DISKLESS = -11,
+       SS_DEVICE_IN_USE = -12,
+       SS_NO_NET_CONFIG = -13,
+       SS_NO_VERIFY_ALG = -14,       /* drbd-8.2 only */
+       SS_NEED_CONNECTION = -15,    /* drbd-8.2 only */
+       SS_LOWER_THAN_OUTDATED = -16,
+       SS_NOT_SUPPORTED = -17,      /* drbd-8.2 only */
+       SS_IN_TRANSIENT_STATE = -18,  /* Retry after the next state change */
+       SS_CONCURRENT_ST_CHG = -19,   /* Concurrent cluster side state change! */
+       SS_AFTER_LAST_ERROR = -20,    /* Keep this at bottom */
+};
+
+/* from drbd_strings.c */
+extern const char *drbd_conn_str(enum drbd_conns);
+extern const char *drbd_role_str(enum drbd_role);
+extern const char *drbd_disk_str(enum drbd_disk_state);
+extern const char *drbd_set_st_err_str(enum drbd_state_ret_codes);
+
+#define SHARED_SECRET_MAX 64
+
+#define MDF_CONSISTENT         (1 << 0)
+#define MDF_PRIMARY_IND                (1 << 1)
+#define MDF_CONNECTED_IND      (1 << 2)
+#define MDF_FULL_SYNC          (1 << 3)
+#define MDF_WAS_UP_TO_DATE     (1 << 4)
+#define MDF_PEER_OUT_DATED     (1 << 5)
+#define MDF_CRASHED_PRIMARY     (1 << 6)
+
+enum drbd_uuid_index {
+       UI_CURRENT,
+       UI_BITMAP,
+       UI_HISTORY_START,
+       UI_HISTORY_END,
+       UI_SIZE,      /* nl-packet: number of dirty bits */
+       UI_FLAGS,     /* nl-packet: flags */
+       UI_EXTENDED_SIZE   /* Everything. */
+};
+
+enum drbd_timeout_flag {
+       UT_DEFAULT      = 0,
+       UT_DEGRADED     = 1,
+       UT_PEER_OUTDATED = 2,
+};
+
+#define UUID_JUST_CREATED ((__u64)4)
+
+#define DRBD_MAGIC 0x83740267
+#define BE_DRBD_MAGIC __constant_cpu_to_be32(DRBD_MAGIC)
+
+/* these are of type "int" */
+#define DRBD_MD_INDEX_INTERNAL -1
+#define DRBD_MD_INDEX_FLEX_EXT -2
+#define DRBD_MD_INDEX_FLEX_INT -3
+
+/* Start of the new netlink/connector stuff */
+
+#define DRBD_NL_CREATE_DEVICE 0x01
+#define DRBD_NL_SET_DEFAULTS  0x02
+
+
+/* For searching a vacant cn_idx value */
+#define CN_IDX_STEP                    6977
+
+struct drbd_nl_cfg_req {
+       int packet_type;
+       unsigned int drbd_minor;
+       int flags;
+       unsigned short tag_list[];
+};
+
+struct drbd_nl_cfg_reply {
+       int packet_type;
+       unsigned int minor;
+       int ret_code; /* enum ret_code or set_st_err_t */
+       unsigned short tag_list[]; /* only used with get_* calls */
+};
+
+#endif
diff --git a/include/linux/drbd_limits.h b/include/linux/drbd_limits.h
new file mode 100644 (file)
index 0000000..51f47a5
--- /dev/null
@@ -0,0 +1,137 @@
+/*
+  drbd_limits.h
+  This file is part of DRBD by Philipp Reisner and Lars Ellenberg.
+*/
+
+/*
+ * Our current limitations.
+ * Some of them are hard limits,
+ * some of them are arbitrary range limits, that make it easier to provide
+ * feedback about nonsense settings for certain configurable values.
+ */
+
+#ifndef DRBD_LIMITS_H
+#define DRBD_LIMITS_H 1
+
+#define DEBUG_RANGE_CHECK 0
+
+#define DRBD_MINOR_COUNT_MIN 1
+#define DRBD_MINOR_COUNT_MAX 255
+
+#define DRBD_DIALOG_REFRESH_MIN 0
+#define DRBD_DIALOG_REFRESH_MAX 600
+
+/* valid port number */
+#define DRBD_PORT_MIN 1
+#define DRBD_PORT_MAX 0xffff
+
+/* startup { */
+  /* if you want more than 3.4 days, disable */
+#define DRBD_WFC_TIMEOUT_MIN 0
+#define DRBD_WFC_TIMEOUT_MAX 300000
+#define DRBD_WFC_TIMEOUT_DEF 0
+
+#define DRBD_DEGR_WFC_TIMEOUT_MIN 0
+#define DRBD_DEGR_WFC_TIMEOUT_MAX 300000
+#define DRBD_DEGR_WFC_TIMEOUT_DEF 0
+
+#define DRBD_OUTDATED_WFC_TIMEOUT_MIN 0
+#define DRBD_OUTDATED_WFC_TIMEOUT_MAX 300000
+#define DRBD_OUTDATED_WFC_TIMEOUT_DEF 0
+/* }*/
+
+/* net { */
+  /* timeout, unit centi seconds
+   * more than one minute timeout is not usefull */
+#define DRBD_TIMEOUT_MIN 1
+#define DRBD_TIMEOUT_MAX 600
+#define DRBD_TIMEOUT_DEF 60       /* 6 seconds */
+
+  /* active connection retries when C_WF_CONNECTION */
+#define DRBD_CONNECT_INT_MIN 1
+#define DRBD_CONNECT_INT_MAX 120
+#define DRBD_CONNECT_INT_DEF 10   /* seconds */
+
+  /* keep-alive probes when idle */
+#define DRBD_PING_INT_MIN 1
+#define DRBD_PING_INT_MAX 120
+#define DRBD_PING_INT_DEF 10
+
+ /* timeout for the ping packets.*/
+#define DRBD_PING_TIMEO_MIN  1
+#define DRBD_PING_TIMEO_MAX  100
+#define DRBD_PING_TIMEO_DEF  5
+
+  /* max number of write requests between write barriers */
+#define DRBD_MAX_EPOCH_SIZE_MIN 1
+#define DRBD_MAX_EPOCH_SIZE_MAX 20000
+#define DRBD_MAX_EPOCH_SIZE_DEF 2048
+
+  /* I don't think that a tcp send buffer of more than 10M is usefull */
+#define DRBD_SNDBUF_SIZE_MIN  0
+#define DRBD_SNDBUF_SIZE_MAX  (10<<20)
+#define DRBD_SNDBUF_SIZE_DEF  0
+
+#define DRBD_RCVBUF_SIZE_MIN  0
+#define DRBD_RCVBUF_SIZE_MAX  (10<<20)
+#define DRBD_RCVBUF_SIZE_DEF  0
+
+  /* @4k PageSize -> 128kB - 512MB */
+#define DRBD_MAX_BUFFERS_MIN  32
+#define DRBD_MAX_BUFFERS_MAX  131072
+#define DRBD_MAX_BUFFERS_DEF  2048
+
+  /* @4k PageSize -> 4kB - 512MB */
+#define DRBD_UNPLUG_WATERMARK_MIN  1
+#define DRBD_UNPLUG_WATERMARK_MAX  131072
+#define DRBD_UNPLUG_WATERMARK_DEF (DRBD_MAX_BUFFERS_DEF/16)
+
+  /* 0 is disabled.
+   * 200 should be more than enough even for very short timeouts */
+#define DRBD_KO_COUNT_MIN  0
+#define DRBD_KO_COUNT_MAX  200
+#define DRBD_KO_COUNT_DEF  0
+/* } */
+
+/* syncer { */
+  /* FIXME allow rate to be zero? */
+#define DRBD_RATE_MIN 1
+/* channel bonding 10 GbE, or other hardware */
+#define DRBD_RATE_MAX (4 << 20)
+#define DRBD_RATE_DEF 250  /* kb/second */
+
+  /* less than 7 would hit performance unneccessarily.
+   * 3833 is the largest prime that still does fit
+   * into 64 sectors of activity log */
+#define DRBD_AL_EXTENTS_MIN  7
+#define DRBD_AL_EXTENTS_MAX  3833
+#define DRBD_AL_EXTENTS_DEF  127
+
+#define DRBD_AFTER_MIN  -1
+#define DRBD_AFTER_MAX  255
+#define DRBD_AFTER_DEF  -1
+
+/* } */
+
+/* drbdsetup XY resize -d Z
+ * you are free to reduce the device size to nothing, if you want to.
+ * the upper limit with 64bit kernel, enough ram and flexible meta data
+ * is 16 TB, currently. */
+/* DRBD_MAX_SECTORS */
+#define DRBD_DISK_SIZE_SECT_MIN  0
+#define DRBD_DISK_SIZE_SECT_MAX  (16 * (2LLU << 30))
+#define DRBD_DISK_SIZE_SECT_DEF  0 /* = disabled = no user size... */
+
+#define DRBD_ON_IO_ERROR_DEF EP_PASS_ON
+#define DRBD_FENCING_DEF FP_DONT_CARE
+#define DRBD_AFTER_SB_0P_DEF ASB_DISCONNECT
+#define DRBD_AFTER_SB_1P_DEF ASB_DISCONNECT
+#define DRBD_AFTER_SB_2P_DEF ASB_DISCONNECT
+#define DRBD_RR_CONFLICT_DEF ASB_DISCONNECT
+
+#define DRBD_MAX_BIO_BVECS_MIN 0
+#define DRBD_MAX_BIO_BVECS_MAX 128
+#define DRBD_MAX_BIO_BVECS_DEF 0
+
+#undef RANGE
+#endif
diff --git a/include/linux/drbd_nl.h b/include/linux/drbd_nl.h
new file mode 100644 (file)
index 0000000..db5721a
--- /dev/null
@@ -0,0 +1,137 @@
+/*
+   PAKET( name,
+         TYPE ( pn, pr, member )
+         ...
+   )
+
+   You may never reissue one of the pn arguments
+*/
+
+#if !defined(NL_PACKET) || !defined(NL_STRING) || !defined(NL_INTEGER) || !defined(NL_BIT) || !defined(NL_INT64)
+#error "The macros NL_PACKET, NL_STRING, NL_INTEGER, NL_INT64 and NL_BIT needs to be defined"
+#endif
+
+NL_PACKET(primary, 1,
+       NL_BIT(         1,      T_MAY_IGNORE,   overwrite_peer)
+)
+
+NL_PACKET(secondary, 2, )
+
+NL_PACKET(disk_conf, 3,
+       NL_INT64(       2,      T_MAY_IGNORE,   disk_size)
+       NL_STRING(      3,      T_MANDATORY,    backing_dev,    128)
+       NL_STRING(      4,      T_MANDATORY,    meta_dev,       128)
+       NL_INTEGER(     5,      T_MANDATORY,    meta_dev_idx)
+       NL_INTEGER(     6,      T_MAY_IGNORE,   on_io_error)
+       NL_INTEGER(     7,      T_MAY_IGNORE,   fencing)
+       NL_BIT(         37,     T_MAY_IGNORE,   use_bmbv)
+       NL_BIT(         53,     T_MAY_IGNORE,   no_disk_flush)
+       NL_BIT(         54,     T_MAY_IGNORE,   no_md_flush)
+         /*  55 max_bio_size was available in 8.2.6rc2 */
+       NL_INTEGER(     56,     T_MAY_IGNORE,   max_bio_bvecs)
+       NL_BIT(         57,     T_MAY_IGNORE,   no_disk_barrier)
+       NL_BIT(         58,     T_MAY_IGNORE,   no_disk_drain)
+)
+
+NL_PACKET(detach, 4, )
+
+NL_PACKET(net_conf, 5,
+       NL_STRING(      8,      T_MANDATORY,    my_addr,        128)
+       NL_STRING(      9,      T_MANDATORY,    peer_addr,      128)
+       NL_STRING(      10,     T_MAY_IGNORE,   shared_secret,  SHARED_SECRET_MAX)
+       NL_STRING(      11,     T_MAY_IGNORE,   cram_hmac_alg,  SHARED_SECRET_MAX)
+       NL_STRING(      44,     T_MAY_IGNORE,   integrity_alg,  SHARED_SECRET_MAX)
+       NL_INTEGER(     14,     T_MAY_IGNORE,   timeout)
+       NL_INTEGER(     15,     T_MANDATORY,    wire_protocol)
+       NL_INTEGER(     16,     T_MAY_IGNORE,   try_connect_int)
+       NL_INTEGER(     17,     T_MAY_IGNORE,   ping_int)
+       NL_INTEGER(     18,     T_MAY_IGNORE,   max_epoch_size)
+       NL_INTEGER(     19,     T_MAY_IGNORE,   max_buffers)
+       NL_INTEGER(     20,     T_MAY_IGNORE,   unplug_watermark)
+       NL_INTEGER(     21,     T_MAY_IGNORE,   sndbuf_size)
+       NL_INTEGER(     22,     T_MAY_IGNORE,   ko_count)
+       NL_INTEGER(     24,     T_MAY_IGNORE,   after_sb_0p)
+       NL_INTEGER(     25,     T_MAY_IGNORE,   after_sb_1p)
+       NL_INTEGER(     26,     T_MAY_IGNORE,   after_sb_2p)
+       NL_INTEGER(     39,     T_MAY_IGNORE,   rr_conflict)
+       NL_INTEGER(     40,     T_MAY_IGNORE,   ping_timeo)
+       NL_INTEGER(     67,     T_MAY_IGNORE,   rcvbuf_size)
+         /* 59 addr_family was available in GIT, never released */
+       NL_BIT(         60,     T_MANDATORY,    mind_af)
+       NL_BIT(         27,     T_MAY_IGNORE,   want_lose)
+       NL_BIT(         28,     T_MAY_IGNORE,   two_primaries)
+       NL_BIT(         41,     T_MAY_IGNORE,   always_asbp)
+       NL_BIT(         61,     T_MAY_IGNORE,   no_cork)
+       NL_BIT(         62,     T_MANDATORY,    auto_sndbuf_size)
+)
+
+NL_PACKET(disconnect, 6, )
+
+NL_PACKET(resize, 7,
+       NL_INT64(               29,     T_MAY_IGNORE,   resize_size)
+)
+
+NL_PACKET(syncer_conf, 8,
+       NL_INTEGER(     30,     T_MAY_IGNORE,   rate)
+       NL_INTEGER(     31,     T_MAY_IGNORE,   after)
+       NL_INTEGER(     32,     T_MAY_IGNORE,   al_extents)
+       NL_STRING(      52,     T_MAY_IGNORE,   verify_alg,     SHARED_SECRET_MAX)
+       NL_STRING(      51,     T_MAY_IGNORE,   cpu_mask,       32)
+       NL_STRING(      64,     T_MAY_IGNORE,   csums_alg,      SHARED_SECRET_MAX)
+       NL_BIT(         65,     T_MAY_IGNORE,   use_rle)
+)
+
+NL_PACKET(invalidate, 9, )
+NL_PACKET(invalidate_peer, 10, )
+NL_PACKET(pause_sync, 11, )
+NL_PACKET(resume_sync, 12, )
+NL_PACKET(suspend_io, 13, )
+NL_PACKET(resume_io, 14, )
+NL_PACKET(outdate, 15, )
+NL_PACKET(get_config, 16, )
+NL_PACKET(get_state, 17,
+       NL_INTEGER(     33,     T_MAY_IGNORE,   state_i)
+)
+
+NL_PACKET(get_uuids, 18,
+       NL_STRING(      34,     T_MAY_IGNORE,   uuids,  (UI_SIZE*sizeof(__u64)))
+       NL_INTEGER(     35,     T_MAY_IGNORE,   uuids_flags)
+)
+
+NL_PACKET(get_timeout_flag, 19,
+       NL_BIT(         36,     T_MAY_IGNORE,   use_degraded)
+)
+
+NL_PACKET(call_helper, 20,
+       NL_STRING(      38,     T_MAY_IGNORE,   helper,         32)
+)
+
+/* Tag nr 42 already allocated in drbd-8.1 development. */
+
+NL_PACKET(sync_progress, 23,
+       NL_INTEGER(     43,     T_MAY_IGNORE,   sync_progress)
+)
+
+NL_PACKET(dump_ee, 24,
+       NL_STRING(      45,     T_MAY_IGNORE,   dump_ee_reason, 32)
+       NL_STRING(      46,     T_MAY_IGNORE,   seen_digest, SHARED_SECRET_MAX)
+       NL_STRING(      47,     T_MAY_IGNORE,   calc_digest, SHARED_SECRET_MAX)
+       NL_INT64(       48,     T_MAY_IGNORE,   ee_sector)
+       NL_INT64(       49,     T_MAY_IGNORE,   ee_block_id)
+       NL_STRING(      50,     T_MAY_IGNORE,   ee_data,        32 << 10)
+)
+
+NL_PACKET(start_ov, 25,
+       NL_INT64(       66,     T_MAY_IGNORE,   start_sector)
+)
+
+NL_PACKET(new_c_uuid, 26,
+       NL_BIT(         63,     T_MANDATORY,    clear_bm)
+)
+
+#undef NL_PACKET
+#undef NL_INTEGER
+#undef NL_INT64
+#undef NL_BIT
+#undef NL_STRING
+
diff --git a/include/linux/drbd_tag_magic.h b/include/linux/drbd_tag_magic.h
new file mode 100644 (file)
index 0000000..fcdff84
--- /dev/null
@@ -0,0 +1,83 @@
+#ifndef DRBD_TAG_MAGIC_H
+#define DRBD_TAG_MAGIC_H
+
+#define TT_END     0
+#define TT_REMOVED 0xE000
+
+/* declare packet_type enums */
+enum packet_types {
+#define NL_PACKET(name, number, fields) P_ ## name = number,
+#define NL_INTEGER(pn, pr, member)
+#define NL_INT64(pn, pr, member)
+#define NL_BIT(pn, pr, member)
+#define NL_STRING(pn, pr, member, len)
+#include "drbd_nl.h"
+       P_nl_after_last_packet,
+};
+
+/* These struct are used to deduce the size of the tag lists: */
+#define NL_PACKET(name, number, fields)        \
+       struct name ## _tag_len_struct { fields };
+#define NL_INTEGER(pn, pr, member)             \
+       int member; int tag_and_len ## member;
+#define NL_INT64(pn, pr, member)               \
+       __u64 member; int tag_and_len ## member;
+#define NL_BIT(pn, pr, member)         \
+       unsigned char member:1; int tag_and_len ## member;
+#define NL_STRING(pn, pr, member, len) \
+       unsigned char member[len]; int member ## _len; \
+       int tag_and_len ## member;
+#include "linux/drbd_nl.h"
+
+/* declate tag-list-sizes */
+static const int tag_list_sizes[] = {
+#define NL_PACKET(name, number, fields) 2 fields ,
+#define NL_INTEGER(pn, pr, member)      + 4 + 4
+#define NL_INT64(pn, pr, member)        + 4 + 8
+#define NL_BIT(pn, pr, member)          + 4 + 1
+#define NL_STRING(pn, pr, member, len)  + 4 + (len)
+#include "drbd_nl.h"
+};
+
+/* The two highest bits are used for the tag type */
+#define TT_MASK      0xC000
+#define TT_INTEGER   0x0000
+#define TT_INT64     0x4000
+#define TT_BIT       0x8000
+#define TT_STRING    0xC000
+/* The next bit indicates if processing of the tag is mandatory */
+#define T_MANDATORY  0x2000
+#define T_MAY_IGNORE 0x0000
+#define TN_MASK      0x1fff
+/* The remaining 13 bits are used to enumerate the tags */
+
+#define tag_type(T)   ((T) & TT_MASK)
+#define tag_number(T) ((T) & TN_MASK)
+
+/* declare tag enums */
+#define NL_PACKET(name, number, fields) fields
+enum drbd_tags {
+#define NL_INTEGER(pn, pr, member)     T_ ## member = pn | TT_INTEGER | pr ,
+#define NL_INT64(pn, pr, member)       T_ ## member = pn | TT_INT64   | pr ,
+#define NL_BIT(pn, pr, member)         T_ ## member = pn | TT_BIT     | pr ,
+#define NL_STRING(pn, pr, member, len) T_ ## member = pn | TT_STRING  | pr ,
+#include "drbd_nl.h"
+};
+
+struct tag {
+       const char *name;
+       int type_n_flags;
+       int max_len;
+};
+
+/* declare tag names */
+#define NL_PACKET(name, number, fields) fields
+static const struct tag tag_descriptions[] = {
+#define NL_INTEGER(pn, pr, member)     [ pn ] = { #member, TT_INTEGER | pr, sizeof(int)   },
+#define NL_INT64(pn, pr, member)       [ pn ] = { #member, TT_INT64   | pr, sizeof(__u64) },
+#define NL_BIT(pn, pr, member)         [ pn ] = { #member, TT_BIT     | pr, sizeof(int)   },
+#define NL_STRING(pn, pr, member, len) [ pn ] = { #member, TT_STRING  | pr, (len)         },
+#include "drbd_nl.h"
+};
+
+#endif
index 7e1d4de..9416a46 100644 (file)
 #define fw_notify(s, args...) printk(KERN_NOTICE KBUILD_MODNAME ": " s, ## args)
 #define fw_error(s, args...) printk(KERN_ERR KBUILD_MODNAME ": " s, ## args)
 
-static inline void fw_memcpy_from_be32(void *_dst, void *_src, size_t size)
-{
-       u32    *dst = _dst;
-       __be32 *src = _src;
-       int i;
-
-       for (i = 0; i < size / 4; i++)
-               dst[i] = be32_to_cpu(src[i]);
-}
-
-static inline void fw_memcpy_to_be32(void *_dst, void *_src, size_t size)
-{
-       fw_memcpy_from_be32(_dst, _src, size);
-}
 #define CSR_REGISTER_BASE              0xfffff0000000ULL
 
 /* register offsets are relative to CSR_REGISTER_BASE */
@@ -131,7 +117,7 @@ struct fw_card {
 
        bool broadcast_channel_allocated;
        u32 broadcast_channel;
-       u32 topology_map[(CSR_TOPOLOGY_MAP_END - CSR_TOPOLOGY_MAP) / 4];
+       __be32 topology_map[(CSR_TOPOLOGY_MAP_END - CSR_TOPOLOGY_MAP) / 4];
 };
 
 struct fw_attribute_group {
@@ -281,6 +267,7 @@ struct fw_packet {
        void *payload;
        size_t payload_length;
        dma_addr_t payload_bus;
+       bool payload_mapped;
        u32 timestamp;
 
        /*
index 2620a8c..891f7d6 100644 (file)
@@ -129,7 +129,7 @@ struct inodes_stat_t {
  * WRITE_SYNC          Like WRITE_SYNC_PLUG, but also unplugs the device
  *                     immediately after submission. The write equivalent
  *                     of READ_SYNC.
- * WRITE_ODIRECT       Special case write for O_DIRECT only.
+ * WRITE_ODIRECT_PLUG  Special case write for O_DIRECT only.
  * SWRITE_SYNC
  * SWRITE_SYNC_PLUG    Like WRITE_SYNC/WRITE_SYNC_PLUG, but locks the buffer.
  *                     See SWRITE.
@@ -151,7 +151,7 @@ struct inodes_stat_t {
 #define READ_META      (READ | (1 << BIO_RW_META))
 #define WRITE_SYNC_PLUG        (WRITE | (1 << BIO_RW_SYNCIO) | (1 << BIO_RW_NOIDLE))
 #define WRITE_SYNC     (WRITE_SYNC_PLUG | (1 << BIO_RW_UNPLUG))
-#define WRITE_ODIRECT  (WRITE | (1 << BIO_RW_SYNCIO) | (1 << BIO_RW_UNPLUG))
+#define WRITE_ODIRECT_PLUG     (WRITE | (1 << BIO_RW_SYNCIO))
 #define SWRITE_SYNC_PLUG       \
                        (SWRITE | (1 << BIO_RW_SYNCIO) | (1 << BIO_RW_NOIDLE))
 #define SWRITE_SYNC    (SWRITE_SYNC_PLUG | (1 << BIO_RW_UNPLUG))
@@ -304,6 +304,7 @@ struct inodes_stat_t {
 #define BLKIOOPT _IO(0x12,121)
 #define BLKALIGNOFF _IO(0x12,122)
 #define BLKPBSZGET _IO(0x12,123)
+#define BLKDISCARDZEROES _IO(0x12,124)
 
 #define BMAP_IOCTL 1           /* obsolete - kept for compatibility */
 #define FIBMAP    _IO(0x00,1)  /* bmap access */
index 4ec5e67..47bbdf9 100644 (file)
@@ -117,12 +117,12 @@ struct ftrace_event_call {
        struct dentry           *dir;
        struct trace_event      *event;
        int                     enabled;
-       int                     (*regfunc)(void *);
-       void                    (*unregfunc)(void *);
+       int                     (*regfunc)(struct ftrace_event_call *);
+       void                    (*unregfunc)(struct ftrace_event_call *);
        int                     id;
-       int                     (*raw_init)(void);
-       int                     (*show_format)(struct ftrace_event_call *call,
-                                              struct trace_seq *s);
+       int                     (*raw_init)(struct ftrace_event_call *);
+       int                     (*show_format)(struct ftrace_event_call *,
+                                              struct trace_seq *);
        int                     (*define_fields)(struct ftrace_event_call *);
        struct list_head        fields;
        int                     filter_active;
@@ -131,20 +131,20 @@ struct ftrace_event_call {
        void                    *data;
 
        atomic_t                profile_count;
-       int                     (*profile_enable)(void);
-       void                    (*profile_disable)(void);
+       int                     (*profile_enable)(struct ftrace_event_call *);
+       void                    (*profile_disable)(struct ftrace_event_call *);
 };
 
 #define FTRACE_MAX_PROFILE_SIZE        2048
 
-extern char                    *trace_profile_buf;
-extern char                    *trace_profile_buf_nmi;
+extern char *perf_trace_buf;
+extern char *perf_trace_buf_nmi;
 
 #define MAX_FILTER_PRED                32
 #define MAX_FILTER_STR_VAL     256     /* Should handle KSYM_SYMBOL_LEN */
 
 extern void destroy_preds(struct ftrace_event_call *call);
-extern int filter_match_preds(struct ftrace_event_call *call, void *rec);
+extern int filter_match_preds(struct event_filter *filter, void *rec);
 extern int filter_current_check_discard(struct ring_buffer *buffer,
                                        struct ftrace_event_call *call,
                                        void *rec,
@@ -157,11 +157,12 @@ enum {
        FILTER_PTR_STRING,
 };
 
-extern int trace_define_field(struct ftrace_event_call *call,
-                             const char *type, const char *name,
-                             int offset, int size, int is_signed,
-                             int filter_type);
 extern int trace_define_common_fields(struct ftrace_event_call *call);
+extern int trace_define_field(struct ftrace_event_call *call, const char *type,
+                             const char *name, int offset, int size,
+                             int is_signed, int filter_type);
+extern int trace_add_event_call(struct ftrace_event_call *call);
+extern void trace_remove_event_call(struct ftrace_event_call *call);
 
 #define is_signed_type(type)   (((type)(-1)) < 0)
 
@@ -186,4 +187,13 @@ do {                                                                       \
                __trace_printk(ip, fmt, ##args);                        \
 } while (0)
 
+#ifdef CONFIG_EVENT_PROFILE
+struct perf_event;
+extern int ftrace_profile_enable(int event_id);
+extern void ftrace_profile_disable(int event_id);
+extern int ftrace_profile_set_filter(struct perf_event *event, int event_id,
+                                    char *filter_str);
+extern void ftrace_profile_free_filter(struct perf_event *event);
+#endif
+
 #endif /* _LINUX_FTRACE_EVENT_H */
index 297df45..c6c0c41 100644 (file)
@@ -91,6 +91,7 @@ struct hd_struct {
        sector_t start_sect;
        sector_t nr_sects;
        sector_t alignment_offset;
+       unsigned int discard_alignment;
        struct device __dev;
        struct kobject *holder_dir;
        int policy, partno;
diff --git a/include/linux/hw_breakpoint.h b/include/linux/hw_breakpoint.h
new file mode 100644 (file)
index 0000000..a03daed
--- /dev/null
@@ -0,0 +1,131 @@
+#ifndef _LINUX_HW_BREAKPOINT_H
+#define _LINUX_HW_BREAKPOINT_H
+
+enum {
+       HW_BREAKPOINT_LEN_1 = 1,
+       HW_BREAKPOINT_LEN_2 = 2,
+       HW_BREAKPOINT_LEN_4 = 4,
+       HW_BREAKPOINT_LEN_8 = 8,
+};
+
+enum {
+       HW_BREAKPOINT_R = 1,
+       HW_BREAKPOINT_W = 2,
+       HW_BREAKPOINT_X = 4,
+};
+
+#ifdef __KERNEL__
+
+#include <linux/perf_event.h>
+
+#ifdef CONFIG_HAVE_HW_BREAKPOINT
+
+/* As it's for in-kernel or ptrace use, we want it to be pinned */
+#define DEFINE_BREAKPOINT_ATTR(name)   \
+struct perf_event_attr name = {                \
+       .type = PERF_TYPE_BREAKPOINT,   \
+       .size = sizeof(name),           \
+       .pinned = 1,                    \
+};
+
+static inline void hw_breakpoint_init(struct perf_event_attr *attr)
+{
+       attr->type = PERF_TYPE_BREAKPOINT;
+       attr->size = sizeof(*attr);
+       attr->pinned = 1;
+}
+
+static inline unsigned long hw_breakpoint_addr(struct perf_event *bp)
+{
+       return bp->attr.bp_addr;
+}
+
+static inline int hw_breakpoint_type(struct perf_event *bp)
+{
+       return bp->attr.bp_type;
+}
+
+static inline int hw_breakpoint_len(struct perf_event *bp)
+{
+       return bp->attr.bp_len;
+}
+
+extern struct perf_event *
+register_user_hw_breakpoint(struct perf_event_attr *attr,
+                           perf_callback_t triggered,
+                           struct task_struct *tsk);
+
+/* FIXME: only change from the attr, and don't unregister */
+extern struct perf_event *
+modify_user_hw_breakpoint(struct perf_event *bp,
+                         struct perf_event_attr *attr,
+                         perf_callback_t triggered,
+                         struct task_struct *tsk);
+
+/*
+ * Kernel breakpoints are not associated with any particular thread.
+ */
+extern struct perf_event *
+register_wide_hw_breakpoint_cpu(struct perf_event_attr *attr,
+                               perf_callback_t triggered,
+                               int cpu);
+
+extern struct perf_event **
+register_wide_hw_breakpoint(struct perf_event_attr *attr,
+                           perf_callback_t triggered);
+
+extern int register_perf_hw_breakpoint(struct perf_event *bp);
+extern int __register_perf_hw_breakpoint(struct perf_event *bp);
+extern void unregister_hw_breakpoint(struct perf_event *bp);
+extern void unregister_wide_hw_breakpoint(struct perf_event **cpu_events);
+
+extern int reserve_bp_slot(struct perf_event *bp);
+extern void release_bp_slot(struct perf_event *bp);
+
+extern void flush_ptrace_hw_breakpoint(struct task_struct *tsk);
+
+static inline struct arch_hw_breakpoint *counter_arch_bp(struct perf_event *bp)
+{
+       return &bp->hw.info;
+}
+
+#else /* !CONFIG_HAVE_HW_BREAKPOINT */
+
+static inline struct perf_event *
+register_user_hw_breakpoint(struct perf_event_attr *attr,
+                           perf_callback_t triggered,
+                           struct task_struct *tsk)    { return NULL; }
+static inline struct perf_event *
+modify_user_hw_breakpoint(struct perf_event *bp,
+                         struct perf_event_attr *attr,
+                         perf_callback_t triggered,
+                         struct task_struct *tsk)      { return NULL; }
+static inline struct perf_event *
+register_wide_hw_breakpoint_cpu(struct perf_event_attr *attr,
+                               perf_callback_t triggered,
+                               int cpu)                { return NULL; }
+static inline struct perf_event **
+register_wide_hw_breakpoint(struct perf_event_attr *attr,
+                           perf_callback_t triggered)  { return NULL; }
+static inline int
+register_perf_hw_breakpoint(struct perf_event *bp)     { return -ENOSYS; }
+static inline int
+__register_perf_hw_breakpoint(struct perf_event *bp)   { return -ENOSYS; }
+static inline void unregister_hw_breakpoint(struct perf_event *bp)     { }
+static inline void
+unregister_wide_hw_breakpoint(struct perf_event **cpu_events)          { }
+static inline int
+reserve_bp_slot(struct perf_event *bp)                 {return -ENOSYS; }
+static inline void release_bp_slot(struct perf_event *bp)              { }
+
+static inline void flush_ptrace_hw_breakpoint(struct task_struct *tsk) { }
+
+static inline struct arch_hw_breakpoint *counter_arch_bp(struct perf_event *bp)
+{
+       return NULL;
+}
+
+#endif /* CONFIG_HAVE_HW_BREAKPOINT */
+#endif /* __KERNEL__ */
+
+#endif /* _LINUX_HW_BREAKPOINT_H */
index 7b40cda..419ab54 100644 (file)
@@ -110,7 +110,7 @@ extern s32 i2c_smbus_write_i2c_block_data(struct i2c_client *client,
  * @driver: Device driver model driver
  * @id_table: List of I2C devices supported by this driver
  * @detect: Callback for device detection
- * @address_data: The I2C addresses to probe, ignore or force (for detect)
+ * @address_data: The I2C addresses to probe (for detect)
  * @clients: List of detected clients we created (for i2c-core use only)
  *
  * The driver.owner field should be set to the module owner of this driver.
@@ -338,8 +338,7 @@ struct i2c_adapter {
        void *algo_data;
 
        /* data fields that are valid for all devices   */
-       u8 level;                       /* nesting level for lockdep */
-       struct mutex bus_lock;
+       struct rt_mutex bus_lock;
 
        int timeout;                    /* in jiffies */
        int retries;
@@ -367,7 +366,7 @@ static inline void i2c_set_adapdata(struct i2c_adapter *dev, void *data)
  */
 static inline void i2c_lock_adapter(struct i2c_adapter *adapter)
 {
-       mutex_lock(&adapter->bus_lock);
+       rt_mutex_lock(&adapter->bus_lock);
 }
 
 /**
@@ -376,7 +375,7 @@ static inline void i2c_lock_adapter(struct i2c_adapter *adapter)
  */
 static inline void i2c_unlock_adapter(struct i2c_adapter *adapter)
 {
-       mutex_unlock(&adapter->bus_lock);
+       rt_mutex_unlock(&adapter->bus_lock);
 }
 
 /*flags for the client struct: */
@@ -398,9 +397,6 @@ static inline void i2c_unlock_adapter(struct i2c_adapter *adapter)
  */
 struct i2c_client_address_data {
        const unsigned short *normal_i2c;
-       const unsigned short *probe;
-       const unsigned short *ignore;
-       const unsigned short * const *forces;
 };
 
 /* Internal numbers to terminate lists */
@@ -614,134 +610,48 @@ union i2c_smbus_data {
   module_param_array(var, short, &var##_num, 0); \
   MODULE_PARM_DESC(var, desc)
 
-#define I2C_CLIENT_MODULE_PARM_FORCE(name)                             \
-I2C_CLIENT_MODULE_PARM(force_##name,                                   \
-                      "List of adapter,address pairs which are "       \
-                      "unquestionably assumed to contain a `"          \
-                      # name "' chip")
-
-
 #define I2C_CLIENT_INSMOD_COMMON                                       \
-I2C_CLIENT_MODULE_PARM(probe, "List of adapter,address pairs to scan " \
-                      "additionally");                                 \
-I2C_CLIENT_MODULE_PARM(ignore, "List of adapter,address pairs not to " \
-                      "scan");                                         \
 static const struct i2c_client_address_data addr_data = {              \
        .normal_i2c     = normal_i2c,                                   \
-       .probe          = probe,                                        \
-       .ignore         = ignore,                                       \
-       .forces         = forces,                                       \
 }
 
-#define I2C_CLIENT_FORCE_TEXT \
-       "List of adapter,address pairs to boldly assume to be present"
-
 /* These are the ones you want to use in your own drivers. Pick the one
    which matches the number of devices the driver differenciates between. */
 #define I2C_CLIENT_INSMOD                                              \
-I2C_CLIENT_MODULE_PARM(force, I2C_CLIENT_FORCE_TEXT);                  \
-static const unsigned short * const forces[] = { force, NULL };                \
 I2C_CLIENT_INSMOD_COMMON
 
 #define I2C_CLIENT_INSMOD_1(chip1)                                     \
 enum chips { any_chip, chip1 };                                                \
-I2C_CLIENT_MODULE_PARM(force, I2C_CLIENT_FORCE_TEXT);                  \
-I2C_CLIENT_MODULE_PARM_FORCE(chip1);                                   \
-static const unsigned short * const forces[] = { force,                \
-       force_##chip1, NULL };                                          \
 I2C_CLIENT_INSMOD_COMMON
 
 #define I2C_CLIENT_INSMOD_2(chip1, chip2)                              \
 enum chips { any_chip, chip1, chip2 };                                 \
-I2C_CLIENT_MODULE_PARM(force, I2C_CLIENT_FORCE_TEXT);                  \
-I2C_CLIENT_MODULE_PARM_FORCE(chip1);                                   \
-I2C_CLIENT_MODULE_PARM_FORCE(chip2);                                   \
-static const unsigned short * const forces[] = { force,                \
-       force_##chip1, force_##chip2, NULL };                           \
 I2C_CLIENT_INSMOD_COMMON
 
 #define I2C_CLIENT_INSMOD_3(chip1, chip2, chip3)                       \
 enum chips { any_chip, chip1, chip2, chip3 };                          \
-I2C_CLIENT_MODULE_PARM(force, I2C_CLIENT_FORCE_TEXT);                  \
-I2C_CLIENT_MODULE_PARM_FORCE(chip1);                                   \
-I2C_CLIENT_MODULE_PARM_FORCE(chip2);                                   \
-I2C_CLIENT_MODULE_PARM_FORCE(chip3);                                   \
-static const unsigned short * const forces[] = { force,                \
-       force_##chip1, force_##chip2, force_##chip3, NULL };            \
 I2C_CLIENT_INSMOD_COMMON
 
 #define I2C_CLIENT_INSMOD_4(chip1, chip2, chip3, chip4)                        \
 enum chips { any_chip, chip1, chip2, chip3, chip4 };                   \
-I2C_CLIENT_MODULE_PARM(force, I2C_CLIENT_FORCE_TEXT);                  \
-I2C_CLIENT_MODULE_PARM_FORCE(chip1);                                   \
-I2C_CLIENT_MODULE_PARM_FORCE(chip2);                                   \
-I2C_CLIENT_MODULE_PARM_FORCE(chip3);                                   \
-I2C_CLIENT_MODULE_PARM_FORCE(chip4);                                   \
-static const unsigned short * const forces[] = { force,                \
-       force_##chip1, force_##chip2, force_##chip3,                    \
-       force_##chip4, NULL};                                           \
 I2C_CLIENT_INSMOD_COMMON
 
 #define I2C_CLIENT_INSMOD_5(chip1, chip2, chip3, chip4, chip5)         \
 enum chips { any_chip, chip1, chip2, chip3, chip4, chip5 };            \
-I2C_CLIENT_MODULE_PARM(force, I2C_CLIENT_FORCE_TEXT);                  \
-I2C_CLIENT_MODULE_PARM_FORCE(chip1);                                   \
-I2C_CLIENT_MODULE_PARM_FORCE(chip2);                                   \
-I2C_CLIENT_MODULE_PARM_FORCE(chip3);                                   \
-I2C_CLIENT_MODULE_PARM_FORCE(chip4);                                   \
-I2C_CLIENT_MODULE_PARM_FORCE(chip5);                                   \
-static const unsigned short * const forces[] = { force,                        \
-       force_##chip1, force_##chip2, force_##chip3,                    \
-       force_##chip4, force_##chip5, NULL };                           \
 I2C_CLIENT_INSMOD_COMMON
 
 #define I2C_CLIENT_INSMOD_6(chip1, chip2, chip3, chip4, chip5, chip6)  \
 enum chips { any_chip, chip1, chip2, chip3, chip4, chip5, chip6 };     \
-I2C_CLIENT_MODULE_PARM(force, I2C_CLIENT_FORCE_TEXT);                  \
-I2C_CLIENT_MODULE_PARM_FORCE(chip1);                                   \
-I2C_CLIENT_MODULE_PARM_FORCE(chip2);                                   \
-I2C_CLIENT_MODULE_PARM_FORCE(chip3);                                   \
-I2C_CLIENT_MODULE_PARM_FORCE(chip4);                                   \
-I2C_CLIENT_MODULE_PARM_FORCE(chip5);                                   \
-I2C_CLIENT_MODULE_PARM_FORCE(chip6);                                   \
-static const unsigned short * const forces[] = { force,                        \
-       force_##chip1, force_##chip2, force_##chip3,                    \
-       force_##chip4, force_##chip5, force_##chip6, NULL };            \
 I2C_CLIENT_INSMOD_COMMON
 
 #define I2C_CLIENT_INSMOD_7(chip1, chip2, chip3, chip4, chip5, chip6, chip7) \
 enum chips { any_chip, chip1, chip2, chip3, chip4, chip5, chip6,       \
             chip7 };                                                   \
-I2C_CLIENT_MODULE_PARM(force, I2C_CLIENT_FORCE_TEXT);                  \
-I2C_CLIENT_MODULE_PARM_FORCE(chip1);                                   \
-I2C_CLIENT_MODULE_PARM_FORCE(chip2);                                   \
-I2C_CLIENT_MODULE_PARM_FORCE(chip3);                                   \
-I2C_CLIENT_MODULE_PARM_FORCE(chip4);                                   \
-I2C_CLIENT_MODULE_PARM_FORCE(chip5);                                   \
-I2C_CLIENT_MODULE_PARM_FORCE(chip6);                                   \
-I2C_CLIENT_MODULE_PARM_FORCE(chip7);                                   \
-static const unsigned short * const forces[] = { force,                        \
-       force_##chip1, force_##chip2, force_##chip3,                    \
-       force_##chip4, force_##chip5, force_##chip6,                    \
-       force_##chip7, NULL };                                          \
 I2C_CLIENT_INSMOD_COMMON
 
 #define I2C_CLIENT_INSMOD_8(chip1, chip2, chip3, chip4, chip5, chip6, chip7, chip8) \
 enum chips { any_chip, chip1, chip2, chip3, chip4, chip5, chip6,       \
             chip7, chip8 };                                            \
-I2C_CLIENT_MODULE_PARM(force, I2C_CLIENT_FORCE_TEXT);                  \
-I2C_CLIENT_MODULE_PARM_FORCE(chip1);                                   \
-I2C_CLIENT_MODULE_PARM_FORCE(chip2);                                   \
-I2C_CLIENT_MODULE_PARM_FORCE(chip3);                                   \
-I2C_CLIENT_MODULE_PARM_FORCE(chip4);                                   \
-I2C_CLIENT_MODULE_PARM_FORCE(chip5);                                   \
-I2C_CLIENT_MODULE_PARM_FORCE(chip6);                                   \
-I2C_CLIENT_MODULE_PARM_FORCE(chip7);                                   \
-I2C_CLIENT_MODULE_PARM_FORCE(chip8);                                   \
-static const unsigned short * const forces[] = { force,                        \
-       force_##chip1, force_##chip2, force_##chip3,                    \
-       force_##chip4, force_##chip5, force_##chip6,                    \
-       force_##chip7, force_##chip8, NULL };                           \
 I2C_CLIENT_INSMOD_COMMON
 #endif /* __KERNEL__ */
 #endif /* _LINUX_I2C_H */
index 508824e..5306a75 100644 (file)
@@ -401,6 +401,24 @@ struct twl4030_power_data {
 
 extern void twl4030_power_init(struct twl4030_power_data *triton2_scripts);
 
+struct twl4030_codec_audio_data {
+       unsigned int    audio_mclk;
+       unsigned int ramp_delay_value;
+       unsigned int hs_extmute:1;
+       void (*set_hs_extmute)(int mute);
+};
+
+struct twl4030_codec_vibra_data {
+       unsigned int    audio_mclk;
+       unsigned int    coexist;
+};
+
+struct twl4030_codec_data {
+       unsigned int    audio_mclk;
+       struct twl4030_codec_audio_data         *audio;
+       struct twl4030_codec_vibra_data         *vibra;
+};
+
 struct twl4030_platform_data {
        unsigned                                irq_base, irq_end;
        struct twl4030_bci_platform_data        *bci;
@@ -409,6 +427,7 @@ struct twl4030_platform_data {
        struct twl4030_keypad_data              *keypad;
        struct twl4030_usb_data                 *usb;
        struct twl4030_power_data               *power;
+       struct twl4030_codec_data               *codec;
 
        /* LDO regulators */
        struct regulator_init_data              *vdac;
index c2b1a7d..84b501a 100644 (file)
@@ -595,6 +595,8 @@ struct input_absinfo {
 #define KEY_NUMERIC_STAR       0x20a
 #define KEY_NUMERIC_POUND      0x20b
 
+#define KEY_CAMERA_FOCUS       0x210
+
 /* We avoid low common keys in module aliases so they don't get huge. */
 #define KEY_MIN_INTERESTING    KEY_MUTE
 #define KEY_MAX                        0x2ff
@@ -677,6 +679,9 @@ struct input_absinfo {
 #define SW_LINEOUT_INSERT      0x06  /* set = inserted */
 #define SW_JACK_PHYSICAL_INSERT 0x07  /* set = mechanical switch set */
 #define SW_VIDEOOUT_INSERT     0x08  /* set = inserted */
+#define SW_CAMERA_LENS_COVER   0x09  /* set = lens covered */
+#define SW_KEYPAD_SLIDE                0x0a  /* set = keypad slide out */
+#define SW_FRONT_PROXIMITY     0x0b  /* set = front proximity sensor active */
 #define SW_MAX                 0x0f
 #define SW_CNT                 (SW_MAX+1)
 
index 4da4a75..a632359 100644 (file)
@@ -40,16 +40,11 @@ struct cfq_io_context {
        struct io_context *ioc;
 
        unsigned long last_end_request;
-       sector_t last_request_pos;
 
        unsigned long ttime_total;
        unsigned long ttime_samples;
        unsigned long ttime_mean;
 
-       unsigned int seek_samples;
-       u64 seek_total;
-       sector_t seek_mean;
-
        struct list_head queue_list;
        struct hlist_node cic_list;
 
@@ -73,6 +68,10 @@ struct io_context {
        unsigned short ioprio;
        unsigned short ioprio_changed;
 
+#ifdef CONFIG_BLK_CGROUP
+       unsigned short cgroup_changed;
+#endif
+
        /*
         * For request batching
         */
@@ -99,14 +98,15 @@ static inline struct io_context *ioc_task_link(struct io_context *ioc)
        return NULL;
 }
 
+struct task_struct;
 #ifdef CONFIG_BLOCK
 int put_io_context(struct io_context *ioc);
-void exit_io_context(void);
+void exit_io_context(struct task_struct *task);
 struct io_context *get_io_context(gfp_t gfp_flags, int node);
 struct io_context *alloc_io_context(gfp_t gfp_flags, int node);
 void copy_io_context(struct io_context **pdst, struct io_context **psrc);
 #else
-static inline void exit_io_context(void)
+static inline void exit_io_context(struct task_struct *task)
 {
 }
 
index 1a9cf78..6811f4b 100644 (file)
@@ -307,6 +307,7 @@ extern clock_t jiffies_to_clock_t(long x);
 extern unsigned long clock_t_to_jiffies(unsigned long x);
 extern u64 jiffies_64_to_clock_t(u64 x);
 extern u64 nsec_to_clock_t(u64 x);
+extern unsigned long nsecs_to_jiffies(u64 n);
 
 #define TIMESTAMP_SIZE 30
 
index 348fa88..c059044 100644 (file)
@@ -25,6 +25,7 @@ struct cpu_usage_stat {
        cputime64_t iowait;
        cputime64_t steal;
        cputime64_t guest;
+       cputime64_t guest_nice;
 };
 
 struct kernel_stat {
index 3a46b7b..1b672f7 100644 (file)
@@ -296,6 +296,8 @@ void recycle_rp_inst(struct kretprobe_instance *ri, struct hlist_head *head);
 int disable_kprobe(struct kprobe *kp);
 int enable_kprobe(struct kprobe *kp);
 
+void dump_kprobe(struct kprobe *kp);
+
 #else /* !CONFIG_KPROBES: */
 
 static inline int kprobes_built_in(void)
index f8f8900..2d241da 100644 (file)
 
 #define KVM_API_VERSION 12
 
-/* for KVM_TRACE_ENABLE, deprecated */
+/* *** Deprecated interfaces *** */
+
+#define KVM_TRC_SHIFT           16
+
+#define KVM_TRC_ENTRYEXIT       (1 << KVM_TRC_SHIFT)
+#define KVM_TRC_HANDLER         (1 << (KVM_TRC_SHIFT + 1))
+
+#define KVM_TRC_VMENTRY         (KVM_TRC_ENTRYEXIT + 0x01)
+#define KVM_TRC_VMEXIT          (KVM_TRC_ENTRYEXIT + 0x02)
+#define KVM_TRC_PAGE_FAULT      (KVM_TRC_HANDLER + 0x01)
+
+#define KVM_TRC_HEAD_SIZE       12
+#define KVM_TRC_CYCLE_SIZE      8
+#define KVM_TRC_EXTRA_MAX       7
+
+#define KVM_TRC_INJ_VIRQ         (KVM_TRC_HANDLER + 0x02)
+#define KVM_TRC_REDELIVER_EVT    (KVM_TRC_HANDLER + 0x03)
+#define KVM_TRC_PEND_INTR        (KVM_TRC_HANDLER + 0x04)
+#define KVM_TRC_IO_READ          (KVM_TRC_HANDLER + 0x05)
+#define KVM_TRC_IO_WRITE         (KVM_TRC_HANDLER + 0x06)
+#define KVM_TRC_CR_READ          (KVM_TRC_HANDLER + 0x07)
+#define KVM_TRC_CR_WRITE         (KVM_TRC_HANDLER + 0x08)
+#define KVM_TRC_DR_READ          (KVM_TRC_HANDLER + 0x09)
+#define KVM_TRC_DR_WRITE         (KVM_TRC_HANDLER + 0x0A)
+#define KVM_TRC_MSR_READ         (KVM_TRC_HANDLER + 0x0B)
+#define KVM_TRC_MSR_WRITE        (KVM_TRC_HANDLER + 0x0C)
+#define KVM_TRC_CPUID            (KVM_TRC_HANDLER + 0x0D)
+#define KVM_TRC_INTR             (KVM_TRC_HANDLER + 0x0E)
+#define KVM_TRC_NMI              (KVM_TRC_HANDLER + 0x0F)
+#define KVM_TRC_VMMCALL          (KVM_TRC_HANDLER + 0x10)
+#define KVM_TRC_HLT              (KVM_TRC_HANDLER + 0x11)
+#define KVM_TRC_CLTS             (KVM_TRC_HANDLER + 0x12)
+#define KVM_TRC_LMSW             (KVM_TRC_HANDLER + 0x13)
+#define KVM_TRC_APIC_ACCESS      (KVM_TRC_HANDLER + 0x14)
+#define KVM_TRC_TDP_FAULT        (KVM_TRC_HANDLER + 0x15)
+#define KVM_TRC_GTLB_WRITE       (KVM_TRC_HANDLER + 0x16)
+#define KVM_TRC_STLB_WRITE       (KVM_TRC_HANDLER + 0x17)
+#define KVM_TRC_STLB_INVAL       (KVM_TRC_HANDLER + 0x18)
+#define KVM_TRC_PPC_INSTR        (KVM_TRC_HANDLER + 0x19)
+
 struct kvm_user_trace_setup {
-       __u32 buf_size; /* sub_buffer size of each per-cpu */
-       __u32 buf_nr; /* the number of sub_buffers of each per-cpu */
+       __u32 buf_size;
+       __u32 buf_nr;
+};
+
+#define __KVM_DEPRECATED_MAIN_W_0x06 \
+       _IOW(KVMIO, 0x06, struct kvm_user_trace_setup)
+#define __KVM_DEPRECATED_MAIN_0x07 _IO(KVMIO, 0x07)
+#define __KVM_DEPRECATED_MAIN_0x08 _IO(KVMIO, 0x08)
+
+#define __KVM_DEPRECATED_VM_R_0x70 _IOR(KVMIO, 0x70, struct kvm_assigned_irq)
+
+struct kvm_breakpoint {
+       __u32 enabled;
+       __u32 padding;
+       __u64 address;
+};
+
+struct kvm_debug_guest {
+       __u32 enabled;
+       __u32 pad;
+       struct kvm_breakpoint breakpoints[4];
+       __u32 singlestep;
 };
 
+#define __KVM_DEPRECATED_VCPU_W_0x87 _IOW(KVMIO, 0x87, struct kvm_debug_guest)
+
+/* *** End of deprecated interfaces *** */
+
+
 /* for KVM_CREATE_MEMORY_REGION */
 struct kvm_memory_region {
        __u32 slot;
@@ -99,6 +163,7 @@ struct kvm_pit_config {
 
 /* For KVM_EXIT_INTERNAL_ERROR */
 #define KVM_INTERNAL_ERROR_EMULATION 1
+#define KVM_INTERNAL_ERROR_SIMUL_EX 2
 
 /* for KVM_RUN, returned by mmap(vcpu_fd, offset=0) */
 struct kvm_run {
@@ -116,6 +181,11 @@ struct kvm_run {
        __u64 cr8;
        __u64 apic_base;
 
+#ifdef __KVM_S390
+       /* the processor status word for s390 */
+       __u64 psw_mask; /* psw upper half */
+       __u64 psw_addr; /* psw lower half */
+#endif
        union {
                /* KVM_EXIT_UNKNOWN */
                struct {
@@ -167,8 +237,6 @@ struct kvm_run {
                /* KVM_EXIT_S390_SIEIC */
                struct {
                        __u8 icptcode;
-                       __u64 mask; /* psw upper half */
-                       __u64 addr; /* psw lower half */
                        __u16 ipa;
                        __u32 ipb;
                } s390_sieic;
@@ -187,6 +255,9 @@ struct kvm_run {
                } dcr;
                struct {
                        __u32 suberror;
+                       /* Available with KVM_CAP_INTERNAL_ERROR_DATA: */
+                       __u32 ndata;
+                       __u64 data[16];
                } internal;
                /* Fix the size of the union. */
                char padding[256];
@@ -329,24 +400,6 @@ struct kvm_ioeventfd {
        __u8  pad[36];
 };
 
-#define KVM_TRC_SHIFT           16
-/*
- * kvm trace categories
- */
-#define KVM_TRC_ENTRYEXIT       (1 << KVM_TRC_SHIFT)
-#define KVM_TRC_HANDLER         (1 << (KVM_TRC_SHIFT + 1)) /* only 12 bits */
-
-/*
- * kvm trace action
- */
-#define KVM_TRC_VMENTRY         (KVM_TRC_ENTRYEXIT + 0x01)
-#define KVM_TRC_VMEXIT          (KVM_TRC_ENTRYEXIT + 0x02)
-#define KVM_TRC_PAGE_FAULT      (KVM_TRC_HANDLER + 0x01)
-
-#define KVM_TRC_HEAD_SIZE       12
-#define KVM_TRC_CYCLE_SIZE      8
-#define KVM_TRC_EXTRA_MAX       7
-
 #define KVMIO 0xAE
 
 /*
@@ -367,12 +420,10 @@ struct kvm_ioeventfd {
  */
 #define KVM_GET_VCPU_MMAP_SIZE    _IO(KVMIO,   0x04) /* in bytes */
 #define KVM_GET_SUPPORTED_CPUID   _IOWR(KVMIO, 0x05, struct kvm_cpuid2)
-/*
- * ioctls for kvm trace
- */
-#define KVM_TRACE_ENABLE          _IOW(KVMIO, 0x06, struct kvm_user_trace_setup)
-#define KVM_TRACE_PAUSE           _IO(KVMIO,  0x07)
-#define KVM_TRACE_DISABLE         _IO(KVMIO,  0x08)
+#define KVM_TRACE_ENABLE          __KVM_DEPRECATED_MAIN_W_0x06
+#define KVM_TRACE_PAUSE           __KVM_DEPRECATED_MAIN_0x07
+#define KVM_TRACE_DISABLE         __KVM_DEPRECATED_MAIN_0x08
+
 /*
  * Extension capability list.
  */
@@ -436,6 +487,15 @@ struct kvm_ioeventfd {
 #endif
 #define KVM_CAP_IOEVENTFD 36
 #define KVM_CAP_SET_IDENTITY_MAP_ADDR 37
+#ifdef __KVM_HAVE_XEN_HVM
+#define KVM_CAP_XEN_HVM 38
+#endif
+#define KVM_CAP_ADJUST_CLOCK 39
+#define KVM_CAP_INTERNAL_ERROR_DATA 40
+#ifdef __KVM_HAVE_VCPU_EVENTS
+#define KVM_CAP_VCPU_EVENTS 41
+#endif
+#define KVM_CAP_S390_PSW 42
 
 #ifdef KVM_CAP_IRQ_ROUTING
 
@@ -488,6 +548,18 @@ struct kvm_x86_mce {
 };
 #endif
 
+#ifdef KVM_CAP_XEN_HVM
+struct kvm_xen_hvm_config {
+       __u32 flags;
+       __u32 msr;
+       __u64 blob_addr_32;
+       __u64 blob_addr_64;
+       __u8 blob_size_32;
+       __u8 blob_size_64;
+       __u8 pad2[30];
+};
+#endif
+
 #define KVM_IRQFD_FLAG_DEASSIGN (1 << 0)
 
 struct kvm_irqfd {
@@ -497,55 +569,66 @@ struct kvm_irqfd {
        __u8  pad[20];
 };
 
+struct kvm_clock_data {
+       __u64 clock;
+       __u32 flags;
+       __u32 pad[9];
+};
+
 /*
  * ioctls for VM fds
  */
-#define KVM_SET_MEMORY_REGION     _IOW(KVMIO, 0x40, struct kvm_memory_region)
+#define KVM_SET_MEMORY_REGION     _IOW(KVMIO,  0x40, struct kvm_memory_region)
 /*
  * KVM_CREATE_VCPU receives as a parameter the vcpu slot, and returns
  * a vcpu fd.
  */
-#define KVM_CREATE_VCPU           _IO(KVMIO,  0x41)
-#define KVM_GET_DIRTY_LOG         _IOW(KVMIO, 0x42, struct kvm_dirty_log)
-#define KVM_SET_MEMORY_ALIAS      _IOW(KVMIO, 0x43, struct kvm_memory_alias)
-#define KVM_SET_NR_MMU_PAGES      _IO(KVMIO, 0x44)
-#define KVM_GET_NR_MMU_PAGES      _IO(KVMIO, 0x45)
-#define KVM_SET_USER_MEMORY_REGION _IOW(KVMIO, 0x46,\
+#define KVM_CREATE_VCPU           _IO(KVMIO,   0x41)
+#define KVM_GET_DIRTY_LOG         _IOW(KVMIO,  0x42, struct kvm_dirty_log)
+#define KVM_SET_MEMORY_ALIAS      _IOW(KVMIO,  0x43, struct kvm_memory_alias)
+#define KVM_SET_NR_MMU_PAGES      _IO(KVMIO,   0x44)
+#define KVM_GET_NR_MMU_PAGES      _IO(KVMIO,   0x45)
+#define KVM_SET_USER_MEMORY_REGION _IOW(KVMIO, 0x46, \
                                        struct kvm_userspace_memory_region)
-#define KVM_SET_TSS_ADDR          _IO(KVMIO, 0x47)
-#define KVM_SET_IDENTITY_MAP_ADDR _IOW(KVMIO, 0x48, __u64)
+#define KVM_SET_TSS_ADDR          _IO(KVMIO,   0x47)
+#define KVM_SET_IDENTITY_MAP_ADDR _IOW(KVMIO,  0x48, __u64)
 /* Device model IOC */
-#define KVM_CREATE_IRQCHIP       _IO(KVMIO,  0x60)
-#define KVM_IRQ_LINE             _IOW(KVMIO, 0x61, struct kvm_irq_level)
-#define KVM_GET_IRQCHIP                  _IOWR(KVMIO, 0x62, struct kvm_irqchip)
-#define KVM_SET_IRQCHIP                  _IOR(KVMIO,  0x63, struct kvm_irqchip)
-#define KVM_CREATE_PIT           _IO(KVMIO,  0x64)
-#define KVM_GET_PIT              _IOWR(KVMIO, 0x65, struct kvm_pit_state)
-#define KVM_SET_PIT              _IOR(KVMIO,  0x66, struct kvm_pit_state)
-#define KVM_IRQ_LINE_STATUS      _IOWR(KVMIO, 0x67, struct kvm_irq_level)
+#define KVM_CREATE_IRQCHIP        _IO(KVMIO,   0x60)
+#define KVM_IRQ_LINE              _IOW(KVMIO,  0x61, struct kvm_irq_level)
+#define KVM_GET_IRQCHIP           _IOWR(KVMIO, 0x62, struct kvm_irqchip)
+#define KVM_SET_IRQCHIP           _IOR(KVMIO,  0x63, struct kvm_irqchip)
+#define KVM_CREATE_PIT            _IO(KVMIO,   0x64)
+#define KVM_GET_PIT               _IOWR(KVMIO, 0x65, struct kvm_pit_state)
+#define KVM_SET_PIT               _IOR(KVMIO,  0x66, struct kvm_pit_state)
+#define KVM_IRQ_LINE_STATUS       _IOWR(KVMIO, 0x67, struct kvm_irq_level)
 #define KVM_REGISTER_COALESCED_MMIO \
                        _IOW(KVMIO,  0x67, struct kvm_coalesced_mmio_zone)
 #define KVM_UNREGISTER_COALESCED_MMIO \
                        _IOW(KVMIO,  0x68, struct kvm_coalesced_mmio_zone)
-#define KVM_ASSIGN_PCI_DEVICE _IOR(KVMIO, 0x69, \
-                                  struct kvm_assigned_pci_dev)
-#define KVM_SET_GSI_ROUTING       _IOW(KVMIO, 0x6a, struct kvm_irq_routing)
+#define KVM_ASSIGN_PCI_DEVICE     _IOR(KVMIO,  0x69, \
+                                      struct kvm_assigned_pci_dev)
+#define KVM_SET_GSI_ROUTING       _IOW(KVMIO,  0x6a, struct kvm_irq_routing)
 /* deprecated, replaced by KVM_ASSIGN_DEV_IRQ */
-#define KVM_ASSIGN_IRQ _IOR(KVMIO, 0x70, \
-                           struct kvm_assigned_irq)
-#define KVM_ASSIGN_DEV_IRQ        _IOW(KVMIO, 0x70, struct kvm_assigned_irq)
-#define KVM_REINJECT_CONTROL      _IO(KVMIO, 0x71)
-#define KVM_DEASSIGN_PCI_DEVICE _IOW(KVMIO, 0x72, \
-                                    struct kvm_assigned_pci_dev)
-#define KVM_ASSIGN_SET_MSIX_NR \
-                       _IOW(KVMIO, 0x73, struct kvm_assigned_msix_nr)
-#define KVM_ASSIGN_SET_MSIX_ENTRY \
-                       _IOW(KVMIO, 0x74, struct kvm_assigned_msix_entry)
-#define KVM_DEASSIGN_DEV_IRQ       _IOW(KVMIO, 0x75, struct kvm_assigned_irq)
-#define KVM_IRQFD                  _IOW(KVMIO, 0x76, struct kvm_irqfd)
-#define KVM_CREATE_PIT2                   _IOW(KVMIO, 0x77, struct kvm_pit_config)
-#define KVM_SET_BOOT_CPU_ID        _IO(KVMIO, 0x78)
-#define KVM_IOEVENTFD             _IOW(KVMIO, 0x79, struct kvm_ioeventfd)
+#define KVM_ASSIGN_IRQ            __KVM_DEPRECATED_VM_R_0x70
+#define KVM_ASSIGN_DEV_IRQ        _IOW(KVMIO,  0x70, struct kvm_assigned_irq)
+#define KVM_REINJECT_CONTROL      _IO(KVMIO,   0x71)
+#define KVM_DEASSIGN_PCI_DEVICE   _IOW(KVMIO,  0x72, \
+                                      struct kvm_assigned_pci_dev)
+#define KVM_ASSIGN_SET_MSIX_NR    _IOW(KVMIO,  0x73, \
+                                      struct kvm_assigned_msix_nr)
+#define KVM_ASSIGN_SET_MSIX_ENTRY _IOW(KVMIO,  0x74, \
+                                      struct kvm_assigned_msix_entry)
+#define KVM_DEASSIGN_DEV_IRQ      _IOW(KVMIO,  0x75, struct kvm_assigned_irq)
+#define KVM_IRQFD                 _IOW(KVMIO,  0x76, struct kvm_irqfd)
+#define KVM_CREATE_PIT2                  _IOW(KVMIO,  0x77, struct kvm_pit_config)
+#define KVM_SET_BOOT_CPU_ID       _IO(KVMIO,   0x78)
+#define KVM_IOEVENTFD             _IOW(KVMIO,  0x79, struct kvm_ioeventfd)
+#define KVM_XEN_HVM_CONFIG        _IOW(KVMIO,  0x7a, struct kvm_xen_hvm_config)
+#define KVM_SET_CLOCK             _IOW(KVMIO,  0x7b, struct kvm_clock_data)
+#define KVM_GET_CLOCK             _IOR(KVMIO,  0x7c, struct kvm_clock_data)
+/* Available with KVM_CAP_PIT_STATE2 */
+#define KVM_GET_PIT2              _IOR(KVMIO,  0x9f, struct kvm_pit_state2)
+#define KVM_SET_PIT2              _IOW(KVMIO,  0xa0, struct kvm_pit_state2)
 
 /*
  * ioctls for vcpu fds
@@ -558,7 +641,7 @@ struct kvm_irqfd {
 #define KVM_TRANSLATE             _IOWR(KVMIO, 0x85, struct kvm_translation)
 #define KVM_INTERRUPT             _IOW(KVMIO,  0x86, struct kvm_interrupt)
 /* KVM_DEBUG_GUEST is no longer supported, use KVM_SET_GUEST_DEBUG instead */
-#define KVM_DEBUG_GUEST           __KVM_DEPRECATED_DEBUG_GUEST
+#define KVM_DEBUG_GUEST           __KVM_DEPRECATED_VCPU_W_0x87
 #define KVM_GET_MSRS              _IOWR(KVMIO, 0x88, struct kvm_msrs)
 #define KVM_SET_MSRS              _IOW(KVMIO,  0x89, struct kvm_msrs)
 #define KVM_SET_CPUID             _IOW(KVMIO,  0x8a, struct kvm_cpuid)
@@ -570,7 +653,7 @@ struct kvm_irqfd {
 #define KVM_SET_CPUID2            _IOW(KVMIO,  0x90, struct kvm_cpuid2)
 #define KVM_GET_CPUID2            _IOWR(KVMIO, 0x91, struct kvm_cpuid2)
 /* Available with KVM_CAP_VAPIC */
-#define KVM_TPR_ACCESS_REPORTING  _IOWR(KVMIO,  0x92, struct kvm_tpr_access_ctl)
+#define KVM_TPR_ACCESS_REPORTING  _IOWR(KVMIO, 0x92, struct kvm_tpr_access_ctl)
 /* Available with KVM_CAP_VAPIC */
 #define KVM_SET_VAPIC_ADDR        _IOW(KVMIO,  0x93, struct kvm_vapic_addr)
 /* valid for virtual machine (for floating interrupt)_and_ vcpu */
@@ -582,66 +665,23 @@ struct kvm_irqfd {
 /* initial ipl psw for s390 */
 #define KVM_S390_SET_INITIAL_PSW  _IOW(KVMIO,  0x96, struct kvm_s390_psw)
 /* initial reset for s390 */
-#define KVM_S390_INITIAL_RESET    _IO(KVMIO,  0x97)
+#define KVM_S390_INITIAL_RESET    _IO(KVMIO,   0x97)
 #define KVM_GET_MP_STATE          _IOR(KVMIO,  0x98, struct kvm_mp_state)
 #define KVM_SET_MP_STATE          _IOW(KVMIO,  0x99, struct kvm_mp_state)
 /* Available with KVM_CAP_NMI */
-#define KVM_NMI                   _IO(KVMIO,  0x9a)
+#define KVM_NMI                   _IO(KVMIO,   0x9a)
 /* Available with KVM_CAP_SET_GUEST_DEBUG */
 #define KVM_SET_GUEST_DEBUG       _IOW(KVMIO,  0x9b, struct kvm_guest_debug)
 /* MCE for x86 */
 #define KVM_X86_SETUP_MCE         _IOW(KVMIO,  0x9c, __u64)
 #define KVM_X86_GET_MCE_CAP_SUPPORTED _IOR(KVMIO,  0x9d, __u64)
 #define KVM_X86_SET_MCE           _IOW(KVMIO,  0x9e, struct kvm_x86_mce)
-
-/*
- * Deprecated interfaces
- */
-struct kvm_breakpoint {
-       __u32 enabled;
-       __u32 padding;
-       __u64 address;
-};
-
-struct kvm_debug_guest {
-       __u32 enabled;
-       __u32 pad;
-       struct kvm_breakpoint breakpoints[4];
-       __u32 singlestep;
-};
-
-#define __KVM_DEPRECATED_DEBUG_GUEST _IOW(KVMIO,  0x87, struct kvm_debug_guest)
-
+/* IA64 stack access */
 #define KVM_IA64_VCPU_GET_STACK   _IOR(KVMIO,  0x9a, void *)
 #define KVM_IA64_VCPU_SET_STACK   _IOW(KVMIO,  0x9b, void *)
-
-#define KVM_GET_PIT2   _IOR(KVMIO,   0x9f, struct kvm_pit_state2)
-#define KVM_SET_PIT2   _IOW(KVMIO,   0xa0, struct kvm_pit_state2)
-
-#define KVM_TRC_INJ_VIRQ         (KVM_TRC_HANDLER + 0x02)
-#define KVM_TRC_REDELIVER_EVT    (KVM_TRC_HANDLER + 0x03)
-#define KVM_TRC_PEND_INTR        (KVM_TRC_HANDLER + 0x04)
-#define KVM_TRC_IO_READ          (KVM_TRC_HANDLER + 0x05)
-#define KVM_TRC_IO_WRITE         (KVM_TRC_HANDLER + 0x06)
-#define KVM_TRC_CR_READ          (KVM_TRC_HANDLER + 0x07)
-#define KVM_TRC_CR_WRITE         (KVM_TRC_HANDLER + 0x08)
-#define KVM_TRC_DR_READ          (KVM_TRC_HANDLER + 0x09)
-#define KVM_TRC_DR_WRITE         (KVM_TRC_HANDLER + 0x0A)
-#define KVM_TRC_MSR_READ         (KVM_TRC_HANDLER + 0x0B)
-#define KVM_TRC_MSR_WRITE        (KVM_TRC_HANDLER + 0x0C)
-#define KVM_TRC_CPUID            (KVM_TRC_HANDLER + 0x0D)
-#define KVM_TRC_INTR             (KVM_TRC_HANDLER + 0x0E)
-#define KVM_TRC_NMI              (KVM_TRC_HANDLER + 0x0F)
-#define KVM_TRC_VMMCALL          (KVM_TRC_HANDLER + 0x10)
-#define KVM_TRC_HLT              (KVM_TRC_HANDLER + 0x11)
-#define KVM_TRC_CLTS             (KVM_TRC_HANDLER + 0x12)
-#define KVM_TRC_LMSW             (KVM_TRC_HANDLER + 0x13)
-#define KVM_TRC_APIC_ACCESS      (KVM_TRC_HANDLER + 0x14)
-#define KVM_TRC_TDP_FAULT        (KVM_TRC_HANDLER + 0x15)
-#define KVM_TRC_GTLB_WRITE       (KVM_TRC_HANDLER + 0x16)
-#define KVM_TRC_STLB_WRITE       (KVM_TRC_HANDLER + 0x17)
-#define KVM_TRC_STLB_INVAL       (KVM_TRC_HANDLER + 0x18)
-#define KVM_TRC_PPC_INSTR        (KVM_TRC_HANDLER + 0x19)
+/* Available with KVM_CAP_VCPU_EVENTS */
+#define KVM_GET_VCPU_EVENTS       _IOR(KVMIO,  0x9f, struct kvm_vcpu_events)
+#define KVM_SET_VCPU_EVENTS       _IOW(KVMIO,  0xa0, struct kvm_vcpu_events)
 
 #define KVM_DEV_ASSIGN_ENABLE_IOMMU    (1 << 0)
 
@@ -696,4 +736,4 @@ struct kvm_assigned_msix_entry {
        __u16 padding[3];
 };
 
-#endif
+#endif /* __LINUX_KVM_H */
index b7bbb5d..bd5a616 100644 (file)
@@ -120,7 +120,7 @@ struct kvm_kernel_irq_routing_entry {
        u32 gsi;
        u32 type;
        int (*set)(struct kvm_kernel_irq_routing_entry *e,
-                   struct kvm *kvm, int level);
+                  struct kvm *kvm, int irq_source_id, int level);
        union {
                struct {
                        unsigned irqchip;
@@ -128,9 +128,28 @@ struct kvm_kernel_irq_routing_entry {
                } irqchip;
                struct msi_msg msi;
        };
-       struct list_head link;
+       struct hlist_node link;
+};
+
+#ifdef __KVM_HAVE_IOAPIC
+
+struct kvm_irq_routing_table {
+       int chip[KVM_NR_IRQCHIPS][KVM_IOAPIC_NUM_PINS];
+       struct kvm_kernel_irq_routing_entry *rt_entries;
+       u32 nr_rt_entries;
+       /*
+        * Array indexed by gsi. Each entry contains list of irq chips
+        * the gsi is connected to.
+        */
+       struct hlist_head map[0];
 };
 
+#else
+
+struct kvm_irq_routing_table {};
+
+#endif
+
 struct kvm {
        spinlock_t mmu_lock;
        spinlock_t requests_lock;
@@ -166,8 +185,9 @@ struct kvm {
 
        struct mutex irq_lock;
 #ifdef CONFIG_HAVE_KVM_IRQCHIP
-       struct list_head irq_routing; /* of kvm_kernel_irq_routing_entry */
+       struct kvm_irq_routing_table *irq_routing;
        struct hlist_head mask_notifier_list;
+       struct hlist_head irq_ack_notifier_list;
 #endif
 
 #ifdef KVM_ARCH_WANT_MMU_NOTIFIER
@@ -266,6 +286,7 @@ int kvm_is_visible_gfn(struct kvm *kvm, gfn_t gfn);
 void mark_page_dirty(struct kvm *kvm, gfn_t gfn);
 
 void kvm_vcpu_block(struct kvm_vcpu *vcpu);
+void kvm_vcpu_on_spin(struct kvm_vcpu *vcpu);
 void kvm_resched(struct kvm_vcpu *vcpu);
 void kvm_load_guest_fpu(struct kvm_vcpu *vcpu);
 void kvm_put_guest_fpu(struct kvm_vcpu *vcpu);
@@ -325,7 +346,7 @@ int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu);
 void kvm_arch_vcpu_destroy(struct kvm_vcpu *vcpu);
 
 int kvm_arch_vcpu_reset(struct kvm_vcpu *vcpu);
-void kvm_arch_hardware_enable(void *garbage);
+int kvm_arch_hardware_enable(void *garbage);
 void kvm_arch_hardware_disable(void *garbage);
 int kvm_arch_hardware_setup(void);
 void kvm_arch_hardware_unsetup(void);
@@ -390,7 +411,12 @@ void kvm_unregister_irq_mask_notifier(struct kvm *kvm, int irq,
                                      struct kvm_irq_mask_notifier *kimn);
 void kvm_fire_mask_notifiers(struct kvm *kvm, int irq, bool mask);
 
-int kvm_set_irq(struct kvm *kvm, int irq_source_id, int irq, int level);
+#ifdef __KVM_HAVE_IOAPIC
+void kvm_get_intr_delivery_bitmask(struct kvm_ioapic *ioapic,
+                                  union kvm_ioapic_redirect_entry *entry,
+                                  unsigned long *deliver_bitmask);
+#endif
+int kvm_set_irq(struct kvm *kvm, int irq_source_id, u32 irq, int level);
 void kvm_notify_acked_irq(struct kvm *kvm, unsigned irqchip, unsigned pin);
 void kvm_register_irq_ack_notifier(struct kvm *kvm,
                                   struct kvm_irq_ack_notifier *kian);
@@ -552,4 +578,21 @@ static inline bool kvm_vcpu_is_bsp(struct kvm_vcpu *vcpu)
        return vcpu->kvm->bsp_vcpu_id == vcpu->vcpu_id;
 }
 #endif
+
+#ifdef __KVM_HAVE_DEVICE_ASSIGNMENT
+
+long kvm_vm_ioctl_assigned_device(struct kvm *kvm, unsigned ioctl,
+                                 unsigned long arg);
+
+#else
+
+static inline long kvm_vm_ioctl_assigned_device(struct kvm *kvm, unsigned ioctl,
+                                               unsigned long arg)
+{
+       return -ENOTTY;
+}
+
 #endif
+
+#endif
+
index 8769864..a5b3dc7 100644 (file)
@@ -365,7 +365,7 @@ enum {
        /* This should match the actual table size of
         * ata_eh_cmd_timeout_table in libata-eh.c.
         */
-       ATA_EH_CMD_TIMEOUT_TABLE_SIZE = 5,
+       ATA_EH_CMD_TIMEOUT_TABLE_SIZE = 6,
 
        /* Horkage types. May be set by libata or controller on drives
           (some horkage may be drive/controller pair dependant */
@@ -595,6 +595,7 @@ struct ata_device {
        unsigned int            horkage;        /* List of broken features */
        unsigned long           flags;          /* ATA_DFLAG_xxx */
        struct scsi_device      *sdev;          /* attached SCSI device */
+       void                    *private_data;
 #ifdef CONFIG_ATA_ACPI
        acpi_handle             acpi_handle;
        union acpi_object       *gtf_cache;
diff --git a/include/linux/lru_cache.h b/include/linux/lru_cache.h
new file mode 100644 (file)
index 0000000..3a2b2d9
--- /dev/null
@@ -0,0 +1,294 @@
+/*
+   lru_cache.c
+
+   This file is part of DRBD by Philipp Reisner and Lars Ellenberg.
+
+   Copyright (C) 2003-2008, LINBIT Information Technologies GmbH.
+   Copyright (C) 2003-2008, Philipp Reisner <philipp.reisner@linbit.com>.
+   Copyright (C) 2003-2008, Lars Ellenberg <lars.ellenberg@linbit.com>.
+
+   drbd is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   drbd 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 drbd; see the file COPYING.  If not, write to
+   the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ */
+
+#ifndef LRU_CACHE_H
+#define LRU_CACHE_H
+
+#include <linux/list.h>
+#include <linux/slab.h>
+#include <linux/bitops.h>
+#include <linux/string.h> /* for memset */
+#include <linux/seq_file.h>
+
+/*
+This header file (and its .c file; kernel-doc of functions see there)
+  define a helper framework to easily keep track of index:label associations,
+  and changes to an "active set" of objects, as well as pending transactions,
+  to persistently record those changes.
+
+  We use an LRU policy if it is necessary to "cool down" a region currently in
+  the active set before we can "heat" a previously unused region.
+
+  Because of this later property, it is called "lru_cache".
+  As it actually Tracks Objects in an Active SeT, we could also call it
+  toast (incidentally that is what may happen to the data on the
+  backend storage uppon next resync, if we don't get it right).
+
+What for?
+
+We replicate IO (more or less synchronously) to local and remote disk.
+
+For crash recovery after replication node failure,
+  we need to resync all regions that have been target of in-flight WRITE IO
+  (in use, or "hot", regions), as we don't know wether or not those WRITEs have
+  made it to stable storage.
+
+  To avoid a "full resync", we need to persistently track these regions.
+
+  This is known as "write intent log", and can be implemented as on-disk
+  (coarse or fine grained) bitmap, or other meta data.
+
+  To avoid the overhead of frequent extra writes to this meta data area,
+  usually the condition is softened to regions that _may_ have been target of
+  in-flight WRITE IO, e.g. by only lazily clearing the on-disk write-intent
+  bitmap, trading frequency of meta data transactions against amount of
+  (possibly unneccessary) resync traffic.
+
+  If we set a hard limit on the area that may be "hot" at any given time, we
+  limit the amount of resync traffic needed for crash recovery.
+
+For recovery after replication link failure,
+  we need to resync all blocks that have been changed on the other replica
+  in the mean time, or, if both replica have been changed independently [*],
+  all blocks that have been changed on either replica in the mean time.
+  [*] usually as a result of a cluster split-brain and insufficient protection.
+      but there are valid use cases to do this on purpose.
+
+  Tracking those blocks can be implemented as "dirty bitmap".
+  Having it fine-grained reduces the amount of resync traffic.
+  It should also be persistent, to allow for reboots (or crashes)
+  while the replication link is down.
+
+There are various possible implementations for persistently storing
+write intent log information, three of which are mentioned here.
+
+"Chunk dirtying"
+  The on-disk "dirty bitmap" may be re-used as "write-intent" bitmap as well.
+  To reduce the frequency of bitmap updates for write-intent log purposes,
+  one could dirty "chunks" (of some size) at a time of the (fine grained)
+  on-disk bitmap, while keeping the in-memory "dirty" bitmap as clean as
+  possible, flushing it to disk again when a previously "hot" (and on-disk
+  dirtied as full chunk) area "cools down" again (no IO in flight anymore,
+  and none expected in the near future either).
+
+"Explicit (coarse) write intent bitmap"
+  An other implementation could chose a (probably coarse) explicit bitmap,
+  for write-intent log purposes, additionally to the fine grained dirty bitmap.
+
+"Activity log"
+  Yet an other implementation may keep track of the hot regions, by starting
+  with an empty set, and writing down a journal of region numbers that have
+  become "hot", or have "cooled down" again.
+
+  To be able to use a ring buffer for this journal of changes to the active
+  set, we not only record the actual changes to that set, but also record the
+  not changing members of the set in a round robin fashion. To do so, we use a
+  fixed (but configurable) number of slots which we can identify by index, and
+  associate region numbers (labels) with these indices.
+  For each transaction recording a change to the active set, we record the
+  change itself (index: -old_label, +new_label), and which index is associated
+  with which label (index: current_label) within a certain sliding window that
+  is moved further over the available indices with each such transaction.
+
+  Thus, for crash recovery, if the ringbuffer is sufficiently large, we can
+  accurately reconstruct the active set.
+
+  Sufficiently large depends only on maximum number of active objects, and the
+  size of the sliding window recording "index: current_label" associations within
+  each transaction.
+
+  This is what we call the "activity log".
+
+  Currently we need one activity log transaction per single label change, which
+  does not give much benefit over the "dirty chunks of bitmap" approach, other
+  than potentially less seeks.
+
+  We plan to change the transaction format to support multiple changes per
+  transaction, which then would reduce several (disjoint, "random") updates to
+  the bitmap into one transaction to the activity log ring buffer.
+*/
+
+/* this defines an element in a tracked set
+ * .colision is for hash table lookup.
+ * When we process a new IO request, we know its sector, thus can deduce the
+ * region number (label) easily.  To do the label -> object lookup without a
+ * full list walk, we use a simple hash table.
+ *
+ * .list is on one of three lists:
+ *  in_use: currently in use (refcnt > 0, lc_number != LC_FREE)
+ *     lru: unused but ready to be reused or recycled
+ *          (ts_refcnt == 0, lc_number != LC_FREE),
+ *    free: unused but ready to be recycled
+ *          (ts_refcnt == 0, lc_number == LC_FREE),
+ *
+ * an element is said to be "in the active set",
+ * if either on "in_use" or "lru", i.e. lc_number != LC_FREE.
+ *
+ * DRBD currently (May 2009) only uses 61 elements on the resync lru_cache
+ * (total memory usage 2 pages), and up to 3833 elements on the act_log
+ * lru_cache, totalling ~215 kB for 64bit architechture, ~53 pages.
+ *
+ * We usually do not actually free these objects again, but only "recycle"
+ * them, as the change "index: -old_label, +LC_FREE" would need a transaction
+ * as well.  Which also means that using a kmem_cache to allocate the objects
+ * from wastes some resources.
+ * But it avoids high order page allocations in kmalloc.
+ */
+struct lc_element {
+       struct hlist_node colision;
+       struct list_head list;           /* LRU list or free list */
+       unsigned refcnt;
+       /* back "pointer" into ts_cache->element[index],
+        * for paranoia, and for "ts_element_to_index" */
+       unsigned lc_index;
+       /* if we want to track a larger set of objects,
+        * it needs to become arch independend u64 */
+       unsigned lc_number;
+
+       /* special label when on free list */
+#define LC_FREE (~0U)
+};
+
+struct lru_cache {
+       /* the least recently used item is kept at lru->prev */
+       struct list_head lru;
+       struct list_head free;
+       struct list_head in_use;
+
+       /* the pre-created kmem cache to allocate the objects from */
+       struct kmem_cache *lc_cache;
+
+       /* size of tracked objects, used to memset(,0,) them in lc_reset */
+       size_t element_size;
+       /* offset of struct lc_element member in the tracked object */
+       size_t element_off;
+
+       /* number of elements (indices) */
+       unsigned int  nr_elements;
+       /* Arbitrary limit on maximum tracked objects. Practical limit is much
+        * lower due to allocation failures, probably. For typical use cases,
+        * nr_elements should be a few thousand at most.
+        * This also limits the maximum value of ts_element.ts_index, allowing the
+        * 8 high bits of .ts_index to be overloaded with flags in the future. */
+#define LC_MAX_ACTIVE  (1<<24)
+
+       /* statistics */
+       unsigned used; /* number of lelements currently on in_use list */
+       unsigned long hits, misses, starving, dirty, changed;
+
+       /* see below: flag-bits for lru_cache */
+       unsigned long flags;
+
+       /* when changing the label of an index element */
+       unsigned int  new_number;
+
+       /* for paranoia when changing the label of an index element */
+       struct lc_element *changing_element;
+
+       void  *lc_private;
+       const char *name;
+
+       /* nr_elements there */
+       struct hlist_head *lc_slot;
+       struct lc_element **lc_element;
+};
+
+
+/* flag-bits for lru_cache */
+enum {
+       /* debugging aid, to catch concurrent access early.
+        * user needs to guarantee exclusive access by proper locking! */
+       __LC_PARANOIA,
+       /* if we need to change the set, but currently there is a changing
+        * transaction pending, we are "dirty", and must deferr further
+        * changing requests */
+       __LC_DIRTY,
+       /* if we need to change the set, but currently there is no free nor
+        * unused element available, we are "starving", and must not give out
+        * further references, to guarantee that eventually some refcnt will
+        * drop to zero and we will be able to make progress again, changing
+        * the set, writing the transaction.
+        * if the statistics say we are frequently starving,
+        * nr_elements is too small. */
+       __LC_STARVING,
+};
+#define LC_PARANOIA (1<<__LC_PARANOIA)
+#define LC_DIRTY    (1<<__LC_DIRTY)
+#define LC_STARVING (1<<__LC_STARVING)
+
+extern struct lru_cache *lc_create(const char *name, struct kmem_cache *cache,
+               unsigned e_count, size_t e_size, size_t e_off);
+extern void lc_reset(struct lru_cache *lc);
+extern void lc_destroy(struct lru_cache *lc);
+extern void lc_set(struct lru_cache *lc, unsigned int enr, int index);
+extern void lc_del(struct lru_cache *lc, struct lc_element *element);
+
+extern struct lc_element *lc_try_get(struct lru_cache *lc, unsigned int enr);
+extern struct lc_element *lc_find(struct lru_cache *lc, unsigned int enr);
+extern struct lc_element *lc_get(struct lru_cache *lc, unsigned int enr);
+extern unsigned int lc_put(struct lru_cache *lc, struct lc_element *e);
+extern void lc_changed(struct lru_cache *lc, struct lc_element *e);
+
+struct seq_file;
+extern size_t lc_seq_printf_stats(struct seq_file *seq, struct lru_cache *lc);
+
+extern void lc_seq_dump_details(struct seq_file *seq, struct lru_cache *lc, char *utext,
+                               void (*detail) (struct seq_file *, struct lc_element *));
+
+/**
+ * lc_try_lock - can be used to stop lc_get() from changing the tracked set
+ * @lc: the lru cache to operate on
+ *
+ * Note that the reference counts and order on the active and lru lists may
+ * still change.  Returns true if we aquired the lock.
+ */
+static inline int lc_try_lock(struct lru_cache *lc)
+{
+       return !test_and_set_bit(__LC_DIRTY, &lc->flags);
+}
+
+/**
+ * lc_unlock - unlock @lc, allow lc_get() to change the set again
+ * @lc: the lru cache to operate on
+ */
+static inline void lc_unlock(struct lru_cache *lc)
+{
+       clear_bit(__LC_DIRTY, &lc->flags);
+       smp_mb__after_clear_bit();
+}
+
+static inline int lc_is_used(struct lru_cache *lc, unsigned int enr)
+{
+       struct lc_element *e = lc_find(lc, enr);
+       return e && e->refcnt;
+}
+
+#define lc_entry(ptr, type, member) \
+       container_of(ptr, type, member)
+
+extern struct lc_element *lc_element_by_index(struct lru_cache *lc, unsigned i);
+extern unsigned int lc_index_of(struct lru_cache *lc, struct lc_element *e);
+
+#endif
index c63b65c..0aa3a1a 100644 (file)
@@ -96,6 +96,10 @@ struct da9034_touch_pdata {
        int     y_inverted;
 };
 
+struct da9034_backlight_pdata {
+       int     output_current; /* output current of WLED, from 0-31 (in mA) */
+};
+
 /* DA9030 battery charger data */
 struct power_supply_info;
 
similarity index 97%
rename from drivers/mfd/mcp.h
rename to include/linux/mfd/mcp.h
index c093a93..ee49670 100644 (file)
@@ -10,6 +10,8 @@
 #ifndef MCP_H
 #define MCP_H
 
+#include <mach/dma.h>
+
 struct mcp_ops;
 
 struct mcp {
@@ -24,6 +26,7 @@ struct mcp {
        dma_device_t    dma_telco_rd;
        dma_device_t    dma_telco_wr;
        struct device   attached_device;
+       int             gpio_base;
 };
 
 struct mcp_ops {
diff --git a/include/linux/mfd/twl4030-codec.h b/include/linux/mfd/twl4030-codec.h
new file mode 100644 (file)
index 0000000..2ec317c
--- /dev/null
@@ -0,0 +1,272 @@
+/*
+ * MFD driver for twl4030 codec submodule
+ *
+ * Author:     Peter Ujfalusi <peter.ujfalusi@nokia.com>
+ *
+ * Copyright:   (C) 2009 Nokia Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __TWL4030_CODEC_H__
+#define __TWL4030_CODEC_H__
+
+/* Codec registers */
+#define TWL4030_REG_CODEC_MODE         0x01
+#define TWL4030_REG_OPTION             0x02
+#define TWL4030_REG_UNKNOWN            0x03
+#define TWL4030_REG_MICBIAS_CTL                0x04
+#define TWL4030_REG_ANAMICL            0x05
+#define TWL4030_REG_ANAMICR            0x06
+#define TWL4030_REG_AVADC_CTL          0x07
+#define TWL4030_REG_ADCMICSEL          0x08
+#define TWL4030_REG_DIGMIXING          0x09
+#define TWL4030_REG_ATXL1PGA           0x0A
+#define TWL4030_REG_ATXR1PGA           0x0B
+#define TWL4030_REG_AVTXL2PGA          0x0C
+#define TWL4030_REG_AVTXR2PGA          0x0D
+#define TWL4030_REG_AUDIO_IF           0x0E
+#define TWL4030_REG_VOICE_IF           0x0F
+#define TWL4030_REG_ARXR1PGA           0x10
+#define TWL4030_REG_ARXL1PGA           0x11
+#define TWL4030_REG_ARXR2PGA           0x12
+#define TWL4030_REG_ARXL2PGA           0x13
+#define TWL4030_REG_VRXPGA             0x14
+#define TWL4030_REG_VSTPGA             0x15
+#define TWL4030_REG_VRX2ARXPGA         0x16
+#define TWL4030_REG_AVDAC_CTL          0x17
+#define TWL4030_REG_ARX2VTXPGA         0x18
+#define TWL4030_REG_ARXL1_APGA_CTL     0x19
+#define TWL4030_REG_ARXR1_APGA_CTL     0x1A
+#define TWL4030_REG_ARXL2_APGA_CTL     0x1B
+#define TWL4030_REG_ARXR2_APGA_CTL     0x1C
+#define TWL4030_REG_ATX2ARXPGA         0x1D
+#define TWL4030_REG_BT_IF              0x1E
+#define TWL4030_REG_BTPGA              0x1F
+#define TWL4030_REG_BTSTPGA            0x20
+#define TWL4030_REG_EAR_CTL            0x21
+#define TWL4030_REG_HS_SEL             0x22
+#define TWL4030_REG_HS_GAIN_SET                0x23
+#define TWL4030_REG_HS_POPN_SET                0x24
+#define TWL4030_REG_PREDL_CTL          0x25
+#define TWL4030_REG_PREDR_CTL          0x26
+#define TWL4030_REG_PRECKL_CTL         0x27
+#define TWL4030_REG_PRECKR_CTL         0x28
+#define TWL4030_REG_HFL_CTL            0x29
+#define TWL4030_REG_HFR_CTL            0x2A
+#define TWL4030_REG_ALC_CTL            0x2B
+#define TWL4030_REG_ALC_SET1           0x2C
+#define TWL4030_REG_ALC_SET2           0x2D
+#define TWL4030_REG_BOOST_CTL          0x2E
+#define TWL4030_REG_SOFTVOL_CTL                0x2F
+#define TWL4030_REG_DTMF_FREQSEL       0x30
+#define TWL4030_REG_DTMF_TONEXT1H      0x31
+#define TWL4030_REG_DTMF_TONEXT1L      0x32
+#define TWL4030_REG_DTMF_TONEXT2H      0x33
+#define TWL4030_REG_DTMF_TONEXT2L      0x34
+#define TWL4030_REG_DTMF_TONOFF                0x35
+#define TWL4030_REG_DTMF_WANONOFF      0x36
+#define TWL4030_REG_I2S_RX_SCRAMBLE_H  0x37
+#define TWL4030_REG_I2S_RX_SCRAMBLE_M  0x38
+#define TWL4030_REG_I2S_RX_SCRAMBLE_L  0x39
+#define TWL4030_REG_APLL_CTL           0x3A
+#define TWL4030_REG_DTMF_CTL           0x3B
+#define TWL4030_REG_DTMF_PGA_CTL2      0x3C
+#define TWL4030_REG_DTMF_PGA_CTL1      0x3D
+#define TWL4030_REG_MISC_SET_1         0x3E
+#define TWL4030_REG_PCMBTMUX           0x3F
+#define TWL4030_REG_RX_PATH_SEL                0x43
+#define TWL4030_REG_VDL_APGA_CTL       0x44
+#define TWL4030_REG_VIBRA_CTL          0x45
+#define TWL4030_REG_VIBRA_SET          0x46
+#define TWL4030_REG_VIBRA_PWM_SET      0x47
+#define TWL4030_REG_ANAMIC_GAIN                0x48
+#define TWL4030_REG_MISC_SET_2         0x49
+
+/* Bitfield Definitions */
+
+/* TWL4030_CODEC_MODE (0x01) Fields */
+#define TWL4030_APLL_RATE              0xF0
+#define TWL4030_APLL_RATE_8000         0x00
+#define TWL4030_APLL_RATE_11025                0x10
+#define TWL4030_APLL_RATE_12000                0x20
+#define TWL4030_APLL_RATE_16000                0x40
+#define TWL4030_APLL_RATE_22050                0x50
+#define TWL4030_APLL_RATE_24000                0x60
+#define TWL4030_APLL_RATE_32000                0x80
+#define TWL4030_APLL_RATE_44100                0x90
+#define TWL4030_APLL_RATE_48000                0xA0
+#define TWL4030_APLL_RATE_96000                0xE0
+#define TWL4030_SEL_16K                        0x08
+#define TWL4030_CODECPDZ               0x02
+#define TWL4030_OPT_MODE               0x01
+#define TWL4030_OPTION_1               (1 << 0)
+#define TWL4030_OPTION_2               (0 << 0)
+
+/* TWL4030_OPTION (0x02) Fields */
+#define TWL4030_ATXL1_EN               (1 << 0)
+#define TWL4030_ATXR1_EN               (1 << 1)
+#define TWL4030_ATXL2_VTXL_EN          (1 << 2)
+#define TWL4030_ATXR2_VTXR_EN          (1 << 3)
+#define TWL4030_ARXL1_VRX_EN           (1 << 4)
+#define TWL4030_ARXR1_EN               (1 << 5)
+#define TWL4030_ARXL2_EN               (1 << 6)
+#define TWL4030_ARXR2_EN               (1 << 7)
+
+/* TWL4030_REG_MICBIAS_CTL (0x04) Fields */
+#define TWL4030_MICBIAS2_CTL           0x40
+#define TWL4030_MICBIAS1_CTL           0x20
+#define TWL4030_HSMICBIAS_EN           0x04
+#define TWL4030_MICBIAS2_EN            0x02
+#define TWL4030_MICBIAS1_EN            0x01
+
+/* ANAMICL (0x05) Fields */
+#define TWL4030_CNCL_OFFSET_START      0x80
+#define TWL4030_OFFSET_CNCL_SEL                0x60
+#define TWL4030_OFFSET_CNCL_SEL_ARX1   0x00
+#define TWL4030_OFFSET_CNCL_SEL_ARX2   0x20
+#define TWL4030_OFFSET_CNCL_SEL_VRX    0x40
+#define TWL4030_OFFSET_CNCL_SEL_ALL    0x60
+#define TWL4030_MICAMPL_EN             0x10
+#define TWL4030_CKMIC_EN               0x08
+#define TWL4030_AUXL_EN                        0x04
+#define TWL4030_HSMIC_EN               0x02
+#define TWL4030_MAINMIC_EN             0x01
+
+/* ANAMICR (0x06) Fields */
+#define TWL4030_MICAMPR_EN             0x10
+#define TWL4030_AUXR_EN                        0x04
+#define TWL4030_SUBMIC_EN              0x01
+
+/* AVADC_CTL (0x07) Fields */
+#define TWL4030_ADCL_EN                        0x08
+#define TWL4030_AVADC_CLK_PRIORITY     0x04
+#define TWL4030_ADCR_EN                        0x02
+
+/* TWL4030_REG_ADCMICSEL (0x08) Fields */
+#define TWL4030_DIGMIC1_EN             0x08
+#define TWL4030_TX2IN_SEL              0x04
+#define TWL4030_DIGMIC0_EN             0x02
+#define TWL4030_TX1IN_SEL              0x01
+
+/* AUDIO_IF (0x0E) Fields */
+#define TWL4030_AIF_SLAVE_EN           0x80
+#define TWL4030_DATA_WIDTH             0x60
+#define TWL4030_DATA_WIDTH_16S_16W     0x00
+#define TWL4030_DATA_WIDTH_32S_16W     0x40
+#define TWL4030_DATA_WIDTH_32S_24W     0x60
+#define TWL4030_AIF_FORMAT             0x18
+#define TWL4030_AIF_FORMAT_CODEC       0x00
+#define TWL4030_AIF_FORMAT_LEFT                0x08
+#define TWL4030_AIF_FORMAT_RIGHT       0x10
+#define TWL4030_AIF_FORMAT_TDM         0x18
+#define TWL4030_AIF_TRI_EN             0x04
+#define TWL4030_CLK256FS_EN            0x02
+#define TWL4030_AIF_EN                 0x01
+
+/* VOICE_IF (0x0F) Fields */
+#define TWL4030_VIF_SLAVE_EN           0x80
+#define TWL4030_VIF_DIN_EN             0x40
+#define TWL4030_VIF_DOUT_EN            0x20
+#define TWL4030_VIF_SWAP               0x10
+#define TWL4030_VIF_FORMAT             0x08
+#define TWL4030_VIF_TRI_EN             0x04
+#define TWL4030_VIF_SUB_EN             0x02
+#define TWL4030_VIF_EN                 0x01
+
+/* EAR_CTL (0x21) */
+#define TWL4030_EAR_GAIN               0x30
+
+/* HS_GAIN_SET (0x23) Fields */
+#define TWL4030_HSR_GAIN               0x0C
+#define TWL4030_HSR_GAIN_PWR_DOWN      0x00
+#define TWL4030_HSR_GAIN_PLUS_6DB      0x04
+#define TWL4030_HSR_GAIN_0DB           0x08
+#define TWL4030_HSR_GAIN_MINUS_6DB     0x0C
+#define TWL4030_HSL_GAIN               0x03
+#define TWL4030_HSL_GAIN_PWR_DOWN      0x00
+#define TWL4030_HSL_GAIN_PLUS_6DB      0x01
+#define TWL4030_HSL_GAIN_0DB           0x02
+#define TWL4030_HSL_GAIN_MINUS_6DB     0x03
+
+/* HS_POPN_SET (0x24) Fields */
+#define TWL4030_VMID_EN                        0x40
+#define        TWL4030_EXTMUTE                 0x20
+#define TWL4030_RAMP_DELAY             0x1C
+#define TWL4030_RAMP_DELAY_20MS                0x00
+#define TWL4030_RAMP_DELAY_40MS                0x04
+#define TWL4030_RAMP_DELAY_81MS                0x08
+#define TWL4030_RAMP_DELAY_161MS       0x0C
+#define TWL4030_RAMP_DELAY_323MS       0x10
+#define TWL4030_RAMP_DELAY_645MS       0x14
+#define TWL4030_RAMP_DELAY_1291MS      0x18
+#define TWL4030_RAMP_DELAY_2581MS      0x1C
+#define TWL4030_RAMP_EN                        0x02
+
+/* PREDL_CTL (0x25) */
+#define TWL4030_PREDL_GAIN             0x30
+
+/* PREDR_CTL (0x26) */
+#define TWL4030_PREDR_GAIN             0x30
+
+/* PRECKL_CTL (0x27) */
+#define TWL4030_PRECKL_GAIN            0x30
+
+/* PRECKR_CTL (0x28) */
+#define TWL4030_PRECKR_GAIN            0x30
+
+/* HFL_CTL (0x29, 0x2A) Fields */
+#define TWL4030_HF_CTL_HB_EN           0x04
+#define TWL4030_HF_CTL_LOOP_EN         0x08
+#define TWL4030_HF_CTL_RAMP_EN         0x10
+#define TWL4030_HF_CTL_REF_EN          0x20
+
+/* APLL_CTL (0x3A) Fields */
+#define TWL4030_APLL_EN                        0x10
+#define TWL4030_APLL_INFREQ            0x0F
+#define TWL4030_APLL_INFREQ_19200KHZ   0x05
+#define TWL4030_APLL_INFREQ_26000KHZ   0x06
+#define TWL4030_APLL_INFREQ_38400KHZ   0x0F
+
+/* REG_MISC_SET_1 (0x3E) Fields */
+#define TWL4030_CLK64_EN               0x80
+#define TWL4030_SCRAMBLE_EN            0x40
+#define TWL4030_FMLOOP_EN              0x20
+#define TWL4030_SMOOTH_ANAVOL_EN       0x02
+#define TWL4030_DIGMIC_LR_SWAP_EN      0x01
+
+/* VIBRA_CTL (0x45) */
+#define TWL4030_VIBRA_EN               0x01
+#define TWL4030_VIBRA_DIR              0x02
+#define TWL4030_VIBRA_AUDIO_SEL_L1     (0x00 << 2)
+#define TWL4030_VIBRA_AUDIO_SEL_R1     (0x01 << 2)
+#define TWL4030_VIBRA_AUDIO_SEL_L2     (0x02 << 2)
+#define TWL4030_VIBRA_AUDIO_SEL_R2     (0x03 << 2)
+#define TWL4030_VIBRA_SEL              0x10
+#define TWL4030_VIBRA_DIR_SEL          0x20
+
+/* TWL4030 codec resource IDs */
+enum twl4030_codec_res {
+       TWL4030_CODEC_RES_POWER = 0,
+       TWL4030_CODEC_RES_APLL,
+       TWL4030_CODEC_RES_MAX,
+};
+
+int twl4030_codec_disable_resource(enum twl4030_codec_res id);
+int twl4030_codec_enable_resource(enum twl4030_codec_res id);
+unsigned int twl4030_codec_get_mclk(void);
+
+#endif /* End of __TWL4030_CODEC_H__ */
similarity index 98%
rename from drivers/mfd/ucb1x00.h
rename to include/linux/mfd/ucb1x00.h
index a8ad8a0..aa9c378 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  linux/drivers/mfd/ucb1x00.h
+ *  linux/include/mfd/ucb1x00.h
  *
  *  Copyright (C) 2001 Russell King, All Rights Reserved.
  *
@@ -10,6 +10,9 @@
 #ifndef UCB1200_H
 #define UCB1200_H
 
+#include <linux/mfd/mcp.h>
+#include <linux/gpio.h>
+
 #define UCB_IO_DATA    0x00
 #define UCB_IO_DIR     0x01
 
 #define UCB_MODE_DYN_VFLAG_ENA (1 << 12)
 #define UCB_MODE_AUD_OFF_CAN   (1 << 13)
 
-#include "mcp.h"
 
 struct ucb1x00_irq {
        void *devid;
@@ -123,6 +125,7 @@ struct ucb1x00 {
        struct device           dev;
        struct list_head        node;
        struct list_head        devs;
+       struct gpio_chip        gpio;
 };
 
 struct ucb1x00_driver;
index 7be2d10..e7facd8 100644 (file)
  */
 #include <linux/types.h>
 #include <linux/bitops.h>
+#include <linux/kref.h>
 #include <linux/mod_devicetable.h>
 
+typedef u32 phandle;
+typedef u32 ihandle;
+
+struct property {
+       char    *name;
+       int     length;
+       void    *value;
+       struct property *next;
+       unsigned long _flags;
+       unsigned int unique_id;
+};
+
+#if defined(CONFIG_SPARC)
+struct of_irq_controller;
+#endif
+
+struct device_node {
+       const char *name;
+       const char *type;
+       phandle node;
+#if !defined(CONFIG_SPARC)
+       phandle linux_phandle;
+#endif
+       char    *full_name;
+
+       struct  property *properties;
+       struct  property *deadprops;    /* removed properties */
+       struct  device_node *parent;
+       struct  device_node *child;
+       struct  device_node *sibling;
+       struct  device_node *next;      /* next device of same type */
+       struct  device_node *allnext;   /* next in list of all nodes */
+       struct  proc_dir_entry *pde;    /* this node's proc directory */
+       struct  kref kref;
+       unsigned long _flags;
+       void    *data;
+#if defined(CONFIG_SPARC)
+       char    *path_component_name;
+       unsigned int unique_id;
+       struct of_irq_controller *irq_trans;
+#endif
+};
+
+static inline int of_node_check_flag(struct device_node *n, unsigned long flag)
+{
+       return test_bit(flag, &n->_flags);
+}
+
+static inline void of_node_set_flag(struct device_node *n, unsigned long flag)
+{
+       set_bit(flag, &n->_flags);
+}
+
+static inline void
+set_node_proc_entry(struct device_node *dn, struct proc_dir_entry *de)
+{
+       dn->pde = de;
+}
+
+extern struct device_node *of_find_all_nodes(struct device_node *prev);
+
+#if defined(CONFIG_SPARC)
+/* Dummy ref counting routines - to be implemented later */
+static inline struct device_node *of_node_get(struct device_node *node)
+{
+       return node;
+}
+static inline void of_node_put(struct device_node *node)
+{
+}
+
+#else
+extern struct device_node *of_node_get(struct device_node *node);
+extern void of_node_put(struct device_node *node);
+#endif
+
+/*
+ * OF address retreival & translation
+ */
+
+/* Helper to read a big number; size is in cells (not bytes) */
+static inline u64 of_read_number(const u32 *cell, int size)
+{
+       u64 r = 0;
+       while (size--)
+               r = (r << 32) | *(cell++);
+       return r;
+}
+
+/* Like of_read_number, but we want an unsigned long result */
+#ifdef CONFIG_PPC32
+static inline unsigned long of_read_ulong(const u32 *cell, int size)
+{
+       return cell[size-1];
+}
+#else
+#define of_read_ulong(cell, size)      of_read_number(cell, size)
+#endif
+
 #include <asm/prom.h>
 
 /* flag descriptions */
 #define OF_DYNAMIC     1 /* node and properties were allocated via kmalloc */
 #define OF_DETACHED    2 /* node has been detached from the device tree */
 
+#define OF_IS_DYNAMIC(x) test_bit(OF_DYNAMIC, &x->_flags)
+#define OF_MARK_DYNAMIC(x) set_bit(OF_DYNAMIC, &x->_flags)
+
 #define OF_BAD_ADDR    ((u64)-1)
 
 extern struct device_node *of_find_node_by_name(struct device_node *from,
diff --git a/include/linux/of_fdt.h b/include/linux/of_fdt.h
new file mode 100644 (file)
index 0000000..41d432b
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * Definitions for working with the Flattened Device Tree data format
+ *
+ * Copyright 2009 Benjamin Herrenschmidt, IBM Corp
+ * benh@kernel.crashing.org
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ */
+
+#ifndef _LINUX_OF_FDT_H
+#define _LINUX_OF_FDT_H
+
+#include <linux/types.h>
+#include <linux/init.h>
+
+/* Definitions used by the flattened device tree */
+#define OF_DT_HEADER           0xd00dfeed      /* marker */
+#define OF_DT_BEGIN_NODE       0x1             /* Start of node, full name */
+#define OF_DT_END_NODE         0x2             /* End node */
+#define OF_DT_PROP             0x3             /* Property: name off, size,
+                                                * content */
+#define OF_DT_NOP              0x4             /* nop */
+#define OF_DT_END              0x9
+
+#define OF_DT_VERSION          0x10
+
+#ifndef __ASSEMBLY__
+/*
+ * This is what gets passed to the kernel by prom_init or kexec
+ *
+ * The dt struct contains the device tree structure, full pathes and
+ * property contents. The dt strings contain a separate block with just
+ * the strings for the property names, and is fully page aligned and
+ * self contained in a page, so that it can be kept around by the kernel,
+ * each property name appears only once in this page (cheap compression)
+ *
+ * the mem_rsvmap contains a map of reserved ranges of physical memory,
+ * passing it here instead of in the device-tree itself greatly simplifies
+ * the job of everybody. It's just a list of u64 pairs (base/size) that
+ * ends when size is 0
+ */
+struct boot_param_header {
+       u32     magic;                  /* magic word OF_DT_HEADER */
+       u32     totalsize;              /* total size of DT block */
+       u32     off_dt_struct;          /* offset to structure */
+       u32     off_dt_strings;         /* offset to strings */
+       u32     off_mem_rsvmap;         /* offset to memory reserve map */
+       u32     version;                /* format version */
+       u32     last_comp_version;      /* last compatible version */
+       /* version 2 fields below */
+       u32     boot_cpuid_phys;        /* Physical CPU id we're booting on */
+       /* version 3 fields below */
+       u32     dt_strings_size;        /* size of the DT strings block */
+       /* version 17 fields below */
+       u32     dt_struct_size;         /* size of the DT structure block */
+};
+
+/* For scanning the flat device-tree at boot time */
+extern int __init of_scan_flat_dt(int (*it)(unsigned long node,
+                                           const char *uname, int depth,
+                                           void *data),
+                                 void *data);
+extern void __init *of_get_flat_dt_prop(unsigned long node, const char *name,
+                                       unsigned long *size);
+extern int __init of_flat_dt_is_compatible(unsigned long node,
+                                          const char *name);
+extern unsigned long __init of_get_flat_dt_root(void);
+
+/* Other Prototypes */
+extern void finish_device_tree(void);
+extern void unflatten_device_tree(void);
+extern void early_init_devtree(void *);
+extern int machine_is_compatible(const char *compat);
+extern void print_properties(struct device_node *node);
+extern int prom_n_intr_cells(struct device_node* np);
+extern void prom_get_irq_senses(unsigned char *senses, int off, int max);
+extern int prom_add_property(struct device_node* np, struct property* prop);
+extern int prom_remove_property(struct device_node *np, struct property *prop);
+extern int prom_update_property(struct device_node *np,
+                               struct property *newprop,
+                               struct property *oldprop);
+
+#endif /* __ASSEMBLY__ */
+#endif /* _LINUX_OF_FDT_H */
index daecca3..cabf074 100644 (file)
 #define PCI_DEVICE_ID_SBE_WANXL400     0x0104
 
 #define PCI_VENDOR_ID_TOSHIBA          0x1179
-#define PCI_DEVICE_ID_TOSHIBA_PICCOLO  0x0102
-#define PCI_DEVICE_ID_TOSHIBA_PICCOLO_1        0x0103
-#define PCI_DEVICE_ID_TOSHIBA_PICCOLO_2        0x0105
+#define PCI_DEVICE_ID_TOSHIBA_PICCOLO_1        0x0101
+#define PCI_DEVICE_ID_TOSHIBA_PICCOLO_2        0x0102
+#define PCI_DEVICE_ID_TOSHIBA_PICCOLO_3        0x0103
+#define PCI_DEVICE_ID_TOSHIBA_PICCOLO_5        0x0105
 #define PCI_DEVICE_ID_TOSHIBA_TOPIC95  0x060a
 #define PCI_DEVICE_ID_TOSHIBA_TOPIC97  0x060f
 #define PCI_DEVICE_ID_TOSHIBA_TOPIC100 0x0617
index 7b7fbf4..e3fb256 100644 (file)
@@ -106,6 +106,8 @@ enum perf_sw_ids {
        PERF_COUNT_SW_CPU_MIGRATIONS            = 4,
        PERF_COUNT_SW_PAGE_FAULTS_MIN           = 5,
        PERF_COUNT_SW_PAGE_FAULTS_MAJ           = 6,
+       PERF_COUNT_SW_ALIGNMENT_FAULTS          = 7,
+       PERF_COUNT_SW_EMULATION_FAULTS          = 8,
 
        PERF_COUNT_SW_MAX,                      /* non-ABI */
 };
@@ -225,6 +227,7 @@ struct perf_counter_attr {
 #define PERF_COUNTER_IOC_RESET         _IO ('$', 3)
 #define PERF_COUNTER_IOC_PERIOD                _IOW('$', 4, u64)
 #define PERF_COUNTER_IOC_SET_OUTPUT    _IO ('$', 5)
+#define PERF_COUNTER_IOC_SET_FILTER    _IOW('$', 6, char *)
 
 enum perf_counter_ioc_flags {
        PERF_IOC_FLAG_GROUP             = 1U << 0,
index 9e70126..43adbd7 100644 (file)
 #include <linux/ioctl.h>
 #include <asm/byteorder.h>
 
+#ifdef CONFIG_HAVE_HW_BREAKPOINT
+#include <asm/hw_breakpoint.h>
+#endif
+
 /*
  * User-space ABI bits:
  */
@@ -31,6 +35,7 @@ enum perf_type_id {
        PERF_TYPE_TRACEPOINT                    = 2,
        PERF_TYPE_HW_CACHE                      = 3,
        PERF_TYPE_RAW                           = 4,
+       PERF_TYPE_BREAKPOINT                    = 5,
 
        PERF_TYPE_MAX,                          /* non-ABI */
 };
@@ -102,6 +107,8 @@ enum perf_sw_ids {
        PERF_COUNT_SW_CPU_MIGRATIONS            = 4,
        PERF_COUNT_SW_PAGE_FAULTS_MIN           = 5,
        PERF_COUNT_SW_PAGE_FAULTS_MAJ           = 6,
+       PERF_COUNT_SW_ALIGNMENT_FAULTS          = 7,
+       PERF_COUNT_SW_EMULATION_FAULTS          = 8,
 
        PERF_COUNT_SW_MAX,                      /* non-ABI */
 };
@@ -207,6 +214,15 @@ struct perf_event_attr {
                __u32           wakeup_events;    /* wakeup every n events */
                __u32           wakeup_watermark; /* bytes before wakeup   */
        };
+
+       union {
+               struct { /* Hardware breakpoint info */
+                       __u64           bp_addr;
+                       __u32           bp_type;
+                       __u32           bp_len;
+               };
+       };
+
        __u32                   __reserved_2;
 
        __u64                   __reserved_3;
@@ -219,8 +235,9 @@ struct perf_event_attr {
 #define PERF_EVENT_IOC_DISABLE         _IO ('$', 1)
 #define PERF_EVENT_IOC_REFRESH         _IO ('$', 2)
 #define PERF_EVENT_IOC_RESET           _IO ('$', 3)
-#define PERF_EVENT_IOC_PERIOD          _IOW('$', 4, u64)
+#define PERF_EVENT_IOC_PERIOD          _IOW('$', 4, __u64)
 #define PERF_EVENT_IOC_SET_OUTPUT      _IO ('$', 5)
+#define PERF_EVENT_IOC_SET_FILTER      _IOW('$', 6, char *)
 
 enum perf_event_ioc_flags {
        PERF_IOC_FLAG_GROUP             = 1U << 0,
@@ -475,6 +492,11 @@ struct hw_perf_event {
                        s64             remaining;
                        struct hrtimer  hrtimer;
                };
+#ifdef CONFIG_HAVE_HW_BREAKPOINT
+               union { /* breakpoint */
+                       struct arch_hw_breakpoint       info;
+               };
+#endif
        };
        atomic64_t                      prev_count;
        u64                             sample_period;
@@ -543,6 +565,10 @@ struct perf_pending_entry {
        void (*func)(struct perf_pending_entry *);
 };
 
+typedef void (*perf_callback_t)(struct perf_event *, void *);
+
+struct perf_sample_data;
+
 /**
  * struct perf_event - performance event kernel representation:
  */
@@ -585,7 +611,7 @@ struct perf_event {
        u64                             tstamp_running;
        u64                             tstamp_stopped;
 
-       struct perf_event_attr  attr;
+       struct perf_event_attr          attr;
        struct hw_perf_event            hw;
 
        struct perf_event_context       *ctx;
@@ -633,7 +659,20 @@ struct perf_event {
 
        struct pid_namespace            *ns;
        u64                             id;
+
+       void (*overflow_handler)(struct perf_event *event,
+                       int nmi, struct perf_sample_data *data,
+                       struct pt_regs *regs);
+
+#ifdef CONFIG_EVENT_PROFILE
+       struct event_filter             *filter;
 #endif
+
+       perf_callback_t                 callback;
+
+       perf_callback_t                 event_callback;
+
+#endif /* CONFIG_PERF_EVENTS */
 };
 
 /**
@@ -706,7 +745,6 @@ struct perf_output_handle {
        int                             nmi;
        int                             sample;
        int                             locked;
-       unsigned long                   flags;
 };
 
 #ifdef CONFIG_PERF_EVENTS
@@ -738,6 +776,14 @@ extern int hw_perf_group_sched_in(struct perf_event *group_leader,
               struct perf_cpu_context *cpuctx,
               struct perf_event_context *ctx, int cpu);
 extern void perf_event_update_userpage(struct perf_event *event);
+extern int perf_event_release_kernel(struct perf_event *event);
+extern struct perf_event *
+perf_event_create_kernel_counter(struct perf_event_attr *attr,
+                               int cpu,
+                               pid_t pid,
+                               perf_callback_t callback);
+extern u64 perf_event_read_value(struct perf_event *event,
+                                u64 *enabled, u64 *running);
 
 struct perf_sample_data {
        u64                             type;
@@ -814,6 +860,7 @@ extern int sysctl_perf_event_sample_rate;
 extern void perf_event_init(void);
 extern void perf_tp_event(int event_id, u64 addr, u64 count,
                                 void *record, int entry_size);
+extern void perf_bp_event(struct perf_event *event, void *data);
 
 #ifndef perf_misc_flags
 #define perf_misc_flags(regs)  (user_mode(regs) ? PERF_RECORD_MISC_USER : \
@@ -827,6 +874,8 @@ extern int perf_output_begin(struct perf_output_handle *handle,
 extern void perf_output_end(struct perf_output_handle *handle);
 extern void perf_output_copy(struct perf_output_handle *handle,
                             const void *buf, unsigned int len);
+extern int perf_swevent_get_recursion_context(void);
+extern void perf_swevent_put_recursion_context(int rctx);
 #else
 static inline void
 perf_event_task_sched_in(struct task_struct *task, int cpu)            { }
@@ -848,11 +897,15 @@ static inline int perf_event_task_enable(void)                            { return -EINVAL; }
 static inline void
 perf_sw_event(u32 event_id, u64 nr, int nmi,
                     struct pt_regs *regs, u64 addr)                    { }
+static inline void
+perf_bp_event(struct perf_event *event, void *data)            { }
 
 static inline void perf_event_mmap(struct vm_area_struct *vma)         { }
 static inline void perf_event_comm(struct task_struct *tsk)            { }
 static inline void perf_event_fork(struct task_struct *tsk)            { }
 static inline void perf_event_init(void)                               { }
+static inline int  perf_swevent_get_recursion_context(void)  { return -1; }
+static inline void perf_swevent_put_recursion_context(int rctx)                { }
 
 #endif
 
index 3b7e04b..0d65934 100644 (file)
@@ -178,9 +178,10 @@ typedef struct pm_message {
  *     This need not mean that the device should be put into a low power state.
  *     For example, if the device is behind a link which is about to be turned
  *     off, the device may remain at full power.  If the device does go to low
- *     power and if device_may_wakeup(dev) is true, remote wake-up (i.e., a
- *     hardware mechanism allowing the device to request a change of its power
- *     state, such as PCI PME) should be enabled for it.
+ *     power and is capable of generating run-time wake-up events, remote
+ *     wake-up (i.e., a hardware mechanism allowing the device to request a
+ *     change of its power state via a wake-up event, such as PCI PME) should
+ *     be enabled for it.
  *
  * @runtime_resume: Put the device into the fully active state in response to a
  *     wake-up event generated by hardware or at the request of software.  If
@@ -428,6 +429,7 @@ struct dev_pm_info {
        unsigned int            idle_notification:1;
        unsigned int            request_pending:1;
        unsigned int            deferred_resume:1;
+       unsigned int            run_wake:1;
        enum rpm_request        request;
        enum rpm_status         runtime_status;
        int                     runtime_error;
index 4408704..370ce0a 100644 (file)
@@ -50,6 +50,16 @@ static inline void pm_runtime_put_noidle(struct device *dev)
        atomic_add_unless(&dev->power.usage_count, -1, 0);
 }
 
+static inline bool device_run_wake(struct device *dev)
+{
+       return dev->power.run_wake;
+}
+
+static inline void device_set_run_wake(struct device *dev, bool enable)
+{
+       dev->power.run_wake = enable;
+}
+
 #else /* !CONFIG_PM_RUNTIME */
 
 static inline int pm_runtime_idle(struct device *dev) { return -ENOSYS; }
@@ -73,6 +83,8 @@ static inline bool pm_children_suspended(struct device *dev) { return false; }
 static inline void pm_suspend_ignore_children(struct device *dev, bool en) {}
 static inline void pm_runtime_get_noresume(struct device *dev) {}
 static inline void pm_runtime_put_noidle(struct device *dev) {}
+static inline bool device_run_wake(struct device *dev) { return false; }
+static inline void device_set_run_wake(struct device *dev, bool enable) {}
 
 #endif /* !CONFIG_PM_RUNTIME */
 
index 72b1a10..2e681d9 100644 (file)
@@ -105,6 +105,11 @@ struct preempt_notifier;
  * @sched_out: we've just been preempted
  *    notifier: struct preempt_notifier for the task being preempted
  *    next: the task that's kicking us out
+ *
+ * Please note that sched_in and out are called under different
+ * contexts.  sched_out is called with rq lock held and irq disabled
+ * while sched_in is called without rq lock and irq enabled.  This
+ * difference is intentional and depended upon by its users.
  */
 struct preempt_ops {
        void (*sched_in)(struct preempt_notifier *notifier, int cpu);
index 882dc48..89115ec 100644 (file)
@@ -145,7 +145,6 @@ extern unsigned long this_cpu_load(void);
 
 
 extern void calc_global_load(void);
-extern u64 cpu_nr_migrations(int cpu);
 
 extern unsigned long get_parent_ip(unsigned long addr);
 
@@ -171,8 +170,6 @@ print_cfs_rq(struct seq_file *m, int cpu, struct cfs_rq *cfs_rq)
 }
 #endif
 
-extern unsigned long long time_sync_thresh;
-
 /*
  * Task state bitmask. NOTE! These bits are also
  * encoded in fs/proc/array.c: get_task_state().
@@ -349,7 +346,6 @@ extern signed long schedule_timeout(signed long timeout);
 extern signed long schedule_timeout_interruptible(signed long timeout);
 extern signed long schedule_timeout_killable(signed long timeout);
 extern signed long schedule_timeout_uninterruptible(signed long timeout);
-asmlinkage void __schedule(void);
 asmlinkage void schedule(void);
 extern int mutex_spin_on_owner(struct mutex *lock, struct thread_info *owner);
 
@@ -628,6 +624,9 @@ struct signal_struct {
        cputime_t utime, stime, cutime, cstime;
        cputime_t gtime;
        cputime_t cgtime;
+#ifndef CONFIG_VIRT_CPU_ACCOUNTING
+       cputime_t prev_utime, prev_stime;
+#endif
        unsigned long nvcsw, nivcsw, cnvcsw, cnivcsw;
        unsigned long min_flt, maj_flt, cmin_flt, cmaj_flt;
        unsigned long inblock, oublock, cinblock, coublock;
@@ -1013,9 +1012,13 @@ static inline struct cpumask *sched_domain_span(struct sched_domain *sd)
        return to_cpumask(sd->span);
 }
 
-extern void partition_sched_domains(int ndoms_new, struct cpumask *doms_new,
+extern void partition_sched_domains(int ndoms_new, cpumask_var_t doms_new[],
                                    struct sched_domain_attr *dattr_new);
 
+/* Allocate an array of sched domains, for partition_sched_domains(). */
+cpumask_var_t *alloc_sched_domains(unsigned int ndoms);
+void free_sched_domains(cpumask_var_t doms[], unsigned int ndoms);
+
 /* Test a flag in parent sched domain */
 static inline int test_sd_parent(struct sched_domain *sd, int flag)
 {
@@ -1033,7 +1036,7 @@ unsigned long default_scale_smt_power(struct sched_domain *sd, int cpu);
 struct sched_domain_attr;
 
 static inline void
-partition_sched_domains(int ndoms_new, struct cpumask *doms_new,
+partition_sched_domains(int ndoms_new, cpumask_var_t doms_new[],
                        struct sched_domain_attr *dattr_new)
 {
 }
@@ -1331,7 +1334,9 @@ struct task_struct {
 
        cputime_t utime, stime, utimescaled, stimescaled;
        cputime_t gtime;
+#ifndef CONFIG_VIRT_CPU_ACCOUNTING
        cputime_t prev_utime, prev_stime;
+#endif
        unsigned long nvcsw, nivcsw; /* context switch counts */
        struct timespec start_time;             /* monotonic time */
        struct timespec real_start_time;        /* boot based time */
@@ -1720,9 +1725,8 @@ static inline void put_task_struct(struct task_struct *t)
                __put_task_struct(t);
 }
 
-extern cputime_t task_utime(struct task_struct *p);
-extern cputime_t task_stime(struct task_struct *p);
-extern cputime_t task_gtime(struct task_struct *p);
+extern void task_times(struct task_struct *p, cputime_t *ut, cputime_t *st);
+extern void thread_group_times(struct task_struct *p, cputime_t *ut, cputime_t *st);
 
 /*
  * Per process flags
index db532ce..8c3dd36 100644 (file)
 /* BCM63xx family SoCs */
 #define PORT_BCM63XX   89
 
+/* Aeroflex Gaisler GRLIB APBUART */
+#define PORT_APBUART    90
+
 #ifdef __KERNEL__
 
 #include <linux/compiler.h>
index 714f063..bc70c58 100644 (file)
@@ -100,37 +100,16 @@ struct perf_event_attr;
 #define __SC_TEST6(t6, a6, ...)        __SC_TEST(t6); __SC_TEST5(__VA_ARGS__)
 
 #ifdef CONFIG_EVENT_PROFILE
-#define TRACE_SYS_ENTER_PROFILE(sname)                                        \
-static int prof_sysenter_enable_##sname(void)                                 \
-{                                                                             \
-       return reg_prof_syscall_enter("sys"#sname);                            \
-}                                                                             \
-                                                                              \
-static void prof_sysenter_disable_##sname(void)                                       \
-{                                                                             \
-       unreg_prof_syscall_enter("sys"#sname);                                 \
-}
-
-#define TRACE_SYS_EXIT_PROFILE(sname)                                         \
-static int prof_sysexit_enable_##sname(void)                                  \
-{                                                                             \
-       return reg_prof_syscall_exit("sys"#sname);                             \
-}                                                                             \
-                                                                              \
-static void prof_sysexit_disable_##sname(void)                                \
-{                                                                              \
-       unreg_prof_syscall_exit("sys"#sname);                                  \
-}
 
 #define TRACE_SYS_ENTER_PROFILE_INIT(sname)                                   \
        .profile_count = ATOMIC_INIT(-1),                                      \
-       .profile_enable = prof_sysenter_enable_##sname,                        \
-       .profile_disable = prof_sysenter_disable_##sname,
+       .profile_enable = prof_sysenter_enable,                                \
+       .profile_disable = prof_sysenter_disable,
 
 #define TRACE_SYS_EXIT_PROFILE_INIT(sname)                                    \
        .profile_count = ATOMIC_INIT(-1),                                      \
-       .profile_enable = prof_sysexit_enable_##sname,                         \
-       .profile_disable = prof_sysexit_disable_##sname,
+       .profile_enable = prof_sysexit_enable,                                 \
+       .profile_disable = prof_sysexit_disable,
 #else
 #define TRACE_SYS_ENTER_PROFILE(sname)
 #define TRACE_SYS_ENTER_PROFILE_INIT(sname)
@@ -154,74 +133,46 @@ static void prof_sysexit_disable_##sname(void)                                   \
 #define __SC_STR_TDECL6(t, a, ...)     #t, __SC_STR_TDECL5(__VA_ARGS__)
 
 #define SYSCALL_TRACE_ENTER_EVENT(sname)                               \
+       static const struct syscall_metadata __syscall_meta_##sname;    \
        static struct ftrace_event_call event_enter_##sname;            \
-       struct trace_event enter_syscall_print_##sname = {              \
+       static struct trace_event enter_syscall_print_##sname = {       \
                .trace                  = print_syscall_enter,          \
        };                                                              \
-       static int init_enter_##sname(void)                             \
-       {                                                               \
-               int num, id;                                            \
-               num = syscall_name_to_nr("sys"#sname);                  \
-               if (num < 0)                                            \
-                       return -ENOSYS;                                 \
-               id = register_ftrace_event(&enter_syscall_print_##sname);\
-               if (!id)                                                \
-                       return -ENODEV;                                 \
-               event_enter_##sname.id = id;                            \
-               set_syscall_enter_id(num, id);                          \
-               INIT_LIST_HEAD(&event_enter_##sname.fields);            \
-               return 0;                                               \
-       }                                                               \
-       TRACE_SYS_ENTER_PROFILE(sname);                                 \
        static struct ftrace_event_call __used                          \
          __attribute__((__aligned__(4)))                               \
          __attribute__((section("_ftrace_events")))                    \
          event_enter_##sname = {                                       \
                .name                   = "sys_enter"#sname,            \
                .system                 = "syscalls",                   \
-               .event                  = &event_syscall_enter,         \
-               .raw_init               = init_enter_##sname,           \
+               .event                  = &enter_syscall_print_##sname, \
+               .raw_init               = init_syscall_trace,           \
                .show_format            = syscall_enter_format,         \
                .define_fields          = syscall_enter_define_fields,  \
                .regfunc                = reg_event_syscall_enter,      \
                .unregfunc              = unreg_event_syscall_enter,    \
-               .data                   = "sys"#sname,                  \
+               .data                   = (void *)&__syscall_meta_##sname,\
                TRACE_SYS_ENTER_PROFILE_INIT(sname)                     \
        }
 
 #define SYSCALL_TRACE_EXIT_EVENT(sname)                                        \
+       static const struct syscall_metadata __syscall_meta_##sname;    \
        static struct ftrace_event_call event_exit_##sname;             \
-       struct trace_event exit_syscall_print_##sname = {               \
+       static struct trace_event exit_syscall_print_##sname = {        \
                .trace                  = print_syscall_exit,           \
        };                                                              \
-       static int init_exit_##sname(void)                              \
-       {                                                               \
-               int num, id;                                            \
-               num = syscall_name_to_nr("sys"#sname);                  \
-               if (num < 0)                                            \
-                       return -ENOSYS;                                 \
-               id = register_ftrace_event(&exit_syscall_print_##sname);\
-               if (!id)                                                \
-                       return -ENODEV;                                 \
-               event_exit_##sname.id = id;                             \
-               set_syscall_exit_id(num, id);                           \
-               INIT_LIST_HEAD(&event_exit_##sname.fields);             \
-               return 0;                                               \
-       }                                                               \
-       TRACE_SYS_EXIT_PROFILE(sname);                                  \
        static struct ftrace_event_call __used                          \
          __attribute__((__aligned__(4)))                               \
          __attribute__((section("_ftrace_events")))                    \
          event_exit_##sname = {                                        \
                .name                   = "sys_exit"#sname,             \
                .system                 = "syscalls",                   \
-               .event                  = &event_syscall_exit,          \
-               .raw_init               = init_exit_##sname,            \
+               .event                  = &exit_syscall_print_##sname,  \
+               .raw_init               = init_syscall_trace,           \
                .show_format            = syscall_exit_format,          \
                .define_fields          = syscall_exit_define_fields,   \
                .regfunc                = reg_event_syscall_exit,       \
                .unregfunc              = unreg_event_syscall_exit,     \
-               .data                   = "sys"#sname,                  \
+               .data                   = (void *)&__syscall_meta_##sname,\
                TRACE_SYS_EXIT_PROFILE_INIT(sname)                      \
        }
 
index 9f047d7..56af3ca 100644 (file)
@@ -15,9 +15,6 @@
  **  The kernel will then return -ENOTDIR to any application using
  **  the old binary interface.
  **
- **  For new interfaces unless you really need a binary number
- **  please use CTL_UNNUMBERED.
- **
  ****************************************************************
  ****************************************************************
  */
@@ -50,12 +47,6 @@ struct __sysctl_args {
 
 /* Top-level names: */
 
-/* For internal pattern-matching use only: */
-#ifdef __KERNEL__
-#define CTL_NONE       0
-#define CTL_UNNUMBERED CTL_NONE        /* sysctl without a binary number */
-#endif
-
 enum
 {
        CTL_KERN=1,             /* General kernel info and control */
@@ -973,10 +964,6 @@ extern int sysctl_perm(struct ctl_table_root *root,
 
 typedef struct ctl_table ctl_table;
 
-typedef int ctl_handler (struct ctl_table *table,
-                        void __user *oldval, size_t __user *oldlenp,
-                        void __user *newval, size_t newlen);
-
 typedef int proc_handler (struct ctl_table *ctl, int write,
                          void __user *buffer, size_t *lenp, loff_t *ppos);
 
@@ -997,21 +984,10 @@ extern int proc_doulongvec_minmax(struct ctl_table *, int,
 extern int proc_doulongvec_ms_jiffies_minmax(struct ctl_table *table, int,
                                      void __user *, size_t *, loff_t *);
 
-extern int do_sysctl (int __user *name, int nlen,
-                     void __user *oldval, size_t __user *oldlenp,
-                     void __user *newval, size_t newlen);
-
-extern ctl_handler sysctl_data;
-extern ctl_handler sysctl_string;
-extern ctl_handler sysctl_intvec;
-extern ctl_handler sysctl_jiffies;
-extern ctl_handler sysctl_ms_jiffies;
-
-
 /*
  * Register a set of sysctl names by calling register_sysctl_table
- * with an initialised array of struct ctl_table's.  An entry with zero
- * ctl_name and NULL procname terminates the table.  table->de will be
+ * with an initialised array of struct ctl_table's.  An entry with 
+ * NULL procname terminates the table.  table->de will be
  * set up by the registration and need not be initialised in advance.
  *
  * sysctl names can be mirrored automatically under /proc/sys.  The
@@ -1024,24 +1000,11 @@ extern ctl_handler sysctl_ms_jiffies;
  * under /proc; non-leaf nodes will be represented by directories.  A
  * null procname disables /proc mirroring at this node.
  *
- * sysctl entries with a zero ctl_name will not be available through
- * the binary sysctl interface.
- *
  * sysctl(2) can automatically manage read and write requests through
  * the sysctl table.  The data and maxlen fields of the ctl_table
  * struct enable minimal validation of the values being written to be
  * performed, and the mode field allows minimal authentication.
  * 
- * More sophisticated management can be enabled by the provision of a
- * strategy routine with the table entry.  This will be called before
- * any automatic read or write of the data is performed.
- * 
- * The strategy routine may return:
- * <0: Error occurred (error is passed to user process)
- * 0:  OK - proceed with automatic read or write.
- * >0: OK - read or write has been done by the strategy routine, so 
- *     return immediately.
- * 
  * There must be a proc_handler routine for any terminal nodes
  * mirrored under /proc/sys (non-terminals are handled by a built-in
  * directory handler).  Several default handlers are available to
@@ -1051,7 +1014,6 @@ extern ctl_handler sysctl_ms_jiffies;
 /* A sysctl table is an array of struct ctl_table: */
 struct ctl_table 
 {
-       int ctl_name;                   /* Binary ID */
        const char *procname;           /* Text ID for /proc/sys, or zero */
        void *data;
        int maxlen;
@@ -1059,7 +1021,6 @@ struct ctl_table
        struct ctl_table *child;
        struct ctl_table *parent;       /* Automatically set */
        proc_handler *proc_handler;     /* Callback for text formatting */
-       ctl_handler *strategy;          /* Callback function for all r/w */
        void *extra1;
        void *extra2;
 };
@@ -1093,7 +1054,6 @@ struct ctl_table_header
 /* struct ctl_path describes where in the hierarchy a table is added */
 struct ctl_path {
        const char *procname;
-       int ctl_name;
 };
 
 void register_sysctl_root(struct ctl_table_root *root);
index 2aac8a8..f59604e 100644 (file)
@@ -280,6 +280,12 @@ static inline void tracepoint_synchronize_unregister(void)
  * TRACE_EVENT_FN to perform any (un)registration work.
  */
 
+#define DECLARE_EVENT_CLASS(name, proto, args, tstruct, assign, print)
+#define DEFINE_EVENT(template, name, proto, args)              \
+       DECLARE_TRACE(name, PARAMS(proto), PARAMS(args))
+#define DEFINE_EVENT_PRINT(template, name, proto, args, print) \
+       DECLARE_TRACE(name, PARAMS(proto), PARAMS(args))
+
 #define TRACE_EVENT(name, proto, args, struct, assign, print)  \
        DECLARE_TRACE(name, PARAMS(proto), PARAMS(args))
 #define TRACE_EVENT_FN(name, proto, args, struct,              \
diff --git a/include/linux/user-return-notifier.h b/include/linux/user-return-notifier.h
new file mode 100644 (file)
index 0000000..9c4a445
--- /dev/null
@@ -0,0 +1,49 @@
+#ifndef _LINUX_USER_RETURN_NOTIFIER_H
+#define _LINUX_USER_RETURN_NOTIFIER_H
+
+#ifdef CONFIG_USER_RETURN_NOTIFIER
+
+#include <linux/list.h>
+#include <linux/sched.h>
+
+struct user_return_notifier {
+       void (*on_user_return)(struct user_return_notifier *urn);
+       struct hlist_node link;
+};
+
+
+void user_return_notifier_register(struct user_return_notifier *urn);
+void user_return_notifier_unregister(struct user_return_notifier *urn);
+
+static inline void propagate_user_return_notify(struct task_struct *prev,
+                                               struct task_struct *next)
+{
+       if (test_tsk_thread_flag(prev, TIF_USER_RETURN_NOTIFY)) {
+               clear_tsk_thread_flag(prev, TIF_USER_RETURN_NOTIFY);
+               set_tsk_thread_flag(next, TIF_USER_RETURN_NOTIFY);
+       }
+}
+
+void fire_user_return_notifiers(void);
+
+static inline void clear_user_return_notifier(struct task_struct *p)
+{
+       clear_tsk_thread_flag(p, TIF_USER_RETURN_NOTIFY);
+}
+
+#else
+
+struct user_return_notifier {};
+
+static inline void propagate_user_return_notify(struct task_struct *prev,
+                                               struct task_struct *next)
+{
+}
+
+static inline void fire_user_return_notifiers(void) {}
+
+static inline void clear_user_return_notifier(struct task_struct *p) {}
+
+#endif
+
+#endif
index 66ebddc..705f01f 100644 (file)
@@ -49,6 +49,7 @@ struct writeback_control {
        unsigned nonblocking:1;         /* Don't get stuck on request queues */
        unsigned encountered_congestion:1; /* An output: a queue is full */
        unsigned for_kupdate:1;         /* A kupdate writeback */
+       unsigned for_background:1;      /* A background writeback */
        unsigned for_reclaim:1;         /* Invoked from the page allocator */
        unsigned range_cyclic:1;        /* range_start is cyclic */
        unsigned more_io:1;             /* more io to be dispatched */
index 28966ca..511a459 100644 (file)
@@ -75,7 +75,6 @@ struct dn_dev_parms {
        unsigned long t3;         /* Default value of t3                */
        int priority;             /* Priority to be a router            */
        char *name;               /* Name for sysctl                    */
-       int ctl_name;             /* Index for sysctl                   */
        int  (*up)(struct net_device *);
        void (*down)(struct net_device *);
        void (*timer3)(struct net_device *, struct dn_ifaddr *ifa);
index db8e96d..0302f31 100644 (file)
@@ -258,8 +258,7 @@ extern int                  neigh_sysctl_register(struct net_device *dev,
                                                      struct neigh_parms *p,
                                                      int p_id, int pdev_id,
                                                      char *p_name,
-                                                     proc_handler *proc_handler,
-                                                     ctl_handler *strategy);
+                                                     proc_handler *proc_handler);
 extern void                    neigh_sysctl_unregister(struct neigh_parms *p);
 
 static inline void __neigh_parms_put(struct neigh_parms *parms)
index fd054a3..e9dd936 100644 (file)
@@ -2,7 +2,6 @@ header-y += asound_fm.h
 header-y += hdsp.h
 header-y += hdspm.h
 header-y += sfnt_info.h
-header-y += sscape_ioctl.h
 
 unifdef-y += asequencer.h
 unifdef-y += asound.h
similarity index 85%
rename from sound/isa/opti9xx/miro.h
rename to include/sound/aci.h
index 6e1385b..ee639d3 100644 (file)
@@ -1,5 +1,5 @@
-#ifndef _MIRO_H_
-#define _MIRO_H_
+#ifndef _ACI_H_
+#define _ACI_H_
 
 #define ACI_REG_COMMAND                0       /* write register offset */
 #define ACI_REG_STATUS         1       /* read register offset */
 #define ACI_SET_EQ6            0x45
 #define ACI_SET_EQ7            0x46    /* ... to Treble */
 
-#endif  /* _MIRO_H_ */
+struct snd_miro_aci {
+       unsigned long aci_port;
+       int aci_vendor;
+       int aci_product;
+       int aci_version;
+       int aci_amp;
+       int aci_preamp;
+       int aci_solomode;
+
+       struct mutex aci_mutex;
+};
+
+int snd_aci_cmd(struct snd_miro_aci *aci, int write1, int write2, int write3);
+
+struct snd_miro_aci *snd_aci_get_aci(void);
+
+#endif  /* _ACI_H_ */
+
diff --git a/include/sound/ak4113.h b/include/sound/ak4113.h
new file mode 100644 (file)
index 0000000..8988eda
--- /dev/null
@@ -0,0 +1,321 @@
+#ifndef __SOUND_AK4113_H
+#define __SOUND_AK4113_H
+
+/*
+ *  Routines for Asahi Kasei AK4113
+ *  Copyright (c) by Jaroslav Kysela <perex@perex.cz>,
+ *  Copyright (c) by Pavel Hofman <pavel.hofman@ivitera.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
+ *
+ */
+
+/* AK4113 registers */
+/* power down */
+#define AK4113_REG_PWRDN       0x00
+/* format control */
+#define AK4113_REG_FORMAT      0x01
+/* input/output control */
+#define AK4113_REG_IO0         0x02
+/* input/output control */
+#define AK4113_REG_IO1         0x03
+/* interrupt0 mask */
+#define AK4113_REG_INT0_MASK   0x04
+/* interrupt1 mask */
+#define AK4113_REG_INT1_MASK   0x05
+/* DAT mask & DTS select */
+#define AK4113_REG_DATDTS      0x06
+/* receiver status 0 */
+#define AK4113_REG_RCS0                0x07
+/* receiver status 1 */
+#define AK4113_REG_RCS1                0x08
+/* receiver status 2 */
+#define AK4113_REG_RCS2                0x09
+/* RX channel status byte 0 */
+#define AK4113_REG_RXCSB0      0x0a
+/* RX channel status byte 1 */
+#define AK4113_REG_RXCSB1      0x0b
+/* RX channel status byte 2 */
+#define AK4113_REG_RXCSB2      0x0c
+/* RX channel status byte 3 */
+#define AK4113_REG_RXCSB3      0x0d
+/* RX channel status byte 4 */
+#define AK4113_REG_RXCSB4      0x0e
+/* burst preamble Pc byte 0 */
+#define AK4113_REG_Pc0         0x0f
+/* burst preamble Pc byte 1 */
+#define AK4113_REG_Pc1         0x10
+/* burst preamble Pd byte 0 */
+#define AK4113_REG_Pd0         0x11
+/* burst preamble Pd byte 1 */
+#define AK4113_REG_Pd1         0x12
+/* Q-subcode address + control */
+#define AK4113_REG_QSUB_ADDR   0x13
+/* Q-subcode track */
+#define AK4113_REG_QSUB_TRACK  0x14
+/* Q-subcode index */
+#define AK4113_REG_QSUB_INDEX  0x15
+/* Q-subcode minute */
+#define AK4113_REG_QSUB_MINUTE 0x16
+/* Q-subcode second */
+#define AK4113_REG_QSUB_SECOND 0x17
+/* Q-subcode frame */
+#define AK4113_REG_QSUB_FRAME  0x18
+/* Q-subcode zero */
+#define AK4113_REG_QSUB_ZERO   0x19
+/* Q-subcode absolute minute */
+#define AK4113_REG_QSUB_ABSMIN 0x1a
+/* Q-subcode absolute second */
+#define AK4113_REG_QSUB_ABSSEC 0x1b
+/* Q-subcode absolute frame */
+#define AK4113_REG_QSUB_ABSFRM 0x1c
+
+/* sizes */
+#define AK4113_REG_RXCSB_SIZE  ((AK4113_REG_RXCSB4-AK4113_REG_RXCSB0)+1)
+#define AK4113_REG_QSUB_SIZE   ((AK4113_REG_QSUB_ABSFRM-AK4113_REG_QSUB_ADDR)\
+               +1)
+
+#define AK4113_WRITABLE_REGS   (AK4113_REG_DATDTS + 1)
+
+/* AK4113_REG_PWRDN bits */
+/* Channel Status Select */
+#define AK4113_CS12            (1<<7)
+/* Block Start & C/U Output Mode */
+#define AK4113_BCU             (1<<6)
+/* Master Clock Operation Select */
+#define AK4113_CM1             (1<<5)
+/* Master Clock Operation Select */
+#define AK4113_CM0             (1<<4)
+/* Master Clock Frequency Select */
+#define AK4113_OCKS1           (1<<3)
+/* Master Clock Frequency Select */
+#define AK4113_OCKS0           (1<<2)
+/* 0 = power down, 1 = normal operation */
+#define AK4113_PWN             (1<<1)
+/* 0 = reset & initialize (except thisregister), 1 = normal operation */
+#define AK4113_RST             (1<<0)
+
+/* AK4113_REQ_FORMAT bits */
+/* V/TX Output select: 0 = Validity Flag Output, 1 = TX */
+#define AK4113_VTX             (1<<7)
+/* Audio Data Control */
+#define AK4113_DIF2            (1<<6)
+/* Audio Data Control */
+#define AK4113_DIF1            (1<<5)
+/* Audio Data Control */
+#define AK4113_DIF0            (1<<4)
+/* Deemphasis Autodetect Enable (1 = enable) */
+#define AK4113_DEAU            (1<<3)
+/* 32kHz-48kHz Deemphasis Control */
+#define AK4113_DEM1            (1<<2)
+/* 32kHz-48kHz Deemphasis Control */
+#define AK4113_DEM0            (1<<1)
+#define AK4113_DEM_OFF         (AK4113_DEM0)
+#define AK4113_DEM_44KHZ       (0)
+#define AK4113_DEM_48KHZ       (AK4113_DEM1)
+#define AK4113_DEM_32KHZ       (AK4113_DEM0|AK4113_DEM1)
+/* STDO: 16-bit, right justified */
+#define AK4113_DIF_16R         (0)
+/* STDO: 18-bit, right justified */
+#define AK4113_DIF_18R         (AK4113_DIF0)
+/* STDO: 20-bit, right justified */
+#define AK4113_DIF_20R         (AK4113_DIF1)
+/* STDO: 24-bit, right justified */
+#define AK4113_DIF_24R         (AK4113_DIF1|AK4113_DIF0)
+/* STDO: 24-bit, left justified */
+#define AK4113_DIF_24L         (AK4113_DIF2)
+/* STDO: I2S */
+#define AK4113_DIF_24I2S       (AK4113_DIF2|AK4113_DIF0)
+/* STDO: 24-bit, left justified; LRCLK, BICK = Input */
+#define AK4113_DIF_I24L                (AK4113_DIF2|AK4113_DIF1)
+/* STDO: I2S;  LRCLK, BICK = Input */
+#define AK4113_DIF_I24I2S      (AK4113_DIF2|AK4113_DIF1|AK4113_DIF0)
+
+/* AK4113_REG_IO0 */
+/* XTL1=0,XTL0=0 -> 11.2896Mhz; XTL1=0,XTL0=1 -> 12.288Mhz */
+#define AK4113_XTL1            (1<<6)
+/* XTL1=1,XTL0=0 -> 24.576Mhz; XTL1=1,XTL0=1 -> use channel status */
+#define AK4113_XTL0            (1<<5)
+/* Block Start Signal Output: 0 = U-bit, 1 = C-bit (req. BCU = 1) */
+#define AK4113_UCE             (1<<4)
+/* TX Output Enable (1 = enable) */
+#define AK4113_TXE             (1<<3)
+/* Output Through Data Selector for TX pin */
+#define AK4113_OPS2            (1<<2)
+/* Output Through Data Selector for TX pin */
+#define AK4113_OPS1            (1<<1)
+/* Output Through Data Selector for TX pin */
+#define AK4113_OPS0            (1<<0)
+/* 11.2896 MHz ref. Xtal freq. */
+#define AK4113_XTL_11_2896M    (0)
+/* 12.288 MHz ref. Xtal freq. */
+#define AK4113_XTL_12_288M     (AK4113_XTL0)
+/* 24.576 MHz ref. Xtal freq. */
+#define AK4113_XTL_24_576M     (AK4113_XTL1)
+
+/* AK4113_REG_IO1 */
+/* Interrupt 0 pin Hold */
+#define AK4113_EFH1            (1<<7)
+/* Interrupt 0 pin Hold */
+#define AK4113_EFH0            (1<<6)
+#define AK4113_EFH_512LRCLK    (0)
+#define AK4113_EFH_1024LRCLK   (AK4113_EFH0)
+#define AK4113_EFH_2048LRCLK   (AK4113_EFH1)
+#define AK4113_EFH_4096LRCLK   (AK4113_EFH1|AK4113_EFH0)
+/* PLL Lock Time: 0 = 384/fs, 1 = 1/fs */
+#define AK4113_FAST            (1<<5)
+/* MCKO2 Output Select: 0 = CMx/OCKSx, 1 = Xtal */
+#define AK4113_XMCK            (1<<4)
+/* MCKO2 Output Freq. Select: 0 = x1, 1 = x0.5  (req. XMCK = 1) */
+#define AK4113_DIV             (1<<3)
+/* Input Recovery Data Select */
+#define AK4113_IPS2            (1<<2)
+/* Input Recovery Data Select */
+#define AK4113_IPS1            (1<<1)
+/* Input Recovery Data Select */
+#define AK4113_IPS0            (1<<0)
+#define AK4113_IPS(x)          ((x)&7)
+
+/* AK4113_REG_INT0_MASK && AK4113_REG_INT1_MASK*/
+/* mask enable for QINT bit */
+#define AK4113_MQI             (1<<7)
+/* mask enable for AUTO bit */
+#define AK4113_MAUT            (1<<6)
+/* mask enable for CINT bit */
+#define AK4113_MCIT            (1<<5)
+/* mask enable for UNLOCK bit */
+#define AK4113_MULK            (1<<4)
+/* mask enable for V bit */
+#define AK4113_V               (1<<3)
+/* mask enable for STC bit */
+#define AK4113_STC             (1<<2)
+/* mask enable for AUDN bit */
+#define AK4113_MAN             (1<<1)
+/* mask enable for PAR bit */
+#define AK4113_MPR             (1<<0)
+
+/* AK4113_REG_DATDTS */
+/* DAT Start ID Counter */
+#define AK4113_DCNT            (1<<4)
+/* DTS-CD 16-bit Sync Word Detect */
+#define AK4113_DTS16           (1<<3)
+/* DTS-CD 14-bit Sync Word Detect */
+#define AK4113_DTS14           (1<<2)
+/* mask enable for DAT bit (if 1, no INT1 effect */
+#define AK4113_MDAT1           (1<<1)
+/* mask enable for DAT bit (if 1, no INT0 effect */
+#define AK4113_MDAT0           (1<<0)
+
+/* AK4113_REG_RCS0 */
+/* Q-subcode buffer interrupt, 0 = no change, 1 = changed */
+#define AK4113_QINT            (1<<7)
+/* Non-PCM or DTS stream auto detection, 0 = no detect, 1 = detect */
+#define AK4113_AUTO            (1<<6)
+/* channel status buffer interrupt, 0 = no change, 1 = change */
+#define AK4113_CINT            (1<<5)
+/* PLL lock status, 0 = lock, 1 = unlock */
+#define AK4113_UNLCK           (1<<4)
+/* Validity bit, 0 = valid, 1 = invalid */
+#define AK4113_V               (1<<3)
+/* sampling frequency or Pre-emphasis change, 0 = no detect, 1 = detect */
+#define AK4113_STC             (1<<2)
+/* audio bit output, 0 = audio, 1 = non-audio */
+#define AK4113_AUDION          (1<<1)
+/* parity error or biphase error status, 0 = no error, 1 = error */
+#define AK4113_PAR             (1<<0)
+
+/* AK4113_REG_RCS1 */
+/* sampling frequency detection */
+#define AK4113_FS3             (1<<7)
+#define AK4113_FS2             (1<<6)
+#define AK4113_FS1             (1<<5)
+#define AK4113_FS0             (1<<4)
+/* Pre-emphasis detect, 0 = OFF, 1 = ON */
+#define AK4113_PEM             (1<<3)
+/* DAT Start ID Detect, 0 = no detect, 1 = detect */
+#define AK4113_DAT             (1<<2)
+/* DTS-CD bit audio stream detect, 0 = no detect, 1 = detect */
+#define AK4113_DTSCD           (1<<1)
+/* Non-PCM bit stream detection, 0 = no detect, 1 = detect */
+#define AK4113_NPCM            (1<<0)
+#define AK4113_FS_8000HZ       (AK4113_FS3|AK4113_FS0)
+#define AK4113_FS_11025HZ      (AK4113_FS2|AK4113_FS0)
+#define AK4113_FS_16000HZ      (AK4113_FS2|AK4113_FS1|AK4113_FS0)
+#define AK4113_FS_22050HZ      (AK4113_FS2)
+#define AK4113_FS_24000HZ      (AK4113_FS2|AK4113_FS1)
+#define AK4113_FS_32000HZ      (AK4113_FS1|AK4113_FS0)
+#define AK4113_FS_44100HZ      (0)
+#define AK4113_FS_48000HZ      (AK4113_FS1)
+#define AK4113_FS_64000HZ      (AK4113_FS3|AK4113_FS1|AK4113_FS0)
+#define AK4113_FS_88200HZ      (AK4113_FS3)
+#define AK4113_FS_96000HZ      (AK4113_FS3|AK4113_FS1)
+#define AK4113_FS_176400HZ     (AK4113_FS3|AK4113_FS2)
+#define AK4113_FS_192000HZ     (AK4113_FS3|AK4113_FS2|AK4113_FS1)
+
+/* AK4113_REG_RCS2 */
+/* CRC for Q-subcode, 0 = no error, 1 = error */
+#define AK4113_QCRC            (1<<1)
+/* CRC for channel status, 0 = no error, 1 = error */
+#define AK4113_CCRC            (1<<0)
+
+/* flags for snd_ak4113_check_rate_and_errors() */
+#define AK4113_CHECK_NO_STAT   (1<<0)  /* no statistics */
+#define AK4113_CHECK_NO_RATE   (1<<1)  /* no rate check */
+
+#define AK4113_CONTROLS                13
+
+typedef void (ak4113_write_t)(void *private_data, unsigned char addr,
+               unsigned char data);
+typedef unsigned char (ak4113_read_t)(void *private_data, unsigned char addr);
+
+struct ak4113 {
+       struct snd_card *card;
+       ak4113_write_t *write;
+       ak4113_read_t *read;
+       void *private_data;
+       unsigned int init:1;
+       spinlock_t lock;
+       unsigned char regmap[AK4113_WRITABLE_REGS];
+       struct snd_kcontrol *kctls[AK4113_CONTROLS];
+       struct snd_pcm_substream *substream;
+       unsigned long parity_errors;
+       unsigned long v_bit_errors;
+       unsigned long qcrc_errors;
+       unsigned long ccrc_errors;
+       unsigned char rcs0;
+       unsigned char rcs1;
+       unsigned char rcs2;
+       struct delayed_work work;
+       unsigned int check_flags;
+       void *change_callback_private;
+       void (*change_callback)(struct ak4113 *ak4113, unsigned char c0,
+                       unsigned char c1);
+};
+
+int snd_ak4113_create(struct snd_card *card, ak4113_read_t *read,
+               ak4113_write_t *write,
+               const unsigned char pgm[AK4113_WRITABLE_REGS],
+               void *private_data, struct ak4113 **r_ak4113);
+void snd_ak4113_reg_write(struct ak4113 *ak4113, unsigned char reg,
+               unsigned char mask, unsigned char val);
+void snd_ak4113_reinit(struct ak4113 *ak4113);
+int snd_ak4113_build(struct ak4113 *ak4113,
+               struct snd_pcm_substream *capture_substream);
+int snd_ak4113_external_rate(struct ak4113 *ak4113);
+int snd_ak4113_check_rate_and_errors(struct ak4113 *ak4113, unsigned int flags);
+
+#endif /* __SOUND_AK4113_H */
+
index d293d36..3ce69fd 100644 (file)
 
 /* AK4114_REG_IO0 */
 #define AK4114_TX1E            (1<<7)  /* TX1 Output Enable (1 = enable) */
-#define AK4114_OPS12           (1<<2)  /* Output Though Data Selector for TX1 pin */
-#define AK4114_OPS11           (1<<1)  /* Output Though Data Selector for TX1 pin */
-#define AK4114_OPS10           (1<<0)  /* Output Though Data Selector for TX1 pin */
+#define AK4114_OPS12           (1<<6)  /* Output Data Selector for TX1 pin */
+#define AK4114_OPS11           (1<<5)  /* Output Data Selector for TX1 pin */
+#define AK4114_OPS10           (1<<4)  /* Output Data Selector for TX1 pin */
 #define AK4114_TX0E            (1<<3)  /* TX0 Output Enable (1 = enable) */
-#define AK4114_OPS02           (1<<2)  /* Output Though Data Selector for TX0 pin */
-#define AK4114_OPS01           (1<<1)  /* Output Though Data Selector for TX0 pin */
-#define AK4114_OPS00           (1<<0)  /* Output Though Data Selector for TX0 pin */
+#define AK4114_OPS02           (1<<2)  /* Output Data Selector for TX0 pin */
+#define AK4114_OPS01           (1<<1)  /* Output Data Selector for TX0 pin */
+#define AK4114_OPS00           (1<<0)  /* Output Data Selector for TX0 pin */
 
 /* AK4114_REG_IO1 */
 #define AK4114_EFH1            (1<<7)  /* Interrupt 0 pin Hold */
index 891cf1a..030b87c 100644 (file)
@@ -68,7 +68,7 @@ struct snd_akm4xxx {
        enum {
                SND_AK4524, SND_AK4528, SND_AK4529,
                SND_AK4355, SND_AK4358, SND_AK4381,
-               SND_AK5365
+               SND_AK5365, SND_AK4620,
        } type;
 
        /* (array) information of combined codecs */
@@ -76,6 +76,9 @@ struct snd_akm4xxx {
        const struct snd_akm4xxx_adc_channel *adc_info;
 
        struct snd_ak4xxx_ops ops;
+       unsigned int num_chips;
+       unsigned int total_regs;
+       const char *name;
 };
 
 void snd_akm4xxx_write(struct snd_akm4xxx *ak, int chip, unsigned char reg,
index ef96f07..112374d 100644 (file)
@@ -56,7 +56,6 @@ struct snd_kcontrol_new {
 
 struct snd_kcontrol_volatile {
        struct snd_ctl_file *owner;     /* locked */
-       pid_t owner_pid;
        unsigned int access;    /* access rights */
 };
 
@@ -87,10 +86,12 @@ struct snd_kctl_event {
 
 #define snd_kctl_event(n) list_entry(n, struct snd_kctl_event, list)
 
+struct pid;
+
 struct snd_ctl_file {
        struct list_head list;          /* list of all control files */
        struct snd_card *card;
-       pid_t pid;
+       struct pid *pid;
        int prefer_pcm_subdevice;
        int prefer_rawmidi_subdevice;
        wait_queue_head_t change_sleep;
index 9264753..66d28c2 100644 (file)
@@ -70,7 +70,6 @@
 #define AD1845_PWR_DOWN                0x1b    /* power down control */
 #define CS4235_LEFT_MASTER     0x1b    /* left master output control */
 #define CS4231_REC_FORMAT      0x1c    /* clock and data format - record - bits 7-0 MCE */
-#define CS4231_PLY_VAR_FREQ    0x1d    /* playback variable frequency */
 #define AD1845_CLOCK           0x1d    /* crystal clock select and total power down */
 #define CS4235_RIGHT_MASTER    0x1d    /* right master output control */
 #define CS4231_REC_UPR_CNT     0x1e    /* record upper count */
index de6d981..c83a4a7 100644 (file)
@@ -348,6 +348,8 @@ struct snd_pcm_group {              /* keep linked substreams */
        int count;
 };
 
+struct pid;
+
 struct snd_pcm_substream {
        struct snd_pcm *pcm;
        struct snd_pcm_str *pstr;
@@ -379,6 +381,7 @@ struct snd_pcm_substream {
        atomic_t mmap_count;
        unsigned int f_flags;
        void (*pcm_release)(struct snd_pcm_substream *);
+       struct pid *pid;
 #if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE)
        /* -- OSS things -- */
        struct snd_pcm_oss_substream oss;
index c23c265..2480e7d 100644 (file)
@@ -46,6 +46,7 @@
 struct snd_rawmidi;
 struct snd_rawmidi_substream;
 struct snd_seq_port_info;
+struct pid;
 
 struct snd_rawmidi_ops {
        int (*open) (struct snd_rawmidi_substream * substream);
@@ -97,6 +98,7 @@ struct snd_rawmidi_substream {
        struct snd_rawmidi_str *pstr;
        char name[32];
        struct snd_rawmidi_runtime *runtime;
+       struct pid *pid;
        /* hardware layer */
        struct snd_rawmidi_ops *ops;
 };
diff --git a/include/sound/sh_dac_audio.h b/include/sound/sh_dac_audio.h
new file mode 100644 (file)
index 0000000..f5deaf1
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ * SH_DAC specific configuration, for the dac_audio platform_device
+ *
+ * Copyright (C) 2009 Rafael Ignacio Zurita <rizurita@yahoo.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 __INCLUDE_SH_DAC_AUDIO_H
+#define __INCLUDE_SH_DAC_AUDIO_H
+
+struct dac_audio_pdata {
+       int buffer_size;
+       int channel;
+       void (*start)(struct dac_audio_pdata *pd);
+       void (*stop)(struct dac_audio_pdata *pd);
+};
+
+#endif /* __INCLUDE_SH_DAC_AUDIO_H */
index 97ca9af..ca24e7f 100644 (file)
@@ -30,6 +30,7 @@ struct snd_pcm_substream;
 #define SND_SOC_DAIFMT_DSP_A           3 /* L data MSB after FRM LRC */
 #define SND_SOC_DAIFMT_DSP_B           4 /* L data MSB during FRM LRC */
 #define SND_SOC_DAIFMT_AC97            5 /* AC97 */
+#define SND_SOC_DAIFMT_PDM             6 /* Pulse density modulation */
 
 /* left and right justified also known as MSB and LSB respectively */
 #define SND_SOC_DAIFMT_MSB             SND_SOC_DAIFMT_LEFT_J
@@ -106,7 +107,7 @@ int snd_soc_dai_set_clkdiv(struct snd_soc_dai *dai,
        int div_id, int div);
 
 int snd_soc_dai_set_pll(struct snd_soc_dai *dai,
-       int pll_id, unsigned int freq_in, unsigned int freq_out);
+       int pll_id, int source, unsigned int freq_in, unsigned int freq_out);
 
 /* Digital Audio interface formatting */
 int snd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt);
@@ -114,6 +115,10 @@ int snd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt);
 int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai,
        unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width);
 
+int snd_soc_dai_set_channel_map(struct snd_soc_dai *dai,
+       unsigned int tx_num, unsigned int *tx_slot,
+       unsigned int rx_num, unsigned int *rx_slot);
+
 int snd_soc_dai_set_tristate(struct snd_soc_dai *dai, int tristate);
 
 /* Digital Audio Interface mute */
@@ -136,8 +141,8 @@ struct snd_soc_dai_ops {
         */
        int (*set_sysclk)(struct snd_soc_dai *dai,
                int clk_id, unsigned int freq, int dir);
-       int (*set_pll)(struct snd_soc_dai *dai,
-               int pll_id, unsigned int freq_in, unsigned int freq_out);
+       int (*set_pll)(struct snd_soc_dai *dai, int pll_id, int source,
+               unsigned int freq_in, unsigned int freq_out);
        int (*set_clkdiv)(struct snd_soc_dai *dai, int div_id, int div);
 
        /*
@@ -148,6 +153,9 @@ struct snd_soc_dai_ops {
        int (*set_tdm_slot)(struct snd_soc_dai *dai,
                unsigned int tx_mask, unsigned int rx_mask,
                int slots, int slot_width);
+       int (*set_channel_map)(struct snd_soc_dai *dai,
+               unsigned int tx_num, unsigned int *tx_slot,
+               unsigned int rx_num, unsigned int *rx_slot);
        int (*set_tristate)(struct snd_soc_dai *dai, int tristate);
 
        /*
index c1410e3..c5c95e1 100644 (file)
        .get = snd_soc_dapm_get_enum_double, \
        .put = snd_soc_dapm_put_enum_double, \
        .private_value = (unsigned long)&xenum }
+#define SOC_DAPM_ENUM_VIRT(xname, xenum)                   \
+{      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+       .info = snd_soc_info_enum_double, \
+       .get = snd_soc_dapm_get_enum_virt, \
+       .put = snd_soc_dapm_put_enum_virt, \
+       .private_value = (unsigned long)&xenum }
 #define SOC_DAPM_VALUE_ENUM(xname, xenum) \
 {      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
        .info = snd_soc_info_enum_double, \
@@ -260,6 +266,10 @@ int snd_soc_dapm_get_enum_double(struct snd_kcontrol *kcontrol,
        struct snd_ctl_elem_value *ucontrol);
 int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol,
        struct snd_ctl_elem_value *ucontrol);
+int snd_soc_dapm_get_enum_virt(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol);
+int snd_soc_dapm_put_enum_virt(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol);
 int snd_soc_dapm_get_value_enum_double(struct snd_kcontrol *kcontrol,
        struct snd_ctl_elem_value *ucontrol);
 int snd_soc_dapm_put_value_enum_double(struct snd_kcontrol *kcontrol,
@@ -333,6 +343,10 @@ struct snd_soc_dapm_route {
        const char *sink;
        const char *control;
        const char *source;
+
+       /* Note: currently only supported for links where source is a supply */
+       int (*connected)(struct snd_soc_dapm_widget *source,
+                        struct snd_soc_dapm_widget *sink);
 };
 
 /* dapm audio path between two widgets */
@@ -349,6 +363,9 @@ struct snd_soc_dapm_path {
        u32 connect:1;  /* source and sink widgets are connected */
        u32 walked:1;   /* path has been walked */
 
+       int (*connected)(struct snd_soc_dapm_widget *source,
+                        struct snd_soc_dapm_widget *sink);
+
        struct list_head list_source;
        struct list_head list_sink;
        struct list_head list;
index 475cb7e..0d7718f 100644 (file)
@@ -223,15 +223,15 @@ int snd_soc_codec_set_cache_io(struct snd_soc_codec *codec,
                               int addr_bits, int data_bits,
                               enum snd_soc_control_type control);
 
-#ifdef CONFIG_PM
-int snd_soc_suspend_device(struct device *dev);
-int snd_soc_resume_device(struct device *dev);
-#endif
-
 /* pcm <-> DAI connect */
 void snd_soc_free_pcms(struct snd_soc_device *socdev);
 int snd_soc_new_pcms(struct snd_soc_device *socdev, int idx, const char *xid);
-int snd_soc_init_card(struct snd_soc_device *socdev);
+
+/* Utility functions to get clock rates from various things */
+int snd_soc_calc_frame_size(int sample_size, int channels, int tdm_slots);
+int snd_soc_params_to_frame_size(struct snd_pcm_hw_params *params);
+int snd_soc_calc_bclk(int fs, int sample_size, int channels, int tdm_slots);
+int snd_soc_params_to_bclk(struct snd_pcm_hw_params *parms);
 
 /* set runtime hw params */
 int snd_soc_set_runtime_hwparams(struct snd_pcm_substream *substream,
@@ -333,6 +333,8 @@ struct snd_soc_jack_gpio {
        int debounce_time;
        struct snd_soc_jack *jack;
        struct work_struct work;
+
+       int (*jack_status_check)(void);
 };
 #endif
 
@@ -413,6 +415,7 @@ struct snd_soc_codec {
        unsigned int num_dai;
 
 #ifdef CONFIG_DEBUG_FS
+       struct dentry *debugfs_codec_root;
        struct dentry *debugfs_reg;
        struct dentry *debugfs_pop_time;
        struct dentry *debugfs_dapm;
diff --git a/include/sound/sscape_ioctl.h b/include/sound/sscape_ioctl.h
deleted file mode 100644 (file)
index 0d88859..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-#ifndef SSCAPE_IOCTL_H
-#define SSCAPE_IOCTL_H
-
-
-struct sscape_bootblock
-{
-  unsigned char code[256];
-  unsigned version;
-};
-
-#define SSCAPE_MICROCODE_SIZE  65536
-
-struct sscape_microcode
-{
-  unsigned char __user *code;
-};
-
-#define SND_SSCAPE_LOAD_BOOTB  _IOWR('P', 100, struct sscape_bootblock)
-#define SND_SSCAPE_LOAD_MCODE  _IOW ('P', 101, struct sscape_microcode)
-
-#endif
diff --git a/include/sound/tlv320dac33-plat.h b/include/sound/tlv320dac33-plat.h
new file mode 100644 (file)
index 0000000..5858d06
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ * Platform header for Texas Instruments TLV320DAC33 codec driver
+ *
+ * Author:     Peter Ujfalusi <peter.ujfalusi@nokia.com>
+ *
+ * Copyright:   (C) 2009 Nokia Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __TLV320DAC33_PLAT_H
+#define __TLV320DAC33_PLAT_H
+
+struct tlv320dac33_platform_data {
+       int power_gpio;
+};
+
+#endif /* __TLV320DAC33_PLAT_H */
diff --git a/include/sound/tpa6130a2-plat.h b/include/sound/tpa6130a2-plat.h
new file mode 100644 (file)
index 0000000..e8c901e
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * TPA6130A2 driver platform header
+ *
+ * Copyright (C) Nokia Corporation
+ *
+ * Written by Peter Ujfalusi <peter.ujfalusi@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#ifndef TPA6130A2_PLAT_H
+#define TPA6130A2_PLAT_H
+
+struct tpa6130a2_platform_data {
+       int power_gpio;
+};
+
+#endif
index 6d65f32..fd01f22 100644 (file)
@@ -154,7 +154,6 @@ int snd_wss_create(struct snd_card *card,
                      unsigned short hardware,
                      unsigned short hwshare,
                      struct snd_wss **rchip);
-int snd_wss_free(struct snd_wss *chip);
 int snd_wss_pcm(struct snd_wss *chip, int device, struct snd_pcm **rpcm);
 int snd_wss_timer(struct snd_wss *chip, int device, struct snd_timer **rtimer);
 int snd_wss_mixer(struct snd_wss *chip);
index 2a4b3bf..5acfb1e 100644 (file)
                assign, print, reg, unreg)                      \
        DEFINE_TRACE_FN(name, reg, unreg)
 
+#undef DEFINE_EVENT
+#define DEFINE_EVENT(template, name, proto, args) \
+       DEFINE_TRACE(name)
+
+#undef DEFINE_EVENT_PRINT
+#define DEFINE_EVENT_PRINT(template, name, proto, args, print) \
+       DEFINE_TRACE(name)
+
 #undef DECLARE_TRACE
 #define DECLARE_TRACE(name, proto, args)       \
        DEFINE_TRACE(name)
@@ -63,6 +71,9 @@
 
 #undef TRACE_EVENT
 #undef TRACE_EVENT_FN
+#undef DECLARE_EVENT_CLASS
+#undef DEFINE_EVENT
+#undef DEFINE_EVENT_PRINT
 #undef TRACE_HEADER_MULTI_READ
 
 /* Only undef what we defined in this file */
index 8abd620..1af72dc 100644 (file)
@@ -13,7 +13,7 @@ TRACE_EVENT(lock_kernel,
        TP_ARGS(func, file, line),
 
        TP_STRUCT__entry(
-               __field(        int,            lock_depth              )
+               __field(        int,            depth                   )
                __field_ext(    const char *,   func, FILTER_PTR_STRING )
                __field_ext(    const char *,   file, FILTER_PTR_STRING )
                __field(        int,            line                    )
@@ -21,13 +21,13 @@ TRACE_EVENT(lock_kernel,
 
        TP_fast_assign(
                /* We want to record the lock_depth after lock is acquired */
-               __entry->lock_depth = current->lock_depth + 1;
+               __entry->depth = current->lock_depth + 1;
                __entry->func = func;
                __entry->file = file;
                __entry->line = line;
        ),
 
-       TP_printk("depth: %d, %s:%d %s()", __entry->lock_depth,
+       TP_printk("depth=%d file:line=%s:%d func=%s()", __entry->depth,
                  __entry->file, __entry->line, __entry->func)
 );
 
@@ -38,20 +38,20 @@ TRACE_EVENT(unlock_kernel,
        TP_ARGS(func, file, line),
 
        TP_STRUCT__entry(
-               __field(int,            lock_depth)
-               __field(const char *,   func)
-               __field(const char *,   file)
-               __field(int,            line)
+               __field(int,            depth           )
+               __field(const char *,   func            )
+               __field(const char *,   file            )
+               __field(int,            line            )
        ),
 
        TP_fast_assign(
-               __entry->lock_depth = current->lock_depth;
+               __entry->depth = current->lock_depth;
                __entry->func = func;
                __entry->file = file;
                __entry->line = line;
        ),
 
-       TP_printk("depth: %d, %s:%d %s()", __entry->lock_depth,
+       TP_printk("depth=%d file:line=%s:%d func=%s()", __entry->depth,
                  __entry->file, __entry->line, __entry->func)
 );
 
index 00405b5..5fb7273 100644 (file)
@@ -8,7 +8,7 @@
 #include <linux/blkdev.h>
 #include <linux/tracepoint.h>
 
-TRACE_EVENT(block_rq_abort,
+DECLARE_EVENT_CLASS(block_rq_with_error,
 
        TP_PROTO(struct request_queue *q, struct request *rq),
 
@@ -40,41 +40,28 @@ TRACE_EVENT(block_rq_abort,
                  __entry->nr_sector, __entry->errors)
 );
 
-TRACE_EVENT(block_rq_insert,
+DEFINE_EVENT(block_rq_with_error, block_rq_abort,
 
        TP_PROTO(struct request_queue *q, struct request *rq),
 
-       TP_ARGS(q, rq),
+       TP_ARGS(q, rq)
+);
 
-       TP_STRUCT__entry(
-               __field(  dev_t,        dev                     )
-               __field(  sector_t,     sector                  )
-               __field(  unsigned int, nr_sector               )
-               __field(  unsigned int, bytes                   )
-               __array(  char,         rwbs,   6               )
-               __array(  char,         comm,   TASK_COMM_LEN   )
-               __dynamic_array( char,  cmd,    blk_cmd_buf_len(rq)     )
-       ),
+DEFINE_EVENT(block_rq_with_error, block_rq_requeue,
 
-       TP_fast_assign(
-               __entry->dev       = rq->rq_disk ? disk_devt(rq->rq_disk) : 0;
-               __entry->sector    = blk_pc_request(rq) ? 0 : blk_rq_pos(rq);
-               __entry->nr_sector = blk_pc_request(rq) ? 0 : blk_rq_sectors(rq);
-               __entry->bytes     = blk_pc_request(rq) ? blk_rq_bytes(rq) : 0;
+       TP_PROTO(struct request_queue *q, struct request *rq),
 
-               blk_fill_rwbs_rq(__entry->rwbs, rq);
-               blk_dump_cmd(__get_str(cmd), rq);
-               memcpy(__entry->comm, current->comm, TASK_COMM_LEN);
-       ),
+       TP_ARGS(q, rq)
+);
 
-       TP_printk("%d,%d %s %u (%s) %llu + %u [%s]",
-                 MAJOR(__entry->dev), MINOR(__entry->dev),
-                 __entry->rwbs, __entry->bytes, __get_str(cmd),
-                 (unsigned long long)__entry->sector,
-                 __entry->nr_sector, __entry->comm)
+DEFINE_EVENT(block_rq_with_error, block_rq_complete,
+
+       TP_PROTO(struct request_queue *q, struct request *rq),
+
+       TP_ARGS(q, rq)
 );
 
-TRACE_EVENT(block_rq_issue,
+DECLARE_EVENT_CLASS(block_rq,
 
        TP_PROTO(struct request_queue *q, struct request *rq),
 
@@ -86,7 +73,7 @@ TRACE_EVENT(block_rq_issue,
                __field(  unsigned int, nr_sector               )
                __field(  unsigned int, bytes                   )
                __array(  char,         rwbs,   6               )
-               __array(  char,         comm,   TASK_COMM_LEN   )
+               __array(  char,         comm,   TASK_COMM_LEN   )
                __dynamic_array( char,  cmd,    blk_cmd_buf_len(rq)     )
        ),
 
@@ -108,68 +95,18 @@ TRACE_EVENT(block_rq_issue,
                  __entry->nr_sector, __entry->comm)
 );
 
-TRACE_EVENT(block_rq_requeue,
+DEFINE_EVENT(block_rq, block_rq_insert,
 
        TP_PROTO(struct request_queue *q, struct request *rq),
 
-       TP_ARGS(q, rq),
-
-       TP_STRUCT__entry(
-               __field(  dev_t,        dev                     )
-               __field(  sector_t,     sector                  )
-               __field(  unsigned int, nr_sector               )
-               __field(  int,          errors                  )
-               __array(  char,         rwbs,   6               )
-               __dynamic_array( char,  cmd,    blk_cmd_buf_len(rq)     )
-       ),
-
-       TP_fast_assign(
-               __entry->dev       = rq->rq_disk ? disk_devt(rq->rq_disk) : 0;
-               __entry->sector    = blk_pc_request(rq) ? 0 : blk_rq_pos(rq);
-               __entry->nr_sector = blk_pc_request(rq) ? 0 : blk_rq_sectors(rq);
-               __entry->errors    = rq->errors;
-
-               blk_fill_rwbs_rq(__entry->rwbs, rq);
-               blk_dump_cmd(__get_str(cmd), rq);
-       ),
-
-       TP_printk("%d,%d %s (%s) %llu + %u [%d]",
-                 MAJOR(__entry->dev), MINOR(__entry->dev),
-                 __entry->rwbs, __get_str(cmd),
-                 (unsigned long long)__entry->sector,
-                 __entry->nr_sector, __entry->errors)
+       TP_ARGS(q, rq)
 );
 
-TRACE_EVENT(block_rq_complete,
+DEFINE_EVENT(block_rq, block_rq_issue,
 
        TP_PROTO(struct request_queue *q, struct request *rq),
 
-       TP_ARGS(q, rq),
-
-       TP_STRUCT__entry(
-               __field(  dev_t,        dev                     )
-               __field(  sector_t,     sector                  )
-               __field(  unsigned int, nr_sector               )
-               __field(  int,          errors                  )
-               __array(  char,         rwbs,   6               )
-               __dynamic_array( char,  cmd,    blk_cmd_buf_len(rq)     )
-       ),
-
-       TP_fast_assign(
-               __entry->dev       = rq->rq_disk ? disk_devt(rq->rq_disk) : 0;
-               __entry->sector    = blk_pc_request(rq) ? 0 : blk_rq_pos(rq);
-               __entry->nr_sector = blk_pc_request(rq) ? 0 : blk_rq_sectors(rq);
-               __entry->errors    = rq->errors;
-
-               blk_fill_rwbs_rq(__entry->rwbs, rq);
-               blk_dump_cmd(__get_str(cmd), rq);
-       ),
-
-       TP_printk("%d,%d %s (%s) %llu + %u [%d]",
-                 MAJOR(__entry->dev), MINOR(__entry->dev),
-                 __entry->rwbs, __get_str(cmd),
-                 (unsigned long long)__entry->sector,
-                 __entry->nr_sector, __entry->errors)
+       TP_ARGS(q, rq)
 );
 
 TRACE_EVENT(block_bio_bounce,
@@ -228,7 +165,7 @@ TRACE_EVENT(block_bio_complete,
                  __entry->nr_sector, __entry->error)
 );
 
-TRACE_EVENT(block_bio_backmerge,
+DECLARE_EVENT_CLASS(block_bio,
 
        TP_PROTO(struct request_queue *q, struct bio *bio),
 
@@ -256,63 +193,28 @@ TRACE_EVENT(block_bio_backmerge,
                  __entry->nr_sector, __entry->comm)
 );
 
-TRACE_EVENT(block_bio_frontmerge,
+DEFINE_EVENT(block_bio, block_bio_backmerge,
 
        TP_PROTO(struct request_queue *q, struct bio *bio),
 
-       TP_ARGS(q, bio),
-
-       TP_STRUCT__entry(
-               __field( dev_t,         dev                     )
-               __field( sector_t,      sector                  )
-               __field( unsigned,      nr_sector               )
-               __array( char,          rwbs,   6               )
-               __array( char,          comm,   TASK_COMM_LEN   )
-       ),
-
-       TP_fast_assign(
-               __entry->dev            = bio->bi_bdev->bd_dev;
-               __entry->sector         = bio->bi_sector;
-               __entry->nr_sector      = bio->bi_size >> 9;
-               blk_fill_rwbs(__entry->rwbs, bio->bi_rw, bio->bi_size);
-               memcpy(__entry->comm, current->comm, TASK_COMM_LEN);
-       ),
-
-       TP_printk("%d,%d %s %llu + %u [%s]",
-                 MAJOR(__entry->dev), MINOR(__entry->dev), __entry->rwbs,
-                 (unsigned long long)__entry->sector,
-                 __entry->nr_sector, __entry->comm)
+       TP_ARGS(q, bio)
 );
 
-TRACE_EVENT(block_bio_queue,
+DEFINE_EVENT(block_bio, block_bio_frontmerge,
 
        TP_PROTO(struct request_queue *q, struct bio *bio),
 
-       TP_ARGS(q, bio),
+       TP_ARGS(q, bio)
+);
 
-       TP_STRUCT__entry(
-               __field( dev_t,         dev                     )
-               __field( sector_t,      sector                  )
-               __field( unsigned int,  nr_sector               )
-               __array( char,          rwbs,   6               )
-               __array( char,          comm,   TASK_COMM_LEN   )
-       ),
+DEFINE_EVENT(block_bio, block_bio_queue,
 
-       TP_fast_assign(
-               __entry->dev            = bio->bi_bdev->bd_dev;
-               __entry->sector         = bio->bi_sector;
-               __entry->nr_sector      = bio->bi_size >> 9;
-               blk_fill_rwbs(__entry->rwbs, bio->bi_rw, bio->bi_size);
-               memcpy(__entry->comm, current->comm, TASK_COMM_LEN);
-       ),
+       TP_PROTO(struct request_queue *q, struct bio *bio),
 
-       TP_printk("%d,%d %s %llu + %u [%s]",
-                 MAJOR(__entry->dev), MINOR(__entry->dev), __entry->rwbs,
-                 (unsigned long long)__entry->sector,
-                 __entry->nr_sector, __entry->comm)
+       TP_ARGS(q, bio)
 );
 
-TRACE_EVENT(block_getrq,
+DECLARE_EVENT_CLASS(block_get_rq,
 
        TP_PROTO(struct request_queue *q, struct bio *bio, int rw),
 
@@ -341,33 +243,18 @@ TRACE_EVENT(block_getrq,
                  __entry->nr_sector, __entry->comm)
 );
 
-TRACE_EVENT(block_sleeprq,
+DEFINE_EVENT(block_get_rq, block_getrq,
 
        TP_PROTO(struct request_queue *q, struct bio *bio, int rw),
 
-       TP_ARGS(q, bio, rw),
+       TP_ARGS(q, bio, rw)
+);
 
-       TP_STRUCT__entry(
-               __field( dev_t,         dev                     )
-               __field( sector_t,      sector                  )
-               __field( unsigned int,  nr_sector               )
-               __array( char,          rwbs,   6               )
-               __array( char,          comm,   TASK_COMM_LEN   )
-       ),
+DEFINE_EVENT(block_get_rq, block_sleeprq,
 
-       TP_fast_assign(
-               __entry->dev            = bio ? bio->bi_bdev->bd_dev : 0;
-               __entry->sector         = bio ? bio->bi_sector : 0;
-               __entry->nr_sector      = bio ? bio->bi_size >> 9 : 0;
-               blk_fill_rwbs(__entry->rwbs,
-                           bio ? bio->bi_rw : 0, __entry->nr_sector);
-               memcpy(__entry->comm, current->comm, TASK_COMM_LEN);
-       ),
+       TP_PROTO(struct request_queue *q, struct bio *bio, int rw),
 
-       TP_printk("%d,%d %s %llu + %u [%s]",
-                 MAJOR(__entry->dev), MINOR(__entry->dev), __entry->rwbs,
-                 (unsigned long long)__entry->sector,
-                 __entry->nr_sector, __entry->comm)
+       TP_ARGS(q, bio, rw)
 );
 
 TRACE_EVENT(block_plug,
@@ -387,7 +274,7 @@ TRACE_EVENT(block_plug,
        TP_printk("[%s]", __entry->comm)
 );
 
-TRACE_EVENT(block_unplug_timer,
+DECLARE_EVENT_CLASS(block_unplug,
 
        TP_PROTO(struct request_queue *q),
 
@@ -406,23 +293,18 @@ TRACE_EVENT(block_unplug_timer,
        TP_printk("[%s] %d", __entry->comm, __entry->nr_rq)
 );
 
-TRACE_EVENT(block_unplug_io,
+DEFINE_EVENT(block_unplug, block_unplug_timer,
 
        TP_PROTO(struct request_queue *q),
 
-       TP_ARGS(q),
+       TP_ARGS(q)
+);
 
-       TP_STRUCT__entry(
-               __field( int,           nr_rq                   )
-               __array( char,          comm,   TASK_COMM_LEN   )
-       ),
+DEFINE_EVENT(block_unplug, block_unplug_io,
 
-       TP_fast_assign(
-               __entry->nr_rq  = q->rq.count[READ] + q->rq.count[WRITE];
-               memcpy(__entry->comm, current->comm, TASK_COMM_LEN);
-       ),
+       TP_PROTO(struct request_queue *q),
 
-       TP_printk("[%s] %d", __entry->comm, __entry->nr_rq)
+       TP_ARGS(q)
 );
 
 TRACE_EVENT(block_split,
index d09550b..318f765 100644 (file)
@@ -90,7 +90,7 @@ TRACE_EVENT(ext4_allocate_inode,
                  (unsigned long) __entry->dir, __entry->mode)
 );
 
-TRACE_EVENT(ext4_write_begin,
+DECLARE_EVENT_CLASS(ext4__write_begin,
 
        TP_PROTO(struct inode *inode, loff_t pos, unsigned int len,
                 unsigned int flags),
@@ -118,7 +118,23 @@ TRACE_EVENT(ext4_write_begin,
                  __entry->pos, __entry->len, __entry->flags)
 );
 
-TRACE_EVENT(ext4_ordered_write_end,
+DEFINE_EVENT(ext4__write_begin, ext4_write_begin,
+
+       TP_PROTO(struct inode *inode, loff_t pos, unsigned int len,
+                unsigned int flags),
+
+       TP_ARGS(inode, pos, len, flags)
+);
+
+DEFINE_EVENT(ext4__write_begin, ext4_da_write_begin,
+
+       TP_PROTO(struct inode *inode, loff_t pos, unsigned int len,
+                unsigned int flags),
+
+       TP_ARGS(inode, pos, len, flags)
+);
+
+DECLARE_EVENT_CLASS(ext4__write_end,
        TP_PROTO(struct inode *inode, loff_t pos, unsigned int len,
                        unsigned int copied),
 
@@ -145,57 +161,36 @@ TRACE_EVENT(ext4_ordered_write_end,
                  __entry->pos, __entry->len, __entry->copied)
 );
 
-TRACE_EVENT(ext4_writeback_write_end,
+DEFINE_EVENT(ext4__write_end, ext4_ordered_write_end,
+
        TP_PROTO(struct inode *inode, loff_t pos, unsigned int len,
                 unsigned int copied),
 
-       TP_ARGS(inode, pos, len, copied),
+       TP_ARGS(inode, pos, len, copied)
+);
 
-       TP_STRUCT__entry(
-               __field(        dev_t,  dev                     )
-               __field(        ino_t,  ino                     )
-               __field(        loff_t, pos                     )
-               __field(        unsigned int, len               )
-               __field(        unsigned int, copied            )
-       ),
+DEFINE_EVENT(ext4__write_end, ext4_writeback_write_end,
 
-       TP_fast_assign(
-               __entry->dev    = inode->i_sb->s_dev;
-               __entry->ino    = inode->i_ino;
-               __entry->pos    = pos;
-               __entry->len    = len;
-               __entry->copied = copied;
-       ),
+       TP_PROTO(struct inode *inode, loff_t pos, unsigned int len,
+                unsigned int copied),
 
-       TP_printk("dev %s ino %lu pos %llu len %u copied %u",
-                 jbd2_dev_to_name(__entry->dev), (unsigned long) __entry->ino,
-                 __entry->pos, __entry->len, __entry->copied)
+       TP_ARGS(inode, pos, len, copied)
 );
 
-TRACE_EVENT(ext4_journalled_write_end,
+DEFINE_EVENT(ext4__write_end, ext4_journalled_write_end,
+
        TP_PROTO(struct inode *inode, loff_t pos, unsigned int len,
                 unsigned int copied),
-       TP_ARGS(inode, pos, len, copied),
 
-       TP_STRUCT__entry(
-               __field(        dev_t,  dev                     )
-               __field(        ino_t,  ino                     )
-               __field(        loff_t, pos                     )
-               __field(        unsigned int, len               )
-               __field(        unsigned int, copied            )
-       ),
+       TP_ARGS(inode, pos, len, copied)
+);
 
-       TP_fast_assign(
-               __entry->dev    = inode->i_sb->s_dev;
-               __entry->ino    = inode->i_ino;
-               __entry->pos    = pos;
-               __entry->len    = len;
-               __entry->copied = copied;
-       ),
+DEFINE_EVENT(ext4__write_end, ext4_da_write_end,
 
-       TP_printk("dev %s ino %lu pos %llu len %u copied %u",
-                 jbd2_dev_to_name(__entry->dev), (unsigned long) __entry->ino,
-                 __entry->pos, __entry->len, __entry->copied)
+       TP_PROTO(struct inode *inode, loff_t pos, unsigned int len,
+                unsigned int copied),
+
+       TP_ARGS(inode, pos, len, copied)
 );
 
 TRACE_EVENT(ext4_writepage,
@@ -337,60 +332,6 @@ TRACE_EVENT(ext4_da_writepages_result,
                  (unsigned long) __entry->writeback_index)
 );
 
-TRACE_EVENT(ext4_da_write_begin,
-       TP_PROTO(struct inode *inode, loff_t pos, unsigned int len,
-                       unsigned int flags),
-
-       TP_ARGS(inode, pos, len, flags),
-
-       TP_STRUCT__entry(
-               __field(        dev_t,  dev                     )
-               __field(        ino_t,  ino                     )
-               __field(        loff_t, pos                     )
-               __field(        unsigned int, len               )
-               __field(        unsigned int, flags             )
-       ),
-
-       TP_fast_assign(
-               __entry->dev    = inode->i_sb->s_dev;
-               __entry->ino    = inode->i_ino;
-               __entry->pos    = pos;
-               __entry->len    = len;
-               __entry->flags  = flags;
-       ),
-
-       TP_printk("dev %s ino %lu pos %llu len %u flags %u",
-                 jbd2_dev_to_name(__entry->dev), (unsigned long) __entry->ino,
-                 __entry->pos, __entry->len, __entry->flags)
-);
-
-TRACE_EVENT(ext4_da_write_end,
-       TP_PROTO(struct inode *inode, loff_t pos, unsigned int len,
-                       unsigned int copied),
-
-       TP_ARGS(inode, pos, len, copied),
-
-       TP_STRUCT__entry(
-               __field(        dev_t,  dev                     )
-               __field(        ino_t,  ino                     )
-               __field(        loff_t, pos                     )
-               __field(        unsigned int, len               )
-               __field(        unsigned int, copied            )
-       ),
-
-       TP_fast_assign(
-               __entry->dev    = inode->i_sb->s_dev;
-               __entry->ino    = inode->i_ino;
-               __entry->pos    = pos;
-               __entry->len    = len;
-               __entry->copied = copied;
-       ),
-
-       TP_printk("dev %s ino %lu pos %llu len %u copied %u",
-                 jbd2_dev_to_name(__entry->dev), (unsigned long) __entry->ino,
-                 __entry->pos, __entry->len, __entry->copied)
-);
-
 TRACE_EVENT(ext4_discard_blocks,
        TP_PROTO(struct super_block *sb, unsigned long long blk,
                        unsigned long long count),
index b89f9db..0e4cfb6 100644 (file)
@@ -48,7 +48,7 @@ TRACE_EVENT(irq_handler_entry,
                __assign_str(name, action->name);
        ),
 
-       TP_printk("irq=%d handler=%s", __entry->irq, __get_str(name))
+       TP_printk("irq=%d name=%s", __entry->irq, __get_str(name))
 );
 
 /**
@@ -78,22 +78,11 @@ TRACE_EVENT(irq_handler_exit,
                __entry->ret    = ret;
        ),
 
-       TP_printk("irq=%d return=%s",
+       TP_printk("irq=%d ret=%s",
                  __entry->irq, __entry->ret ? "handled" : "unhandled")
 );
 
-/**
- * softirq_entry - called immediately before the softirq handler
- * @h: pointer to struct softirq_action
- * @vec: pointer to first struct softirq_action in softirq_vec array
- *
- * The @h parameter, contains a pointer to the struct softirq_action
- * which has a pointer to the action handler that is called. By subtracting
- * the @vec pointer from the @h pointer, we can determine the softirq
- * number. Also, when used in combination with the softirq_exit tracepoint
- * we can determine the softirq latency.
- */
-TRACE_EVENT(softirq_entry,
+DECLARE_EVENT_CLASS(softirq,
 
        TP_PROTO(struct softirq_action *h, struct softirq_action *vec),
 
@@ -107,11 +96,29 @@ TRACE_EVENT(softirq_entry,
                __entry->vec = (int)(h - vec);
        ),
 
-       TP_printk("softirq=%d action=%s", __entry->vec,
+       TP_printk("vec=%d [action=%s]", __entry->vec,
                  show_softirq_name(__entry->vec))
 );
 
 /**
+ * softirq_entry - called immediately before the softirq handler
+ * @h: pointer to struct softirq_action
+ * @vec: pointer to first struct softirq_action in softirq_vec array
+ *
+ * The @h parameter, contains a pointer to the struct softirq_action
+ * which has a pointer to the action handler that is called. By subtracting
+ * the @vec pointer from the @h pointer, we can determine the softirq
+ * number. Also, when used in combination with the softirq_exit tracepoint
+ * we can determine the softirq latency.
+ */
+DEFINE_EVENT(softirq, softirq_entry,
+
+       TP_PROTO(struct softirq_action *h, struct softirq_action *vec),
+
+       TP_ARGS(h, vec)
+);
+
+/**
  * softirq_exit - called immediately after the softirq handler returns
  * @h: pointer to struct softirq_action
  * @vec: pointer to first struct softirq_action in softirq_vec array
@@ -122,22 +129,11 @@ TRACE_EVENT(softirq_entry,
  * combination with the softirq_entry tracepoint we can determine the softirq
  * latency.
  */
-TRACE_EVENT(softirq_exit,
+DEFINE_EVENT(softirq, softirq_exit,
 
        TP_PROTO(struct softirq_action *h, struct softirq_action *vec),
 
-       TP_ARGS(h, vec),
-
-       TP_STRUCT__entry(
-               __field(        int,    vec                     )
-       ),
-
-       TP_fast_assign(
-               __entry->vec = (int)(h - vec);
-       ),
-
-       TP_printk("softirq=%d action=%s", __entry->vec,
-                 show_softirq_name(__entry->vec))
+       TP_ARGS(h, vec)
 );
 
 #endif /*  _TRACE_IRQ_H */
index 3c60b75..96b370a 100644 (file)
@@ -30,7 +30,7 @@ TRACE_EVENT(jbd2_checkpoint,
                  jbd2_dev_to_name(__entry->dev), __entry->result)
 );
 
-TRACE_EVENT(jbd2_start_commit,
+DECLARE_EVENT_CLASS(jbd2_commit,
 
        TP_PROTO(journal_t *journal, transaction_t *commit_transaction),
 
@@ -53,73 +53,32 @@ TRACE_EVENT(jbd2_start_commit,
                  __entry->sync_commit)
 );
 
-TRACE_EVENT(jbd2_commit_locking,
+DEFINE_EVENT(jbd2_commit, jbd2_start_commit,
 
        TP_PROTO(journal_t *journal, transaction_t *commit_transaction),
 
-       TP_ARGS(journal, commit_transaction),
-
-       TP_STRUCT__entry(
-               __field(        dev_t,  dev                     )
-               __field(        char,   sync_commit               )
-               __field(        int,    transaction               )
-       ),
-
-       TP_fast_assign(
-               __entry->dev            = journal->j_fs_dev->bd_dev;
-               __entry->sync_commit = commit_transaction->t_synchronous_commit;
-               __entry->transaction    = commit_transaction->t_tid;
-       ),
-
-       TP_printk("dev %s transaction %d sync %d",
-                 jbd2_dev_to_name(__entry->dev), __entry->transaction,
-                 __entry->sync_commit)
+       TP_ARGS(journal, commit_transaction)
 );
 
-TRACE_EVENT(jbd2_commit_flushing,
+DEFINE_EVENT(jbd2_commit, jbd2_commit_locking,
 
        TP_PROTO(journal_t *journal, transaction_t *commit_transaction),
 
-       TP_ARGS(journal, commit_transaction),
-
-       TP_STRUCT__entry(
-               __field(        dev_t,  dev                     )
-               __field(        char,   sync_commit               )
-               __field(        int,    transaction               )
-       ),
-
-       TP_fast_assign(
-               __entry->dev            = journal->j_fs_dev->bd_dev;
-               __entry->sync_commit = commit_transaction->t_synchronous_commit;
-               __entry->transaction    = commit_transaction->t_tid;
-       ),
-
-       TP_printk("dev %s transaction %d sync %d",
-                 jbd2_dev_to_name(__entry->dev), __entry->transaction,
-                 __entry->sync_commit)
+       TP_ARGS(journal, commit_transaction)
 );
 
-TRACE_EVENT(jbd2_commit_logging,
+DEFINE_EVENT(jbd2_commit, jbd2_commit_flushing,
 
        TP_PROTO(journal_t *journal, transaction_t *commit_transaction),
 
-       TP_ARGS(journal, commit_transaction),
+       TP_ARGS(journal, commit_transaction)
+);
 
-       TP_STRUCT__entry(
-               __field(        dev_t,  dev                     )
-               __field(        char,   sync_commit               )
-               __field(        int,    transaction               )
-       ),
+DEFINE_EVENT(jbd2_commit, jbd2_commit_logging,
 
-       TP_fast_assign(
-               __entry->dev            = journal->j_fs_dev->bd_dev;
-               __entry->sync_commit = commit_transaction->t_synchronous_commit;
-               __entry->transaction    = commit_transaction->t_tid;
-       ),
+       TP_PROTO(journal_t *journal, transaction_t *commit_transaction),
 
-       TP_printk("dev %s transaction %d sync %d",
-                 jbd2_dev_to_name(__entry->dev), __entry->transaction,
-                 __entry->sync_commit)
+       TP_ARGS(journal, commit_transaction)
 );
 
 TRACE_EVENT(jbd2_end_commit,
index eaf46bd..3adca0c 100644 (file)
@@ -44,7 +44,7 @@
        {(unsigned long)__GFP_MOVABLE,          "GFP_MOVABLE"}          \
        ) : "GFP_NOWAIT"
 
-TRACE_EVENT(kmalloc,
+DECLARE_EVENT_CLASS(kmem_alloc,
 
        TP_PROTO(unsigned long call_site,
                 const void *ptr,
@@ -78,41 +78,23 @@ TRACE_EVENT(kmalloc,
                show_gfp_flags(__entry->gfp_flags))
 );
 
-TRACE_EVENT(kmem_cache_alloc,
+DEFINE_EVENT(kmem_alloc, kmalloc,
 
-       TP_PROTO(unsigned long call_site,
-                const void *ptr,
-                size_t bytes_req,
-                size_t bytes_alloc,
-                gfp_t gfp_flags),
+       TP_PROTO(unsigned long call_site, const void *ptr,
+                size_t bytes_req, size_t bytes_alloc, gfp_t gfp_flags),
 
-       TP_ARGS(call_site, ptr, bytes_req, bytes_alloc, gfp_flags),
+       TP_ARGS(call_site, ptr, bytes_req, bytes_alloc, gfp_flags)
+);
 
-       TP_STRUCT__entry(
-               __field(        unsigned long,  call_site       )
-               __field(        const void *,   ptr             )
-               __field(        size_t,         bytes_req       )
-               __field(        size_t,         bytes_alloc     )
-               __field(        gfp_t,          gfp_flags       )
-       ),
+DEFINE_EVENT(kmem_alloc, kmem_cache_alloc,
 
-       TP_fast_assign(
-               __entry->call_site      = call_site;
-               __entry->ptr            = ptr;
-               __entry->bytes_req      = bytes_req;
-               __entry->bytes_alloc    = bytes_alloc;
-               __entry->gfp_flags      = gfp_flags;
-       ),
+       TP_PROTO(unsigned long call_site, const void *ptr,
+                size_t bytes_req, size_t bytes_alloc, gfp_t gfp_flags),
 
-       TP_printk("call_site=%lx ptr=%p bytes_req=%zu bytes_alloc=%zu gfp_flags=%s",
-               __entry->call_site,
-               __entry->ptr,
-               __entry->bytes_req,
-               __entry->bytes_alloc,
-               show_gfp_flags(__entry->gfp_flags))
+       TP_ARGS(call_site, ptr, bytes_req, bytes_alloc, gfp_flags)
 );
 
-TRACE_EVENT(kmalloc_node,
+DECLARE_EVENT_CLASS(kmem_alloc_node,
 
        TP_PROTO(unsigned long call_site,
                 const void *ptr,
@@ -150,45 +132,25 @@ TRACE_EVENT(kmalloc_node,
                __entry->node)
 );
 
-TRACE_EVENT(kmem_cache_alloc_node,
+DEFINE_EVENT(kmem_alloc_node, kmalloc_node,
 
-       TP_PROTO(unsigned long call_site,
-                const void *ptr,
-                size_t bytes_req,
-                size_t bytes_alloc,
-                gfp_t gfp_flags,
-                int node),
+       TP_PROTO(unsigned long call_site, const void *ptr,
+                size_t bytes_req, size_t bytes_alloc,
+                gfp_t gfp_flags, int node),
 
-       TP_ARGS(call_site, ptr, bytes_req, bytes_alloc, gfp_flags, node),
+       TP_ARGS(call_site, ptr, bytes_req, bytes_alloc, gfp_flags, node)
+);
 
-       TP_STRUCT__entry(
-               __field(        unsigned long,  call_site       )
-               __field(        const void *,   ptr             )
-               __field(        size_t,         bytes_req       )
-               __field(        size_t,         bytes_alloc     )
-               __field(        gfp_t,          gfp_flags       )
-               __field(        int,            node            )
-       ),
+DEFINE_EVENT(kmem_alloc_node, kmem_cache_alloc_node,
 
-       TP_fast_assign(
-               __entry->call_site      = call_site;
-               __entry->ptr            = ptr;
-               __entry->bytes_req      = bytes_req;
-               __entry->bytes_alloc    = bytes_alloc;
-               __entry->gfp_flags      = gfp_flags;
-               __entry->node           = node;
-       ),
+       TP_PROTO(unsigned long call_site, const void *ptr,
+                size_t bytes_req, size_t bytes_alloc,
+                gfp_t gfp_flags, int node),
 
-       TP_printk("call_site=%lx ptr=%p bytes_req=%zu bytes_alloc=%zu gfp_flags=%s node=%d",
-               __entry->call_site,
-               __entry->ptr,
-               __entry->bytes_req,
-               __entry->bytes_alloc,
-               show_gfp_flags(__entry->gfp_flags),
-               __entry->node)
+       TP_ARGS(call_site, ptr, bytes_req, bytes_alloc, gfp_flags, node)
 );
 
-TRACE_EVENT(kfree,
+DECLARE_EVENT_CLASS(kmem_free,
 
        TP_PROTO(unsigned long call_site, const void *ptr),
 
@@ -207,23 +169,18 @@ TRACE_EVENT(kfree,
        TP_printk("call_site=%lx ptr=%p", __entry->call_site, __entry->ptr)
 );
 
-TRACE_EVENT(kmem_cache_free,
+DEFINE_EVENT(kmem_free, kfree,
 
        TP_PROTO(unsigned long call_site, const void *ptr),
 
-       TP_ARGS(call_site, ptr),
+       TP_ARGS(call_site, ptr)
+);
 
-       TP_STRUCT__entry(
-               __field(        unsigned long,  call_site       )
-               __field(        const void *,   ptr             )
-       ),
+DEFINE_EVENT(kmem_free, kmem_cache_free,
 
-       TP_fast_assign(
-               __entry->call_site      = call_site;
-               __entry->ptr            = ptr;
-       ),
+       TP_PROTO(unsigned long call_site, const void *ptr),
 
-       TP_printk("call_site=%lx ptr=%p", __entry->call_site, __entry->ptr)
+       TP_ARGS(call_site, ptr)
 );
 
 TRACE_EVENT(mm_page_free_direct,
@@ -299,7 +256,7 @@ TRACE_EVENT(mm_page_alloc,
                show_gfp_flags(__entry->gfp_flags))
 );
 
-TRACE_EVENT(mm_page_alloc_zone_locked,
+DECLARE_EVENT_CLASS(mm_page,
 
        TP_PROTO(struct page *page, unsigned int order, int migratetype),
 
@@ -325,29 +282,22 @@ TRACE_EVENT(mm_page_alloc_zone_locked,
                __entry->order == 0)
 );
 
-TRACE_EVENT(mm_page_pcpu_drain,
+DEFINE_EVENT(mm_page, mm_page_alloc_zone_locked,
 
-       TP_PROTO(struct page *page, int order, int migratetype),
+       TP_PROTO(struct page *page, unsigned int order, int migratetype),
 
-       TP_ARGS(page, order, migratetype),
+       TP_ARGS(page, order, migratetype)
+);
 
-       TP_STRUCT__entry(
-               __field(        struct page *,  page            )
-               __field(        int,            order           )
-               __field(        int,            migratetype     )
-       ),
+DEFINE_EVENT_PRINT(mm_page, mm_page_pcpu_drain,
 
-       TP_fast_assign(
-               __entry->page           = page;
-               __entry->order          = order;
-               __entry->migratetype    = migratetype;
-       ),
+       TP_PROTO(struct page *page, unsigned int order, int migratetype),
+
+       TP_ARGS(page, order, migratetype),
 
        TP_printk("page=%p pfn=%lu order=%d migratetype=%d",
-               __entry->page,
-               page_to_pfn(__entry->page),
-               __entry->order,
-               __entry->migratetype)
+               __entry->page, page_to_pfn(__entry->page),
+               __entry->order, __entry->migratetype)
 );
 
 TRACE_EVENT(mm_page_alloc_extfrag,
similarity index 92%
rename from include/trace/events/lockdep.h
rename to include/trace/events/lock.h
index bcf1d20..a870ba1 100644 (file)
@@ -1,8 +1,8 @@
 #undef TRACE_SYSTEM
-#define TRACE_SYSTEM lockdep
+#define TRACE_SYSTEM lock
 
-#if !defined(_TRACE_LOCKDEP_H) || defined(TRACE_HEADER_MULTI_READ)
-#define _TRACE_LOCKDEP_H
+#if !defined(_TRACE_LOCK_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_LOCK_H
 
 #include <linux/lockdep.h>
 #include <linux/tracepoint.h>
@@ -90,7 +90,7 @@ TRACE_EVENT(lock_acquired,
 #endif
 #endif
 
-#endif /* _TRACE_LOCKDEP_H */
+#endif /* _TRACE_LOCK_H */
 
 /* This part must be outside protection */
 #include <trace/define_trace.h>
diff --git a/include/trace/events/mce.h b/include/trace/events/mce.h
new file mode 100644 (file)
index 0000000..7eee778
--- /dev/null
@@ -0,0 +1,69 @@
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM mce
+
+#if !defined(_TRACE_MCE_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_MCE_H
+
+#include <linux/ktime.h>
+#include <linux/tracepoint.h>
+#include <asm/mce.h>
+
+TRACE_EVENT(mce_record,
+
+       TP_PROTO(struct mce *m),
+
+       TP_ARGS(m),
+
+       TP_STRUCT__entry(
+               __field(        u64,            mcgcap          )
+               __field(        u64,            mcgstatus       )
+               __field(        u8,             bank            )
+               __field(        u64,            status          )
+               __field(        u64,            addr            )
+               __field(        u64,            misc            )
+               __field(        u64,            ip              )
+               __field(        u8,             cs              )
+               __field(        u64,            tsc             )
+               __field(        u64,            walltime        )
+               __field(        u32,            cpu             )
+               __field(        u32,            cpuid           )
+               __field(        u32,            apicid          )
+               __field(        u32,            socketid        )
+               __field(        u8,             cpuvendor       )
+       ),
+
+       TP_fast_assign(
+               __entry->mcgcap         = m->mcgcap;
+               __entry->mcgstatus      = m->mcgstatus;
+               __entry->bank           = m->bank;
+               __entry->status         = m->status;
+               __entry->addr           = m->addr;
+               __entry->misc           = m->misc;
+               __entry->ip             = m->ip;
+               __entry->cs             = m->cs;
+               __entry->tsc            = m->tsc;
+               __entry->walltime       = m->time;
+               __entry->cpu            = m->extcpu;
+               __entry->cpuid          = m->cpuid;
+               __entry->apicid         = m->apicid;
+               __entry->socketid       = m->socketid;
+               __entry->cpuvendor      = m->cpuvendor;
+       ),
+
+       TP_printk("CPU: %d, MCGc/s: %llx/%llx, MC%d: %016Lx, ADDR/MISC: %016Lx/%016Lx, RIP: %02x:<%016Lx>, TSC: %llx, PROCESSOR: %u:%x, TIME: %llu, SOCKET: %u, APIC: %x",
+               __entry->cpu,
+               __entry->mcgcap, __entry->mcgstatus,
+               __entry->bank, __entry->status,
+               __entry->addr, __entry->misc,
+               __entry->cs, __entry->ip,
+               __entry->tsc,
+               __entry->cpuvendor, __entry->cpuid,
+               __entry->walltime,
+               __entry->socketid,
+               __entry->apicid)
+);
+
+#endif /* _TRACE_MCE_H */
+
+/* This part must be outside protection */
+#include <trace/define_trace.h>
index 84160fb..4b0f48b 100644 (file)
@@ -51,7 +51,7 @@ TRACE_EVENT(module_free,
        TP_printk("%s", __get_str(name))
 );
 
-TRACE_EVENT(module_get,
+DECLARE_EVENT_CLASS(module_refcnt,
 
        TP_PROTO(struct module *mod, unsigned long ip, int refcnt),
 
@@ -73,26 +73,18 @@ TRACE_EVENT(module_get,
                  __get_str(name), (void *)__entry->ip, __entry->refcnt)
 );
 
-TRACE_EVENT(module_put,
+DEFINE_EVENT(module_refcnt, module_get,
 
        TP_PROTO(struct module *mod, unsigned long ip, int refcnt),
 
-       TP_ARGS(mod, ip, refcnt),
+       TP_ARGS(mod, ip, refcnt)
+);
 
-       TP_STRUCT__entry(
-               __field(        unsigned long,  ip              )
-               __field(        int,            refcnt          )
-               __string(       name,           mod->name       )
-       ),
+DEFINE_EVENT(module_refcnt, module_put,
 
-       TP_fast_assign(
-               __entry->ip     = ip;
-               __entry->refcnt = refcnt;
-               __assign_str(name, mod->name);
-       ),
+       TP_PROTO(struct module *mod, unsigned long ip, int refcnt),
 
-       TP_printk("%s call_site=%pf refcnt=%d",
-                 __get_str(name), (void *)__entry->ip, __entry->refcnt)
+       TP_ARGS(mod, ip, refcnt)
 );
 
 TRACE_EVENT(module_request,
index ea6d579..c4efe9b 100644 (file)
@@ -16,9 +16,7 @@ enum {
 };
 #endif
 
-
-
-TRACE_EVENT(power_start,
+DECLARE_EVENT_CLASS(power,
 
        TP_PROTO(unsigned int type, unsigned int state),
 
@@ -37,42 +35,36 @@ TRACE_EVENT(power_start,
        TP_printk("type=%lu state=%lu", (unsigned long)__entry->type, (unsigned long)__entry->state)
 );
 
-TRACE_EVENT(power_end,
-
-       TP_PROTO(int dummy),
+DEFINE_EVENT(power, power_start,
 
-       TP_ARGS(dummy),
+       TP_PROTO(unsigned int type, unsigned int state),
 
-       TP_STRUCT__entry(
-               __field(        u64,            dummy           )
-       ),
+       TP_ARGS(type, state)
+);
 
-       TP_fast_assign(
-               __entry->dummy = 0xffff;
-       ),
+DEFINE_EVENT(power, power_frequency,
 
-       TP_printk("dummy=%lu", (unsigned long)__entry->dummy)
+       TP_PROTO(unsigned int type, unsigned int state),
 
+       TP_ARGS(type, state)
 );
 
+TRACE_EVENT(power_end,
 
-TRACE_EVENT(power_frequency,
-
-       TP_PROTO(unsigned int type, unsigned int state),
+       TP_PROTO(int dummy),
 
-       TP_ARGS(type, state),
+       TP_ARGS(dummy),
 
        TP_STRUCT__entry(
-               __field(        u64,            type            )
-               __field(        u64,            state           )
+               __field(        u64,            dummy           )
        ),
 
        TP_fast_assign(
-               __entry->type = type;
-               __entry->state = state;
+               __entry->dummy = 0xffff;
        ),
 
-       TP_printk("type=%lu state=%lu", (unsigned long)__entry->type, (unsigned long) __entry->state)
+       TP_printk("dummy=%lu", (unsigned long)__entry->dummy)
+
 );
 
 #endif /* _TRACE_POWER_H */
index 4069c43..cfceb0b 100644 (file)
@@ -26,7 +26,7 @@ TRACE_EVENT(sched_kthread_stop,
                __entry->pid    = t->pid;
        ),
 
-       TP_printk("task %s:%d", __entry->comm, __entry->pid)
+       TP_printk("comm=%s pid=%d", __entry->comm, __entry->pid)
 );
 
 /*
@@ -46,7 +46,7 @@ TRACE_EVENT(sched_kthread_stop_ret,
                __entry->ret    = ret;
        ),
 
-       TP_printk("ret %d", __entry->ret)
+       TP_printk("ret=%d", __entry->ret)
 );
 
 /*
@@ -73,7 +73,7 @@ TRACE_EVENT(sched_wait_task,
                __entry->prio   = p->prio;
        ),
 
-       TP_printk("task %s:%d [%d]",
+       TP_printk("comm=%s pid=%d prio=%d",
                  __entry->comm, __entry->pid, __entry->prio)
 );
 
@@ -83,7 +83,7 @@ TRACE_EVENT(sched_wait_task,
  * (NOTE: the 'rq' argument is not used by generic trace events,
  *        but used by the latency tracer plugin. )
  */
-TRACE_EVENT(sched_wakeup,
+DECLARE_EVENT_CLASS(sched_wakeup_template,
 
        TP_PROTO(struct rq *rq, struct task_struct *p, int success),
 
@@ -94,7 +94,7 @@ TRACE_EVENT(sched_wakeup,
                __field(        pid_t,  pid                     )
                __field(        int,    prio                    )
                __field(        int,    success                 )
-               __field(        int,    cpu                     )
+               __field(        int,    target_cpu              )
        ),
 
        TP_fast_assign(
@@ -102,46 +102,27 @@ TRACE_EVENT(sched_wakeup,
                __entry->pid            = p->pid;
                __entry->prio           = p->prio;
                __entry->success        = success;
-               __entry->cpu            = task_cpu(p);
+               __entry->target_cpu     = task_cpu(p);
        ),
 
-       TP_printk("task %s:%d [%d] success=%d [%03d]",
+       TP_printk("comm=%s pid=%d prio=%d success=%d target_cpu=%03d",
                  __entry->comm, __entry->pid, __entry->prio,
-                 __entry->success, __entry->cpu)
+                 __entry->success, __entry->target_cpu)
 );
 
+DEFINE_EVENT(sched_wakeup_template, sched_wakeup,
+            TP_PROTO(struct rq *rq, struct task_struct *p, int success),
+            TP_ARGS(rq, p, success));
+
 /*
  * Tracepoint for waking up a new task:
  *
  * (NOTE: the 'rq' argument is not used by generic trace events,
  *        but used by the latency tracer plugin. )
  */
-TRACE_EVENT(sched_wakeup_new,
-
-       TP_PROTO(struct rq *rq, struct task_struct *p, int success),
-
-       TP_ARGS(rq, p, success),
-
-       TP_STRUCT__entry(
-               __array(        char,   comm,   TASK_COMM_LEN   )
-               __field(        pid_t,  pid                     )
-               __field(        int,    prio                    )
-               __field(        int,    success                 )
-               __field(        int,    cpu                     )
-       ),
-
-       TP_fast_assign(
-               memcpy(__entry->comm, p->comm, TASK_COMM_LEN);
-               __entry->pid            = p->pid;
-               __entry->prio           = p->prio;
-               __entry->success        = success;
-               __entry->cpu            = task_cpu(p);
-       ),
-
-       TP_printk("task %s:%d [%d] success=%d [%03d]",
-                 __entry->comm, __entry->pid, __entry->prio,
-                 __entry->success, __entry->cpu)
-);
+DEFINE_EVENT(sched_wakeup_template, sched_wakeup_new,
+            TP_PROTO(struct rq *rq, struct task_struct *p, int success),
+            TP_ARGS(rq, p, success));
 
 /*
  * Tracepoint for task switches, performed by the scheduler:
@@ -176,7 +157,7 @@ TRACE_EVENT(sched_switch,
                __entry->next_prio      = next->prio;
        ),
 
-       TP_printk("task %s:%d [%d] (%s) ==> %s:%d [%d]",
+       TP_printk("prev_comm=%s prev_pid=%d prev_prio=%d prev_state=%s ==> next_comm=%s next_pid=%d next_prio=%d",
                __entry->prev_comm, __entry->prev_pid, __entry->prev_prio,
                __entry->prev_state ?
                  __print_flags(__entry->prev_state, "|",
@@ -211,15 +192,12 @@ TRACE_EVENT(sched_migrate_task,
                __entry->dest_cpu       = dest_cpu;
        ),
 
-       TP_printk("task %s:%d [%d] from: %d  to: %d",
+       TP_printk("comm=%s pid=%d prio=%d orig_cpu=%d dest_cpu=%d",
                  __entry->comm, __entry->pid, __entry->prio,
                  __entry->orig_cpu, __entry->dest_cpu)
 );
 
-/*
- * Tracepoint for freeing a task:
- */
-TRACE_EVENT(sched_process_free,
+DECLARE_EVENT_CLASS(sched_process_template,
 
        TP_PROTO(struct task_struct *p),
 
@@ -237,34 +215,24 @@ TRACE_EVENT(sched_process_free,
                __entry->prio           = p->prio;
        ),
 
-       TP_printk("task %s:%d [%d]",
+       TP_printk("comm=%s pid=%d prio=%d",
                  __entry->comm, __entry->pid, __entry->prio)
 );
 
 /*
- * Tracepoint for a task exiting:
+ * Tracepoint for freeing a task:
  */
-TRACE_EVENT(sched_process_exit,
+DEFINE_EVENT(sched_process_template, sched_process_free,
+            TP_PROTO(struct task_struct *p),
+            TP_ARGS(p));
+            
 
-       TP_PROTO(struct task_struct *p),
-
-       TP_ARGS(p),
-
-       TP_STRUCT__entry(
-               __array(        char,   comm,   TASK_COMM_LEN   )
-               __field(        pid_t,  pid                     )
-               __field(        int,    prio                    )
-       ),
-
-       TP_fast_assign(
-               memcpy(__entry->comm, p->comm, TASK_COMM_LEN);
-               __entry->pid            = p->pid;
-               __entry->prio           = p->prio;
-       ),
-
-       TP_printk("task %s:%d [%d]",
-                 __entry->comm, __entry->pid, __entry->prio)
-);
+/*
+ * Tracepoint for a task exiting:
+ */
+DEFINE_EVENT(sched_process_template, sched_process_exit,
+            TP_PROTO(struct task_struct *p),
+            TP_ARGS(p));
 
 /*
  * Tracepoint for a waiting task:
@@ -287,7 +255,7 @@ TRACE_EVENT(sched_process_wait,
                __entry->prio           = current->prio;
        ),
 
-       TP_printk("task %s:%d [%d]",
+       TP_printk("comm=%s pid=%d prio=%d",
                  __entry->comm, __entry->pid, __entry->prio)
 );
 
@@ -314,46 +282,16 @@ TRACE_EVENT(sched_process_fork,
                __entry->child_pid      = child->pid;
        ),
 
-       TP_printk("parent %s:%d  child %s:%d",
+       TP_printk("comm=%s pid=%d child_comm=%s child_pid=%d",
                __entry->parent_comm, __entry->parent_pid,
                __entry->child_comm, __entry->child_pid)
 );
 
 /*
- * Tracepoint for sending a signal:
- */
-TRACE_EVENT(sched_signal_send,
-
-       TP_PROTO(int sig, struct task_struct *p),
-
-       TP_ARGS(sig, p),
-
-       TP_STRUCT__entry(
-               __field(        int,    sig                     )
-               __array(        char,   comm,   TASK_COMM_LEN   )
-               __field(        pid_t,  pid                     )
-       ),
-
-       TP_fast_assign(
-               memcpy(__entry->comm, p->comm, TASK_COMM_LEN);
-               __entry->pid    = p->pid;
-               __entry->sig    = sig;
-       ),
-
-       TP_printk("sig: %d  task %s:%d",
-                 __entry->sig, __entry->comm, __entry->pid)
-);
-
-/*
  * XXX the below sched_stat tracepoints only apply to SCHED_OTHER/BATCH/IDLE
  *     adding sched_stat support to SCHED_FIFO/RR would be welcome.
  */
-
-/*
- * Tracepoint for accounting wait time (time the task is runnable
- * but not actually running due to scheduler contention).
- */
-TRACE_EVENT(sched_stat_wait,
+DECLARE_EVENT_CLASS(sched_stat_template,
 
        TP_PROTO(struct task_struct *tsk, u64 delay),
 
@@ -374,11 +312,36 @@ TRACE_EVENT(sched_stat_wait,
                __perf_count(delay);
        ),
 
-       TP_printk("task: %s:%d wait: %Lu [ns]",
+       TP_printk("comm=%s pid=%d delay=%Lu [ns]",
                        __entry->comm, __entry->pid,
                        (unsigned long long)__entry->delay)
 );
 
+
+/*
+ * Tracepoint for accounting wait time (time the task is runnable
+ * but not actually running due to scheduler contention).
+ */
+DEFINE_EVENT(sched_stat_template, sched_stat_wait,
+            TP_PROTO(struct task_struct *tsk, u64 delay),
+            TP_ARGS(tsk, delay));
+
+/*
+ * Tracepoint for accounting sleep time (time the task is not runnable,
+ * including iowait, see below).
+ */
+DEFINE_EVENT(sched_stat_template, sched_stat_sleep,
+            TP_PROTO(struct task_struct *tsk, u64 delay),
+            TP_ARGS(tsk, delay));
+
+/*
+ * Tracepoint for accounting iowait time (time the task is not runnable
+ * due to waiting on IO to complete).
+ */
+DEFINE_EVENT(sched_stat_template, sched_stat_iowait,
+            TP_PROTO(struct task_struct *tsk, u64 delay),
+            TP_ARGS(tsk, delay));
+
 /*
  * Tracepoint for accounting runtime (time the task is executing
  * on a CPU).
@@ -406,72 +369,12 @@ TRACE_EVENT(sched_stat_runtime,
                __perf_count(runtime);
        ),
 
-       TP_printk("task: %s:%d runtime: %Lu [ns], vruntime: %Lu [ns]",
+       TP_printk("comm=%s pid=%d runtime=%Lu [ns] vruntime=%Lu [ns]",
                        __entry->comm, __entry->pid,
                        (unsigned long long)__entry->runtime,
                        (unsigned long long)__entry->vruntime)
 );
 
-/*
- * Tracepoint for accounting sleep time (time the task is not runnable,
- * including iowait, see below).
- */
-TRACE_EVENT(sched_stat_sleep,
-
-       TP_PROTO(struct task_struct *tsk, u64 delay),
-
-       TP_ARGS(tsk, delay),
-
-       TP_STRUCT__entry(
-               __array( char,  comm,   TASK_COMM_LEN   )
-               __field( pid_t, pid                     )
-               __field( u64,   delay                   )
-       ),
-
-       TP_fast_assign(
-               memcpy(__entry->comm, tsk->comm, TASK_COMM_LEN);
-               __entry->pid    = tsk->pid;
-               __entry->delay  = delay;
-       )
-       TP_perf_assign(
-               __perf_count(delay);
-       ),
-
-       TP_printk("task: %s:%d sleep: %Lu [ns]",
-                       __entry->comm, __entry->pid,
-                       (unsigned long long)__entry->delay)
-);
-
-/*
- * Tracepoint for accounting iowait time (time the task is not runnable
- * due to waiting on IO to complete).
- */
-TRACE_EVENT(sched_stat_iowait,
-
-       TP_PROTO(struct task_struct *tsk, u64 delay),
-
-       TP_ARGS(tsk, delay),
-
-       TP_STRUCT__entry(
-               __array( char,  comm,   TASK_COMM_LEN   )
-               __field( pid_t, pid                     )
-               __field( u64,   delay                   )
-       ),
-
-       TP_fast_assign(
-               memcpy(__entry->comm, tsk->comm, TASK_COMM_LEN);
-               __entry->pid    = tsk->pid;
-               __entry->delay  = delay;
-       )
-       TP_perf_assign(
-               __perf_count(delay);
-       ),
-
-       TP_printk("task: %s:%d iowait: %Lu [ns]",
-                       __entry->comm, __entry->pid,
-                       (unsigned long long)__entry->delay)
-);
-
 #endif /* _TRACE_SCHED_H */
 
 /* This part must be outside protection */
diff --git a/include/trace/events/signal.h b/include/trace/events/signal.h
new file mode 100644 (file)
index 0000000..a510b75
--- /dev/null
@@ -0,0 +1,173 @@
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM signal
+
+#if !defined(_TRACE_SIGNAL_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_SIGNAL_H
+
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/tracepoint.h>
+
+#define TP_STORE_SIGINFO(__entry, info)                                \
+       do {                                                    \
+               if (info == SEND_SIG_NOINFO) {                  \
+                       __entry->errno  = 0;                    \
+                       __entry->code   = SI_USER;              \
+               } else if (info == SEND_SIG_PRIV) {             \
+                       __entry->errno  = 0;                    \
+                       __entry->code   = SI_KERNEL;            \
+               } else {                                        \
+                       __entry->errno  = info->si_errno;       \
+                       __entry->code   = info->si_code;        \
+               }                                               \
+       } while (0)
+
+/**
+ * signal_generate - called when a signal is generated
+ * @sig: signal number
+ * @info: pointer to struct siginfo
+ * @task: pointer to struct task_struct
+ *
+ * Current process sends a 'sig' signal to 'task' process with
+ * 'info' siginfo. If 'info' is SEND_SIG_NOINFO or SEND_SIG_PRIV,
+ * 'info' is not a pointer and you can't access its field. Instead,
+ * SEND_SIG_NOINFO means that si_code is SI_USER, and SEND_SIG_PRIV
+ * means that si_code is SI_KERNEL.
+ */
+TRACE_EVENT(signal_generate,
+
+       TP_PROTO(int sig, struct siginfo *info, struct task_struct *task),
+
+       TP_ARGS(sig, info, task),
+
+       TP_STRUCT__entry(
+               __field(        int,    sig                     )
+               __field(        int,    errno                   )
+               __field(        int,    code                    )
+               __array(        char,   comm,   TASK_COMM_LEN   )
+               __field(        pid_t,  pid                     )
+       ),
+
+       TP_fast_assign(
+               __entry->sig    = sig;
+               TP_STORE_SIGINFO(__entry, info);
+               memcpy(__entry->comm, task->comm, TASK_COMM_LEN);
+               __entry->pid    = task->pid;
+       ),
+
+       TP_printk("sig=%d errno=%d code=%d comm=%s pid=%d",
+                 __entry->sig, __entry->errno, __entry->code,
+                 __entry->comm, __entry->pid)
+);
+
+/**
+ * signal_deliver - called when a signal is delivered
+ * @sig: signal number
+ * @info: pointer to struct siginfo
+ * @ka: pointer to struct k_sigaction
+ *
+ * A 'sig' signal is delivered to current process with 'info' siginfo,
+ * and it will be handled by 'ka'. ka->sa.sa_handler can be SIG_IGN or
+ * SIG_DFL.
+ * Note that some signals reported by signal_generate tracepoint can be
+ * lost, ignored or modified (by debugger) before hitting this tracepoint.
+ * This means, this can show which signals are actually delivered, but
+ * matching generated signals and delivered signals may not be correct.
+ */
+TRACE_EVENT(signal_deliver,
+
+       TP_PROTO(int sig, struct siginfo *info, struct k_sigaction *ka),
+
+       TP_ARGS(sig, info, ka),
+
+       TP_STRUCT__entry(
+               __field(        int,            sig             )
+               __field(        int,            errno           )
+               __field(        int,            code            )
+               __field(        unsigned long,  sa_handler      )
+               __field(        unsigned long,  sa_flags        )
+       ),
+
+       TP_fast_assign(
+               __entry->sig    = sig;
+               TP_STORE_SIGINFO(__entry, info);
+               __entry->sa_handler     = (unsigned long)ka->sa.sa_handler;
+               __entry->sa_flags       = ka->sa.sa_flags;
+       ),
+
+       TP_printk("sig=%d errno=%d code=%d sa_handler=%lx sa_flags=%lx",
+                 __entry->sig, __entry->errno, __entry->code,
+                 __entry->sa_handler, __entry->sa_flags)
+);
+
+/**
+ * signal_overflow_fail - called when signal queue is overflow
+ * @sig: signal number
+ * @group: signal to process group or not (bool)
+ * @info: pointer to struct siginfo
+ *
+ * Kernel fails to generate 'sig' signal with 'info' siginfo, because
+ * siginfo queue is overflow, and the signal is dropped.
+ * 'group' is not 0 if the signal will be sent to a process group.
+ * 'sig' is always one of RT signals.
+ */
+TRACE_EVENT(signal_overflow_fail,
+
+       TP_PROTO(int sig, int group, struct siginfo *info),
+
+       TP_ARGS(sig, group, info),
+
+       TP_STRUCT__entry(
+               __field(        int,    sig     )
+               __field(        int,    group   )
+               __field(        int,    errno   )
+               __field(        int,    code    )
+       ),
+
+       TP_fast_assign(
+               __entry->sig    = sig;
+               __entry->group  = group;
+               TP_STORE_SIGINFO(__entry, info);
+       ),
+
+       TP_printk("sig=%d group=%d errno=%d code=%d",
+                 __entry->sig, __entry->group, __entry->errno, __entry->code)
+);
+
+/**
+ * signal_lose_info - called when siginfo is lost
+ * @sig: signal number
+ * @group: signal to process group or not (bool)
+ * @info: pointer to struct siginfo
+ *
+ * Kernel generates 'sig' signal but loses 'info' siginfo, because siginfo
+ * queue is overflow.
+ * 'group' is not 0 if the signal will be sent to a process group.
+ * 'sig' is always one of non-RT signals.
+ */
+TRACE_EVENT(signal_lose_info,
+
+       TP_PROTO(int sig, int group, struct siginfo *info),
+
+       TP_ARGS(sig, group, info),
+
+       TP_STRUCT__entry(
+               __field(        int,    sig     )
+               __field(        int,    group   )
+               __field(        int,    errno   )
+               __field(        int,    code    )
+       ),
+
+       TP_fast_assign(
+               __entry->sig    = sig;
+               __entry->group  = group;
+               TP_STORE_SIGINFO(__entry, info);
+       ),
+
+       TP_printk("sig=%d group=%d errno=%d code=%d",
+                 __entry->sig, __entry->group, __entry->errno, __entry->code)
+);
+#endif /* _TRACE_SIGNAL_H */
+
+/* This part must be outside protection */
+#include <trace/define_trace.h>
index 1844c48..e5ce87a 100644 (file)
@@ -26,7 +26,7 @@ TRACE_EVENT(timer_init,
                __entry->timer  = timer;
        ),
 
-       TP_printk("timer %p", __entry->timer)
+       TP_printk("timer=%p", __entry->timer)
 );
 
 /**
@@ -54,7 +54,7 @@ TRACE_EVENT(timer_start,
                __entry->now            = jiffies;
        ),
 
-       TP_printk("timer %p: func %pf, expires %lu, timeout %ld",
+       TP_printk("timer=%p function=%pf expires=%lu [timeout=%ld]",
                  __entry->timer, __entry->function, __entry->expires,
                  (long)__entry->expires - __entry->now)
 );
@@ -81,7 +81,7 @@ TRACE_EVENT(timer_expire_entry,
                __entry->now            = jiffies;
        ),
 
-       TP_printk("timer %p: now %lu", __entry->timer, __entry->now)
+       TP_printk("timer=%p now=%lu", __entry->timer, __entry->now)
 );
 
 /**
@@ -108,7 +108,7 @@ TRACE_EVENT(timer_expire_exit,
                __entry->timer  = timer;
        ),
 
-       TP_printk("timer %p", __entry->timer)
+       TP_printk("timer=%p", __entry->timer)
 );
 
 /**
@@ -129,7 +129,7 @@ TRACE_EVENT(timer_cancel,
                __entry->timer  = timer;
        ),
 
-       TP_printk("timer %p", __entry->timer)
+       TP_printk("timer=%p", __entry->timer)
 );
 
 /**
@@ -140,24 +140,24 @@ TRACE_EVENT(timer_cancel,
  */
 TRACE_EVENT(hrtimer_init,
 
-       TP_PROTO(struct hrtimer *timer, clockid_t clockid,
+       TP_PROTO(struct hrtimer *hrtimer, clockid_t clockid,
                 enum hrtimer_mode mode),
 
-       TP_ARGS(timer, clockid, mode),
+       TP_ARGS(hrtimer, clockid, mode),
 
        TP_STRUCT__entry(
-               __field( void *,                timer           )
+               __field( void *,                hrtimer         )
                __field( clockid_t,             clockid         )
                __field( enum hrtimer_mode,     mode            )
        ),
 
        TP_fast_assign(
-               __entry->timer          = timer;
+               __entry->hrtimer        = hrtimer;
                __entry->clockid        = clockid;
                __entry->mode           = mode;
        ),
 
-       TP_printk("hrtimer %p, clockid %s, mode %s", __entry->timer,
+       TP_printk("hrtimer=%p clockid=%s mode=%s", __entry->hrtimer,
                  __entry->clockid == CLOCK_REALTIME ?
                        "CLOCK_REALTIME" : "CLOCK_MONOTONIC",
                  __entry->mode == HRTIMER_MODE_ABS ?
@@ -170,26 +170,26 @@ TRACE_EVENT(hrtimer_init,
  */
 TRACE_EVENT(hrtimer_start,
 
-       TP_PROTO(struct hrtimer *timer),
+       TP_PROTO(struct hrtimer *hrtimer),
 
-       TP_ARGS(timer),
+       TP_ARGS(hrtimer),
 
        TP_STRUCT__entry(
-               __field( void *,        timer           )
+               __field( void *,        hrtimer         )
                __field( void *,        function        )
                __field( s64,           expires         )
                __field( s64,           softexpires     )
        ),
 
        TP_fast_assign(
-               __entry->timer          = timer;
-               __entry->function       = timer->function;
-               __entry->expires        = hrtimer_get_expires(timer).tv64;
-               __entry->softexpires    = hrtimer_get_softexpires(timer).tv64;
+               __entry->hrtimer        = hrtimer;
+               __entry->function       = hrtimer->function;
+               __entry->expires        = hrtimer_get_expires(hrtimer).tv64;
+               __entry->softexpires    = hrtimer_get_softexpires(hrtimer).tv64;
        ),
 
-       TP_printk("hrtimer %p, func %pf, expires %llu, softexpires %llu",
-                 __entry->timer, __entry->function,
+       TP_printk("hrtimer=%p function=%pf expires=%llu softexpires=%llu",
+                 __entry->hrtimer, __entry->function,
                  (unsigned long long)ktime_to_ns((ktime_t) {
                                  .tv64 = __entry->expires }),
                  (unsigned long long)ktime_to_ns((ktime_t) {
@@ -206,23 +206,22 @@ TRACE_EVENT(hrtimer_start,
  */
 TRACE_EVENT(hrtimer_expire_entry,
 
-       TP_PROTO(struct hrtimer *timer, ktime_t *now),
+       TP_PROTO(struct hrtimer *hrtimer, ktime_t *now),
 
-       TP_ARGS(timer, now),
+       TP_ARGS(hrtimer, now),
 
        TP_STRUCT__entry(
-               __field( void *,        timer   )
+               __field( void *,        hrtimer )
                __field( s64,           now     )
        ),
 
        TP_fast_assign(
-               __entry->timer  = timer;
-               __entry->now    = now->tv64;
+               __entry->hrtimer        = hrtimer;
+               __entry->now            = now->tv64;
        ),
 
-       TP_printk("hrtimer %p, now %llu", __entry->timer,
-                 (unsigned long long)ktime_to_ns((ktime_t) {
-                                 .tv64 = __entry->now }))
+       TP_printk("hrtimer=%p now=%llu", __entry->hrtimer,
+                 (unsigned long long)ktime_to_ns((ktime_t) { .tv64 = __entry->now }))
  );
 
 /**
@@ -234,40 +233,40 @@ TRACE_EVENT(hrtimer_expire_entry,
  */
 TRACE_EVENT(hrtimer_expire_exit,
 
-       TP_PROTO(struct hrtimer *timer),
+       TP_PROTO(struct hrtimer *hrtimer),
 
-       TP_ARGS(timer),
+       TP_ARGS(hrtimer),
 
        TP_STRUCT__entry(
-               __field( void *,        timer   )
+               __field( void *,        hrtimer )
        ),
 
        TP_fast_assign(
-               __entry->timer  = timer;
+               __entry->hrtimer        = hrtimer;
        ),
 
-       TP_printk("hrtimer %p", __entry->timer)
+       TP_printk("hrtimer=%p", __entry->hrtimer)
 );
 
 /**
  * hrtimer_cancel - called when the hrtimer is canceled
- * @timer:     pointer to struct hrtimer
+ * @hrtimer:   pointer to struct hrtimer
  */
 TRACE_EVENT(hrtimer_cancel,
 
-       TP_PROTO(struct hrtimer *timer),
+       TP_PROTO(struct hrtimer *hrtimer),
 
-       TP_ARGS(timer),
+       TP_ARGS(hrtimer),
 
        TP_STRUCT__entry(
-               __field( void *,        timer   )
+               __field( void *,        hrtimer )
        ),
 
        TP_fast_assign(
-               __entry->timer  = timer;
+               __entry->hrtimer        = hrtimer;
        ),
 
-       TP_printk("hrtimer %p", __entry->timer)
+       TP_printk("hrtimer=%p", __entry->hrtimer)
 );
 
 /**
@@ -302,7 +301,7 @@ TRACE_EVENT(itimer_state,
                __entry->interval_usec  = value->it_interval.tv_usec;
        ),
 
-       TP_printk("which %d, expires %lu, it_value %lu.%lu, it_interval %lu.%lu",
+       TP_printk("which=%d expires=%lu it_value=%lu.%lu it_interval=%lu.%lu",
                  __entry->which, __entry->expires,
                  __entry->value_sec, __entry->value_usec,
                  __entry->interval_sec, __entry->interval_usec)
@@ -332,7 +331,7 @@ TRACE_EVENT(itimer_expire,
                __entry->pid    = pid_nr(pid);
        ),
 
-           TP_printk("which %d, pid %d, now %lu", __entry->which,
+           TP_printk("which=%d pid=%d now=%lu", __entry->which,
                      (int) __entry->pid, __entry->now)
 );
 
index e4612db..d6c9744 100644 (file)
@@ -8,7 +8,7 @@
 #include <linux/sched.h>
 #include <linux/tracepoint.h>
 
-TRACE_EVENT(workqueue_insertion,
+DECLARE_EVENT_CLASS(workqueue,
 
        TP_PROTO(struct task_struct *wq_thread, struct work_struct *work),
 
@@ -30,26 +30,18 @@ TRACE_EVENT(workqueue_insertion,
                __entry->thread_pid, __entry->func)
 );
 
-TRACE_EVENT(workqueue_execution,
+DEFINE_EVENT(workqueue, workqueue_insertion,
 
        TP_PROTO(struct task_struct *wq_thread, struct work_struct *work),
 
-       TP_ARGS(wq_thread, work),
+       TP_ARGS(wq_thread, work)
+);
 
-       TP_STRUCT__entry(
-               __array(char,           thread_comm,    TASK_COMM_LEN)
-               __field(pid_t,          thread_pid)
-               __field(work_func_t,    func)
-       ),
+DEFINE_EVENT(workqueue, workqueue_execution,
 
-       TP_fast_assign(
-               memcpy(__entry->thread_comm, wq_thread->comm, TASK_COMM_LEN);
-               __entry->thread_pid     = wq_thread->pid;
-               __entry->func           = work->func;
-       ),
+       TP_PROTO(struct task_struct *wq_thread, struct work_struct *work),
 
-       TP_printk("thread=%s:%d func=%pf", __entry->thread_comm,
-               __entry->thread_pid, __entry->func)
+       TP_ARGS(wq_thread, work)
 );
 
 /* Trace the creation of one workqueue thread on a cpu */
index dacb8ef..d1b3de9 100644 (file)
 
 #include <linux/ftrace_event.h>
 
+/*
+ * DECLARE_EVENT_CLASS can be used to add a generic function
+ * handlers for events. That is, if all events have the same
+ * parameters and just have distinct trace points.
+ * Each tracepoint can be defined with DEFINE_EVENT and that
+ * will map the DECLARE_EVENT_CLASS to the tracepoint.
+ *
+ * TRACE_EVENT is a one to one mapping between tracepoint and template.
+ */
+#undef TRACE_EVENT
+#define TRACE_EVENT(name, proto, args, tstruct, assign, print) \
+       DECLARE_EVENT_CLASS(name,                              \
+                            PARAMS(proto),                    \
+                            PARAMS(args),                     \
+                            PARAMS(tstruct),                  \
+                            PARAMS(assign),                   \
+                            PARAMS(print));                   \
+       DEFINE_EVENT(name, name, PARAMS(proto), PARAMS(args));
+
+
 #undef __field
 #define __field(type, item)            type    item;
 
 #undef TP_STRUCT__entry
 #define TP_STRUCT__entry(args...) args
 
-#undef TRACE_EVENT
-#define TRACE_EVENT(name, proto, args, tstruct, assign, print) \
-       struct ftrace_raw_##name {                              \
-               struct trace_entry      ent;                    \
-               tstruct                                         \
-               char                    __data[0];              \
-       };                                                      \
+#undef DECLARE_EVENT_CLASS
+#define DECLARE_EVENT_CLASS(name, proto, args, tstruct, assign, print) \
+       struct ftrace_raw_##name {                                      \
+               struct trace_entry      ent;                            \
+               tstruct                                                 \
+               char                    __data[0];                      \
+       };
+#undef DEFINE_EVENT
+#define DEFINE_EVENT(template, name, proto, args)      \
        static struct ftrace_event_call event_##name
 
+#undef DEFINE_EVENT_PRINT
+#define DEFINE_EVENT_PRINT(template, name, proto, args, print) \
+       DEFINE_EVENT(template, name, PARAMS(proto), PARAMS(args))
+
 #undef __cpparg
 #define __cpparg(arg...) arg
 
 #undef __string
 #define __string(item, src) __dynamic_array(char, item, -1)
 
-#undef TRACE_EVENT
-#define TRACE_EVENT(call, proto, args, tstruct, assign, print)         \
+#undef DECLARE_EVENT_CLASS
+#define DECLARE_EVENT_CLASS(call, proto, args, tstruct, assign, print) \
        struct ftrace_data_offsets_##call {                             \
                tstruct;                                                \
        };
 
+#undef DEFINE_EVENT
+#define DEFINE_EVENT(template, name, proto, args)
+
+#undef DEFINE_EVENT_PRINT
+#define DEFINE_EVENT_PRINT(template, name, proto, args, print) \
+       DEFINE_EVENT(template, name, PARAMS(proto), PARAMS(args))
+
 #include TRACE_INCLUDE(TRACE_INCLUDE_FILE)
 
 /*
 #undef __field
 #define __field(type, item)                                    \
        ret = trace_seq_printf(s, "\tfield:" #type " " #item ";\t"      \
-                              "offset:%u;\tsize:%u;\n",                \
+                              "offset:%u;\tsize:%u;\tsigned:%u;\n",    \
                               (unsigned int)offsetof(typeof(field), item), \
-                              (unsigned int)sizeof(field.item));       \
+                              (unsigned int)sizeof(field.item),        \
+                              (unsigned int)is_signed_type(type));     \
        if (!ret)                                                       \
                return 0;
 
 #undef __array
 #define __array(type, item, len)                                               \
        ret = trace_seq_printf(s, "\tfield:" #type " " #item "[" #len "];\t"    \
-                              "offset:%u;\tsize:%u;\n",                \
+                              "offset:%u;\tsize:%u;\tsigned:%u;\n",    \
                               (unsigned int)offsetof(typeof(field), item), \
-                              (unsigned int)sizeof(field.item));       \
+                              (unsigned int)sizeof(field.item),        \
+                              (unsigned int)is_signed_type(type));     \
        if (!ret)                                                       \
                return 0;
 
 #undef __dynamic_array
 #define __dynamic_array(type, item, len)                                      \
        ret = trace_seq_printf(s, "\tfield:__data_loc " #type "[] " #item ";\t"\
-                              "offset:%u;\tsize:%u;\n",                       \
+                              "offset:%u;\tsize:%u;\tsigned:%u;\n",           \
                               (unsigned int)offsetof(typeof(field),           \
                                        __data_loc_##item),                    \
-                              (unsigned int)sizeof(field.__data_loc_##item)); \
+                              (unsigned int)sizeof(field.__data_loc_##item), \
+                              (unsigned int)is_signed_type(type));     \
        if (!ret)                                                              \
                return 0;
 
 #undef TP_perf_assign
 #define TP_perf_assign(args...)
 
-#undef TRACE_EVENT
-#define TRACE_EVENT(call, proto, args, tstruct, func, print)           \
+#undef DECLARE_EVENT_CLASS
+#define DECLARE_EVENT_CLASS(call, proto, args, tstruct, func, print)   \
 static int                                                             \
-ftrace_format_##call(struct ftrace_event_call *unused,                 \
-                     struct trace_seq *s)                              \
+ftrace_format_setup_##call(struct ftrace_event_call *unused,           \
+                          struct trace_seq *s)                         \
 {                                                                      \
        struct ftrace_raw_##call field __attribute__((unused));         \
        int ret = 0;                                                    \
                                                                        \
        tstruct;                                                        \
                                                                        \
+       return ret;                                                     \
+}                                                                      \
+                                                                       \
+static int                                                             \
+ftrace_format_##call(struct ftrace_event_call *unused,                 \
+                    struct trace_seq *s)                               \
+{                                                                      \
+       int ret = 0;                                                    \
+                                                                       \
+       ret = ftrace_format_setup_##call(unused, s);                    \
+       if (!ret)                                                       \
+               return ret;                                             \
+                                                                       \
+       ret = trace_seq_printf(s, "\nprint fmt: " print);               \
+                                                                       \
+       return ret;                                                     \
+}
+
+#undef DEFINE_EVENT
+#define DEFINE_EVENT(template, name, proto, args)
+
+#undef DEFINE_EVENT_PRINT
+#define DEFINE_EVENT_PRINT(template, name, proto, args, print)         \
+static int                                                             \
+ftrace_format_##name(struct ftrace_event_call *unused,                 \
+                     struct trace_seq *s)                              \
+{                                                                      \
+       int ret = 0;                                                    \
+                                                                       \
+       ret = ftrace_format_setup_##template(unused, s);                \
+       if (!ret)                                                       \
+               return ret;                                             \
+                                                                       \
        trace_seq_printf(s, "\nprint fmt: " print);                     \
                                                                        \
        return ret;                                                     \
@@ -252,10 +321,11 @@ ftrace_format_##call(struct ftrace_event_call *unused,                    \
                ftrace_print_symbols_seq(p, value, symbols);            \
        })
 
-#undef TRACE_EVENT
-#define TRACE_EVENT(call, proto, args, tstruct, assign, print)         \
+#undef DECLARE_EVENT_CLASS
+#define DECLARE_EVENT_CLASS(call, proto, args, tstruct, assign, print) \
 static enum print_line_t                                               \
-ftrace_raw_output_##call(struct trace_iterator *iter, int flags)       \
+ftrace_raw_output_id_##call(int event_id, const char *name,            \
+                           struct trace_iterator *iter, int flags)     \
 {                                                                      \
        struct trace_seq *s = &iter->seq;                               \
        struct ftrace_raw_##call *field;                                \
@@ -265,6 +335,47 @@ ftrace_raw_output_##call(struct trace_iterator *iter, int flags)   \
                                                                        \
        entry = iter->ent;                                              \
                                                                        \
+       if (entry->type != event_id) {                                  \
+               WARN_ON_ONCE(1);                                        \
+               return TRACE_TYPE_UNHANDLED;                            \
+       }                                                               \
+                                                                       \
+       field = (typeof(field))entry;                                   \
+                                                                       \
+       p = &get_cpu_var(ftrace_event_seq);                             \
+       trace_seq_init(p);                                              \
+       ret = trace_seq_printf(s, "%s: ", name);                        \
+       if (ret)                                                        \
+               ret = trace_seq_printf(s, print);                       \
+       put_cpu();                                                      \
+       if (!ret)                                                       \
+               return TRACE_TYPE_PARTIAL_LINE;                         \
+                                                                       \
+       return TRACE_TYPE_HANDLED;                                      \
+}
+
+#undef DEFINE_EVENT
+#define DEFINE_EVENT(template, name, proto, args)                      \
+static enum print_line_t                                               \
+ftrace_raw_output_##name(struct trace_iterator *iter, int flags)       \
+{                                                                      \
+       return ftrace_raw_output_id_##template(event_##name.id,         \
+                                              #name, iter, flags);     \
+}
+
+#undef DEFINE_EVENT_PRINT
+#define DEFINE_EVENT_PRINT(template, call, proto, args, print)         \
+static enum print_line_t                                               \
+ftrace_raw_output_##call(struct trace_iterator *iter, int flags)       \
+{                                                                      \
+       struct trace_seq *s = &iter->seq;                               \
+       struct ftrace_raw_##template *field;                            \
+       struct trace_entry *entry;                                      \
+       struct trace_seq *p;                                            \
+       int ret;                                                        \
+                                                                       \
+       entry = iter->ent;                                              \
+                                                                       \
        if (entry->type != event_##call.id) {                           \
                WARN_ON_ONCE(1);                                        \
                return TRACE_TYPE_UNHANDLED;                            \
@@ -274,14 +385,16 @@ ftrace_raw_output_##call(struct trace_iterator *iter, int flags)  \
                                                                        \
        p = &get_cpu_var(ftrace_event_seq);                             \
        trace_seq_init(p);                                              \
-       ret = trace_seq_printf(s, #call ": " print);                    \
+       ret = trace_seq_printf(s, "%s: ", #call);                       \
+       if (ret)                                                        \
+               ret = trace_seq_printf(s, print);                       \
        put_cpu();                                                      \
        if (!ret)                                                       \
                return TRACE_TYPE_PARTIAL_LINE;                         \
                                                                        \
        return TRACE_TYPE_HANDLED;                                      \
 }
-       
+
 #include TRACE_INCLUDE(TRACE_INCLUDE_FILE)
 
 #undef __field_ext
@@ -315,8 +428,8 @@ ftrace_raw_output_##call(struct trace_iterator *iter, int flags)    \
 #undef __string
 #define __string(item, src) __dynamic_array(char, item, -1)
 
-#undef TRACE_EVENT
-#define TRACE_EVENT(call, proto, args, tstruct, func, print)           \
+#undef DECLARE_EVENT_CLASS
+#define DECLARE_EVENT_CLASS(call, proto, args, tstruct, func, print)   \
 static int                                                             \
 ftrace_define_fields_##call(struct ftrace_event_call *event_call)      \
 {                                                                      \
@@ -332,6 +445,13 @@ ftrace_define_fields_##call(struct ftrace_event_call *event_call)  \
        return ret;                                                     \
 }
 
+#undef DEFINE_EVENT
+#define DEFINE_EVENT(template, name, proto, args)
+
+#undef DEFINE_EVENT_PRINT
+#define DEFINE_EVENT_PRINT(template, name, proto, args, print) \
+       DEFINE_EVENT(template, name, PARAMS(proto), PARAMS(args))
+
 #include TRACE_INCLUDE(TRACE_INCLUDE_FILE)
 
 /*
@@ -358,10 +478,10 @@ ftrace_define_fields_##call(struct ftrace_event_call *event_call) \
        __data_size += (len) * sizeof(type);
 
 #undef __string
-#define __string(item, src) __dynamic_array(char, item, strlen(src) + 1)       \
+#define __string(item, src) __dynamic_array(char, item, strlen(src) + 1)
 
-#undef TRACE_EVENT
-#define TRACE_EVENT(call, proto, args, tstruct, assign, print)         \
+#undef DECLARE_EVENT_CLASS
+#define DECLARE_EVENT_CLASS(call, proto, args, tstruct, assign, print) \
 static inline int ftrace_get_offsets_##call(                           \
        struct ftrace_data_offsets_##call *__data_offsets, proto)       \
 {                                                                      \
@@ -373,6 +493,13 @@ static inline int ftrace_get_offsets_##call(                               \
        return __data_size;                                             \
 }
 
+#undef DEFINE_EVENT
+#define DEFINE_EVENT(template, name, proto, args)
+
+#undef DEFINE_EVENT_PRINT
+#define DEFINE_EVENT_PRINT(template, name, proto, args, print) \
+       DEFINE_EVENT(template, name, PARAMS(proto), PARAMS(args))
+
 #include TRACE_INCLUDE(TRACE_INCLUDE_FILE)
 
 #ifdef CONFIG_EVENT_PROFILE
@@ -394,21 +521,28 @@ static inline int ftrace_get_offsets_##call(                              \
  *
  */
 
-#undef TRACE_EVENT
-#define TRACE_EVENT(call, proto, args, tstruct, assign, print)         \
+#undef DECLARE_EVENT_CLASS
+#define DECLARE_EVENT_CLASS(call, proto, args, tstruct, assign, print)
+
+#undef DEFINE_EVENT
+#define DEFINE_EVENT(template, name, proto, args)                      \
                                                                        \
-static void ftrace_profile_##call(proto);                              \
+static void ftrace_profile_##name(proto);                              \
                                                                        \
-static int ftrace_profile_enable_##call(void)                          \
+static int ftrace_profile_enable_##name(struct ftrace_event_call *unused)\
 {                                                                      \
-       return register_trace_##call(ftrace_profile_##call);            \
+       return register_trace_##name(ftrace_profile_##name);            \
 }                                                                      \
                                                                        \
-static void ftrace_profile_disable_##call(void)                                \
+static void ftrace_profile_disable_##name(struct ftrace_event_call *unused)\
 {                                                                      \
-       unregister_trace_##call(ftrace_profile_##call);                 \
+       unregister_trace_##name(ftrace_profile_##name);                 \
 }
 
+#undef DEFINE_EVENT_PRINT
+#define DEFINE_EVENT_PRINT(template, name, proto, args, print) \
+       DEFINE_EVENT(template, name, PARAMS(proto), PARAMS(args))
+
 #include TRACE_INCLUDE(TRACE_INCLUDE_FILE)
 
 #endif
@@ -423,7 +557,7 @@ static void ftrace_profile_disable_##call(void)                             \
  *     event_trace_printk(_RET_IP_, "<call>: " <fmt>);
  * }
  *
- * static int ftrace_reg_event_<call>(void)
+ * static int ftrace_reg_event_<call>(struct ftrace_event_call *unused)
  * {
  *     int ret;
  *
@@ -434,7 +568,7 @@ static void ftrace_profile_disable_##call(void)                             \
  *     return ret;
  * }
  *
- * static void ftrace_unreg_event_<call>(void)
+ * static void ftrace_unreg_event_<call>(struct ftrace_event_call *unused)
  * {
  *     unregister_trace_<call>(ftrace_event_<call>);
  * }
@@ -469,7 +603,7 @@ static void ftrace_profile_disable_##call(void)                             \
  *     trace_current_buffer_unlock_commit(buffer, event, irq_flags, pc);
  * }
  *
- * static int ftrace_raw_reg_event_<call>(void)
+ * static int ftrace_raw_reg_event_<call>(struct ftrace_event_call *unused)
  * {
  *     int ret;
  *
@@ -480,7 +614,7 @@ static void ftrace_profile_disable_##call(void)                             \
  *     return ret;
  * }
  *
- * static void ftrace_unreg_event_<call>(void)
+ * static void ftrace_unreg_event_<call>(struct ftrace_event_call *unused)
  * {
  *     unregister_trace_<call>(ftrace_raw_event_<call>);
  * }
@@ -489,7 +623,7 @@ static void ftrace_profile_disable_##call(void)                             \
  *     .trace                  = ftrace_raw_output_<call>, <-- stage 2
  * };
  *
- * static int ftrace_raw_init_event_<call>(void)
+ * static int ftrace_raw_init_event_<call>(struct ftrace_event_call *unused)
  * {
  *     int id;
  *
@@ -547,15 +681,13 @@ static void ftrace_profile_disable_##call(void)                           \
 #define __assign_str(dst, src)                                         \
        strcpy(__get_str(dst), src);
 
-#undef TRACE_EVENT
-#define TRACE_EVENT(call, proto, args, tstruct, assign, print)         \
+#undef DECLARE_EVENT_CLASS
+#define DECLARE_EVENT_CLASS(call, proto, args, tstruct, assign, print) \
                                                                        \
-static struct ftrace_event_call event_##call;                          \
-                                                                       \
-static void ftrace_raw_event_##call(proto)                             \
+static void ftrace_raw_event_id_##call(struct ftrace_event_call *event_call, \
+                                      proto)                           \
 {                                                                      \
        struct ftrace_data_offsets_##call __maybe_unused __data_offsets;\
-       struct ftrace_event_call *event_call = &event_##call;           \
        struct ring_buffer_event *event;                                \
        struct ftrace_raw_##call *entry;                                \
        struct ring_buffer *buffer;                                     \
@@ -569,7 +701,7 @@ static void ftrace_raw_event_##call(proto)                          \
        __data_size = ftrace_get_offsets_##call(&__data_offsets, args); \
                                                                        \
        event = trace_current_buffer_lock_reserve(&buffer,              \
-                                event_##call.id,                       \
+                                event_call->id,                        \
                                 sizeof(*entry) + __data_size,          \
                                 irq_flags, pc);                        \
        if (!event)                                                     \
@@ -584,9 +716,17 @@ static void ftrace_raw_event_##call(proto)                         \
        if (!filter_current_check_discard(buffer, event_call, entry, event)) \
                trace_nowake_buffer_unlock_commit(buffer,               \
                                                  event, irq_flags, pc); \
+}
+
+#undef DEFINE_EVENT
+#define DEFINE_EVENT(template, call, proto, args)                      \
+                                                                       \
+static void ftrace_raw_event_##call(proto)                             \
+{                                                                      \
+       ftrace_raw_event_id_##template(&event_##call, args);            \
 }                                                                      \
                                                                        \
-static int ftrace_raw_reg_event_##call(void *ptr)                      \
+static int ftrace_raw_reg_event_##call(struct ftrace_event_call *unused)\
 {                                                                      \
        int ret;                                                        \
                                                                        \
@@ -597,7 +737,7 @@ static int ftrace_raw_reg_event_##call(void *ptr)                   \
        return ret;                                                     \
 }                                                                      \
                                                                        \
-static void ftrace_raw_unreg_event_##call(void *ptr)                   \
+static void ftrace_raw_unreg_event_##call(struct ftrace_event_call *unused)\
 {                                                                      \
        unregister_trace_##call(ftrace_raw_event_##call);               \
 }                                                                      \
@@ -606,7 +746,7 @@ static struct trace_event ftrace_event_type_##call = {                      \
        .trace                  = ftrace_raw_output_##call,             \
 };                                                                     \
                                                                        \
-static int ftrace_raw_init_event_##call(void)                          \
+static int ftrace_raw_init_event_##call(struct ftrace_event_call *unused)\
 {                                                                      \
        int id;                                                         \
                                                                        \
@@ -616,7 +756,36 @@ static int ftrace_raw_init_event_##call(void)                              \
        event_##call.id = id;                                           \
        INIT_LIST_HEAD(&event_##call.fields);                           \
        return 0;                                                       \
-}                                                                      \
+}
+
+#undef DEFINE_EVENT_PRINT
+#define DEFINE_EVENT_PRINT(template, name, proto, args, print) \
+       DEFINE_EVENT(template, name, PARAMS(proto), PARAMS(args))
+
+#include TRACE_INCLUDE(TRACE_INCLUDE_FILE)
+
+#undef DECLARE_EVENT_CLASS
+#define DECLARE_EVENT_CLASS(call, proto, args, tstruct, assign, print)
+
+#undef DEFINE_EVENT
+#define DEFINE_EVENT(template, call, proto, args)                      \
+                                                                       \
+static struct ftrace_event_call __used                                 \
+__attribute__((__aligned__(4)))                                                \
+__attribute__((section("_ftrace_events"))) event_##call = {            \
+       .name                   = #call,                                \
+       .system                 = __stringify(TRACE_SYSTEM),            \
+       .event                  = &ftrace_event_type_##call,            \
+       .raw_init               = ftrace_raw_init_event_##call,         \
+       .regfunc                = ftrace_raw_reg_event_##call,          \
+       .unregfunc              = ftrace_raw_unreg_event_##call,        \
+       .show_format            = ftrace_format_##template,             \
+       .define_fields          = ftrace_define_fields_##template,      \
+       _TRACE_PROFILE_INIT(call)                                       \
+}
+
+#undef DEFINE_EVENT_PRINT
+#define DEFINE_EVENT_PRINT(template, call, proto, args, print)         \
                                                                        \
 static struct ftrace_event_call __used                                 \
 __attribute__((__aligned__(4)))                                                \
@@ -628,7 +797,7 @@ __attribute__((section("_ftrace_events"))) event_##call = {         \
        .regfunc                = ftrace_raw_reg_event_##call,          \
        .unregfunc              = ftrace_raw_unreg_event_##call,        \
        .show_format            = ftrace_format_##call,                 \
-       .define_fields          = ftrace_define_fields_##call,          \
+       .define_fields          = ftrace_define_fields_##template,      \
        _TRACE_PROFILE_INIT(call)                                       \
 }
 
@@ -646,6 +815,7 @@ __attribute__((section("_ftrace_events"))) event_##call = {         \
  *     struct ftrace_event_call *event_call = &event_<call>;
  *     extern void perf_tp_event(int, u64, u64, void *, int);
  *     struct ftrace_raw_##call *entry;
+ *     struct perf_trace_buf *trace_buf;
  *     u64 __addr = 0, __count = 1;
  *     unsigned long irq_flags;
  *     struct trace_entry *ent;
@@ -670,14 +840,25 @@ __attribute__((section("_ftrace_events"))) event_##call = {               \
  *     __cpu = smp_processor_id();
  *
  *     if (in_nmi())
- *             raw_data = rcu_dereference(trace_profile_buf_nmi);
+ *             trace_buf = rcu_dereference(perf_trace_buf_nmi);
  *     else
- *             raw_data = rcu_dereference(trace_profile_buf);
+ *             trace_buf = rcu_dereference(perf_trace_buf);
  *
- *     if (!raw_data)
+ *     if (!trace_buf)
  *             goto end;
  *
- *     raw_data = per_cpu_ptr(raw_data, __cpu);
+ *     trace_buf = per_cpu_ptr(trace_buf, __cpu);
+ *
+ *     // Avoid recursion from perf that could mess up the buffer
+ *     if (trace_buf->recursion++)
+ *             goto end_recursion;
+ *
+ *     raw_data = trace_buf->buf;
+ *
+ *     // Make recursion update visible before entering perf_tp_event
+ *     // so that we protect from perf recursions.
+ *
+ *     barrier();
  *
  *     //zero dead bytes from alignment to avoid stack leak to userspace:
  *     *(u64 *)(&raw_data[__entry_size - sizeof(u64)]) = 0ULL;
@@ -704,21 +885,26 @@ __attribute__((section("_ftrace_events"))) event_##call = {               \
 #undef __perf_count
 #define __perf_count(c) __count = (c)
 
-#undef TRACE_EVENT
-#define TRACE_EVENT(call, proto, args, tstruct, assign, print)         \
-static void ftrace_profile_##call(proto)                               \
+#undef DECLARE_EVENT_CLASS
+#define DECLARE_EVENT_CLASS(call, proto, args, tstruct, assign, print) \
+static void                                                            \
+ftrace_profile_templ_##call(struct ftrace_event_call *event_call,      \
+                           proto)                                      \
 {                                                                      \
        struct ftrace_data_offsets_##call __maybe_unused __data_offsets;\
-       struct ftrace_event_call *event_call = &event_##call;           \
-       extern void perf_tp_event(int, u64, u64, void *, int);  \
+       extern int perf_swevent_get_recursion_context(void);            \
+       extern void perf_swevent_put_recursion_context(int rctx);       \
+       extern void perf_tp_event(int, u64, u64, void *, int);          \
        struct ftrace_raw_##call *entry;                                \
        u64 __addr = 0, __count = 1;                                    \
        unsigned long irq_flags;                                        \
        struct trace_entry *ent;                                        \
        int __entry_size;                                               \
        int __data_size;                                                \
+       char *trace_buf;                                                \
        char *raw_data;                                                 \
        int __cpu;                                                      \
+       int rctx;                                                       \
        int pc;                                                         \
                                                                        \
        pc = preempt_count();                                           \
@@ -733,17 +919,22 @@ static void ftrace_profile_##call(proto)                          \
                return;                                                 \
                                                                        \
        local_irq_save(irq_flags);                                      \
+                                                                       \
+       rctx = perf_swevent_get_recursion_context();                    \
+       if (rctx < 0)                                                   \
+               goto end_recursion;                                     \
+                                                                       \
        __cpu = smp_processor_id();                                     \
                                                                        \
        if (in_nmi())                                                   \
-               raw_data = rcu_dereference(trace_profile_buf_nmi);              \
+               trace_buf = rcu_dereference(perf_trace_buf_nmi);        \
        else                                                            \
-               raw_data = rcu_dereference(trace_profile_buf);          \
+               trace_buf = rcu_dereference(perf_trace_buf);            \
                                                                        \
-       if (!raw_data)                                                  \
+       if (!trace_buf)                                                 \
                goto end;                                               \
                                                                        \
-       raw_data = per_cpu_ptr(raw_data, __cpu);                        \
+       raw_data = per_cpu_ptr(trace_buf, __cpu);                       \
                                                                        \
        *(u64 *)(&raw_data[__entry_size - sizeof(u64)]) = 0ULL;         \
        entry = (struct ftrace_raw_##call *)raw_data;                   \
@@ -759,10 +950,25 @@ static void ftrace_profile_##call(proto)                          \
                             __entry_size);                             \
                                                                        \
 end:                                                                   \
+       perf_swevent_put_recursion_context(rctx);                       \
+end_recursion:                                                         \
        local_irq_restore(irq_flags);                                   \
                                                                        \
 }
 
+#undef DEFINE_EVENT
+#define DEFINE_EVENT(template, call, proto, args)              \
+static void ftrace_profile_##call(proto)                       \
+{                                                              \
+       struct ftrace_event_call *event_call = &event_##call;   \
+                                                               \
+       ftrace_profile_templ_##template(event_call, args);      \
+}
+
+#undef DEFINE_EVENT_PRINT
+#define DEFINE_EVENT_PRINT(template, name, proto, args, print) \
+       DEFINE_EVENT(template, name, PARAMS(proto), PARAMS(args))
+
 #include TRACE_INCLUDE(TRACE_INCLUDE_FILE)
 #endif /* CONFIG_EVENT_PROFILE */
 
index e972f0a..961fda3 100644 (file)
  * A syscall entry in the ftrace syscalls array.
  *
  * @name: name of the syscall
+ * @syscall_nr: number of the syscall
  * @nb_args: number of parameters it takes
  * @types: list of types as strings
  * @args: list of args as strings (args[i] matches types[i])
- * @enter_id: associated ftrace enter event id
- * @exit_id: associated ftrace exit event id
  * @enter_event: associated syscall_enter trace event
  * @exit_event: associated syscall_exit trace event
  */
 struct syscall_metadata {
        const char      *name;
+       int             syscall_nr;
        int             nb_args;
        const char      **types;
        const char      **args;
-       int             enter_id;
-       int             exit_id;
 
        struct ftrace_event_call *enter_event;
        struct ftrace_event_call *exit_event;
@@ -34,29 +32,28 @@ struct syscall_metadata {
 
 #ifdef CONFIG_FTRACE_SYSCALLS
 extern unsigned long arch_syscall_addr(int nr);
-extern int syscall_name_to_nr(char *name);
-void set_syscall_enter_id(int num, int id);
-void set_syscall_exit_id(int num, int id);
-extern struct trace_event event_syscall_enter;
-extern struct trace_event event_syscall_exit;
-extern int reg_event_syscall_enter(void *ptr);
-extern void unreg_event_syscall_enter(void *ptr);
-extern int reg_event_syscall_exit(void *ptr);
-extern void unreg_event_syscall_exit(void *ptr);
+extern int init_syscall_trace(struct ftrace_event_call *call);
+
 extern int syscall_enter_format(struct ftrace_event_call *call,
                                struct trace_seq *s);
 extern int syscall_exit_format(struct ftrace_event_call *call,
                                struct trace_seq *s);
 extern int syscall_enter_define_fields(struct ftrace_event_call *call);
 extern int syscall_exit_define_fields(struct ftrace_event_call *call);
+extern int reg_event_syscall_enter(struct ftrace_event_call *call);
+extern void unreg_event_syscall_enter(struct ftrace_event_call *call);
+extern int reg_event_syscall_exit(struct ftrace_event_call *call);
+extern void unreg_event_syscall_exit(struct ftrace_event_call *call);
+extern int
+ftrace_format_syscall(struct ftrace_event_call *call, struct trace_seq *s);
 enum print_line_t print_syscall_enter(struct trace_iterator *iter, int flags);
 enum print_line_t print_syscall_exit(struct trace_iterator *iter, int flags);
 #endif
 #ifdef CONFIG_EVENT_PROFILE
-int reg_prof_syscall_enter(char *name);
-void unreg_prof_syscall_enter(char *name);
-int reg_prof_syscall_exit(char *name);
-void unreg_prof_syscall_exit(char *name);
+int prof_sysenter_enable(struct ftrace_event_call *call);
+void prof_sysenter_disable(struct ftrace_event_call *call);
+int prof_sysexit_enable(struct ftrace_event_call *call);
+void prof_sysexit_disable(struct ftrace_event_call *call);
 
 #endif
 
index b5cc72f..8c2f385 100644 (file)
@@ -117,8 +117,6 @@ struct pxa168fb_mach_info {
        unsigned        invert_composite_blank:1;
        unsigned        invert_pix_val_ena:1;
        unsigned        invert_pixclock:1;
-       unsigned        invert_vsync:1;
-       unsigned        invert_hsync:1;
        unsigned        panel_rbswap:1;
        unsigned        active:1;
        unsigned        enable_lcd:1;
index 9ee7782..3889924 100644 (file)
@@ -763,6 +763,7 @@ config UID16
 
 config SYSCTL_SYSCALL
        bool "Sysctl syscall support" if EMBEDDED
+       depends on PROC_SYSCTL
        default y
        select SYSCTL
        ---help---
index 7d37047..56410fa 100644 (file)
@@ -129,136 +129,60 @@ static int proc_ipcauto_dointvec_minmax(ctl_table *table, int write,
 #define proc_ipcauto_dointvec_minmax NULL
 #endif
 
-#ifdef CONFIG_SYSCTL_SYSCALL
-/* The generic sysctl ipc data routine. */
-static int sysctl_ipc_data(ctl_table *table,
-               void __user *oldval, size_t __user *oldlenp,
-               void __user *newval, size_t newlen)
-{
-       size_t len;
-       void *data;
-
-       /* Get out of I don't have a variable */
-       if (!table->data || !table->maxlen)
-               return -ENOTDIR;
-
-       data = get_ipc(table);
-       if (!data)
-               return -ENOTDIR;
-
-       if (oldval && oldlenp) {
-               if (get_user(len, oldlenp))
-                       return -EFAULT;
-               if (len) {
-                       if (len > table->maxlen)
-                               len = table->maxlen;
-                       if (copy_to_user(oldval, data, len))
-                               return -EFAULT;
-                       if (put_user(len, oldlenp))
-                               return -EFAULT;
-               }
-       }
-
-       if (newval && newlen) {
-               if (newlen > table->maxlen)
-                       newlen = table->maxlen;
-
-               if (copy_from_user(data, newval, newlen))
-                       return -EFAULT;
-       }
-       return 1;
-}
-
-static int sysctl_ipc_registered_data(ctl_table *table,
-               void __user *oldval, size_t __user *oldlenp,
-               void __user *newval, size_t newlen)
-{
-       int rc;
-
-       rc = sysctl_ipc_data(table, oldval, oldlenp, newval, newlen);
-
-       if (newval && newlen && rc > 0)
-               /*
-                * Tunable has successfully been changed from userland
-                */
-               unregister_ipcns_notifier(current->nsproxy->ipc_ns);
-
-       return rc;
-}
-#else
-#define sysctl_ipc_data NULL
-#define sysctl_ipc_registered_data NULL
-#endif
-
 static int zero;
 static int one = 1;
 
 static struct ctl_table ipc_kern_table[] = {
        {
-               .ctl_name       = KERN_SHMMAX,
                .procname       = "shmmax",
                .data           = &init_ipc_ns.shm_ctlmax,
                .maxlen         = sizeof (init_ipc_ns.shm_ctlmax),
                .mode           = 0644,
                .proc_handler   = proc_ipc_doulongvec_minmax,
-               .strategy       = sysctl_ipc_data,
        },
        {
-               .ctl_name       = KERN_SHMALL,
                .procname       = "shmall",
                .data           = &init_ipc_ns.shm_ctlall,
                .maxlen         = sizeof (init_ipc_ns.shm_ctlall),
                .mode           = 0644,
                .proc_handler   = proc_ipc_doulongvec_minmax,
-               .strategy       = sysctl_ipc_data,
        },
        {
-               .ctl_name       = KERN_SHMMNI,
                .procname       = "shmmni",
                .data           = &init_ipc_ns.shm_ctlmni,
                .maxlen         = sizeof (init_ipc_ns.shm_ctlmni),
                .mode           = 0644,
                .proc_handler   = proc_ipc_dointvec,
-               .strategy       = sysctl_ipc_data,
        },
        {
-               .ctl_name       = KERN_MSGMAX,
                .procname       = "msgmax",
                .data           = &init_ipc_ns.msg_ctlmax,
                .maxlen         = sizeof (init_ipc_ns.msg_ctlmax),
                .mode           = 0644,
                .proc_handler   = proc_ipc_dointvec,
-               .strategy       = sysctl_ipc_data,
        },
        {
-               .ctl_name       = KERN_MSGMNI,
                .procname       = "msgmni",
                .data           = &init_ipc_ns.msg_ctlmni,
                .maxlen         = sizeof (init_ipc_ns.msg_ctlmni),
                .mode           = 0644,
                .proc_handler   = proc_ipc_callback_dointvec,
-               .strategy       = sysctl_ipc_registered_data,
        },
        {
-               .ctl_name       = KERN_MSGMNB,
                .procname       =  "msgmnb",
                .data           = &init_ipc_ns.msg_ctlmnb,
                .maxlen         = sizeof (init_ipc_ns.msg_ctlmnb),
                .mode           = 0644,
                .proc_handler   = proc_ipc_dointvec,
-               .strategy       = sysctl_ipc_data,
        },
        {
-               .ctl_name       = KERN_SEM,
                .procname       = "sem",
                .data           = &init_ipc_ns.sem_ctls,
                .maxlen         = 4*sizeof (int),
                .mode           = 0644,
                .proc_handler   = proc_ipc_dointvec,
-               .strategy       = sysctl_ipc_data,
        },
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "auto_msgmni",
                .data           = &init_ipc_ns.auto_msgmni,
                .maxlen         = sizeof(int),
@@ -272,7 +196,6 @@ static struct ctl_table ipc_kern_table[] = {
 
 static struct ctl_table ipc_root_table[] = {
        {
-               .ctl_name       = CTL_KERN,
                .procname       = "kernel",
                .mode           = 0555,
                .child          = ipc_kern_table,
index 8a05871..0c09366 100644 (file)
@@ -88,7 +88,7 @@ static ctl_table mq_sysctls[] = {
                .extra1         = &msg_maxsize_limit_min,
                .extra2         = &msg_maxsize_limit_max,
        },
-       { .ctl_name = 0 }
+       {}
 };
 
 static ctl_table mq_sysctl_dir[] = {
@@ -97,17 +97,16 @@ static ctl_table mq_sysctl_dir[] = {
                .mode           = 0555,
                .child          = mq_sysctls,
        },
-       { .ctl_name = 0 }
+       {}
 };
 
 static ctl_table mq_sysctl_root[] = {
        {
-               .ctl_name       = CTL_FS,
                .procname       = "fs",
                .mode           = 0555,
                .child          = mq_sysctl_dir,
        },
-       { .ctl_name = 0 }
+       {}
 };
 
 struct ctl_table_header *mq_register_sysctl_table(void)
index dcf6789..864ff75 100644 (file)
@@ -4,7 +4,7 @@
 
 obj-y     = sched.o fork.o exec_domain.o panic.o printk.o \
            cpu.o exit.o itimer.o time.o softirq.o resource.o \
-           sysctl.o capability.o ptrace.o timer.o user.o \
+           sysctl.o sysctl_binary.o capability.o ptrace.o timer.o user.o \
            signal.o sys.o kmod.o workqueue.o pid.o \
            rcupdate.o extable.o params.o posix-timers.o \
            kthread.o wait.o kfifo.o sys_ni.o posix-cpu-timers.o mutex.o \
@@ -21,6 +21,7 @@ CFLAGS_REMOVE_mutex-debug.o = -pg
 CFLAGS_REMOVE_rtmutex-debug.o = -pg
 CFLAGS_REMOVE_cgroup-debug.o = -pg
 CFLAGS_REMOVE_sched_clock.o = -pg
+CFLAGS_REMOVE_perf_event.o = -pg
 endif
 
 obj-$(CONFIG_FREEZER) += freezer.o
@@ -97,6 +98,8 @@ obj-$(CONFIG_SMP) += sched_cpupri.o
 obj-$(CONFIG_SLOW_WORK) += slow-work.o
 obj-$(CONFIG_SLOW_WORK_DEBUG) += slow-work-debugfs.o
 obj-$(CONFIG_PERF_EVENTS) += perf_event.o
+obj-$(CONFIG_HAVE_HW_BREAKPOINT) += hw_breakpoint.o
+obj-$(CONFIG_USER_RETURN_NOTIFIER) += user-return-notifier.o
 
 ifneq ($(CONFIG_SCHED_OMIT_FRAME_POINTER),y)
 # According to Alan Modra <alan@linuxcare.com.au>, the -fno-omit-frame-pointer is
index b5cb469..3cf2183 100644 (file)
@@ -537,8 +537,7 @@ update_domain_attr_tree(struct sched_domain_attr *dattr, struct cpuset *c)
  *     element of the partition (one sched domain) to be passed to
  *     partition_sched_domains().
  */
-/* FIXME: see the FIXME in partition_sched_domains() */
-static int generate_sched_domains(struct cpumask **domains,
+static int generate_sched_domains(cpumask_var_t **domains,
                        struct sched_domain_attr **attributes)
 {
        LIST_HEAD(q);           /* queue of cpusets to be scanned */
@@ -546,7 +545,7 @@ static int generate_sched_domains(struct cpumask **domains,
        struct cpuset **csa;    /* array of all cpuset ptrs */
        int csn;                /* how many cpuset ptrs in csa so far */
        int i, j, k;            /* indices for partition finding loops */
-       struct cpumask *doms;   /* resulting partition; i.e. sched domains */
+       cpumask_var_t *doms;    /* resulting partition; i.e. sched domains */
        struct sched_domain_attr *dattr;  /* attributes for custom domains */
        int ndoms = 0;          /* number of sched domains in result */
        int nslot;              /* next empty doms[] struct cpumask slot */
@@ -557,7 +556,8 @@ static int generate_sched_domains(struct cpumask **domains,
 
        /* Special case for the 99% of systems with one, full, sched domain */
        if (is_sched_load_balance(&top_cpuset)) {
-               doms = kmalloc(cpumask_size(), GFP_KERNEL);
+               ndoms = 1;
+               doms = alloc_sched_domains(ndoms);
                if (!doms)
                        goto done;
 
@@ -566,9 +566,8 @@ static int generate_sched_domains(struct cpumask **domains,
                        *dattr = SD_ATTR_INIT;
                        update_domain_attr_tree(dattr, &top_cpuset);
                }
-               cpumask_copy(doms, top_cpuset.cpus_allowed);
+               cpumask_copy(doms[0], top_cpuset.cpus_allowed);
 
-               ndoms = 1;
                goto done;
        }
 
@@ -636,7 +635,7 @@ restart:
         * Now we know how many domains to create.
         * Convert <csn, csa> to <ndoms, doms> and populate cpu masks.
         */
-       doms = kmalloc(ndoms * cpumask_size(), GFP_KERNEL);
+       doms = alloc_sched_domains(ndoms);
        if (!doms)
                goto done;
 
@@ -656,7 +655,7 @@ restart:
                        continue;
                }
 
-               dp = doms + nslot;
+               dp = doms[nslot];
 
                if (nslot == ndoms) {
                        static int warnings = 10;
@@ -718,7 +717,7 @@ done:
 static void do_rebuild_sched_domains(struct work_struct *unused)
 {
        struct sched_domain_attr *attr;
-       struct cpumask *doms;
+       cpumask_var_t *doms;
        int ndoms;
 
        get_online_cpus();
@@ -2052,7 +2051,7 @@ static int cpuset_track_online_cpus(struct notifier_block *unused_nb,
                                unsigned long phase, void *unused_cpu)
 {
        struct sched_domain_attr *attr;
-       struct cpumask *doms;
+       cpumask_var_t *doms;
        int ndoms;
 
        switch (phase) {
@@ -2537,15 +2536,9 @@ const struct file_operations proc_cpuset_operations = {
 };
 #endif /* CONFIG_PROC_PID_CPUSET */
 
-/* Display task cpus_allowed, mems_allowed in /proc/<pid>/status file. */
+/* Display task mems_allowed in /proc/<pid>/status file. */
 void cpuset_task_status_allowed(struct seq_file *m, struct task_struct *task)
 {
-       seq_printf(m, "Cpus_allowed:\t");
-       seq_cpumask(m, &task->cpus_allowed);
-       seq_printf(m, "\n");
-       seq_printf(m, "Cpus_allowed_list:\t");
-       seq_cpumask_list(m, &task->cpus_allowed);
-       seq_printf(m, "\n");
        seq_printf(m, "Mems_allowed:\t");
        seq_nodemask(m, &task->mems_allowed);
        seq_printf(m, "\n");
index f7864ac..1143012 100644 (file)
@@ -49,6 +49,7 @@
 #include <linux/init_task.h>
 #include <linux/perf_event.h>
 #include <trace/events/sched.h>
+#include <linux/hw_breakpoint.h>
 
 #include <asm/uaccess.h>
 #include <asm/unistd.h>
@@ -110,9 +111,9 @@ static void __exit_signal(struct task_struct *tsk)
                 * We won't ever get here for the group leader, since it
                 * will have been the last reference on the signal_struct.
                 */
-               sig->utime = cputime_add(sig->utime, task_utime(tsk));
-               sig->stime = cputime_add(sig->stime, task_stime(tsk));
-               sig->gtime = cputime_add(sig->gtime, task_gtime(tsk));
+               sig->utime = cputime_add(sig->utime, tsk->utime);
+               sig->stime = cputime_add(sig->stime, tsk->stime);
+               sig->gtime = cputime_add(sig->gtime, tsk->gtime);
                sig->min_flt += tsk->min_flt;
                sig->maj_flt += tsk->maj_flt;
                sig->nvcsw += tsk->nvcsw;
@@ -978,6 +979,10 @@ NORET_TYPE void do_exit(long code)
        proc_exit_connector(tsk);
 
        /*
+        * FIXME: do that only when needed, using sched_exit tracepoint
+        */
+       flush_ptrace_hw_breakpoint(tsk);
+       /*
         * Flush inherited counters to the parent - before the parent
         * gets woken up by child-exit notifications.
         */
@@ -1004,7 +1009,7 @@ NORET_TYPE void do_exit(long code)
        tsk->flags |= PF_EXITPIDONE;
 
        if (tsk->io_context)
-               exit_io_context();
+               exit_io_context(tsk);
 
        if (tsk->splice_pipe)
                __free_pipe_info(tsk->splice_pipe);
@@ -1205,6 +1210,7 @@ static int wait_task_zombie(struct wait_opts *wo, struct task_struct *p)
                struct signal_struct *psig;
                struct signal_struct *sig;
                unsigned long maxrss;
+               cputime_t tgutime, tgstime;
 
                /*
                 * The resource counters for the group leader are in its
@@ -1220,20 +1226,23 @@ static int wait_task_zombie(struct wait_opts *wo, struct task_struct *p)
                 * need to protect the access to parent->signal fields,
                 * as other threads in the parent group can be right
                 * here reaping other children at the same time.
+                *
+                * We use thread_group_times() to get times for the thread
+                * group, which consolidates times for all threads in the
+                * group including the group leader.
                 */
+               thread_group_times(p, &tgutime, &tgstime);
                spin_lock_irq(&p->real_parent->sighand->siglock);
                psig = p->real_parent->signal;
                sig = p->signal;
                psig->cutime =
                        cputime_add(psig->cutime,
-                       cputime_add(p->utime,
-                       cputime_add(sig->utime,
-                                   sig->cutime)));
+                       cputime_add(tgutime,
+                                   sig->cutime));
                psig->cstime =
                        cputime_add(psig->cstime,
-                       cputime_add(p->stime,
-                       cputime_add(sig->stime,
-                                   sig->cstime)));
+                       cputime_add(tgstime,
+                                   sig->cstime));
                psig->cgtime =
                        cputime_add(psig->cgtime,
                        cputime_add(p->gtime,
index 166b8c4..1415dc4 100644 (file)
@@ -64,6 +64,7 @@
 #include <linux/magic.h>
 #include <linux/perf_event.h>
 #include <linux/posix-timers.h>
+#include <linux/user-return-notifier.h>
 
 #include <asm/pgtable.h>
 #include <asm/pgalloc.h>
@@ -249,6 +250,7 @@ static struct task_struct *dup_task_struct(struct task_struct *orig)
                goto out;
 
        setup_thread_stack(tsk, orig);
+       clear_user_return_notifier(tsk);
        stackend = end_of_stack(tsk);
        *stackend = STACK_END_MAGIC;    /* for overflow detection */
 
@@ -884,6 +886,9 @@ static int copy_signal(unsigned long clone_flags, struct task_struct *tsk)
        sig->utime = sig->stime = sig->cutime = sig->cstime = cputime_zero;
        sig->gtime = cputime_zero;
        sig->cgtime = cputime_zero;
+#ifndef CONFIG_VIRT_CPU_ACCOUNTING
+       sig->prev_utime = sig->prev_stime = cputime_zero;
+#endif
        sig->nvcsw = sig->nivcsw = sig->cnvcsw = sig->cnivcsw = 0;
        sig->min_flt = sig->maj_flt = sig->cmin_flt = sig->cmaj_flt = 0;
        sig->inblock = sig->oublock = sig->cinblock = sig->coublock = 0;
@@ -1066,8 +1071,10 @@ static struct task_struct *copy_process(unsigned long clone_flags,
        p->gtime = cputime_zero;
        p->utimescaled = cputime_zero;
        p->stimescaled = cputime_zero;
+#ifndef CONFIG_VIRT_CPU_ACCOUNTING
        p->prev_utime = cputime_zero;
        p->prev_stime = cputime_zero;
+#endif
 
        p->default_timer_slack_ns = current->timer_slack_ns;
 
@@ -1310,7 +1317,8 @@ bad_fork_free_pid:
        if (pid != &init_struct_pid)
                free_pid(pid);
 bad_fork_cleanup_io:
-       put_io_context(p->io_context);
+       if (p->io_context)
+               exit_io_context(p);
 bad_fork_cleanup_namespaces:
        exit_task_namespaces(p);
 bad_fork_cleanup_mm:
diff --git a/kernel/hw_breakpoint.c b/kernel/hw_breakpoint.c
new file mode 100644 (file)
index 0000000..cf5ee16
--- /dev/null
@@ -0,0 +1,423 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Copyright (C) 2007 Alan Stern
+ * Copyright (C) IBM Corporation, 2009
+ * Copyright (C) 2009, Frederic Weisbecker <fweisbec@gmail.com>
+ *
+ * Thanks to Ingo Molnar for his many suggestions.
+ *
+ * Authors: Alan Stern <stern@rowland.harvard.edu>
+ *          K.Prasad <prasad@linux.vnet.ibm.com>
+ *          Frederic Weisbecker <fweisbec@gmail.com>
+ */
+
+/*
+ * HW_breakpoint: a unified kernel/user-space hardware breakpoint facility,
+ * using the CPU's debug registers.
+ * This file contains the arch-independent routines.
+ */
+
+#include <linux/irqflags.h>
+#include <linux/kallsyms.h>
+#include <linux/notifier.h>
+#include <linux/kprobes.h>
+#include <linux/kdebug.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/percpu.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/smp.h>
+
+#include <linux/hw_breakpoint.h>
+
+/*
+ * Constraints data
+ */
+
+/* Number of pinned cpu breakpoints in a cpu */
+static DEFINE_PER_CPU(unsigned int, nr_cpu_bp_pinned);
+
+/* Number of pinned task breakpoints in a cpu */
+static DEFINE_PER_CPU(unsigned int, task_bp_pinned[HBP_NUM]);
+
+/* Number of non-pinned cpu/task breakpoints in a cpu */
+static DEFINE_PER_CPU(unsigned int, nr_bp_flexible);
+
+/* Gather the number of total pinned and un-pinned bp in a cpuset */
+struct bp_busy_slots {
+       unsigned int pinned;
+       unsigned int flexible;
+};
+
+/* Serialize accesses to the above constraints */
+static DEFINE_MUTEX(nr_bp_mutex);
+
+/*
+ * Report the maximum number of pinned breakpoints a task
+ * have in this cpu
+ */
+static unsigned int max_task_bp_pinned(int cpu)
+{
+       int i;
+       unsigned int *tsk_pinned = per_cpu(task_bp_pinned, cpu);
+
+       for (i = HBP_NUM -1; i >= 0; i--) {
+               if (tsk_pinned[i] > 0)
+                       return i + 1;
+       }
+
+       return 0;
+}
+
+/*
+ * Report the number of pinned/un-pinned breakpoints we have in
+ * a given cpu (cpu > -1) or in all of them (cpu = -1).
+ */
+static void fetch_bp_busy_slots(struct bp_busy_slots *slots, int cpu)
+{
+       if (cpu >= 0) {
+               slots->pinned = per_cpu(nr_cpu_bp_pinned, cpu);
+               slots->pinned += max_task_bp_pinned(cpu);
+               slots->flexible = per_cpu(nr_bp_flexible, cpu);
+
+               return;
+       }
+
+       for_each_online_cpu(cpu) {
+               unsigned int nr;
+
+               nr = per_cpu(nr_cpu_bp_pinned, cpu);
+               nr += max_task_bp_pinned(cpu);
+
+               if (nr > slots->pinned)
+                       slots->pinned = nr;
+
+               nr = per_cpu(nr_bp_flexible, cpu);
+
+               if (nr > slots->flexible)
+                       slots->flexible = nr;
+       }
+}
+
+/*
+ * Add a pinned breakpoint for the given task in our constraint table
+ */
+static void toggle_bp_task_slot(struct task_struct *tsk, int cpu, bool enable)
+{
+       int count = 0;
+       struct perf_event *bp;
+       struct perf_event_context *ctx = tsk->perf_event_ctxp;
+       unsigned int *tsk_pinned;
+       struct list_head *list;
+       unsigned long flags;
+
+       if (WARN_ONCE(!ctx, "No perf context for this task"))
+               return;
+
+       list = &ctx->event_list;
+
+       spin_lock_irqsave(&ctx->lock, flags);
+
+       /*
+        * The current breakpoint counter is not included in the list
+        * at the open() callback time
+        */
+       list_for_each_entry(bp, list, event_entry) {
+               if (bp->attr.type == PERF_TYPE_BREAKPOINT)
+                       count++;
+       }
+
+       spin_unlock_irqrestore(&ctx->lock, flags);
+
+       if (WARN_ONCE(count < 0, "No breakpoint counter found in the counter list"))
+               return;
+
+       tsk_pinned = per_cpu(task_bp_pinned, cpu);
+       if (enable) {
+               tsk_pinned[count]++;
+               if (count > 0)
+                       tsk_pinned[count-1]--;
+       } else {
+               tsk_pinned[count]--;
+               if (count > 0)
+                       tsk_pinned[count-1]++;
+       }
+}
+
+/*
+ * Add/remove the given breakpoint in our constraint table
+ */
+static void toggle_bp_slot(struct perf_event *bp, bool enable)
+{
+       int cpu = bp->cpu;
+       struct task_struct *tsk = bp->ctx->task;
+
+       /* Pinned counter task profiling */
+       if (tsk) {
+               if (cpu >= 0) {
+                       toggle_bp_task_slot(tsk, cpu, enable);
+                       return;
+               }
+
+               for_each_online_cpu(cpu)
+                       toggle_bp_task_slot(tsk, cpu, enable);
+               return;
+       }
+
+       /* Pinned counter cpu profiling */
+       if (enable)
+               per_cpu(nr_cpu_bp_pinned, bp->cpu)++;
+       else
+               per_cpu(nr_cpu_bp_pinned, bp->cpu)--;
+}
+
+/*
+ * Contraints to check before allowing this new breakpoint counter:
+ *
+ *  == Non-pinned counter == (Considered as pinned for now)
+ *
+ *   - If attached to a single cpu, check:
+ *
+ *       (per_cpu(nr_bp_flexible, cpu) || (per_cpu(nr_cpu_bp_pinned, cpu)
+ *           + max(per_cpu(task_bp_pinned, cpu)))) < HBP_NUM
+ *
+ *       -> If there are already non-pinned counters in this cpu, it means
+ *          there is already a free slot for them.
+ *          Otherwise, we check that the maximum number of per task
+ *          breakpoints (for this cpu) plus the number of per cpu breakpoint
+ *          (for this cpu) doesn't cover every registers.
+ *
+ *   - If attached to every cpus, check:
+ *
+ *       (per_cpu(nr_bp_flexible, *) || (max(per_cpu(nr_cpu_bp_pinned, *))
+ *           + max(per_cpu(task_bp_pinned, *)))) < HBP_NUM
+ *
+ *       -> This is roughly the same, except we check the number of per cpu
+ *          bp for every cpu and we keep the max one. Same for the per tasks
+ *          breakpoints.
+ *
+ *
+ * == Pinned counter ==
+ *
+ *   - If attached to a single cpu, check:
+ *
+ *       ((per_cpu(nr_bp_flexible, cpu) > 1) + per_cpu(nr_cpu_bp_pinned, cpu)
+ *            + max(per_cpu(task_bp_pinned, cpu))) < HBP_NUM
+ *
+ *       -> Same checks as before. But now the nr_bp_flexible, if any, must keep
+ *          one register at least (or they will never be fed).
+ *
+ *   - If attached to every cpus, check:
+ *
+ *       ((per_cpu(nr_bp_flexible, *) > 1) + max(per_cpu(nr_cpu_bp_pinned, *))
+ *            + max(per_cpu(task_bp_pinned, *))) < HBP_NUM
+ */
+int reserve_bp_slot(struct perf_event *bp)
+{
+       struct bp_busy_slots slots = {0};
+       int ret = 0;
+
+       mutex_lock(&nr_bp_mutex);
+
+       fetch_bp_busy_slots(&slots, bp->cpu);
+
+       /* Flexible counters need to keep at least one slot */
+       if (slots.pinned + (!!slots.flexible) == HBP_NUM) {
+               ret = -ENOSPC;
+               goto end;
+       }
+
+       toggle_bp_slot(bp, true);
+
+end:
+       mutex_unlock(&nr_bp_mutex);
+
+       return ret;
+}
+
+void release_bp_slot(struct perf_event *bp)
+{
+       mutex_lock(&nr_bp_mutex);
+
+       toggle_bp_slot(bp, false);
+
+       mutex_unlock(&nr_bp_mutex);
+}
+
+
+int __register_perf_hw_breakpoint(struct perf_event *bp)
+{
+       int ret;
+
+       ret = reserve_bp_slot(bp);
+       if (ret)
+               return ret;
+
+       /*
+        * Ptrace breakpoints can be temporary perf events only
+        * meant to reserve a slot. In this case, it is created disabled and
+        * we don't want to check the params right now (as we put a null addr)
+        * But perf tools create events as disabled and we want to check
+        * the params for them.
+        * This is a quick hack that will be removed soon, once we remove
+        * the tmp breakpoints from ptrace
+        */
+       if (!bp->attr.disabled || bp->callback == perf_bp_event)
+               ret = arch_validate_hwbkpt_settings(bp, bp->ctx->task);
+
+       return ret;
+}
+
+int register_perf_hw_breakpoint(struct perf_event *bp)
+{
+       bp->callback = perf_bp_event;
+
+       return __register_perf_hw_breakpoint(bp);
+}
+
+/**
+ * register_user_hw_breakpoint - register a hardware breakpoint for user space
+ * @attr: breakpoint attributes
+ * @triggered: callback to trigger when we hit the breakpoint
+ * @tsk: pointer to 'task_struct' of the process to which the address belongs
+ */
+struct perf_event *
+register_user_hw_breakpoint(struct perf_event_attr *attr,
+                           perf_callback_t triggered,
+                           struct task_struct *tsk)
+{
+       return perf_event_create_kernel_counter(attr, -1, tsk->pid, triggered);
+}
+EXPORT_SYMBOL_GPL(register_user_hw_breakpoint);
+
+/**
+ * modify_user_hw_breakpoint - modify a user-space hardware breakpoint
+ * @bp: the breakpoint structure to modify
+ * @attr: new breakpoint attributes
+ * @triggered: callback to trigger when we hit the breakpoint
+ * @tsk: pointer to 'task_struct' of the process to which the address belongs
+ */
+struct perf_event *
+modify_user_hw_breakpoint(struct perf_event *bp, struct perf_event_attr *attr,
+                         perf_callback_t triggered,
+                         struct task_struct *tsk)
+{
+       /*
+        * FIXME: do it without unregistering
+        * - We don't want to lose our slot
+        * - If the new bp is incorrect, don't lose the older one
+        */
+       unregister_hw_breakpoint(bp);
+
+       return perf_event_create_kernel_counter(attr, -1, tsk->pid, triggered);
+}
+EXPORT_SYMBOL_GPL(modify_user_hw_breakpoint);
+
+/**
+ * unregister_hw_breakpoint - unregister a user-space hardware breakpoint
+ * @bp: the breakpoint structure to unregister
+ */
+void unregister_hw_breakpoint(struct perf_event *bp)
+{
+       if (!bp)
+               return;
+       perf_event_release_kernel(bp);
+}
+EXPORT_SYMBOL_GPL(unregister_hw_breakpoint);
+
+/**
+ * register_wide_hw_breakpoint - register a wide breakpoint in the kernel
+ * @attr: breakpoint attributes
+ * @triggered: callback to trigger when we hit the breakpoint
+ *
+ * @return a set of per_cpu pointers to perf events
+ */
+struct perf_event **
+register_wide_hw_breakpoint(struct perf_event_attr *attr,
+                           perf_callback_t triggered)
+{
+       struct perf_event **cpu_events, **pevent, *bp;
+       long err;
+       int cpu;
+
+       cpu_events = alloc_percpu(typeof(*cpu_events));
+       if (!cpu_events)
+               return ERR_PTR(-ENOMEM);
+
+       for_each_possible_cpu(cpu) {
+               pevent = per_cpu_ptr(cpu_events, cpu);
+               bp = perf_event_create_kernel_counter(attr, cpu, -1, triggered);
+
+               *pevent = bp;
+
+               if (IS_ERR(bp)) {
+                       err = PTR_ERR(bp);
+                       goto fail;
+               }
+       }
+
+       return cpu_events;
+
+fail:
+       for_each_possible_cpu(cpu) {
+               pevent = per_cpu_ptr(cpu_events, cpu);
+               if (IS_ERR(*pevent))
+                       break;
+               unregister_hw_breakpoint(*pevent);
+       }
+       free_percpu(cpu_events);
+       /* return the error if any */
+       return ERR_PTR(err);
+}
+EXPORT_SYMBOL_GPL(register_wide_hw_breakpoint);
+
+/**
+ * unregister_wide_hw_breakpoint - unregister a wide breakpoint in the kernel
+ * @cpu_events: the per cpu set of events to unregister
+ */
+void unregister_wide_hw_breakpoint(struct perf_event **cpu_events)
+{
+       int cpu;
+       struct perf_event **pevent;
+
+       for_each_possible_cpu(cpu) {
+               pevent = per_cpu_ptr(cpu_events, cpu);
+               unregister_hw_breakpoint(*pevent);
+       }
+       free_percpu(cpu_events);
+}
+EXPORT_SYMBOL_GPL(unregister_wide_hw_breakpoint);
+
+static struct notifier_block hw_breakpoint_exceptions_nb = {
+       .notifier_call = hw_breakpoint_exceptions_notify,
+       /* we need to be notified first */
+       .priority = 0x7fffffff
+};
+
+static int __init init_hw_breakpoint(void)
+{
+       return register_die_notifier(&hw_breakpoint_exceptions_nb);
+}
+core_initcall(init_hw_breakpoint);
+
+
+struct pmu perf_ops_bp = {
+       .enable         = arch_install_hw_breakpoint,
+       .disable        = arch_uninstall_hw_breakpoint,
+       .read           = hw_breakpoint_pmu_read,
+       .unthrottle     = hw_breakpoint_pmu_unthrottle
+};
index 8b6b8b6..8e5288a 100644 (file)
@@ -181,6 +181,7 @@ unsigned long kallsyms_lookup_name(const char *name)
        }
        return module_kallsyms_lookup_name(name);
 }
+EXPORT_SYMBOL_GPL(kallsyms_lookup_name);
 
 int kallsyms_on_each_symbol(int (*fn)(void *, const char *, struct module *,
                                      unsigned long),
index 9147a31..7d70146 100644 (file)
@@ -870,7 +870,7 @@ static void gdb_cmd_getregs(struct kgdb_state *ks)
 
        /*
         * All threads that don't have debuggerinfo should be
-        * in __schedule() sleeping, since all other CPUs
+        * in schedule() sleeping, since all other CPUs
         * are in kgdb_wait, and thus have debuggerinfo.
         */
        if (local_debuggerinfo) {
index 1494e85..e5342a3 100644 (file)
@@ -90,6 +90,9 @@ static spinlock_t *kretprobe_table_lock_ptr(unsigned long hash)
  */
 static struct kprobe_blackpoint kprobe_blacklist[] = {
        {"preempt_schedule",},
+       {"native_get_debugreg",},
+       {"irq_entries_start",},
+       {"common_interrupt",},
        {NULL}    /* Terminator */
 };
 
@@ -673,6 +676,40 @@ static kprobe_opcode_t __kprobes *kprobe_addr(struct kprobe *p)
        return (kprobe_opcode_t *)(((char *)addr) + p->offset);
 }
 
+/* Check passed kprobe is valid and return kprobe in kprobe_table. */
+static struct kprobe * __kprobes __get_valid_kprobe(struct kprobe *p)
+{
+       struct kprobe *old_p, *list_p;
+
+       old_p = get_kprobe(p->addr);
+       if (unlikely(!old_p))
+               return NULL;
+
+       if (p != old_p) {
+               list_for_each_entry_rcu(list_p, &old_p->list, list)
+                       if (list_p == p)
+                       /* kprobe p is a valid probe */
+                               goto valid;
+               return NULL;
+       }
+valid:
+       return old_p;
+}
+
+/* Return error if the kprobe is being re-registered */
+static inline int check_kprobe_rereg(struct kprobe *p)
+{
+       int ret = 0;
+       struct kprobe *old_p;
+
+       mutex_lock(&kprobe_mutex);
+       old_p = __get_valid_kprobe(p);
+       if (old_p)
+               ret = -EINVAL;
+       mutex_unlock(&kprobe_mutex);
+       return ret;
+}
+
 int __kprobes register_kprobe(struct kprobe *p)
 {
        int ret = 0;
@@ -685,6 +722,10 @@ int __kprobes register_kprobe(struct kprobe *p)
                return -EINVAL;
        p->addr = addr;
 
+       ret = check_kprobe_rereg(p);
+       if (ret)
+               return ret;
+
        preempt_disable();
        if (!kernel_text_address((unsigned long) p->addr) ||
            in_kprobes_functions((unsigned long) p->addr)) {
@@ -754,26 +795,6 @@ out:
 }
 EXPORT_SYMBOL_GPL(register_kprobe);
 
-/* Check passed kprobe is valid and return kprobe in kprobe_table. */
-static struct kprobe * __kprobes __get_valid_kprobe(struct kprobe *p)
-{
-       struct kprobe *old_p, *list_p;
-
-       old_p = get_kprobe(p->addr);
-       if (unlikely(!old_p))
-               return NULL;
-
-       if (p != old_p) {
-               list_for_each_entry_rcu(list_p, &old_p->list, list)
-                       if (list_p == p)
-                       /* kprobe p is a valid probe */
-                               goto valid;
-               return NULL;
-       }
-valid:
-       return old_p;
-}
-
 /*
  * Unregister a kprobe without a scheduler synchronization.
  */
@@ -1141,6 +1162,13 @@ static void __kprobes kill_kprobe(struct kprobe *p)
        arch_remove_kprobe(p);
 }
 
+void __kprobes dump_kprobe(struct kprobe *kp)
+{
+       printk(KERN_WARNING "Dumping kprobe:\n");
+       printk(KERN_WARNING "Name: %s\nAddress: %p\nOffset: %x\n",
+              kp->symbol_name, kp->addr, kp->offset);
+}
+
 /* Module notifier call back, checking kprobes on the module */
 static int __kprobes kprobes_module_callback(struct notifier_block *nb,
                                             unsigned long val, void *data)
index 9af5672..f5dcd36 100644 (file)
@@ -49,7 +49,7 @@
 #include "lockdep_internals.h"
 
 #define CREATE_TRACE_POINTS
-#include <trace/events/lockdep.h>
+#include <trace/events/lock.h>
 
 #ifdef CONFIG_PROVE_LOCKING
 int prove_locking = 1;
index 61d5aa5..acd24e7 100644 (file)
@@ -558,7 +558,7 @@ EXPORT_SYMBOL(unregister_reboot_notifier);
 
 static ATOMIC_NOTIFIER_HEAD(die_chain);
 
-int notrace notify_die(enum die_val val, const char *str,
+int notrace __kprobes notify_die(enum die_val val, const char *str,
               struct pt_regs *regs, long err, int trap, int sig)
 {
        struct die_args args = {
index 7f29643..6b7ddba 100644 (file)
@@ -28,6 +28,8 @@
 #include <linux/anon_inodes.h>
 #include <linux/kernel_stat.h>
 #include <linux/perf_event.h>
+#include <linux/ftrace_event.h>
+#include <linux/hw_breakpoint.h>
 
 #include <asm/irq_regs.h>
 
@@ -244,6 +246,49 @@ static void perf_unpin_context(struct perf_event_context *ctx)
        put_ctx(ctx);
 }
 
+static inline u64 perf_clock(void)
+{
+       return cpu_clock(smp_processor_id());
+}
+
+/*
+ * Update the record of the current time in a context.
+ */
+static void update_context_time(struct perf_event_context *ctx)
+{
+       u64 now = perf_clock();
+
+       ctx->time += now - ctx->timestamp;
+       ctx->timestamp = now;
+}
+
+/*
+ * Update the total_time_enabled and total_time_running fields for a event.
+ */
+static void update_event_times(struct perf_event *event)
+{
+       struct perf_event_context *ctx = event->ctx;
+       u64 run_end;
+
+       if (event->state < PERF_EVENT_STATE_INACTIVE ||
+           event->group_leader->state < PERF_EVENT_STATE_INACTIVE)
+               return;
+
+       if (ctx->is_active)
+               run_end = ctx->time;
+       else
+               run_end = event->tstamp_stopped;
+
+       event->total_time_enabled = run_end - event->tstamp_enabled;
+
+       if (event->state == PERF_EVENT_STATE_INACTIVE)
+               run_end = event->tstamp_stopped;
+       else
+               run_end = ctx->time;
+
+       event->total_time_running = run_end - event->tstamp_running;
+}
+
 /*
  * Add a event from the lists for its context.
  * Must be called with ctx->mutex and ctx->lock held.
@@ -292,6 +337,18 @@ list_del_event(struct perf_event *event, struct perf_event_context *ctx)
        if (event->group_leader != event)
                event->group_leader->nr_siblings--;
 
+       update_event_times(event);
+
+       /*
+        * If event was in error state, then keep it
+        * that way, otherwise bogus counts will be
+        * returned on read(). The only way to get out
+        * of error state is by explicit re-enabling
+        * of the event
+        */
+       if (event->state > PERF_EVENT_STATE_OFF)
+               event->state = PERF_EVENT_STATE_OFF;
+
        /*
         * If this was a group event with sibling events then
         * upgrade the siblings to singleton events by adding them
@@ -445,50 +502,11 @@ retry:
         * can remove the event safely, if the call above did not
         * succeed.
         */
-       if (!list_empty(&event->group_entry)) {
+       if (!list_empty(&event->group_entry))
                list_del_event(event, ctx);
-       }
        spin_unlock_irq(&ctx->lock);
 }
 
-static inline u64 perf_clock(void)
-{
-       return cpu_clock(smp_processor_id());
-}
-
-/*
- * Update the record of the current time in a context.
- */
-static void update_context_time(struct perf_event_context *ctx)
-{
-       u64 now = perf_clock();
-
-       ctx->time += now - ctx->timestamp;
-       ctx->timestamp = now;
-}
-
-/*
- * Update the total_time_enabled and total_time_running fields for a event.
- */
-static void update_event_times(struct perf_event *event)
-{
-       struct perf_event_context *ctx = event->ctx;
-       u64 run_end;
-
-       if (event->state < PERF_EVENT_STATE_INACTIVE ||
-           event->group_leader->state < PERF_EVENT_STATE_INACTIVE)
-               return;
-
-       event->total_time_enabled = ctx->time - event->tstamp_enabled;
-
-       if (event->state == PERF_EVENT_STATE_INACTIVE)
-               run_end = event->tstamp_stopped;
-       else
-               run_end = ctx->time;
-
-       event->total_time_running = run_end - event->tstamp_running;
-}
-
 /*
  * Update total_time_enabled and total_time_running for all events in a group.
  */
@@ -1031,10 +1049,10 @@ void __perf_event_sched_out(struct perf_event_context *ctx,
        update_context_time(ctx);
 
        perf_disable();
-       if (ctx->nr_active)
+       if (ctx->nr_active) {
                list_for_each_entry(event, &ctx->group_list, group_entry)
                        group_sched_out(event, cpuctx, ctx);
-
+       }
        perf_enable();
  out:
        spin_unlock(&ctx->lock);
@@ -1059,8 +1077,6 @@ static int context_equiv(struct perf_event_context *ctx1,
                && !ctx1->pin_count && !ctx2->pin_count;
 }
 
-static void __perf_event_read(void *event);
-
 static void __perf_event_sync_stat(struct perf_event *event,
                                     struct perf_event *next_event)
 {
@@ -1078,8 +1094,8 @@ static void __perf_event_sync_stat(struct perf_event *event,
         */
        switch (event->state) {
        case PERF_EVENT_STATE_ACTIVE:
-               __perf_event_read(event);
-               break;
+               event->pmu->read(event);
+               /* fall-through */
 
        case PERF_EVENT_STATE_INACTIVE:
                update_event_times(event);
@@ -1118,6 +1134,8 @@ static void perf_event_sync_stat(struct perf_event_context *ctx,
        if (!ctx->nr_stat)
                return;
 
+       update_context_time(ctx);
+
        event = list_first_entry(&ctx->event_list,
                                   struct perf_event, event_entry);
 
@@ -1161,8 +1179,6 @@ void perf_event_task_sched_out(struct task_struct *task,
        if (likely(!ctx || !cpuctx->task_ctx))
                return;
 
-       update_context_time(ctx);
-
        rcu_read_lock();
        parent = rcu_dereference(ctx->parent_ctx);
        next_ctx = next->perf_event_ctxp;
@@ -1515,7 +1531,6 @@ static void __perf_event_read(void *info)
        struct perf_cpu_context *cpuctx = &__get_cpu_var(perf_cpu_context);
        struct perf_event *event = info;
        struct perf_event_context *ctx = event->ctx;
-       unsigned long flags;
 
        /*
         * If this is a task context, we need to check whether it is
@@ -1527,12 +1542,12 @@ static void __perf_event_read(void *info)
        if (ctx->task && cpuctx->task_ctx != ctx)
                return;
 
-       local_irq_save(flags);
-       if (ctx->is_active)
-               update_context_time(ctx);
-       event->pmu->read(event);
+       spin_lock(&ctx->lock);
+       update_context_time(ctx);
        update_event_times(event);
-       local_irq_restore(flags);
+       spin_unlock(&ctx->lock);
+
+       event->pmu->read(event);
 }
 
 static u64 perf_event_read(struct perf_event *event)
@@ -1545,7 +1560,13 @@ static u64 perf_event_read(struct perf_event *event)
                smp_call_function_single(event->oncpu,
                                         __perf_event_read, event, 1);
        } else if (event->state == PERF_EVENT_STATE_INACTIVE) {
+               struct perf_event_context *ctx = event->ctx;
+               unsigned long flags;
+
+               spin_lock_irqsave(&ctx->lock, flags);
+               update_context_time(ctx);
                update_event_times(event);
+               spin_unlock_irqrestore(&ctx->lock, flags);
        }
 
        return atomic64_read(&event->count);
@@ -1658,6 +1679,8 @@ static struct perf_event_context *find_get_context(pid_t pid, int cpu)
        return ERR_PTR(err);
 }
 
+static void perf_event_free_filter(struct perf_event *event);
+
 static void free_event_rcu(struct rcu_head *head)
 {
        struct perf_event *event;
@@ -1665,6 +1688,7 @@ static void free_event_rcu(struct rcu_head *head)
        event = container_of(head, struct perf_event, rcu_head);
        if (event->ns)
                put_pid_ns(event->ns);
+       perf_event_free_filter(event);
        kfree(event);
 }
 
@@ -1696,16 +1720,10 @@ static void free_event(struct perf_event *event)
        call_rcu(&event->rcu_head, free_event_rcu);
 }
 
-/*
- * Called when the last reference to the file is gone.
- */
-static int perf_release(struct inode *inode, struct file *file)
+int perf_event_release_kernel(struct perf_event *event)
 {
-       struct perf_event *event = file->private_data;
        struct perf_event_context *ctx = event->ctx;
 
-       file->private_data = NULL;
-
        WARN_ON_ONCE(ctx->parent_ctx);
        mutex_lock(&ctx->mutex);
        perf_event_remove_from_context(event);
@@ -1720,6 +1738,19 @@ static int perf_release(struct inode *inode, struct file *file)
 
        return 0;
 }
+EXPORT_SYMBOL_GPL(perf_event_release_kernel);
+
+/*
+ * Called when the last reference to the file is gone.
+ */
+static int perf_release(struct inode *inode, struct file *file)
+{
+       struct perf_event *event = file->private_data;
+
+       file->private_data = NULL;
+
+       return perf_event_release_kernel(event);
+}
 
 static int perf_event_read_size(struct perf_event *event)
 {
@@ -1746,91 +1777,94 @@ static int perf_event_read_size(struct perf_event *event)
        return size;
 }
 
-static u64 perf_event_read_value(struct perf_event *event)
+u64 perf_event_read_value(struct perf_event *event, u64 *enabled, u64 *running)
 {
        struct perf_event *child;
        u64 total = 0;
 
+       *enabled = 0;
+       *running = 0;
+
+       mutex_lock(&event->child_mutex);
        total += perf_event_read(event);
-       list_for_each_entry(child, &event->child_list, child_list)
+       *enabled += event->total_time_enabled +
+                       atomic64_read(&event->child_total_time_enabled);
+       *running += event->total_time_running +
+                       atomic64_read(&event->child_total_time_running);
+
+       list_for_each_entry(child, &event->child_list, child_list) {
                total += perf_event_read(child);
+               *enabled += child->total_time_enabled;
+               *running += child->total_time_running;
+       }
+       mutex_unlock(&event->child_mutex);
 
        return total;
 }
-
-static int perf_event_read_entry(struct perf_event *event,
-                                  u64 read_format, char __user *buf)
-{
-       int n = 0, count = 0;
-       u64 values[2];
-
-       values[n++] = perf_event_read_value(event);
-       if (read_format & PERF_FORMAT_ID)
-               values[n++] = primary_event_id(event);
-
-       count = n * sizeof(u64);
-
-       if (copy_to_user(buf, values, count))
-               return -EFAULT;
-
-       return count;
-}
+EXPORT_SYMBOL_GPL(perf_event_read_value);
 
 static int perf_event_read_group(struct perf_event *event,
                                   u64 read_format, char __user *buf)
 {
        struct perf_event *leader = event->group_leader, *sub;
-       int n = 0, size = 0, err = -EFAULT;
-       u64 values[3];
+       int n = 0, size = 0, ret = -EFAULT;
+       struct perf_event_context *ctx = leader->ctx;
+       u64 values[5];
+       u64 count, enabled, running;
+
+       mutex_lock(&ctx->mutex);
+       count = perf_event_read_value(leader, &enabled, &running);
 
        values[n++] = 1 + leader->nr_siblings;
-       if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED) {
-               values[n++] = leader->total_time_enabled +
-                       atomic64_read(&leader->child_total_time_enabled);
-       }
-       if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING) {
-               values[n++] = leader->total_time_running +
-                       atomic64_read(&leader->child_total_time_running);
-       }
+       if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED)
+               values[n++] = enabled;
+       if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING)
+               values[n++] = running;
+       values[n++] = count;
+       if (read_format & PERF_FORMAT_ID)
+               values[n++] = primary_event_id(leader);
 
        size = n * sizeof(u64);
 
        if (copy_to_user(buf, values, size))
-               return -EFAULT;
-
-       err = perf_event_read_entry(leader, read_format, buf + size);
-       if (err < 0)
-               return err;
+               goto unlock;
 
-       size += err;
+       ret = size;
 
        list_for_each_entry(sub, &leader->sibling_list, group_entry) {
-               err = perf_event_read_entry(sub, read_format,
-                               buf + size);
-               if (err < 0)
-                       return err;
+               n = 0;
+
+               values[n++] = perf_event_read_value(sub, &enabled, &running);
+               if (read_format & PERF_FORMAT_ID)
+                       values[n++] = primary_event_id(sub);
+
+               size = n * sizeof(u64);
 
-               size += err;
+               if (copy_to_user(buf + ret, values, size)) {
+                       ret = -EFAULT;
+                       goto unlock;
+               }
+
+               ret += size;
        }
+unlock:
+       mutex_unlock(&ctx->mutex);
 
-       return size;
+       return ret;
 }
 
 static int perf_event_read_one(struct perf_event *event,
                                 u64 read_format, char __user *buf)
 {
+       u64 enabled, running;
        u64 values[4];
        int n = 0;
 
-       values[n++] = perf_event_read_value(event);
-       if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED) {
-               values[n++] = event->total_time_enabled +
-                       atomic64_read(&event->child_total_time_enabled);
-       }
-       if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING) {
-               values[n++] = event->total_time_running +
-                       atomic64_read(&event->child_total_time_running);
-       }
+       values[n++] = perf_event_read_value(event, &enabled, &running);
+       if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED)
+               values[n++] = enabled;
+       if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING)
+               values[n++] = running;
        if (read_format & PERF_FORMAT_ID)
                values[n++] = primary_event_id(event);
 
@@ -1861,12 +1895,10 @@ perf_read_hw(struct perf_event *event, char __user *buf, size_t count)
                return -ENOSPC;
 
        WARN_ON_ONCE(event->ctx->parent_ctx);
-       mutex_lock(&event->child_mutex);
        if (read_format & PERF_FORMAT_GROUP)
                ret = perf_event_read_group(event, read_format, buf);
        else
                ret = perf_event_read_one(event, read_format, buf);
-       mutex_unlock(&event->child_mutex);
 
        return ret;
 }
@@ -1974,7 +2006,8 @@ unlock:
        return ret;
 }
 
-int perf_event_set_output(struct perf_event *event, int output_fd);
+static int perf_event_set_output(struct perf_event *event, int output_fd);
+static int perf_event_set_filter(struct perf_event *event, void __user *arg);
 
 static long perf_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 {
@@ -2002,6 +2035,9 @@ static long perf_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
        case PERF_EVENT_IOC_SET_OUTPUT:
                return perf_event_set_output(event, arg);
 
+       case PERF_EVENT_IOC_SET_FILTER:
+               return perf_event_set_filter(event, (void __user *)arg);
+
        default:
                return -ENOTTY;
        }
@@ -2174,6 +2210,7 @@ static void perf_mmap_data_free(struct perf_mmap_data *data)
        perf_mmap_free_page((unsigned long)data->user_page);
        for (i = 0; i < data->nr_pages; i++)
                perf_mmap_free_page((unsigned long)data->data_pages[i]);
+       kfree(data);
 }
 
 #else
@@ -2214,6 +2251,7 @@ static void perf_mmap_data_free_work(struct work_struct *work)
                perf_mmap_unmark_page(base + (i * PAGE_SIZE));
 
        vfree(base);
+       kfree(data);
 }
 
 static void perf_mmap_data_free(struct perf_mmap_data *data)
@@ -2307,7 +2345,7 @@ perf_mmap_data_init(struct perf_event *event, struct perf_mmap_data *data)
        }
 
        if (!data->watermark)
-               data->watermark = max_t(long, PAGE_SIZE, max_size / 2);
+               data->watermark = max_size / 2;
 
 
        rcu_assign_pointer(event->data, data);
@@ -2319,7 +2357,6 @@ static void perf_mmap_data_free_rcu(struct rcu_head *rcu_head)
 
        data = container_of(rcu_head, struct perf_mmap_data, rcu_head);
        perf_mmap_data_free(data);
-       kfree(data);
 }
 
 static void perf_mmap_data_release(struct perf_event *event)
@@ -2666,20 +2703,21 @@ static void perf_output_wakeup(struct perf_output_handle *handle)
 static void perf_output_lock(struct perf_output_handle *handle)
 {
        struct perf_mmap_data *data = handle->data;
-       int cpu;
+       int cur, cpu = get_cpu();
 
        handle->locked = 0;
 
-       local_irq_save(handle->flags);
-       cpu = smp_processor_id();
-
-       if (in_nmi() && atomic_read(&data->lock) == cpu)
-               return;
+       for (;;) {
+               cur = atomic_cmpxchg(&data->lock, -1, cpu);
+               if (cur == -1) {
+                       handle->locked = 1;
+                       break;
+               }
+               if (cur == cpu)
+                       break;
 
-       while (atomic_cmpxchg(&data->lock, -1, cpu) != -1)
                cpu_relax();
-
-       handle->locked = 1;
+       }
 }
 
 static void perf_output_unlock(struct perf_output_handle *handle)
@@ -2725,7 +2763,7 @@ again:
        if (atomic_xchg(&data->wakeup, 0))
                perf_output_wakeup(handle);
 out:
-       local_irq_restore(handle->flags);
+       put_cpu();
 }
 
 void perf_output_copy(struct perf_output_handle *handle,
@@ -3236,15 +3274,10 @@ static void perf_event_task_ctx(struct perf_event_context *ctx,
 {
        struct perf_event *event;
 
-       if (system_state != SYSTEM_RUNNING || list_empty(&ctx->event_list))
-               return;
-
-       rcu_read_lock();
        list_for_each_entry_rcu(event, &ctx->event_list, event_entry) {
                if (perf_event_task_match(event))
                        perf_event_task_output(event, task_event);
        }
-       rcu_read_unlock();
 }
 
 static void perf_event_task_event(struct perf_task_event *task_event)
@@ -3252,11 +3285,11 @@ static void perf_event_task_event(struct perf_task_event *task_event)
        struct perf_cpu_context *cpuctx;
        struct perf_event_context *ctx = task_event->task_ctx;
 
+       rcu_read_lock();
        cpuctx = &get_cpu_var(perf_cpu_context);
        perf_event_task_ctx(&cpuctx->ctx, task_event);
        put_cpu_var(perf_cpu_context);
 
-       rcu_read_lock();
        if (!ctx)
                ctx = rcu_dereference(task_event->task->perf_event_ctxp);
        if (ctx)
@@ -3348,15 +3381,10 @@ static void perf_event_comm_ctx(struct perf_event_context *ctx,
 {
        struct perf_event *event;
 
-       if (system_state != SYSTEM_RUNNING || list_empty(&ctx->event_list))
-               return;
-
-       rcu_read_lock();
        list_for_each_entry_rcu(event, &ctx->event_list, event_entry) {
                if (perf_event_comm_match(event))
                        perf_event_comm_output(event, comm_event);
        }
-       rcu_read_unlock();
 }
 
 static void perf_event_comm_event(struct perf_comm_event *comm_event)
@@ -3367,7 +3395,7 @@ static void perf_event_comm_event(struct perf_comm_event *comm_event)
        char comm[TASK_COMM_LEN];
 
        memset(comm, 0, sizeof(comm));
-       strncpy(comm, comm_event->task->comm, sizeof(comm));
+       strlcpy(comm, comm_event->task->comm, sizeof(comm));
        size = ALIGN(strlen(comm)+1, sizeof(u64));
 
        comm_event->comm = comm;
@@ -3375,11 +3403,11 @@ static void perf_event_comm_event(struct perf_comm_event *comm_event)
 
        comm_event->event_id.header.size = sizeof(comm_event->event_id) + size;
 
+       rcu_read_lock();
        cpuctx = &get_cpu_var(perf_cpu_context);
        perf_event_comm_ctx(&cpuctx->ctx, comm_event);
        put_cpu_var(perf_cpu_context);
 
-       rcu_read_lock();
        /*
         * doesn't really matter which of the child contexts the
         * events ends up in.
@@ -3472,15 +3500,10 @@ static void perf_event_mmap_ctx(struct perf_event_context *ctx,
 {
        struct perf_event *event;
 
-       if (system_state != SYSTEM_RUNNING || list_empty(&ctx->event_list))
-               return;
-
-       rcu_read_lock();
        list_for_each_entry_rcu(event, &ctx->event_list, event_entry) {
                if (perf_event_mmap_match(event, mmap_event))
                        perf_event_mmap_output(event, mmap_event);
        }
-       rcu_read_unlock();
 }
 
 static void perf_event_mmap_event(struct perf_mmap_event *mmap_event)
@@ -3536,11 +3559,11 @@ got_name:
 
        mmap_event->event_id.header.size = sizeof(mmap_event->event_id) + size;
 
+       rcu_read_lock();
        cpuctx = &get_cpu_var(perf_cpu_context);
        perf_event_mmap_ctx(&cpuctx->ctx, mmap_event);
        put_cpu_var(perf_cpu_context);
 
-       rcu_read_lock();
        /*
         * doesn't really matter which of the child contexts the
         * events ends up in.
@@ -3679,7 +3702,11 @@ static int __perf_event_overflow(struct perf_event *event, int nmi,
                        perf_event_disable(event);
        }
 
-       perf_event_output(event, nmi, data, regs);
+       if (event->overflow_handler)
+               event->overflow_handler(event, nmi, data, regs);
+       else
+               perf_event_output(event, nmi, data, regs);
+
        return ret;
 }
 
@@ -3724,16 +3751,16 @@ again:
        return nr;
 }
 
-static void perf_swevent_overflow(struct perf_event *event,
+static void perf_swevent_overflow(struct perf_event *event, u64 overflow,
                                    int nmi, struct perf_sample_data *data,
                                    struct pt_regs *regs)
 {
        struct hw_perf_event *hwc = &event->hw;
        int throttle = 0;
-       u64 overflow;
 
        data->period = event->hw.last_period;
-       overflow = perf_swevent_set_period(event);
+       if (!overflow)
+               overflow = perf_swevent_set_period(event);
 
        if (hwc->interrupts == MAX_INTERRUPTS)
                return;
@@ -3766,14 +3793,19 @@ static void perf_swevent_add(struct perf_event *event, u64 nr,
 
        atomic64_add(nr, &event->count);
 
+       if (!regs)
+               return;
+
        if (!hwc->sample_period)
                return;
 
-       if (!regs)
+       if (nr == 1 && hwc->sample_period == 1 && !event->attr.freq)
+               return perf_swevent_overflow(event, 1, nmi, data, regs);
+
+       if (atomic64_add_negative(nr, &hwc->period_left))
                return;
 
-       if (!atomic64_add_negative(nr, &hwc->period_left))
-               perf_swevent_overflow(event, nmi, data, regs);
+       perf_swevent_overflow(event, 0, nmi, data, regs);
 }
 
 static int perf_swevent_is_counting(struct perf_event *event)
@@ -3806,25 +3838,44 @@ static int perf_swevent_is_counting(struct perf_event *event)
        return 1;
 }
 
+static int perf_tp_event_match(struct perf_event *event,
+                               struct perf_sample_data *data);
+
+static int perf_exclude_event(struct perf_event *event,
+                             struct pt_regs *regs)
+{
+       if (regs) {
+               if (event->attr.exclude_user && user_mode(regs))
+                       return 1;
+
+               if (event->attr.exclude_kernel && !user_mode(regs))
+                       return 1;
+       }
+
+       return 0;
+}
+
 static int perf_swevent_match(struct perf_event *event,
                                enum perf_type_id type,
-                               u32 event_id, struct pt_regs *regs)
+                               u32 event_id,
+                               struct perf_sample_data *data,
+                               struct pt_regs *regs)
 {
        if (!perf_swevent_is_counting(event))
                return 0;
 
        if (event->attr.type != type)
                return 0;
+
        if (event->attr.config != event_id)
                return 0;
 
-       if (regs) {
-               if (event->attr.exclude_user && user_mode(regs))
-                       return 0;
+       if (perf_exclude_event(event, regs))
+               return 0;
 
-               if (event->attr.exclude_kernel && !user_mode(regs))
-                       return 0;
-       }
+       if (event->attr.type == PERF_TYPE_TRACEPOINT &&
+           !perf_tp_event_match(event, data))
+               return 0;
 
        return 1;
 }
@@ -3837,49 +3888,59 @@ static void perf_swevent_ctx_event(struct perf_event_context *ctx,
 {
        struct perf_event *event;
 
-       if (system_state != SYSTEM_RUNNING || list_empty(&ctx->event_list))
-               return;
-
-       rcu_read_lock();
        list_for_each_entry_rcu(event, &ctx->event_list, event_entry) {
-               if (perf_swevent_match(event, type, event_id, regs))
+               if (perf_swevent_match(event, type, event_id, data, regs))
                        perf_swevent_add(event, nr, nmi, data, regs);
        }
-       rcu_read_unlock();
 }
 
-static int *perf_swevent_recursion_context(struct perf_cpu_context *cpuctx)
+int perf_swevent_get_recursion_context(void)
 {
+       struct perf_cpu_context *cpuctx = &get_cpu_var(perf_cpu_context);
+       int rctx;
+
        if (in_nmi())
-               return &cpuctx->recursion[3];
+               rctx = 3;
+       else if (in_irq())
+               rctx = 2;
+       else if (in_softirq())
+               rctx = 1;
+       else
+               rctx = 0;
+
+       if (cpuctx->recursion[rctx]) {
+               put_cpu_var(perf_cpu_context);
+               return -1;
+       }
 
-       if (in_irq())
-               return &cpuctx->recursion[2];
+       cpuctx->recursion[rctx]++;
+       barrier();
 
-       if (in_softirq())
-               return &cpuctx->recursion[1];
+       return rctx;
+}
+EXPORT_SYMBOL_GPL(perf_swevent_get_recursion_context);
 
-       return &cpuctx->recursion[0];
+void perf_swevent_put_recursion_context(int rctx)
+{
+       struct perf_cpu_context *cpuctx = &__get_cpu_var(perf_cpu_context);
+       barrier();
+       cpuctx->recursion[rctx]--;
+       put_cpu_var(perf_cpu_context);
 }
+EXPORT_SYMBOL_GPL(perf_swevent_put_recursion_context);
 
 static void do_perf_sw_event(enum perf_type_id type, u32 event_id,
                                    u64 nr, int nmi,
                                    struct perf_sample_data *data,
                                    struct pt_regs *regs)
 {
-       struct perf_cpu_context *cpuctx = &get_cpu_var(perf_cpu_context);
-       int *recursion = perf_swevent_recursion_context(cpuctx);
+       struct perf_cpu_context *cpuctx;
        struct perf_event_context *ctx;
 
-       if (*recursion)
-               goto out;
-
-       (*recursion)++;
-       barrier();
-
+       cpuctx = &__get_cpu_var(perf_cpu_context);
+       rcu_read_lock();
        perf_swevent_ctx_event(&cpuctx->ctx, type, event_id,
                                 nr, nmi, data, regs);
-       rcu_read_lock();
        /*
         * doesn't really matter which of the child contexts the
         * events ends up in.
@@ -3888,23 +3949,24 @@ static void do_perf_sw_event(enum perf_type_id type, u32 event_id,
        if (ctx)
                perf_swevent_ctx_event(ctx, type, event_id, nr, nmi, data, regs);
        rcu_read_unlock();
-
-       barrier();
-       (*recursion)--;
-
-out:
-       put_cpu_var(perf_cpu_context);
 }
 
 void __perf_sw_event(u32 event_id, u64 nr, int nmi,
                            struct pt_regs *regs, u64 addr)
 {
-       struct perf_sample_data data = {
-               .addr = addr,
-       };
+       struct perf_sample_data data;
+       int rctx;
 
-       do_perf_sw_event(PERF_TYPE_SOFTWARE, event_id, nr, nmi,
-                               &data, regs);
+       rctx = perf_swevent_get_recursion_context();
+       if (rctx < 0)
+               return;
+
+       data.addr = addr;
+       data.raw  = NULL;
+
+       do_perf_sw_event(PERF_TYPE_SOFTWARE, event_id, nr, nmi, &data, regs);
+
+       perf_swevent_put_recursion_context(rctx);
 }
 
 static void perf_swevent_read(struct perf_event *event)
@@ -3949,6 +4011,7 @@ static enum hrtimer_restart perf_swevent_hrtimer(struct hrtimer *hrtimer)
        event->pmu->read(event);
 
        data.addr = 0;
+       data.period = event->hw.last_period;
        regs = get_irq_regs();
        /*
         * In case we exclude kernel IPs or are somehow not in interrupt
@@ -4108,6 +4171,7 @@ static const struct pmu perf_ops_task_clock = {
 };
 
 #ifdef CONFIG_EVENT_PROFILE
+
 void perf_tp_event(int event_id, u64 addr, u64 count, void *record,
                          int entry_size)
 {
@@ -4126,13 +4190,21 @@ void perf_tp_event(int event_id, u64 addr, u64 count, void *record,
        if (!regs)
                regs = task_pt_regs(current);
 
+       /* Trace events already protected against recursion */
        do_perf_sw_event(PERF_TYPE_TRACEPOINT, event_id, count, 1,
                                &data, regs);
 }
 EXPORT_SYMBOL_GPL(perf_tp_event);
 
-extern int ftrace_profile_enable(int);
-extern void ftrace_profile_disable(int);
+static int perf_tp_event_match(struct perf_event *event,
+                               struct perf_sample_data *data)
+{
+       void *record = data->raw->data;
+
+       if (likely(!event->filter) || filter_match_preds(event->filter, record))
+               return 1;
+       return 0;
+}
 
 static void tp_perf_event_destroy(struct perf_event *event)
 {
@@ -4157,11 +4229,99 @@ static const struct pmu *tp_perf_event_init(struct perf_event *event)
 
        return &perf_ops_generic;
 }
+
+static int perf_event_set_filter(struct perf_event *event, void __user *arg)
+{
+       char *filter_str;
+       int ret;
+
+       if (event->attr.type != PERF_TYPE_TRACEPOINT)
+               return -EINVAL;
+
+       filter_str = strndup_user(arg, PAGE_SIZE);
+       if (IS_ERR(filter_str))
+               return PTR_ERR(filter_str);
+
+       ret = ftrace_profile_set_filter(event, event->attr.config, filter_str);
+
+       kfree(filter_str);
+       return ret;
+}
+
+static void perf_event_free_filter(struct perf_event *event)
+{
+       ftrace_profile_free_filter(event);
+}
+
 #else
+
+static int perf_tp_event_match(struct perf_event *event,
+                               struct perf_sample_data *data)
+{
+       return 1;
+}
+
 static const struct pmu *tp_perf_event_init(struct perf_event *event)
 {
        return NULL;
 }
+
+static int perf_event_set_filter(struct perf_event *event, void __user *arg)
+{
+       return -ENOENT;
+}
+
+static void perf_event_free_filter(struct perf_event *event)
+{
+}
+
+#endif /* CONFIG_EVENT_PROFILE */
+
+#ifdef CONFIG_HAVE_HW_BREAKPOINT
+static void bp_perf_event_destroy(struct perf_event *event)
+{
+       release_bp_slot(event);
+}
+
+static const struct pmu *bp_perf_event_init(struct perf_event *bp)
+{
+       int err;
+       /*
+        * The breakpoint is already filled if we haven't created the counter
+        * through perf syscall
+        * FIXME: manage to get trigerred to NULL if it comes from syscalls
+        */
+       if (!bp->callback)
+               err = register_perf_hw_breakpoint(bp);
+       else
+               err = __register_perf_hw_breakpoint(bp);
+       if (err)
+               return ERR_PTR(err);
+
+       bp->destroy = bp_perf_event_destroy;
+
+       return &perf_ops_bp;
+}
+
+void perf_bp_event(struct perf_event *bp, void *data)
+{
+       struct perf_sample_data sample;
+       struct pt_regs *regs = data;
+
+       sample.addr = bp->attr.bp_addr;
+
+       if (!perf_exclude_event(bp, regs))
+               perf_swevent_add(bp, 1, 1, &sample, regs);
+}
+#else
+static const struct pmu *bp_perf_event_init(struct perf_event *bp)
+{
+       return NULL;
+}
+
+void perf_bp_event(struct perf_event *bp, void *regs)
+{
+}
 #endif
 
 atomic_t perf_swevent_enabled[PERF_COUNT_SW_MAX];
@@ -4208,6 +4368,8 @@ static const struct pmu *sw_perf_event_init(struct perf_event *event)
        case PERF_COUNT_SW_PAGE_FAULTS_MAJ:
        case PERF_COUNT_SW_CONTEXT_SWITCHES:
        case PERF_COUNT_SW_CPU_MIGRATIONS:
+       case PERF_COUNT_SW_ALIGNMENT_FAULTS:
+       case PERF_COUNT_SW_EMULATION_FAULTS:
                if (!event->parent) {
                        atomic_inc(&perf_swevent_enabled[event_id]);
                        event->destroy = sw_perf_event_destroy;
@@ -4228,6 +4390,7 @@ perf_event_alloc(struct perf_event_attr *attr,
                   struct perf_event_context *ctx,
                   struct perf_event *group_leader,
                   struct perf_event *parent_event,
+                  perf_callback_t callback,
                   gfp_t gfpflags)
 {
        const struct pmu *pmu;
@@ -4270,6 +4433,11 @@ perf_event_alloc(struct perf_event_attr *attr,
 
        event->state            = PERF_EVENT_STATE_INACTIVE;
 
+       if (!callback && parent_event)
+               callback = parent_event->callback;
+       
+       event->callback = callback;
+
        if (attr->disabled)
                event->state = PERF_EVENT_STATE_OFF;
 
@@ -4304,6 +4472,11 @@ perf_event_alloc(struct perf_event_attr *attr,
                pmu = tp_perf_event_init(event);
                break;
 
+       case PERF_TYPE_BREAKPOINT:
+               pmu = bp_perf_event_init(event);
+               break;
+
+
        default:
                break;
        }
@@ -4416,7 +4589,7 @@ err_size:
        goto out;
 }
 
-int perf_event_set_output(struct perf_event *event, int output_fd)
+static int perf_event_set_output(struct perf_event *event, int output_fd)
 {
        struct perf_event *output_event = NULL;
        struct file *output_file = NULL;
@@ -4546,7 +4719,7 @@ SYSCALL_DEFINE5(perf_event_open,
        }
 
        event = perf_event_alloc(&attr, cpu, ctx, group_leader,
-                                    NULL, GFP_KERNEL);
+                                    NULL, NULL, GFP_KERNEL);
        err = PTR_ERR(event);
        if (IS_ERR(event))
                goto err_put_context;
@@ -4594,6 +4767,60 @@ err_put_context:
        return err;
 }
 
+/**
+ * perf_event_create_kernel_counter
+ *
+ * @attr: attributes of the counter to create
+ * @cpu: cpu in which the counter is bound
+ * @pid: task to profile
+ */
+struct perf_event *
+perf_event_create_kernel_counter(struct perf_event_attr *attr, int cpu,
+                                pid_t pid, perf_callback_t callback)
+{
+       struct perf_event *event;
+       struct perf_event_context *ctx;
+       int err;
+
+       /*
+        * Get the target context (task or percpu):
+        */
+
+       ctx = find_get_context(pid, cpu);
+       if (IS_ERR(ctx)) {
+               err = PTR_ERR(ctx);
+               goto err_exit;
+       }
+
+       event = perf_event_alloc(attr, cpu, ctx, NULL,
+                                    NULL, callback, GFP_KERNEL);
+       if (IS_ERR(event)) {
+               err = PTR_ERR(event);
+               goto err_put_context;
+       }
+
+       event->filp = NULL;
+       WARN_ON_ONCE(ctx->parent_ctx);
+       mutex_lock(&ctx->mutex);
+       perf_install_in_context(ctx, event, cpu);
+       ++ctx->generation;
+       mutex_unlock(&ctx->mutex);
+
+       event->owner = current;
+       get_task_struct(current);
+       mutex_lock(&current->perf_event_mutex);
+       list_add_tail(&event->owner_entry, &current->perf_event_list);
+       mutex_unlock(&current->perf_event_mutex);
+
+       return event;
+
+ err_put_context:
+       put_ctx(ctx);
+ err_exit:
+       return ERR_PTR(err);
+}
+EXPORT_SYMBOL_GPL(perf_event_create_kernel_counter);
+
 /*
  * inherit a event from parent task to child task:
  */
@@ -4619,7 +4846,7 @@ inherit_event(struct perf_event *parent_event,
        child_event = perf_event_alloc(&parent_event->attr,
                                           parent_event->cpu, child_ctx,
                                           group_leader, parent_event,
-                                          GFP_KERNEL);
+                                          NULL, GFP_KERNEL);
        if (IS_ERR(child_event))
                return child_event;
        get_ctx(child_ctx);
@@ -4637,6 +4864,8 @@ inherit_event(struct perf_event *parent_event,
        if (parent_event->attr.freq)
                child_event->hw.sample_period = parent_event->hw.sample_period;
 
+       child_event->overflow_handler = parent_event->overflow_handler;
+
        /*
         * Link it up in the child's context:
         */
@@ -4726,7 +4955,6 @@ __perf_event_exit_task(struct perf_event *child_event,
 {
        struct perf_event *parent_event;
 
-       update_event_times(child_event);
        perf_event_remove_from_context(child_event);
 
        parent_event = child_event->parent;
@@ -4778,6 +5006,7 @@ void perf_event_exit_task(struct task_struct *child)
         * the events from it.
         */
        unclone_ctx(child_ctx);
+       update_context_time(child_ctx);
        spin_unlock_irqrestore(&child_ctx->lock, flags);
 
        /*
index c3b81c3..4319181 100644 (file)
@@ -8,7 +8,7 @@ obj-$(CONFIG_PM_SLEEP)          += console.o
 obj-$(CONFIG_FREEZER)          += process.o
 obj-$(CONFIG_SUSPEND)          += suspend.o
 obj-$(CONFIG_PM_TEST_SUSPEND)  += suspend_test.o
-obj-$(CONFIG_HIBERNATION)      += swsusp.o hibernate.o snapshot.o swap.o user.o
+obj-$(CONFIG_HIBERNATION)      += hibernate.o snapshot.o swap.o user.o
 obj-$(CONFIG_HIBERNATION_NVS)  += hibernate_nvs.o
 
 obj-$(CONFIG_MAGIC_SYSRQ)      += poweroff.o
index 04a9e90..bbfe472 100644 (file)
@@ -32,6 +32,7 @@ static int noresume = 0;
 static char resume_file[256] = CONFIG_PM_STD_PARTITION;
 dev_t swsusp_resume_device;
 sector_t swsusp_resume_block;
+int in_suspend __nosavedata = 0;
 
 enum {
        HIBERNATION_INVALID,
@@ -202,6 +203,35 @@ static void platform_recover(int platform_mode)
 }
 
 /**
+ *     swsusp_show_speed - print the time elapsed between two events.
+ *     @start: Starting event.
+ *     @stop: Final event.
+ *     @nr_pages -     number of pages processed between @start and @stop
+ *     @msg -          introductory message to print
+ */
+
+void swsusp_show_speed(struct timeval *start, struct timeval *stop,
+                       unsigned nr_pages, char *msg)
+{
+       s64 elapsed_centisecs64;
+       int centisecs;
+       int k;
+       int kps;
+
+       elapsed_centisecs64 = timeval_to_ns(stop) - timeval_to_ns(start);
+       do_div(elapsed_centisecs64, NSEC_PER_SEC / 100);
+       centisecs = elapsed_centisecs64;
+       if (centisecs == 0)
+               centisecs = 1;  /* avoid div-by-zero */
+       k = nr_pages * (PAGE_SIZE / 1024);
+       kps = (k * 100) / centisecs;
+       printk(KERN_INFO "PM: %s %d kbytes in %d.%02d seconds (%d.%02d MB/s)\n",
+                       msg, k,
+                       centisecs / 100, centisecs % 100,
+                       kps / 1000, (kps % 1000) / 10);
+}
+
+/**
  *     create_image - freeze devices that need to be frozen with interrupts
  *     off, create the hibernation image and thaw those devices.  Control
  *     reappears in this routine after a restore.
index 347d2cc..0998c71 100644 (file)
@@ -220,6 +220,7 @@ static struct attribute_group attr_group = {
 
 #ifdef CONFIG_PM_RUNTIME
 struct workqueue_struct *pm_wq;
+EXPORT_SYMBOL_GPL(pm_wq);
 
 static int __init pm_start_workqueue(void)
 {
index cc2e553..5ade1bd 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/module.h>
 #include <linux/syscalls.h>
 #include <linux/freezer.h>
+#include <linux/delay.h>
 
 /* 
  * Timeout for stopping processes
@@ -41,7 +42,7 @@ static int try_to_freeze_tasks(bool sig_only)
        do_gettimeofday(&start);
 
        end_time = jiffies + TIMEOUT;
-       do {
+       while (true) {
                todo = 0;
                read_lock(&tasklist_lock);
                do_each_thread(g, p) {
@@ -62,10 +63,15 @@ static int try_to_freeze_tasks(bool sig_only)
                                todo++;
                } while_each_thread(g, p);
                read_unlock(&tasklist_lock);
-               yield();                        /* Yield is okay here */
-               if (time_after(jiffies, end_time))
+               if (!todo || time_after(jiffies, end_time))
                        break;
-       } while (todo);
+
+               /*
+                * We need to retry, but first give the freezing tasks some
+                * time to enter the regrigerator.
+                */
+               msleep(10);
+       }
 
        do_gettimeofday(&end);
        elapsed_csecs64 = timeval_to_ns(&end) - timeval_to_ns(&start);
index 890f6b1..09b2b0a 100644 (file)
@@ -38,6 +38,107 @@ struct swsusp_header {
 
 static struct swsusp_header *swsusp_header;
 
+/**
+ *     The following functions are used for tracing the allocated
+ *     swap pages, so that they can be freed in case of an error.
+ */
+
+struct swsusp_extent {
+       struct rb_node node;
+       unsigned long start;
+       unsigned long end;
+};
+
+static struct rb_root swsusp_extents = RB_ROOT;
+
+static int swsusp_extents_insert(unsigned long swap_offset)
+{
+       struct rb_node **new = &(swsusp_extents.rb_node);
+       struct rb_node *parent = NULL;
+       struct swsusp_extent *ext;
+
+       /* Figure out where to put the new node */
+       while (*new) {
+               ext = container_of(*new, struct swsusp_extent, node);
+               parent = *new;
+               if (swap_offset < ext->start) {
+                       /* Try to merge */
+                       if (swap_offset == ext->start - 1) {
+                               ext->start--;
+                               return 0;
+                       }
+                       new = &((*new)->rb_left);
+               } else if (swap_offset > ext->end) {
+                       /* Try to merge */
+                       if (swap_offset == ext->end + 1) {
+                               ext->end++;
+                               return 0;
+                       }
+                       new = &((*new)->rb_right);
+               } else {
+                       /* It already is in the tree */
+                       return -EINVAL;
+               }
+       }
+       /* Add the new node and rebalance the tree. */
+       ext = kzalloc(sizeof(struct swsusp_extent), GFP_KERNEL);
+       if (!ext)
+               return -ENOMEM;
+
+       ext->start = swap_offset;
+       ext->end = swap_offset;
+       rb_link_node(&ext->node, parent, new);
+       rb_insert_color(&ext->node, &swsusp_extents);
+       return 0;
+}
+
+/**
+ *     alloc_swapdev_block - allocate a swap page and register that it has
+ *     been allocated, so that it can be freed in case of an error.
+ */
+
+sector_t alloc_swapdev_block(int swap)
+{
+       unsigned long offset;
+
+       offset = swp_offset(get_swap_page_of_type(swap));
+       if (offset) {
+               if (swsusp_extents_insert(offset))
+                       swap_free(swp_entry(swap, offset));
+               else
+                       return swapdev_block(swap, offset);
+       }
+       return 0;
+}
+
+/**
+ *     free_all_swap_pages - free swap pages allocated for saving image data.
+ *     It also frees the extents used to register which swap entres had been
+ *     allocated.
+ */
+
+void free_all_swap_pages(int swap)
+{
+       struct rb_node *node;
+
+       while ((node = swsusp_extents.rb_node)) {
+               struct swsusp_extent *ext;
+               unsigned long offset;
+
+               ext = container_of(node, struct swsusp_extent, node);
+               rb_erase(node, &swsusp_extents);
+               for (offset = ext->start; offset <= ext->end; offset++)
+                       swap_free(swp_entry(swap, offset));
+
+               kfree(ext);
+       }
+}
+
+int swsusp_swap_in_use(void)
+{
+       return (swsusp_extents.rb_node != NULL);
+}
+
 /*
  * General things
  */
@@ -336,7 +437,7 @@ static int save_image(struct swap_map_handle *handle,
                if (ret)
                        break;
                if (!(nr_pages % m))
-                       printk("\b\b\b\b%3d%%", nr_pages / m);
+                       printk(KERN_CONT "\b\b\b\b%3d%%", nr_pages / m);
                nr_pages++;
        }
        err2 = wait_on_bio_chain(&bio);
@@ -344,9 +445,9 @@ static int save_image(struct swap_map_handle *handle,
        if (!ret)
                ret = err2;
        if (!ret)
-               printk("\b\b\b\bdone\n");
+               printk(KERN_CONT "\b\b\b\bdone\n");
        else
-               printk("\n");
+               printk(KERN_CONT "\n");
        swsusp_show_speed(&start, &stop, nr_to_write, "Wrote");
        return ret;
 }
index 6a07f4d..5b3601b 100644 (file)
 #include "power.h"
 
 int in_suspend __nosavedata = 0;
-
-/**
- *     The following functions are used for tracing the allocated
- *     swap pages, so that they can be freed in case of an error.
- */
-
-struct swsusp_extent {
-       struct rb_node node;
-       unsigned long start;
-       unsigned long end;
-};
-
-static struct rb_root swsusp_extents = RB_ROOT;
-
-static int swsusp_extents_insert(unsigned long swap_offset)
-{
-       struct rb_node **new = &(swsusp_extents.rb_node);
-       struct rb_node *parent = NULL;
-       struct swsusp_extent *ext;
-
-       /* Figure out where to put the new node */
-       while (*new) {
-               ext = container_of(*new, struct swsusp_extent, node);
-               parent = *new;
-               if (swap_offset < ext->start) {
-                       /* Try to merge */
-                       if (swap_offset == ext->start - 1) {
-                               ext->start--;
-                               return 0;
-                       }
-                       new = &((*new)->rb_left);
-               } else if (swap_offset > ext->end) {
-                       /* Try to merge */
-                       if (swap_offset == ext->end + 1) {
-                               ext->end++;
-                               return 0;
-                       }
-                       new = &((*new)->rb_right);
-               } else {
-                       /* It already is in the tree */
-                       return -EINVAL;
-               }
-       }
-       /* Add the new node and rebalance the tree. */
-       ext = kzalloc(sizeof(struct swsusp_extent), GFP_KERNEL);
-       if (!ext)
-               return -ENOMEM;
-
-       ext->start = swap_offset;
-       ext->end = swap_offset;
-       rb_link_node(&ext->node, parent, new);
-       rb_insert_color(&ext->node, &swsusp_extents);
-       return 0;
-}
-
-/**
- *     alloc_swapdev_block - allocate a swap page and register that it has
- *     been allocated, so that it can be freed in case of an error.
- */
-
-sector_t alloc_swapdev_block(int swap)
-{
-       unsigned long offset;
-
-       offset = swp_offset(get_swap_page_of_type(swap));
-       if (offset) {
-               if (swsusp_extents_insert(offset))
-                       swap_free(swp_entry(swap, offset));
-               else
-                       return swapdev_block(swap, offset);
-       }
-       return 0;
-}
-
-/**
- *     free_all_swap_pages - free swap pages allocated for saving image data.
- *     It also frees the extents used to register which swap entres had been
- *     allocated.
- */
-
-void free_all_swap_pages(int swap)
-{
-       struct rb_node *node;
-
-       while ((node = swsusp_extents.rb_node)) {
-               struct swsusp_extent *ext;
-               unsigned long offset;
-
-               ext = container_of(node, struct swsusp_extent, node);
-               rb_erase(node, &swsusp_extents);
-               for (offset = ext->start; offset <= ext->end; offset++)
-                       swap_free(swp_entry(swap, offset));
-
-               kfree(ext);
-       }
-}
-
-int swsusp_swap_in_use(void)
-{
-       return (swsusp_extents.rb_node != NULL);
-}
-
-/**
- *     swsusp_show_speed - print the time elapsed between two events represented by
- *     @start and @stop
- *
- *     @nr_pages -     number of pages processed between @start and @stop
- *     @msg -          introductory message to print
- */
-
-void swsusp_show_speed(struct timeval *start, struct timeval *stop,
-                       unsigned nr_pages, char *msg)
-{
-       s64 elapsed_centisecs64;
-       int centisecs;
-       int k;
-       int kps;
-
-       elapsed_centisecs64 = timeval_to_ns(stop) - timeval_to_ns(start);
-       do_div(elapsed_centisecs64, NSEC_PER_SEC / 100);
-       centisecs = elapsed_centisecs64;
-       if (centisecs == 0)
-               centisecs = 1;  /* avoid div-by-zero */
-       k = nr_pages * (PAGE_SIZE / 1024);
-       kps = (k * 100) / centisecs;
-       printk(KERN_INFO "PM: %s %d kbytes in %d.%02d seconds (%d.%02d MB/s)\n",
-                       msg, k,
-                       centisecs / 100, centisecs % 100,
-                       kps / 1000, (kps % 1000) / 10);
-}
index 6ae2739..e7f2cfa 100644 (file)
@@ -535,14 +535,12 @@ struct rq {
        #define CPU_LOAD_IDX_MAX 5
        unsigned long cpu_load[CPU_LOAD_IDX_MAX];
 #ifdef CONFIG_NO_HZ
-       unsigned long last_tick_seen;
        unsigned char in_nohz_recently;
 #endif
        /* capture load from *all* tasks on this cpu: */
        struct load_weight load;
        unsigned long nr_load_updates;
        u64 nr_switches;
-       u64 nr_migrations_in;
 
        struct cfs_rq cfs;
        struct rt_rq rt;
@@ -591,6 +589,8 @@ struct rq {
 
        u64 rt_avg;
        u64 age_stamp;
+       u64 idle_stamp;
+       u64 avg_idle;
 #endif
 
        /* calc_load related fields */
@@ -772,7 +772,7 @@ sched_feat_write(struct file *filp, const char __user *ubuf,
        if (!sched_feat_names[i])
                return -EINVAL;
 
-       filp->f_pos += cnt;
+       *ppos += cnt;
 
        return cnt;
 }
@@ -2017,6 +2017,7 @@ void kthread_bind(struct task_struct *p, unsigned int cpu)
        }
 
        spin_lock_irqsave(&rq->lock, flags);
+       update_rq_clock(rq);
        set_task_cpu(p, cpu);
        p->cpus_allowed = cpumask_of_cpu(cpu);
        p->rt.nr_cpus_allowed = 1;
@@ -2078,7 +2079,6 @@ void set_task_cpu(struct task_struct *p, unsigned int new_cpu)
 #endif
        if (old_cpu != new_cpu) {
                p->se.nr_migrations++;
-               new_rq->nr_migrations_in++;
 #ifdef CONFIG_SCHEDSTATS
                if (task_hot(p, old_rq->clock, NULL))
                        schedstat_inc(p, se.nr_forced2_migrations);
@@ -2115,6 +2115,7 @@ migrate_task(struct task_struct *p, int dest_cpu, struct migration_req *req)
         * it is sufficient to simply update the task's cpu field.
         */
        if (!p->se.on_rq && !task_running(rq, p)) {
+               update_rq_clock(rq);
                set_task_cpu(p, dest_cpu);
                return 0;
        }
@@ -2376,14 +2377,15 @@ static int try_to_wake_up(struct task_struct *p, unsigned int state,
        task_rq_unlock(rq, &flags);
 
        cpu = p->sched_class->select_task_rq(p, SD_BALANCE_WAKE, wake_flags);
-       if (cpu != orig_cpu)
+       if (cpu != orig_cpu) {
+               local_irq_save(flags);
+               rq = cpu_rq(cpu);
+               update_rq_clock(rq);
                set_task_cpu(p, cpu);
-
+               local_irq_restore(flags);
+       }
        rq = task_rq_lock(p, &flags);
 
-       if (rq != orig_rq)
-               update_rq_clock(rq);
-
        WARN_ON(p->state != TASK_WAKING);
        cpu = task_cpu(p);
 
@@ -2440,6 +2442,17 @@ out_running:
 #ifdef CONFIG_SMP
        if (p->sched_class->task_wake_up)
                p->sched_class->task_wake_up(rq, p);
+
+       if (unlikely(rq->idle_stamp)) {
+               u64 delta = rq->clock - rq->idle_stamp;
+               u64 max = 2*sysctl_sched_migration_cost;
+
+               if (delta > max)
+                       rq->avg_idle = max;
+               else
+                       update_avg(&rq->avg_idle, delta);
+               rq->idle_stamp = 0;
+       }
 #endif
 out:
        task_rq_unlock(rq, &flags);
@@ -2545,6 +2558,7 @@ static void __sched_fork(struct task_struct *p)
 void sched_fork(struct task_struct *p, int clone_flags)
 {
        int cpu = get_cpu();
+       unsigned long flags;
 
        __sched_fork(p);
 
@@ -2581,7 +2595,10 @@ void sched_fork(struct task_struct *p, int clone_flags)
 #ifdef CONFIG_SMP
        cpu = p->sched_class->select_task_rq(p, SD_BALANCE_FORK, 0);
 #endif
+       local_irq_save(flags);
+       update_rq_clock(cpu_rq(cpu));
        set_task_cpu(p, cpu);
+       local_irq_restore(flags);
 
 #if defined(CONFIG_SCHEDSTATS) || defined(CONFIG_TASK_DELAY_ACCT)
        if (likely(sched_info_on()))
@@ -2848,14 +2865,14 @@ context_switch(struct rq *rq, struct task_struct *prev,
         */
        arch_start_context_switch(prev);
 
-       if (unlikely(!mm)) {
+       if (likely(!mm)) {
                next->active_mm = oldmm;
                atomic_inc(&oldmm->mm_count);
                enter_lazy_tlb(oldmm, next);
        } else
                switch_mm(oldmm, mm, next);
 
-       if (unlikely(!prev->mm)) {
+       if (likely(!prev->mm)) {
                prev->active_mm = NULL;
                rq->prev_mm = oldmm;
        }
@@ -3018,15 +3035,6 @@ static void calc_load_account_active(struct rq *this_rq)
 }
 
 /*
- * Externally visible per-cpu scheduler statistics:
- * cpu_nr_migrations(cpu) - number of migrations into that cpu
- */
-u64 cpu_nr_migrations(int cpu)
-{
-       return cpu_rq(cpu)->nr_migrations_in;
-}
-
-/*
  * Update rq->cpu_load[] statistics. This function is usually called every
  * scheduler tick (TICK_NSEC).
  */
@@ -4126,7 +4134,7 @@ static int load_balance(int this_cpu, struct rq *this_rq,
        unsigned long flags;
        struct cpumask *cpus = __get_cpu_var(load_balance_tmpmask);
 
-       cpumask_setall(cpus);
+       cpumask_copy(cpus, cpu_online_mask);
 
        /*
         * When power savings policy is enabled for the parent domain, idle
@@ -4289,7 +4297,7 @@ load_balance_newidle(int this_cpu, struct rq *this_rq, struct sched_domain *sd)
        int all_pinned = 0;
        struct cpumask *cpus = __get_cpu_var(load_balance_tmpmask);
 
-       cpumask_setall(cpus);
+       cpumask_copy(cpus, cpu_online_mask);
 
        /*
         * When power savings policy is enabled for the parent domain, idle
@@ -4429,6 +4437,11 @@ static void idle_balance(int this_cpu, struct rq *this_rq)
        int pulled_task = 0;
        unsigned long next_balance = jiffies + HZ;
 
+       this_rq->idle_stamp = this_rq->clock;
+
+       if (this_rq->avg_idle < sysctl_sched_migration_cost)
+               return;
+
        for_each_domain(this_cpu, sd) {
                unsigned long interval;
 
@@ -4443,8 +4456,10 @@ static void idle_balance(int this_cpu, struct rq *this_rq)
                interval = msecs_to_jiffies(sd->balance_interval);
                if (time_after(next_balance, sd->last_balance + interval))
                        next_balance = sd->last_balance + interval;
-               if (pulled_task)
+               if (pulled_task) {
+                       this_rq->idle_stamp = 0;
                        break;
+               }
        }
        if (pulled_task || time_after(jiffies, this_rq->next_balance)) {
                /*
@@ -5046,8 +5061,13 @@ static void account_guest_time(struct task_struct *p, cputime_t cputime,
        p->gtime = cputime_add(p->gtime, cputime);
 
        /* Add guest time to cpustat. */
-       cpustat->user = cputime64_add(cpustat->user, tmp);
-       cpustat->guest = cputime64_add(cpustat->guest, tmp);
+       if (TASK_NICE(p) > 0) {
+               cpustat->nice = cputime64_add(cpustat->nice, tmp);
+               cpustat->guest_nice = cputime64_add(cpustat->guest_nice, tmp);
+       } else {
+               cpustat->user = cputime64_add(cpustat->user, tmp);
+               cpustat->guest = cputime64_add(cpustat->guest, tmp);
+       }
 }
 
 /*
@@ -5162,60 +5182,86 @@ void account_idle_ticks(unsigned long ticks)
  * Use precise platform statistics if available:
  */
 #ifdef CONFIG_VIRT_CPU_ACCOUNTING
-cputime_t task_utime(struct task_struct *p)
+void task_times(struct task_struct *p, cputime_t *ut, cputime_t *st)
 {
-       return p->utime;
+       *ut = p->utime;
+       *st = p->stime;
 }
 
-cputime_t task_stime(struct task_struct *p)
+void thread_group_times(struct task_struct *p, cputime_t *ut, cputime_t *st)
 {
-       return p->stime;
+       struct task_cputime cputime;
+
+       thread_group_cputime(p, &cputime);
+
+       *ut = cputime.utime;
+       *st = cputime.stime;
 }
 #else
-cputime_t task_utime(struct task_struct *p)
+
+#ifndef nsecs_to_cputime
+# define nsecs_to_cputime(__nsecs)     nsecs_to_jiffies(__nsecs)
+#endif
+
+void task_times(struct task_struct *p, cputime_t *ut, cputime_t *st)
 {
-       clock_t utime = cputime_to_clock_t(p->utime),
-               total = utime + cputime_to_clock_t(p->stime);
-       u64 temp;
+       cputime_t rtime, utime = p->utime, total = cputime_add(utime, p->stime);
 
        /*
         * Use CFS's precise accounting:
         */
-       temp = (u64)nsec_to_clock_t(p->se.sum_exec_runtime);
+       rtime = nsecs_to_cputime(p->se.sum_exec_runtime);
 
        if (total) {
-               temp *= utime;
+               u64 temp;
+
+               temp = (u64)(rtime * utime);
                do_div(temp, total);
-       }
-       utime = (clock_t)temp;
+               utime = (cputime_t)temp;
+       } else
+               utime = rtime;
+
+       /*
+        * Compare with previous values, to keep monotonicity:
+        */
+       p->prev_utime = max(p->prev_utime, utime);
+       p->prev_stime = max(p->prev_stime, cputime_sub(rtime, p->prev_utime));
 
-       p->prev_utime = max(p->prev_utime, clock_t_to_cputime(utime));
-       return p->prev_utime;
+       *ut = p->prev_utime;
+       *st = p->prev_stime;
 }
 
-cputime_t task_stime(struct task_struct *p)
+/*
+ * Must be called with siglock held.
+ */
+void thread_group_times(struct task_struct *p, cputime_t *ut, cputime_t *st)
 {
-       clock_t stime;
+       struct signal_struct *sig = p->signal;
+       struct task_cputime cputime;
+       cputime_t rtime, utime, total;
 
-       /*
-        * Use CFS's precise accounting. (we subtract utime from
-        * the total, to make sure the total observed by userspace
-        * grows monotonically - apps rely on that):
-        */
-       stime = nsec_to_clock_t(p->se.sum_exec_runtime) -
-                       cputime_to_clock_t(task_utime(p));
+       thread_group_cputime(p, &cputime);
 
-       if (stime >= 0)
-               p->prev_stime = max(p->prev_stime, clock_t_to_cputime(stime));
+       total = cputime_add(cputime.utime, cputime.stime);
+       rtime = nsecs_to_cputime(cputime.sum_exec_runtime);
 
-       return p->prev_stime;
-}
-#endif
+       if (total) {
+               u64 temp;
 
-inline cputime_t task_gtime(struct task_struct *p)
-{
-       return p->gtime;
+               temp = (u64)(rtime * cputime.utime);
+               do_div(temp, total);
+               utime = (cputime_t)temp;
+       } else
+               utime = rtime;
+
+       sig->prev_utime = max(sig->prev_utime, utime);
+       sig->prev_stime = max(sig->prev_stime,
+                             cputime_sub(rtime, sig->prev_utime));
+
+       *ut = sig->prev_utime;
+       *st = sig->prev_stime;
 }
+#endif
 
 /*
  * This function gets called by the timer code, with HZ frequency.
@@ -6175,22 +6221,14 @@ __setscheduler(struct rq *rq, struct task_struct *p, int policy, int prio)
        BUG_ON(p->se.on_rq);
 
        p->policy = policy;
-       switch (p->policy) {
-       case SCHED_NORMAL:
-       case SCHED_BATCH:
-       case SCHED_IDLE:
-               p->sched_class = &fair_sched_class;
-               break;
-       case SCHED_FIFO:
-       case SCHED_RR:
-               p->sched_class = &rt_sched_class;
-               break;
-       }
-
        p->rt_priority = prio;
        p->normal_prio = normal_prio(p);
        /* we are holding p->pi_lock already */
        p->prio = rt_mutex_getprio(p);
+       if (rt_prio(p->prio))
+               p->sched_class = &rt_sched_class;
+       else
+               p->sched_class = &fair_sched_class;
        set_load_weight(p);
 }
 
@@ -6935,7 +6973,7 @@ void show_state_filter(unsigned long state_filter)
        /*
         * Only show locks if all tasks are dumped:
         */
-       if (state_filter == -1)
+       if (!state_filter)
                debug_show_all_locks();
 }
 
@@ -7406,17 +7444,16 @@ static struct ctl_table sd_ctl_dir[] = {
                .procname       = "sched_domain",
                .mode           = 0555,
        },
-       {0, },
+       {}
 };
 
 static struct ctl_table sd_ctl_root[] = {
        {
-               .ctl_name       = CTL_KERN,
                .procname       = "kernel",
                .mode           = 0555,
                .child          = sd_ctl_dir,
        },
-       {0, },
+       {}
 };
 
 static struct ctl_table *sd_alloc_ctl_entry(int n)
@@ -7740,6 +7777,16 @@ early_initcall(migration_init);
 
 #ifdef CONFIG_SCHED_DEBUG
 
+static __read_mostly int sched_domain_debug_enabled;
+
+static int __init sched_domain_debug_setup(char *str)
+{
+       sched_domain_debug_enabled = 1;
+
+       return 0;
+}
+early_param("sched_debug", sched_domain_debug_setup);
+
 static int sched_domain_debug_one(struct sched_domain *sd, int cpu, int level,
                                  struct cpumask *groupmask)
 {
@@ -7826,6 +7873,9 @@ static void sched_domain_debug(struct sched_domain *sd, int cpu)
        cpumask_var_t groupmask;
        int level = 0;
 
+       if (!sched_domain_debug_enabled)
+               return;
+
        if (!sd) {
                printk(KERN_DEBUG "CPU%d attaching NULL sched-domain.\n", cpu);
                return;
@@ -7905,6 +7955,8 @@ sd_parent_degenerate(struct sched_domain *sd, struct sched_domain *parent)
 
 static void free_rootdomain(struct root_domain *rd)
 {
+       synchronize_sched();
+
        cpupri_cleanup(&rd->cpupri);
 
        free_cpumask_var(rd->rto_mask);
@@ -8045,6 +8097,7 @@ static cpumask_var_t cpu_isolated_map;
 /* Setup the mask of cpus configured for isolated domains */
 static int __init isolated_cpu_setup(char *str)
 {
+       alloc_bootmem_cpumask_var(&cpu_isolated_map);
        cpulist_parse(str, cpu_isolated_map);
        return 1;
 }
@@ -8881,7 +8934,7 @@ static int build_sched_domains(const struct cpumask *cpu_map)
        return __build_sched_domains(cpu_map, NULL);
 }
 
-static struct cpumask *doms_cur;       /* current sched domains */
+static cpumask_var_t *doms_cur;        /* current sched domains */
 static int ndoms_cur;          /* number of sched domains in 'doms_cur' */
 static struct sched_domain_attr *dattr_cur;
                                /* attribues of custom domains in 'doms_cur' */
@@ -8903,6 +8956,31 @@ int __attribute__((weak)) arch_update_cpu_topology(void)
        return 0;
 }
 
+cpumask_var_t *alloc_sched_domains(unsigned int ndoms)
+{
+       int i;
+       cpumask_var_t *doms;
+
+       doms = kmalloc(sizeof(*doms) * ndoms, GFP_KERNEL);
+       if (!doms)
+               return NULL;
+       for (i = 0; i < ndoms; i++) {
+               if (!alloc_cpumask_var(&doms[i], GFP_KERNEL)) {
+                       free_sched_domains(doms, i);
+                       return NULL;
+               }
+       }
+       return doms;
+}
+
+void free_sched_domains(cpumask_var_t doms[], unsigned int ndoms)
+{
+       unsigned int i;
+       for (i = 0; i < ndoms; i++)
+               free_cpumask_var(doms[i]);
+       kfree(doms);
+}
+
 /*
  * Set up scheduler domains and groups. Callers must hold the hotplug lock.
  * For now this just excludes isolated cpus, but could be used to
@@ -8914,12 +8992,12 @@ static int arch_init_sched_domains(const struct cpumask *cpu_map)
 
        arch_update_cpu_topology();
        ndoms_cur = 1;
-       doms_cur = kmalloc(cpumask_size(), GFP_KERNEL);
+       doms_cur = alloc_sched_domains(ndoms_cur);
        if (!doms_cur)
-               doms_cur = fallback_doms;
-       cpumask_andnot(doms_cur, cpu_map, cpu_isolated_map);
+               doms_cur = &fallback_doms;
+       cpumask_andnot(doms_cur[0], cpu_map, cpu_isolated_map);
        dattr_cur = NULL;
-       err = build_sched_domains(doms_cur);
+       err = build_sched_domains(doms_cur[0]);
        register_sched_domain_sysctl();
 
        return err;
@@ -8969,19 +9047,19 @@ static int dattrs_equal(struct sched_domain_attr *cur, int idx_cur,
  * doms_new[] to the current sched domain partitioning, doms_cur[].
  * It destroys each deleted domain and builds each new domain.
  *
- * 'doms_new' is an array of cpumask's of length 'ndoms_new'.
+ * 'doms_new' is an array of cpumask_var_t's of length 'ndoms_new'.
  * The masks don't intersect (don't overlap.) We should setup one
  * sched domain for each mask. CPUs not in any of the cpumasks will
  * not be load balanced. If the same cpumask appears both in the
  * current 'doms_cur' domains and in the new 'doms_new', we can leave
  * it as it is.
  *
- * The passed in 'doms_new' should be kmalloc'd. This routine takes
- * ownership of it and will kfree it when done with it. If the caller
- * failed the kmalloc call, then it can pass in doms_new == NULL &&
- * ndoms_new == 1, and partition_sched_domains() will fallback to
- * the single partition 'fallback_doms', it also forces the domains
- * to be rebuilt.
+ * The passed in 'doms_new' should be allocated using
+ * alloc_sched_domains.  This routine takes ownership of it and will
+ * free_sched_domains it when done with it. If the caller failed the
+ * alloc call, then it can pass in doms_new == NULL && ndoms_new == 1,
+ * and partition_sched_domains() will fallback to the single partition
+ * 'fallback_doms', it also forces the domains to be rebuilt.
  *
  * If doms_new == NULL it will be replaced with cpu_online_mask.
  * ndoms_new == 0 is a special case for destroying existing domains,
@@ -8989,8 +9067,7 @@ static int dattrs_equal(struct sched_domain_attr *cur, int idx_cur,
  *
  * Call with hotplug lock held
  */
-/* FIXME: Change to struct cpumask *doms_new[] */
-void partition_sched_domains(int ndoms_new, struct cpumask *doms_new,
+void partition_sched_domains(int ndoms_new, cpumask_var_t doms_new[],
                             struct sched_domain_attr *dattr_new)
 {
        int i, j, n;
@@ -9009,40 +9086,40 @@ void partition_sched_domains(int ndoms_new, struct cpumask *doms_new,
        /* Destroy deleted domains */
        for (i = 0; i < ndoms_cur; i++) {
                for (j = 0; j < n && !new_topology; j++) {
-                       if (cpumask_equal(&doms_cur[i], &doms_new[j])
+                       if (cpumask_equal(doms_cur[i], doms_new[j])
                            && dattrs_equal(dattr_cur, i, dattr_new, j))
                                goto match1;
                }
                /* no match - a current sched domain not in new doms_new[] */
-               detach_destroy_domains(doms_cur + i);
+               detach_destroy_domains(doms_cur[i]);
 match1:
                ;
        }
 
        if (doms_new == NULL) {
                ndoms_cur = 0;
-               doms_new = fallback_doms;
-               cpumask_andnot(&doms_new[0], cpu_online_mask, cpu_isolated_map);
+               doms_new = &fallback_doms;
+               cpumask_andnot(doms_new[0], cpu_online_mask, cpu_isolated_map);
                WARN_ON_ONCE(dattr_new);
        }
 
        /* Build new domains */
        for (i = 0; i < ndoms_new; i++) {
                for (j = 0; j < ndoms_cur && !new_topology; j++) {
-                       if (cpumask_equal(&doms_new[i], &doms_cur[j])
+                       if (cpumask_equal(doms_new[i], doms_cur[j])
                            && dattrs_equal(dattr_new, i, dattr_cur, j))
                                goto match2;
                }
                /* no match - add a new doms_new */
-               __build_sched_domains(doms_new + i,
+               __build_sched_domains(doms_new[i],
                                        dattr_new ? dattr_new + i : NULL);
 match2:
                ;
        }
 
        /* Remember the new sched domains */
-       if (doms_cur != fallback_doms)
-               kfree(doms_cur);
+       if (doms_cur != &fallback_doms)
+               free_sched_domains(doms_cur, ndoms_cur);
        kfree(dattr_cur);       /* kfree(NULL) is safe */
        doms_cur = doms_new;
        dattr_cur = dattr_new;
@@ -9364,10 +9441,6 @@ void __init sched_init(void)
 #ifdef CONFIG_CPUMASK_OFFSTACK
        alloc_size += num_possible_cpus() * cpumask_size();
 #endif
-       /*
-        * As sched_init() is called before page_alloc is setup,
-        * we use alloc_bootmem().
-        */
        if (alloc_size) {
                ptr = (unsigned long)kzalloc(alloc_size, GFP_NOWAIT);
 
@@ -9522,6 +9595,8 @@ void __init sched_init(void)
                rq->cpu = i;
                rq->online = 0;
                rq->migration_thread = NULL;
+               rq->idle_stamp = 0;
+               rq->avg_idle = 2*sysctl_sched_migration_cost;
                INIT_LIST_HEAD(&rq->migration_queue);
                rq_attach_root(rq, &def_root_domain);
 #endif
@@ -9571,7 +9646,9 @@ void __init sched_init(void)
        zalloc_cpumask_var(&nohz.cpu_mask, GFP_NOWAIT);
        alloc_cpumask_var(&nohz.ilb_grp_nohz_mask, GFP_NOWAIT);
 #endif
-       zalloc_cpumask_var(&cpu_isolated_map, GFP_NOWAIT);
+       /* May be allocated at isolcpus cmdline parse time */
+       if (cpu_isolated_map == NULL)
+               zalloc_cpumask_var(&cpu_isolated_map, GFP_NOWAIT);
 #endif /* SMP */
 
        perf_event_init();
index efb8440..6988cf0 100644 (file)
@@ -285,12 +285,16 @@ static void print_cpu(struct seq_file *m, int cpu)
 
 #ifdef CONFIG_SCHEDSTATS
 #define P(n) SEQ_printf(m, "  .%-30s: %d\n", #n, rq->n);
+#define P64(n) SEQ_printf(m, "  .%-30s: %Ld\n", #n, rq->n);
 
        P(yld_count);
 
        P(sched_switch);
        P(sched_count);
        P(sched_goidle);
+#ifdef CONFIG_SMP
+       P64(avg_idle);
+#endif
 
        P(ttwu_count);
        P(ttwu_local);
index 37087a7..f61837a 100644 (file)
@@ -1345,6 +1345,37 @@ find_idlest_cpu(struct sched_group *group, struct task_struct *p, int this_cpu)
 }
 
 /*
+ * Try and locate an idle CPU in the sched_domain.
+ */
+static int
+select_idle_sibling(struct task_struct *p, struct sched_domain *sd, int target)
+{
+       int cpu = smp_processor_id();
+       int prev_cpu = task_cpu(p);
+       int i;
+
+       /*
+        * If this domain spans both cpu and prev_cpu (see the SD_WAKE_AFFINE
+        * test in select_task_rq_fair) and the prev_cpu is idle then that's
+        * always a better target than the current cpu.
+        */
+       if (target == cpu && !cpu_rq(prev_cpu)->cfs.nr_running)
+               return prev_cpu;
+
+       /*
+        * Otherwise, iterate the domain and find an elegible idle cpu.
+        */
+       for_each_cpu_and(i, sched_domain_span(sd), &p->cpus_allowed) {
+               if (!cpu_rq(i)->cfs.nr_running) {
+                       target = i;
+                       break;
+               }
+       }
+
+       return target;
+}
+
+/*
  * sched_balance_self: balance the current task (running on cpu) in domains
  * that have the 'flag' flag set. In practice, this is SD_BALANCE_FORK and
  * SD_BALANCE_EXEC.
@@ -1398,11 +1429,35 @@ static int select_task_rq_fair(struct task_struct *p, int sd_flag, int wake_flag
                                want_sd = 0;
                }
 
-               if (want_affine && (tmp->flags & SD_WAKE_AFFINE) &&
-                   cpumask_test_cpu(prev_cpu, sched_domain_span(tmp))) {
+               /*
+                * While iterating the domains looking for a spanning
+                * WAKE_AFFINE domain, adjust the affine target to any idle cpu
+                * in cache sharing domains along the way.
+                */
+               if (want_affine) {
+                       int target = -1;
 
-                       affine_sd = tmp;
-                       want_affine = 0;
+                       /*
+                        * If both cpu and prev_cpu are part of this domain,
+                        * cpu is a valid SD_WAKE_AFFINE target.
+                        */
+                       if (cpumask_test_cpu(prev_cpu, sched_domain_span(tmp)))
+                               target = cpu;
+
+                       /*
+                        * If there's an idle sibling in this domain, make that
+                        * the wake_affine target instead of the current cpu.
+                        */
+                       if (tmp->flags & SD_PREFER_SIBLING)
+                               target = select_idle_sibling(p, tmp, target);
+
+                       if (target >= 0) {
+                               if (tmp->flags & SD_WAKE_AFFINE) {
+                                       affine_sd = tmp;
+                                       want_affine = 0;
+                               }
+                               cpu = target;
+                       }
                }
 
                if (!want_sd && !want_affine)
@@ -1679,7 +1734,7 @@ static struct task_struct *pick_next_task_fair(struct rq *rq)
        struct cfs_rq *cfs_rq = &rq->cfs;
        struct sched_entity *se;
 
-       if (unlikely(!cfs_rq->nr_running))
+       if (!cfs_rq->nr_running)
                return NULL;
 
        do {
index a4d790c..5c5fef3 100644 (file)
@@ -1153,29 +1153,12 @@ static struct task_struct *pick_next_highest_task_rt(struct rq *rq, int cpu)
 
 static DEFINE_PER_CPU(cpumask_var_t, local_cpu_mask);
 
-static inline int pick_optimal_cpu(int this_cpu,
-                                  const struct cpumask *mask)
-{
-       int first;
-
-       /* "this_cpu" is cheaper to preempt than a remote processor */
-       if ((this_cpu != -1) && cpumask_test_cpu(this_cpu, mask))
-               return this_cpu;
-
-       first = cpumask_first(mask);
-       if (first < nr_cpu_ids)
-               return first;
-
-       return -1;
-}
-
 static int find_lowest_rq(struct task_struct *task)
 {
        struct sched_domain *sd;
        struct cpumask *lowest_mask = __get_cpu_var(local_cpu_mask);
        int this_cpu = smp_processor_id();
        int cpu      = task_cpu(task);
-       cpumask_var_t domain_mask;
 
        if (task->rt.nr_cpus_allowed == 1)
                return -1; /* No other targets possible */
@@ -1198,28 +1181,26 @@ static int find_lowest_rq(struct task_struct *task)
         * Otherwise, we consult the sched_domains span maps to figure
         * out which cpu is logically closest to our hot cache data.
         */
-       if (this_cpu == cpu)
-               this_cpu = -1; /* Skip this_cpu opt if the same */
-
-       if (alloc_cpumask_var(&domain_mask, GFP_ATOMIC)) {
-               for_each_domain(cpu, sd) {
-                       if (sd->flags & SD_WAKE_AFFINE) {
-                               int best_cpu;
+       if (!cpumask_test_cpu(this_cpu, lowest_mask))
+               this_cpu = -1; /* Skip this_cpu opt if not among lowest */
 
-                               cpumask_and(domain_mask,
-                                           sched_domain_span(sd),
-                                           lowest_mask);
+       for_each_domain(cpu, sd) {
+               if (sd->flags & SD_WAKE_AFFINE) {
+                       int best_cpu;
 
-                               best_cpu = pick_optimal_cpu(this_cpu,
-                                                           domain_mask);
-
-                               if (best_cpu != -1) {
-                                       free_cpumask_var(domain_mask);
-                                       return best_cpu;
-                               }
-                       }
+                       /*
+                        * "this_cpu" is cheaper to preempt than a
+                        * remote processor.
+                        */
+                       if (this_cpu != -1 &&
+                           cpumask_test_cpu(this_cpu, sched_domain_span(sd)))
+                               return this_cpu;
+
+                       best_cpu = cpumask_first_and(lowest_mask,
+                                                    sched_domain_span(sd));
+                       if (best_cpu < nr_cpu_ids)
+                               return best_cpu;
                }
-               free_cpumask_var(domain_mask);
        }
 
        /*
@@ -1227,7 +1208,13 @@ static int find_lowest_rq(struct task_struct *task)
         * just give the caller *something* to work with from the compatible
         * locations.
         */
-       return pick_optimal_cpu(this_cpu, lowest_mask);
+       if (this_cpu != -1)
+               return this_cpu;
+
+       cpu = cpumask_any(lowest_mask);
+       if (cpu < nr_cpu_ids)
+               return cpu;
+       return -1;
 }
 
 /* Will lock the rq it finds */
index fe08008..6b982f2 100644 (file)
@@ -28,7 +28,8 @@
 #include <linux/freezer.h>
 #include <linux/pid_namespace.h>
 #include <linux/nsproxy.h>
-#include <trace/events/sched.h>
+#define CREATE_TRACE_POINTS
+#include <trace/events/signal.h>
 
 #include <asm/param.h>
 #include <asm/uaccess.h>
@@ -856,7 +857,7 @@ static int __send_signal(int sig, struct siginfo *info, struct task_struct *t,
        struct sigqueue *q;
        int override_rlimit;
 
-       trace_sched_signal_send(sig, t);
+       trace_signal_generate(sig, info, t);
 
        assert_spin_locked(&t->sighand->siglock);
 
@@ -918,12 +919,21 @@ static int __send_signal(int sig, struct siginfo *info, struct task_struct *t,
                        break;
                }
        } else if (!is_si_special(info)) {
-               if (sig >= SIGRTMIN && info->si_code != SI_USER)
-               /*
-                * Queue overflow, abort.  We may abort if the signal was rt
-                * and sent by user using something other than kill().
-                */
+               if (sig >= SIGRTMIN && info->si_code != SI_USER) {
+                       /*
+                        * Queue overflow, abort.  We may abort if the
+                        * signal was rt and sent by user using something
+                        * other than kill().
+                        */
+                       trace_signal_overflow_fail(sig, group, info);
                        return -EAGAIN;
+               } else {
+                       /*
+                        * This is a silent loss of information.  We still
+                        * send the signal, but the *info bits are lost.
+                        */
+                       trace_signal_lose_info(sig, group, info);
+               }
        }
 
 out_set:
@@ -1859,6 +1869,9 @@ relock:
                        ka = &sighand->action[signr-1];
                }
 
+               /* Trace actually delivered signals. */
+               trace_signal_deliver(signr, info, ka);
+
                if (ka->sa.sa_handler == SIG_IGN) /* Do nothing.  */
                        continue;
                if (ka->sa.sa_handler != SIG_DFL) {
index 00889bd..7494bbf 100644 (file)
@@ -49,7 +49,6 @@ static const int slow_work_max_vslow = 99;
 
 ctl_table slow_work_sysctls[] = {
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "min-threads",
                .data           = &slow_work_min_threads,
                .maxlen         = sizeof(unsigned),
@@ -59,7 +58,6 @@ ctl_table slow_work_sysctls[] = {
                .extra2         = &slow_work_max_threads,
        },
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "max-threads",
                .data           = &slow_work_max_threads,
                .maxlen         = sizeof(unsigned),
@@ -69,16 +67,15 @@ ctl_table slow_work_sysctls[] = {
                .extra2         = (void *) &slow_work_max_max_threads,
        },
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "vslow-percentage",
                .data           = &vslow_work_proportion,
                .maxlen         = sizeof(unsigned),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec_minmax,
+               .proc_handler   = proc_dointvec_minmax,
                .extra1         = (void *) &slow_work_min_vslow,
                .extra2         = (void *) &slow_work_max_vslow,
        },
-       { .ctl_name = 0 }
+       {}
 };
 #endif
 
index ce17760..9968c5f 100644 (file)
@@ -911,16 +911,15 @@ change_okay:
 
 void do_sys_times(struct tms *tms)
 {
-       struct task_cputime cputime;
-       cputime_t cutime, cstime;
+       cputime_t tgutime, tgstime, cutime, cstime;
 
-       thread_group_cputime(current, &cputime);
        spin_lock_irq(&current->sighand->siglock);
+       thread_group_times(current, &tgutime, &tgstime);
        cutime = current->signal->cutime;
        cstime = current->signal->cstime;
        spin_unlock_irq(&current->sighand->siglock);
-       tms->tms_utime = cputime_to_clock_t(cputime.utime);
-       tms->tms_stime = cputime_to_clock_t(cputime.stime);
+       tms->tms_utime = cputime_to_clock_t(tgutime);
+       tms->tms_stime = cputime_to_clock_t(tgstime);
        tms->tms_cutime = cputime_to_clock_t(cutime);
        tms->tms_cstime = cputime_to_clock_t(cstime);
 }
@@ -1338,16 +1337,14 @@ static void k_getrusage(struct task_struct *p, int who, struct rusage *r)
 {
        struct task_struct *t;
        unsigned long flags;
-       cputime_t utime, stime;
-       struct task_cputime cputime;
+       cputime_t tgutime, tgstime, utime, stime;
        unsigned long maxrss = 0;
 
        memset((char *) r, 0, sizeof *r);
        utime = stime = cputime_zero;
 
        if (who == RUSAGE_THREAD) {
-               utime = task_utime(current);
-               stime = task_stime(current);
+               task_times(current, &utime, &stime);
                accumulate_thread_rusage(p, r);
                maxrss = p->signal->maxrss;
                goto out;
@@ -1373,9 +1370,9 @@ static void k_getrusage(struct task_struct *p, int who, struct rusage *r)
                                break;
 
                case RUSAGE_SELF:
-                       thread_group_cputime(p, &cputime);
-                       utime = cputime_add(utime, cputime.utime);
-                       stime = cputime_add(stime, cputime.stime);
+                       thread_group_times(p, &tgutime, &tgstime);
+                       utime = cputime_add(utime, tgutime);
+                       stime = cputime_add(stime, tgstime);
                        r->ru_nvcsw += p->signal->nvcsw;
                        r->ru_nivcsw += p->signal->nivcsw;
                        r->ru_minflt += p->signal->min_flt;
index f050ba8..695384f 100644 (file)
@@ -141,7 +141,6 @@ cond_syscall(sys_pciconfig_read);
 cond_syscall(sys_pciconfig_write);
 cond_syscall(sys_pciconfig_iobase);
 cond_syscall(sys32_ipc);
-cond_syscall(sys32_sysctl);
 cond_syscall(ppc_rtas);
 cond_syscall(sys_spu_run);
 cond_syscall(sys_spu_create);
index 4dbf93a..9327a26 100644 (file)
@@ -27,7 +27,6 @@
 #include <linux/security.h>
 #include <linux/ctype.h>
 #include <linux/kmemcheck.h>
-#include <linux/smp_lock.h>
 #include <linux/fs.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
@@ -61,7 +60,6 @@
 #include <asm/io.h>
 #endif
 
-static int deprecated_sysctl_warning(struct __sysctl_args *args);
 
 #if defined(CONFIG_SYSCTL)
 
@@ -210,31 +208,26 @@ extern int lock_stat;
 
 static struct ctl_table root_table[] = {
        {
-               .ctl_name       = CTL_KERN,
                .procname       = "kernel",
                .mode           = 0555,
                .child          = kern_table,
        },
        {
-               .ctl_name       = CTL_VM,
                .procname       = "vm",
                .mode           = 0555,
                .child          = vm_table,
        },
        {
-               .ctl_name       = CTL_FS,
                .procname       = "fs",
                .mode           = 0555,
                .child          = fs_table,
        },
        {
-               .ctl_name       = CTL_DEBUG,
                .procname       = "debug",
                .mode           = 0555,
                .child          = debug_table,
        },
        {
-               .ctl_name       = CTL_DEV,
                .procname       = "dev",
                .mode           = 0555,
                .child          = dev_table,
@@ -243,7 +236,7 @@ static struct ctl_table root_table[] = {
  * NOTE: do not add new entries to this table unless you have read
  * Documentation/sysctl/ctl_unnumbered.txt
  */
-       { .ctl_name = 0 }
+       { }
 };
 
 #ifdef CONFIG_SCHED_DEBUG
@@ -255,192 +248,166 @@ static int max_wakeup_granularity_ns = NSEC_PER_SEC;    /* 1 second */
 
 static struct ctl_table kern_table[] = {
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "sched_child_runs_first",
                .data           = &sysctl_sched_child_runs_first,
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec,
+               .proc_handler   = proc_dointvec,
        },
 #ifdef CONFIG_SCHED_DEBUG
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "sched_min_granularity_ns",
                .data           = &sysctl_sched_min_granularity,
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
-               .proc_handler   = &sched_nr_latency_handler,
-               .strategy       = &sysctl_intvec,
+               .proc_handler   = sched_nr_latency_handler,
                .extra1         = &min_sched_granularity_ns,
                .extra2         = &max_sched_granularity_ns,
        },
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "sched_latency_ns",
                .data           = &sysctl_sched_latency,
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
-               .proc_handler   = &sched_nr_latency_handler,
-               .strategy       = &sysctl_intvec,
+               .proc_handler   = sched_nr_latency_handler,
                .extra1         = &min_sched_granularity_ns,
                .extra2         = &max_sched_granularity_ns,
        },
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "sched_wakeup_granularity_ns",
                .data           = &sysctl_sched_wakeup_granularity,
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec_minmax,
-               .strategy       = &sysctl_intvec,
+               .proc_handler   = proc_dointvec_minmax,
                .extra1         = &min_wakeup_granularity_ns,
                .extra2         = &max_wakeup_granularity_ns,
        },
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "sched_shares_ratelimit",
                .data           = &sysctl_sched_shares_ratelimit,
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec,
+               .proc_handler   = proc_dointvec,
        },
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "sched_shares_thresh",
                .data           = &sysctl_sched_shares_thresh,
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec_minmax,
-               .strategy       = &sysctl_intvec,
+               .proc_handler   = proc_dointvec_minmax,
                .extra1         = &zero,
        },
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "sched_features",
                .data           = &sysctl_sched_features,
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec,
+               .proc_handler   = proc_dointvec,
        },
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "sched_migration_cost",
                .data           = &sysctl_sched_migration_cost,
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec,
+               .proc_handler   = proc_dointvec,
        },
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "sched_nr_migrate",
                .data           = &sysctl_sched_nr_migrate,
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec,
+               .proc_handler   = proc_dointvec,
        },
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "sched_time_avg",
                .data           = &sysctl_sched_time_avg,
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec,
+               .proc_handler   = proc_dointvec,
        },
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "timer_migration",
                .data           = &sysctl_timer_migration,
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec_minmax,
-               .strategy       = &sysctl_intvec,
+               .proc_handler   = proc_dointvec_minmax,
                .extra1         = &zero,
                .extra2         = &one,
        },
 #endif
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "sched_rt_period_us",
                .data           = &sysctl_sched_rt_period,
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
-               .proc_handler   = &sched_rt_handler,
+               .proc_handler   = sched_rt_handler,
        },
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "sched_rt_runtime_us",
                .data           = &sysctl_sched_rt_runtime,
                .maxlen         = sizeof(int),
                .mode           = 0644,
-               .proc_handler   = &sched_rt_handler,
+               .proc_handler   = sched_rt_handler,
        },
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "sched_compat_yield",
                .data           = &sysctl_sched_compat_yield,
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec,
+               .proc_handler   = proc_dointvec,
        },
 #ifdef CONFIG_PROVE_LOCKING
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "prove_locking",
                .data           = &prove_locking,
                .maxlen         = sizeof(int),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec,
+               .proc_handler   = proc_dointvec,
        },
 #endif
 #ifdef CONFIG_LOCK_STAT
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "lock_stat",
                .data           = &lock_stat,
                .maxlen         = sizeof(int),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec,
+               .proc_handler   = proc_dointvec,
        },
 #endif
        {
-               .ctl_name       = KERN_PANIC,
                .procname       = "panic",
                .data           = &panic_timeout,
                .maxlen         = sizeof(int),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec,
+               .proc_handler   = proc_dointvec,
        },
        {
-               .ctl_name       = KERN_CORE_USES_PID,
                .procname       = "core_uses_pid",
                .data           = &core_uses_pid,
                .maxlen         = sizeof(int),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec,
+               .proc_handler   = proc_dointvec,
        },
        {
-               .ctl_name       = KERN_CORE_PATTERN,
                .procname       = "core_pattern",
                .data           = core_pattern,
                .maxlen         = CORENAME_MAX_SIZE,
                .mode           = 0644,
-               .proc_handler   = &proc_dostring,
-               .strategy       = &sysctl_string,
+               .proc_handler   = proc_dostring,
        },
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "core_pipe_limit",
                .data           = &core_pipe_limit,
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec,
+               .proc_handler   = proc_dointvec,
        },
 #ifdef CONFIG_PROC_SYSCTL
        {
                .procname       = "tainted",
                .maxlen         = sizeof(long),
                .mode           = 0644,
-               .proc_handler   = &proc_taint,
+               .proc_handler   = proc_taint,
        },
 #endif
 #ifdef CONFIG_LATENCYTOP
@@ -449,181 +416,160 @@ static struct ctl_table kern_table[] = {
                .data           = &latencytop_enabled,
                .maxlen         = sizeof(int),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec,
+               .proc_handler   = proc_dointvec,
        },
 #endif
 #ifdef CONFIG_BLK_DEV_INITRD
        {
-               .ctl_name       = KERN_REALROOTDEV,
                .procname       = "real-root-dev",
                .data           = &real_root_dev,
                .maxlen         = sizeof(int),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec,
+               .proc_handler   = proc_dointvec,
        },
 #endif
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "print-fatal-signals",
                .data           = &print_fatal_signals,
                .maxlen         = sizeof(int),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec,
+               .proc_handler   = proc_dointvec,
        },
 #ifdef CONFIG_SPARC
        {
-               .ctl_name       = KERN_SPARC_REBOOT,
                .procname       = "reboot-cmd",
                .data           = reboot_command,
                .maxlen         = 256,
                .mode           = 0644,
-               .proc_handler   = &proc_dostring,
-               .strategy       = &sysctl_string,
+               .proc_handler   = proc_dostring,
        },
        {
-               .ctl_name       = KERN_SPARC_STOP_A,
                .procname       = "stop-a",
                .data           = &stop_a_enabled,
                .maxlen         = sizeof (int),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec,
+               .proc_handler   = proc_dointvec,
        },
        {
-               .ctl_name       = KERN_SPARC_SCONS_PWROFF,
                .procname       = "scons-poweroff",
                .data           = &scons_pwroff,
                .maxlen         = sizeof (int),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec,
+               .proc_handler   = proc_dointvec,
        },
 #endif
 #ifdef CONFIG_SPARC64
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "tsb-ratio",
                .data           = &sysctl_tsb_ratio,
                .maxlen         = sizeof (int),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec,
+               .proc_handler   = proc_dointvec,
        },
 #endif
 #ifdef __hppa__
        {
-               .ctl_name       = KERN_HPPA_PWRSW,
                .procname       = "soft-power",
                .data           = &pwrsw_enabled,
                .maxlen         = sizeof (int),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec,
+               .proc_handler   = proc_dointvec,
        },
        {
-               .ctl_name       = KERN_HPPA_UNALIGNED,
                .procname       = "unaligned-trap",
                .data           = &unaligned_enabled,
                .maxlen         = sizeof (int),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec,
+               .proc_handler   = proc_dointvec,
        },
 #endif
        {
-               .ctl_name       = KERN_CTLALTDEL,
                .procname       = "ctrl-alt-del",
                .data           = &C_A_D,
                .maxlen         = sizeof(int),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec,
+               .proc_handler   = proc_dointvec,
        },
 #ifdef CONFIG_FUNCTION_TRACER
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "ftrace_enabled",
                .data           = &ftrace_enabled,
                .maxlen         = sizeof(int),
                .mode           = 0644,
-               .proc_handler   = &ftrace_enable_sysctl,
+               .proc_handler   = ftrace_enable_sysctl,
        },
 #endif
 #ifdef CONFIG_STACK_TRACER
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "stack_tracer_enabled",
                .data           = &stack_tracer_enabled,
                .maxlen         = sizeof(int),
                .mode           = 0644,
-               .proc_handler   = &stack_trace_sysctl,
+               .proc_handler   = stack_trace_sysctl,
        },
 #endif
 #ifdef CONFIG_TRACING
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "ftrace_dump_on_oops",
                .data           = &ftrace_dump_on_oops,
                .maxlen         = sizeof(int),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec,
+               .proc_handler   = proc_dointvec,
        },
 #endif
 #ifdef CONFIG_MODULES
        {
-               .ctl_name       = KERN_MODPROBE,
                .procname       = "modprobe",
                .data           = &modprobe_path,
                .maxlen         = KMOD_PATH_LEN,
                .mode           = 0644,
-               .proc_handler   = &proc_dostring,
-               .strategy       = &sysctl_string,
+               .proc_handler   = proc_dostring,
        },
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "modules_disabled",
                .data           = &modules_disabled,
                .maxlen         = sizeof(int),
                .mode           = 0644,
                /* only handle a transition from default "0" to "1" */
-               .proc_handler   = &proc_dointvec_minmax,
+               .proc_handler   = proc_dointvec_minmax,
                .extra1         = &one,
                .extra2         = &one,
        },
 #endif
 #if defined(CONFIG_HOTPLUG) && defined(CONFIG_NET)
        {
-               .ctl_name       = KERN_HOTPLUG,
                .procname       = "hotplug",
                .data           = &uevent_helper,
                .maxlen         = UEVENT_HELPER_PATH_LEN,
                .mode           = 0644,
-               .proc_handler   = &proc_dostring,
-               .strategy       = &sysctl_string,
+               .proc_handler   = proc_dostring,
        },
 #endif
 #ifdef CONFIG_CHR_DEV_SG
        {
-               .ctl_name       = KERN_SG_BIG_BUFF,
                .procname       = "sg-big-buff",
                .data           = &sg_big_buff,
                .maxlen         = sizeof (int),
                .mode           = 0444,
-               .proc_handler   = &proc_dointvec,
+               .proc_handler   = proc_dointvec,
        },
 #endif
 #ifdef CONFIG_BSD_PROCESS_ACCT
        {
-               .ctl_name       = KERN_ACCT,
                .procname       = "acct",
                .data           = &acct_parm,
                .maxlen         = 3*sizeof(int),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec,
+               .proc_handler   = proc_dointvec,
        },
 #endif
 #ifdef CONFIG_MAGIC_SYSRQ
        {
-               .ctl_name       = KERN_SYSRQ,
                .procname       = "sysrq",
                .data           = &__sysrq_enabled,
                .maxlen         = sizeof (int),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec,
+               .proc_handler   = proc_dointvec,
        },
 #endif
 #ifdef CONFIG_PROC_SYSCTL
@@ -632,215 +578,188 @@ static struct ctl_table kern_table[] = {
                .data           = NULL,
                .maxlen         = sizeof (int),
                .mode           = 0600,
-               .proc_handler   = &proc_do_cad_pid,
+               .proc_handler   = proc_do_cad_pid,
        },
 #endif
        {
-               .ctl_name       = KERN_MAX_THREADS,
                .procname       = "threads-max",
                .data           = &max_threads,
                .maxlen         = sizeof(int),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec,
+               .proc_handler   = proc_dointvec,
        },
        {
-               .ctl_name       = KERN_RANDOM,
                .procname       = "random",
                .mode           = 0555,
                .child          = random_table,
        },
        {
-               .ctl_name       = KERN_OVERFLOWUID,
                .procname       = "overflowuid",
                .data           = &overflowuid,
                .maxlen         = sizeof(int),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec_minmax,
-               .strategy       = &sysctl_intvec,
+               .proc_handler   = proc_dointvec_minmax,
                .extra1         = &minolduid,
                .extra2         = &maxolduid,
        },
        {
-               .ctl_name       = KERN_OVERFLOWGID,
                .procname       = "overflowgid",
                .data           = &overflowgid,
                .maxlen         = sizeof(int),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec_minmax,
-               .strategy       = &sysctl_intvec,
+               .proc_handler   = proc_dointvec_minmax,
                .extra1         = &minolduid,
                .extra2         = &maxolduid,
        },
 #ifdef CONFIG_S390
 #ifdef CONFIG_MATHEMU
        {
-               .ctl_name       = KERN_IEEE_EMULATION_WARNINGS,
                .procname       = "ieee_emulation_warnings",
                .data           = &sysctl_ieee_emulation_warnings,
                .maxlen         = sizeof(int),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec,
+               .proc_handler   = proc_dointvec,
        },
 #endif
        {
-               .ctl_name       = KERN_S390_USER_DEBUG_LOGGING,
                .procname       = "userprocess_debug",
                .data           = &sysctl_userprocess_debug,
                .maxlen         = sizeof(int),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec,
+               .proc_handler   = proc_dointvec,
        },
 #endif
        {
-               .ctl_name       = KERN_PIDMAX,
                .procname       = "pid_max",
                .data           = &pid_max,
                .maxlen         = sizeof (int),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec_minmax,
-               .strategy       = sysctl_intvec,
+               .proc_handler   = proc_dointvec_minmax,
                .extra1         = &pid_max_min,
                .extra2         = &pid_max_max,
        },
        {
-               .ctl_name       = KERN_PANIC_ON_OOPS,
                .procname       = "panic_on_oops",
                .data           = &panic_on_oops,
                .maxlen         = sizeof(int),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec,
+               .proc_handler   = proc_dointvec,
        },
 #if defined CONFIG_PRINTK
        {
-               .ctl_name       = KERN_PRINTK,
                .procname       = "printk",
                .data           = &console_loglevel,
                .maxlen         = 4*sizeof(int),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec,
+               .proc_handler   = proc_dointvec,
        },
        {
-               .ctl_name       = KERN_PRINTK_RATELIMIT,
                .procname       = "printk_ratelimit",
                .data           = &printk_ratelimit_state.interval,
                .maxlen         = sizeof(int),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec_jiffies,
-               .strategy       = &sysctl_jiffies,
+               .proc_handler   = proc_dointvec_jiffies,
        },
        {
-               .ctl_name       = KERN_PRINTK_RATELIMIT_BURST,
                .procname       = "printk_ratelimit_burst",
                .data           = &printk_ratelimit_state.burst,
                .maxlen         = sizeof(int),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec,
+               .proc_handler   = proc_dointvec,
        },
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "printk_delay",
                .data           = &printk_delay_msec,
                .maxlen         = sizeof(int),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec_minmax,
-               .strategy       = &sysctl_intvec,
+               .proc_handler   = proc_dointvec_minmax,
                .extra1         = &zero,
                .extra2         = &ten_thousand,
        },
 #endif
        {
-               .ctl_name       = KERN_NGROUPS_MAX,
                .procname       = "ngroups_max",
                .data           = &ngroups_max,
                .maxlen         = sizeof (int),
                .mode           = 0444,
-               .proc_handler   = &proc_dointvec,
+               .proc_handler   = proc_dointvec,
        },
 #if defined(CONFIG_X86_LOCAL_APIC) && defined(CONFIG_X86)
        {
-               .ctl_name       = KERN_UNKNOWN_NMI_PANIC,
                .procname       = "unknown_nmi_panic",
                .data           = &unknown_nmi_panic,
                .maxlen         = sizeof (int),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec,
+               .proc_handler   = proc_dointvec,
        },
        {
                .procname       = "nmi_watchdog",
                .data           = &nmi_watchdog_enabled,
                .maxlen         = sizeof (int),
                .mode           = 0644,
-               .proc_handler   = &proc_nmi_enabled,
+               .proc_handler   = proc_nmi_enabled,
        },
 #endif
 #if defined(CONFIG_X86)
        {
-               .ctl_name       = KERN_PANIC_ON_NMI,
                .procname       = "panic_on_unrecovered_nmi",
                .data           = &panic_on_unrecovered_nmi,
                .maxlen         = sizeof(int),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec,
+               .proc_handler   = proc_dointvec,
        },
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "panic_on_io_nmi",
                .data           = &panic_on_io_nmi,
                .maxlen         = sizeof(int),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec,
+               .proc_handler   = proc_dointvec,
        },
        {
-               .ctl_name       = KERN_BOOTLOADER_TYPE,
                .procname       = "bootloader_type",
                .data           = &bootloader_type,
                .maxlen         = sizeof (int),
                .mode           = 0444,
-               .proc_handler   = &proc_dointvec,
+               .proc_handler   = proc_dointvec,
        },
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "bootloader_version",
                .data           = &bootloader_version,
                .maxlen         = sizeof (int),
                .mode           = 0444,
-               .proc_handler   = &proc_dointvec,
+               .proc_handler   = proc_dointvec,
        },
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "kstack_depth_to_print",
                .data           = &kstack_depth_to_print,
                .maxlen         = sizeof(int),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec,
+               .proc_handler   = proc_dointvec,
        },
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "io_delay_type",
                .data           = &io_delay_type,
                .maxlen         = sizeof(int),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec,
+               .proc_handler   = proc_dointvec,
        },
 #endif
 #if defined(CONFIG_MMU)
        {
-               .ctl_name       = KERN_RANDOMIZE,
                .procname       = "randomize_va_space",
                .data           = &randomize_va_space,
                .maxlen         = sizeof(int),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec,
+               .proc_handler   = proc_dointvec,
        },
 #endif
 #if defined(CONFIG_S390) && defined(CONFIG_SMP)
        {
-               .ctl_name       = KERN_SPIN_RETRY,
                .procname       = "spin_retry",
                .data           = &spin_retry,
                .maxlen         = sizeof (int),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec,
+               .proc_handler   = proc_dointvec,
        },
 #endif
 #if    defined(CONFIG_ACPI_SLEEP) && defined(CONFIG_X86)
@@ -849,123 +768,104 @@ static struct ctl_table kern_table[] = {
                .data           = &acpi_realmode_flags,
                .maxlen         = sizeof (unsigned long),
                .mode           = 0644,
-               .proc_handler   = &proc_doulongvec_minmax,
+               .proc_handler   = proc_doulongvec_minmax,
        },
 #endif
 #ifdef CONFIG_IA64
        {
-               .ctl_name       = KERN_IA64_UNALIGNED,
                .procname       = "ignore-unaligned-usertrap",
                .data           = &no_unaligned_warning,
                .maxlen         = sizeof (int),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec,
+               .proc_handler   = proc_dointvec,
        },
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "unaligned-dump-stack",
                .data           = &unaligned_dump_stack,
                .maxlen         = sizeof (int),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec,
+               .proc_handler   = proc_dointvec,
        },
 #endif
 #ifdef CONFIG_DETECT_SOFTLOCKUP
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "softlockup_panic",
                .data           = &softlockup_panic,
                .maxlen         = sizeof(int),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec_minmax,
-               .strategy       = &sysctl_intvec,
+               .proc_handler   = proc_dointvec_minmax,
                .extra1         = &zero,
                .extra2         = &one,
        },
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "softlockup_thresh",
                .data           = &softlockup_thresh,
                .maxlen         = sizeof(int),
                .mode           = 0644,
-               .proc_handler   = &proc_dosoftlockup_thresh,
-               .strategy       = &sysctl_intvec,
+               .proc_handler   = proc_dosoftlockup_thresh,
                .extra1         = &neg_one,
                .extra2         = &sixty,
        },
 #endif
 #ifdef CONFIG_DETECT_HUNG_TASK
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "hung_task_panic",
                .data           = &sysctl_hung_task_panic,
                .maxlen         = sizeof(int),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec_minmax,
-               .strategy       = &sysctl_intvec,
+               .proc_handler   = proc_dointvec_minmax,
                .extra1         = &zero,
                .extra2         = &one,
        },
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "hung_task_check_count",
                .data           = &sysctl_hung_task_check_count,
                .maxlen         = sizeof(unsigned long),
                .mode           = 0644,
-               .proc_handler   = &proc_doulongvec_minmax,
-               .strategy       = &sysctl_intvec,
+               .proc_handler   = proc_doulongvec_minmax,
        },
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "hung_task_timeout_secs",
                .data           = &sysctl_hung_task_timeout_secs,
                .maxlen         = sizeof(unsigned long),
                .mode           = 0644,
-               .proc_handler   = &proc_dohung_task_timeout_secs,
-               .strategy       = &sysctl_intvec,
+               .proc_handler   = proc_dohung_task_timeout_secs,
        },
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "hung_task_warnings",
                .data           = &sysctl_hung_task_warnings,
                .maxlen         = sizeof(unsigned long),
                .mode           = 0644,
-               .proc_handler   = &proc_doulongvec_minmax,
-               .strategy       = &sysctl_intvec,
+               .proc_handler   = proc_doulongvec_minmax,
        },
 #endif
 #ifdef CONFIG_COMPAT
        {
-               .ctl_name       = KERN_COMPAT_LOG,
                .procname       = "compat-log",
                .data           = &compat_log,
                .maxlen         = sizeof (int),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec,
+               .proc_handler   = proc_dointvec,
        },
 #endif
 #ifdef CONFIG_RT_MUTEXES
        {
-               .ctl_name       = KERN_MAX_LOCK_DEPTH,
                .procname       = "max_lock_depth",
                .data           = &max_lock_depth,
                .maxlen         = sizeof(int),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec,
+               .proc_handler   = proc_dointvec,
        },
 #endif
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "poweroff_cmd",
                .data           = &poweroff_cmd,
                .maxlen         = POWEROFF_CMD_PATH_LEN,
                .mode           = 0644,
-               .proc_handler   = &proc_dostring,
-               .strategy       = &sysctl_string,
+               .proc_handler   = proc_dostring,
        },
 #ifdef CONFIG_KEYS
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "keys",
                .mode           = 0555,
                .child          = key_sysctls,
@@ -973,17 +873,15 @@ static struct ctl_table kern_table[] = {
 #endif
 #ifdef CONFIG_RCU_TORTURE_TEST
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "rcutorture_runnable",
                .data           = &rcutorture_runnable,
                .maxlen         = sizeof(int),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec,
+               .proc_handler   = proc_dointvec,
        },
 #endif
 #ifdef CONFIG_SLOW_WORK
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "slow-work",
                .mode           = 0555,
                .child          = slow_work_sysctls,
@@ -991,146 +889,127 @@ static struct ctl_table kern_table[] = {
 #endif
 #ifdef CONFIG_PERF_EVENTS
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "perf_event_paranoid",
                .data           = &sysctl_perf_event_paranoid,
                .maxlen         = sizeof(sysctl_perf_event_paranoid),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec,
+               .proc_handler   = proc_dointvec,
        },
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "perf_event_mlock_kb",
                .data           = &sysctl_perf_event_mlock,
                .maxlen         = sizeof(sysctl_perf_event_mlock),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec,
+               .proc_handler   = proc_dointvec,
        },
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "perf_event_max_sample_rate",
                .data           = &sysctl_perf_event_sample_rate,
                .maxlen         = sizeof(sysctl_perf_event_sample_rate),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec,
+               .proc_handler   = proc_dointvec,
        },
 #endif
 #ifdef CONFIG_KMEMCHECK
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "kmemcheck",
                .data           = &kmemcheck_enabled,
                .maxlen         = sizeof(int),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec,
+               .proc_handler   = proc_dointvec,
        },
 #endif
 #ifdef CONFIG_BLOCK
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "blk_iopoll",
                .data           = &blk_iopoll_enabled,
                .maxlen         = sizeof(int),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec,
+               .proc_handler   = proc_dointvec,
        },
 #endif
 /*
  * NOTE: do not add new entries to this table unless you have read
  * Documentation/sysctl/ctl_unnumbered.txt
  */
-       { .ctl_name = 0 }
+       { }
 };
 
 static struct ctl_table vm_table[] = {
        {
-               .ctl_name       = VM_OVERCOMMIT_MEMORY,
                .procname       = "overcommit_memory",
                .data           = &sysctl_overcommit_memory,
                .maxlen         = sizeof(sysctl_overcommit_memory),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec,
+               .proc_handler   = proc_dointvec,
        },
        {
-               .ctl_name       = VM_PANIC_ON_OOM,
                .procname       = "panic_on_oom",
                .data           = &sysctl_panic_on_oom,
                .maxlen         = sizeof(sysctl_panic_on_oom),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec,
+               .proc_handler   = proc_dointvec,
        },
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "oom_kill_allocating_task",
                .data           = &sysctl_oom_kill_allocating_task,
                .maxlen         = sizeof(sysctl_oom_kill_allocating_task),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec,
+               .proc_handler   = proc_dointvec,
        },
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "oom_dump_tasks",
                .data           = &sysctl_oom_dump_tasks,
                .maxlen         = sizeof(sysctl_oom_dump_tasks),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec,
+               .proc_handler   = proc_dointvec,
        },
        {
-               .ctl_name       = VM_OVERCOMMIT_RATIO,
                .procname       = "overcommit_ratio",
                .data           = &sysctl_overcommit_ratio,
                .maxlen         = sizeof(sysctl_overcommit_ratio),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec,
+               .proc_handler   = proc_dointvec,
        },
        {
-               .ctl_name       = VM_PAGE_CLUSTER,
                .procname       = "page-cluster", 
                .data           = &page_cluster,
                .maxlen         = sizeof(int),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec,
+               .proc_handler   = proc_dointvec,
        },
        {
-               .ctl_name       = VM_DIRTY_BACKGROUND,
                .procname       = "dirty_background_ratio",
                .data           = &dirty_background_ratio,
                .maxlen         = sizeof(dirty_background_ratio),
                .mode           = 0644,
-               .proc_handler   = &dirty_background_ratio_handler,
-               .strategy       = &sysctl_intvec,
+               .proc_handler   = dirty_background_ratio_handler,
                .extra1         = &zero,
                .extra2         = &one_hundred,
        },
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "dirty_background_bytes",
                .data           = &dirty_background_bytes,
                .maxlen         = sizeof(dirty_background_bytes),
                .mode           = 0644,
-               .proc_handler   = &dirty_background_bytes_handler,
-               .strategy       = &sysctl_intvec,
+               .proc_handler   = dirty_background_bytes_handler,
                .extra1         = &one_ul,
        },
        {
-               .ctl_name       = VM_DIRTY_RATIO,
                .procname       = "dirty_ratio",
                .data           = &vm_dirty_ratio,
                .maxlen         = sizeof(vm_dirty_ratio),
                .mode           = 0644,
-               .proc_handler   = &dirty_ratio_handler,
-               .strategy       = &sysctl_intvec,
+               .proc_handler   = dirty_ratio_handler,
                .extra1         = &zero,
                .extra2         = &one_hundred,
        },
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "dirty_bytes",
                .data           = &vm_dirty_bytes,
                .maxlen         = sizeof(vm_dirty_bytes),
                .mode           = 0644,
-               .proc_handler   = &dirty_bytes_handler,
-               .strategy       = &sysctl_intvec,
+               .proc_handler   = dirty_bytes_handler,
                .extra1         = &dirty_bytes_min,
        },
        {
@@ -1138,31 +1017,28 @@ static struct ctl_table vm_table[] = {
                .data           = &dirty_writeback_interval,
                .maxlen         = sizeof(dirty_writeback_interval),
                .mode           = 0644,
-               .proc_handler   = &dirty_writeback_centisecs_handler,
+               .proc_handler   = dirty_writeback_centisecs_handler,
        },
        {
                .procname       = "dirty_expire_centisecs",
                .data           = &dirty_expire_interval,
                .maxlen         = sizeof(dirty_expire_interval),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec,
+               .proc_handler   = proc_dointvec,
        },
        {
-               .ctl_name       = VM_NR_PDFLUSH_THREADS,
                .procname       = "nr_pdflush_threads",
                .data           = &nr_pdflush_threads,
                .maxlen         = sizeof nr_pdflush_threads,
                .mode           = 0444 /* read-only*/,
-               .proc_handler   = &proc_dointvec,
+               .proc_handler   = proc_dointvec,
        },
        {
-               .ctl_name       = VM_SWAPPINESS,
                .procname       = "swappiness",
                .data           = &vm_swappiness,
                .maxlen         = sizeof(vm_swappiness),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec_minmax,
-               .strategy       = &sysctl_intvec,
+               .proc_handler   = proc_dointvec_minmax,
                .extra1         = &zero,
                .extra2         = &one_hundred,
        },
@@ -1172,255 +1048,213 @@ static struct ctl_table vm_table[] = {
                .data           = NULL,
                .maxlen         = sizeof(unsigned long),
                .mode           = 0644,
-               .proc_handler   = &hugetlb_sysctl_handler,
+               .proc_handler   = hugetlb_sysctl_handler,
                .extra1         = (void *)&hugetlb_zero,
                .extra2         = (void *)&hugetlb_infinity,
         },
         {
-               .ctl_name       = VM_HUGETLB_GROUP,
                .procname       = "hugetlb_shm_group",
                .data           = &sysctl_hugetlb_shm_group,
                .maxlen         = sizeof(gid_t),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec,
+               .proc_handler   = proc_dointvec,
         },
         {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "hugepages_treat_as_movable",
                .data           = &hugepages_treat_as_movable,
                .maxlen         = sizeof(int),
                .mode           = 0644,
-               .proc_handler   = &hugetlb_treat_movable_handler,
+               .proc_handler   = hugetlb_treat_movable_handler,
        },
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "nr_overcommit_hugepages",
                .data           = NULL,
                .maxlen         = sizeof(unsigned long),
                .mode           = 0644,
-               .proc_handler   = &hugetlb_overcommit_handler,
+               .proc_handler   = hugetlb_overcommit_handler,
                .extra1         = (void *)&hugetlb_zero,
                .extra2         = (void *)&hugetlb_infinity,
        },
 #endif
        {
-               .ctl_name       = VM_LOWMEM_RESERVE_RATIO,
                .procname       = "lowmem_reserve_ratio",
                .data           = &sysctl_lowmem_reserve_ratio,
                .maxlen         = sizeof(sysctl_lowmem_reserve_ratio),
                .mode           = 0644,
-               .proc_handler   = &lowmem_reserve_ratio_sysctl_handler,
-               .strategy       = &sysctl_intvec,
+               .proc_handler   = lowmem_reserve_ratio_sysctl_handler,
        },
        {
-               .ctl_name       = VM_DROP_PAGECACHE,
                .procname       = "drop_caches",
                .data           = &sysctl_drop_caches,
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = drop_caches_sysctl_handler,
-               .strategy       = &sysctl_intvec,
        },
        {
-               .ctl_name       = VM_MIN_FREE_KBYTES,
                .procname       = "min_free_kbytes",
                .data           = &min_free_kbytes,
                .maxlen         = sizeof(min_free_kbytes),
                .mode           = 0644,
-               .proc_handler   = &min_free_kbytes_sysctl_handler,
-               .strategy       = &sysctl_intvec,
+               .proc_handler   = min_free_kbytes_sysctl_handler,
                .extra1         = &zero,
        },
        {
-               .ctl_name       = VM_PERCPU_PAGELIST_FRACTION,
                .procname       = "percpu_pagelist_fraction",
                .data           = &percpu_pagelist_fraction,
                .maxlen         = sizeof(percpu_pagelist_fraction),
                .mode           = 0644,
-               .proc_handler   = &percpu_pagelist_fraction_sysctl_handler,
-               .strategy       = &sysctl_intvec,
+               .proc_handler   = percpu_pagelist_fraction_sysctl_handler,
                .extra1         = &min_percpu_pagelist_fract,
        },
 #ifdef CONFIG_MMU
        {
-               .ctl_name       = VM_MAX_MAP_COUNT,
                .procname       = "max_map_count",
                .data           = &sysctl_max_map_count,
                .maxlen         = sizeof(sysctl_max_map_count),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec
+               .proc_handler   = proc_dointvec
        },
 #else
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "nr_trim_pages",
                .data           = &sysctl_nr_trim_pages,
                .maxlen         = sizeof(sysctl_nr_trim_pages),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec_minmax,
-               .strategy       = &sysctl_intvec,
+               .proc_handler   = proc_dointvec_minmax,
                .extra1         = &zero,
        },
 #endif
        {
-               .ctl_name       = VM_LAPTOP_MODE,
                .procname       = "laptop_mode",
                .data           = &laptop_mode,
                .maxlen         = sizeof(laptop_mode),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec_jiffies,
-               .strategy       = &sysctl_jiffies,
+               .proc_handler   = proc_dointvec_jiffies,
        },
        {
-               .ctl_name       = VM_BLOCK_DUMP,
                .procname       = "block_dump",
                .data           = &block_dump,
                .maxlen         = sizeof(block_dump),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec,
-               .strategy       = &sysctl_intvec,
+               .proc_handler   = proc_dointvec,
                .extra1         = &zero,
        },
        {
-               .ctl_name       = VM_VFS_CACHE_PRESSURE,
                .procname       = "vfs_cache_pressure",
                .data           = &sysctl_vfs_cache_pressure,
                .maxlen         = sizeof(sysctl_vfs_cache_pressure),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec,
-               .strategy       = &sysctl_intvec,
+               .proc_handler   = proc_dointvec,
                .extra1         = &zero,
        },
 #ifdef HAVE_ARCH_PICK_MMAP_LAYOUT
        {
-               .ctl_name       = VM_LEGACY_VA_LAYOUT,
                .procname       = "legacy_va_layout",
                .data           = &sysctl_legacy_va_layout,
                .maxlen         = sizeof(sysctl_legacy_va_layout),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec,
-               .strategy       = &sysctl_intvec,
+               .proc_handler   = proc_dointvec,
                .extra1         = &zero,
        },
 #endif
 #ifdef CONFIG_NUMA
        {
-               .ctl_name       = VM_ZONE_RECLAIM_MODE,
                .procname       = "zone_reclaim_mode",
                .data           = &zone_reclaim_mode,
                .maxlen         = sizeof(zone_reclaim_mode),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec,
-               .strategy       = &sysctl_intvec,
+               .proc_handler   = proc_dointvec,
                .extra1         = &zero,
        },
        {
-               .ctl_name       = VM_MIN_UNMAPPED,
                .procname       = "min_unmapped_ratio",
                .data           = &sysctl_min_unmapped_ratio,
                .maxlen         = sizeof(sysctl_min_unmapped_ratio),
                .mode           = 0644,
-               .proc_handler   = &sysctl_min_unmapped_ratio_sysctl_handler,
-               .strategy       = &sysctl_intvec,
+               .proc_handler   = sysctl_min_unmapped_ratio_sysctl_handler,
                .extra1         = &zero,
                .extra2         = &one_hundred,
        },
        {
-               .ctl_name       = VM_MIN_SLAB,
                .procname       = "min_slab_ratio",
                .data           = &sysctl_min_slab_ratio,
                .maxlen         = sizeof(sysctl_min_slab_ratio),
                .mode           = 0644,
-               .proc_handler   = &sysctl_min_slab_ratio_sysctl_handler,
-               .strategy       = &sysctl_intvec,
+               .proc_handler   = sysctl_min_slab_ratio_sysctl_handler,
                .extra1         = &zero,
                .extra2         = &one_hundred,
        },
 #endif
 #ifdef CONFIG_SMP
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "stat_interval",
                .data           = &sysctl_stat_interval,
                .maxlen         = sizeof(sysctl_stat_interval),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec_jiffies,
-               .strategy       = &sysctl_jiffies,
+               .proc_handler   = proc_dointvec_jiffies,
        },
 #endif
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "mmap_min_addr",
                .data           = &dac_mmap_min_addr,
                .maxlen         = sizeof(unsigned long),
                .mode           = 0644,
-               .proc_handler   = &mmap_min_addr_handler,
+               .proc_handler   = mmap_min_addr_handler,
        },
 #ifdef CONFIG_NUMA
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "numa_zonelist_order",
                .data           = &numa_zonelist_order,
                .maxlen         = NUMA_ZONELIST_ORDER_LEN,
                .mode           = 0644,
-               .proc_handler   = &numa_zonelist_order_handler,
-               .strategy       = &sysctl_string,
+               .proc_handler   = numa_zonelist_order_handler,
        },
 #endif
 #if (defined(CONFIG_X86_32) && !defined(CONFIG_UML))|| \
    (defined(CONFIG_SUPERH) && defined(CONFIG_VSYSCALL))
        {
-               .ctl_name       = VM_VDSO_ENABLED,
                .procname       = "vdso_enabled",
                .data           = &vdso_enabled,
                .maxlen         = sizeof(vdso_enabled),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec,
-               .strategy       = &sysctl_intvec,
+               .proc_handler   = proc_dointvec,
                .extra1         = &zero,
        },
 #endif
 #ifdef CONFIG_HIGHMEM
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "highmem_is_dirtyable",
                .data           = &vm_highmem_is_dirtyable,
                .maxlen         = sizeof(vm_highmem_is_dirtyable),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec_minmax,
-               .strategy       = &sysctl_intvec,
+               .proc_handler   = proc_dointvec_minmax,
                .extra1         = &zero,
                .extra2         = &one,
        },
 #endif
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "scan_unevictable_pages",
                .data           = &scan_unevictable_pages,
                .maxlen         = sizeof(scan_unevictable_pages),
                .mode           = 0644,
-               .proc_handler   = &scan_unevictable_handler,
+               .proc_handler   = scan_unevictable_handler,
        },
 #ifdef CONFIG_MEMORY_FAILURE
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "memory_failure_early_kill",
                .data           = &sysctl_memory_failure_early_kill,
                .maxlen         = sizeof(sysctl_memory_failure_early_kill),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec_minmax,
-               .strategy       = &sysctl_intvec,
+               .proc_handler   = proc_dointvec_minmax,
                .extra1         = &zero,
                .extra2         = &one,
        },
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "memory_failure_recovery",
                .data           = &sysctl_memory_failure_recovery,
                .maxlen         = sizeof(sysctl_memory_failure_recovery),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec_minmax,
-               .strategy       = &sysctl_intvec,
+               .proc_handler   = proc_dointvec_minmax,
                .extra1         = &zero,
                .extra2         = &one,
        },
@@ -1430,116 +1264,104 @@ static struct ctl_table vm_table[] = {
  * NOTE: do not add new entries to this table unless you have read
  * Documentation/sysctl/ctl_unnumbered.txt
  */
-       { .ctl_name = 0 }
+       { }
 };
 
 #if defined(CONFIG_BINFMT_MISC) || defined(CONFIG_BINFMT_MISC_MODULE)
 static struct ctl_table binfmt_misc_table[] = {
-       { .ctl_name = 0 }
+       { }
 };
 #endif
 
 static struct ctl_table fs_table[] = {
        {
-               .ctl_name       = FS_NRINODE,
                .procname       = "inode-nr",
                .data           = &inodes_stat,
                .maxlen         = 2*sizeof(int),
                .mode           = 0444,
-               .proc_handler   = &proc_dointvec,
+               .proc_handler   = proc_dointvec,
        },
        {
-               .ctl_name       = FS_STATINODE,
                .procname       = "inode-state",
                .data           = &inodes_stat,
                .maxlen         = 7*sizeof(int),
                .mode           = 0444,
-               .proc_handler   = &proc_dointvec,
+               .proc_handler   = proc_dointvec,
        },
        {
                .procname       = "file-nr",
                .data           = &files_stat,
                .maxlen         = 3*sizeof(int),
                .mode           = 0444,
-               .proc_handler   = &proc_nr_files,
+               .proc_handler   = proc_nr_files,
        },
        {
-               .ctl_name       = FS_MAXFILE,
                .procname       = "file-max",
                .data           = &files_stat.max_files,
                .maxlen         = sizeof(int),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec,
+               .proc_handler   = proc_dointvec,
        },
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "nr_open",
                .data           = &sysctl_nr_open,
                .maxlen         = sizeof(int),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec_minmax,
+               .proc_handler   = proc_dointvec_minmax,
                .extra1         = &sysctl_nr_open_min,
                .extra2         = &sysctl_nr_open_max,
        },
        {
-               .ctl_name       = FS_DENTRY,
                .procname       = "dentry-state",
                .data           = &dentry_stat,
                .maxlen         = 6*sizeof(int),
                .mode           = 0444,
-               .proc_handler   = &proc_dointvec,
+               .proc_handler   = proc_dointvec,
        },
        {
-               .ctl_name       = FS_OVERFLOWUID,
                .procname       = "overflowuid",
                .data           = &fs_overflowuid,
                .maxlen         = sizeof(int),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec_minmax,
-               .strategy       = &sysctl_intvec,
+               .proc_handler   = proc_dointvec_minmax,
                .extra1         = &minolduid,
                .extra2         = &maxolduid,
        },
        {
-               .ctl_name       = FS_OVERFLOWGID,
                .procname       = "overflowgid",
                .data           = &fs_overflowgid,
                .maxlen         = sizeof(int),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec_minmax,
-               .strategy       = &sysctl_intvec,
+               .proc_handler   = proc_dointvec_minmax,
                .extra1         = &minolduid,
                .extra2         = &maxolduid,
        },
 #ifdef CONFIG_FILE_LOCKING
        {
-               .ctl_name       = FS_LEASES,
                .procname       = "leases-enable",
                .data           = &leases_enable,
                .maxlen         = sizeof(int),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec,
+               .proc_handler   = proc_dointvec,
        },
 #endif
 #ifdef CONFIG_DNOTIFY
        {
-               .ctl_name       = FS_DIR_NOTIFY,
                .procname       = "dir-notify-enable",
                .data           = &dir_notify_enable,
                .maxlen         = sizeof(int),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec,
+               .proc_handler   = proc_dointvec,
        },
 #endif
 #ifdef CONFIG_MMU
 #ifdef CONFIG_FILE_LOCKING
        {
-               .ctl_name       = FS_LEASE_TIME,
                .procname       = "lease-break-time",
                .data           = &lease_break_time,
                .maxlen         = sizeof(int),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec,
+               .proc_handler   = proc_dointvec,
        },
 #endif
 #ifdef CONFIG_AIO
@@ -1548,19 +1370,18 @@ static struct ctl_table fs_table[] = {
                .data           = &aio_nr,
                .maxlen         = sizeof(aio_nr),
                .mode           = 0444,
-               .proc_handler   = &proc_doulongvec_minmax,
+               .proc_handler   = proc_doulongvec_minmax,
        },
        {
                .procname       = "aio-max-nr",
                .data           = &aio_max_nr,
                .maxlen         = sizeof(aio_max_nr),
                .mode           = 0644,
-               .proc_handler   = &proc_doulongvec_minmax,
+               .proc_handler   = proc_doulongvec_minmax,
        },
 #endif /* CONFIG_AIO */
 #ifdef CONFIG_INOTIFY_USER
        {
-               .ctl_name       = FS_INOTIFY,
                .procname       = "inotify",
                .mode           = 0555,
                .child          = inotify_table,
@@ -1575,19 +1396,16 @@ static struct ctl_table fs_table[] = {
 #endif
 #endif
        {
-               .ctl_name       = KERN_SETUID_DUMPABLE,
                .procname       = "suid_dumpable",
                .data           = &suid_dumpable,
                .maxlen         = sizeof(int),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec_minmax,
-               .strategy       = &sysctl_intvec,
+               .proc_handler   = proc_dointvec_minmax,
                .extra1         = &zero,
                .extra2         = &two,
        },
 #if defined(CONFIG_BINFMT_MISC) || defined(CONFIG_BINFMT_MISC_MODULE)
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "binfmt_misc",
                .mode           = 0555,
                .child          = binfmt_misc_table,
@@ -1597,13 +1415,12 @@ static struct ctl_table fs_table[] = {
  * NOTE: do not add new entries to this table unless you have read
  * Documentation/sysctl/ctl_unnumbered.txt
  */
-       { .ctl_name = 0 }
+       { }
 };
 
 static struct ctl_table debug_table[] = {
 #if defined(CONFIG_X86) || defined(CONFIG_PPC)
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "exception-trace",
                .data           = &show_unhandled_signals,
                .maxlen         = sizeof(int),
@@ -1611,11 +1428,11 @@ static struct ctl_table debug_table[] = {
                .proc_handler   = proc_dointvec
        },
 #endif
-       { .ctl_name = 0 }
+       { }
 };
 
 static struct ctl_table dev_table[] = {
-       { .ctl_name = 0 }
+       { }
 };
 
 static DEFINE_SPINLOCK(sysctl_lock);
@@ -1769,122 +1586,6 @@ void register_sysctl_root(struct ctl_table_root *root)
        spin_unlock(&sysctl_lock);
 }
 
-#ifdef CONFIG_SYSCTL_SYSCALL
-/* Perform the actual read/write of a sysctl table entry. */
-static int do_sysctl_strategy(struct ctl_table_root *root,
-                       struct ctl_table *table,
-                       void __user *oldval, size_t __user *oldlenp,
-                       void __user *newval, size_t newlen)
-{
-       int op = 0, rc;
-
-       if (oldval)
-               op |= MAY_READ;
-       if (newval)
-               op |= MAY_WRITE;
-       if (sysctl_perm(root, table, op))
-               return -EPERM;
-
-       if (table->strategy) {
-               rc = table->strategy(table, oldval, oldlenp, newval, newlen);
-               if (rc < 0)
-                       return rc;
-               if (rc > 0)
-                       return 0;
-       }
-
-       /* If there is no strategy routine, or if the strategy returns
-        * zero, proceed with automatic r/w */
-       if (table->data && table->maxlen) {
-               rc = sysctl_data(table, oldval, oldlenp, newval, newlen);
-               if (rc < 0)
-                       return rc;
-       }
-       return 0;
-}
-
-static int parse_table(int __user *name, int nlen,
-                      void __user *oldval, size_t __user *oldlenp,
-                      void __user *newval, size_t newlen,
-                      struct ctl_table_root *root,
-                      struct ctl_table *table)
-{
-       int n;
-repeat:
-       if (!nlen)
-               return -ENOTDIR;
-       if (get_user(n, name))
-               return -EFAULT;
-       for ( ; table->ctl_name || table->procname; table++) {
-               if (!table->ctl_name)
-                       continue;
-               if (n == table->ctl_name) {
-                       int error;
-                       if (table->child) {
-                               if (sysctl_perm(root, table, MAY_EXEC))
-                                       return -EPERM;
-                               name++;
-                               nlen--;
-                               table = table->child;
-                               goto repeat;
-                       }
-                       error = do_sysctl_strategy(root, table,
-                                                  oldval, oldlenp,
-                                                  newval, newlen);
-                       return error;
-               }
-       }
-       return -ENOTDIR;
-}
-
-int do_sysctl(int __user *name, int nlen, void __user *oldval, size_t __user *oldlenp,
-              void __user *newval, size_t newlen)
-{
-       struct ctl_table_header *head;
-       int error = -ENOTDIR;
-
-       if (nlen <= 0 || nlen >= CTL_MAXNAME)
-               return -ENOTDIR;
-       if (oldval) {
-               int old_len;
-               if (!oldlenp || get_user(old_len, oldlenp))
-                       return -EFAULT;
-       }
-
-       for (head = sysctl_head_next(NULL); head;
-                       head = sysctl_head_next(head)) {
-               error = parse_table(name, nlen, oldval, oldlenp, 
-                                       newval, newlen,
-                                       head->root, head->ctl_table);
-               if (error != -ENOTDIR) {
-                       sysctl_head_finish(head);
-                       break;
-               }
-       }
-       return error;
-}
-
-SYSCALL_DEFINE1(sysctl, struct __sysctl_args __user *, args)
-{
-       struct __sysctl_args tmp;
-       int error;
-
-       if (copy_from_user(&tmp, args, sizeof(tmp)))
-               return -EFAULT;
-
-       error = deprecated_sysctl_warning(&tmp);
-       if (error)
-               goto out;
-
-       lock_kernel();
-       error = do_sysctl(tmp.name, tmp.nlen, tmp.oldval, tmp.oldlenp,
-                         tmp.newval, tmp.newlen);
-       unlock_kernel();
-out:
-       return error;
-}
-#endif /* CONFIG_SYSCTL_SYSCALL */
-
 /*
  * sysctl_perm does NOT grant the superuser all rights automatically, because
  * some sysctl variables are readonly even to root.
@@ -1920,7 +1621,7 @@ int sysctl_perm(struct ctl_table_root *root, struct ctl_table *table, int op)
 
 static void sysctl_set_parent(struct ctl_table *parent, struct ctl_table *table)
 {
-       for (; table->ctl_name || table->procname; table++) {
+       for (; table->procname; table++) {
                table->parent = parent;
                if (table->child)
                        sysctl_set_parent(table, table->child);
@@ -1952,11 +1653,11 @@ static struct ctl_table *is_branch_in(struct ctl_table *branch,
                return NULL;
 
        /* ... and nothing else */
-       if (branch[1].procname || branch[1].ctl_name)
+       if (branch[1].procname)
                return NULL;
 
        /* table should contain subdirectory with the same name */
-       for (p = table; p->procname || p->ctl_name; p++) {
+       for (p = table; p->procname; p++) {
                if (!p->child)
                        continue;
                if (p->procname && strcmp(p->procname, s) == 0)
@@ -2001,9 +1702,6 @@ static void try_attach(struct ctl_table_header *p, struct ctl_table_header *q)
  *
  * The members of the &struct ctl_table structure are used as follows:
  *
- * ctl_name - This is the numeric sysctl value used by sysctl(2). The number
- *            must be unique within that level of sysctl
- *
  * procname - the name of the sysctl file under /proc/sys. Set to %NULL to not
  *            enter a sysctl file
  *
@@ -2018,8 +1716,6 @@ static void try_attach(struct ctl_table_header *p, struct ctl_table_header *q)
  *
  * proc_handler - the text handler routine (described below)
  *
- * strategy - the strategy routine (described below)
- *
  * de - for internal use by the sysctl routines
  *
  * extra1, extra2 - extra pointers usable by the proc handler routines
@@ -2032,19 +1728,6 @@ static void try_attach(struct ctl_table_header *p, struct ctl_table_header *q)
  * struct enable minimal validation of the values being written to be
  * performed, and the mode field allows minimal authentication.
  *
- * More sophisticated management can be enabled by the provision of a
- * strategy routine with the table entry.  This will be called before
- * any automatic read or write of the data is performed.
- *
- * The strategy routine may return
- *
- * < 0 - Error occurred (error is passed to user process)
- *
- * 0   - OK - proceed with automatic read or write.
- *
- * > 0 - OK - read or write has been done by the strategy routine, so
- *       return immediately.
- *
  * There must be a proc_handler routine for any terminal nodes
  * mirrored under /proc/sys (non-terminals are handled by a built-in
  * directory handler).  Several default handlers are available to
@@ -2071,13 +1754,13 @@ struct ctl_table_header *__register_sysctl_paths(
        struct ctl_table_set *set;
 
        /* Count the path components */
-       for (npath = 0; path[npath].ctl_name || path[npath].procname; ++npath)
+       for (npath = 0; path[npath].procname; ++npath)
                ;
 
        /*
         * For each path component, allocate a 2-element ctl_table array.
         * The first array element will be filled with the sysctl entry
-        * for this, the second will be the sentinel (ctl_name == 0).
+        * for this, the second will be the sentinel (procname == 0).
         *
         * We allocate everything in one go so that we don't have to
         * worry about freeing additional memory in unregister_sysctl_table.
@@ -2094,7 +1777,6 @@ struct ctl_table_header *__register_sysctl_paths(
        for (n = 0; n < npath; ++n, ++path) {
                /* Copy the procname */
                new->procname = path->procname;
-               new->ctl_name = path->ctl_name;
                new->mode     = 0555;
 
                *prevp = new;
@@ -2956,286 +2638,6 @@ int proc_doulongvec_ms_jiffies_minmax(struct ctl_table *table, int write,
 
 #endif /* CONFIG_PROC_FS */
 
-
-#ifdef CONFIG_SYSCTL_SYSCALL
-/*
- * General sysctl support routines 
- */
-
-/* The generic sysctl data routine (used if no strategy routine supplied) */
-int sysctl_data(struct ctl_table *table,
-               void __user *oldval, size_t __user *oldlenp,
-               void __user *newval, size_t newlen)
-{
-       size_t len;
-
-       /* Get out of I don't have a variable */
-       if (!table->data || !table->maxlen)
-               return -ENOTDIR;
-
-       if (oldval && oldlenp) {
-               if (get_user(len, oldlenp))
-                       return -EFAULT;
-               if (len) {
-                       if (len > table->maxlen)
-                               len = table->maxlen;
-                       if (copy_to_user(oldval, table->data, len))
-                               return -EFAULT;
-                       if (put_user(len, oldlenp))
-                               return -EFAULT;
-               }
-       }
-
-       if (newval && newlen) {
-               if (newlen > table->maxlen)
-                       newlen = table->maxlen;
-
-               if (copy_from_user(table->data, newval, newlen))
-                       return -EFAULT;
-       }
-       return 1;
-}
-
-/* The generic string strategy routine: */
-int sysctl_string(struct ctl_table *table,
-                 void __user *oldval, size_t __user *oldlenp,
-                 void __user *newval, size_t newlen)
-{
-       if (!table->data || !table->maxlen) 
-               return -ENOTDIR;
-       
-       if (oldval && oldlenp) {
-               size_t bufsize;
-               if (get_user(bufsize, oldlenp))
-                       return -EFAULT;
-               if (bufsize) {
-                       size_t len = strlen(table->data), copied;
-
-                       /* This shouldn't trigger for a well-formed sysctl */
-                       if (len > table->maxlen)
-                               len = table->maxlen;
-
-                       /* Copy up to a max of bufsize-1 bytes of the string */
-                       copied = (len >= bufsize) ? bufsize - 1 : len;
-
-                       if (copy_to_user(oldval, table->data, copied) ||
-                           put_user(0, (char __user *)(oldval + copied)))
-                               return -EFAULT;
-                       if (put_user(len, oldlenp))
-                               return -EFAULT;
-               }
-       }
-       if (newval && newlen) {
-               size_t len = newlen;
-               if (len > table->maxlen)
-                       len = table->maxlen;
-               if(copy_from_user(table->data, newval, len))
-                       return -EFAULT;
-               if (len == table->maxlen)
-                       len--;
-               ((char *) table->data)[len] = 0;
-       }
-       return 1;
-}
-
-/*
- * This function makes sure that all of the integers in the vector
- * are between the minimum and maximum values given in the arrays
- * table->extra1 and table->extra2, respectively.
- */
-int sysctl_intvec(struct ctl_table *table,
-               void __user *oldval, size_t __user *oldlenp,
-               void __user *newval, size_t newlen)
-{
-
-       if (newval && newlen) {
-               int __user *vec = (int __user *) newval;
-               int *min = (int *) table->extra1;
-               int *max = (int *) table->extra2;
-               size_t length;
-               int i;
-
-               if (newlen % sizeof(int) != 0)
-                       return -EINVAL;
-
-               if (!table->extra1 && !table->extra2)
-                       return 0;
-
-               if (newlen > table->maxlen)
-                       newlen = table->maxlen;
-               length = newlen / sizeof(int);
-
-               for (i = 0; i < length; i++) {
-                       int value;
-                       if (get_user(value, vec + i))
-                               return -EFAULT;
-                       if (min && value < min[i])
-                               return -EINVAL;
-                       if (max && value > max[i])
-                               return -EINVAL;
-               }
-       }
-       return 0;
-}
-
-/* Strategy function to convert jiffies to seconds */ 
-int sysctl_jiffies(struct ctl_table *table,
-               void __user *oldval, size_t __user *oldlenp,
-               void __user *newval, size_t newlen)
-{
-       if (oldval && oldlenp) {
-               size_t olen;
-
-               if (get_user(olen, oldlenp))
-                       return -EFAULT;
-               if (olen) {
-                       int val;
-
-                       if (olen < sizeof(int))
-                               return -EINVAL;
-
-                       val = *(int *)(table->data) / HZ;
-                       if (put_user(val, (int __user *)oldval))
-                               return -EFAULT;
-                       if (put_user(sizeof(int), oldlenp))
-                               return -EFAULT;
-               }
-       }
-       if (newval && newlen) { 
-               int new;
-               if (newlen != sizeof(int))
-                       return -EINVAL; 
-               if (get_user(new, (int __user *)newval))
-                       return -EFAULT;
-               *(int *)(table->data) = new*HZ; 
-       }
-       return 1;
-}
-
-/* Strategy function to convert jiffies to seconds */ 
-int sysctl_ms_jiffies(struct ctl_table *table,
-               void __user *oldval, size_t __user *oldlenp,
-               void __user *newval, size_t newlen)
-{
-       if (oldval && oldlenp) {
-               size_t olen;
-
-               if (get_user(olen, oldlenp))
-                       return -EFAULT;
-               if (olen) {
-                       int val;
-
-                       if (olen < sizeof(int))
-                               return -EINVAL;
-
-                       val = jiffies_to_msecs(*(int *)(table->data));
-                       if (put_user(val, (int __user *)oldval))
-                               return -EFAULT;
-                       if (put_user(sizeof(int), oldlenp))
-                               return -EFAULT;
-               }
-       }
-       if (newval && newlen) { 
-               int new;
-               if (newlen != sizeof(int))
-                       return -EINVAL; 
-               if (get_user(new, (int __user *)newval))
-                       return -EFAULT;
-               *(int *)(table->data) = msecs_to_jiffies(new);
-       }
-       return 1;
-}
-
-
-
-#else /* CONFIG_SYSCTL_SYSCALL */
-
-
-SYSCALL_DEFINE1(sysctl, struct __sysctl_args __user *, args)
-{
-       struct __sysctl_args tmp;
-       int error;
-
-       if (copy_from_user(&tmp, args, sizeof(tmp)))
-               return -EFAULT;
-
-       error = deprecated_sysctl_warning(&tmp);
-
-       /* If no error reading the parameters then just -ENOSYS ... */
-       if (!error)
-               error = -ENOSYS;
-
-       return error;
-}
-
-int sysctl_data(struct ctl_table *table,
-                 void __user *oldval, size_t __user *oldlenp,
-                 void __user *newval, size_t newlen)
-{
-       return -ENOSYS;
-}
-
-int sysctl_string(struct ctl_table *table,
-                 void __user *oldval, size_t __user *oldlenp,
-                 void __user *newval, size_t newlen)
-{
-       return -ENOSYS;
-}
-
-int sysctl_intvec(struct ctl_table *table,
-               void __user *oldval, size_t __user *oldlenp,
-               void __user *newval, size_t newlen)
-{
-       return -ENOSYS;
-}
-
-int sysctl_jiffies(struct ctl_table *table,
-               void __user *oldval, size_t __user *oldlenp,
-               void __user *newval, size_t newlen)
-{
-       return -ENOSYS;
-}
-
-int sysctl_ms_jiffies(struct ctl_table *table,
-               void __user *oldval, size_t __user *oldlenp,
-               void __user *newval, size_t newlen)
-{
-       return -ENOSYS;
-}
-
-#endif /* CONFIG_SYSCTL_SYSCALL */
-
-static int deprecated_sysctl_warning(struct __sysctl_args *args)
-{
-       static int msg_count;
-       int name[CTL_MAXNAME];
-       int i;
-
-       /* Check args->nlen. */
-       if (args->nlen < 0 || args->nlen > CTL_MAXNAME)
-               return -ENOTDIR;
-
-       /* Read in the sysctl name for better debug message logging */
-       for (i = 0; i < args->nlen; i++)
-               if (get_user(name[i], args->name + i))
-                       return -EFAULT;
-
-       /* Ignore accesses to kernel.version */
-       if ((args->nlen == 2) && (name[0] == CTL_KERN) && (name[1] == KERN_VERSION))
-               return 0;
-
-       if (msg_count < 5) {
-               msg_count++;
-               printk(KERN_INFO
-                       "warning: process `%s' used the deprecated sysctl "
-                       "system call with ", current->comm);
-               for (i = 0; i < args->nlen; i++)
-                       printk("%d.", name[i]);
-               printk("\n");
-       }
-       return 0;
-}
-
 /*
  * No sense putting this after each symbol definition, twice,
  * exception granted :-)
@@ -3250,9 +2652,4 @@ EXPORT_SYMBOL(proc_doulongvec_minmax);
 EXPORT_SYMBOL(proc_doulongvec_ms_jiffies_minmax);
 EXPORT_SYMBOL(register_sysctl_table);
 EXPORT_SYMBOL(register_sysctl_paths);
-EXPORT_SYMBOL(sysctl_intvec);
-EXPORT_SYMBOL(sysctl_jiffies);
-EXPORT_SYMBOL(sysctl_ms_jiffies);
-EXPORT_SYMBOL(sysctl_string);
-EXPORT_SYMBOL(sysctl_data);
 EXPORT_SYMBOL(unregister_sysctl_table);
diff --git a/kernel/sysctl_binary.c b/kernel/sysctl_binary.c
new file mode 100644 (file)
index 0000000..b75dbf4
--- /dev/null
@@ -0,0 +1,1507 @@
+#include <linux/stat.h>
+#include <linux/sysctl.h>
+#include "../fs/xfs/linux-2.6/xfs_sysctl.h"
+#include <linux/sunrpc/debug.h>
+#include <linux/string.h>
+#include <net/ip_vs.h>
+#include <linux/syscalls.h>
+#include <linux/namei.h>
+#include <linux/mount.h>
+#include <linux/fs.h>
+#include <linux/nsproxy.h>
+#include <linux/pid_namespace.h>
+#include <linux/file.h>
+#include <linux/ctype.h>
+#include <linux/netdevice.h>
+
+#ifdef CONFIG_SYSCTL_SYSCALL
+
+struct bin_table;
+typedef ssize_t bin_convert_t(struct file *file,
+       void __user *oldval, size_t oldlen, void __user *newval, size_t newlen);
+
+static bin_convert_t bin_dir;
+static bin_convert_t bin_string;
+static bin_convert_t bin_intvec;
+static bin_convert_t bin_ulongvec;
+static bin_convert_t bin_uuid;
+static bin_convert_t bin_dn_node_address;
+
+#define CTL_DIR   bin_dir
+#define CTL_STR   bin_string
+#define CTL_INT   bin_intvec
+#define CTL_ULONG bin_ulongvec
+#define CTL_UUID  bin_uuid
+#define CTL_DNADR bin_dn_node_address
+
+#define BUFSZ 256
+
+struct bin_table {
+       bin_convert_t           *convert;
+       int                     ctl_name;
+       const char              *procname;
+       const struct bin_table  *child;
+};
+
+static const struct bin_table bin_random_table[] = {
+       { CTL_INT,      RANDOM_POOLSIZE,        "poolsize" },
+       { CTL_INT,      RANDOM_ENTROPY_COUNT,   "entropy_avail" },
+       { CTL_INT,      RANDOM_READ_THRESH,     "read_wakeup_threshold" },
+       { CTL_INT,      RANDOM_WRITE_THRESH,    "write_wakeup_threshold" },
+       { CTL_UUID,     RANDOM_BOOT_ID,         "boot_id" },
+       { CTL_UUID,     RANDOM_UUID,            "uuid" },
+       {}
+};
+
+static const struct bin_table bin_pty_table[] = {
+       { CTL_INT,      PTY_MAX,        "max" },
+       { CTL_INT,      PTY_NR,         "nr" },
+       {}
+};
+
+static const struct bin_table bin_kern_table[] = {
+       { CTL_STR,      KERN_OSTYPE,                    "ostype" },
+       { CTL_STR,      KERN_OSRELEASE,                 "osrelease" },
+       /* KERN_OSREV not used */
+       { CTL_STR,      KERN_VERSION,                   "version" },
+       /* KERN_SECUREMASK not used */
+       /* KERN_PROF not used */
+       { CTL_STR,      KERN_NODENAME,                  "hostname" },
+       { CTL_STR,      KERN_DOMAINNAME,                "domainname" },
+
+       { CTL_INT,      KERN_PANIC,                     "panic" },
+       { CTL_INT,      KERN_REALROOTDEV,               "real-root-dev" },
+
+       { CTL_STR,      KERN_SPARC_REBOOT,              "reboot-cmd" },
+       { CTL_INT,      KERN_CTLALTDEL,                 "ctrl-alt-del" },
+       { CTL_INT,      KERN_PRINTK,                    "printk" },
+
+       /* KERN_NAMETRANS not used */
+       /* KERN_PPC_HTABRECLAIM not used */
+       /* KERN_PPC_ZEROPAGED not used */
+       { CTL_INT,      KERN_PPC_POWERSAVE_NAP,         "powersave-nap" },
+
+       { CTL_STR,      KERN_MODPROBE,                  "modprobe" },
+       { CTL_INT,      KERN_SG_BIG_BUFF,               "sg-big-buff" },
+       { CTL_INT,      KERN_ACCT,                      "acct" },
+       /* KERN_PPC_L2CR "l2cr" no longer used */
+
+       /* KERN_RTSIGNR not used */
+       /* KERN_RTSIGMAX not used */
+
+       { CTL_ULONG,    KERN_SHMMAX,                    "shmmax" },
+       { CTL_INT,      KERN_MSGMAX,                    "msgmax" },
+       { CTL_INT,      KERN_MSGMNB,                    "msgmnb" },
+       /* KERN_MSGPOOL not used*/
+       { CTL_INT,      KERN_SYSRQ,                     "sysrq" },
+       { CTL_INT,      KERN_MAX_THREADS,               "threads-max" },
+       { CTL_DIR,      KERN_RANDOM,                    "random",       bin_random_table },
+       { CTL_ULONG,    KERN_SHMALL,                    "shmall" },
+       { CTL_INT,      KERN_MSGMNI,                    "msgmni" },
+       { CTL_INT,      KERN_SEM,                       "sem" },
+       { CTL_INT,      KERN_SPARC_STOP_A,              "stop-a" },
+       { CTL_INT,      KERN_SHMMNI,                    "shmmni" },
+
+       { CTL_INT,      KERN_OVERFLOWUID,               "overflowuid" },
+       { CTL_INT,      KERN_OVERFLOWGID,               "overflowgid" },
+
+       { CTL_STR,      KERN_HOTPLUG,                   "hotplug", },
+       { CTL_INT,      KERN_IEEE_EMULATION_WARNINGS,   "ieee_emulation_warnings" },
+
+       { CTL_INT,      KERN_S390_USER_DEBUG_LOGGING,   "userprocess_debug" },
+       { CTL_INT,      KERN_CORE_USES_PID,             "core_uses_pid" },
+       /* KERN_TAINTED "tainted" no longer used */
+       { CTL_INT,      KERN_CADPID,                    "cad_pid" },
+       { CTL_INT,      KERN_PIDMAX,                    "pid_max" },
+       { CTL_STR,      KERN_CORE_PATTERN,              "core_pattern" },
+       { CTL_INT,      KERN_PANIC_ON_OOPS,             "panic_on_oops" },
+       { CTL_INT,      KERN_HPPA_PWRSW,                "soft-power" },
+       { CTL_INT,      KERN_HPPA_UNALIGNED,            "unaligned-trap" },
+
+       { CTL_INT,      KERN_PRINTK_RATELIMIT,          "printk_ratelimit" },
+       { CTL_INT,      KERN_PRINTK_RATELIMIT_BURST,    "printk_ratelimit_burst" },
+
+       { CTL_DIR,      KERN_PTY,                       "pty",          bin_pty_table },
+       { CTL_INT,      KERN_NGROUPS_MAX,               "ngroups_max" },
+       { CTL_INT,      KERN_SPARC_SCONS_PWROFF,        "scons-poweroff" },
+       /* KERN_HZ_TIMER "hz_timer" no longer used */
+       { CTL_INT,      KERN_UNKNOWN_NMI_PANIC,         "unknown_nmi_panic" },
+       { CTL_INT,      KERN_BOOTLOADER_TYPE,           "bootloader_type" },
+       { CTL_INT,      KERN_RANDOMIZE,                 "randomize_va_space" },
+
+       { CTL_INT,      KERN_SPIN_RETRY,                "spin_retry" },
+       /* KERN_ACPI_VIDEO_FLAGS "acpi_video_flags" no longer used */
+       { CTL_INT,      KERN_IA64_UNALIGNED,            "ignore-unaligned-usertrap" },
+       { CTL_INT,      KERN_COMPAT_LOG,                "compat-log" },
+       { CTL_INT,      KERN_MAX_LOCK_DEPTH,            "max_lock_depth" },
+       { CTL_INT,      KERN_NMI_WATCHDOG,              "nmi_watchdog" },
+       { CTL_INT,      KERN_PANIC_ON_NMI,              "panic_on_unrecovered_nmi" },
+       {}
+};
+
+static const struct bin_table bin_vm_table[] = {
+       { CTL_INT,      VM_OVERCOMMIT_MEMORY,           "overcommit_memory" },
+       { CTL_INT,      VM_PAGE_CLUSTER,                "page-cluster" },
+       { CTL_INT,      VM_DIRTY_BACKGROUND,            "dirty_background_ratio" },
+       { CTL_INT,      VM_DIRTY_RATIO,                 "dirty_ratio" },
+       /* VM_DIRTY_WB_CS "dirty_writeback_centisecs" no longer used */
+       /* VM_DIRTY_EXPIRE_CS "dirty_expire_centisecs" no longer used */
+       { CTL_INT,      VM_NR_PDFLUSH_THREADS,          "nr_pdflush_threads" },
+       { CTL_INT,      VM_OVERCOMMIT_RATIO,            "overcommit_ratio" },
+       /* VM_PAGEBUF unused */
+       /* VM_HUGETLB_PAGES "nr_hugepages" no longer used */
+       { CTL_INT,      VM_SWAPPINESS,                  "swappiness" },
+       { CTL_INT,      VM_LOWMEM_RESERVE_RATIO,        "lowmem_reserve_ratio" },
+       { CTL_INT,      VM_MIN_FREE_KBYTES,             "min_free_kbytes" },
+       { CTL_INT,      VM_MAX_MAP_COUNT,               "max_map_count" },
+       { CTL_INT,      VM_LAPTOP_MODE,                 "laptop_mode" },
+       { CTL_INT,      VM_BLOCK_DUMP,                  "block_dump" },
+       { CTL_INT,      VM_HUGETLB_GROUP,               "hugetlb_shm_group" },
+       { CTL_INT,      VM_VFS_CACHE_PRESSURE,  "vfs_cache_pressure" },
+       { CTL_INT,      VM_LEGACY_VA_LAYOUT,            "legacy_va_layout" },
+       /* VM_SWAP_TOKEN_TIMEOUT unused */
+       { CTL_INT,      VM_DROP_PAGECACHE,              "drop_caches" },
+       { CTL_INT,      VM_PERCPU_PAGELIST_FRACTION,    "percpu_pagelist_fraction" },
+       { CTL_INT,      VM_ZONE_RECLAIM_MODE,           "zone_reclaim_mode" },
+       { CTL_INT,      VM_MIN_UNMAPPED,                "min_unmapped_ratio" },
+       { CTL_INT,      VM_PANIC_ON_OOM,                "panic_on_oom" },
+       { CTL_INT,      VM_VDSO_ENABLED,                "vdso_enabled" },
+       { CTL_INT,      VM_MIN_SLAB,                    "min_slab_ratio" },
+
+       {}
+};
+
+static const struct bin_table bin_net_core_table[] = {
+       { CTL_INT,      NET_CORE_WMEM_MAX,      "wmem_max" },
+       { CTL_INT,      NET_CORE_RMEM_MAX,      "rmem_max" },
+       { CTL_INT,      NET_CORE_WMEM_DEFAULT,  "wmem_default" },
+       { CTL_INT,      NET_CORE_RMEM_DEFAULT,  "rmem_default" },
+       /* NET_CORE_DESTROY_DELAY unused */
+       { CTL_INT,      NET_CORE_MAX_BACKLOG,   "netdev_max_backlog" },
+       /* NET_CORE_FASTROUTE unused */
+       { CTL_INT,      NET_CORE_MSG_COST,      "message_cost" },
+       { CTL_INT,      NET_CORE_MSG_BURST,     "message_burst" },
+       { CTL_INT,      NET_CORE_OPTMEM_MAX,    "optmem_max" },
+       /* NET_CORE_HOT_LIST_LENGTH unused */
+       /* NET_CORE_DIVERT_VERSION unused */
+       /* NET_CORE_NO_CONG_THRESH unused */
+       /* NET_CORE_NO_CONG unused */
+       /* NET_CORE_LO_CONG unused */
+       /* NET_CORE_MOD_CONG unused */
+       { CTL_INT,      NET_CORE_DEV_WEIGHT,    "dev_weight" },
+       { CTL_INT,      NET_CORE_SOMAXCONN,     "somaxconn" },
+       { CTL_INT,      NET_CORE_BUDGET,        "netdev_budget" },
+       { CTL_INT,      NET_CORE_AEVENT_ETIME,  "xfrm_aevent_etime" },
+       { CTL_INT,      NET_CORE_AEVENT_RSEQTH, "xfrm_aevent_rseqth" },
+       { CTL_INT,      NET_CORE_WARNINGS,      "warnings" },
+       {},
+};
+
+static const struct bin_table bin_net_unix_table[] = {
+       /* NET_UNIX_DESTROY_DELAY unused */
+       /* NET_UNIX_DELETE_DELAY unused */
+       { CTL_INT,      NET_UNIX_MAX_DGRAM_QLEN,        "max_dgram_qlen" },
+       {}
+};
+
+static const struct bin_table bin_net_ipv4_route_table[] = {
+       { CTL_INT,      NET_IPV4_ROUTE_FLUSH,                   "flush" },
+       /* NET_IPV4_ROUTE_MIN_DELAY "min_delay" no longer used */
+       /* NET_IPV4_ROUTE_MAX_DELAY "max_delay" no longer used */
+       { CTL_INT,      NET_IPV4_ROUTE_GC_THRESH,               "gc_thresh" },
+       { CTL_INT,      NET_IPV4_ROUTE_MAX_SIZE,                "max_size" },
+       { CTL_INT,      NET_IPV4_ROUTE_GC_MIN_INTERVAL,         "gc_min_interval" },
+       { CTL_INT,      NET_IPV4_ROUTE_GC_MIN_INTERVAL_MS,      "gc_min_interval_ms" },
+       { CTL_INT,      NET_IPV4_ROUTE_GC_TIMEOUT,              "gc_timeout" },
+       { CTL_INT,      NET_IPV4_ROUTE_GC_INTERVAL,             "gc_interval" },
+       { CTL_INT,      NET_IPV4_ROUTE_REDIRECT_LOAD,           "redirect_load" },
+       { CTL_INT,      NET_IPV4_ROUTE_REDIRECT_NUMBER,         "redirect_number" },
+       { CTL_INT,      NET_IPV4_ROUTE_REDIRECT_SILENCE,        "redirect_silence" },
+       { CTL_INT,      NET_IPV4_ROUTE_ERROR_COST,              "error_cost" },
+       { CTL_INT,      NET_IPV4_ROUTE_ERROR_BURST,             "error_burst" },
+       { CTL_INT,      NET_IPV4_ROUTE_GC_ELASTICITY,           "gc_elasticity" },
+       { CTL_INT,      NET_IPV4_ROUTE_MTU_EXPIRES,             "mtu_expires" },
+       { CTL_INT,      NET_IPV4_ROUTE_MIN_PMTU,                "min_pmtu" },
+       { CTL_INT,      NET_IPV4_ROUTE_MIN_ADVMSS,              "min_adv_mss" },
+       { CTL_INT,      NET_IPV4_ROUTE_SECRET_INTERVAL,         "secret_interval" },
+       {}
+};
+
+static const struct bin_table bin_net_ipv4_conf_vars_table[] = {
+       { CTL_INT,      NET_IPV4_CONF_FORWARDING,               "forwarding" },
+       { CTL_INT,      NET_IPV4_CONF_MC_FORWARDING,            "mc_forwarding" },
+
+       { CTL_INT,      NET_IPV4_CONF_ACCEPT_REDIRECTS,         "accept_redirects" },
+       { CTL_INT,      NET_IPV4_CONF_SECURE_REDIRECTS,         "secure_redirects" },
+       { CTL_INT,      NET_IPV4_CONF_SEND_REDIRECTS,           "send_redirects" },
+       { CTL_INT,      NET_IPV4_CONF_SHARED_MEDIA,             "shared_media" },
+       { CTL_INT,      NET_IPV4_CONF_RP_FILTER,                "rp_filter" },
+       { CTL_INT,      NET_IPV4_CONF_ACCEPT_SOURCE_ROUTE,      "accept_source_route" },
+       { CTL_INT,      NET_IPV4_CONF_PROXY_ARP,                "proxy_arp" },
+       { CTL_INT,      NET_IPV4_CONF_MEDIUM_ID,                "medium_id" },
+       { CTL_INT,      NET_IPV4_CONF_BOOTP_RELAY,              "bootp_relay" },
+       { CTL_INT,      NET_IPV4_CONF_LOG_MARTIANS,             "log_martians" },
+       { CTL_INT,      NET_IPV4_CONF_TAG,                      "tag" },
+       { CTL_INT,      NET_IPV4_CONF_ARPFILTER,                "arp_filter" },
+       { CTL_INT,      NET_IPV4_CONF_ARP_ANNOUNCE,             "arp_announce" },
+       { CTL_INT,      NET_IPV4_CONF_ARP_IGNORE,               "arp_ignore" },
+       { CTL_INT,      NET_IPV4_CONF_ARP_ACCEPT,               "arp_accept" },
+       { CTL_INT,      NET_IPV4_CONF_ARP_NOTIFY,               "arp_notify" },
+
+       { CTL_INT,      NET_IPV4_CONF_NOXFRM,                   "disable_xfrm" },
+       { CTL_INT,      NET_IPV4_CONF_NOPOLICY,                 "disable_policy" },
+       { CTL_INT,      NET_IPV4_CONF_FORCE_IGMP_VERSION,       "force_igmp_version" },
+       { CTL_INT,      NET_IPV4_CONF_PROMOTE_SECONDARIES,      "promote_secondaries" },
+       {}
+};
+
+static const struct bin_table bin_net_ipv4_conf_table[] = {
+       { CTL_DIR,      NET_PROTO_CONF_ALL,     "all",          bin_net_ipv4_conf_vars_table },
+       { CTL_DIR,      NET_PROTO_CONF_DEFAULT, "default",      bin_net_ipv4_conf_vars_table },
+       { CTL_DIR,      0, NULL, bin_net_ipv4_conf_vars_table },
+       {}
+};
+
+static const struct bin_table bin_net_neigh_vars_table[] = {
+       { CTL_INT,      NET_NEIGH_MCAST_SOLICIT,        "mcast_solicit" },
+       { CTL_INT,      NET_NEIGH_UCAST_SOLICIT,        "ucast_solicit" },
+       { CTL_INT,      NET_NEIGH_APP_SOLICIT,          "app_solicit" },
+       /* NET_NEIGH_RETRANS_TIME "retrans_time" no longer used */
+       { CTL_INT,      NET_NEIGH_REACHABLE_TIME,       "base_reachable_time" },
+       { CTL_INT,      NET_NEIGH_DELAY_PROBE_TIME,     "delay_first_probe_time" },
+       { CTL_INT,      NET_NEIGH_GC_STALE_TIME,        "gc_stale_time" },
+       { CTL_INT,      NET_NEIGH_UNRES_QLEN,           "unres_qlen" },
+       { CTL_INT,      NET_NEIGH_PROXY_QLEN,           "proxy_qlen" },
+       /* NET_NEIGH_ANYCAST_DELAY "anycast_delay" no longer used */
+       /* NET_NEIGH_PROXY_DELAY "proxy_delay" no longer used */
+       /* NET_NEIGH_LOCKTIME "locktime" no longer used */
+       { CTL_INT,      NET_NEIGH_GC_INTERVAL,          "gc_interval" },
+       { CTL_INT,      NET_NEIGH_GC_THRESH1,           "gc_thresh1" },
+       { CTL_INT,      NET_NEIGH_GC_THRESH2,           "gc_thresh2" },
+       { CTL_INT,      NET_NEIGH_GC_THRESH3,           "gc_thresh3" },
+       { CTL_INT,      NET_NEIGH_RETRANS_TIME_MS,      "retrans_time_ms" },
+       { CTL_INT,      NET_NEIGH_REACHABLE_TIME_MS,    "base_reachable_time_ms" },
+       {}
+};
+
+static const struct bin_table bin_net_neigh_table[] = {
+       { CTL_DIR,      NET_PROTO_CONF_DEFAULT, "default", bin_net_neigh_vars_table },
+       { CTL_DIR,      0, NULL, bin_net_neigh_vars_table },
+       {}
+};
+
+static const struct bin_table bin_net_ipv4_netfilter_table[] = {
+       { CTL_INT,      NET_IPV4_NF_CONNTRACK_MAX,              "ip_conntrack_max" },
+
+       /* NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_SYN_SENT "ip_conntrack_tcp_timeout_syn_sent" no longer used */
+       /* NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_SYN_RECV "ip_conntrack_tcp_timeout_syn_recv" no longer used */
+       /* NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_ESTABLISHED "ip_conntrack_tcp_timeout_established" no longer used */
+       /* NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_FIN_WAIT "ip_conntrack_tcp_timeout_fin_wait" no longer used */
+       /* NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_CLOSE_WAIT "ip_conntrack_tcp_timeout_close_wait" no longer used */
+       /* NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_LAST_ACK "ip_conntrack_tcp_timeout_last_ack" no longer used */
+       /* NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_TIME_WAIT "ip_conntrack_tcp_timeout_time_wait" no longer used */
+       /* NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_CLOSE "ip_conntrack_tcp_timeout_close" no longer used */
+
+       /* NET_IPV4_NF_CONNTRACK_UDP_TIMEOUT "ip_conntrack_udp_timeout" no longer used */
+       /* NET_IPV4_NF_CONNTRACK_UDP_TIMEOUT_STREAM "ip_conntrack_udp_timeout_stream" no longer used */
+       /* NET_IPV4_NF_CONNTRACK_ICMP_TIMEOUT "ip_conntrack_icmp_timeout" no longer used */
+       /* NET_IPV4_NF_CONNTRACK_GENERIC_TIMEOUT "ip_conntrack_generic_timeout" no longer used */
+
+       { CTL_INT,      NET_IPV4_NF_CONNTRACK_BUCKETS,          "ip_conntrack_buckets" },
+       { CTL_INT,      NET_IPV4_NF_CONNTRACK_LOG_INVALID,      "ip_conntrack_log_invalid" },
+       /* NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_MAX_RETRANS "ip_conntrack_tcp_timeout_max_retrans" no longer used */
+       { CTL_INT,      NET_IPV4_NF_CONNTRACK_TCP_LOOSE,        "ip_conntrack_tcp_loose" },
+       { CTL_INT,      NET_IPV4_NF_CONNTRACK_TCP_BE_LIBERAL,   "ip_conntrack_tcp_be_liberal" },
+       { CTL_INT,      NET_IPV4_NF_CONNTRACK_TCP_MAX_RETRANS,  "ip_conntrack_tcp_max_retrans" },
+
+       /* NET_IPV4_NF_CONNTRACK_SCTP_TIMEOUT_CLOSED "ip_conntrack_sctp_timeout_closed" no longer used */
+       /* NET_IPV4_NF_CONNTRACK_SCTP_TIMEOUT_COOKIE_WAIT "ip_conntrack_sctp_timeout_cookie_wait" no longer used */
+       /* NET_IPV4_NF_CONNTRACK_SCTP_TIMEOUT_COOKIE_ECHOED "ip_conntrack_sctp_timeout_cookie_echoed" no longer used */
+       /* NET_IPV4_NF_CONNTRACK_SCTP_TIMEOUT_ESTABLISHED "ip_conntrack_sctp_timeout_established" no longer used */
+       /* NET_IPV4_NF_CONNTRACK_SCTP_TIMEOUT_SHUTDOWN_SENT "ip_conntrack_sctp_timeout_shutdown_sent" no longer used */
+       /* NET_IPV4_NF_CONNTRACK_SCTP_TIMEOUT_SHUTDOWN_RECD "ip_conntrack_sctp_timeout_shutdown_recd" no longer used */
+       /* NET_IPV4_NF_CONNTRACK_SCTP_TIMEOUT_SHUTDOWN_ACK_SENT "ip_conntrack_sctp_timeout_shutdown_ack_sent" no longer used */
+
+       { CTL_INT,      NET_IPV4_NF_CONNTRACK_COUNT,            "ip_conntrack_count" },
+       { CTL_INT,      NET_IPV4_NF_CONNTRACK_CHECKSUM,         "ip_conntrack_checksum" },
+       {}
+};
+
+static const struct bin_table bin_net_ipv4_table[] = {
+       {CTL_INT,       NET_IPV4_FORWARD,                       "ip_forward" },
+
+       { CTL_DIR,      NET_IPV4_CONF,          "conf",         bin_net_ipv4_conf_table },
+       { CTL_DIR,      NET_IPV4_NEIGH,         "neigh",        bin_net_neigh_table },
+       { CTL_DIR,      NET_IPV4_ROUTE,         "route",        bin_net_ipv4_route_table },
+       /* NET_IPV4_FIB_HASH unused */
+       { CTL_DIR,      NET_IPV4_NETFILTER,     "netfilter",    bin_net_ipv4_netfilter_table },
+
+       { CTL_INT,      NET_IPV4_TCP_TIMESTAMPS,                "tcp_timestamps" },
+       { CTL_INT,      NET_IPV4_TCP_WINDOW_SCALING,            "tcp_window_scaling" },
+       { CTL_INT,      NET_IPV4_TCP_SACK,                      "tcp_sack" },
+       { CTL_INT,      NET_IPV4_TCP_RETRANS_COLLAPSE,          "tcp_retrans_collapse" },
+       { CTL_INT,      NET_IPV4_DEFAULT_TTL,                   "ip_default_ttl" },
+       /* NET_IPV4_AUTOCONFIG unused */
+       { CTL_INT,      NET_IPV4_NO_PMTU_DISC,                  "ip_no_pmtu_disc" },
+       { CTL_INT,      NET_IPV4_NONLOCAL_BIND,                 "ip_nonlocal_bind" },
+       { CTL_INT,      NET_IPV4_TCP_SYN_RETRIES,               "tcp_syn_retries" },
+       { CTL_INT,      NET_TCP_SYNACK_RETRIES,                 "tcp_synack_retries" },
+       { CTL_INT,      NET_TCP_MAX_ORPHANS,                    "tcp_max_orphans" },
+       { CTL_INT,      NET_TCP_MAX_TW_BUCKETS,                 "tcp_max_tw_buckets" },
+       { CTL_INT,      NET_IPV4_DYNADDR,                       "ip_dynaddr" },
+       { CTL_INT,      NET_IPV4_TCP_KEEPALIVE_TIME,            "tcp_keepalive_time" },
+       { CTL_INT,      NET_IPV4_TCP_KEEPALIVE_PROBES,          "tcp_keepalive_probes" },
+       { CTL_INT,      NET_IPV4_TCP_KEEPALIVE_INTVL,           "tcp_keepalive_intvl" },
+       { CTL_INT,      NET_IPV4_TCP_RETRIES1,                  "tcp_retries1" },
+       { CTL_INT,      NET_IPV4_TCP_RETRIES2,                  "tcp_retries2" },
+       { CTL_INT,      NET_IPV4_TCP_FIN_TIMEOUT,               "tcp_fin_timeout" },
+       { CTL_INT,      NET_TCP_SYNCOOKIES,                     "tcp_syncookies" },
+       { CTL_INT,      NET_TCP_TW_RECYCLE,                     "tcp_tw_recycle" },
+       { CTL_INT,      NET_TCP_ABORT_ON_OVERFLOW,              "tcp_abort_on_overflow" },
+       { CTL_INT,      NET_TCP_STDURG,                         "tcp_stdurg" },
+       { CTL_INT,      NET_TCP_RFC1337,                        "tcp_rfc1337" },
+       { CTL_INT,      NET_TCP_MAX_SYN_BACKLOG,                "tcp_max_syn_backlog" },
+       { CTL_INT,      NET_IPV4_LOCAL_PORT_RANGE,              "ip_local_port_range" },
+       { CTL_INT,      NET_IPV4_IGMP_MAX_MEMBERSHIPS,          "igmp_max_memberships" },
+       { CTL_INT,      NET_IPV4_IGMP_MAX_MSF,                  "igmp_max_msf" },
+       { CTL_INT,      NET_IPV4_INET_PEER_THRESHOLD,           "inet_peer_threshold" },
+       { CTL_INT,      NET_IPV4_INET_PEER_MINTTL,              "inet_peer_minttl" },
+       { CTL_INT,      NET_IPV4_INET_PEER_MAXTTL,              "inet_peer_maxttl" },
+       { CTL_INT,      NET_IPV4_INET_PEER_GC_MINTIME,          "inet_peer_gc_mintime" },
+       { CTL_INT,      NET_IPV4_INET_PEER_GC_MAXTIME,          "inet_peer_gc_maxtime" },
+       { CTL_INT,      NET_TCP_ORPHAN_RETRIES,                 "tcp_orphan_retries" },
+       { CTL_INT,      NET_TCP_FACK,                           "tcp_fack" },
+       { CTL_INT,      NET_TCP_REORDERING,                     "tcp_reordering" },
+       { CTL_INT,      NET_TCP_ECN,                            "tcp_ecn" },
+       { CTL_INT,      NET_TCP_DSACK,                          "tcp_dsack" },
+       { CTL_INT,      NET_TCP_MEM,                            "tcp_mem" },
+       { CTL_INT,      NET_TCP_WMEM,                           "tcp_wmem" },
+       { CTL_INT,      NET_TCP_RMEM,                           "tcp_rmem" },
+       { CTL_INT,      NET_TCP_APP_WIN,                        "tcp_app_win" },
+       { CTL_INT,      NET_TCP_ADV_WIN_SCALE,                  "tcp_adv_win_scale" },
+       { CTL_INT,      NET_TCP_TW_REUSE,                       "tcp_tw_reuse" },
+       { CTL_INT,      NET_TCP_FRTO,                           "tcp_frto" },
+       { CTL_INT,      NET_TCP_FRTO_RESPONSE,                  "tcp_frto_response" },
+       { CTL_INT,      NET_TCP_LOW_LATENCY,                    "tcp_low_latency" },
+       { CTL_INT,      NET_TCP_NO_METRICS_SAVE,                "tcp_no_metrics_save" },
+       { CTL_INT,      NET_TCP_MODERATE_RCVBUF,                "tcp_moderate_rcvbuf" },
+       { CTL_INT,      NET_TCP_TSO_WIN_DIVISOR,                "tcp_tso_win_divisor" },
+       { CTL_STR,      NET_TCP_CONG_CONTROL,                   "tcp_congestion_control" },
+       { CTL_INT,      NET_TCP_ABC,                            "tcp_abc" },
+       { CTL_INT,      NET_TCP_MTU_PROBING,                    "tcp_mtu_probing" },
+       { CTL_INT,      NET_TCP_BASE_MSS,                       "tcp_base_mss" },
+       { CTL_INT,      NET_IPV4_TCP_WORKAROUND_SIGNED_WINDOWS, "tcp_workaround_signed_windows" },
+       { CTL_INT,      NET_TCP_DMA_COPYBREAK,                  "tcp_dma_copybreak" },
+       { CTL_INT,      NET_TCP_SLOW_START_AFTER_IDLE,          "tcp_slow_start_after_idle" },
+       { CTL_INT,      NET_CIPSOV4_CACHE_ENABLE,               "cipso_cache_enable" },
+       { CTL_INT,      NET_CIPSOV4_CACHE_BUCKET_SIZE,          "cipso_cache_bucket_size" },
+       { CTL_INT,      NET_CIPSOV4_RBM_OPTFMT,                 "cipso_rbm_optfmt" },
+       { CTL_INT,      NET_CIPSOV4_RBM_STRICTVALID,            "cipso_rbm_strictvalid" },
+       /* NET_TCP_AVAIL_CONG_CONTROL "tcp_available_congestion_control" no longer used */
+       { CTL_STR,      NET_TCP_ALLOWED_CONG_CONTROL,           "tcp_allowed_congestion_control" },
+       { CTL_INT,      NET_TCP_MAX_SSTHRESH,                   "tcp_max_ssthresh" },
+
+       { CTL_INT,      NET_IPV4_ICMP_ECHO_IGNORE_ALL,          "icmp_echo_ignore_all" },
+       { CTL_INT,      NET_IPV4_ICMP_ECHO_IGNORE_BROADCASTS,   "icmp_echo_ignore_broadcasts" },
+       { CTL_INT,      NET_IPV4_ICMP_IGNORE_BOGUS_ERROR_RESPONSES,     "icmp_ignore_bogus_error_responses" },
+       { CTL_INT,      NET_IPV4_ICMP_ERRORS_USE_INBOUND_IFADDR,        "icmp_errors_use_inbound_ifaddr" },
+       { CTL_INT,      NET_IPV4_ICMP_RATELIMIT,                "icmp_ratelimit" },
+       { CTL_INT,      NET_IPV4_ICMP_RATEMASK,                 "icmp_ratemask" },
+
+       { CTL_INT,      NET_IPV4_IPFRAG_HIGH_THRESH,            "ipfrag_high_thresh" },
+       { CTL_INT,      NET_IPV4_IPFRAG_LOW_THRESH,             "ipfrag_low_thresh" },
+       { CTL_INT,      NET_IPV4_IPFRAG_TIME,                   "ipfrag_time" },
+
+       { CTL_INT,      NET_IPV4_IPFRAG_SECRET_INTERVAL,        "ipfrag_secret_interval" },
+       /* NET_IPV4_IPFRAG_MAX_DIST "ipfrag_max_dist" no longer used */
+
+       { CTL_INT,      2088 /* NET_IPQ_QMAX */,                "ip_queue_maxlen" },
+
+       /* NET_TCP_DEFAULT_WIN_SCALE unused */
+       /* NET_TCP_BIC_BETA unused */
+       /* NET_IPV4_TCP_MAX_KA_PROBES unused */
+       /* NET_IPV4_IP_MASQ_DEBUG unused */
+       /* NET_TCP_SYN_TAILDROP unused */
+       /* NET_IPV4_ICMP_SOURCEQUENCH_RATE unused */
+       /* NET_IPV4_ICMP_DESTUNREACH_RATE unused */
+       /* NET_IPV4_ICMP_TIMEEXCEED_RATE unused */
+       /* NET_IPV4_ICMP_PARAMPROB_RATE unused */
+       /* NET_IPV4_ICMP_ECHOREPLY_RATE unused */
+       /* NET_IPV4_ALWAYS_DEFRAG unused */
+       {}
+};
+
+static const struct bin_table bin_net_ipx_table[] = {
+       { CTL_INT,      NET_IPX_PPROP_BROADCASTING,     "ipx_pprop_broadcasting" },
+       /* NET_IPX_FORWARDING unused */
+       {}
+};
+
+static const struct bin_table bin_net_atalk_table[] = {
+       { CTL_INT,      NET_ATALK_AARP_EXPIRY_TIME,             "aarp-expiry-time" },
+       { CTL_INT,      NET_ATALK_AARP_TICK_TIME,               "aarp-tick-time" },
+       { CTL_INT,      NET_ATALK_AARP_RETRANSMIT_LIMIT,        "aarp-retransmit-limit" },
+       { CTL_INT,      NET_ATALK_AARP_RESOLVE_TIME,            "aarp-resolve-time" },
+       {},
+};
+
+static const struct bin_table bin_net_netrom_table[] = {
+       { CTL_INT,      NET_NETROM_DEFAULT_PATH_QUALITY,                "default_path_quality" },
+       { CTL_INT,      NET_NETROM_OBSOLESCENCE_COUNT_INITIALISER,      "obsolescence_count_initialiser" },
+       { CTL_INT,      NET_NETROM_NETWORK_TTL_INITIALISER,             "network_ttl_initialiser" },
+       { CTL_INT,      NET_NETROM_TRANSPORT_TIMEOUT,                   "transport_timeout" },
+       { CTL_INT,      NET_NETROM_TRANSPORT_MAXIMUM_TRIES,             "transport_maximum_tries" },
+       { CTL_INT,      NET_NETROM_TRANSPORT_ACKNOWLEDGE_DELAY,         "transport_acknowledge_delay" },
+       { CTL_INT,      NET_NETROM_TRANSPORT_BUSY_DELAY,                "transport_busy_delay" },
+       { CTL_INT,      NET_NETROM_TRANSPORT_REQUESTED_WINDOW_SIZE,     "transport_requested_window_size" },
+       { CTL_INT,      NET_NETROM_TRANSPORT_NO_ACTIVITY_TIMEOUT,       "transport_no_activity_timeout" },
+       { CTL_INT,      NET_NETROM_ROUTING_CONTROL,                     "routing_control" },
+       { CTL_INT,      NET_NETROM_LINK_FAILS_COUNT,                    "link_fails_count" },
+       { CTL_INT,      NET_NETROM_RESET,                               "reset" },
+       {}
+};
+
+static const struct bin_table bin_net_ax25_param_table[] = {
+       { CTL_INT,      NET_AX25_IP_DEFAULT_MODE,       "ip_default_mode" },
+       { CTL_INT,      NET_AX25_DEFAULT_MODE,          "ax25_default_mode" },
+       { CTL_INT,      NET_AX25_BACKOFF_TYPE,          "backoff_type" },
+       { CTL_INT,      NET_AX25_CONNECT_MODE,          "connect_mode" },
+       { CTL_INT,      NET_AX25_STANDARD_WINDOW,       "standard_window_size" },
+       { CTL_INT,      NET_AX25_EXTENDED_WINDOW,       "extended_window_size" },
+       { CTL_INT,      NET_AX25_T1_TIMEOUT,            "t1_timeout" },
+       { CTL_INT,      NET_AX25_T2_TIMEOUT,            "t2_timeout" },
+       { CTL_INT,      NET_AX25_T3_TIMEOUT,            "t3_timeout" },
+       { CTL_INT,      NET_AX25_IDLE_TIMEOUT,          "idle_timeout" },
+       { CTL_INT,      NET_AX25_N2,                    "maximum_retry_count" },
+       { CTL_INT,      NET_AX25_PACLEN,                "maximum_packet_length" },
+       { CTL_INT,      NET_AX25_PROTOCOL,              "protocol" },
+       { CTL_INT,      NET_AX25_DAMA_SLAVE_TIMEOUT,    "dama_slave_timeout" },
+       {}
+};
+
+static const struct bin_table bin_net_ax25_table[] = {
+       { CTL_DIR,      0, NULL, bin_net_ax25_param_table },
+       {}
+};
+
+static const struct bin_table bin_net_rose_table[] = {
+       { CTL_INT,      NET_ROSE_RESTART_REQUEST_TIMEOUT,       "restart_request_timeout" },
+       { CTL_INT,      NET_ROSE_CALL_REQUEST_TIMEOUT,          "call_request_timeout" },
+       { CTL_INT,      NET_ROSE_RESET_REQUEST_TIMEOUT,         "reset_request_timeout" },
+       { CTL_INT,      NET_ROSE_CLEAR_REQUEST_TIMEOUT,         "clear_request_timeout" },
+       { CTL_INT,      NET_ROSE_ACK_HOLD_BACK_TIMEOUT,         "acknowledge_hold_back_timeout" },
+       { CTL_INT,      NET_ROSE_ROUTING_CONTROL,               "routing_control" },
+       { CTL_INT,      NET_ROSE_LINK_FAIL_TIMEOUT,             "link_fail_timeout" },
+       { CTL_INT,      NET_ROSE_MAX_VCS,                       "maximum_virtual_circuits" },
+       { CTL_INT,      NET_ROSE_WINDOW_SIZE,                   "window_size" },
+       { CTL_INT,      NET_ROSE_NO_ACTIVITY_TIMEOUT,           "no_activity_timeout" },
+       {}
+};
+
+static const struct bin_table bin_net_ipv6_conf_var_table[] = {
+       { CTL_INT,      NET_IPV6_FORWARDING,                    "forwarding" },
+       { CTL_INT,      NET_IPV6_HOP_LIMIT,                     "hop_limit" },
+       { CTL_INT,      NET_IPV6_MTU,                           "mtu" },
+       { CTL_INT,      NET_IPV6_ACCEPT_RA,                     "accept_ra" },
+       { CTL_INT,      NET_IPV6_ACCEPT_REDIRECTS,              "accept_redirects" },
+       { CTL_INT,      NET_IPV6_AUTOCONF,                      "autoconf" },
+       { CTL_INT,      NET_IPV6_DAD_TRANSMITS,                 "dad_transmits" },
+       { CTL_INT,      NET_IPV6_RTR_SOLICITS,                  "router_solicitations" },
+       { CTL_INT,      NET_IPV6_RTR_SOLICIT_INTERVAL,          "router_solicitation_interval" },
+       { CTL_INT,      NET_IPV6_RTR_SOLICIT_DELAY,             "router_solicitation_delay" },
+       { CTL_INT,      NET_IPV6_USE_TEMPADDR,                  "use_tempaddr" },
+       { CTL_INT,      NET_IPV6_TEMP_VALID_LFT,                "temp_valid_lft" },
+       { CTL_INT,      NET_IPV6_TEMP_PREFERED_LFT,             "temp_prefered_lft" },
+       { CTL_INT,      NET_IPV6_REGEN_MAX_RETRY,               "regen_max_retry" },
+       { CTL_INT,      NET_IPV6_MAX_DESYNC_FACTOR,             "max_desync_factor" },
+       { CTL_INT,      NET_IPV6_MAX_ADDRESSES,                 "max_addresses" },
+       { CTL_INT,      NET_IPV6_FORCE_MLD_VERSION,             "force_mld_version" },
+       { CTL_INT,      NET_IPV6_ACCEPT_RA_DEFRTR,              "accept_ra_defrtr" },
+       { CTL_INT,      NET_IPV6_ACCEPT_RA_PINFO,               "accept_ra_pinfo" },
+       { CTL_INT,      NET_IPV6_ACCEPT_RA_RTR_PREF,            "accept_ra_rtr_pref" },
+       { CTL_INT,      NET_IPV6_RTR_PROBE_INTERVAL,            "router_probe_interval" },
+       { CTL_INT,      NET_IPV6_ACCEPT_RA_RT_INFO_MAX_PLEN,    "accept_ra_rt_info_max_plen" },
+       { CTL_INT,      NET_IPV6_PROXY_NDP,                     "proxy_ndp" },
+       { CTL_INT,      NET_IPV6_ACCEPT_SOURCE_ROUTE,           "accept_source_route" },
+       {}
+};
+
+static const struct bin_table bin_net_ipv6_conf_table[] = {
+       { CTL_DIR,      NET_PROTO_CONF_ALL,             "all",  bin_net_ipv6_conf_var_table },
+       { CTL_DIR,      NET_PROTO_CONF_DEFAULT,         "default", bin_net_ipv6_conf_var_table },
+       { CTL_DIR,      0, NULL, bin_net_ipv6_conf_var_table },
+       {}
+};
+
+static const struct bin_table bin_net_ipv6_route_table[] = {
+       /* NET_IPV6_ROUTE_FLUSH "flush"  no longer used */
+       { CTL_INT,      NET_IPV6_ROUTE_GC_THRESH,               "gc_thresh" },
+       { CTL_INT,      NET_IPV6_ROUTE_MAX_SIZE,                "max_size" },
+       { CTL_INT,      NET_IPV6_ROUTE_GC_MIN_INTERVAL,         "gc_min_interval" },
+       { CTL_INT,      NET_IPV6_ROUTE_GC_TIMEOUT,              "gc_timeout" },
+       { CTL_INT,      NET_IPV6_ROUTE_GC_INTERVAL,             "gc_interval" },
+       { CTL_INT,      NET_IPV6_ROUTE_GC_ELASTICITY,           "gc_elasticity" },
+       { CTL_INT,      NET_IPV6_ROUTE_MTU_EXPIRES,             "mtu_expires" },
+       { CTL_INT,      NET_IPV6_ROUTE_MIN_ADVMSS,              "min_adv_mss" },
+       { CTL_INT,      NET_IPV6_ROUTE_GC_MIN_INTERVAL_MS,      "gc_min_interval_ms" },
+       {}
+};
+
+static const struct bin_table bin_net_ipv6_icmp_table[] = {
+       { CTL_INT,      NET_IPV6_ICMP_RATELIMIT,        "ratelimit" },
+       {}
+};
+
+static const struct bin_table bin_net_ipv6_table[] = {
+       { CTL_DIR,      NET_IPV6_CONF,          "conf",         bin_net_ipv6_conf_table },
+       { CTL_DIR,      NET_IPV6_NEIGH,         "neigh",        bin_net_neigh_table },
+       { CTL_DIR,      NET_IPV6_ROUTE,         "route",        bin_net_ipv6_route_table },
+       { CTL_DIR,      NET_IPV6_ICMP,          "icmp",         bin_net_ipv6_icmp_table },
+       { CTL_INT,      NET_IPV6_BINDV6ONLY,            "bindv6only" },
+       { CTL_INT,      NET_IPV6_IP6FRAG_HIGH_THRESH,   "ip6frag_high_thresh" },
+       { CTL_INT,      NET_IPV6_IP6FRAG_LOW_THRESH,    "ip6frag_low_thresh" },
+       { CTL_INT,      NET_IPV6_IP6FRAG_TIME,          "ip6frag_time" },
+       { CTL_INT,      NET_IPV6_IP6FRAG_SECRET_INTERVAL,       "ip6frag_secret_interval" },
+       { CTL_INT,      NET_IPV6_MLD_MAX_MSF,           "mld_max_msf" },
+       { CTL_INT,      2088 /* IPQ_QMAX */,            "ip6_queue_maxlen" },
+       {}
+};
+
+static const struct bin_table bin_net_x25_table[] = {
+       { CTL_INT,      NET_X25_RESTART_REQUEST_TIMEOUT,        "restart_request_timeout" },
+       { CTL_INT,      NET_X25_CALL_REQUEST_TIMEOUT,           "call_request_timeout" },
+       { CTL_INT,      NET_X25_RESET_REQUEST_TIMEOUT,  "reset_request_timeout" },
+       { CTL_INT,      NET_X25_CLEAR_REQUEST_TIMEOUT,  "clear_request_timeout" },
+       { CTL_INT,      NET_X25_ACK_HOLD_BACK_TIMEOUT,  "acknowledgement_hold_back_timeout" },
+       { CTL_INT,      NET_X25_FORWARD,                        "x25_forward" },
+       {}
+};
+
+static const struct bin_table bin_net_tr_table[] = {
+       { CTL_INT,      NET_TR_RIF_TIMEOUT,     "rif_timeout" },
+       {}
+};
+
+
+static const struct bin_table bin_net_decnet_conf_vars[] = {
+       { CTL_INT,      NET_DECNET_CONF_DEV_FORWARDING, "forwarding" },
+       { CTL_INT,      NET_DECNET_CONF_DEV_PRIORITY,   "priority" },
+       { CTL_INT,      NET_DECNET_CONF_DEV_T2,         "t2" },
+       { CTL_INT,      NET_DECNET_CONF_DEV_T3,         "t3" },
+       {}
+};
+
+static const struct bin_table bin_net_decnet_conf[] = {
+       { CTL_DIR, NET_DECNET_CONF_ETHER,    "ethernet", bin_net_decnet_conf_vars },
+       { CTL_DIR, NET_DECNET_CONF_GRE,      "ipgre",    bin_net_decnet_conf_vars },
+       { CTL_DIR, NET_DECNET_CONF_X25,      "x25",      bin_net_decnet_conf_vars },
+       { CTL_DIR, NET_DECNET_CONF_PPP,      "ppp",      bin_net_decnet_conf_vars },
+       { CTL_DIR, NET_DECNET_CONF_DDCMP,    "ddcmp",    bin_net_decnet_conf_vars },
+       { CTL_DIR, NET_DECNET_CONF_LOOPBACK, "loopback", bin_net_decnet_conf_vars },
+       { CTL_DIR, 0,                        NULL,       bin_net_decnet_conf_vars },
+       {}
+};
+
+static const struct bin_table bin_net_decnet_table[] = {
+       { CTL_DIR,      NET_DECNET_CONF,                "conf", bin_net_decnet_conf },
+       { CTL_DNADR,    NET_DECNET_NODE_ADDRESS,        "node_address" },
+       { CTL_STR,      NET_DECNET_NODE_NAME,           "node_name" },
+       { CTL_STR,      NET_DECNET_DEFAULT_DEVICE,      "default_device" },
+       { CTL_INT,      NET_DECNET_TIME_WAIT,           "time_wait" },
+       { CTL_INT,      NET_DECNET_DN_COUNT,            "dn_count" },
+       { CTL_INT,      NET_DECNET_DI_COUNT,            "di_count" },
+       { CTL_INT,      NET_DECNET_DR_COUNT,            "dr_count" },
+       { CTL_INT,      NET_DECNET_DST_GC_INTERVAL,     "dst_gc_interval" },
+       { CTL_INT,      NET_DECNET_NO_FC_MAX_CWND,      "no_fc_max_cwnd" },
+       { CTL_INT,      NET_DECNET_MEM,         "decnet_mem" },
+       { CTL_INT,      NET_DECNET_RMEM,                "decnet_rmem" },
+       { CTL_INT,      NET_DECNET_WMEM,                "decnet_wmem" },
+       { CTL_INT,      NET_DECNET_DEBUG_LEVEL, "debug" },
+       {}
+};
+
+static const struct bin_table bin_net_sctp_table[] = {
+       { CTL_INT,      NET_SCTP_RTO_INITIAL,           "rto_initial" },
+       { CTL_INT,      NET_SCTP_RTO_MIN,               "rto_min" },
+       { CTL_INT,      NET_SCTP_RTO_MAX,               "rto_max" },
+       { CTL_INT,      NET_SCTP_RTO_ALPHA,             "rto_alpha_exp_divisor" },
+       { CTL_INT,      NET_SCTP_RTO_BETA,              "rto_beta_exp_divisor" },
+       { CTL_INT,      NET_SCTP_VALID_COOKIE_LIFE,     "valid_cookie_life" },
+       { CTL_INT,      NET_SCTP_ASSOCIATION_MAX_RETRANS,       "association_max_retrans" },
+       { CTL_INT,      NET_SCTP_PATH_MAX_RETRANS,      "path_max_retrans" },
+       { CTL_INT,      NET_SCTP_MAX_INIT_RETRANSMITS,  "max_init_retransmits" },
+       { CTL_INT,      NET_SCTP_HB_INTERVAL,           "hb_interval" },
+       { CTL_INT,      NET_SCTP_PRESERVE_ENABLE,       "cookie_preserve_enable" },
+       { CTL_INT,      NET_SCTP_MAX_BURST,             "max_burst" },
+       { CTL_INT,      NET_SCTP_ADDIP_ENABLE,          "addip_enable" },
+       { CTL_INT,      NET_SCTP_PRSCTP_ENABLE,         "prsctp_enable" },
+       { CTL_INT,      NET_SCTP_SNDBUF_POLICY,         "sndbuf_policy" },
+       { CTL_INT,      NET_SCTP_SACK_TIMEOUT,          "sack_timeout" },
+       { CTL_INT,      NET_SCTP_RCVBUF_POLICY,         "rcvbuf_policy" },
+       {}
+};
+
+static const struct bin_table bin_net_llc_llc2_timeout_table[] = {
+       { CTL_INT,      NET_LLC2_ACK_TIMEOUT,   "ack" },
+       { CTL_INT,      NET_LLC2_P_TIMEOUT,     "p" },
+       { CTL_INT,      NET_LLC2_REJ_TIMEOUT,   "rej" },
+       { CTL_INT,      NET_LLC2_BUSY_TIMEOUT,  "busy" },
+       {}
+};
+
+static const struct bin_table bin_net_llc_station_table[] = {
+       { CTL_INT,      NET_LLC_STATION_ACK_TIMEOUT,    "ack_timeout" },
+       {}
+};
+
+static const struct bin_table bin_net_llc_llc2_table[] = {
+       { CTL_DIR,      NET_LLC2,               "timeout",      bin_net_llc_llc2_timeout_table },
+       {}
+};
+
+static const struct bin_table bin_net_llc_table[] = {
+       { CTL_DIR,      NET_LLC2,               "llc2",         bin_net_llc_llc2_table },
+       { CTL_DIR,      NET_LLC_STATION,        "station",      bin_net_llc_station_table },
+       {}
+};
+
+static const struct bin_table bin_net_netfilter_table[] = {
+       { CTL_INT,      NET_NF_CONNTRACK_MAX,                   "nf_conntrack_max" },
+       /* NET_NF_CONNTRACK_TCP_TIMEOUT_SYN_SENT "nf_conntrack_tcp_timeout_syn_sent" no longer used */
+       /* NET_NF_CONNTRACK_TCP_TIMEOUT_SYN_RECV "nf_conntrack_tcp_timeout_syn_recv" no longer used */
+       /* NET_NF_CONNTRACK_TCP_TIMEOUT_ESTABLISHED "nf_conntrack_tcp_timeout_established" no longer used */
+       /* NET_NF_CONNTRACK_TCP_TIMEOUT_FIN_WAIT "nf_conntrack_tcp_timeout_fin_wait" no longer used */
+       /* NET_NF_CONNTRACK_TCP_TIMEOUT_CLOSE_WAIT "nf_conntrack_tcp_timeout_close_wait" no longer used */
+       /* NET_NF_CONNTRACK_TCP_TIMEOUT_LAST_ACK "nf_conntrack_tcp_timeout_last_ack" no longer used */
+       /* NET_NF_CONNTRACK_TCP_TIMEOUT_TIME_WAIT "nf_conntrack_tcp_timeout_time_wait" no longer used */
+       /* NET_NF_CONNTRACK_TCP_TIMEOUT_CLOSE "nf_conntrack_tcp_timeout_close" no longer used */
+       /* NET_NF_CONNTRACK_UDP_TIMEOUT "nf_conntrack_udp_timeout" no longer used */
+       /* NET_NF_CONNTRACK_UDP_TIMEOUT_STREAM "nf_conntrack_udp_timeout_stream" no longer used */
+       /* NET_NF_CONNTRACK_ICMP_TIMEOUT "nf_conntrack_icmp_timeout" no longer used */
+       /* NET_NF_CONNTRACK_GENERIC_TIMEOUT "nf_conntrack_generic_timeout" no longer used */
+       { CTL_INT,      NET_NF_CONNTRACK_BUCKETS,               "nf_conntrack_buckets" },
+       { CTL_INT,      NET_NF_CONNTRACK_LOG_INVALID,           "nf_conntrack_log_invalid" },
+       /* NET_NF_CONNTRACK_TCP_TIMEOUT_MAX_RETRANS "nf_conntrack_tcp_timeout_max_retrans" no longer used */
+       { CTL_INT,      NET_NF_CONNTRACK_TCP_LOOSE,             "nf_conntrack_tcp_loose" },
+       { CTL_INT,      NET_NF_CONNTRACK_TCP_BE_LIBERAL,        "nf_conntrack_tcp_be_liberal" },
+       { CTL_INT,      NET_NF_CONNTRACK_TCP_MAX_RETRANS,       "nf_conntrack_tcp_max_retrans" },
+       /* NET_NF_CONNTRACK_SCTP_TIMEOUT_CLOSED "nf_conntrack_sctp_timeout_closed" no longer used */
+       /* NET_NF_CONNTRACK_SCTP_TIMEOUT_COOKIE_WAIT "nf_conntrack_sctp_timeout_cookie_wait" no longer used */
+       /* NET_NF_CONNTRACK_SCTP_TIMEOUT_COOKIE_ECHOED "nf_conntrack_sctp_timeout_cookie_echoed" no longer used */
+       /* NET_NF_CONNTRACK_SCTP_TIMEOUT_ESTABLISHED "nf_conntrack_sctp_timeout_established" no longer used */
+       /* NET_NF_CONNTRACK_SCTP_TIMEOUT_SHUTDOWN_SENT "nf_conntrack_sctp_timeout_shutdown_sent" no longer used */
+       /* NET_NF_CONNTRACK_SCTP_TIMEOUT_SHUTDOWN_RECD "nf_conntrack_sctp_timeout_shutdown_recd" no longer used */
+       /* NET_NF_CONNTRACK_SCTP_TIMEOUT_SHUTDOWN_ACK_SENT "nf_conntrack_sctp_timeout_shutdown_ack_sent" no longer used */
+       { CTL_INT,      NET_NF_CONNTRACK_COUNT,                 "nf_conntrack_count" },
+       /* NET_NF_CONNTRACK_ICMPV6_TIMEOUT "nf_conntrack_icmpv6_timeout" no longer used */
+       /* NET_NF_CONNTRACK_FRAG6_TIMEOUT "nf_conntrack_frag6_timeout" no longer used */
+       { CTL_INT,      NET_NF_CONNTRACK_FRAG6_LOW_THRESH,      "nf_conntrack_frag6_low_thresh" },
+       { CTL_INT,      NET_NF_CONNTRACK_FRAG6_HIGH_THRESH,     "nf_conntrack_frag6_high_thresh" },
+       { CTL_INT,      NET_NF_CONNTRACK_CHECKSUM,              "nf_conntrack_checksum" },
+
+       {}
+};
+
+static const struct bin_table bin_net_irda_table[] = {
+       { CTL_INT,      NET_IRDA_DISCOVERY,             "discovery" },
+       { CTL_STR,      NET_IRDA_DEVNAME,               "devname" },
+       { CTL_INT,      NET_IRDA_DEBUG,                 "debug" },
+       { CTL_INT,      NET_IRDA_FAST_POLL,             "fast_poll_increase" },
+       { CTL_INT,      NET_IRDA_DISCOVERY_SLOTS,       "discovery_slots" },
+       { CTL_INT,      NET_IRDA_DISCOVERY_TIMEOUT,     "discovery_timeout" },
+       { CTL_INT,      NET_IRDA_SLOT_TIMEOUT,          "slot_timeout" },
+       { CTL_INT,      NET_IRDA_MAX_BAUD_RATE,         "max_baud_rate" },
+       { CTL_INT,      NET_IRDA_MIN_TX_TURN_TIME,      "min_tx_turn_time" },
+       { CTL_INT,      NET_IRDA_MAX_TX_DATA_SIZE,      "max_tx_data_size" },
+       { CTL_INT,      NET_IRDA_MAX_TX_WINDOW,         "max_tx_window" },
+       { CTL_INT,      NET_IRDA_MAX_NOREPLY_TIME,      "max_noreply_time" },
+       { CTL_INT,      NET_IRDA_WARN_NOREPLY_TIME,     "warn_noreply_time" },
+       { CTL_INT,      NET_IRDA_LAP_KEEPALIVE_TIME,    "lap_keepalive_time" },
+       {}
+};
+
+static const struct bin_table bin_net_table[] = {
+       { CTL_DIR,      NET_CORE,               "core",         bin_net_core_table },
+       /* NET_ETHER not used */
+       /* NET_802 not used */
+       { CTL_DIR,      NET_UNIX,               "unix",         bin_net_unix_table },
+       { CTL_DIR,      NET_IPV4,               "ipv4",         bin_net_ipv4_table },
+       { CTL_DIR,      NET_IPX,                "ipx",          bin_net_ipx_table },
+       { CTL_DIR,      NET_ATALK,              "appletalk",    bin_net_atalk_table },
+       { CTL_DIR,      NET_NETROM,             "netrom",       bin_net_netrom_table },
+       { CTL_DIR,      NET_AX25,               "ax25",         bin_net_ax25_table },
+       /*  NET_BRIDGE "bridge" no longer used */
+       { CTL_DIR,      NET_ROSE,               "rose",         bin_net_rose_table },
+       { CTL_DIR,      NET_IPV6,               "ipv6",         bin_net_ipv6_table },
+       { CTL_DIR,      NET_X25,                "x25",          bin_net_x25_table },
+       { CTL_DIR,      NET_TR,                 "token-ring",   bin_net_tr_table },
+       { CTL_DIR,      NET_DECNET,             "decnet",       bin_net_decnet_table },
+       /*  NET_ECONET not used */
+       { CTL_DIR,      NET_SCTP,               "sctp",         bin_net_sctp_table },
+       { CTL_DIR,      NET_LLC,                "llc",          bin_net_llc_table },
+       { CTL_DIR,      NET_NETFILTER,          "netfilter",    bin_net_netfilter_table },
+       /* NET_DCCP "dccp" no longer used */
+       { CTL_DIR,      NET_IRDA,               "irda",         bin_net_irda_table },
+       { CTL_INT,      2089,                   "nf_conntrack_max" },
+       {}
+};
+
+static const struct bin_table bin_fs_quota_table[] = {
+       { CTL_INT,      FS_DQ_LOOKUPS,          "lookups" },
+       { CTL_INT,      FS_DQ_DROPS,            "drops" },
+       { CTL_INT,      FS_DQ_READS,            "reads" },
+       { CTL_INT,      FS_DQ_WRITES,           "writes" },
+       { CTL_INT,      FS_DQ_CACHE_HITS,       "cache_hits" },
+       { CTL_INT,      FS_DQ_ALLOCATED,        "allocated_dquots" },
+       { CTL_INT,      FS_DQ_FREE,             "free_dquots" },
+       { CTL_INT,      FS_DQ_SYNCS,            "syncs" },
+       { CTL_INT,      FS_DQ_WARNINGS,         "warnings" },
+       {}
+};
+
+static const struct bin_table bin_fs_xfs_table[] = {
+       { CTL_INT,      XFS_SGID_INHERIT,       "irix_sgid_inherit" },
+       { CTL_INT,      XFS_SYMLINK_MODE,       "irix_symlink_mode" },
+       { CTL_INT,      XFS_PANIC_MASK,         "panic_mask" },
+
+       { CTL_INT,      XFS_ERRLEVEL,           "error_level" },
+       { CTL_INT,      XFS_SYNCD_TIMER,        "xfssyncd_centisecs" },
+       { CTL_INT,      XFS_INHERIT_SYNC,       "inherit_sync" },
+       { CTL_INT,      XFS_INHERIT_NODUMP,     "inherit_nodump" },
+       { CTL_INT,      XFS_INHERIT_NOATIME,    "inherit_noatime" },
+       { CTL_INT,      XFS_BUF_TIMER,          "xfsbufd_centisecs" },
+       { CTL_INT,      XFS_BUF_AGE,            "age_buffer_centisecs" },
+       { CTL_INT,      XFS_INHERIT_NOSYM,      "inherit_nosymlinks" },
+       { CTL_INT,      XFS_ROTORSTEP,  "rotorstep" },
+       { CTL_INT,      XFS_INHERIT_NODFRG,     "inherit_nodefrag" },
+       { CTL_INT,      XFS_FILESTREAM_TIMER,   "filestream_centisecs" },
+       { CTL_INT,      XFS_STATS_CLEAR,        "stats_clear" },
+       {}
+};
+
+static const struct bin_table bin_fs_ocfs2_nm_table[] = {
+       { CTL_STR,      1, "hb_ctl_path" },
+       {}
+};
+
+static const struct bin_table bin_fs_ocfs2_table[] = {
+       { CTL_DIR,      1,      "nm",   bin_fs_ocfs2_nm_table },
+       {}
+};
+
+static const struct bin_table bin_inotify_table[] = {
+       { CTL_INT,      INOTIFY_MAX_USER_INSTANCES,     "max_user_instances" },
+       { CTL_INT,      INOTIFY_MAX_USER_WATCHES,       "max_user_watches" },
+       { CTL_INT,      INOTIFY_MAX_QUEUED_EVENTS,      "max_queued_events" },
+       {}
+};
+
+static const struct bin_table bin_fs_table[] = {
+       { CTL_INT,      FS_NRINODE,             "inode-nr" },
+       { CTL_INT,      FS_STATINODE,           "inode-state" },
+       /* FS_MAXINODE unused */
+       /* FS_NRDQUOT unused */
+       /* FS_MAXDQUOT unused */
+       /* FS_NRFILE "file-nr" no longer used */
+       { CTL_INT,      FS_MAXFILE,             "file-max" },
+       { CTL_INT,      FS_DENTRY,              "dentry-state" },
+       /* FS_NRSUPER unused */
+       /* FS_MAXUPSER unused */
+       { CTL_INT,      FS_OVERFLOWUID,         "overflowuid" },
+       { CTL_INT,      FS_OVERFLOWGID,         "overflowgid" },
+       { CTL_INT,      FS_LEASES,              "leases-enable" },
+       { CTL_INT,      FS_DIR_NOTIFY,          "dir-notify-enable" },
+       { CTL_INT,      FS_LEASE_TIME,          "lease-break-time" },
+       { CTL_DIR,      FS_DQSTATS,             "quota",        bin_fs_quota_table },
+       { CTL_DIR,      FS_XFS,                 "xfs",          bin_fs_xfs_table },
+       { CTL_ULONG,    FS_AIO_NR,              "aio-nr" },
+       { CTL_ULONG,    FS_AIO_MAX_NR,          "aio-max-nr" },
+       { CTL_DIR,      FS_INOTIFY,             "inotify",      bin_inotify_table },
+       { CTL_DIR,      FS_OCFS2,               "ocfs2",        bin_fs_ocfs2_table },
+       { CTL_INT,      KERN_SETUID_DUMPABLE,   "suid_dumpable" },
+       {}
+};
+
+static const struct bin_table bin_ipmi_table[] = {
+       { CTL_INT,      DEV_IPMI_POWEROFF_POWERCYCLE,   "poweroff_powercycle" },
+       {}
+};
+
+static const struct bin_table bin_mac_hid_files[] = {
+       /* DEV_MAC_HID_KEYBOARD_SENDS_LINUX_KEYCODES unused */
+       /* DEV_MAC_HID_KEYBOARD_LOCK_KEYCODES unused */
+       { CTL_INT,      DEV_MAC_HID_MOUSE_BUTTON_EMULATION,     "mouse_button_emulation" },
+       { CTL_INT,      DEV_MAC_HID_MOUSE_BUTTON2_KEYCODE,      "mouse_button2_keycode" },
+       { CTL_INT,      DEV_MAC_HID_MOUSE_BUTTON3_KEYCODE,      "mouse_button3_keycode" },
+       /* DEV_MAC_HID_ADB_MOUSE_SENDS_KEYCODES unused */
+       {}
+};
+
+static const struct bin_table bin_raid_table[] = {
+       { CTL_INT,      DEV_RAID_SPEED_LIMIT_MIN,       "speed_limit_min" },
+       { CTL_INT,      DEV_RAID_SPEED_LIMIT_MAX,       "speed_limit_max" },
+       {}
+};
+
+static const struct bin_table bin_scsi_table[] = {
+       { CTL_INT, DEV_SCSI_LOGGING_LEVEL, "logging_level" },
+       {}
+};
+
+static const struct bin_table bin_dev_table[] = {
+       /* DEV_CDROM    "cdrom" no longer used */
+       /* DEV_HWMON unused */
+       /* DEV_PARPORT  "parport" no longer used */
+       { CTL_DIR,      DEV_RAID,       "raid",         bin_raid_table },
+       { CTL_DIR,      DEV_MAC_HID,    "mac_hid",      bin_mac_hid_files },
+       { CTL_DIR,      DEV_SCSI,       "scsi",         bin_scsi_table },
+       { CTL_DIR,      DEV_IPMI,       "ipmi",         bin_ipmi_table },
+       {}
+};
+
+static const struct bin_table bin_bus_isa_table[] = {
+       { CTL_INT,      BUS_ISA_MEM_BASE,       "membase" },
+       { CTL_INT,      BUS_ISA_PORT_BASE,      "portbase" },
+       { CTL_INT,      BUS_ISA_PORT_SHIFT,     "portshift" },
+       {}
+};
+
+static const struct bin_table bin_bus_table[] = {
+       { CTL_DIR,      CTL_BUS_ISA,    "isa",  bin_bus_isa_table },
+       {}
+};
+
+
+static const struct bin_table bin_s390dbf_table[] = {
+       { CTL_INT,      5678 /* CTL_S390DBF_STOPPABLE */, "debug_stoppable" },
+       { CTL_INT,      5679 /* CTL_S390DBF_ACTIVE */,    "debug_active" },
+       {}
+};
+
+static const struct bin_table bin_sunrpc_table[] = {
+       /* CTL_RPCDEBUG "rpc_debug"  no longer used */
+       /* CTL_NFSDEBUG "nfs_debug"  no longer used */
+       /* CTL_NFSDDEBUG "nfsd_debug" no longer used  */
+       /* CTL_NLMDEBUG "nlm_debug" no longer used */
+
+       { CTL_INT,      CTL_SLOTTABLE_UDP,      "udp_slot_table_entries" },
+       { CTL_INT,      CTL_SLOTTABLE_TCP,      "tcp_slot_table_entries" },
+       { CTL_INT,      CTL_MIN_RESVPORT,       "min_resvport" },
+       { CTL_INT,      CTL_MAX_RESVPORT,       "max_resvport" },
+       {}
+};
+
+static const struct bin_table bin_pm_table[] = {
+       /* frv specific */
+       /* 1 == CTL_PM_SUSPEND  "suspend"  no longer used" */
+       { CTL_INT,      2 /* CTL_PM_CMODE */,           "cmode" },
+       { CTL_INT,      3 /* CTL_PM_P0 */,              "p0" },
+       { CTL_INT,      4 /* CTL_PM_CM */,              "cm" },
+       {}
+};
+
+static const struct bin_table bin_root_table[] = {
+       { CTL_DIR,      CTL_KERN,       "kernel",       bin_kern_table },
+       { CTL_DIR,      CTL_VM,         "vm",           bin_vm_table },
+       { CTL_DIR,      CTL_NET,        "net",          bin_net_table },
+       /* CTL_PROC not used */
+       { CTL_DIR,      CTL_FS,         "fs",           bin_fs_table },
+       /* CTL_DEBUG "debug" no longer used */
+       { CTL_DIR,      CTL_DEV,        "dev",          bin_dev_table },
+       { CTL_DIR,      CTL_BUS,        "bus",          bin_bus_table },
+       { CTL_DIR,      CTL_ABI,        "abi" },
+       /* CTL_CPU not used */
+       /* CTL_ARLAN "arlan" no longer used */
+       { CTL_DIR,      CTL_S390DBF,    "s390dbf",      bin_s390dbf_table },
+       { CTL_DIR,      CTL_SUNRPC,     "sunrpc",       bin_sunrpc_table },
+       { CTL_DIR,      CTL_PM,         "pm",           bin_pm_table },
+       {}
+};
+
+static ssize_t bin_dir(struct file *file,
+       void __user *oldval, size_t oldlen, void __user *newval, size_t newlen)
+{
+       return -ENOTDIR;
+}
+
+
+static ssize_t bin_string(struct file *file,
+       void __user *oldval, size_t oldlen, void __user *newval, size_t newlen)
+{
+       ssize_t result, copied = 0;
+
+       if (oldval && oldlen) {
+               char __user *lastp;
+               loff_t pos = 0;
+               int ch;
+
+               result = vfs_read(file, oldval, oldlen, &pos);
+               if (result < 0)
+                       goto out;
+
+               copied = result;
+               lastp = oldval + copied - 1;
+
+               result = -EFAULT;
+               if (get_user(ch, lastp))
+                       goto out;
+
+               /* Trim off the trailing newline */
+               if (ch == '\n') {
+                       result = -EFAULT;
+                       if (put_user('\0', lastp))
+                               goto out;
+                       copied -= 1;
+               }
+       }
+
+       if (newval && newlen) {
+               loff_t pos = 0;
+
+               result = vfs_write(file, newval, newlen, &pos);
+               if (result < 0)
+                       goto out;
+       }
+
+       result = copied;
+out:
+       return result;
+}
+
+static ssize_t bin_intvec(struct file *file,
+       void __user *oldval, size_t oldlen, void __user *newval, size_t newlen)
+{
+       mm_segment_t old_fs = get_fs();
+       ssize_t copied = 0;
+       char *buffer;
+       ssize_t result;
+
+       result = -ENOMEM;
+       buffer = kmalloc(BUFSZ, GFP_KERNEL);
+       if (!buffer)
+               goto out;
+
+       if (oldval && oldlen) {
+               unsigned __user *vec = oldval;
+               size_t length = oldlen / sizeof(*vec);
+               loff_t pos = 0;
+               char *str, *end;
+               int i;
+
+               set_fs(KERNEL_DS);
+               result = vfs_read(file, buffer, BUFSZ - 1, &pos);
+               set_fs(old_fs);
+               if (result < 0)
+                       goto out_kfree;
+
+               str = buffer;
+               end = str + result;
+               *end++ = '\0';
+               for (i = 0; i < length; i++) {
+                       unsigned long value;
+
+                       value = simple_strtoul(str, &str, 10);
+                       while (isspace(*str))
+                               str++;
+                       
+                       result = -EFAULT;
+                       if (put_user(value, vec + i))
+                               goto out_kfree;
+
+                       copied += sizeof(*vec);
+                       if (!isdigit(*str))
+                               break;
+               }
+       }
+
+       if (newval && newlen) {
+               unsigned __user *vec = newval;
+               size_t length = newlen / sizeof(*vec);
+               loff_t pos = 0;
+               char *str, *end;
+               int i;
+
+               str = buffer;
+               end = str + BUFSZ;
+               for (i = 0; i < length; i++) {
+                       unsigned long value;
+
+                       result = -EFAULT;
+                       if (get_user(value, vec + i))
+                               goto out_kfree;
+
+                       str += snprintf(str, end - str, "%lu\t", value);
+               }
+
+               set_fs(KERNEL_DS);
+               result = vfs_write(file, buffer, str - buffer, &pos);
+               set_fs(old_fs);
+               if (result < 0)
+                       goto out_kfree;
+       }
+       result = copied;
+out_kfree:
+       kfree(buffer);
+out:
+       return result;
+}
+
+static ssize_t bin_ulongvec(struct file *file,
+       void __user *oldval, size_t oldlen, void __user *newval, size_t newlen)
+{
+       mm_segment_t old_fs = get_fs();
+       ssize_t copied = 0;
+       char *buffer;
+       ssize_t result;
+
+       result = -ENOMEM;
+       buffer = kmalloc(BUFSZ, GFP_KERNEL);
+       if (!buffer)
+               goto out;
+
+       if (oldval && oldlen) {
+               unsigned long __user *vec = oldval;
+               size_t length = oldlen / sizeof(*vec);
+               loff_t pos = 0;
+               char *str, *end;
+               int i;
+
+               set_fs(KERNEL_DS);
+               result = vfs_read(file, buffer, BUFSZ - 1, &pos);
+               set_fs(old_fs);
+               if (result < 0)
+                       goto out_kfree;
+
+               str = buffer;
+               end = str + result;
+               *end++ = '\0';
+               for (i = 0; i < length; i++) {
+                       unsigned long value;
+
+                       value = simple_strtoul(str, &str, 10);
+                       while (isspace(*str))
+                               str++;
+                       
+                       result = -EFAULT;
+                       if (put_user(value, vec + i))
+                               goto out_kfree;
+
+                       copied += sizeof(*vec);
+                       if (!isdigit(*str))
+                               break;
+               }
+       }
+
+       if (newval && newlen) {
+               unsigned long __user *vec = newval;
+               size_t length = newlen / sizeof(*vec);
+               loff_t pos = 0;
+               char *str, *end;
+               int i;
+
+               str = buffer;
+               end = str + BUFSZ;
+               for (i = 0; i < length; i++) {
+                       unsigned long value;
+
+                       result = -EFAULT;
+                       if (get_user(value, vec + i))
+                               goto out_kfree;
+
+                       str += snprintf(str, end - str, "%lu\t", value);
+               }
+
+               set_fs(KERNEL_DS);
+               result = vfs_write(file, buffer, str - buffer, &pos);
+               set_fs(old_fs);
+               if (result < 0)
+                       goto out_kfree;
+       }
+       result = copied;
+out_kfree:
+       kfree(buffer);
+out:
+       return result;
+}
+
+static unsigned hex_value(int ch)
+{
+       return isdigit(ch) ? ch - '0' : ((ch | 0x20) - 'a') + 10;
+}
+
+static ssize_t bin_uuid(struct file *file,
+       void __user *oldval, size_t oldlen, void __user *newval, size_t newlen)
+{
+       mm_segment_t old_fs = get_fs();
+       ssize_t result, copied = 0;
+
+       /* Only supports reads */
+       if (oldval && oldlen) {
+               loff_t pos = 0;
+               char buf[40], *str = buf;
+               unsigned char uuid[16];
+               int i;
+
+               set_fs(KERNEL_DS);
+               result = vfs_read(file, buf, sizeof(buf) - 1, &pos);
+               set_fs(old_fs);
+               if (result < 0)
+                       goto out;
+
+               buf[result] = '\0';
+
+               /* Convert the uuid to from a string to binary */
+               for (i = 0; i < 16; i++) {
+                       result = -EIO;
+                       if (!isxdigit(str[0]) || !isxdigit(str[1]))
+                               goto out;
+
+                       uuid[i] = (hex_value(str[0]) << 4) | hex_value(str[1]);
+                       str += 2;
+                       if (*str == '-')
+                               str++;
+               }
+
+               if (oldlen > 16)
+                       oldlen = 16;
+
+               result = -EFAULT;
+               if (copy_to_user(oldval, uuid, oldlen))
+                       goto out;
+
+               copied = oldlen;
+       }
+       result = copied;
+out:
+       return result;
+}
+
+static ssize_t bin_dn_node_address(struct file *file,
+       void __user *oldval, size_t oldlen, void __user *newval, size_t newlen)
+{
+       mm_segment_t old_fs = get_fs();
+       ssize_t result, copied = 0;
+
+       if (oldval && oldlen) {
+               loff_t pos = 0;
+               char buf[15], *nodep;
+               unsigned long area, node;
+               __le16 dnaddr;
+
+               set_fs(KERNEL_DS);
+               result = vfs_read(file, buf, sizeof(buf) - 1, &pos);
+               set_fs(old_fs);
+               if (result < 0)
+                       goto out;
+
+               buf[result] = '\0';
+
+               /* Convert the decnet addresss to binary */
+               result = -EIO;
+               nodep = strchr(buf, '.') + 1;
+               if (!nodep)
+                       goto out;
+
+               area = simple_strtoul(buf, NULL, 10);
+               node = simple_strtoul(nodep, NULL, 10);
+
+               result = -EIO;
+               if ((area > 63)||(node > 1023))
+                       goto out;
+
+               dnaddr = cpu_to_le16((area << 10) | node);
+
+               result = -EFAULT;
+               if (put_user(dnaddr, (__le16 __user *)oldval))
+                       goto out;
+
+               copied = sizeof(dnaddr);
+       }
+
+       if (newval && newlen) {
+               loff_t pos = 0;
+               __le16 dnaddr;
+               char buf[15];
+               int len;
+
+               result = -EINVAL;
+               if (newlen != sizeof(dnaddr))
+                       goto out;
+
+               result = -EFAULT;
+               if (get_user(dnaddr, (__le16 __user *)newval))
+                       goto out;
+
+               len = snprintf(buf, sizeof(buf), "%hu.%hu",
+                               le16_to_cpu(dnaddr) >> 10,
+                               le16_to_cpu(dnaddr) & 0x3ff);
+
+               set_fs(KERNEL_DS);
+               result = vfs_write(file, buf, len, &pos);
+               set_fs(old_fs);
+               if (result < 0)
+                       goto out;
+       }
+
+       result = copied;
+out:
+       return result;
+}
+
+static const struct bin_table *get_sysctl(const int *name, int nlen, char *path)
+{
+       const struct bin_table *table = &bin_root_table[0];
+       int ctl_name;
+
+       /* The binary sysctl tables have a small maximum depth so
+        * there is no danger of overflowing our path as it PATH_MAX
+        * bytes long.
+        */
+       memcpy(path, "sys/", 4);
+       path += 4;
+
+repeat:
+       if (!nlen)
+               return ERR_PTR(-ENOTDIR);
+       ctl_name = *name;
+       name++;
+       nlen--;
+       for ( ; table->convert; table++) {
+               int len = 0;
+
+               /*
+                * For a wild card entry map from ifindex to network
+                * device name.
+                */
+               if (!table->ctl_name) {
+#ifdef CONFIG_NET
+                       struct net *net = current->nsproxy->net_ns;
+                       struct net_device *dev;
+                       dev = dev_get_by_index(net, ctl_name);
+                       if (dev) {
+                               len = strlen(dev->name);
+                               memcpy(path, dev->name, len);
+                               dev_put(dev);
+                       }
+#endif
+               /* Use the well known sysctl number to proc name mapping */
+               } else if (ctl_name == table->ctl_name) {
+                       len = strlen(table->procname);
+                       memcpy(path, table->procname, len);
+               }
+               if (len) {
+                       path += len;
+                       if (table->child) {
+                               *path++ = '/';
+                               table = table->child;
+                               goto repeat;
+                       }
+                       *path = '\0';
+                       return table;
+               }
+       }
+       return ERR_PTR(-ENOTDIR);
+}
+
+static char *sysctl_getname(const int *name, int nlen, const struct bin_table **tablep)
+{
+       char *tmp, *result;
+
+       result = ERR_PTR(-ENOMEM);
+       tmp = __getname();
+       if (tmp) {
+               const struct bin_table *table = get_sysctl(name, nlen, tmp);
+               result = tmp;
+               *tablep = table;
+               if (IS_ERR(table)) {
+                       __putname(tmp);
+                       result = ERR_CAST(table);
+               }
+       }
+       return result;
+}
+
+static ssize_t binary_sysctl(const int *name, int nlen,
+       void __user *oldval, size_t oldlen, void __user *newval, size_t newlen)
+{
+       const struct bin_table *table = NULL;
+       struct nameidata nd;
+       struct vfsmount *mnt;
+       struct file *file;
+       ssize_t result;
+       char *pathname;
+       int flags;
+       int acc_mode, fmode;
+
+       pathname = sysctl_getname(name, nlen, &table);
+       result = PTR_ERR(pathname);
+       if (IS_ERR(pathname))
+               goto out;
+
+       /* How should the sysctl be accessed? */
+       if (oldval && oldlen && newval && newlen) {
+               flags = O_RDWR;
+               acc_mode = MAY_READ | MAY_WRITE;
+               fmode = FMODE_READ | FMODE_WRITE;
+       } else if (newval && newlen) {
+               flags = O_WRONLY;
+               acc_mode = MAY_WRITE;
+               fmode = FMODE_WRITE;
+       } else if (oldval && oldlen) {
+               flags = O_RDONLY;
+               acc_mode = MAY_READ;
+               fmode = FMODE_READ;
+       } else {
+               result = 0;
+               goto out_putname;
+       }
+
+       mnt = current->nsproxy->pid_ns->proc_mnt;
+       result = vfs_path_lookup(mnt->mnt_root, mnt, pathname, 0, &nd);
+       if (result)
+               goto out_putname;
+
+       result = may_open(&nd.path, acc_mode, fmode);
+       if (result)
+               goto out_putpath;
+
+       file = dentry_open(nd.path.dentry, nd.path.mnt, flags, current_cred());
+       result = PTR_ERR(file);
+       if (IS_ERR(file))
+               goto out_putname;
+
+       result = table->convert(file, oldval, oldlen, newval, newlen);
+
+       fput(file);
+out_putname:
+       putname(pathname);
+out:
+       return result;
+
+out_putpath:
+       path_put(&nd.path);
+       goto out_putname;
+}
+
+
+#else /* CONFIG_SYSCTL_SYSCALL */
+
+static ssize_t binary_sysctl(const int *name, int nlen,
+       void __user *oldval, size_t oldlen, void __user *newval, size_t newlen)
+{
+       return -ENOSYS;
+}
+
+#endif /* CONFIG_SYSCTL_SYSCALL */
+
+
+static void deprecated_sysctl_warning(const int *name, int nlen)
+{
+       int i;
+
+       if (printk_ratelimit()) {
+               printk(KERN_INFO
+                       "warning: process `%s' used the deprecated sysctl "
+                       "system call with ", current->comm);
+               for (i = 0; i < nlen; i++)
+                       printk("%d.", name[i]);
+               printk("\n");
+       }
+       return;
+}
+
+static ssize_t do_sysctl(int __user *args_name, int nlen,
+       void __user *oldval, size_t oldlen, void __user *newval, size_t newlen)
+{
+       int name[CTL_MAXNAME];
+       int i;
+
+       /* Check args->nlen. */
+       if (nlen < 0 || nlen > CTL_MAXNAME)
+               return -ENOTDIR;
+       /* Read in the sysctl name for simplicity */
+       for (i = 0; i < nlen; i++)
+               if (get_user(name[i], args_name + i))
+                       return -EFAULT;
+
+       deprecated_sysctl_warning(name, nlen);
+
+       return binary_sysctl(name, nlen, oldval, oldlen, newval, newlen);
+}
+
+SYSCALL_DEFINE1(sysctl, struct __sysctl_args __user *, args)
+{
+       struct __sysctl_args tmp;
+       size_t oldlen = 0;
+       ssize_t result;
+
+       if (copy_from_user(&tmp, args, sizeof(tmp)))
+               return -EFAULT;
+
+       if (tmp.oldval && !tmp.oldlenp)
+               return -EFAULT;
+
+       if (tmp.oldlenp && get_user(oldlen, tmp.oldlenp))
+               return -EFAULT;
+
+       result = do_sysctl(tmp.name, tmp.nlen, tmp.oldval, oldlen,
+                          tmp.newval, tmp.newlen);
+
+       if (result >= 0) {
+               oldlen = result;
+               result = 0;
+       }
+
+       if (tmp.oldlenp && put_user(oldlen, tmp.oldlenp))
+               return -EFAULT;
+
+       return result;
+}
+
+
+#ifdef CONFIG_COMPAT
+#include <asm/compat.h>
+
+struct compat_sysctl_args {
+       compat_uptr_t   name;
+       int             nlen;
+       compat_uptr_t   oldval;
+       compat_uptr_t   oldlenp;
+       compat_uptr_t   newval;
+       compat_size_t   newlen;
+       compat_ulong_t  __unused[4];
+};
+
+asmlinkage long compat_sys_sysctl(struct compat_sysctl_args __user *args)
+{
+       struct compat_sysctl_args tmp;
+       compat_size_t __user *compat_oldlenp;
+       size_t oldlen = 0;
+       ssize_t result;
+
+       if (copy_from_user(&tmp, args, sizeof(tmp)))
+               return -EFAULT;
+
+       if (tmp.oldval && !tmp.oldlenp)
+               return -EFAULT;
+
+       compat_oldlenp = compat_ptr(tmp.oldlenp);
+       if (compat_oldlenp && get_user(oldlen, compat_oldlenp))
+               return -EFAULT;
+
+       result = do_sysctl(compat_ptr(tmp.name), tmp.nlen,
+                          compat_ptr(tmp.oldval), oldlen,
+                          compat_ptr(tmp.newval), tmp.newlen);
+
+       if (result >= 0) {
+               oldlen = result;
+               result = 0;
+       }
+
+       if (compat_oldlenp && put_user(oldlen, compat_oldlenp))
+               return -EFAULT;
+
+       return result;
+}
+
+#endif /* CONFIG_COMPAT */
index f1d676e..04cdcf7 100644 (file)
 #include <linux/string.h>
 #include <net/ip_vs.h>
 
-struct trans_ctl_table {
-       int                     ctl_name;
-       const char              *procname;
-       const struct trans_ctl_table *child;
-};
-
-static const struct trans_ctl_table trans_random_table[] = {
-       { RANDOM_POOLSIZE,      "poolsize" },
-       { RANDOM_ENTROPY_COUNT, "entropy_avail" },
-       { RANDOM_READ_THRESH,   "read_wakeup_threshold" },
-       { RANDOM_WRITE_THRESH,  "write_wakeup_threshold" },
-       { RANDOM_BOOT_ID,       "boot_id" },
-       { RANDOM_UUID,          "uuid" },
-       {}
-};
-
-static const struct trans_ctl_table trans_pty_table[] = {
-       { PTY_MAX,              "max" },
-       { PTY_NR,               "nr" },
-       {}
-};
-
-static const struct trans_ctl_table trans_kern_table[] = {
-       { KERN_OSTYPE,                  "ostype" },
-       { KERN_OSRELEASE,               "osrelease" },
-       /* KERN_OSREV not used */
-       { KERN_VERSION,                 "version" },
-       /* KERN_SECUREMASK not used */
-       /* KERN_PROF not used */
-       { KERN_NODENAME,                "hostname" },
-       { KERN_DOMAINNAME,              "domainname" },
-
-       { KERN_PANIC,                   "panic" },
-       { KERN_REALROOTDEV,             "real-root-dev" },
-
-       { KERN_SPARC_REBOOT,            "reboot-cmd" },
-       { KERN_CTLALTDEL,               "ctrl-alt-del" },
-       { KERN_PRINTK,                  "printk" },
-
-       /* KERN_NAMETRANS not used */
-       /* KERN_PPC_HTABRECLAIM not used */
-       /* KERN_PPC_ZEROPAGED not used */
-       { KERN_PPC_POWERSAVE_NAP,       "powersave-nap" },
-
-       { KERN_MODPROBE,                "modprobe" },
-       { KERN_SG_BIG_BUFF,             "sg-big-buff" },
-       { KERN_ACCT,                    "acct" },
-       { KERN_PPC_L2CR,                "l2cr" },
-
-       /* KERN_RTSIGNR not used */
-       /* KERN_RTSIGMAX not used */
-
-       { KERN_SHMMAX,                  "shmmax" },
-       { KERN_MSGMAX,                  "msgmax" },
-       { KERN_MSGMNB,                  "msgmnb" },
-       /* KERN_MSGPOOL not used*/
-       { KERN_SYSRQ,                   "sysrq" },
-       { KERN_MAX_THREADS,             "threads-max" },
-       { KERN_RANDOM,                  "random",       trans_random_table },
-       { KERN_SHMALL,                  "shmall" },
-       { KERN_MSGMNI,                  "msgmni" },
-       { KERN_SEM,                     "sem" },
-       { KERN_SPARC_STOP_A,            "stop-a" },
-       { KERN_SHMMNI,                  "shmmni" },
-
-       { KERN_OVERFLOWUID,             "overflowuid" },
-       { KERN_OVERFLOWGID,             "overflowgid" },
-
-       { KERN_HOTPLUG,                 "hotplug", },
-       { KERN_IEEE_EMULATION_WARNINGS, "ieee_emulation_warnings" },
-
-       { KERN_S390_USER_DEBUG_LOGGING, "userprocess_debug" },
-       { KERN_CORE_USES_PID,           "core_uses_pid" },
-       { KERN_TAINTED,                 "tainted" },
-       { KERN_CADPID,                  "cad_pid" },
-       { KERN_PIDMAX,                  "pid_max" },
-       { KERN_CORE_PATTERN,            "core_pattern" },
-       { KERN_PANIC_ON_OOPS,           "panic_on_oops" },
-       { KERN_HPPA_PWRSW,              "soft-power" },
-       { KERN_HPPA_UNALIGNED,          "unaligned-trap" },
-
-       { KERN_PRINTK_RATELIMIT,        "printk_ratelimit" },
-       { KERN_PRINTK_RATELIMIT_BURST,  "printk_ratelimit_burst" },
-
-       { KERN_PTY,                     "pty",          trans_pty_table },
-       { KERN_NGROUPS_MAX,             "ngroups_max" },
-       { KERN_SPARC_SCONS_PWROFF,      "scons-poweroff" },
-       { KERN_HZ_TIMER,                "hz_timer" },
-       { KERN_UNKNOWN_NMI_PANIC,       "unknown_nmi_panic" },
-       { KERN_BOOTLOADER_TYPE,         "bootloader_type" },
-       { KERN_RANDOMIZE,               "randomize_va_space" },
-
-       { KERN_SPIN_RETRY,              "spin_retry" },
-       { KERN_ACPI_VIDEO_FLAGS,        "acpi_video_flags" },
-       { KERN_IA64_UNALIGNED,          "ignore-unaligned-usertrap" },
-       { KERN_COMPAT_LOG,              "compat-log" },
-       { KERN_MAX_LOCK_DEPTH,          "max_lock_depth" },
-       { KERN_NMI_WATCHDOG,            "nmi_watchdog" },
-       { KERN_PANIC_ON_NMI,            "panic_on_unrecovered_nmi" },
-       {}
-};
-
-static const struct trans_ctl_table trans_vm_table[] = {
-       { VM_OVERCOMMIT_MEMORY,         "overcommit_memory" },
-       { VM_PAGE_CLUSTER,              "page-cluster" },
-       { VM_DIRTY_BACKGROUND,          "dirty_background_ratio" },
-       { VM_DIRTY_RATIO,               "dirty_ratio" },
-       { VM_DIRTY_WB_CS,               "dirty_writeback_centisecs" },
-       { VM_DIRTY_EXPIRE_CS,           "dirty_expire_centisecs" },
-       { VM_NR_PDFLUSH_THREADS,        "nr_pdflush_threads" },
-       { VM_OVERCOMMIT_RATIO,          "overcommit_ratio" },
-       /* VM_PAGEBUF unused */
-       { VM_HUGETLB_PAGES,             "nr_hugepages" },
-       { VM_SWAPPINESS,                "swappiness" },
-       { VM_LOWMEM_RESERVE_RATIO,      "lowmem_reserve_ratio" },
-       { VM_MIN_FREE_KBYTES,           "min_free_kbytes" },
-       { VM_MAX_MAP_COUNT,             "max_map_count" },
-       { VM_LAPTOP_MODE,               "laptop_mode" },
-       { VM_BLOCK_DUMP,                "block_dump" },
-       { VM_HUGETLB_GROUP,             "hugetlb_shm_group" },
-       { VM_VFS_CACHE_PRESSURE,        "vfs_cache_pressure" },
-       { VM_LEGACY_VA_LAYOUT,          "legacy_va_layout" },
-       /* VM_SWAP_TOKEN_TIMEOUT unused */
-       { VM_DROP_PAGECACHE,            "drop_caches" },
-       { VM_PERCPU_PAGELIST_FRACTION,  "percpu_pagelist_fraction" },
-       { VM_ZONE_RECLAIM_MODE,         "zone_reclaim_mode" },
-       { VM_MIN_UNMAPPED,              "min_unmapped_ratio" },
-       { VM_PANIC_ON_OOM,              "panic_on_oom" },
-       { VM_VDSO_ENABLED,              "vdso_enabled" },
-       { VM_MIN_SLAB,                  "min_slab_ratio" },
-
-       {}
-};
-
-static const struct trans_ctl_table trans_net_core_table[] = {
-       { NET_CORE_WMEM_MAX,            "wmem_max" },
-       { NET_CORE_RMEM_MAX,            "rmem_max" },
-       { NET_CORE_WMEM_DEFAULT,        "wmem_default" },
-       { NET_CORE_RMEM_DEFAULT,        "rmem_default" },
-       /* NET_CORE_DESTROY_DELAY unused */
-       { NET_CORE_MAX_BACKLOG,         "netdev_max_backlog" },
-       /* NET_CORE_FASTROUTE unused */
-       { NET_CORE_MSG_COST,            "message_cost" },
-       { NET_CORE_MSG_BURST,           "message_burst" },
-       { NET_CORE_OPTMEM_MAX,          "optmem_max" },
-       /* NET_CORE_HOT_LIST_LENGTH unused */
-       /* NET_CORE_DIVERT_VERSION unused */
-       /* NET_CORE_NO_CONG_THRESH unused */
-       /* NET_CORE_NO_CONG unused */
-       /* NET_CORE_LO_CONG unused */
-       /* NET_CORE_MOD_CONG unused */
-       { NET_CORE_DEV_WEIGHT,          "dev_weight" },
-       { NET_CORE_SOMAXCONN,           "somaxconn" },
-       { NET_CORE_BUDGET,              "netdev_budget" },
-       { NET_CORE_AEVENT_ETIME,        "xfrm_aevent_etime" },
-       { NET_CORE_AEVENT_RSEQTH,       "xfrm_aevent_rseqth" },
-       { NET_CORE_WARNINGS,            "warnings" },
-       {},
-};
-
-static const struct trans_ctl_table trans_net_unix_table[] = {
-       /* NET_UNIX_DESTROY_DELAY unused */
-       /* NET_UNIX_DELETE_DELAY unused */
-       { NET_UNIX_MAX_DGRAM_QLEN,      "max_dgram_qlen" },
-       {}
-};
-
-static const struct trans_ctl_table trans_net_ipv4_route_table[] = {
-       { NET_IPV4_ROUTE_FLUSH,                 "flush" },
-       { NET_IPV4_ROUTE_MIN_DELAY,             "min_delay" },
-       { NET_IPV4_ROUTE_MAX_DELAY,             "max_delay" },
-       { NET_IPV4_ROUTE_GC_THRESH,             "gc_thresh" },
-       { NET_IPV4_ROUTE_MAX_SIZE,              "max_size" },
-       { NET_IPV4_ROUTE_GC_MIN_INTERVAL,       "gc_min_interval" },
-       { NET_IPV4_ROUTE_GC_TIMEOUT,            "gc_timeout" },
-       { NET_IPV4_ROUTE_GC_INTERVAL,           "gc_interval" },
-       { NET_IPV4_ROUTE_REDIRECT_LOAD,         "redirect_load" },
-       { NET_IPV4_ROUTE_REDIRECT_NUMBER,       "redirect_number" },
-       { NET_IPV4_ROUTE_REDIRECT_SILENCE,      "redirect_silence" },
-       { NET_IPV4_ROUTE_ERROR_COST,            "error_cost" },
-       { NET_IPV4_ROUTE_ERROR_BURST,           "error_burst" },
-       { NET_IPV4_ROUTE_GC_ELASTICITY,         "gc_elasticity" },
-       { NET_IPV4_ROUTE_MTU_EXPIRES,           "mtu_expires" },
-       { NET_IPV4_ROUTE_MIN_PMTU,              "min_pmtu" },
-       { NET_IPV4_ROUTE_MIN_ADVMSS,            "min_adv_mss" },
-       { NET_IPV4_ROUTE_SECRET_INTERVAL,       "secret_interval" },
-       { NET_IPV4_ROUTE_GC_MIN_INTERVAL_MS,    "gc_min_interval_ms" },
-       {}
-};
-
-static const struct trans_ctl_table trans_net_ipv4_conf_vars_table[] = {
-       { NET_IPV4_CONF_FORWARDING,             "forwarding" },
-       { NET_IPV4_CONF_MC_FORWARDING,          "mc_forwarding" },
-
-       { NET_IPV4_CONF_PROXY_ARP,              "proxy_arp" },
-       { NET_IPV4_CONF_ACCEPT_REDIRECTS,       "accept_redirects" },
-       { NET_IPV4_CONF_SECURE_REDIRECTS,       "secure_redirects" },
-       { NET_IPV4_CONF_SEND_REDIRECTS,         "send_redirects" },
-       { NET_IPV4_CONF_SHARED_MEDIA,           "shared_media" },
-       { NET_IPV4_CONF_RP_FILTER,              "rp_filter" },
-       { NET_IPV4_CONF_ACCEPT_SOURCE_ROUTE,    "accept_source_route" },
-       { NET_IPV4_CONF_BOOTP_RELAY,            "bootp_relay" },
-       { NET_IPV4_CONF_LOG_MARTIANS,           "log_martians" },
-       { NET_IPV4_CONF_TAG,                    "tag" },
-       { NET_IPV4_CONF_ARPFILTER,              "arp_filter" },
-       { NET_IPV4_CONF_MEDIUM_ID,              "medium_id" },
-       { NET_IPV4_CONF_NOXFRM,                 "disable_xfrm" },
-       { NET_IPV4_CONF_NOPOLICY,               "disable_policy" },
-       { NET_IPV4_CONF_FORCE_IGMP_VERSION,     "force_igmp_version" },
-
-       { NET_IPV4_CONF_ARP_ANNOUNCE,           "arp_announce" },
-       { NET_IPV4_CONF_ARP_IGNORE,             "arp_ignore" },
-       { NET_IPV4_CONF_PROMOTE_SECONDARIES,    "promote_secondaries" },
-       { NET_IPV4_CONF_ARP_ACCEPT,             "arp_accept" },
-       { NET_IPV4_CONF_ARP_NOTIFY,             "arp_notify" },
-       { NET_IPV4_CONF_ACCEPT_LOCAL,           "accept_local" },
-       {}
-};
-
-static const struct trans_ctl_table trans_net_ipv4_conf_table[] = {
-       { NET_PROTO_CONF_ALL,           "all",          trans_net_ipv4_conf_vars_table },
-       { NET_PROTO_CONF_DEFAULT,       "default",      trans_net_ipv4_conf_vars_table },
-       { 0, NULL, trans_net_ipv4_conf_vars_table },
-       {}
-};
-
-static const struct trans_ctl_table trans_net_neigh_vars_table[] = {
-       { NET_NEIGH_MCAST_SOLICIT,      "mcast_solicit" },
-       { NET_NEIGH_UCAST_SOLICIT,      "ucast_solicit" },
-       { NET_NEIGH_APP_SOLICIT,        "app_solicit" },
-       { NET_NEIGH_RETRANS_TIME,       "retrans_time" },
-       { NET_NEIGH_REACHABLE_TIME,     "base_reachable_time" },
-       { NET_NEIGH_DELAY_PROBE_TIME,   "delay_first_probe_time" },
-       { NET_NEIGH_GC_STALE_TIME,      "gc_stale_time" },
-       { NET_NEIGH_UNRES_QLEN,         "unres_qlen" },
-       { NET_NEIGH_PROXY_QLEN,         "proxy_qlen" },
-       { NET_NEIGH_ANYCAST_DELAY,      "anycast_delay" },
-       { NET_NEIGH_PROXY_DELAY,        "proxy_delay" },
-       { NET_NEIGH_LOCKTIME,           "locktime" },
-       { NET_NEIGH_GC_INTERVAL,        "gc_interval" },
-       { NET_NEIGH_GC_THRESH1,         "gc_thresh1" },
-       { NET_NEIGH_GC_THRESH2,         "gc_thresh2" },
-       { NET_NEIGH_GC_THRESH3,         "gc_thresh3" },
-       { NET_NEIGH_RETRANS_TIME_MS,    "retrans_time_ms" },
-       { NET_NEIGH_REACHABLE_TIME_MS,  "base_reachable_time_ms" },
-       {}
-};
-
-static const struct trans_ctl_table trans_net_neigh_table[] = {
-       { NET_PROTO_CONF_DEFAULT, "default", trans_net_neigh_vars_table },
-       { 0, NULL, trans_net_neigh_vars_table },
-       {}
-};
-
-static const struct trans_ctl_table trans_net_ipv4_netfilter_table[] = {
-       { NET_IPV4_NF_CONNTRACK_MAX,                            "ip_conntrack_max" },
-
-       { NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_SYN_SENT,           "ip_conntrack_tcp_timeout_syn_sent" },
-       { NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_SYN_RECV,           "ip_conntrack_tcp_timeout_syn_recv" },
-       { NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_ESTABLISHED,        "ip_conntrack_tcp_timeout_established" },
-       { NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_FIN_WAIT,           "ip_conntrack_tcp_timeout_fin_wait" },
-       { NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_CLOSE_WAIT,         "ip_conntrack_tcp_timeout_close_wait" },
-       { NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_LAST_ACK,           "ip_conntrack_tcp_timeout_last_ack" },
-       { NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_TIME_WAIT,          "ip_conntrack_tcp_timeout_time_wait" },
-       { NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_CLOSE,              "ip_conntrack_tcp_timeout_close" },
-
-       { NET_IPV4_NF_CONNTRACK_UDP_TIMEOUT,                    "ip_conntrack_udp_timeout" },
-       { NET_IPV4_NF_CONNTRACK_UDP_TIMEOUT_STREAM,             "ip_conntrack_udp_timeout_stream" },
-       { NET_IPV4_NF_CONNTRACK_ICMP_TIMEOUT,                   "ip_conntrack_icmp_timeout" },
-       { NET_IPV4_NF_CONNTRACK_GENERIC_TIMEOUT,                "ip_conntrack_generic_timeout" },
-
-       { NET_IPV4_NF_CONNTRACK_BUCKETS,                        "ip_conntrack_buckets" },
-       { NET_IPV4_NF_CONNTRACK_LOG_INVALID,                    "ip_conntrack_log_invalid" },
-       { NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_MAX_RETRANS,        "ip_conntrack_tcp_timeout_max_retrans" },
-       { NET_IPV4_NF_CONNTRACK_TCP_LOOSE,                      "ip_conntrack_tcp_loose" },
-       { NET_IPV4_NF_CONNTRACK_TCP_BE_LIBERAL,                 "ip_conntrack_tcp_be_liberal" },
-       { NET_IPV4_NF_CONNTRACK_TCP_MAX_RETRANS,                "ip_conntrack_tcp_max_retrans" },
-
-       { NET_IPV4_NF_CONNTRACK_SCTP_TIMEOUT_CLOSED,            "ip_conntrack_sctp_timeout_closed" },
-       { NET_IPV4_NF_CONNTRACK_SCTP_TIMEOUT_COOKIE_WAIT,       "ip_conntrack_sctp_timeout_cookie_wait" },
-       { NET_IPV4_NF_CONNTRACK_SCTP_TIMEOUT_COOKIE_ECHOED,     "ip_conntrack_sctp_timeout_cookie_echoed" },
-       { NET_IPV4_NF_CONNTRACK_SCTP_TIMEOUT_ESTABLISHED,       "ip_conntrack_sctp_timeout_established" },
-       { NET_IPV4_NF_CONNTRACK_SCTP_TIMEOUT_SHUTDOWN_SENT,     "ip_conntrack_sctp_timeout_shutdown_sent" },
-       { NET_IPV4_NF_CONNTRACK_SCTP_TIMEOUT_SHUTDOWN_RECD,     "ip_conntrack_sctp_timeout_shutdown_recd" },
-       { NET_IPV4_NF_CONNTRACK_SCTP_TIMEOUT_SHUTDOWN_ACK_SENT, "ip_conntrack_sctp_timeout_shutdown_ack_sent" },
-
-       { NET_IPV4_NF_CONNTRACK_COUNT,          "ip_conntrack_count" },
-       { NET_IPV4_NF_CONNTRACK_CHECKSUM,       "ip_conntrack_checksum" },
-       {}
-};
-
-static const struct trans_ctl_table trans_net_ipv4_table[] = {
-       { NET_IPV4_FORWARD,                     "ip_forward" },
-       { NET_IPV4_DYNADDR,                     "ip_dynaddr" },
-
-       { NET_IPV4_CONF,                "conf",         trans_net_ipv4_conf_table },
-       { NET_IPV4_NEIGH,               "neigh",        trans_net_neigh_table },
-       { NET_IPV4_ROUTE,               "route",        trans_net_ipv4_route_table },
-       /* NET_IPV4_FIB_HASH unused */
-       { NET_IPV4_NETFILTER,           "netfilter",    trans_net_ipv4_netfilter_table },
-
-       { NET_IPV4_TCP_TIMESTAMPS,              "tcp_timestamps" },
-       { NET_IPV4_TCP_WINDOW_SCALING,          "tcp_window_scaling" },
-       { NET_IPV4_TCP_SACK,                    "tcp_sack" },
-       { NET_IPV4_TCP_RETRANS_COLLAPSE,        "tcp_retrans_collapse" },
-       { NET_IPV4_DEFAULT_TTL,                 "ip_default_ttl" },
-       /* NET_IPV4_AUTOCONFIG unused */
-       { NET_IPV4_NO_PMTU_DISC,                "ip_no_pmtu_disc" },
-       { NET_IPV4_TCP_SYN_RETRIES,             "tcp_syn_retries" },
-       { NET_IPV4_IPFRAG_HIGH_THRESH,          "ipfrag_high_thresh" },
-       { NET_IPV4_IPFRAG_LOW_THRESH,           "ipfrag_low_thresh" },
-       { NET_IPV4_IPFRAG_TIME,                 "ipfrag_time" },
-       /* NET_IPV4_TCP_MAX_KA_PROBES unused */
-       { NET_IPV4_TCP_KEEPALIVE_TIME,          "tcp_keepalive_time" },
-       { NET_IPV4_TCP_KEEPALIVE_PROBES,        "tcp_keepalive_probes" },
-       { NET_IPV4_TCP_RETRIES1,                "tcp_retries1" },
-       { NET_IPV4_TCP_RETRIES2,                "tcp_retries2" },
-       { NET_IPV4_TCP_FIN_TIMEOUT,             "tcp_fin_timeout" },
-       /* NET_IPV4_IP_MASQ_DEBUG unused */
-       { NET_TCP_SYNCOOKIES,                   "tcp_syncookies" },
-       { NET_TCP_STDURG,                       "tcp_stdurg" },
-       { NET_TCP_RFC1337,                      "tcp_rfc1337" },
-       /* NET_TCP_SYN_TAILDROP unused */
-       { NET_TCP_MAX_SYN_BACKLOG,              "tcp_max_syn_backlog" },
-       { NET_IPV4_LOCAL_PORT_RANGE,            "ip_local_port_range" },
-       { NET_IPV4_ICMP_ECHO_IGNORE_ALL,        "icmp_echo_ignore_all" },
-       { NET_IPV4_ICMP_ECHO_IGNORE_BROADCASTS, "icmp_echo_ignore_broadcasts" },
-       /* NET_IPV4_ICMP_SOURCEQUENCH_RATE unused */
-       /* NET_IPV4_ICMP_DESTUNREACH_RATE unused */
-       /* NET_IPV4_ICMP_TIMEEXCEED_RATE unused */
-       /* NET_IPV4_ICMP_PARAMPROB_RATE unused */
-       /* NET_IPV4_ICMP_ECHOREPLY_RATE unused */
-       { NET_IPV4_ICMP_IGNORE_BOGUS_ERROR_RESPONSES,   "icmp_ignore_bogus_error_responses" },
-       { NET_IPV4_IGMP_MAX_MEMBERSHIPS,        "igmp_max_memberships" },
-       { NET_TCP_TW_RECYCLE,                   "tcp_tw_recycle" },
-       /* NET_IPV4_ALWAYS_DEFRAG unused */
-       { NET_IPV4_TCP_KEEPALIVE_INTVL,         "tcp_keepalive_intvl" },
-       { NET_IPV4_INET_PEER_THRESHOLD,         "inet_peer_threshold" },
-       { NET_IPV4_INET_PEER_MINTTL,            "inet_peer_minttl" },
-       { NET_IPV4_INET_PEER_MAXTTL,            "inet_peer_maxttl" },
-       { NET_IPV4_INET_PEER_GC_MINTIME,        "inet_peer_gc_mintime" },
-       { NET_IPV4_INET_PEER_GC_MAXTIME,        "inet_peer_gc_maxtime" },
-       { NET_TCP_ORPHAN_RETRIES,               "tcp_orphan_retries" },
-       { NET_TCP_ABORT_ON_OVERFLOW,            "tcp_abort_on_overflow" },
-       { NET_TCP_SYNACK_RETRIES,               "tcp_synack_retries" },
-       { NET_TCP_MAX_ORPHANS,                  "tcp_max_orphans" },
-       { NET_TCP_MAX_TW_BUCKETS,               "tcp_max_tw_buckets" },
-       { NET_TCP_FACK,                         "tcp_fack" },
-       { NET_TCP_REORDERING,                   "tcp_reordering" },
-       { NET_TCP_ECN,                          "tcp_ecn" },
-       { NET_TCP_DSACK,                        "tcp_dsack" },
-       { NET_TCP_MEM,                          "tcp_mem" },
-       { NET_TCP_WMEM,                         "tcp_wmem" },
-       { NET_TCP_RMEM,                         "tcp_rmem" },
-       { NET_TCP_APP_WIN,                      "tcp_app_win" },
-       { NET_TCP_ADV_WIN_SCALE,                "tcp_adv_win_scale" },
-       { NET_IPV4_NONLOCAL_BIND,               "ip_nonlocal_bind" },
-       { NET_IPV4_ICMP_RATELIMIT,              "icmp_ratelimit" },
-       { NET_IPV4_ICMP_RATEMASK,               "icmp_ratemask" },
-       { NET_TCP_TW_REUSE,                     "tcp_tw_reuse" },
-       { NET_TCP_FRTO,                         "tcp_frto" },
-       { NET_TCP_LOW_LATENCY,                  "tcp_low_latency" },
-       { NET_IPV4_IPFRAG_SECRET_INTERVAL,      "ipfrag_secret_interval" },
-       { NET_IPV4_IGMP_MAX_MSF,                "igmp_max_msf" },
-       { NET_TCP_NO_METRICS_SAVE,              "tcp_no_metrics_save" },
-       /* NET_TCP_DEFAULT_WIN_SCALE unused */
-       { NET_TCP_MODERATE_RCVBUF,              "tcp_moderate_rcvbuf" },
-       { NET_TCP_TSO_WIN_DIVISOR,              "tcp_tso_win_divisor" },
-       /* NET_TCP_BIC_BETA unused */
-       { NET_IPV4_ICMP_ERRORS_USE_INBOUND_IFADDR,      "icmp_errors_use_inbound_ifaddr" },
-       { NET_TCP_CONG_CONTROL,                 "tcp_congestion_control" },
-       { NET_TCP_ABC,                          "tcp_abc" },
-       { NET_IPV4_IPFRAG_MAX_DIST,             "ipfrag_max_dist" },
-       { NET_TCP_MTU_PROBING,                  "tcp_mtu_probing" },
-       { NET_TCP_BASE_MSS,                     "tcp_base_mss" },
-       { NET_IPV4_TCP_WORKAROUND_SIGNED_WINDOWS,       "tcp_workaround_signed_windows" },
-       { NET_TCP_DMA_COPYBREAK,                "tcp_dma_copybreak" },
-       { NET_TCP_SLOW_START_AFTER_IDLE,        "tcp_slow_start_after_idle" },
-       { NET_CIPSOV4_CACHE_ENABLE,             "cipso_cache_enable" },
-       { NET_CIPSOV4_CACHE_BUCKET_SIZE,        "cipso_cache_bucket_size" },
-       { NET_CIPSOV4_RBM_OPTFMT,               "cipso_rbm_optfmt" },
-       { NET_CIPSOV4_RBM_STRICTVALID,          "cipso_rbm_strictvalid" },
-       { NET_TCP_AVAIL_CONG_CONTROL,           "tcp_available_congestion_control" },
-       { NET_TCP_ALLOWED_CONG_CONTROL,         "tcp_allowed_congestion_control" },
-       { NET_TCP_MAX_SSTHRESH,                 "tcp_max_ssthresh" },
-       { NET_TCP_FRTO_RESPONSE,                "tcp_frto_response" },
-       { 2088 /* NET_IPQ_QMAX */,              "ip_queue_maxlen" },
-       {}
-};
-
-static const struct trans_ctl_table trans_net_ipx_table[] = {
-       { NET_IPX_PPROP_BROADCASTING,   "ipx_pprop_broadcasting" },
-       /* NET_IPX_FORWARDING unused */
-       {}
-};
-
-static const struct trans_ctl_table trans_net_atalk_table[] = {
-       { NET_ATALK_AARP_EXPIRY_TIME,           "aarp-expiry-time" },
-       { NET_ATALK_AARP_TICK_TIME,             "aarp-tick-time" },
-       { NET_ATALK_AARP_RETRANSMIT_LIMIT,      "aarp-retransmit-limit" },
-       { NET_ATALK_AARP_RESOLVE_TIME,          "aarp-resolve-time" },
-       {},
-};
-
-static const struct trans_ctl_table trans_net_netrom_table[] = {
-       { NET_NETROM_DEFAULT_PATH_QUALITY,              "default_path_quality" },
-       { NET_NETROM_OBSOLESCENCE_COUNT_INITIALISER,    "obsolescence_count_initialiser" },
-       { NET_NETROM_NETWORK_TTL_INITIALISER,           "network_ttl_initialiser" },
-       { NET_NETROM_TRANSPORT_TIMEOUT,                 "transport_timeout" },
-       { NET_NETROM_TRANSPORT_MAXIMUM_TRIES,           "transport_maximum_tries" },
-       { NET_NETROM_TRANSPORT_ACKNOWLEDGE_DELAY,       "transport_acknowledge_delay" },
-       { NET_NETROM_TRANSPORT_BUSY_DELAY,              "transport_busy_delay" },
-       { NET_NETROM_TRANSPORT_REQUESTED_WINDOW_SIZE,   "transport_requested_window_size" },
-       { NET_NETROM_TRANSPORT_NO_ACTIVITY_TIMEOUT,     "transport_no_activity_timeout" },
-       { NET_NETROM_ROUTING_CONTROL,                   "routing_control" },
-       { NET_NETROM_LINK_FAILS_COUNT,                  "link_fails_count" },
-       { NET_NETROM_RESET,                             "reset" },
-       {}
-};
-
-static const struct trans_ctl_table trans_net_ax25_param_table[] = {
-       { NET_AX25_IP_DEFAULT_MODE,     "ip_default_mode" },
-       { NET_AX25_DEFAULT_MODE,        "ax25_default_mode" },
-       { NET_AX25_BACKOFF_TYPE,        "backoff_type" },
-       { NET_AX25_CONNECT_MODE,        "connect_mode" },
-       { NET_AX25_STANDARD_WINDOW,     "standard_window_size" },
-       { NET_AX25_EXTENDED_WINDOW,     "extended_window_size" },
-       { NET_AX25_T1_TIMEOUT,          "t1_timeout" },
-       { NET_AX25_T2_TIMEOUT,          "t2_timeout" },
-       { NET_AX25_T3_TIMEOUT,          "t3_timeout" },
-       { NET_AX25_IDLE_TIMEOUT,        "idle_timeout" },
-       { NET_AX25_N2,                  "maximum_retry_count" },
-       { NET_AX25_PACLEN,              "maximum_packet_length" },
-       { NET_AX25_PROTOCOL,            "protocol" },
-       { NET_AX25_DAMA_SLAVE_TIMEOUT,  "dama_slave_timeout" },
-       {}
-};
-
-static const struct trans_ctl_table trans_net_ax25_table[] = {
-       { 0, NULL, trans_net_ax25_param_table },
-       {}
-};
-
-static const struct trans_ctl_table trans_net_bridge_table[] = {
-       { NET_BRIDGE_NF_CALL_ARPTABLES,         "bridge-nf-call-arptables" },
-       { NET_BRIDGE_NF_CALL_IPTABLES,          "bridge-nf-call-iptables" },
-       { NET_BRIDGE_NF_CALL_IP6TABLES,         "bridge-nf-call-ip6tables" },
-       { NET_BRIDGE_NF_FILTER_VLAN_TAGGED,     "bridge-nf-filter-vlan-tagged" },
-       { NET_BRIDGE_NF_FILTER_PPPOE_TAGGED,    "bridge-nf-filter-pppoe-tagged" },
-       {}
-};
-
-static const struct trans_ctl_table trans_net_rose_table[] = {
-       { NET_ROSE_RESTART_REQUEST_TIMEOUT,     "restart_request_timeout" },
-       { NET_ROSE_CALL_REQUEST_TIMEOUT,        "call_request_timeout" },
-       { NET_ROSE_RESET_REQUEST_TIMEOUT,       "reset_request_timeout" },
-       { NET_ROSE_CLEAR_REQUEST_TIMEOUT,       "clear_request_timeout" },
-       { NET_ROSE_ACK_HOLD_BACK_TIMEOUT,       "acknowledge_hold_back_timeout" },
-       { NET_ROSE_ROUTING_CONTROL,             "routing_control" },
-       { NET_ROSE_LINK_FAIL_TIMEOUT,           "link_fail_timeout" },
-       { NET_ROSE_MAX_VCS,                     "maximum_virtual_circuits" },
-       { NET_ROSE_WINDOW_SIZE,                 "window_size" },
-       { NET_ROSE_NO_ACTIVITY_TIMEOUT,         "no_activity_timeout" },
-       {}
-};
-
-static const struct trans_ctl_table trans_net_ipv6_conf_var_table[] = {
-       { NET_IPV6_FORWARDING,                  "forwarding" },
-       { NET_IPV6_HOP_LIMIT,                   "hop_limit" },
-       { NET_IPV6_MTU,                         "mtu" },
-       { NET_IPV6_ACCEPT_RA,                   "accept_ra" },
-       { NET_IPV6_ACCEPT_REDIRECTS,            "accept_redirects" },
-       { NET_IPV6_AUTOCONF,                    "autoconf" },
-       { NET_IPV6_DAD_TRANSMITS,               "dad_transmits" },
-       { NET_IPV6_RTR_SOLICITS,                "router_solicitations" },
-       { NET_IPV6_RTR_SOLICIT_INTERVAL,        "router_solicitation_interval" },
-       { NET_IPV6_RTR_SOLICIT_DELAY,           "router_solicitation_delay" },
-       { NET_IPV6_USE_TEMPADDR,                "use_tempaddr" },
-       { NET_IPV6_TEMP_VALID_LFT,              "temp_valid_lft" },
-       { NET_IPV6_TEMP_PREFERED_LFT,           "temp_prefered_lft" },
-       { NET_IPV6_REGEN_MAX_RETRY,             "regen_max_retry" },
-       { NET_IPV6_MAX_DESYNC_FACTOR,           "max_desync_factor" },
-       { NET_IPV6_MAX_ADDRESSES,               "max_addresses" },
-       { NET_IPV6_FORCE_MLD_VERSION,           "force_mld_version" },
-       { NET_IPV6_ACCEPT_RA_DEFRTR,            "accept_ra_defrtr" },
-       { NET_IPV6_ACCEPT_RA_PINFO,             "accept_ra_pinfo" },
-       { NET_IPV6_ACCEPT_RA_RTR_PREF,          "accept_ra_rtr_pref" },
-       { NET_IPV6_RTR_PROBE_INTERVAL,          "router_probe_interval" },
-       { NET_IPV6_ACCEPT_RA_RT_INFO_MAX_PLEN,  "accept_ra_rt_info_max_plen" },
-       { NET_IPV6_PROXY_NDP,                   "proxy_ndp" },
-       { NET_IPV6_ACCEPT_SOURCE_ROUTE,         "accept_source_route" },
-       {}
-};
-
-static const struct trans_ctl_table trans_net_ipv6_conf_table[] = {
-       { NET_PROTO_CONF_ALL,           "all",  trans_net_ipv6_conf_var_table },
-       { NET_PROTO_CONF_DEFAULT,       "default", trans_net_ipv6_conf_var_table },
-       { 0, NULL, trans_net_ipv6_conf_var_table },
-       {}
-};
-
-static const struct trans_ctl_table trans_net_ipv6_route_table[] = {
-       { NET_IPV6_ROUTE_FLUSH,                 "flush" },
-       { NET_IPV6_ROUTE_GC_THRESH,             "gc_thresh" },
-       { NET_IPV6_ROUTE_MAX_SIZE,              "max_size" },
-       { NET_IPV6_ROUTE_GC_MIN_INTERVAL,       "gc_min_interval" },
-       { NET_IPV6_ROUTE_GC_TIMEOUT,            "gc_timeout" },
-       { NET_IPV6_ROUTE_GC_INTERVAL,           "gc_interval" },
-       { NET_IPV6_ROUTE_GC_ELASTICITY,         "gc_elasticity" },
-       { NET_IPV6_ROUTE_MTU_EXPIRES,           "mtu_expires" },
-       { NET_IPV6_ROUTE_MIN_ADVMSS,            "min_adv_mss" },
-       { NET_IPV6_ROUTE_GC_MIN_INTERVAL_MS,    "gc_min_interval_ms" },
-       {}
-};
-
-static const struct trans_ctl_table trans_net_ipv6_icmp_table[] = {
-       { NET_IPV6_ICMP_RATELIMIT,      "ratelimit" },
-       {}
-};
-
-static const struct trans_ctl_table trans_net_ipv6_table[] = {
-       { NET_IPV6_CONF,                "conf",         trans_net_ipv6_conf_table },
-       { NET_IPV6_NEIGH,               "neigh",        trans_net_neigh_table },
-       { NET_IPV6_ROUTE,               "route",        trans_net_ipv6_route_table },
-       { NET_IPV6_ICMP,                "icmp",         trans_net_ipv6_icmp_table },
-       { NET_IPV6_BINDV6ONLY,          "bindv6only" },
-       { NET_IPV6_IP6FRAG_HIGH_THRESH, "ip6frag_high_thresh" },
-       { NET_IPV6_IP6FRAG_LOW_THRESH,  "ip6frag_low_thresh" },
-       { NET_IPV6_IP6FRAG_TIME,        "ip6frag_time" },
-       { NET_IPV6_IP6FRAG_SECRET_INTERVAL,     "ip6frag_secret_interval" },
-       { NET_IPV6_MLD_MAX_MSF,         "mld_max_msf" },
-       { 2088 /* IPQ_QMAX */,          "ip6_queue_maxlen" },
-       {}
-};
-
-static const struct trans_ctl_table trans_net_x25_table[] = {
-       { NET_X25_RESTART_REQUEST_TIMEOUT,      "restart_request_timeout" },
-       { NET_X25_CALL_REQUEST_TIMEOUT,         "call_request_timeout" },
-       { NET_X25_RESET_REQUEST_TIMEOUT,        "reset_request_timeout" },
-       { NET_X25_CLEAR_REQUEST_TIMEOUT,        "clear_request_timeout" },
-       { NET_X25_ACK_HOLD_BACK_TIMEOUT,        "acknowledgement_hold_back_timeout" },
-       { NET_X25_FORWARD,                      "x25_forward" },
-       {}
-};
-
-static const struct trans_ctl_table trans_net_tr_table[] = {
-       { NET_TR_RIF_TIMEOUT,   "rif_timeout" },
-       {}
-};
-
-
-static const struct trans_ctl_table trans_net_decnet_conf_vars[] = {
-       { NET_DECNET_CONF_DEV_FORWARDING,       "forwarding" },
-       { NET_DECNET_CONF_DEV_PRIORITY,         "priority" },
-       { NET_DECNET_CONF_DEV_T2,               "t2" },
-       { NET_DECNET_CONF_DEV_T3,               "t3" },
-       {}
-};
-
-static const struct trans_ctl_table trans_net_decnet_conf[] = {
-       { 0, NULL, trans_net_decnet_conf_vars },
-       {}
-};
-
-static const struct trans_ctl_table trans_net_decnet_table[] = {
-       { NET_DECNET_CONF,              "conf", trans_net_decnet_conf },
-       { NET_DECNET_NODE_ADDRESS,      "node_address" },
-       { NET_DECNET_NODE_NAME,         "node_name" },
-       { NET_DECNET_DEFAULT_DEVICE,    "default_device" },
-       { NET_DECNET_TIME_WAIT,         "time_wait" },
-       { NET_DECNET_DN_COUNT,          "dn_count" },
-       { NET_DECNET_DI_COUNT,          "di_count" },
-       { NET_DECNET_DR_COUNT,          "dr_count" },
-       { NET_DECNET_DST_GC_INTERVAL,   "dst_gc_interval" },
-       { NET_DECNET_NO_FC_MAX_CWND,    "no_fc_max_cwnd" },
-       { NET_DECNET_MEM,               "decnet_mem" },
-       { NET_DECNET_RMEM,              "decnet_rmem" },
-       { NET_DECNET_WMEM,              "decnet_wmem" },
-       { NET_DECNET_DEBUG_LEVEL,       "debug" },
-       {}
-};
-
-static const struct trans_ctl_table trans_net_sctp_table[] = {
-       { NET_SCTP_RTO_INITIAL,         "rto_initial" },
-       { NET_SCTP_RTO_MIN,             "rto_min" },
-       { NET_SCTP_RTO_MAX,             "rto_max" },
-       { NET_SCTP_RTO_ALPHA,           "rto_alpha_exp_divisor" },
-       { NET_SCTP_RTO_BETA,            "rto_beta_exp_divisor" },
-       { NET_SCTP_VALID_COOKIE_LIFE,   "valid_cookie_life" },
-       { NET_SCTP_ASSOCIATION_MAX_RETRANS,     "association_max_retrans" },
-       { NET_SCTP_PATH_MAX_RETRANS,    "path_max_retrans" },
-       { NET_SCTP_MAX_INIT_RETRANSMITS,        "max_init_retransmits" },
-       { NET_SCTP_HB_INTERVAL,         "hb_interval" },
-       { NET_SCTP_PRESERVE_ENABLE,     "cookie_preserve_enable" },
-       { NET_SCTP_MAX_BURST,           "max_burst" },
-       { NET_SCTP_ADDIP_ENABLE,        "addip_enable" },
-       { NET_SCTP_PRSCTP_ENABLE,       "prsctp_enable" },
-       { NET_SCTP_SNDBUF_POLICY,       "sndbuf_policy" },
-       { NET_SCTP_SACK_TIMEOUT,        "sack_timeout" },
-       { NET_SCTP_RCVBUF_POLICY,       "rcvbuf_policy" },
-       {}
-};
-
-static const struct trans_ctl_table trans_net_llc_llc2_timeout_table[] = {
-       { NET_LLC2_ACK_TIMEOUT,         "ack" },
-       { NET_LLC2_P_TIMEOUT,           "p" },
-       { NET_LLC2_REJ_TIMEOUT,         "rej" },
-       { NET_LLC2_BUSY_TIMEOUT,        "busy" },
-       {}
-};
-
-static const struct trans_ctl_table trans_net_llc_station_table[] = {
-       { NET_LLC_STATION_ACK_TIMEOUT,  "ack_timeout" },
-       {}
-};
-
-static const struct trans_ctl_table trans_net_llc_llc2_table[] = {
-       { NET_LLC2,             "timeout",      trans_net_llc_llc2_timeout_table },
-       {}
-};
-
-static const struct trans_ctl_table trans_net_llc_table[] = {
-       { NET_LLC2,             "llc2",         trans_net_llc_llc2_table },
-       { NET_LLC_STATION,      "station",      trans_net_llc_station_table },
-       {}
-};
-
-static const struct trans_ctl_table trans_net_netfilter_table[] = {
-       { NET_NF_CONNTRACK_MAX,                         "nf_conntrack_max" },
-       { NET_NF_CONNTRACK_TCP_TIMEOUT_SYN_SENT,        "nf_conntrack_tcp_timeout_syn_sent" },
-       { NET_NF_CONNTRACK_TCP_TIMEOUT_SYN_RECV,        "nf_conntrack_tcp_timeout_syn_recv" },
-       { NET_NF_CONNTRACK_TCP_TIMEOUT_ESTABLISHED,     "nf_conntrack_tcp_timeout_established" },
-       { NET_NF_CONNTRACK_TCP_TIMEOUT_FIN_WAIT,        "nf_conntrack_tcp_timeout_fin_wait" },
-       { NET_NF_CONNTRACK_TCP_TIMEOUT_CLOSE_WAIT,      "nf_conntrack_tcp_timeout_close_wait" },
-       { NET_NF_CONNTRACK_TCP_TIMEOUT_LAST_ACK,        "nf_conntrack_tcp_timeout_last_ack" },
-       { NET_NF_CONNTRACK_TCP_TIMEOUT_TIME_WAIT,       "nf_conntrack_tcp_timeout_time_wait" },
-       { NET_NF_CONNTRACK_TCP_TIMEOUT_CLOSE,           "nf_conntrack_tcp_timeout_close" },
-       { NET_NF_CONNTRACK_UDP_TIMEOUT,                 "nf_conntrack_udp_timeout" },
-       { NET_NF_CONNTRACK_UDP_TIMEOUT_STREAM,          "nf_conntrack_udp_timeout_stream" },
-       { NET_NF_CONNTRACK_ICMP_TIMEOUT,        "nf_conntrack_icmp_timeout" },
-       { NET_NF_CONNTRACK_GENERIC_TIMEOUT,             "nf_conntrack_generic_timeout" },
-       { NET_NF_CONNTRACK_BUCKETS,                     "nf_conntrack_buckets" },
-       { NET_NF_CONNTRACK_LOG_INVALID,                 "nf_conntrack_log_invalid" },
-       { NET_NF_CONNTRACK_TCP_TIMEOUT_MAX_RETRANS,     "nf_conntrack_tcp_timeout_max_retrans" },
-       { NET_NF_CONNTRACK_TCP_LOOSE,                   "nf_conntrack_tcp_loose" },
-       { NET_NF_CONNTRACK_TCP_BE_LIBERAL,              "nf_conntrack_tcp_be_liberal" },
-       { NET_NF_CONNTRACK_TCP_MAX_RETRANS,             "nf_conntrack_tcp_max_retrans" },
-       { NET_NF_CONNTRACK_SCTP_TIMEOUT_CLOSED,         "nf_conntrack_sctp_timeout_closed" },
-       { NET_NF_CONNTRACK_SCTP_TIMEOUT_COOKIE_WAIT,    "nf_conntrack_sctp_timeout_cookie_wait" },
-       { NET_NF_CONNTRACK_SCTP_TIMEOUT_COOKIE_ECHOED,  "nf_conntrack_sctp_timeout_cookie_echoed" },
-       { NET_NF_CONNTRACK_SCTP_TIMEOUT_ESTABLISHED,    "nf_conntrack_sctp_timeout_established" },
-       { NET_NF_CONNTRACK_SCTP_TIMEOUT_SHUTDOWN_SENT,  "nf_conntrack_sctp_timeout_shutdown_sent" },
-       { NET_NF_CONNTRACK_SCTP_TIMEOUT_SHUTDOWN_RECD,  "nf_conntrack_sctp_timeout_shutdown_recd" },
-       { NET_NF_CONNTRACK_SCTP_TIMEOUT_SHUTDOWN_ACK_SENT,      "nf_conntrack_sctp_timeout_shutdown_ack_sent" },
-       { NET_NF_CONNTRACK_COUNT,                       "nf_conntrack_count" },
-       { NET_NF_CONNTRACK_ICMPV6_TIMEOUT,      "nf_conntrack_icmpv6_timeout" },
-       { NET_NF_CONNTRACK_FRAG6_TIMEOUT,               "nf_conntrack_frag6_timeout" },
-       { NET_NF_CONNTRACK_FRAG6_LOW_THRESH,            "nf_conntrack_frag6_low_thresh" },
-       { NET_NF_CONNTRACK_FRAG6_HIGH_THRESH,           "nf_conntrack_frag6_high_thresh" },
-       { NET_NF_CONNTRACK_CHECKSUM,                    "nf_conntrack_checksum" },
-
-       {}
-};
-
-static const struct trans_ctl_table trans_net_dccp_table[] = {
-       { NET_DCCP_DEFAULT,     "default" },
-       {}
-};
-
-static const struct trans_ctl_table trans_net_irda_table[] = {
-       { NET_IRDA_DISCOVERY,           "discovery" },
-       { NET_IRDA_DEVNAME,             "devname" },
-       { NET_IRDA_DEBUG,               "debug" },
-       { NET_IRDA_FAST_POLL,           "fast_poll_increase" },
-       { NET_IRDA_DISCOVERY_SLOTS,     "discovery_slots" },
-       { NET_IRDA_DISCOVERY_TIMEOUT,   "discovery_timeout" },
-       { NET_IRDA_SLOT_TIMEOUT,        "slot_timeout" },
-       { NET_IRDA_MAX_BAUD_RATE,       "max_baud_rate" },
-       { NET_IRDA_MIN_TX_TURN_TIME,    "min_tx_turn_time" },
-       { NET_IRDA_MAX_TX_DATA_SIZE,    "max_tx_data_size" },
-       { NET_IRDA_MAX_TX_WINDOW,       "max_tx_window" },
-       { NET_IRDA_MAX_NOREPLY_TIME,    "max_noreply_time" },
-       { NET_IRDA_WARN_NOREPLY_TIME,   "warn_noreply_time" },
-       { NET_IRDA_LAP_KEEPALIVE_TIME,  "lap_keepalive_time" },
-       {}
-};
-
-static const struct trans_ctl_table trans_net_table[] = {
-       { NET_CORE,             "core",         trans_net_core_table },
-       /* NET_ETHER not used */
-       /* NET_802 not used */
-       { NET_UNIX,             "unix",         trans_net_unix_table },
-       { NET_IPV4,             "ipv4",         trans_net_ipv4_table },
-       { NET_IPX,              "ipx",          trans_net_ipx_table },
-       { NET_ATALK,            "appletalk",    trans_net_atalk_table },
-       { NET_NETROM,           "netrom",       trans_net_netrom_table },
-       { NET_AX25,             "ax25",         trans_net_ax25_table },
-       { NET_BRIDGE,           "bridge",       trans_net_bridge_table },
-       { NET_ROSE,             "rose",         trans_net_rose_table },
-       { NET_IPV6,             "ipv6",         trans_net_ipv6_table },
-       { NET_X25,              "x25",          trans_net_x25_table },
-       { NET_TR,               "token-ring",   trans_net_tr_table },
-       { NET_DECNET,           "decnet",       trans_net_decnet_table },
-       /*  NET_ECONET not used */
-       { NET_SCTP,             "sctp",         trans_net_sctp_table },
-       { NET_LLC,              "llc",          trans_net_llc_table },
-       { NET_NETFILTER,        "netfilter",    trans_net_netfilter_table },
-       { NET_DCCP,             "dccp",         trans_net_dccp_table },
-       { NET_IRDA,             "irda",         trans_net_irda_table },
-       { 2089,                 "nf_conntrack_max" },
-       {}
-};
-
-static const struct trans_ctl_table trans_fs_quota_table[] = {
-       { FS_DQ_LOOKUPS,        "lookups" },
-       { FS_DQ_DROPS,          "drops" },
-       { FS_DQ_READS,          "reads" },
-       { FS_DQ_WRITES,         "writes" },
-       { FS_DQ_CACHE_HITS,     "cache_hits" },
-       { FS_DQ_ALLOCATED,      "allocated_dquots" },
-       { FS_DQ_FREE,           "free_dquots" },
-       { FS_DQ_SYNCS,          "syncs" },
-       { FS_DQ_WARNINGS,       "warnings" },
-       {}
-};
-
-static const struct trans_ctl_table trans_fs_xfs_table[] = {
-       { XFS_SGID_INHERIT,     "irix_sgid_inherit" },
-       { XFS_SYMLINK_MODE,     "irix_symlink_mode" },
-       { XFS_PANIC_MASK,       "panic_mask" },
-
-       { XFS_ERRLEVEL,         "error_level" },
-       { XFS_SYNCD_TIMER,      "xfssyncd_centisecs" },
-       { XFS_INHERIT_SYNC,     "inherit_sync" },
-       { XFS_INHERIT_NODUMP,   "inherit_nodump" },
-       { XFS_INHERIT_NOATIME,  "inherit_noatime" },
-       { XFS_BUF_TIMER,        "xfsbufd_centisecs" },
-       { XFS_BUF_AGE,          "age_buffer_centisecs" },
-       { XFS_INHERIT_NOSYM,    "inherit_nosymlinks" },
-       { XFS_ROTORSTEP,        "rotorstep" },
-       { XFS_INHERIT_NODFRG,   "inherit_nodefrag" },
-       { XFS_FILESTREAM_TIMER, "filestream_centisecs" },
-       { XFS_STATS_CLEAR,      "stats_clear" },
-       {}
-};
-
-static const struct trans_ctl_table trans_fs_ocfs2_nm_table[] = {
-       { 1, "hb_ctl_path" },
-       {}
-};
-
-static const struct trans_ctl_table trans_fs_ocfs2_table[] = {
-       { 1,    "nm",   trans_fs_ocfs2_nm_table },
-       {}
-};
-
-static const struct trans_ctl_table trans_inotify_table[] = {
-       { INOTIFY_MAX_USER_INSTANCES,   "max_user_instances" },
-       { INOTIFY_MAX_USER_WATCHES,     "max_user_watches" },
-       { INOTIFY_MAX_QUEUED_EVENTS,    "max_queued_events" },
-       {}
-};
-
-static const struct trans_ctl_table trans_fs_table[] = {
-       { FS_NRINODE,           "inode-nr" },
-       { FS_STATINODE,         "inode-state" },
-       /* FS_MAXINODE unused */
-       /* FS_NRDQUOT unused */
-       /* FS_MAXDQUOT unused */
-       { FS_NRFILE,            "file-nr" },
-       { FS_MAXFILE,           "file-max" },
-       { FS_DENTRY,            "dentry-state" },
-       /* FS_NRSUPER unused */
-       /* FS_MAXUPSER unused */
-       { FS_OVERFLOWUID,       "overflowuid" },
-       { FS_OVERFLOWGID,       "overflowgid" },
-       { FS_LEASES,            "leases-enable" },
-       { FS_DIR_NOTIFY,        "dir-notify-enable" },
-       { FS_LEASE_TIME,        "lease-break-time" },
-       { FS_DQSTATS,           "quota",                trans_fs_quota_table },
-       { FS_XFS,               "xfs",                  trans_fs_xfs_table },
-       { FS_AIO_NR,            "aio-nr" },
-       { FS_AIO_MAX_NR,        "aio-max-nr" },
-       { FS_INOTIFY,           "inotify",              trans_inotify_table },
-       { FS_OCFS2,             "ocfs2",                trans_fs_ocfs2_table },
-       { KERN_SETUID_DUMPABLE, "suid_dumpable" },
-       {}
-};
-
-static const struct trans_ctl_table trans_debug_table[] = {
-       {}
-};
-
-static const struct trans_ctl_table trans_cdrom_table[] = {
-       { DEV_CDROM_INFO,               "info" },
-       { DEV_CDROM_AUTOCLOSE,          "autoclose" },
-       { DEV_CDROM_AUTOEJECT,          "autoeject" },
-       { DEV_CDROM_DEBUG,              "debug" },
-       { DEV_CDROM_LOCK,               "lock" },
-       { DEV_CDROM_CHECK_MEDIA,        "check_media" },
-       {}
-};
-
-static const struct trans_ctl_table trans_ipmi_table[] = {
-       { DEV_IPMI_POWEROFF_POWERCYCLE, "poweroff_powercycle" },
-       {}
-};
-
-static const struct trans_ctl_table trans_mac_hid_files[] = {
-       /* DEV_MAC_HID_KEYBOARD_SENDS_LINUX_KEYCODES unused */
-       /* DEV_MAC_HID_KEYBOARD_LOCK_KEYCODES unused */
-       { DEV_MAC_HID_MOUSE_BUTTON_EMULATION,   "mouse_button_emulation" },
-       { DEV_MAC_HID_MOUSE_BUTTON2_KEYCODE,    "mouse_button2_keycode" },
-       { DEV_MAC_HID_MOUSE_BUTTON3_KEYCODE,    "mouse_button3_keycode" },
-       /* DEV_MAC_HID_ADB_MOUSE_SENDS_KEYCODES unused */
-       {}
-};
-
-static const struct trans_ctl_table trans_raid_table[] = {
-       { DEV_RAID_SPEED_LIMIT_MIN,     "speed_limit_min" },
-       { DEV_RAID_SPEED_LIMIT_MAX,     "speed_limit_max" },
-       {}
-};
-
-static const struct trans_ctl_table trans_scsi_table[] = {
-       { DEV_SCSI_LOGGING_LEVEL, "logging_level" },
-       {}
-};
-
-static const struct trans_ctl_table trans_parport_default_table[] = {
-       { DEV_PARPORT_DEFAULT_TIMESLICE,        "timeslice" },
-       { DEV_PARPORT_DEFAULT_SPINTIME,         "spintime" },
-       {}
-};
-
-static const struct trans_ctl_table trans_parport_device_table[] = {
-       { DEV_PARPORT_DEVICE_TIMESLICE,         "timeslice" },
-       {}
-};
-
-static const struct trans_ctl_table trans_parport_devices_table[] = {
-       { DEV_PARPORT_DEVICES_ACTIVE,           "active" },
-       { 0, NULL, trans_parport_device_table },
-       {}
-};
-
-static const struct trans_ctl_table trans_parport_parport_table[] = {
-       { DEV_PARPORT_SPINTIME,         "spintime" },
-       { DEV_PARPORT_BASE_ADDR,        "base-addr" },
-       { DEV_PARPORT_IRQ,              "irq" },
-       { DEV_PARPORT_DMA,              "dma" },
-       { DEV_PARPORT_MODES,            "modes" },
-       { DEV_PARPORT_DEVICES,          "devices",      trans_parport_devices_table },
-       { DEV_PARPORT_AUTOPROBE,        "autoprobe" },
-       { DEV_PARPORT_AUTOPROBE + 1,    "autoprobe0" },
-       { DEV_PARPORT_AUTOPROBE + 2,    "autoprobe1" },
-       { DEV_PARPORT_AUTOPROBE + 3,    "autoprobe2" },
-       { DEV_PARPORT_AUTOPROBE + 4,    "autoprobe3" },
-       {}
-};
-static const struct trans_ctl_table trans_parport_table[] = {
-       { DEV_PARPORT_DEFAULT,  "default",      trans_parport_default_table },
-       { 0, NULL, trans_parport_parport_table },
-       {}
-};
-
-static const struct trans_ctl_table trans_dev_table[] = {
-       { DEV_CDROM,    "cdrom",        trans_cdrom_table },
-       /* DEV_HWMON unused */
-       { DEV_PARPORT,  "parport",      trans_parport_table },
-       { DEV_RAID,     "raid",         trans_raid_table },
-       { DEV_MAC_HID,  "mac_hid",      trans_mac_hid_files },
-       { DEV_SCSI,     "scsi",         trans_scsi_table },
-       { DEV_IPMI,     "ipmi",         trans_ipmi_table },
-       {}
-};
-
-static const struct trans_ctl_table trans_bus_isa_table[] = {
-       { BUS_ISA_MEM_BASE,     "membase" },
-       { BUS_ISA_PORT_BASE,    "portbase" },
-       { BUS_ISA_PORT_SHIFT,   "portshift" },
-       {}
-};
-
-static const struct trans_ctl_table trans_bus_table[] = {
-       { CTL_BUS_ISA,  "isa",  trans_bus_isa_table },
-       {}
-};
-
-static const struct trans_ctl_table trans_arlan_conf_table0[] = {
-       { 1,    "spreadingCode" },
-       { 2,    "channelNumber" },
-       { 3,    "scramblingDisable" },
-       { 4,    "txAttenuation" },
-       { 5,    "systemId" },
-       { 6,    "maxDatagramSize" },
-       { 7,    "maxFrameSize" },
-       { 8,    "maxRetries" },
-       { 9,    "receiveMode" },
-       { 10,   "priority" },
-       { 11,   "rootOrRepeater" },
-       { 12,   "SID" },
-       { 13,   "registrationMode" },
-       { 14,   "registrationFill" },
-       { 15,   "localTalkAddress" },
-       { 16,   "codeFormat" },
-       { 17,   "numChannels" },
-       { 18,   "channel1" },
-       { 19,   "channel2" },
-       { 20,   "channel3" },
-       { 21,   "channel4" },
-       { 22,   "txClear" },
-       { 23,   "txRetries" },
-       { 24,   "txRouting" },
-       { 25,   "txScrambled" },
-       { 26,   "rxParameter" },
-       { 27,   "txTimeoutMs" },
-       { 28,   "waitCardTimeout" },
-       { 29,   "channelSet" },
-       { 30,   "name" },
-       { 31,   "waitTime" },
-       { 32,   "lParameter" },
-       { 33,   "_15" },
-       { 34,   "headerSize" },
-       { 36,   "tx_delay_ms" },
-       { 37,   "retries" },
-       { 38,   "ReTransmitPacketMaxSize" },
-       { 39,   "waitReTransmitPacketMaxSize" },
-       { 40,   "fastReTransCount" },
-       { 41,   "driverRetransmissions" },
-       { 42,   "txAckTimeoutMs" },
-       { 43,   "registrationInterrupts" },
-       { 44,   "hardwareType" },
-       { 45,   "radioType" },
-       { 46,   "writeEEPROM" },
-       { 47,   "writeRadioType" },
-       { 48,   "entry_exit_debug" },
-       { 49,   "debug" },
-       { 50,   "in_speed" },
-       { 51,   "out_speed" },
-       { 52,   "in_speed10" },
-       { 53,   "out_speed10" },
-       { 54,   "in_speed_max" },
-       { 55,   "out_speed_max" },
-       { 56,   "measure_rate" },
-       { 57,   "pre_Command_Wait" },
-       { 58,   "rx_tweak1" },
-       { 59,   "rx_tweak2" },
-       { 60,   "tx_queue_len" },
-
-       { 150,  "arlan0-txRing" },
-       { 151,  "arlan0-rxRing" },
-       { 152,  "arlan0-18" },
-       { 153,  "arlan0-ring" },
-       { 154,  "arlan0-shm-cpy" },
-       { 155,  "config0" },
-       { 156,  "reset0" },
-       {}
-};
-
-static const struct trans_ctl_table trans_arlan_conf_table1[] = {
-       { 1,    "spreadingCode" },
-       { 2,    "channelNumber" },
-       { 3,    "scramblingDisable" },
-       { 4,    "txAttenuation" },
-       { 5,    "systemId" },
-       { 6,    "maxDatagramSize" },
-       { 7,    "maxFrameSize" },
-       { 8,    "maxRetries" },
-       { 9,    "receiveMode" },
-       { 10,   "priority" },
-       { 11,   "rootOrRepeater" },
-       { 12,   "SID" },
-       { 13,   "registrationMode" },
-       { 14,   "registrationFill" },
-       { 15,   "localTalkAddress" },
-       { 16,   "codeFormat" },
-       { 17,   "numChannels" },
-       { 18,   "channel1" },
-       { 19,   "channel2" },
-       { 20,   "channel3" },
-       { 21,   "channel4" },
-       { 22,   "txClear" },
-       { 23,   "txRetries" },
-       { 24,   "txRouting" },
-       { 25,   "txScrambled" },
-       { 26,   "rxParameter" },
-       { 27,   "txTimeoutMs" },
-       { 28,   "waitCardTimeout" },
-       { 29,   "channelSet" },
-       { 30,   "name" },
-       { 31,   "waitTime" },
-       { 32,   "lParameter" },
-       { 33,   "_15" },
-       { 34,   "headerSize" },
-       { 36,   "tx_delay_ms" },
-       { 37,   "retries" },
-       { 38,   "ReTransmitPacketMaxSize" },
-       { 39,   "waitReTransmitPacketMaxSize" },
-       { 40,   "fastReTransCount" },
-       { 41,   "driverRetransmissions" },
-       { 42,   "txAckTimeoutMs" },
-       { 43,   "registrationInterrupts" },
-       { 44,   "hardwareType" },
-       { 45,   "radioType" },
-       { 46,   "writeEEPROM" },
-       { 47,   "writeRadioType" },
-       { 48,   "entry_exit_debug" },
-       { 49,   "debug" },
-       { 50,   "in_speed" },
-       { 51,   "out_speed" },
-       { 52,   "in_speed10" },
-       { 53,   "out_speed10" },
-       { 54,   "in_speed_max" },
-       { 55,   "out_speed_max" },
-       { 56,   "measure_rate" },
-       { 57,   "pre_Command_Wait" },
-       { 58,   "rx_tweak1" },
-       { 59,   "rx_tweak2" },
-       { 60,   "tx_queue_len" },
-
-       { 150,  "arlan1-txRing" },
-       { 151,  "arlan1-rxRing" },
-       { 152,  "arlan1-18" },
-       { 153,  "arlan1-ring" },
-       { 154,  "arlan1-shm-cpy" },
-       { 155,  "config1" },
-       { 156,  "reset1" },
-       {}
-};
-
-static const struct trans_ctl_table trans_arlan_conf_table2[] = {
-       { 1,    "spreadingCode" },
-       { 2,    "channelNumber" },
-       { 3,    "scramblingDisable" },
-       { 4,    "txAttenuation" },
-       { 5,    "systemId" },
-       { 6,    "maxDatagramSize" },
-       { 7,    "maxFrameSize" },
-       { 8,    "maxRetries" },
-       { 9,    "receiveMode" },
-       { 10,   "priority" },
-       { 11,   "rootOrRepeater" },
-       { 12,   "SID" },
-       { 13,   "registrationMode" },
-       { 14,   "registrationFill" },
-       { 15,   "localTalkAddress" },
-       { 16,   "codeFormat" },
-       { 17,   "numChannels" },
-       { 18,   "channel1" },
-       { 19,   "channel2" },
-       { 20,   "channel3" },
-       { 21,   "channel4" },
-       { 22,   "txClear" },
-       { 23,   "txRetries" },
-       { 24,   "txRouting" },
-       { 25,   "txScrambled" },
-       { 26,   "rxParameter" },
-       { 27,   "txTimeoutMs" },
-       { 28,   "waitCardTimeout" },
-       { 29,   "channelSet" },
-       { 30,   "name" },
-       { 31,   "waitTime" },
-       { 32,   "lParameter" },
-       { 33,   "_15" },
-       { 34,   "headerSize" },
-       { 36,   "tx_delay_ms" },
-       { 37,   "retries" },
-       { 38,   "ReTransmitPacketMaxSize" },
-       { 39,   "waitReTransmitPacketMaxSize" },
-       { 40,   "fastReTransCount" },
-       { 41,   "driverRetransmissions" },
-       { 42,   "txAckTimeoutMs" },
-       { 43,   "registrationInterrupts" },
-       { 44,   "hardwareType" },
-       { 45,   "radioType" },
-       { 46,   "writeEEPROM" },
-       { 47,   "writeRadioType" },
-       { 48,   "entry_exit_debug" },
-       { 49,   "debug" },
-       { 50,   "in_speed" },
-       { 51,   "out_speed" },
-       { 52,   "in_speed10" },
-       { 53,   "out_speed10" },
-       { 54,   "in_speed_max" },
-       { 55,   "out_speed_max" },
-       { 56,   "measure_rate" },
-       { 57,   "pre_Command_Wait" },
-       { 58,   "rx_tweak1" },
-       { 59,   "rx_tweak2" },
-       { 60,   "tx_queue_len" },
-
-       { 150,  "arlan2-txRing" },
-       { 151,  "arlan2-rxRing" },
-       { 152,  "arlan2-18" },
-       { 153,  "arlan2-ring" },
-       { 154,  "arlan2-shm-cpy" },
-       { 155,  "config2" },
-       { 156,  "reset2" },
-       {}
-};
-
-static const struct trans_ctl_table trans_arlan_conf_table3[] = {
-       { 1,    "spreadingCode" },
-       { 2,    "channelNumber" },
-       { 3,    "scramblingDisable" },
-       { 4,    "txAttenuation" },
-       { 5,    "systemId" },
-       { 6,    "maxDatagramSize" },
-       { 7,    "maxFrameSize" },
-       { 8,    "maxRetries" },
-       { 9,    "receiveMode" },
-       { 10,   "priority" },
-       { 11,   "rootOrRepeater" },
-       { 12,   "SID" },
-       { 13,   "registrationMode" },
-       { 14,   "registrationFill" },
-       { 15,   "localTalkAddress" },
-       { 16,   "codeFormat" },
-       { 17,   "numChannels" },
-       { 18,   "channel1" },
-       { 19,   "channel2" },
-       { 20,   "channel3" },
-       { 21,   "channel4" },
-       { 22,   "txClear" },
-       { 23,   "txRetries" },
-       { 24,   "txRouting" },
-       { 25,   "txScrambled" },
-       { 26,   "rxParameter" },
-       { 27,   "txTimeoutMs" },
-       { 28,   "waitCardTimeout" },
-       { 29,   "channelSet" },
-       { 30,   "name" },
-       { 31,   "waitTime" },
-       { 32,   "lParameter" },
-       { 33,   "_15" },
-       { 34,   "headerSize" },
-       { 36,   "tx_delay_ms" },
-       { 37,   "retries" },
-       { 38,   "ReTransmitPacketMaxSize" },
-       { 39,   "waitReTransmitPacketMaxSize" },
-       { 40,   "fastReTransCount" },
-       { 41,   "driverRetransmissions" },
-       { 42,   "txAckTimeoutMs" },
-       { 43,   "registrationInterrupts" },
-       { 44,   "hardwareType" },
-       { 45,   "radioType" },
-       { 46,   "writeEEPROM" },
-       { 47,   "writeRadioType" },
-       { 48,   "entry_exit_debug" },
-       { 49,   "debug" },
-       { 50,   "in_speed" },
-       { 51,   "out_speed" },
-       { 52,   "in_speed10" },
-       { 53,   "out_speed10" },
-       { 54,   "in_speed_max" },
-       { 55,   "out_speed_max" },
-       { 56,   "measure_rate" },
-       { 57,   "pre_Command_Wait" },
-       { 58,   "rx_tweak1" },
-       { 59,   "rx_tweak2" },
-       { 60,   "tx_queue_len" },
-
-       { 150,  "arlan3-txRing" },
-       { 151,  "arlan3-rxRing" },
-       { 152,  "arlan3-18" },
-       { 153,  "arlan3-ring" },
-       { 154,  "arlan3-shm-cpy" },
-       { 155,  "config3" },
-       { 156,  "reset3" },
-       {}
-};
-
-static const struct trans_ctl_table trans_arlan_table[] = {
-       { 1,            "arlan0",       trans_arlan_conf_table0 },
-       { 2,            "arlan1",       trans_arlan_conf_table1 },
-       { 3,            "arlan2",       trans_arlan_conf_table2 },
-       { 4,            "arlan3",       trans_arlan_conf_table3 },
-       {}
-};
-
-static const struct trans_ctl_table trans_s390dbf_table[] = {
-       { 5678 /* CTL_S390DBF_STOPPABLE */,     "debug_stoppable" },
-       { 5679 /* CTL_S390DBF_ACTIVE */,        "debug_active" },
-       {}
-};
-
-static const struct trans_ctl_table trans_sunrpc_table[] = {
-       { CTL_RPCDEBUG,         "rpc_debug" },
-       { CTL_NFSDEBUG,         "nfs_debug" },
-       { CTL_NFSDDEBUG,        "nfsd_debug" },
-       { CTL_NLMDEBUG,         "nlm_debug" },
-       { CTL_SLOTTABLE_UDP,    "udp_slot_table_entries" },
-       { CTL_SLOTTABLE_TCP,    "tcp_slot_table_entries" },
-       { CTL_MIN_RESVPORT,     "min_resvport" },
-       { CTL_MAX_RESVPORT,     "max_resvport" },
-       {}
-};
-
-static const struct trans_ctl_table trans_pm_table[] = {
-       { 1 /* CTL_PM_SUSPEND */,       "suspend" },
-       { 2 /* CTL_PM_CMODE */,         "cmode" },
-       { 3 /* CTL_PM_P0 */,            "p0" },
-       { 4 /* CTL_PM_CM */,            "cm" },
-       {}
-};
-
-static const struct trans_ctl_table trans_frv_table[] = {
-       { 1,    "cache-mode" },
-       { 2,    "pin-cxnr" },
-       {}
-};
-
-static const struct trans_ctl_table trans_root_table[] = {
-       { CTL_KERN,     "kernel",       trans_kern_table },
-       { CTL_VM,       "vm",           trans_vm_table },
-       { CTL_NET,      "net",          trans_net_table },
-       /* CTL_PROC not used */
-       { CTL_FS,       "fs",           trans_fs_table },
-       { CTL_DEBUG,    "debug",        trans_debug_table },
-       { CTL_DEV,      "dev",          trans_dev_table },
-       { CTL_BUS,      "bus",          trans_bus_table },
-       { CTL_ABI,      "abi" },
-       /* CTL_CPU not used */
-       { CTL_ARLAN,    "arlan",        trans_arlan_table },
-       { CTL_S390DBF,  "s390dbf",      trans_s390dbf_table },
-       { CTL_SUNRPC,   "sunrpc",       trans_sunrpc_table },
-       { CTL_PM,       "pm",           trans_pm_table },
-       { CTL_FRV,      "frv",          trans_frv_table },
-       {}
-};
-
-
-
 
 static int sysctl_depth(struct ctl_table *table)
 {
@@ -1262,47 +28,6 @@ static struct ctl_table *sysctl_parent(struct ctl_table *table, int n)
        return table;
 }
 
-static const struct trans_ctl_table *sysctl_binary_lookup(struct ctl_table *table)
-{
-       struct ctl_table *test;
-       const struct trans_ctl_table *ref;
-       int cur_depth;
-
-       cur_depth = sysctl_depth(table);
-
-       ref = trans_root_table;
-repeat:
-       test = sysctl_parent(table, cur_depth);
-       for (; ref->ctl_name || ref->procname || ref->child; ref++) {
-               int match = 0;
-
-               if (cur_depth && !ref->child)
-                       continue;
-
-               if (test->procname && ref->procname &&
-                       (strcmp(test->procname, ref->procname) == 0))
-                       match++;
-
-               if (test->ctl_name && ref->ctl_name &&
-                       (test->ctl_name == ref->ctl_name))
-                       match++;
-
-               if (!ref->ctl_name && !ref->procname)
-                       match++;
-
-               if (match) {
-                       if (cur_depth != 0) {
-                               cur_depth--;
-                               ref = ref->child;
-                               goto repeat;
-                       }
-                       goto out;
-               }
-       }
-       ref = NULL;
-out:
-       return ref;
-}
 
 static void sysctl_print_path(struct ctl_table *table)
 {
@@ -1316,26 +41,6 @@ static void sysctl_print_path(struct ctl_table *table)
                }
        }
        printk(" ");
-       if (table->ctl_name) {
-               for (i = depth; i >= 0; i--) {
-                       tmp = sysctl_parent(table, i);
-                       printk(".%d", tmp->ctl_name);
-               }
-       }
-}
-
-static void sysctl_repair_table(struct ctl_table *table)
-{
-       /* Don't complain about the classic default
-        * sysctl strategy routine.  Maybe later we
-        * can get the tables fixed and complain about
-        * this.
-        */
-       if (table->ctl_name && table->procname &&
-               (table->proc_handler == proc_dointvec) &&
-               (!table->strategy)) {
-               table->strategy = sysctl_data;
-       }
 }
 
 static struct ctl_table *sysctl_check_lookup(struct nsproxy *namespaces,
@@ -1353,7 +58,7 @@ static struct ctl_table *sysctl_check_lookup(struct nsproxy *namespaces,
                ref = head->ctl_table;
 repeat:
                test = sysctl_parent(table, cur_depth);
-               for (; ref->ctl_name || ref->procname; ref++) {
+               for (; ref->procname; ref++) {
                        int match = 0;
                        if (cur_depth && !ref->child)
                                continue;
@@ -1362,10 +67,6 @@ repeat:
                            (strcmp(test->procname, ref->procname) == 0))
                                        match++;
 
-                       if (test->ctl_name && ref->ctl_name &&
-                           (test->ctl_name == ref->ctl_name))
-                               match++;
-
                        if (match) {
                                if (cur_depth != 0) {
                                        cur_depth--;
@@ -1393,38 +94,6 @@ static void set_fail(const char **fail, struct ctl_table *table, const char *str
        *fail = str;
 }
 
-static int sysctl_check_dir(struct nsproxy *namespaces,
-                               struct ctl_table *table)
-{
-       struct ctl_table *ref;
-       int error;
-
-       error = 0;
-       ref = sysctl_check_lookup(namespaces, table);
-       if (ref) {
-               int match = 0;
-               if ((!table->procname && !ref->procname) ||
-                   (table->procname && ref->procname &&
-                    (strcmp(table->procname, ref->procname) == 0)))
-                       match++;
-
-               if ((!table->ctl_name && !ref->ctl_name) ||
-                   (table->ctl_name && ref->ctl_name &&
-                    (table->ctl_name == ref->ctl_name)))
-                       match++;
-
-               if (match != 2) {
-                       printk(KERN_ERR "%s: failed: ", __func__);
-                       sysctl_print_path(table);
-                       printk(" ref: ");
-                       sysctl_print_path(ref);
-                       printk("\n");
-                       error = -EINVAL;
-               }
-       }
-       return error;
-}
-
 static void sysctl_check_leaf(struct nsproxy *namespaces,
                                struct ctl_table *table, const char **fail)
 {
@@ -1435,37 +104,15 @@ static void sysctl_check_leaf(struct nsproxy *namespaces,
                set_fail(fail, table, "Sysctl already exists");
 }
 
-static void sysctl_check_bin_path(struct ctl_table *table, const char **fail)
-{
-       const struct trans_ctl_table *ref;
-
-       ref = sysctl_binary_lookup(table);
-       if (table->ctl_name && !ref)
-               set_fail(fail, table, "Unknown sysctl binary path");
-       if (ref) {
-               if (ref->procname &&
-                   (!table->procname ||
-                    (strcmp(table->procname, ref->procname) != 0)))
-                       set_fail(fail, table, "procname does not match binary path procname");
-
-               if (ref->ctl_name && table->ctl_name &&
-                   (table->ctl_name != ref->ctl_name))
-                       set_fail(fail, table, "ctl_name does not match binary path ctl_name");
-       }
-}
-
 int sysctl_check_table(struct nsproxy *namespaces, struct ctl_table *table)
 {
        int error = 0;
-       for (; table->ctl_name || table->procname; table++) {
+       for (; table->procname; table++) {
                const char *fail = NULL;
 
-               sysctl_repair_table(table);
                if (table->parent) {
                        if (table->procname && !table->parent->procname)
                                set_fail(&fail, table, "Parent without procname");
-                       if (table->ctl_name && !table->parent->ctl_name)
-                               set_fail(&fail, table, "Parent without ctl_name");
                }
                if (!table->procname)
                        set_fail(&fail, table, "No procname");
@@ -1478,21 +125,12 @@ int sysctl_check_table(struct nsproxy *namespaces, struct ctl_table *table)
                                set_fail(&fail, table, "Writable sysctl directory");
                        if (table->proc_handler)
                                set_fail(&fail, table, "Directory with proc_handler");
-                       if (table->strategy)
-                               set_fail(&fail, table, "Directory with strategy");
                        if (table->extra1)
                                set_fail(&fail, table, "Directory with extra1");
                        if (table->extra2)
                                set_fail(&fail, table, "Directory with extra2");
-                       if (sysctl_check_dir(namespaces, table))
-                               set_fail(&fail, table, "Inconsistent directory names");
                } else {
-                       if ((table->strategy == sysctl_data) ||
-                           (table->strategy == sysctl_string) ||
-                           (table->strategy == sysctl_intvec) ||
-                           (table->strategy == sysctl_jiffies) ||
-                           (table->strategy == sysctl_ms_jiffies) ||
-                           (table->proc_handler == proc_dostring) ||
+                       if ((table->proc_handler == proc_dostring) ||
                            (table->proc_handler == proc_dointvec) ||
                            (table->proc_handler == proc_dointvec_minmax) ||
                            (table->proc_handler == proc_dointvec_jiffies) ||
@@ -1514,14 +152,6 @@ int sysctl_check_table(struct nsproxy *namespaces, struct ctl_table *table)
                                                set_fail(&fail, table, "No max");
                                }
                        }
-#ifdef CONFIG_SYSCTL_SYSCALL
-                       if (table->ctl_name && !table->strategy)
-                               set_fail(&fail, table, "Missing strategy");
-#endif
-#if 0
-                       if (!table->ctl_name && table->strategy)
-                               set_fail(&fail, table, "Strategy without ctl_name");
-#endif
 #ifdef CONFIG_PROC_SYSCTL
                        if (table->procname && !table->proc_handler)
                                set_fail(&fail, table, "No proc_handler");
@@ -1532,7 +162,6 @@ int sysctl_check_table(struct nsproxy *namespaces, struct ctl_table *table)
 #endif
                        sysctl_check_leaf(namespaces, table, &fail);
                }
-               sysctl_check_bin_path(table, &fail);
                if (table->mode > 0777)
                        set_fail(&fail, table, "bogus .mode");
                if (fail) {
index 2e2e469..8047980 100644 (file)
@@ -662,6 +662,36 @@ u64 nsec_to_clock_t(u64 x)
 #endif
 }
 
+/**
+ * nsecs_to_jiffies - Convert nsecs in u64 to jiffies
+ *
+ * @n: nsecs in u64
+ *
+ * Unlike {m,u}secs_to_jiffies, type of input is not unsigned int but u64.
+ * And this doesn't return MAX_JIFFY_OFFSET since this function is designed
+ * for scheduler, not for use in device drivers to calculate timeout value.
+ *
+ * note:
+ *   NSEC_PER_SEC = 10^9 = (5^9 * 2^9) = (1953125 * 512)
+ *   ULLONG_MAX ns = 18446744073.709551615 secs = about 584 years
+ */
+unsigned long nsecs_to_jiffies(u64 n)
+{
+#if (NSEC_PER_SEC % HZ) == 0
+       /* Common case, HZ = 100, 128, 200, 250, 256, 500, 512, 1000 etc. */
+       return div_u64(n, NSEC_PER_SEC / HZ);
+#elif (HZ % 512) == 0
+       /* overflow after 292 years if HZ = 1024 */
+       return div_u64(n * HZ / 512, NSEC_PER_SEC / 512);
+#else
+       /*
+        * Generic case - optimized for cases where HZ is a multiple of 3.
+        * overflow after 64.99 years, exact for HZ = 60, 72, 90, 120 etc.
+        */
+       return div_u64(n * 9, (9ull * NSEC_PER_SEC + HZ / 2) / HZ);
+#endif
+}
+
 #if (BITS_PER_LONG < 64)
 u64 get_jiffies_64(void)
 {
index b416512..d006554 100644 (file)
@@ -339,6 +339,27 @@ config POWER_TRACER
          power management decisions, specifically the C-state and P-state
          behavior.
 
+config KSYM_TRACER
+       bool "Trace read and write access on kernel memory locations"
+       depends on HAVE_HW_BREAKPOINT
+       select TRACING
+       help
+         This tracer helps find read and write operations on any given kernel
+         symbol i.e. /proc/kallsyms.
+
+config PROFILE_KSYM_TRACER
+       bool "Profile all kernel memory accesses on 'watched' variables"
+       depends on KSYM_TRACER
+       help
+         This tracer profiles kernel accesses on variables watched through the
+         ksym tracer ftrace plugin. Depending upon the hardware, all read
+         and write operations on kernel variables can be monitored for
+         accesses.
+
+         The results will be displayed in:
+         /debugfs/tracing/profile_ksym
+
+         Say N if unsure.
 
 config STACK_TRACER
        bool "Trace max stack"
@@ -428,6 +449,23 @@ config BLK_DEV_IO_TRACE
 
          If unsure, say N.
 
+config KPROBE_EVENT
+       depends on KPROBES
+       depends on X86
+       bool "Enable kprobes-based dynamic events"
+       select TRACING
+       default y
+       help
+         This allows the user to add tracing events (similar to tracepoints) on the fly
+         via the ftrace interface. See Documentation/trace/kprobetrace.txt
+         for more details.
+
+         Those events can be inserted wherever kprobes can probe, and record
+         various register and memory values.
+
+         This option is also required by perf-probe subcommand of perf tools. If
+         you want to use perf tools, this option is strongly recommended.
+
 config DYNAMIC_FTRACE
        bool "enable/disable ftrace tracepoints dynamically"
        depends on FUNCTION_TRACER
index 26f03ac..cd9ecd8 100644 (file)
@@ -53,6 +53,8 @@ obj-$(CONFIG_EVENT_TRACING) += trace_export.o
 obj-$(CONFIG_FTRACE_SYSCALLS) += trace_syscalls.o
 obj-$(CONFIG_EVENT_PROFILE) += trace_event_profile.o
 obj-$(CONFIG_EVENT_TRACING) += trace_events_filter.o
+obj-$(CONFIG_KPROBE_EVENT) += trace_kprobe.o
+obj-$(CONFIG_KSYM_TRACER) += trace_ksym.o
 obj-$(CONFIG_EVENT_TRACING) += power-traces.o
 
 libftrace-y := ftrace.o
index a72c6e0..a1ca495 100644 (file)
@@ -397,18 +397,21 @@ int ring_buffer_print_page_header(struct trace_seq *s)
        int ret;
 
        ret = trace_seq_printf(s, "\tfield: u64 timestamp;\t"
-                              "offset:0;\tsize:%u;\n",
-                              (unsigned int)sizeof(field.time_stamp));
+                              "offset:0;\tsize:%u;\tsigned:%u;\n",
+                              (unsigned int)sizeof(field.time_stamp),
+                              (unsigned int)is_signed_type(u64));
 
        ret = trace_seq_printf(s, "\tfield: local_t commit;\t"
-                              "offset:%u;\tsize:%u;\n",
+                              "offset:%u;\tsize:%u;\tsigned:%u;\n",
                               (unsigned int)offsetof(typeof(field), commit),
-                              (unsigned int)sizeof(field.commit));
+                              (unsigned int)sizeof(field.commit),
+                              (unsigned int)is_signed_type(long));
 
        ret = trace_seq_printf(s, "\tfield: char data;\t"
-                              "offset:%u;\tsize:%u;\n",
+                              "offset:%u;\tsize:%u;\tsigned:%u;\n",
                               (unsigned int)offsetof(typeof(field), data),
-                              (unsigned int)BUF_PAGE_SIZE);
+                              (unsigned int)BUF_PAGE_SIZE,
+                              (unsigned int)is_signed_type(char));
 
        return ret;
 }
index acef8b4..1d7f483 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/ftrace.h>
 #include <trace/boot.h>
 #include <linux/kmemtrace.h>
+#include <linux/hw_breakpoint.h>
 
 #include <linux/trace_seq.h>
 #include <linux/ftrace_event.h>
@@ -37,6 +38,7 @@ enum trace_type {
        TRACE_KMEM_ALLOC,
        TRACE_KMEM_FREE,
        TRACE_BLK,
+       TRACE_KSYM,
 
        __TRACE_LAST_TYPE,
 };
@@ -98,9 +100,32 @@ struct syscall_trace_enter {
 struct syscall_trace_exit {
        struct trace_entry      ent;
        int                     nr;
-       unsigned long           ret;
+       long                    ret;
 };
 
+struct kprobe_trace_entry {
+       struct trace_entry      ent;
+       unsigned long           ip;
+       int                     nargs;
+       unsigned long           args[];
+};
+
+#define SIZEOF_KPROBE_TRACE_ENTRY(n)                   \
+       (offsetof(struct kprobe_trace_entry, args) +    \
+       (sizeof(unsigned long) * (n)))
+
+struct kretprobe_trace_entry {
+       struct trace_entry      ent;
+       unsigned long           func;
+       unsigned long           ret_ip;
+       int                     nargs;
+       unsigned long           args[];
+};
+
+#define SIZEOF_KRETPROBE_TRACE_ENTRY(n)                        \
+       (offsetof(struct kretprobe_trace_entry, args) + \
+       (sizeof(unsigned long) * (n)))
+
 /*
  * trace_flag_type is an enumeration that holds different
  * states when a trace occurs. These are:
@@ -209,6 +234,7 @@ extern void __ftrace_bad_type(void);
                          TRACE_KMEM_ALLOC);    \
                IF_ASSIGN(var, ent, struct kmemtrace_free_entry,        \
                          TRACE_KMEM_FREE);     \
+               IF_ASSIGN(var, ent, struct ksym_trace_entry, TRACE_KSYM);\
                __ftrace_bad_type();                                    \
        } while (0)
 
@@ -364,6 +390,8 @@ int register_tracer(struct tracer *type);
 void unregister_tracer(struct tracer *type);
 int is_tracing_stopped(void);
 
+extern int process_new_ksym_entry(char *ksymname, int op, unsigned long addr);
+
 extern unsigned long nsecs_to_usecs(unsigned long nsecs);
 
 #ifdef CONFIG_TRACER_MAX_TRACE
@@ -438,6 +466,8 @@ extern int trace_selftest_startup_branch(struct tracer *trace,
                                         struct trace_array *tr);
 extern int trace_selftest_startup_hw_branches(struct tracer *trace,
                                              struct trace_array *tr);
+extern int trace_selftest_startup_ksym(struct tracer *trace,
+                                        struct trace_array *tr);
 #endif /* CONFIG_FTRACE_STARTUP_TEST */
 
 extern void *head_page(struct trace_array_cpu *data);
@@ -683,7 +713,6 @@ struct event_filter {
        int                     n_preds;
        struct filter_pred      **preds;
        char                    *filter_string;
-       bool                    no_reset;
 };
 
 struct event_subsystem {
@@ -703,7 +732,7 @@ typedef int (*filter_pred_fn_t) (struct filter_pred *pred, void *event,
 typedef int (*regex_match_func)(char *str, struct regex *r, int len);
 
 enum regex_type {
-       MATCH_FULL,
+       MATCH_FULL = 0,
        MATCH_FRONT_ONLY,
        MATCH_MIDDLE_ONLY,
        MATCH_END_ONLY,
@@ -744,7 +773,8 @@ filter_check_discard(struct ftrace_event_call *call, void *rec,
                     struct ring_buffer *buffer,
                     struct ring_buffer_event *event)
 {
-       if (unlikely(call->filter_active) && !filter_match_preds(call, rec)) {
+       if (unlikely(call->filter_active) &&
+           !filter_match_preds(call->filter, rec)) {
                ring_buffer_discard_commit(buffer, event);
                return 1;
        }
index ead3d72..c16a08f 100644 (file)
@@ -364,3 +364,19 @@ FTRACE_ENTRY(kmem_free, kmemtrace_free_entry,
        F_printk("type:%u call_site:%lx ptr:%p",
                 __entry->type_id, __entry->call_site, __entry->ptr)
 );
+
+FTRACE_ENTRY(ksym_trace, ksym_trace_entry,
+
+       TRACE_KSYM,
+
+       F_STRUCT(
+               __field(        unsigned long,  ip                        )
+               __field(        unsigned char,  type                      )
+               __array(        char         ,  cmd,       TASK_COMM_LEN  )
+               __field(        unsigned long,  addr                      )
+       ),
+
+       F_printk("ip: %pF type: %d ksym_name: %pS cmd: %s",
+               (void *)__entry->ip, (unsigned int)__entry->type,
+               (void *)__entry->addr,  __entry->cmd)
+);
index 8d5c171..d9c60f8 100644 (file)
@@ -8,17 +8,14 @@
 #include <linux/module.h>
 #include "trace.h"
 
-/*
- * We can't use a size but a type in alloc_percpu()
- * So let's create a dummy type that matches the desired size
- */
-typedef struct {char buf[FTRACE_MAX_PROFILE_SIZE];} profile_buf_t;
 
-char           *trace_profile_buf;
-EXPORT_SYMBOL_GPL(trace_profile_buf);
+char *perf_trace_buf;
+EXPORT_SYMBOL_GPL(perf_trace_buf);
+
+char *perf_trace_buf_nmi;
+EXPORT_SYMBOL_GPL(perf_trace_buf_nmi);
 
-char           *trace_profile_buf_nmi;
-EXPORT_SYMBOL_GPL(trace_profile_buf_nmi);
+typedef typeof(char [FTRACE_MAX_PROFILE_SIZE]) perf_trace_t ;
 
 /* Count the events in use (per event id, not per instance) */
 static int     total_profile_count;
@@ -32,20 +29,20 @@ static int ftrace_profile_enable_event(struct ftrace_event_call *event)
                return 0;
 
        if (!total_profile_count) {
-               buf = (char *)alloc_percpu(profile_buf_t);
+               buf = (char *)alloc_percpu(perf_trace_t);
                if (!buf)
                        goto fail_buf;
 
-               rcu_assign_pointer(trace_profile_buf, buf);
+               rcu_assign_pointer(perf_trace_buf, buf);
 
-               buf = (char *)alloc_percpu(profile_buf_t);
+               buf = (char *)alloc_percpu(perf_trace_t);
                if (!buf)
                        goto fail_buf_nmi;
 
-               rcu_assign_pointer(trace_profile_buf_nmi, buf);
+               rcu_assign_pointer(perf_trace_buf_nmi, buf);
        }
 
-       ret = event->profile_enable();
+       ret = event->profile_enable(event);
        if (!ret) {
                total_profile_count++;
                return 0;
@@ -53,10 +50,10 @@ static int ftrace_profile_enable_event(struct ftrace_event_call *event)
 
 fail_buf_nmi:
        if (!total_profile_count) {
-               free_percpu(trace_profile_buf_nmi);
-               free_percpu(trace_profile_buf);
-               trace_profile_buf_nmi = NULL;
-               trace_profile_buf = NULL;
+               free_percpu(perf_trace_buf_nmi);
+               free_percpu(perf_trace_buf);
+               perf_trace_buf_nmi = NULL;
+               perf_trace_buf = NULL;
        }
 fail_buf:
        atomic_dec(&event->profile_count);
@@ -89,14 +86,14 @@ static void ftrace_profile_disable_event(struct ftrace_event_call *event)
        if (!atomic_add_negative(-1, &event->profile_count))
                return;
 
-       event->profile_disable();
+       event->profile_disable(event);
 
        if (!--total_profile_count) {
-               buf = trace_profile_buf;
-               rcu_assign_pointer(trace_profile_buf, NULL);
+               buf = perf_trace_buf;
+               rcu_assign_pointer(perf_trace_buf, NULL);
 
-               nmi_buf = trace_profile_buf_nmi;
-               rcu_assign_pointer(trace_profile_buf_nmi, NULL);
+               nmi_buf = perf_trace_buf_nmi;
+               rcu_assign_pointer(perf_trace_buf_nmi, NULL);
 
                /*
                 * Ensure every events in profiling have finished before
index 5e9ffc3..1d18315 100644 (file)
@@ -93,9 +93,7 @@ int trace_define_common_fields(struct ftrace_event_call *call)
 }
 EXPORT_SYMBOL_GPL(trace_define_common_fields);
 
-#ifdef CONFIG_MODULES
-
-static void trace_destroy_fields(struct ftrace_event_call *call)
+void trace_destroy_fields(struct ftrace_event_call *call)
 {
        struct ftrace_event_field *field, *next;
 
@@ -107,8 +105,6 @@ static void trace_destroy_fields(struct ftrace_event_call *call)
        }
 }
 
-#endif /* CONFIG_MODULES */
-
 static void ftrace_event_enable_disable(struct ftrace_event_call *call,
                                        int enable)
 {
@@ -117,14 +113,14 @@ static void ftrace_event_enable_disable(struct ftrace_event_call *call,
                if (call->enabled) {
                        call->enabled = 0;
                        tracing_stop_cmdline_record();
-                       call->unregfunc(call->data);
+                       call->unregfunc(call);
                }
                break;
        case 1:
                if (!call->enabled) {
                        call->enabled = 1;
                        tracing_start_cmdline_record();
-                       call->regfunc(call->data);
+                       call->regfunc(call);
                }
                break;
        }
@@ -507,7 +503,7 @@ extern char *__bad_type_size(void);
 #define FIELD(type, name)                                              \
        sizeof(type) != sizeof(field.name) ? __bad_type_size() :        \
        #type, "common_" #name, offsetof(typeof(field), name),          \
-               sizeof(field.name)
+               sizeof(field.name), is_signed_type(type)
 
 static int trace_write_header(struct trace_seq *s)
 {
@@ -515,17 +511,17 @@ static int trace_write_header(struct trace_seq *s)
 
        /* struct trace_entry */
        return trace_seq_printf(s,
-                               "\tfield:%s %s;\toffset:%zu;\tsize:%zu;\n"
-                               "\tfield:%s %s;\toffset:%zu;\tsize:%zu;\n"
-                               "\tfield:%s %s;\toffset:%zu;\tsize:%zu;\n"
-                               "\tfield:%s %s;\toffset:%zu;\tsize:%zu;\n"
-                               "\tfield:%s %s;\toffset:%zu;\tsize:%zu;\n"
-                               "\n",
-                               FIELD(unsigned short, type),
-                               FIELD(unsigned char, flags),
-                               FIELD(unsigned char, preempt_count),
-                               FIELD(int, pid),
-                               FIELD(int, lock_depth));
+                       "\tfield:%s %s;\toffset:%zu;\tsize:%zu;\tsigned:%u;\n"
+                       "\tfield:%s %s;\toffset:%zu;\tsize:%zu;\tsigned:%u;\n"
+                       "\tfield:%s %s;\toffset:%zu;\tsize:%zu;\tsigned:%u;\n"
+                       "\tfield:%s %s;\toffset:%zu;\tsize:%zu;\tsigned:%u;\n"
+                       "\tfield:%s %s;\toffset:%zu;\tsize:%zu;\tsigned:%u;\n"
+                       "\n",
+                       FIELD(unsigned short, type),
+                       FIELD(unsigned char, flags),
+                       FIELD(unsigned char, preempt_count),
+                       FIELD(int, pid),
+                       FIELD(int, lock_depth));
 }
 
 static ssize_t
@@ -937,27 +933,46 @@ event_create_dir(struct ftrace_event_call *call, struct dentry *d_events,
        return 0;
 }
 
-#define for_each_event(event, start, end)                      \
-       for (event = start;                                     \
-            (unsigned long)event < (unsigned long)end;         \
-            event++)
+static int __trace_add_event_call(struct ftrace_event_call *call)
+{
+       struct dentry *d_events;
+       int ret;
 
-#ifdef CONFIG_MODULES
+       if (!call->name)
+               return -EINVAL;
 
-static LIST_HEAD(ftrace_module_file_list);
+       if (call->raw_init) {
+               ret = call->raw_init(call);
+               if (ret < 0) {
+                       if (ret != -ENOSYS)
+                               pr_warning("Could not initialize trace "
+                               "events/%s\n", call->name);
+                       return ret;
+               }
+       }
 
-/*
- * Modules must own their file_operations to keep up with
- * reference counting.
- */
-struct ftrace_module_file_ops {
-       struct list_head                list;
-       struct module                   *mod;
-       struct file_operations          id;
-       struct file_operations          enable;
-       struct file_operations          format;
-       struct file_operations          filter;
-};
+       d_events = event_trace_events_dir();
+       if (!d_events)
+               return -ENOENT;
+
+       ret = event_create_dir(call, d_events, &ftrace_event_id_fops,
+                               &ftrace_enable_fops, &ftrace_event_filter_fops,
+                               &ftrace_event_format_fops);
+       if (!ret)
+               list_add(&call->list, &ftrace_events);
+
+       return ret;
+}
+
+/* Add an additional event_call dynamically */
+int trace_add_event_call(struct ftrace_event_call *call)
+{
+       int ret;
+       mutex_lock(&event_mutex);
+       ret = __trace_add_event_call(call);
+       mutex_unlock(&event_mutex);
+       return ret;
+}
 
 static void remove_subsystem_dir(const char *name)
 {
@@ -985,6 +1000,53 @@ static void remove_subsystem_dir(const char *name)
        }
 }
 
+/*
+ * Must be called under locking both of event_mutex and trace_event_mutex.
+ */
+static void __trace_remove_event_call(struct ftrace_event_call *call)
+{
+       ftrace_event_enable_disable(call, 0);
+       if (call->event)
+               __unregister_ftrace_event(call->event);
+       debugfs_remove_recursive(call->dir);
+       list_del(&call->list);
+       trace_destroy_fields(call);
+       destroy_preds(call);
+       remove_subsystem_dir(call->system);
+}
+
+/* Remove an event_call */
+void trace_remove_event_call(struct ftrace_event_call *call)
+{
+       mutex_lock(&event_mutex);
+       down_write(&trace_event_mutex);
+       __trace_remove_event_call(call);
+       up_write(&trace_event_mutex);
+       mutex_unlock(&event_mutex);
+}
+
+#define for_each_event(event, start, end)                      \
+       for (event = start;                                     \
+            (unsigned long)event < (unsigned long)end;         \
+            event++)
+
+#ifdef CONFIG_MODULES
+
+static LIST_HEAD(ftrace_module_file_list);
+
+/*
+ * Modules must own their file_operations to keep up with
+ * reference counting.
+ */
+struct ftrace_module_file_ops {
+       struct list_head                list;
+       struct module                   *mod;
+       struct file_operations          id;
+       struct file_operations          enable;
+       struct file_operations          format;
+       struct file_operations          filter;
+};
+
 static struct ftrace_module_file_ops *
 trace_create_file_ops(struct module *mod)
 {
@@ -1042,7 +1104,7 @@ static void trace_module_add_events(struct module *mod)
                if (!call->name)
                        continue;
                if (call->raw_init) {
-                       ret = call->raw_init();
+                       ret = call->raw_init(call);
                        if (ret < 0) {
                                if (ret != -ENOSYS)
                                        pr_warning("Could not initialize trace "
@@ -1060,10 +1122,11 @@ static void trace_module_add_events(struct module *mod)
                                return;
                }
                call->mod = mod;
-               list_add(&call->list, &ftrace_events);
-               event_create_dir(call, d_events,
-                                &file_ops->id, &file_ops->enable,
-                                &file_ops->filter, &file_ops->format);
+               ret = event_create_dir(call, d_events,
+                                      &file_ops->id, &file_ops->enable,
+                                      &file_ops->filter, &file_ops->format);
+               if (!ret)
+                       list_add(&call->list, &ftrace_events);
        }
 }
 
@@ -1077,14 +1140,7 @@ static void trace_module_remove_events(struct module *mod)
        list_for_each_entry_safe(call, p, &ftrace_events, list) {
                if (call->mod == mod) {
                        found = true;
-                       ftrace_event_enable_disable(call, 0);
-                       if (call->event)
-                               __unregister_ftrace_event(call->event);
-                       debugfs_remove_recursive(call->dir);
-                       list_del(&call->list);
-                       trace_destroy_fields(call);
-                       destroy_preds(call);
-                       remove_subsystem_dir(call->system);
+                       __trace_remove_event_call(call);
                }
        }
 
@@ -1202,7 +1258,7 @@ static __init int event_trace_init(void)
                if (!call->name)
                        continue;
                if (call->raw_init) {
-                       ret = call->raw_init();
+                       ret = call->raw_init(call);
                        if (ret < 0) {
                                if (ret != -ENOSYS)
                                        pr_warning("Could not initialize trace "
@@ -1210,10 +1266,12 @@ static __init int event_trace_init(void)
                                continue;
                        }
                }
-               list_add(&call->list, &ftrace_events);
-               event_create_dir(call, d_events, &ftrace_event_id_fops,
-                                &ftrace_enable_fops, &ftrace_event_filter_fops,
-                                &ftrace_event_format_fops);
+               ret = event_create_dir(call, d_events, &ftrace_event_id_fops,
+                                      &ftrace_enable_fops,
+                                      &ftrace_event_filter_fops,
+                                      &ftrace_event_format_fops);
+               if (!ret)
+                       list_add(&call->list, &ftrace_events);
        }
 
        while (true) {
index 9267201..50504cb 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/module.h>
 #include <linux/ctype.h>
 #include <linux/mutex.h>
+#include <linux/perf_event.h>
 
 #include "trace.h"
 #include "trace_output.h"
@@ -29,6 +30,7 @@ enum filter_op_ids
 {
        OP_OR,
        OP_AND,
+       OP_GLOB,
        OP_NE,
        OP_EQ,
        OP_LT,
@@ -46,16 +48,17 @@ struct filter_op {
 };
 
 static struct filter_op filter_ops[] = {
-       { OP_OR, "||", 1 },
-       { OP_AND, "&&", 2 },
-       { OP_NE, "!=", 4 },
-       { OP_EQ, "==", 4 },
-       { OP_LT, "<", 5 },
-       { OP_LE, "<=", 5 },
-       { OP_GT, ">", 5 },
-       { OP_GE, ">=", 5 },
-       { OP_NONE, "OP_NONE", 0 },
-       { OP_OPEN_PAREN, "(", 0 },
+       { OP_OR,        "||",           1 },
+       { OP_AND,       "&&",           2 },
+       { OP_GLOB,      "~",            4 },
+       { OP_NE,        "!=",           4 },
+       { OP_EQ,        "==",           4 },
+       { OP_LT,        "<",            5 },
+       { OP_LE,        "<=",           5 },
+       { OP_GT,        ">",            5 },
+       { OP_GE,        ">=",           5 },
+       { OP_NONE,      "OP_NONE",      0 },
+       { OP_OPEN_PAREN, "(",           0 },
 };
 
 enum {
@@ -329,22 +332,18 @@ enum regex_type filter_parse_regex(char *buff, int len, char **search, int *not)
        return type;
 }
 
-static int filter_build_regex(struct filter_pred *pred)
+static void filter_build_regex(struct filter_pred *pred)
 {
        struct regex *r = &pred->regex;
-       char *search, *dup;
-       enum regex_type type;
-       int not;
-
-       type = filter_parse_regex(r->pattern, r->len, &search, &not);
-       dup = kstrdup(search, GFP_KERNEL);
-       if (!dup)
-               return -ENOMEM;
-
-       strcpy(r->pattern, dup);
-       kfree(dup);
-
-       r->len = strlen(r->pattern);
+       char *search;
+       enum regex_type type = MATCH_FULL;
+       int not = 0;
+
+       if (pred->op == OP_GLOB) {
+               type = filter_parse_regex(r->pattern, r->len, &search, &not);
+               r->len = strlen(search);
+               memmove(r->pattern, search, r->len+1);
+       }
 
        switch (type) {
        case MATCH_FULL:
@@ -362,14 +361,11 @@ static int filter_build_regex(struct filter_pred *pred)
        }
 
        pred->not ^= not;
-
-       return 0;
 }
 
 /* return 1 if event matches, 0 otherwise (discard) */
-int filter_match_preds(struct ftrace_event_call *call, void *rec)
+int filter_match_preds(struct event_filter *filter, void *rec)
 {
-       struct event_filter *filter = call->filter;
        int match, top = 0, val1 = 0, val2 = 0;
        int stack[MAX_FILTER_PRED];
        struct filter_pred *pred;
@@ -542,9 +538,8 @@ static void filter_disable_preds(struct ftrace_event_call *call)
                filter->preds[i]->fn = filter_pred_none;
 }
 
-void destroy_preds(struct ftrace_event_call *call)
+static void __free_preds(struct event_filter *filter)
 {
-       struct event_filter *filter = call->filter;
        int i;
 
        if (!filter)
@@ -557,21 +552,24 @@ void destroy_preds(struct ftrace_event_call *call)
        kfree(filter->preds);
        kfree(filter->filter_string);
        kfree(filter);
+}
+
+void destroy_preds(struct ftrace_event_call *call)
+{
+       __free_preds(call->filter);
        call->filter = NULL;
+       call->filter_active = 0;
 }
 
-static int init_preds(struct ftrace_event_call *call)
+static struct event_filter *__alloc_preds(void)
 {
        struct event_filter *filter;
        struct filter_pred *pred;
        int i;
 
-       if (call->filter)
-               return 0;
-
-       filter = call->filter = kzalloc(sizeof(*filter), GFP_KERNEL);
-       if (!call->filter)
-               return -ENOMEM;
+       filter = kzalloc(sizeof(*filter), GFP_KERNEL);
+       if (!filter)
+               return ERR_PTR(-ENOMEM);
 
        filter->n_preds = 0;
 
@@ -587,12 +585,24 @@ static int init_preds(struct ftrace_event_call *call)
                filter->preds[i] = pred;
        }
 
-       return 0;
+       return filter;
 
 oom:
-       destroy_preds(call);
+       __free_preds(filter);
+       return ERR_PTR(-ENOMEM);
+}
+
+static int init_preds(struct ftrace_event_call *call)
+{
+       if (call->filter)
+               return 0;
 
-       return -ENOMEM;
+       call->filter_active = 0;
+       call->filter = __alloc_preds();
+       if (IS_ERR(call->filter))
+               return PTR_ERR(call->filter);
+
+       return 0;
 }
 
 static int init_subsystem_preds(struct event_subsystem *system)
@@ -615,14 +625,7 @@ static int init_subsystem_preds(struct event_subsystem *system)
        return 0;
 }
 
-enum {
-       FILTER_DISABLE_ALL,
-       FILTER_INIT_NO_RESET,
-       FILTER_SKIP_NO_RESET,
-};
-
-static void filter_free_subsystem_preds(struct event_subsystem *system,
-                                       int flag)
+static void filter_free_subsystem_preds(struct event_subsystem *system)
 {
        struct ftrace_event_call *call;
 
@@ -633,14 +636,6 @@ static void filter_free_subsystem_preds(struct event_subsystem *system,
                if (strcmp(call->system, system->name) != 0)
                        continue;
 
-               if (flag == FILTER_INIT_NO_RESET) {
-                       call->filter->no_reset = false;
-                       continue;
-               }
-
-               if (flag == FILTER_SKIP_NO_RESET && call->filter->no_reset)
-                       continue;
-
                filter_disable_preds(call);
                remove_filter_string(call->filter);
        }
@@ -648,10 +643,10 @@ static void filter_free_subsystem_preds(struct event_subsystem *system,
 
 static int filter_add_pred_fn(struct filter_parse_state *ps,
                              struct ftrace_event_call *call,
+                             struct event_filter *filter,
                              struct filter_pred *pred,
                              filter_pred_fn_t fn)
 {
-       struct event_filter *filter = call->filter;
        int idx, err;
 
        if (filter->n_preds == MAX_FILTER_PRED) {
@@ -666,7 +661,6 @@ static int filter_add_pred_fn(struct filter_parse_state *ps,
                return err;
 
        filter->n_preds++;
-       call->filter_active = 1;
 
        return 0;
 }
@@ -691,7 +685,10 @@ static bool is_string_field(struct ftrace_event_field *field)
 
 static int is_legal_op(struct ftrace_event_field *field, int op)
 {
-       if (is_string_field(field) && (op != OP_EQ && op != OP_NE))
+       if (is_string_field(field) &&
+           (op != OP_EQ && op != OP_NE && op != OP_GLOB))
+               return 0;
+       if (!is_string_field(field) && op == OP_GLOB)
                return 0;
 
        return 1;
@@ -742,6 +739,7 @@ static filter_pred_fn_t select_comparison_fn(int op, int field_size,
 
 static int filter_add_pred(struct filter_parse_state *ps,
                           struct ftrace_event_call *call,
+                          struct event_filter *filter,
                           struct filter_pred *pred,
                           bool dry_run)
 {
@@ -776,15 +774,13 @@ static int filter_add_pred(struct filter_parse_state *ps,
        }
 
        if (is_string_field(field)) {
-               ret = filter_build_regex(pred);
-               if (ret)
-                       return ret;
+               filter_build_regex(pred);
 
                if (field->filter_type == FILTER_STATIC_STRING) {
                        fn = filter_pred_string;
                        pred->regex.field_len = field->size;
                } else if (field->filter_type == FILTER_DYN_STRING)
-                               fn = filter_pred_strloc;
+                       fn = filter_pred_strloc;
                else {
                        fn = filter_pred_pchar;
                        pred->regex.field_len = strlen(pred->regex.pattern);
@@ -813,45 +809,7 @@ static int filter_add_pred(struct filter_parse_state *ps,
 
 add_pred_fn:
        if (!dry_run)
-               return filter_add_pred_fn(ps, call, pred, fn);
-       return 0;
-}
-
-static int filter_add_subsystem_pred(struct filter_parse_state *ps,
-                                    struct event_subsystem *system,
-                                    struct filter_pred *pred,
-                                    char *filter_string,
-                                    bool dry_run)
-{
-       struct ftrace_event_call *call;
-       int err = 0;
-       bool fail = true;
-
-       list_for_each_entry(call, &ftrace_events, list) {
-
-               if (!call->define_fields)
-                       continue;
-
-               if (strcmp(call->system, system->name))
-                       continue;
-
-               if (call->filter->no_reset)
-                       continue;
-
-               err = filter_add_pred(ps, call, pred, dry_run);
-               if (err)
-                       call->filter->no_reset = true;
-               else
-                       fail = false;
-
-               if (!dry_run)
-                       replace_filter_string(call->filter, filter_string);
-       }
-
-       if (fail) {
-               parse_error(ps, FILT_ERR_BAD_SUBSYS_FILTER, 0);
-               return err;
-       }
+               return filter_add_pred_fn(ps, call, filter, pred, fn);
        return 0;
 }
 
@@ -1209,8 +1167,8 @@ static int check_preds(struct filter_parse_state *ps)
        return 0;
 }
 
-static int replace_preds(struct event_subsystem *system,
-                        struct ftrace_event_call *call,
+static int replace_preds(struct ftrace_event_call *call,
+                        struct event_filter *filter,
                         struct filter_parse_state *ps,
                         char *filter_string,
                         bool dry_run)
@@ -1257,11 +1215,7 @@ static int replace_preds(struct event_subsystem *system,
 add_pred:
                if (!pred)
                        return -ENOMEM;
-               if (call)
-                       err = filter_add_pred(ps, call, pred, false);
-               else
-                       err = filter_add_subsystem_pred(ps, system, pred,
-                                               filter_string, dry_run);
+               err = filter_add_pred(ps, call, filter, pred, dry_run);
                filter_free_pred(pred);
                if (err)
                        return err;
@@ -1272,10 +1226,50 @@ add_pred:
        return 0;
 }
 
-int apply_event_filter(struct ftrace_event_call *call, char *filter_string)
+static int replace_system_preds(struct event_subsystem *system,
+                               struct filter_parse_state *ps,
+                               char *filter_string)
 {
+       struct ftrace_event_call *call;
+       bool fail = true;
        int err;
 
+       list_for_each_entry(call, &ftrace_events, list) {
+               struct event_filter *filter = call->filter;
+
+               if (!call->define_fields)
+                       continue;
+
+               if (strcmp(call->system, system->name) != 0)
+                       continue;
+
+               /* try to see if the filter can be applied */
+               err = replace_preds(call, filter, ps, filter_string, true);
+               if (err)
+                       continue;
+
+               /* really apply the filter */
+               filter_disable_preds(call);
+               err = replace_preds(call, filter, ps, filter_string, false);
+               if (err)
+                       filter_disable_preds(call);
+               else {
+                       call->filter_active = 1;
+                       replace_filter_string(filter, filter_string);
+               }
+               fail = false;
+       }
+
+       if (fail) {
+               parse_error(ps, FILT_ERR_BAD_SUBSYS_FILTER, 0);
+               return -EINVAL;
+       }
+       return 0;
+}
+
+int apply_event_filter(struct ftrace_event_call *call, char *filter_string)
+{
+       int err;
        struct filter_parse_state *ps;
 
        mutex_lock(&event_mutex);
@@ -1287,8 +1281,7 @@ int apply_event_filter(struct ftrace_event_call *call, char *filter_string)
        if (!strcmp(strstrip(filter_string), "0")) {
                filter_disable_preds(call);
                remove_filter_string(call->filter);
-               mutex_unlock(&event_mutex);
-               return 0;
+               goto out_unlock;
        }
 
        err = -ENOMEM;
@@ -1306,10 +1299,11 @@ int apply_event_filter(struct ftrace_event_call *call, char *filter_string)
                goto out;
        }
 
-       err = replace_preds(NULL, call, ps, filter_string, false);
+       err = replace_preds(call, call->filter, ps, filter_string, false);
        if (err)
                append_filter_err(ps, call->filter);
-
+       else
+               call->filter_active = 1;
 out:
        filter_opstack_clear(ps);
        postfix_clear(ps);
@@ -1324,7 +1318,6 @@ int apply_subsystem_event_filter(struct event_subsystem *system,
                                 char *filter_string)
 {
        int err;
-
        struct filter_parse_state *ps;
 
        mutex_lock(&event_mutex);
@@ -1334,10 +1327,9 @@ int apply_subsystem_event_filter(struct event_subsystem *system,
                goto out_unlock;
 
        if (!strcmp(strstrip(filter_string), "0")) {
-               filter_free_subsystem_preds(system, FILTER_DISABLE_ALL);
+               filter_free_subsystem_preds(system);
                remove_filter_string(system->filter);
-               mutex_unlock(&event_mutex);
-               return 0;
+               goto out_unlock;
        }
 
        err = -ENOMEM;
@@ -1354,31 +1346,87 @@ int apply_subsystem_event_filter(struct event_subsystem *system,
                goto out;
        }
 
-       filter_free_subsystem_preds(system, FILTER_INIT_NO_RESET);
-
-       /* try to see the filter can be applied to which events */
-       err = replace_preds(system, NULL, ps, filter_string, true);
-       if (err) {
+       err = replace_system_preds(system, ps, filter_string);
+       if (err)
                append_filter_err(ps, system->filter);
-               goto out;
+
+out:
+       filter_opstack_clear(ps);
+       postfix_clear(ps);
+       kfree(ps);
+out_unlock:
+       mutex_unlock(&event_mutex);
+
+       return err;
+}
+
+#ifdef CONFIG_EVENT_PROFILE
+
+void ftrace_profile_free_filter(struct perf_event *event)
+{
+       struct event_filter *filter = event->filter;
+
+       event->filter = NULL;
+       __free_preds(filter);
+}
+
+int ftrace_profile_set_filter(struct perf_event *event, int event_id,
+                             char *filter_str)
+{
+       int err;
+       struct event_filter *filter;
+       struct filter_parse_state *ps;
+       struct ftrace_event_call *call = NULL;
+
+       mutex_lock(&event_mutex);
+
+       list_for_each_entry(call, &ftrace_events, list) {
+               if (call->id == event_id)
+                       break;
        }
 
-       filter_free_subsystem_preds(system, FILTER_SKIP_NO_RESET);
+       err = -EINVAL;
+       if (!call)
+               goto out_unlock;
 
-       /* really apply the filter to the events */
-       err = replace_preds(system, NULL, ps, filter_string, false);
-       if (err) {
-               append_filter_err(ps, system->filter);
-               filter_free_subsystem_preds(system, 2);
+       err = -EEXIST;
+       if (event->filter)
+               goto out_unlock;
+
+       filter = __alloc_preds();
+       if (IS_ERR(filter)) {
+               err = PTR_ERR(filter);
+               goto out_unlock;
        }
 
-out:
+       err = -ENOMEM;
+       ps = kzalloc(sizeof(*ps), GFP_KERNEL);
+       if (!ps)
+               goto free_preds;
+
+       parse_init(ps, filter_ops, filter_str);
+       err = filter_parse(ps);
+       if (err)
+               goto free_ps;
+
+       err = replace_preds(call, filter, ps, filter_str, false);
+       if (!err)
+               event->filter = filter;
+
+free_ps:
        filter_opstack_clear(ps);
        postfix_clear(ps);
        kfree(ps);
+
+free_preds:
+       if (err)
+               __free_preds(filter);
+
 out_unlock:
        mutex_unlock(&event_mutex);
 
        return err;
 }
 
+#endif /* CONFIG_EVENT_PROFILE */
+
index c74848d..dff8c84 100644 (file)
@@ -66,44 +66,47 @@ static void __always_unused ____ftrace_check_##name(void)   \
 #undef __field
 #define __field(type, item)                                            \
        ret = trace_seq_printf(s, "\tfield:" #type " " #item ";\t"      \
-                              "offset:%zu;\tsize:%zu;\n",              \
+                              "offset:%zu;\tsize:%zu;\tsigned:%u;\n",  \
                               offsetof(typeof(field), item),           \
-                              sizeof(field.item));                     \
+                              sizeof(field.item), is_signed_type(type)); \
        if (!ret)                                                       \
                return 0;
 
 #undef __field_desc
 #define __field_desc(type, container, item)                            \
        ret = trace_seq_printf(s, "\tfield:" #type " " #item ";\t"      \
-                              "offset:%zu;\tsize:%zu;\n",              \
+                              "offset:%zu;\tsize:%zu;\tsigned:%u;\n",  \
                               offsetof(typeof(field), container.item), \
-                              sizeof(field.container.item));           \
+                              sizeof(field.container.item),            \
+                              is_signed_type(type));                   \
        if (!ret)                                                       \
                return 0;
 
 #undef __array
 #define __array(type, item, len)                                       \
        ret = trace_seq_printf(s, "\tfield:" #type " " #item "[" #len "];\t" \
-                              "offset:%zu;\tsize:%zu;\n",              \
-                              offsetof(typeof(field), item),   \
-                              sizeof(field.item));             \
+                              "offset:%zu;\tsize:%zu;\tsigned:%u;\n",  \
+                              offsetof(typeof(field), item),           \
+                              sizeof(field.item), is_signed_type(type)); \
        if (!ret)                                                       \
                return 0;
 
 #undef __array_desc
 #define __array_desc(type, container, item, len)                       \
        ret = trace_seq_printf(s, "\tfield:" #type " " #item "[" #len "];\t" \
-                              "offset:%zu;\tsize:%zu;\n",              \
+                              "offset:%zu;\tsize:%zu;\tsigned:%u;\n",  \
                               offsetof(typeof(field), container.item), \
-                              sizeof(field.container.item));           \
+                              sizeof(field.container.item),            \
+                              is_signed_type(type));                   \
        if (!ret)                                                       \
                return 0;
 
 #undef __dynamic_array
 #define __dynamic_array(type, item)                                    \
        ret = trace_seq_printf(s, "\tfield:" #type " " #item ";\t"      \
-                              "offset:%zu;\tsize:0;\n",                \
-                              offsetof(typeof(field), item));          \
+                              "offset:%zu;\tsize:0;\tsigned:%u;\n",    \
+                              offsetof(typeof(field), item),           \
+                              is_signed_type(type));                   \
        if (!ret)                                                       \
                return 0;
 
@@ -131,7 +134,6 @@ ftrace_format_##name(struct ftrace_event_call *unused,                      \
 
 #include "trace_entries.h"
 
-
 #undef __field
 #define __field(type, item)                                            \
        ret = trace_define_field(event_call, #type, #item,              \
@@ -193,6 +195,11 @@ ftrace_define_fields_##name(struct ftrace_event_call *event_call)  \
 
 #include "trace_entries.h"
 
+static int ftrace_raw_init_event(struct ftrace_event_call *call)
+{
+       INIT_LIST_HEAD(&call->fields);
+       return 0;
+}
 
 #undef __field
 #define __field(type, item)
@@ -211,7 +218,6 @@ ftrace_define_fields_##name(struct ftrace_event_call *event_call)   \
 
 #undef FTRACE_ENTRY
 #define FTRACE_ENTRY(call, struct_name, type, tstruct, print)          \
-static int ftrace_raw_init_event_##call(void);                         \
                                                                        \
 struct ftrace_event_call __used                                                \
 __attribute__((__aligned__(4)))                                                \
@@ -219,14 +225,9 @@ __attribute__((section("_ftrace_events"))) event_##call = {                \
        .name                   = #call,                                \
        .id                     = type,                                 \
        .system                 = __stringify(TRACE_SYSTEM),            \
-       .raw_init               = ftrace_raw_init_event_##call,         \
+       .raw_init               = ftrace_raw_init_event,                \
        .show_format            = ftrace_format_##call,                 \
        .define_fields          = ftrace_define_fields_##call,          \
 };                                                                     \
-static int ftrace_raw_init_event_##call(void)                          \
-{                                                                      \
-       INIT_LIST_HEAD(&event_##call.fields);                           \
-       return 0;                                                       \
-}                                                                      \
 
 #include "trace_entries.h"
diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c
new file mode 100644 (file)
index 0000000..aff5f80
--- /dev/null
@@ -0,0 +1,1523 @@
+/*
+ * Kprobes-based tracing events
+ *
+ * Created by Masami Hiramatsu <mhiramat@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/module.h>
+#include <linux/uaccess.h>
+#include <linux/kprobes.h>
+#include <linux/seq_file.h>
+#include <linux/slab.h>
+#include <linux/smp.h>
+#include <linux/debugfs.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/ctype.h>
+#include <linux/ptrace.h>
+#include <linux/perf_event.h>
+
+#include "trace.h"
+#include "trace_output.h"
+
+#define MAX_TRACE_ARGS 128
+#define MAX_ARGSTR_LEN 63
+#define MAX_EVENT_NAME_LEN 64
+#define KPROBE_EVENT_SYSTEM "kprobes"
+
+/* Reserved field names */
+#define FIELD_STRING_IP "__probe_ip"
+#define FIELD_STRING_NARGS "__probe_nargs"
+#define FIELD_STRING_RETIP "__probe_ret_ip"
+#define FIELD_STRING_FUNC "__probe_func"
+
+const char *reserved_field_names[] = {
+       "common_type",
+       "common_flags",
+       "common_preempt_count",
+       "common_pid",
+       "common_tgid",
+       "common_lock_depth",
+       FIELD_STRING_IP,
+       FIELD_STRING_NARGS,
+       FIELD_STRING_RETIP,
+       FIELD_STRING_FUNC,
+};
+
+struct fetch_func {
+       unsigned long (*func)(struct pt_regs *, void *);
+       void *data;
+};
+
+static __kprobes unsigned long call_fetch(struct fetch_func *f,
+                                         struct pt_regs *regs)
+{
+       return f->func(regs, f->data);
+}
+
+/* fetch handlers */
+static __kprobes unsigned long fetch_register(struct pt_regs *regs,
+                                             void *offset)
+{
+       return regs_get_register(regs, (unsigned int)((unsigned long)offset));
+}
+
+static __kprobes unsigned long fetch_stack(struct pt_regs *regs,
+                                          void *num)
+{
+       return regs_get_kernel_stack_nth(regs,
+                                        (unsigned int)((unsigned long)num));
+}
+
+static __kprobes unsigned long fetch_memory(struct pt_regs *regs, void *addr)
+{
+       unsigned long retval;
+
+       if (probe_kernel_address(addr, retval))
+               return 0;
+       return retval;
+}
+
+static __kprobes unsigned long fetch_argument(struct pt_regs *regs, void *num)
+{
+       return regs_get_argument_nth(regs, (unsigned int)((unsigned long)num));
+}
+
+static __kprobes unsigned long fetch_retvalue(struct pt_regs *regs,
+                                             void *dummy)
+{
+       return regs_return_value(regs);
+}
+
+static __kprobes unsigned long fetch_stack_address(struct pt_regs *regs,
+                                                  void *dummy)
+{
+       return kernel_stack_pointer(regs);
+}
+
+/* Memory fetching by symbol */
+struct symbol_cache {
+       char *symbol;
+       long offset;
+       unsigned long addr;
+};
+
+static unsigned long update_symbol_cache(struct symbol_cache *sc)
+{
+       sc->addr = (unsigned long)kallsyms_lookup_name(sc->symbol);
+       if (sc->addr)
+               sc->addr += sc->offset;
+       return sc->addr;
+}
+
+static void free_symbol_cache(struct symbol_cache *sc)
+{
+       kfree(sc->symbol);
+       kfree(sc);
+}
+
+static struct symbol_cache *alloc_symbol_cache(const char *sym, long offset)
+{
+       struct symbol_cache *sc;
+
+       if (!sym || strlen(sym) == 0)
+               return NULL;
+       sc = kzalloc(sizeof(struct symbol_cache), GFP_KERNEL);
+       if (!sc)
+               return NULL;
+
+       sc->symbol = kstrdup(sym, GFP_KERNEL);
+       if (!sc->symbol) {
+               kfree(sc);
+               return NULL;
+       }
+       sc->offset = offset;
+
+       update_symbol_cache(sc);
+       return sc;
+}
+
+static __kprobes unsigned long fetch_symbol(struct pt_regs *regs, void *data)
+{
+       struct symbol_cache *sc = data;
+
+       if (sc->addr)
+               return fetch_memory(regs, (void *)sc->addr);
+       else
+               return 0;
+}
+
+/* Special indirect memory access interface */
+struct indirect_fetch_data {
+       struct fetch_func orig;
+       long offset;
+};
+
+static __kprobes unsigned long fetch_indirect(struct pt_regs *regs, void *data)
+{
+       struct indirect_fetch_data *ind = data;
+       unsigned long addr;
+
+       addr = call_fetch(&ind->orig, regs);
+       if (addr) {
+               addr += ind->offset;
+               return fetch_memory(regs, (void *)addr);
+       } else
+               return 0;
+}
+
+static __kprobes void free_indirect_fetch_data(struct indirect_fetch_data *data)
+{
+       if (data->orig.func == fetch_indirect)
+               free_indirect_fetch_data(data->orig.data);
+       else if (data->orig.func == fetch_symbol)
+               free_symbol_cache(data->orig.data);
+       kfree(data);
+}
+
+/**
+ * Kprobe event core functions
+ */
+
+struct probe_arg {
+       struct fetch_func       fetch;
+       const char              *name;
+};
+
+/* Flags for trace_probe */
+#define TP_FLAG_TRACE  1
+#define TP_FLAG_PROFILE        2
+
+struct trace_probe {
+       struct list_head        list;
+       struct kretprobe        rp;     /* Use rp.kp for kprobe use */
+       unsigned long           nhit;
+       unsigned int            flags;  /* For TP_FLAG_* */
+       const char              *symbol;        /* symbol name */
+       struct ftrace_event_call        call;
+       struct trace_event              event;
+       unsigned int            nr_args;
+       struct probe_arg        args[];
+};
+
+#define SIZEOF_TRACE_PROBE(n)                  \
+       (offsetof(struct trace_probe, args) +   \
+       (sizeof(struct probe_arg) * (n)))
+
+static __kprobes int probe_is_return(struct trace_probe *tp)
+{
+       return tp->rp.handler != NULL;
+}
+
+static __kprobes const char *probe_symbol(struct trace_probe *tp)
+{
+       return tp->symbol ? tp->symbol : "unknown";
+}
+
+static int probe_arg_string(char *buf, size_t n, struct fetch_func *ff)
+{
+       int ret = -EINVAL;
+
+       if (ff->func == fetch_argument)
+               ret = snprintf(buf, n, "$arg%lu", (unsigned long)ff->data);
+       else if (ff->func == fetch_register) {
+               const char *name;
+               name = regs_query_register_name((unsigned int)((long)ff->data));
+               ret = snprintf(buf, n, "%%%s", name);
+       } else if (ff->func == fetch_stack)
+               ret = snprintf(buf, n, "$stack%lu", (unsigned long)ff->data);
+       else if (ff->func == fetch_memory)
+               ret = snprintf(buf, n, "@0x%p", ff->data);
+       else if (ff->func == fetch_symbol) {
+               struct symbol_cache *sc = ff->data;
+               if (sc->offset)
+                       ret = snprintf(buf, n, "@%s%+ld", sc->symbol,
+                                       sc->offset);
+               else
+                       ret = snprintf(buf, n, "@%s", sc->symbol);
+       } else if (ff->func == fetch_retvalue)
+               ret = snprintf(buf, n, "$retval");
+       else if (ff->func == fetch_stack_address)
+               ret = snprintf(buf, n, "$stack");
+       else if (ff->func == fetch_indirect) {
+               struct indirect_fetch_data *id = ff->data;
+               size_t l = 0;
+               ret = snprintf(buf, n, "%+ld(", id->offset);
+               if (ret >= n)
+                       goto end;
+               l += ret;
+               ret = probe_arg_string(buf + l, n - l, &id->orig);
+               if (ret < 0)
+                       goto end;
+               l += ret;
+               ret = snprintf(buf + l, n - l, ")");
+               ret += l;
+       }
+end:
+       if (ret >= n)
+               return -ENOSPC;
+       return ret;
+}
+
+static int register_probe_event(struct trace_probe *tp);
+static void unregister_probe_event(struct trace_probe *tp);
+
+static DEFINE_MUTEX(probe_lock);
+static LIST_HEAD(probe_list);
+
+static int kprobe_dispatcher(struct kprobe *kp, struct pt_regs *regs);
+static int kretprobe_dispatcher(struct kretprobe_instance *ri,
+                               struct pt_regs *regs);
+
+/*
+ * Allocate new trace_probe and initialize it (including kprobes).
+ */
+static struct trace_probe *alloc_trace_probe(const char *group,
+                                            const char *event,
+                                            void *addr,
+                                            const char *symbol,
+                                            unsigned long offs,
+                                            int nargs, int is_return)
+{
+       struct trace_probe *tp;
+
+       tp = kzalloc(SIZEOF_TRACE_PROBE(nargs), GFP_KERNEL);
+       if (!tp)
+               return ERR_PTR(-ENOMEM);
+
+       if (symbol) {
+               tp->symbol = kstrdup(symbol, GFP_KERNEL);
+               if (!tp->symbol)
+                       goto error;
+               tp->rp.kp.symbol_name = tp->symbol;
+               tp->rp.kp.offset = offs;
+       } else
+               tp->rp.kp.addr = addr;
+
+       if (is_return)
+               tp->rp.handler = kretprobe_dispatcher;
+       else
+               tp->rp.kp.pre_handler = kprobe_dispatcher;
+
+       if (!event)
+               goto error;
+       tp->call.name = kstrdup(event, GFP_KERNEL);
+       if (!tp->call.name)
+               goto error;
+
+       if (!group)
+               goto error;
+       tp->call.system = kstrdup(group, GFP_KERNEL);
+       if (!tp->call.system)
+               goto error;
+
+       INIT_LIST_HEAD(&tp->list);
+       return tp;
+error:
+       kfree(tp->call.name);
+       kfree(tp->symbol);
+       kfree(tp);
+       return ERR_PTR(-ENOMEM);
+}
+
+static void free_probe_arg(struct probe_arg *arg)
+{
+       if (arg->fetch.func == fetch_symbol)
+               free_symbol_cache(arg->fetch.data);
+       else if (arg->fetch.func == fetch_indirect)
+               free_indirect_fetch_data(arg->fetch.data);
+       kfree(arg->name);
+}
+
+static void free_trace_probe(struct trace_probe *tp)
+{
+       int i;
+
+       for (i = 0; i < tp->nr_args; i++)
+               free_probe_arg(&tp->args[i]);
+
+       kfree(tp->call.system);
+       kfree(tp->call.name);
+       kfree(tp->symbol);
+       kfree(tp);
+}
+
+static struct trace_probe *find_probe_event(const char *event,
+                                           const char *group)
+{
+       struct trace_probe *tp;
+
+       list_for_each_entry(tp, &probe_list, list)
+               if (strcmp(tp->call.name, event) == 0 &&
+                   strcmp(tp->call.system, group) == 0)
+                       return tp;
+       return NULL;
+}
+
+/* Unregister a trace_probe and probe_event: call with locking probe_lock */
+static void unregister_trace_probe(struct trace_probe *tp)
+{
+       if (probe_is_return(tp))
+               unregister_kretprobe(&tp->rp);
+       else
+               unregister_kprobe(&tp->rp.kp);
+       list_del(&tp->list);
+       unregister_probe_event(tp);
+}
+
+/* Register a trace_probe and probe_event */
+static int register_trace_probe(struct trace_probe *tp)
+{
+       struct trace_probe *old_tp;
+       int ret;
+
+       mutex_lock(&probe_lock);
+
+       /* register as an event */
+       old_tp = find_probe_event(tp->call.name, tp->call.system);
+       if (old_tp) {
+               /* delete old event */
+               unregister_trace_probe(old_tp);
+               free_trace_probe(old_tp);
+       }
+       ret = register_probe_event(tp);
+       if (ret) {
+               pr_warning("Faild to register probe event(%d)\n", ret);
+               goto end;
+       }
+
+       tp->rp.kp.flags |= KPROBE_FLAG_DISABLED;
+       if (probe_is_return(tp))
+               ret = register_kretprobe(&tp->rp);
+       else
+               ret = register_kprobe(&tp->rp.kp);
+
+       if (ret) {
+               pr_warning("Could not insert probe(%d)\n", ret);
+               if (ret == -EILSEQ) {
+                       pr_warning("Probing address(0x%p) is not an "
+                                  "instruction boundary.\n",
+                                  tp->rp.kp.addr);
+                       ret = -EINVAL;
+               }
+               unregister_probe_event(tp);
+       } else
+               list_add_tail(&tp->list, &probe_list);
+end:
+       mutex_unlock(&probe_lock);
+       return ret;
+}
+
+/* Split symbol and offset. */
+static int split_symbol_offset(char *symbol, unsigned long *offset)
+{
+       char *tmp;
+       int ret;
+
+       if (!offset)
+               return -EINVAL;
+
+       tmp = strchr(symbol, '+');
+       if (tmp) {
+               /* skip sign because strict_strtol doesn't accept '+' */
+               ret = strict_strtoul(tmp + 1, 0, offset);
+               if (ret)
+                       return ret;
+               *tmp = '\0';
+       } else
+               *offset = 0;
+       return 0;
+}
+
+#define PARAM_MAX_ARGS 16
+#define PARAM_MAX_STACK (THREAD_SIZE / sizeof(unsigned long))
+
+static int parse_probe_vars(char *arg, struct fetch_func *ff, int is_return)
+{
+       int ret = 0;
+       unsigned long param;
+
+       if (strcmp(arg, "retval") == 0) {
+               if (is_return) {
+                       ff->func = fetch_retvalue;
+                       ff->data = NULL;
+               } else
+                       ret = -EINVAL;
+       } else if (strncmp(arg, "stack", 5) == 0) {
+               if (arg[5] == '\0') {
+                       ff->func = fetch_stack_address;
+                       ff->data = NULL;
+               } else if (isdigit(arg[5])) {
+                       ret = strict_strtoul(arg + 5, 10, &param);
+                       if (ret || param > PARAM_MAX_STACK)
+                               ret = -EINVAL;
+                       else {
+                               ff->func = fetch_stack;
+                               ff->data = (void *)param;
+                       }
+               } else
+                       ret = -EINVAL;
+       } else if (strncmp(arg, "arg", 3) == 0 && isdigit(arg[3])) {
+               ret = strict_strtoul(arg + 3, 10, &param);
+               if (ret || param > PARAM_MAX_ARGS)
+                       ret = -EINVAL;
+               else {
+                       ff->func = fetch_argument;
+                       ff->data = (void *)param;
+               }
+       } else
+               ret = -EINVAL;
+       return ret;
+}
+
+/* Recursive argument parser */
+static int __parse_probe_arg(char *arg, struct fetch_func *ff, int is_return)
+{
+       int ret = 0;
+       unsigned long param;
+       long offset;
+       char *tmp;
+
+       switch (arg[0]) {
+       case '$':
+               ret = parse_probe_vars(arg + 1, ff, is_return);
+               break;
+       case '%':       /* named register */
+               ret = regs_query_register_offset(arg + 1);
+               if (ret >= 0) {
+                       ff->func = fetch_register;
+                       ff->data = (void *)(unsigned long)ret;
+                       ret = 0;
+               }
+               break;
+       case '@':       /* memory or symbol */
+               if (isdigit(arg[1])) {
+                       ret = strict_strtoul(arg + 1, 0, &param);
+                       if (ret)
+                               break;
+                       ff->func = fetch_memory;
+                       ff->data = (void *)param;
+               } else {
+                       ret = split_symbol_offset(arg + 1, &offset);
+                       if (ret)
+                               break;
+                       ff->data = alloc_symbol_cache(arg + 1, offset);
+                       if (ff->data)
+                               ff->func = fetch_symbol;
+                       else
+                               ret = -EINVAL;
+               }
+               break;
+       case '+':       /* indirect memory */
+       case '-':
+               tmp = strchr(arg, '(');
+               if (!tmp) {
+                       ret = -EINVAL;
+                       break;
+               }
+               *tmp = '\0';
+               ret = strict_strtol(arg + 1, 0, &offset);
+               if (ret)
+                       break;
+               if (arg[0] == '-')
+                       offset = -offset;
+               arg = tmp + 1;
+               tmp = strrchr(arg, ')');
+               if (tmp) {
+                       struct indirect_fetch_data *id;
+                       *tmp = '\0';
+                       id = kzalloc(sizeof(struct indirect_fetch_data),
+                                    GFP_KERNEL);
+                       if (!id)
+                               return -ENOMEM;
+                       id->offset = offset;
+                       ret = __parse_probe_arg(arg, &id->orig, is_return);
+                       if (ret)
+                               kfree(id);
+                       else {
+                               ff->func = fetch_indirect;
+                               ff->data = (void *)id;
+                       }
+               } else
+                       ret = -EINVAL;
+               break;
+       default:
+               /* TODO: support custom handler */
+               ret = -EINVAL;
+       }
+       return ret;
+}
+
+/* String length checking wrapper */
+static int parse_probe_arg(char *arg, struct fetch_func *ff, int is_return)
+{
+       if (strlen(arg) > MAX_ARGSTR_LEN) {
+               pr_info("Argument is too long.: %s\n",  arg);
+               return -ENOSPC;
+       }
+       return __parse_probe_arg(arg, ff, is_return);
+}
+
+/* Return 1 if name is reserved or already used by another argument */
+static int conflict_field_name(const char *name,
+                              struct probe_arg *args, int narg)
+{
+       int i;
+       for (i = 0; i < ARRAY_SIZE(reserved_field_names); i++)
+               if (strcmp(reserved_field_names[i], name) == 0)
+                       return 1;
+       for (i = 0; i < narg; i++)
+               if (strcmp(args[i].name, name) == 0)
+                       return 1;
+       return 0;
+}
+
+static int create_trace_probe(int argc, char **argv)
+{
+       /*
+        * Argument syntax:
+        *  - Add kprobe: p[:[GRP/]EVENT] KSYM[+OFFS]|KADDR [FETCHARGS]
+        *  - Add kretprobe: r[:[GRP/]EVENT] KSYM[+0] [FETCHARGS]
+        * Fetch args:
+        *  $argN       : fetch Nth of function argument. (N:0-)
+        *  $retval     : fetch return value
+        *  $stack      : fetch stack address
+        *  $stackN     : fetch Nth of stack (N:0-)
+        *  @ADDR       : fetch memory at ADDR (ADDR should be in kernel)
+        *  @SYM[+|-offs] : fetch memory at SYM +|- offs (SYM is a data symbol)
+        *  %REG        : fetch register REG
+        * Indirect memory fetch:
+        *  +|-offs(ARG) : fetch memory at ARG +|- offs address.
+        * Alias name of args:
+        *  NAME=FETCHARG : set NAME as alias of FETCHARG.
+        */
+       struct trace_probe *tp;
+       int i, ret = 0;
+       int is_return = 0;
+       char *symbol = NULL, *event = NULL, *arg = NULL, *group = NULL;
+       unsigned long offset = 0;
+       void *addr = NULL;
+       char buf[MAX_EVENT_NAME_LEN];
+
+       if (argc < 2) {
+               pr_info("Probe point is not specified.\n");
+               return -EINVAL;
+       }
+
+       if (argv[0][0] == 'p')
+               is_return = 0;
+       else if (argv[0][0] == 'r')
+               is_return = 1;
+       else {
+               pr_info("Probe definition must be started with 'p' or 'r'.\n");
+               return -EINVAL;
+       }
+
+       if (argv[0][1] == ':') {
+               event = &argv[0][2];
+               if (strchr(event, '/')) {
+                       group = event;
+                       event = strchr(group, '/') + 1;
+                       event[-1] = '\0';
+                       if (strlen(group) == 0) {
+                               pr_info("Group name is not specifiled\n");
+                               return -EINVAL;
+                       }
+               }
+               if (strlen(event) == 0) {
+                       pr_info("Event name is not specifiled\n");
+                       return -EINVAL;
+               }
+       }
+
+       if (isdigit(argv[1][0])) {
+               if (is_return) {
+                       pr_info("Return probe point must be a symbol.\n");
+                       return -EINVAL;
+               }
+               /* an address specified */
+               ret = strict_strtoul(&argv[0][2], 0, (unsigned long *)&addr);
+               if (ret) {
+                       pr_info("Failed to parse address.\n");
+                       return ret;
+               }
+       } else {
+               /* a symbol specified */
+               symbol = argv[1];
+               /* TODO: support .init module functions */
+               ret = split_symbol_offset(symbol, &offset);
+               if (ret) {
+                       pr_info("Failed to parse symbol.\n");
+                       return ret;
+               }
+               if (offset && is_return) {
+                       pr_info("Return probe must be used without offset.\n");
+                       return -EINVAL;
+               }
+       }
+       argc -= 2; argv += 2;
+
+       /* setup a probe */
+       if (!group)
+               group = KPROBE_EVENT_SYSTEM;
+       if (!event) {
+               /* Make a new event name */
+               if (symbol)
+                       snprintf(buf, MAX_EVENT_NAME_LEN, "%c@%s%+ld",
+                                is_return ? 'r' : 'p', symbol, offset);
+               else
+                       snprintf(buf, MAX_EVENT_NAME_LEN, "%c@0x%p",
+                                is_return ? 'r' : 'p', addr);
+               event = buf;
+       }
+       tp = alloc_trace_probe(group, event, addr, symbol, offset, argc,
+                              is_return);
+       if (IS_ERR(tp)) {
+               pr_info("Failed to allocate trace_probe.(%d)\n",
+                       (int)PTR_ERR(tp));
+               return PTR_ERR(tp);
+       }
+
+       /* parse arguments */
+       ret = 0;
+       for (i = 0; i < argc && i < MAX_TRACE_ARGS; i++) {
+               /* Parse argument name */
+               arg = strchr(argv[i], '=');
+               if (arg)
+                       *arg++ = '\0';
+               else
+                       arg = argv[i];
+
+               if (conflict_field_name(argv[i], tp->args, i)) {
+                       pr_info("Argument%d name '%s' conflicts with "
+                               "another field.\n", i, argv[i]);
+                       ret = -EINVAL;
+                       goto error;
+               }
+
+               tp->args[i].name = kstrdup(argv[i], GFP_KERNEL);
+               if (!tp->args[i].name) {
+                       pr_info("Failed to allocate argument%d name '%s'.\n",
+                               i, argv[i]);
+                       ret = -ENOMEM;
+                       goto error;
+               }
+
+               /* Parse fetch argument */
+               ret = parse_probe_arg(arg, &tp->args[i].fetch, is_return);
+               if (ret) {
+                       pr_info("Parse error at argument%d. (%d)\n", i, ret);
+                       kfree(tp->args[i].name);
+                       goto error;
+               }
+
+               tp->nr_args++;
+       }
+
+       ret = register_trace_probe(tp);
+       if (ret)
+               goto error;
+       return 0;
+
+error:
+       free_trace_probe(tp);
+       return ret;
+}
+
+static void cleanup_all_probes(void)
+{
+       struct trace_probe *tp;
+
+       mutex_lock(&probe_lock);
+       /* TODO: Use batch unregistration */
+       while (!list_empty(&probe_list)) {
+               tp = list_entry(probe_list.next, struct trace_probe, list);
+               unregister_trace_probe(tp);
+               free_trace_probe(tp);
+       }
+       mutex_unlock(&probe_lock);
+}
+
+
+/* Probes listing interfaces */
+static void *probes_seq_start(struct seq_file *m, loff_t *pos)
+{
+       mutex_lock(&probe_lock);
+       return seq_list_start(&probe_list, *pos);
+}
+
+static void *probes_seq_next(struct seq_file *m, void *v, loff_t *pos)
+{
+       return seq_list_next(v, &probe_list, pos);
+}
+
+static void probes_seq_stop(struct seq_file *m, void *v)
+{
+       mutex_unlock(&probe_lock);
+}
+
+static int probes_seq_show(struct seq_file *m, void *v)
+{
+       struct trace_probe *tp = v;
+       int i, ret;
+       char buf[MAX_ARGSTR_LEN + 1];
+
+       seq_printf(m, "%c", probe_is_return(tp) ? 'r' : 'p');
+       seq_printf(m, ":%s/%s", tp->call.system, tp->call.name);
+
+       if (!tp->symbol)
+               seq_printf(m, " 0x%p", tp->rp.kp.addr);
+       else if (tp->rp.kp.offset)
+               seq_printf(m, " %s+%u", probe_symbol(tp), tp->rp.kp.offset);
+       else
+               seq_printf(m, " %s", probe_symbol(tp));
+
+       for (i = 0; i < tp->nr_args; i++) {
+               ret = probe_arg_string(buf, MAX_ARGSTR_LEN, &tp->args[i].fetch);
+               if (ret < 0) {
+                       pr_warning("Argument%d decoding error(%d).\n", i, ret);
+                       return ret;
+               }
+               seq_printf(m, " %s=%s", tp->args[i].name, buf);
+       }
+       seq_printf(m, "\n");
+       return 0;
+}
+
+static const struct seq_operations probes_seq_op = {
+       .start  = probes_seq_start,
+       .next   = probes_seq_next,
+       .stop   = probes_seq_stop,
+       .show   = probes_seq_show
+};
+
+static int probes_open(struct inode *inode, struct file *file)
+{
+       if ((file->f_mode & FMODE_WRITE) &&
+           (file->f_flags & O_TRUNC))
+               cleanup_all_probes();
+
+       return seq_open(file, &probes_seq_op);
+}
+
+static int command_trace_probe(const char *buf)
+{
+       char **argv;
+       int argc = 0, ret = 0;
+
+       argv = argv_split(GFP_KERNEL, buf, &argc);
+       if (!argv)
+               return -ENOMEM;
+
+       if (argc)
+               ret = create_trace_probe(argc, argv);
+
+       argv_free(argv);
+       return ret;
+}
+
+#define WRITE_BUFSIZE 128
+
+static ssize_t probes_write(struct file *file, const char __user *buffer,
+                           size_t count, loff_t *ppos)
+{
+       char *kbuf, *tmp;
+       int ret;
+       size_t done;
+       size_t size;
+
+       kbuf = kmalloc(WRITE_BUFSIZE, GFP_KERNEL);
+       if (!kbuf)
+               return -ENOMEM;
+
+       ret = done = 0;
+       while (done < count) {
+               size = count - done;
+               if (size >= WRITE_BUFSIZE)
+                       size = WRITE_BUFSIZE - 1;
+               if (copy_from_user(kbuf, buffer + done, size)) {
+                       ret = -EFAULT;
+                       goto out;
+               }
+               kbuf[size] = '\0';
+               tmp = strchr(kbuf, '\n');
+               if (tmp) {
+                       *tmp = '\0';
+                       size = tmp - kbuf + 1;
+               } else if (done + size < count) {
+                       pr_warning("Line length is too long: "
+                                  "Should be less than %d.", WRITE_BUFSIZE);
+                       ret = -EINVAL;
+                       goto out;
+               }
+               done += size;
+               /* Remove comments */
+               tmp = strchr(kbuf, '#');
+               if (tmp)
+                       *tmp = '\0';
+
+               ret = command_trace_probe(kbuf);
+               if (ret)
+                       goto out;
+       }
+       ret = done;
+out:
+       kfree(kbuf);
+       return ret;
+}
+
+static const struct file_operations kprobe_events_ops = {
+       .owner          = THIS_MODULE,
+       .open           = probes_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = seq_release,
+       .write          = probes_write,
+};
+
+/* Probes profiling interfaces */
+static int probes_profile_seq_show(struct seq_file *m, void *v)
+{
+       struct trace_probe *tp = v;
+
+       seq_printf(m, "  %-44s %15lu %15lu\n", tp->call.name, tp->nhit,
+                  tp->rp.kp.nmissed);
+
+       return 0;
+}
+
+static const struct seq_operations profile_seq_op = {
+       .start  = probes_seq_start,
+       .next   = probes_seq_next,
+       .stop   = probes_seq_stop,
+       .show   = probes_profile_seq_show
+};
+
+static int profile_open(struct inode *inode, struct file *file)
+{
+       return seq_open(file, &profile_seq_op);
+}
+
+static const struct file_operations kprobe_profile_ops = {
+       .owner          = THIS_MODULE,
+       .open           = profile_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = seq_release,
+};
+
+/* Kprobe handler */
+static __kprobes int kprobe_trace_func(struct kprobe *kp, struct pt_regs *regs)
+{
+       struct trace_probe *tp = container_of(kp, struct trace_probe, rp.kp);
+       struct kprobe_trace_entry *entry;
+       struct ring_buffer_event *event;
+       struct ring_buffer *buffer;
+       int size, i, pc;
+       unsigned long irq_flags;
+       struct ftrace_event_call *call = &tp->call;
+
+       tp->nhit++;
+
+       local_save_flags(irq_flags);
+       pc = preempt_count();
+
+       size = SIZEOF_KPROBE_TRACE_ENTRY(tp->nr_args);
+
+       event = trace_current_buffer_lock_reserve(&buffer, call->id, size,
+                                                 irq_flags, pc);
+       if (!event)
+               return 0;
+
+       entry = ring_buffer_event_data(event);
+       entry->nargs = tp->nr_args;
+       entry->ip = (unsigned long)kp->addr;
+       for (i = 0; i < tp->nr_args; i++)
+               entry->args[i] = call_fetch(&tp->args[i].fetch, regs);
+
+       if (!filter_current_check_discard(buffer, call, entry, event))
+               trace_nowake_buffer_unlock_commit(buffer, event, irq_flags, pc);
+       return 0;
+}
+
+/* Kretprobe handler */
+static __kprobes int kretprobe_trace_func(struct kretprobe_instance *ri,
+                                         struct pt_regs *regs)
+{
+       struct trace_probe *tp = container_of(ri->rp, struct trace_probe, rp);
+       struct kretprobe_trace_entry *entry;
+       struct ring_buffer_event *event;
+       struct ring_buffer *buffer;
+       int size, i, pc;
+       unsigned long irq_flags;
+       struct ftrace_event_call *call = &tp->call;
+
+       local_save_flags(irq_flags);
+       pc = preempt_count();
+
+       size = SIZEOF_KRETPROBE_TRACE_ENTRY(tp->nr_args);
+
+       event = trace_current_buffer_lock_reserve(&buffer, call->id, size,
+                                                 irq_flags, pc);
+       if (!event)
+               return 0;
+
+       entry = ring_buffer_event_data(event);
+       entry->nargs = tp->nr_args;
+       entry->func = (unsigned long)tp->rp.kp.addr;
+       entry->ret_ip = (unsigned long)ri->ret_addr;
+       for (i = 0; i < tp->nr_args; i++)
+               entry->args[i] = call_fetch(&tp->args[i].fetch, regs);
+
+       if (!filter_current_check_discard(buffer, call, entry, event))
+               trace_nowake_buffer_unlock_commit(buffer, event, irq_flags, pc);
+
+       return 0;
+}
+
+/* Event entry printers */
+enum print_line_t
+print_kprobe_event(struct trace_iterator *iter, int flags)
+{
+       struct kprobe_trace_entry *field;
+       struct trace_seq *s = &iter->seq;
+       struct trace_event *event;
+       struct trace_probe *tp;
+       int i;
+
+       field = (struct kprobe_trace_entry *)iter->ent;
+       event = ftrace_find_event(field->ent.type);
+       tp = container_of(event, struct trace_probe, event);
+
+       if (!trace_seq_printf(s, "%s: (", tp->call.name))
+               goto partial;
+
+       if (!seq_print_ip_sym(s, field->ip, flags | TRACE_ITER_SYM_OFFSET))
+               goto partial;
+
+       if (!trace_seq_puts(s, ")"))
+               goto partial;
+
+       for (i = 0; i < field->nargs; i++)
+               if (!trace_seq_printf(s, " %s=%lx",
+                                     tp->args[i].name, field->args[i]))
+                       goto partial;
+
+       if (!trace_seq_puts(s, "\n"))
+               goto partial;
+
+       return TRACE_TYPE_HANDLED;
+partial:
+       return TRACE_TYPE_PARTIAL_LINE;
+}
+
+enum print_line_t
+print_kretprobe_event(struct trace_iterator *iter, int flags)
+{
+       struct kretprobe_trace_entry *field;
+       struct trace_seq *s = &iter->seq;
+       struct trace_event *event;
+       struct trace_probe *tp;
+       int i;
+
+       field = (struct kretprobe_trace_entry *)iter->ent;
+       event = ftrace_find_event(field->ent.type);
+       tp = container_of(event, struct trace_probe, event);
+
+       if (!trace_seq_printf(s, "%s: (", tp->call.name))
+               goto partial;
+
+       if (!seq_print_ip_sym(s, field->ret_ip, flags | TRACE_ITER_SYM_OFFSET))
+               goto partial;
+
+       if (!trace_seq_puts(s, " <- "))
+               goto partial;
+
+       if (!seq_print_ip_sym(s, field->func, flags & ~TRACE_ITER_SYM_OFFSET))
+               goto partial;
+
+       if (!trace_seq_puts(s, ")"))
+               goto partial;
+
+       for (i = 0; i < field->nargs; i++)
+               if (!trace_seq_printf(s, " %s=%lx",
+                                     tp->args[i].name, field->args[i]))
+                       goto partial;
+
+       if (!trace_seq_puts(s, "\n"))
+               goto partial;
+
+       return TRACE_TYPE_HANDLED;
+partial:
+       return TRACE_TYPE_PARTIAL_LINE;
+}
+
+static int probe_event_enable(struct ftrace_event_call *call)
+{
+       struct trace_probe *tp = (struct trace_probe *)call->data;
+
+       tp->flags |= TP_FLAG_TRACE;
+       if (probe_is_return(tp))
+               return enable_kretprobe(&tp->rp);
+       else
+               return enable_kprobe(&tp->rp.kp);
+}
+
+static void probe_event_disable(struct ftrace_event_call *call)
+{
+       struct trace_probe *tp = (struct trace_probe *)call->data;
+
+       tp->flags &= ~TP_FLAG_TRACE;
+       if (!(tp->flags & (TP_FLAG_TRACE | TP_FLAG_PROFILE))) {
+               if (probe_is_return(tp))
+                       disable_kretprobe(&tp->rp);
+               else
+                       disable_kprobe(&tp->rp.kp);
+       }
+}
+
+static int probe_event_raw_init(struct ftrace_event_call *event_call)
+{
+       INIT_LIST_HEAD(&event_call->fields);
+
+       return 0;
+}
+
+#undef DEFINE_FIELD
+#define DEFINE_FIELD(type, item, name, is_signed)                      \
+       do {                                                            \
+               ret = trace_define_field(event_call, #type, name,       \
+                                        offsetof(typeof(field), item), \
+                                        sizeof(field.item), is_signed, \
+                                        FILTER_OTHER);                 \
+               if (ret)                                                \
+                       return ret;                                     \
+       } while (0)
+
+static int kprobe_event_define_fields(struct ftrace_event_call *event_call)
+{
+       int ret, i;
+       struct kprobe_trace_entry field;
+       struct trace_probe *tp = (struct trace_probe *)event_call->data;
+
+       ret = trace_define_common_fields(event_call);
+       if (!ret)
+               return ret;
+
+       DEFINE_FIELD(unsigned long, ip, FIELD_STRING_IP, 0);
+       DEFINE_FIELD(int, nargs, FIELD_STRING_NARGS, 1);
+       /* Set argument names as fields */
+       for (i = 0; i < tp->nr_args; i++)
+               DEFINE_FIELD(unsigned long, args[i], tp->args[i].name, 0);
+       return 0;
+}
+
+static int kretprobe_event_define_fields(struct ftrace_event_call *event_call)
+{
+       int ret, i;
+       struct kretprobe_trace_entry field;
+       struct trace_probe *tp = (struct trace_probe *)event_call->data;
+
+       ret = trace_define_common_fields(event_call);
+       if (!ret)
+               return ret;
+
+       DEFINE_FIELD(unsigned long, func, FIELD_STRING_FUNC, 0);
+       DEFINE_FIELD(unsigned long, ret_ip, FIELD_STRING_RETIP, 0);
+       DEFINE_FIELD(int, nargs, FIELD_STRING_NARGS, 1);
+       /* Set argument names as fields */
+       for (i = 0; i < tp->nr_args; i++)
+               DEFINE_FIELD(unsigned long, args[i], tp->args[i].name, 0);
+       return 0;
+}
+
+static int __probe_event_show_format(struct trace_seq *s,
+                                    struct trace_probe *tp, const char *fmt,
+                                    const char *arg)
+{
+       int i;
+
+       /* Show format */
+       if (!trace_seq_printf(s, "\nprint fmt: \"%s", fmt))
+               return 0;
+
+       for (i = 0; i < tp->nr_args; i++)
+               if (!trace_seq_printf(s, " %s=%%lx", tp->args[i].name))
+                       return 0;
+
+       if (!trace_seq_printf(s, "\", %s", arg))
+               return 0;
+
+       for (i = 0; i < tp->nr_args; i++)
+               if (!trace_seq_printf(s, ", REC->%s", tp->args[i].name))
+                       return 0;
+
+       return trace_seq_puts(s, "\n");
+}
+
+#undef SHOW_FIELD
+#define SHOW_FIELD(type, item, name)                                   \
+       do {                                                            \
+               ret = trace_seq_printf(s, "\tfield: " #type " %s;\t"    \
+                               "offset:%u;\tsize:%u;\n", name,         \
+                               (unsigned int)offsetof(typeof(field), item),\
+                               (unsigned int)sizeof(type));            \
+               if (!ret)                                               \
+                       return 0;                                       \
+       } while (0)
+
+static int kprobe_event_show_format(struct ftrace_event_call *call,
+                                   struct trace_seq *s)
+{
+       struct kprobe_trace_entry field __attribute__((unused));
+       int ret, i;
+       struct trace_probe *tp = (struct trace_probe *)call->data;
+
+       SHOW_FIELD(unsigned long, ip, FIELD_STRING_IP);
+       SHOW_FIELD(int, nargs, FIELD_STRING_NARGS);
+
+       /* Show fields */
+       for (i = 0; i < tp->nr_args; i++)
+               SHOW_FIELD(unsigned long, args[i], tp->args[i].name);
+       trace_seq_puts(s, "\n");
+
+       return __probe_event_show_format(s, tp, "(%lx)",
+                                        "REC->" FIELD_STRING_IP);
+}
+
+static int kretprobe_event_show_format(struct ftrace_event_call *call,
+                                      struct trace_seq *s)
+{
+       struct kretprobe_trace_entry field __attribute__((unused));
+       int ret, i;
+       struct trace_probe *tp = (struct trace_probe *)call->data;
+
+       SHOW_FIELD(unsigned long, func, FIELD_STRING_FUNC);
+       SHOW_FIELD(unsigned long, ret_ip, FIELD_STRING_RETIP);
+       SHOW_FIELD(int, nargs, FIELD_STRING_NARGS);
+
+       /* Show fields */
+       for (i = 0; i < tp->nr_args; i++)
+               SHOW_FIELD(unsigned long, args[i], tp->args[i].name);
+       trace_seq_puts(s, "\n");
+
+       return __probe_event_show_format(s, tp, "(%lx <- %lx)",
+                                        "REC->" FIELD_STRING_FUNC
+                                        ", REC->" FIELD_STRING_RETIP);
+}
+
+#ifdef CONFIG_EVENT_PROFILE
+
+/* Kprobe profile handler */
+static __kprobes int kprobe_profile_func(struct kprobe *kp,
+                                        struct pt_regs *regs)
+{
+       struct trace_probe *tp = container_of(kp, struct trace_probe, rp.kp);
+       struct ftrace_event_call *call = &tp->call;
+       struct kprobe_trace_entry *entry;
+       struct trace_entry *ent;
+       int size, __size, i, pc, __cpu;
+       unsigned long irq_flags;
+       char *trace_buf;
+       char *raw_data;
+       int rctx;
+
+       pc = preempt_count();
+       __size = SIZEOF_KPROBE_TRACE_ENTRY(tp->nr_args);
+       size = ALIGN(__size + sizeof(u32), sizeof(u64));
+       size -= sizeof(u32);
+       if (WARN_ONCE(size > FTRACE_MAX_PROFILE_SIZE,
+                    "profile buffer not large enough"))
+               return 0;
+
+       /*
+        * Protect the non nmi buffer
+        * This also protects the rcu read side
+        */
+       local_irq_save(irq_flags);
+
+       rctx = perf_swevent_get_recursion_context();
+       if (rctx < 0)
+               goto end_recursion;
+
+       __cpu = smp_processor_id();
+
+       if (in_nmi())
+               trace_buf = rcu_dereference(perf_trace_buf_nmi);
+       else
+               trace_buf = rcu_dereference(perf_trace_buf);
+
+       if (!trace_buf)
+               goto end;
+
+       raw_data = per_cpu_ptr(trace_buf, __cpu);
+
+       /* Zero dead bytes from alignment to avoid buffer leak to userspace */
+       *(u64 *)(&raw_data[size - sizeof(u64)]) = 0ULL;
+       entry = (struct kprobe_trace_entry *)raw_data;
+       ent = &entry->ent;
+
+       tracing_generic_entry_update(ent, irq_flags, pc);
+       ent->type = call->id;
+       entry->nargs = tp->nr_args;
+       entry->ip = (unsigned long)kp->addr;
+       for (i = 0; i < tp->nr_args; i++)
+               entry->args[i] = call_fetch(&tp->args[i].fetch, regs);
+       perf_tp_event(call->id, entry->ip, 1, entry, size);
+
+end:
+       perf_swevent_put_recursion_context(rctx);
+end_recursion:
+       local_irq_restore(irq_flags);
+
+       return 0;
+}
+
+/* Kretprobe profile handler */
+static __kprobes int kretprobe_profile_func(struct kretprobe_instance *ri,
+                                           struct pt_regs *regs)
+{
+       struct trace_probe *tp = container_of(ri->rp, struct trace_probe, rp);
+       struct ftrace_event_call *call = &tp->call;
+       struct kretprobe_trace_entry *entry;
+       struct trace_entry *ent;
+       int size, __size, i, pc, __cpu;
+       unsigned long irq_flags;
+       char *trace_buf;
+       char *raw_data;
+       int rctx;
+
+       pc = preempt_count();
+       __size = SIZEOF_KRETPROBE_TRACE_ENTRY(tp->nr_args);
+       size = ALIGN(__size + sizeof(u32), sizeof(u64));
+       size -= sizeof(u32);
+       if (WARN_ONCE(size > FTRACE_MAX_PROFILE_SIZE,
+                    "profile buffer not large enough"))
+               return 0;
+
+       /*
+        * Protect the non nmi buffer
+        * This also protects the rcu read side
+        */
+       local_irq_save(irq_flags);
+
+       rctx = perf_swevent_get_recursion_context();
+       if (rctx < 0)
+               goto end_recursion;
+
+       __cpu = smp_processor_id();
+
+       if (in_nmi())
+               trace_buf = rcu_dereference(perf_trace_buf_nmi);
+       else
+               trace_buf = rcu_dereference(perf_trace_buf);
+
+       if (!trace_buf)
+               goto end;
+
+       raw_data = per_cpu_ptr(trace_buf, __cpu);
+
+       /* Zero dead bytes from alignment to avoid buffer leak to userspace */
+       *(u64 *)(&raw_data[size - sizeof(u64)]) = 0ULL;
+       entry = (struct kretprobe_trace_entry *)raw_data;
+       ent = &entry->ent;
+
+       tracing_generic_entry_update(ent, irq_flags, pc);
+       ent->type = call->id;
+       entry->nargs = tp->nr_args;
+       entry->func = (unsigned long)tp->rp.kp.addr;
+       entry->ret_ip = (unsigned long)ri->ret_addr;
+       for (i = 0; i < tp->nr_args; i++)
+               entry->args[i] = call_fetch(&tp->args[i].fetch, regs);
+       perf_tp_event(call->id, entry->ret_ip, 1, entry, size);
+
+end:
+       perf_swevent_put_recursion_context(rctx);
+end_recursion:
+       local_irq_restore(irq_flags);
+
+       return 0;
+}
+
+static int probe_profile_enable(struct ftrace_event_call *call)
+{
+       struct trace_probe *tp = (struct trace_probe *)call->data;
+
+       tp->flags |= TP_FLAG_PROFILE;
+
+       if (probe_is_return(tp))
+               return enable_kretprobe(&tp->rp);
+       else
+               return enable_kprobe(&tp->rp.kp);
+}
+
+static void probe_profile_disable(struct ftrace_event_call *call)
+{
+       struct trace_probe *tp = (struct trace_probe *)call->data;
+
+       tp->flags &= ~TP_FLAG_PROFILE;
+
+       if (!(tp->flags & TP_FLAG_TRACE)) {
+               if (probe_is_return(tp))
+                       disable_kretprobe(&tp->rp);
+               else
+                       disable_kprobe(&tp->rp.kp);
+       }
+}
+#endif /* CONFIG_EVENT_PROFILE */
+
+
+static __kprobes
+int kprobe_dispatcher(struct kprobe *kp, struct pt_regs *regs)
+{
+       struct trace_probe *tp = container_of(kp, struct trace_probe, rp.kp);
+
+       if (tp->flags & TP_FLAG_TRACE)
+               kprobe_trace_func(kp, regs);
+#ifdef CONFIG_EVENT_PROFILE
+       if (tp->flags & TP_FLAG_PROFILE)
+               kprobe_profile_func(kp, regs);
+#endif /* CONFIG_EVENT_PROFILE */
+       return 0;       /* We don't tweek kernel, so just return 0 */
+}
+
+static __kprobes
+int kretprobe_dispatcher(struct kretprobe_instance *ri, struct pt_regs *regs)
+{
+       struct trace_probe *tp = container_of(ri->rp, struct trace_probe, rp);
+
+       if (tp->flags & TP_FLAG_TRACE)
+               kretprobe_trace_func(ri, regs);
+#ifdef CONFIG_EVENT_PROFILE
+       if (tp->flags & TP_FLAG_PROFILE)
+               kretprobe_profile_func(ri, regs);
+#endif /* CONFIG_EVENT_PROFILE */
+       return 0;       /* We don't tweek kernel, so just return 0 */
+}
+
+static int register_probe_event(struct trace_probe *tp)
+{
+       struct ftrace_event_call *call = &tp->call;
+       int ret;
+
+       /* Initialize ftrace_event_call */
+       if (probe_is_return(tp)) {
+               tp->event.trace = print_kretprobe_event;
+               call->raw_init = probe_event_raw_init;
+               call->show_format = kretprobe_event_show_format;
+               call->define_fields = kretprobe_event_define_fields;
+       } else {
+               tp->event.trace = print_kprobe_event;
+               call->raw_init = probe_event_raw_init;
+               call->show_format = kprobe_event_show_format;
+               call->define_fields = kprobe_event_define_fields;
+       }
+       call->event = &tp->event;
+       call->id = register_ftrace_event(&tp->event);
+       if (!call->id)
+               return -ENODEV;
+       call->enabled = 0;
+       call->regfunc = probe_event_enable;
+       call->unregfunc = probe_event_disable;
+
+#ifdef CONFIG_EVENT_PROFILE
+       atomic_set(&call->profile_count, -1);
+       call->profile_enable = probe_profile_enable;
+       call->profile_disable = probe_profile_disable;
+#endif
+       call->data = tp;
+       ret = trace_add_event_call(call);
+       if (ret) {
+               pr_info("Failed to register kprobe event: %s\n", call->name);
+               unregister_ftrace_event(&tp->event);
+       }
+       return ret;
+}
+
+static void unregister_probe_event(struct trace_probe *tp)
+{
+       /* tp->event is unregistered in trace_remove_event_call() */
+       trace_remove_event_call(&tp->call);
+}
+
+/* Make a debugfs interface for controling probe points */
+static __init int init_kprobe_trace(void)
+{
+       struct dentry *d_tracer;
+       struct dentry *entry;
+
+       d_tracer = tracing_init_dentry();
+       if (!d_tracer)
+               return 0;
+
+       entry = debugfs_create_file("kprobe_events", 0644, d_tracer,
+                                   NULL, &kprobe_events_ops);
+
+       /* Event list interface */
+       if (!entry)
+               pr_warning("Could not create debugfs "
+                          "'kprobe_events' entry\n");
+
+       /* Profile interface */
+       entry = debugfs_create_file("kprobe_profile", 0444, d_tracer,
+                                   NULL, &kprobe_profile_ops);
+
+       if (!entry)
+               pr_warning("Could not create debugfs "
+                          "'kprobe_profile' entry\n");
+       return 0;
+}
+fs_initcall(init_kprobe_trace);
+
+
+#ifdef CONFIG_FTRACE_STARTUP_TEST
+
+static int kprobe_trace_selftest_target(int a1, int a2, int a3,
+                                       int a4, int a5, int a6)
+{
+       return a1 + a2 + a3 + a4 + a5 + a6;
+}
+
+static __init int kprobe_trace_self_tests_init(void)
+{
+       int ret;
+       int (*target)(int, int, int, int, int, int);
+
+       target = kprobe_trace_selftest_target;
+
+       pr_info("Testing kprobe tracing: ");
+
+       ret = command_trace_probe("p:testprobe kprobe_trace_selftest_target "
+                                 "$arg1 $arg2 $arg3 $arg4 $stack $stack0");
+       if (WARN_ON_ONCE(ret))
+               pr_warning("error enabling function entry\n");
+
+       ret = command_trace_probe("r:testprobe2 kprobe_trace_selftest_target "
+                                 "$retval");
+       if (WARN_ON_ONCE(ret))
+               pr_warning("error enabling function return\n");
+
+       ret = target(1, 2, 3, 4, 5, 6);
+
+       cleanup_all_probes();
+
+       pr_cont("OK\n");
+       return 0;
+}
+
+late_initcall(kprobe_trace_self_tests_init);
+
+#endif
diff --git a/kernel/trace/trace_ksym.c b/kernel/trace/trace_ksym.c
new file mode 100644 (file)
index 0000000..ddfa0fd
--- /dev/null
@@ -0,0 +1,550 @@
+/*
+ * trace_ksym.c - Kernel Symbol Tracer
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Copyright (C) IBM Corporation, 2009
+ */
+
+#include <linux/kallsyms.h>
+#include <linux/uaccess.h>
+#include <linux/debugfs.h>
+#include <linux/ftrace.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+
+#include "trace_output.h"
+#include "trace_stat.h"
+#include "trace.h"
+
+#include <linux/hw_breakpoint.h>
+#include <asm/hw_breakpoint.h>
+
+/*
+ * For now, let us restrict the no. of symbols traced simultaneously to number
+ * of available hardware breakpoint registers.
+ */
+#define KSYM_TRACER_MAX HBP_NUM
+
+#define KSYM_TRACER_OP_LEN 3 /* rw- */
+
+struct trace_ksym {
+       struct perf_event       **ksym_hbp;
+       struct perf_event_attr  attr;
+#ifdef CONFIG_PROFILE_KSYM_TRACER
+       unsigned long           counter;
+#endif
+       struct hlist_node       ksym_hlist;
+};
+
+static struct trace_array *ksym_trace_array;
+
+static unsigned int ksym_filter_entry_count;
+static unsigned int ksym_tracing_enabled;
+
+static HLIST_HEAD(ksym_filter_head);
+
+static DEFINE_MUTEX(ksym_tracer_mutex);
+
+#ifdef CONFIG_PROFILE_KSYM_TRACER
+
+#define MAX_UL_INT 0xffffffff
+
+void ksym_collect_stats(unsigned long hbp_hit_addr)
+{
+       struct hlist_node *node;
+       struct trace_ksym *entry;
+
+       rcu_read_lock();
+       hlist_for_each_entry_rcu(entry, node, &ksym_filter_head, ksym_hlist) {
+               if ((entry->attr.bp_addr == hbp_hit_addr) &&
+                   (entry->counter <= MAX_UL_INT)) {
+                       entry->counter++;
+                       break;
+               }
+       }
+       rcu_read_unlock();
+}
+#endif /* CONFIG_PROFILE_KSYM_TRACER */
+
+void ksym_hbp_handler(struct perf_event *hbp, void *data)
+{
+       struct ring_buffer_event *event;
+       struct ksym_trace_entry *entry;
+       struct pt_regs *regs = data;
+       struct ring_buffer *buffer;
+       int pc;
+
+       if (!ksym_tracing_enabled)
+               return;
+
+       buffer = ksym_trace_array->buffer;
+
+       pc = preempt_count();
+
+       event = trace_buffer_lock_reserve(buffer, TRACE_KSYM,
+                                                       sizeof(*entry), 0, pc);
+       if (!event)
+               return;
+
+       entry           = ring_buffer_event_data(event);
+       entry->ip       = instruction_pointer(regs);
+       entry->type     = hw_breakpoint_type(hbp);
+       entry->addr     = hw_breakpoint_addr(hbp);
+       strlcpy(entry->cmd, current->comm, TASK_COMM_LEN);
+
+#ifdef CONFIG_PROFILE_KSYM_TRACER
+       ksym_collect_stats(hw_breakpoint_addr(hbp));
+#endif /* CONFIG_PROFILE_KSYM_TRACER */
+
+       trace_buffer_unlock_commit(buffer, event, 0, pc);
+}
+
+/* Valid access types are represented as
+ *
+ * rw- : Set Read/Write Access Breakpoint
+ * -w- : Set Write Access Breakpoint
+ * --- : Clear Breakpoints
+ * --x : Set Execution Break points (Not available yet)
+ *
+ */
+static int ksym_trace_get_access_type(char *str)
+{
+       int access = 0;
+
+       if (str[0] == 'r')
+               access |= HW_BREAKPOINT_R;
+
+       if (str[1] == 'w')
+               access |= HW_BREAKPOINT_W;
+
+       if (str[2] == 'x')
+               access |= HW_BREAKPOINT_X;
+
+       switch (access) {
+       case HW_BREAKPOINT_R:
+       case HW_BREAKPOINT_W:
+       case HW_BREAKPOINT_W | HW_BREAKPOINT_R:
+               return access;
+       default:
+               return -EINVAL;
+       }
+}
+
+/*
+ * There can be several possible malformed requests and we attempt to capture
+ * all of them. We enumerate some of the rules
+ * 1. We will not allow kernel symbols with ':' since it is used as a delimiter.
+ *    i.e. multiple ':' symbols disallowed. Possible uses are of the form
+ *    <module>:<ksym_name>:<op>.
+ * 2. No delimiter symbol ':' in the input string
+ * 3. Spurious operator symbols or symbols not in their respective positions
+ * 4. <ksym_name>:--- i.e. clear breakpoint request when ksym_name not in file
+ * 5. Kernel symbol not a part of /proc/kallsyms
+ * 6. Duplicate requests
+ */
+static int parse_ksym_trace_str(char *input_string, char **ksymname,
+                                                       unsigned long *addr)
+{
+       int ret;
+
+       *ksymname = strsep(&input_string, ":");
+       *addr = kallsyms_lookup_name(*ksymname);
+
+       /* Check for malformed request: (2), (1) and (5) */
+       if ((!input_string) ||
+           (strlen(input_string) != KSYM_TRACER_OP_LEN) ||
+           (*addr == 0))
+               return -EINVAL;;
+
+       ret = ksym_trace_get_access_type(input_string);
+
+       return ret;
+}
+
+int process_new_ksym_entry(char *ksymname, int op, unsigned long addr)
+{
+       struct trace_ksym *entry;
+       int ret = -ENOMEM;
+
+       if (ksym_filter_entry_count >= KSYM_TRACER_MAX) {
+               printk(KERN_ERR "ksym_tracer: Maximum limit:(%d) reached. No"
+               " new requests for tracing can be accepted now.\n",
+                       KSYM_TRACER_MAX);
+               return -ENOSPC;
+       }
+
+       entry = kzalloc(sizeof(struct trace_ksym), GFP_KERNEL);
+       if (!entry)
+               return -ENOMEM;
+
+       hw_breakpoint_init(&entry->attr);
+
+       entry->attr.bp_type = op;
+       entry->attr.bp_addr = addr;
+       entry->attr.bp_len = HW_BREAKPOINT_LEN_4;
+
+       ret = -EAGAIN;
+       entry->ksym_hbp = register_wide_hw_breakpoint(&entry->attr,
+                                       ksym_hbp_handler);
+
+       if (IS_ERR(entry->ksym_hbp)) {
+               ret = PTR_ERR(entry->ksym_hbp);
+               printk(KERN_INFO "ksym_tracer request failed. Try again"
+                                       " later!!\n");
+               goto err;
+       }
+
+       hlist_add_head_rcu(&(entry->ksym_hlist), &ksym_filter_head);
+       ksym_filter_entry_count++;
+
+       return 0;
+
+err:
+       kfree(entry);
+
+       return ret;
+}
+
+static ssize_t ksym_trace_filter_read(struct file *filp, char __user *ubuf,
+                                               size_t count, loff_t *ppos)
+{
+       struct trace_ksym *entry;
+       struct hlist_node *node;
+       struct trace_seq *s;
+       ssize_t cnt = 0;
+       int ret;
+
+       s = kmalloc(sizeof(*s), GFP_KERNEL);
+       if (!s)
+               return -ENOMEM;
+       trace_seq_init(s);
+
+       mutex_lock(&ksym_tracer_mutex);
+
+       hlist_for_each_entry(entry, node, &ksym_filter_head, ksym_hlist) {
+               ret = trace_seq_printf(s, "%pS:", (void *)entry->attr.bp_addr);
+               if (entry->attr.bp_type == HW_BREAKPOINT_R)
+                       ret = trace_seq_puts(s, "r--\n");
+               else if (entry->attr.bp_type == HW_BREAKPOINT_W)
+                       ret = trace_seq_puts(s, "-w-\n");
+               else if (entry->attr.bp_type == (HW_BREAKPOINT_W | HW_BREAKPOINT_R))
+                       ret = trace_seq_puts(s, "rw-\n");
+               WARN_ON_ONCE(!ret);
+       }
+
+       cnt = simple_read_from_buffer(ubuf, count, ppos, s->buffer, s->len);
+
+       mutex_unlock(&ksym_tracer_mutex);
+
+       kfree(s);
+
+       return cnt;
+}
+
+static void __ksym_trace_reset(void)
+{
+       struct trace_ksym *entry;
+       struct hlist_node *node, *node1;
+
+       mutex_lock(&ksym_tracer_mutex);
+       hlist_for_each_entry_safe(entry, node, node1, &ksym_filter_head,
+                                                               ksym_hlist) {
+               unregister_wide_hw_breakpoint(entry->ksym_hbp);
+               ksym_filter_entry_count--;
+               hlist_del_rcu(&(entry->ksym_hlist));
+               synchronize_rcu();
+               kfree(entry);
+       }
+       mutex_unlock(&ksym_tracer_mutex);
+}
+
+static ssize_t ksym_trace_filter_write(struct file *file,
+                                       const char __user *buffer,
+                                               size_t count, loff_t *ppos)
+{
+       struct trace_ksym *entry;
+       struct hlist_node *node;
+       char *input_string, *ksymname = NULL;
+       unsigned long ksym_addr = 0;
+       int ret, op, changed = 0;
+
+       input_string = kzalloc(count + 1, GFP_KERNEL);
+       if (!input_string)
+               return -ENOMEM;
+
+       if (copy_from_user(input_string, buffer, count)) {
+               kfree(input_string);
+               return -EFAULT;
+       }
+       input_string[count] = '\0';
+
+       strstrip(input_string);
+
+       /*
+        * Clear all breakpoints if:
+        * 1: echo > ksym_trace_filter
+        * 2: echo 0 > ksym_trace_filter
+        * 3: echo "*:---" > ksym_trace_filter
+        */
+       if (!input_string[0] || !strcmp(input_string, "0") ||
+           !strcmp(input_string, "*:---")) {
+               __ksym_trace_reset();
+               kfree(input_string);
+               return count;
+       }
+
+       ret = op = parse_ksym_trace_str(input_string, &ksymname, &ksym_addr);
+       if (ret < 0) {
+               kfree(input_string);
+               return ret;
+       }
+
+       mutex_lock(&ksym_tracer_mutex);
+
+       ret = -EINVAL;
+       hlist_for_each_entry(entry, node, &ksym_filter_head, ksym_hlist) {
+               if (entry->attr.bp_addr == ksym_addr) {
+                       /* Check for malformed request: (6) */
+                       if (entry->attr.bp_type != op)
+                               changed = 1;
+                       else
+                               goto out;
+                       break;
+               }
+       }
+       if (changed) {
+               unregister_wide_hw_breakpoint(entry->ksym_hbp);
+               entry->attr.bp_type = op;
+               ret = 0;
+               if (op > 0) {
+                       entry->ksym_hbp =
+                               register_wide_hw_breakpoint(&entry->attr,
+                                       ksym_hbp_handler);
+                       if (IS_ERR(entry->ksym_hbp))
+                               ret = PTR_ERR(entry->ksym_hbp);
+                       else
+                               goto out;
+               }
+               /* Error or "symbol:---" case: drop it */
+               ksym_filter_entry_count--;
+               hlist_del_rcu(&(entry->ksym_hlist));
+               synchronize_rcu();
+               kfree(entry);
+               goto out;
+       } else {
+               /* Check for malformed request: (4) */
+               if (op == 0)
+                       goto out;
+               ret = process_new_ksym_entry(ksymname, op, ksym_addr);
+       }
+out:
+       mutex_unlock(&ksym_tracer_mutex);
+
+       kfree(input_string);
+
+       if (!ret)
+               ret = count;
+       return ret;
+}
+
+static const struct file_operations ksym_tracing_fops = {
+       .open           = tracing_open_generic,
+       .read           = ksym_trace_filter_read,
+       .write          = ksym_trace_filter_write,
+};
+
+static void ksym_trace_reset(struct trace_array *tr)
+{
+       ksym_tracing_enabled = 0;
+       __ksym_trace_reset();
+}
+
+static int ksym_trace_init(struct trace_array *tr)
+{
+       int cpu, ret = 0;
+
+       for_each_online_cpu(cpu)
+               tracing_reset(tr, cpu);
+       ksym_tracing_enabled = 1;
+       ksym_trace_array = tr;
+
+       return ret;
+}
+
+static void ksym_trace_print_header(struct seq_file *m)
+{
+       seq_puts(m,
+                "#       TASK-PID   CPU#      Symbol                    "
+                "Type    Function\n");
+       seq_puts(m,
+                "#          |        |          |                       "
+                " |         |\n");
+}
+
+static enum print_line_t ksym_trace_output(struct trace_iterator *iter)
+{
+       struct trace_entry *entry = iter->ent;
+       struct trace_seq *s = &iter->seq;
+       struct ksym_trace_entry *field;
+       char str[KSYM_SYMBOL_LEN];
+       int ret;
+
+       if (entry->type != TRACE_KSYM)
+               return TRACE_TYPE_UNHANDLED;
+
+       trace_assign_type(field, entry);
+
+       ret = trace_seq_printf(s, "%11s-%-5d [%03d] %pS", field->cmd,
+                               entry->pid, iter->cpu, (char *)field->addr);
+       if (!ret)
+               return TRACE_TYPE_PARTIAL_LINE;
+
+       switch (field->type) {
+       case HW_BREAKPOINT_R:
+               ret = trace_seq_printf(s, " R  ");
+               break;
+       case HW_BREAKPOINT_W:
+               ret = trace_seq_printf(s, " W  ");
+               break;
+       case HW_BREAKPOINT_R | HW_BREAKPOINT_W:
+               ret = trace_seq_printf(s, " RW ");
+               break;
+       default:
+               return TRACE_TYPE_PARTIAL_LINE;
+       }
+
+       if (!ret)
+               return TRACE_TYPE_PARTIAL_LINE;
+
+       sprint_symbol(str, field->ip);
+       ret = trace_seq_printf(s, "%s\n", str);
+       if (!ret)
+               return TRACE_TYPE_PARTIAL_LINE;
+
+       return TRACE_TYPE_HANDLED;
+}
+
+struct tracer ksym_tracer __read_mostly =
+{
+       .name           = "ksym_tracer",
+       .init           = ksym_trace_init,
+       .reset          = ksym_trace_reset,
+#ifdef CONFIG_FTRACE_SELFTEST
+       .selftest       = trace_selftest_startup_ksym,
+#endif
+       .print_header   = ksym_trace_print_header,
+       .print_line     = ksym_trace_output
+};
+
+__init static int init_ksym_trace(void)
+{
+       struct dentry *d_tracer;
+       struct dentry *entry;
+
+       d_tracer = tracing_init_dentry();
+       ksym_filter_entry_count = 0;
+
+       entry = debugfs_create_file("ksym_trace_filter", 0644, d_tracer,
+                                   NULL, &ksym_tracing_fops);
+       if (!entry)
+               pr_warning("Could not create debugfs "
+                          "'ksym_trace_filter' file\n");
+
+       return register_tracer(&ksym_tracer);
+}
+device_initcall(init_ksym_trace);
+
+
+#ifdef CONFIG_PROFILE_KSYM_TRACER
+static int ksym_tracer_stat_headers(struct seq_file *m)
+{
+       seq_puts(m, "  Access Type ");
+       seq_puts(m, "  Symbol                                       Counter\n");
+       seq_puts(m, "  ----------- ");
+       seq_puts(m, "  ------                                       -------\n");
+       return 0;
+}
+
+static int ksym_tracer_stat_show(struct seq_file *m, void *v)
+{
+       struct hlist_node *stat = v;
+       struct trace_ksym *entry;
+       int access_type = 0;
+       char fn_name[KSYM_NAME_LEN];
+
+       entry = hlist_entry(stat, struct trace_ksym, ksym_hlist);
+
+       access_type = entry->attr.bp_type;
+
+       switch (access_type) {
+       case HW_BREAKPOINT_R:
+               seq_puts(m, "  R           ");
+               break;
+       case HW_BREAKPOINT_W:
+               seq_puts(m, "  W           ");
+               break;
+       case HW_BREAKPOINT_R | HW_BREAKPOINT_W:
+               seq_puts(m, "  RW          ");
+               break;
+       default:
+               seq_puts(m, "  NA          ");
+       }
+
+       if (lookup_symbol_name(entry->attr.bp_addr, fn_name) >= 0)
+               seq_printf(m, "  %-36s", fn_name);
+       else
+               seq_printf(m, "  %-36s", "<NA>");
+       seq_printf(m, " %15lu\n", entry->counter);
+
+       return 0;
+}
+
+static void *ksym_tracer_stat_start(struct tracer_stat *trace)
+{
+       return ksym_filter_head.first;
+}
+
+static void *
+ksym_tracer_stat_next(void *v, int idx)
+{
+       struct hlist_node *stat = v;
+
+       return stat->next;
+}
+
+static struct tracer_stat ksym_tracer_stats = {
+       .name = "ksym_tracer",
+       .stat_start = ksym_tracer_stat_start,
+       .stat_next = ksym_tracer_stat_next,
+       .stat_headers = ksym_tracer_stat_headers,
+       .stat_show = ksym_tracer_stat_show
+};
+
+__init static int ksym_tracer_stat_init(void)
+{
+       int ret;
+
+       ret = register_stat_tracer(&ksym_tracer_stats);
+       if (ret) {
+               printk(KERN_WARNING "Warning: could not register "
+                                   "ksym tracer stats\n");
+               return 1;
+       }
+
+       return 0;
+}
+fs_initcall(ksym_tracer_stat_init);
+#endif /* CONFIG_PROFILE_KSYM_TRACER */
index d2cdbab..dc98309 100644 (file)
@@ -17,6 +17,7 @@ static inline int trace_valid_entry(struct trace_entry *entry)
        case TRACE_GRAPH_ENT:
        case TRACE_GRAPH_RET:
        case TRACE_HW_BRANCHES:
+       case TRACE_KSYM:
                return 1;
        }
        return 0;
@@ -808,3 +809,57 @@ trace_selftest_startup_hw_branches(struct tracer *trace,
        return ret;
 }
 #endif /* CONFIG_HW_BRANCH_TRACER */
+
+#ifdef CONFIG_KSYM_TRACER
+static int ksym_selftest_dummy;
+
+int
+trace_selftest_startup_ksym(struct tracer *trace, struct trace_array *tr)
+{
+       unsigned long count;
+       int ret;
+
+       /* start the tracing */
+       ret = tracer_init(trace, tr);
+       if (ret) {
+               warn_failed_init_tracer(trace, ret);
+               return ret;
+       }
+
+       ksym_selftest_dummy = 0;
+       /* Register the read-write tracing request */
+
+       ret = process_new_ksym_entry("ksym_selftest_dummy",
+                                    HW_BREAKPOINT_R | HW_BREAKPOINT_W,
+                                       (unsigned long)(&ksym_selftest_dummy));
+
+       if (ret < 0) {
+               printk(KERN_CONT "ksym_trace read-write startup test failed\n");
+               goto ret_path;
+       }
+       /* Perform a read and a write operation over the dummy variable to
+        * trigger the tracer
+        */
+       if (ksym_selftest_dummy == 0)
+               ksym_selftest_dummy++;
+
+       /* stop the tracing. */
+       tracing_stop();
+       /* check the trace buffer */
+       ret = trace_test_buffer(tr, &count);
+       trace->reset(tr);
+       tracing_start();
+
+       /* read & write operations - one each is performed on the dummy variable
+        * triggering two entries in the trace buffer
+        */
+       if (!ret && count != 2) {
+               printk(KERN_CONT "Ksym tracer startup test failed");
+               ret = -1;
+       }
+
+ret_path:
+       return ret;
+}
+#endif /* CONFIG_KSYM_TRACER */
+
index ddee9c5..57501d9 100644 (file)
@@ -51,32 +51,6 @@ static struct syscall_metadata *syscall_nr_to_meta(int nr)
        return syscalls_metadata[nr];
 }
 
-int syscall_name_to_nr(char *name)
-{
-       int i;
-
-       if (!syscalls_metadata)
-               return -1;
-
-       for (i = 0; i < NR_syscalls; i++) {
-               if (syscalls_metadata[i]) {
-                       if (!strcmp(syscalls_metadata[i]->name, name))
-                               return i;
-               }
-       }
-       return -1;
-}
-
-void set_syscall_enter_id(int num, int id)
-{
-       syscalls_metadata[num]->enter_id = id;
-}
-
-void set_syscall_exit_id(int num, int id)
-{
-       syscalls_metadata[num]->exit_id = id;
-}
-
 enum print_line_t
 print_syscall_enter(struct trace_iterator *iter, int flags)
 {
@@ -93,7 +67,7 @@ print_syscall_enter(struct trace_iterator *iter, int flags)
        if (!entry)
                goto end;
 
-       if (entry->enter_id != ent->type) {
+       if (entry->enter_event->id != ent->type) {
                WARN_ON_ONCE(1);
                goto end;
        }
@@ -148,7 +122,7 @@ print_syscall_exit(struct trace_iterator *iter, int flags)
                return TRACE_TYPE_HANDLED;
        }
 
-       if (entry->exit_id != ent->type) {
+       if (entry->exit_event->id != ent->type) {
                WARN_ON_ONCE(1);
                return TRACE_TYPE_UNHANDLED;
        }
@@ -166,24 +140,19 @@ extern char *__bad_type_size(void);
 #define SYSCALL_FIELD(type, name)                                      \
        sizeof(type) != sizeof(trace.name) ?                            \
                __bad_type_size() :                                     \
-               #type, #name, offsetof(typeof(trace), name), sizeof(trace.name)
+               #type, #name, offsetof(typeof(trace), name),            \
+               sizeof(trace.name), is_signed_type(type)
 
 int syscall_enter_format(struct ftrace_event_call *call, struct trace_seq *s)
 {
        int i;
-       int nr;
        int ret;
-       struct syscall_metadata *entry;
+       struct syscall_metadata *entry = call->data;
        struct syscall_trace_enter trace;
        int offset = offsetof(struct syscall_trace_enter, args);
 
-       nr = syscall_name_to_nr(call->data);
-       entry = syscall_nr_to_meta(nr);
-
-       if (!entry)
-               return 0;
-
-       ret = trace_seq_printf(s, "\tfield:%s %s;\toffset:%zu;\tsize:%zu;\n",
+       ret = trace_seq_printf(s, "\tfield:%s %s;\toffset:%zu;\tsize:%zu;"
+                              "\tsigned:%u;\n",
                               SYSCALL_FIELD(int, nr));
        if (!ret)
                return 0;
@@ -193,8 +162,10 @@ int syscall_enter_format(struct ftrace_event_call *call, struct trace_seq *s)
                                        entry->args[i]);
                if (!ret)
                        return 0;
-               ret = trace_seq_printf(s, "\toffset:%d;\tsize:%zu;\n", offset,
-                                      sizeof(unsigned long));
+               ret = trace_seq_printf(s, "\toffset:%d;\tsize:%zu;"
+                                      "\tsigned:%u;\n", offset,
+                                      sizeof(unsigned long),
+                                      is_signed_type(unsigned long));
                if (!ret)
                        return 0;
                offset += sizeof(unsigned long);
@@ -226,8 +197,10 @@ int syscall_exit_format(struct ftrace_event_call *call, struct trace_seq *s)
        struct syscall_trace_exit trace;
 
        ret = trace_seq_printf(s,
-                              "\tfield:%s %s;\toffset:%zu;\tsize:%zu;\n"
-                              "\tfield:%s %s;\toffset:%zu;\tsize:%zu;\n",
+                              "\tfield:%s %s;\toffset:%zu;\tsize:%zu;"
+                              "\tsigned:%u;\n"
+                              "\tfield:%s %s;\toffset:%zu;\tsize:%zu;"
+                              "\tsigned:%u;\n",
                               SYSCALL_FIELD(int, nr),
                               SYSCALL_FIELD(long, ret));
        if (!ret)
@@ -239,22 +212,19 @@ int syscall_exit_format(struct ftrace_event_call *call, struct trace_seq *s)
 int syscall_enter_define_fields(struct ftrace_event_call *call)
 {
        struct syscall_trace_enter trace;
-       struct syscall_metadata *meta;
+       struct syscall_metadata *meta = call->data;
        int ret;
-       int nr;
        int i;
        int offset = offsetof(typeof(trace), args);
 
-       nr = syscall_name_to_nr(call->data);
-       meta = syscall_nr_to_meta(nr);
-
-       if (!meta)
-               return 0;
-
        ret = trace_define_common_fields(call);
        if (ret)
                return ret;
 
+       ret = trace_define_field(call, SYSCALL_FIELD(int, nr), FILTER_OTHER);
+       if (ret)
+               return ret;
+
        for (i = 0; i < meta->nb_args; i++) {
                ret = trace_define_field(call, meta->types[i],
                                         meta->args[i], offset,
@@ -275,7 +245,11 @@ int syscall_exit_define_fields(struct ftrace_event_call *call)
        if (ret)
                return ret;
 
-       ret = trace_define_field(call, SYSCALL_FIELD(long, ret), 0,
+       ret = trace_define_field(call, SYSCALL_FIELD(int, nr), FILTER_OTHER);
+       if (ret)
+               return ret;
+
+       ret = trace_define_field(call, SYSCALL_FIELD(long, ret),
                                 FILTER_OTHER);
 
        return ret;
@@ -302,8 +276,8 @@ void ftrace_syscall_enter(struct pt_regs *regs, long id)
 
        size = sizeof(*entry) + sizeof(unsigned long) * sys_data->nb_args;
 
-       event = trace_current_buffer_lock_reserve(&buffer, sys_data->enter_id,
-                                                 size, 0, 0);
+       event = trace_current_buffer_lock_reserve(&buffer,
+                       sys_data->enter_event->id, size, 0, 0);
        if (!event)
                return;
 
@@ -334,8 +308,8 @@ void ftrace_syscall_exit(struct pt_regs *regs, long ret)
        if (!sys_data)
                return;
 
-       event = trace_current_buffer_lock_reserve(&buffer, sys_data->exit_id,
-                               sizeof(*entry), 0, 0);
+       event = trace_current_buffer_lock_reserve(&buffer,
+                       sys_data->exit_event->id, sizeof(*entry), 0, 0);
        if (!event)
                return;
 
@@ -348,14 +322,12 @@ void ftrace_syscall_exit(struct pt_regs *regs, long ret)
                trace_current_buffer_unlock_commit(buffer, event, 0, 0);
 }
 
-int reg_event_syscall_enter(void *ptr)
+int reg_event_syscall_enter(struct ftrace_event_call *call)
 {
        int ret = 0;
        int num;
-       char *name;
 
-       name = (char *)ptr;
-       num = syscall_name_to_nr(name);
+       num = ((struct syscall_metadata *)call->data)->syscall_nr;
        if (num < 0 || num >= NR_syscalls)
                return -ENOSYS;
        mutex_lock(&syscall_trace_lock);
@@ -372,13 +344,11 @@ int reg_event_syscall_enter(void *ptr)
        return ret;
 }
 
-void unreg_event_syscall_enter(void *ptr)
+void unreg_event_syscall_enter(struct ftrace_event_call *call)
 {
        int num;
-       char *name;
 
-       name = (char *)ptr;
-       num = syscall_name_to_nr(name);
+       num = ((struct syscall_metadata *)call->data)->syscall_nr;
        if (num < 0 || num >= NR_syscalls)
                return;
        mutex_lock(&syscall_trace_lock);
@@ -389,14 +359,12 @@ void unreg_event_syscall_enter(void *ptr)
        mutex_unlock(&syscall_trace_lock);
 }
 
-int reg_event_syscall_exit(void *ptr)
+int reg_event_syscall_exit(struct ftrace_event_call *call)
 {
        int ret = 0;
        int num;
-       char *name;
 
-       name = (char *)ptr;
-       num = syscall_name_to_nr(name);
+       num = ((struct syscall_metadata *)call->data)->syscall_nr;
        if (num < 0 || num >= NR_syscalls)
                return -ENOSYS;
        mutex_lock(&syscall_trace_lock);
@@ -413,13 +381,11 @@ int reg_event_syscall_exit(void *ptr)
        return ret;
 }
 
-void unreg_event_syscall_exit(void *ptr)
+void unreg_event_syscall_exit(struct ftrace_event_call *call)
 {
        int num;
-       char *name;
 
-       name = (char *)ptr;
-       num = syscall_name_to_nr(name);
+       num = ((struct syscall_metadata *)call->data)->syscall_nr;
        if (num < 0 || num >= NR_syscalls)
                return;
        mutex_lock(&syscall_trace_lock);
@@ -430,13 +396,17 @@ void unreg_event_syscall_exit(void *ptr)
        mutex_unlock(&syscall_trace_lock);
 }
 
-struct trace_event event_syscall_enter = {
-       .trace                  = print_syscall_enter,
-};
+int init_syscall_trace(struct ftrace_event_call *call)
+{
+       int id;
 
-struct trace_event event_syscall_exit = {
-       .trace                  = print_syscall_exit,
-};
+       id = register_ftrace_event(call->event);
+       if (!id)
+               return -ENODEV;
+       call->id = id;
+       INIT_LIST_HEAD(&call->fields);
+       return 0;
+}
 
 int __init init_ftrace_syscalls(void)
 {
@@ -454,6 +424,10 @@ int __init init_ftrace_syscalls(void)
        for (i = 0; i < NR_syscalls; i++) {
                addr = arch_syscall_addr(i);
                meta = find_syscall_meta(addr);
+               if (!meta)
+                       continue;
+
+               meta->syscall_nr = i;
                syscalls_metadata[i] = meta;
        }
 
@@ -473,8 +447,10 @@ static void prof_syscall_enter(struct pt_regs *regs, long id)
        struct syscall_metadata *sys_data;
        struct syscall_trace_enter *rec;
        unsigned long flags;
+       char *trace_buf;
        char *raw_data;
        int syscall_nr;
+       int rctx;
        int size;
        int cpu;
 
@@ -498,41 +474,42 @@ static void prof_syscall_enter(struct pt_regs *regs, long id)
        /* Protect the per cpu buffer, begin the rcu read side */
        local_irq_save(flags);
 
+       rctx = perf_swevent_get_recursion_context();
+       if (rctx < 0)
+               goto end_recursion;
+
        cpu = smp_processor_id();
 
-       if (in_nmi())
-               raw_data = rcu_dereference(trace_profile_buf_nmi);
-       else
-               raw_data = rcu_dereference(trace_profile_buf);
+       trace_buf = rcu_dereference(perf_trace_buf);
 
-       if (!raw_data)
+       if (!trace_buf)
                goto end;
 
-       raw_data = per_cpu_ptr(raw_data, cpu);
+       raw_data = per_cpu_ptr(trace_buf, cpu);
 
        /* zero the dead bytes from align to not leak stack to user */
        *(u64 *)(&raw_data[size - sizeof(u64)]) = 0ULL;
 
        rec = (struct syscall_trace_enter *) raw_data;
        tracing_generic_entry_update(&rec->ent, 0, 0);
-       rec->ent.type = sys_data->enter_id;
+       rec->ent.type = sys_data->enter_event->id;
        rec->nr = syscall_nr;
        syscall_get_arguments(current, regs, 0, sys_data->nb_args,
                               (unsigned long *)&rec->args);
-       perf_tp_event(sys_data->enter_id, 0, 1, rec, size);
+       perf_tp_event(sys_data->enter_event->id, 0, 1, rec, size);
 
 end:
+       perf_swevent_put_recursion_context(rctx);
+end_recursion:
        local_irq_restore(flags);
 }
 
-int reg_prof_syscall_enter(char *name)
+int prof_sysenter_enable(struct ftrace_event_call *call)
 {
        int ret = 0;
        int num;
 
-       num = syscall_name_to_nr(name);
-       if (num < 0 || num >= NR_syscalls)
-               return -ENOSYS;
+       num = ((struct syscall_metadata *)call->data)->syscall_nr;
 
        mutex_lock(&syscall_trace_lock);
        if (!sys_prof_refcount_enter)
@@ -548,13 +525,11 @@ int reg_prof_syscall_enter(char *name)
        return ret;
 }
 
-void unreg_prof_syscall_enter(char *name)
+void prof_sysenter_disable(struct ftrace_event_call *call)
 {
        int num;
 
-       num = syscall_name_to_nr(name);
-       if (num < 0 || num >= NR_syscalls)
-               return;
+       num = ((struct syscall_metadata *)call->data)->syscall_nr;
 
        mutex_lock(&syscall_trace_lock);
        sys_prof_refcount_enter--;
@@ -570,7 +545,9 @@ static void prof_syscall_exit(struct pt_regs *regs, long ret)
        struct syscall_trace_exit *rec;
        unsigned long flags;
        int syscall_nr;
+       char *trace_buf;
        char *raw_data;
+       int rctx;
        int size;
        int cpu;
 
@@ -596,17 +573,19 @@ static void prof_syscall_exit(struct pt_regs *regs, long ret)
 
        /* Protect the per cpu buffer, begin the rcu read side */
        local_irq_save(flags);
+
+       rctx = perf_swevent_get_recursion_context();
+       if (rctx < 0)
+               goto end_recursion;
+
        cpu = smp_processor_id();
 
-       if (in_nmi())
-               raw_data = rcu_dereference(trace_profile_buf_nmi);
-       else
-               raw_data = rcu_dereference(trace_profile_buf);
+       trace_buf = rcu_dereference(perf_trace_buf);
 
-       if (!raw_data)
+       if (!trace_buf)
                goto end;
 
-       raw_data = per_cpu_ptr(raw_data, cpu);
+       raw_data = per_cpu_ptr(trace_buf, cpu);
 
        /* zero the dead bytes from align to not leak stack to user */
        *(u64 *)(&raw_data[size - sizeof(u64)]) = 0ULL;
@@ -614,24 +593,24 @@ static void prof_syscall_exit(struct pt_regs *regs, long ret)
        rec = (struct syscall_trace_exit *)raw_data;
 
        tracing_generic_entry_update(&rec->ent, 0, 0);
-       rec->ent.type = sys_data->exit_id;
+       rec->ent.type = sys_data->exit_event->id;
        rec->nr = syscall_nr;
        rec->ret = syscall_get_return_value(current, regs);
 
-       perf_tp_event(sys_data->exit_id, 0, 1, rec, size);
+       perf_tp_event(sys_data->exit_event->id, 0, 1, rec, size);
 
 end:
+       perf_swevent_put_recursion_context(rctx);
+end_recursion:
        local_irq_restore(flags);
 }
 
-int reg_prof_syscall_exit(char *name)
+int prof_sysexit_enable(struct ftrace_event_call *call)
 {
        int ret = 0;
        int num;
 
-       num = syscall_name_to_nr(name);
-       if (num < 0 || num >= NR_syscalls)
-               return -ENOSYS;
+       num = ((struct syscall_metadata *)call->data)->syscall_nr;
 
        mutex_lock(&syscall_trace_lock);
        if (!sys_prof_refcount_exit)
@@ -647,13 +626,11 @@ int reg_prof_syscall_exit(char *name)
        return ret;
 }
 
-void unreg_prof_syscall_exit(char *name)
+void prof_sysexit_disable(struct ftrace_event_call *call)
 {
        int num;
 
-       num = syscall_name_to_nr(name);
-       if (num < 0 || num >= NR_syscalls)
-               return;
+       num = ((struct syscall_metadata *)call->data)->syscall_nr;
 
        mutex_lock(&syscall_trace_lock);
        sys_prof_refcount_exit--;
diff --git a/kernel/user-return-notifier.c b/kernel/user-return-notifier.c
new file mode 100644 (file)
index 0000000..03e2d6f
--- /dev/null
@@ -0,0 +1,46 @@
+
+#include <linux/user-return-notifier.h>
+#include <linux/percpu.h>
+#include <linux/sched.h>
+#include <linux/module.h>
+
+static DEFINE_PER_CPU(struct hlist_head, return_notifier_list);
+
+#define URN_LIST_HEAD per_cpu(return_notifier_list, raw_smp_processor_id())
+
+/*
+ * Request a notification when the current cpu returns to userspace.  Must be
+ * called in atomic context.  The notifier will also be called in atomic
+ * context.
+ */
+void user_return_notifier_register(struct user_return_notifier *urn)
+{
+       set_tsk_thread_flag(current, TIF_USER_RETURN_NOTIFY);
+       hlist_add_head(&urn->link, &URN_LIST_HEAD);
+}
+EXPORT_SYMBOL_GPL(user_return_notifier_register);
+
+/*
+ * Removes a registered user return notifier.  Must be called from atomic
+ * context, and from the same cpu registration occured in.
+ */
+void user_return_notifier_unregister(struct user_return_notifier *urn)
+{
+       hlist_del(&urn->link);
+       if (hlist_empty(&URN_LIST_HEAD))
+               clear_tsk_thread_flag(current, TIF_USER_RETURN_NOTIFY);
+}
+EXPORT_SYMBOL_GPL(user_return_notifier_unregister);
+
+/* Calls registered user return notifiers */
+void fire_user_return_notifiers(void)
+{
+       struct user_return_notifier *urn;
+       struct hlist_node *tmp1, *tmp2;
+       struct hlist_head *head;
+
+       head = &get_cpu_var(return_notifier_list);
+       hlist_for_each_entry_safe(urn, tmp1, tmp2, head, link)
+               urn->on_user_return(urn);
+       put_cpu_var(return_notifier_list);
+}
index 69eae35..a2cd77e 100644 (file)
@@ -57,78 +57,47 @@ static int proc_do_uts_string(ctl_table *table, int write,
 #define proc_do_uts_string NULL
 #endif
 
-
-#ifdef CONFIG_SYSCTL_SYSCALL
-/* The generic string strategy routine: */
-static int sysctl_uts_string(ctl_table *table,
-                 void __user *oldval, size_t __user *oldlenp,
-                 void __user *newval, size_t newlen)
-{
-       struct ctl_table uts_table;
-       int r, write;
-       write = newval && newlen;
-       memcpy(&uts_table, table, sizeof(uts_table));
-       uts_table.data = get_uts(table, write);
-       r = sysctl_string(&uts_table, oldval, oldlenp, newval, newlen);
-       put_uts(table, write, uts_table.data);
-       return r;
-}
-#else
-#define sysctl_uts_string NULL
-#endif
-
 static struct ctl_table uts_kern_table[] = {
        {
-               .ctl_name       = KERN_OSTYPE,
                .procname       = "ostype",
                .data           = init_uts_ns.name.sysname,
                .maxlen         = sizeof(init_uts_ns.name.sysname),
                .mode           = 0444,
                .proc_handler   = proc_do_uts_string,
-               .strategy       = sysctl_uts_string,
        },
        {
-               .ctl_name       = KERN_OSRELEASE,
                .procname       = "osrelease",
                .data           = init_uts_ns.name.release,
                .maxlen         = sizeof(init_uts_ns.name.release),
                .mode           = 0444,
                .proc_handler   = proc_do_uts_string,
-               .strategy       = sysctl_uts_string,
        },
        {
-               .ctl_name       = KERN_VERSION,
                .procname       = "version",
                .data           = init_uts_ns.name.version,
                .maxlen         = sizeof(init_uts_ns.name.version),
                .mode           = 0444,
                .proc_handler   = proc_do_uts_string,
-               .strategy       = sysctl_uts_string,
        },
        {
-               .ctl_name       = KERN_NODENAME,
                .procname       = "hostname",
                .data           = init_uts_ns.name.nodename,
                .maxlen         = sizeof(init_uts_ns.name.nodename),
                .mode           = 0644,
                .proc_handler   = proc_do_uts_string,
-               .strategy       = sysctl_uts_string,
        },
        {
-               .ctl_name       = KERN_DOMAINNAME,
                .procname       = "domainname",
                .data           = init_uts_ns.name.domainname,
                .maxlen         = sizeof(init_uts_ns.name.domainname),
                .mode           = 0644,
                .proc_handler   = proc_do_uts_string,
-               .strategy       = sysctl_uts_string,
        },
        {}
 };
 
 static struct ctl_table uts_root_table[] = {
        {
-               .ctl_name       = CTL_KERN,
                .procname       = "kernel",
                .mode           = 0555,
                .child          = uts_kern_table,
index bb1326d..1cfe516 100644 (file)
@@ -200,4 +200,7 @@ config NLATTR
 config GENERIC_ATOMIC64
        bool
 
+config LRU_CACHE
+       tristate
+
 endmenu
index a79c4d0..0b8f359 100644 (file)
@@ -912,7 +912,7 @@ config LATENCYTOP
 
 config SYSCTL_SYSCALL_CHECK
        bool "Sysctl checks"
-       depends on SYSCTL_SYSCALL
+       depends on SYSCTL
        ---help---
          sys_sysctl uses binary paths that have been found challenging
          to properly maintain and use. This enables checks that help
index 2e78277..347ad8d 100644 (file)
@@ -91,6 +91,8 @@ obj-$(CONFIG_DYNAMIC_DEBUG) += dynamic_debug.o
 
 obj-$(CONFIG_NLATTR) += nlattr.o
 
+obj-$(CONFIG_LRU_CACHE) += lru_cache.o
+
 obj-$(CONFIG_DMA_API_DEBUG) += dma-debug.o
 
 obj-$(CONFIG_GENERIC_CSUM) += checksum.o
diff --git a/lib/lru_cache.c b/lib/lru_cache.c
new file mode 100644 (file)
index 0000000..270de9d
--- /dev/null
@@ -0,0 +1,560 @@
+/*
+   lru_cache.c
+
+   This file is part of DRBD by Philipp Reisner and Lars Ellenberg.
+
+   Copyright (C) 2003-2008, LINBIT Information Technologies GmbH.
+   Copyright (C) 2003-2008, Philipp Reisner <philipp.reisner@linbit.com>.
+   Copyright (C) 2003-2008, Lars Ellenberg <lars.ellenberg@linbit.com>.
+
+   drbd is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   drbd 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 drbd; see the file COPYING.  If not, write to
+   the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ */
+
+#include <linux/module.h>
+#include <linux/bitops.h>
+#include <linux/slab.h>
+#include <linux/string.h> /* for memset */
+#include <linux/seq_file.h> /* for seq_printf */
+#include <linux/lru_cache.h>
+
+MODULE_AUTHOR("Philipp Reisner <phil@linbit.com>, "
+             "Lars Ellenberg <lars@linbit.com>");
+MODULE_DESCRIPTION("lru_cache - Track sets of hot objects");
+MODULE_LICENSE("GPL");
+
+/* this is developers aid only.
+ * it catches concurrent access (lack of locking on the users part) */
+#define PARANOIA_ENTRY() do {          \
+       BUG_ON(!lc);                    \
+       BUG_ON(!lc->nr_elements);       \
+       BUG_ON(test_and_set_bit(__LC_PARANOIA, &lc->flags)); \
+} while (0)
+
+#define RETURN(x...)     do { \
+       clear_bit(__LC_PARANOIA, &lc->flags); \
+       smp_mb__after_clear_bit(); return x ; } while (0)
+
+/* BUG() if e is not one of the elements tracked by lc */
+#define PARANOIA_LC_ELEMENT(lc, e) do {        \
+       struct lru_cache *lc_ = (lc);   \
+       struct lc_element *e_ = (e);    \
+       unsigned i = e_->lc_index;      \
+       BUG_ON(i >= lc_->nr_elements);  \
+       BUG_ON(lc_->lc_element[i] != e_); } while (0)
+
+/**
+ * lc_create - prepares to track objects in an active set
+ * @name: descriptive name only used in lc_seq_printf_stats and lc_seq_dump_details
+ * @e_count: number of elements allowed to be active simultaneously
+ * @e_size: size of the tracked objects
+ * @e_off: offset to the &struct lc_element member in a tracked object
+ *
+ * Returns a pointer to a newly initialized struct lru_cache on success,
+ * or NULL on (allocation) failure.
+ */
+struct lru_cache *lc_create(const char *name, struct kmem_cache *cache,
+               unsigned e_count, size_t e_size, size_t e_off)
+{
+       struct hlist_head *slot = NULL;
+       struct lc_element **element = NULL;
+       struct lru_cache *lc;
+       struct lc_element *e;
+       unsigned cache_obj_size = kmem_cache_size(cache);
+       unsigned i;
+
+       WARN_ON(cache_obj_size < e_size);
+       if (cache_obj_size < e_size)
+               return NULL;
+
+       /* e_count too big; would probably fail the allocation below anyways.
+        * for typical use cases, e_count should be few thousand at most. */
+       if (e_count > LC_MAX_ACTIVE)
+               return NULL;
+
+       slot = kzalloc(e_count * sizeof(struct hlist_head*), GFP_KERNEL);
+       if (!slot)
+               goto out_fail;
+       element = kzalloc(e_count * sizeof(struct lc_element *), GFP_KERNEL);
+       if (!element)
+               goto out_fail;
+
+       lc = kzalloc(sizeof(*lc), GFP_KERNEL);
+       if (!lc)
+               goto out_fail;
+
+       INIT_LIST_HEAD(&lc->in_use);
+       INIT_LIST_HEAD(&lc->lru);
+       INIT_LIST_HEAD(&lc->free);
+
+       lc->name = name;
+       lc->element_size = e_size;
+       lc->element_off = e_off;
+       lc->nr_elements = e_count;
+       lc->new_number = LC_FREE;
+       lc->lc_cache = cache;
+       lc->lc_element = element;
+       lc->lc_slot = slot;
+
+       /* preallocate all objects */
+       for (i = 0; i < e_count; i++) {
+               void *p = kmem_cache_alloc(cache, GFP_KERNEL);
+               if (!p)
+                       break;
+               memset(p, 0, lc->element_size);
+               e = p + e_off;
+               e->lc_index = i;
+               e->lc_number = LC_FREE;
+               list_add(&e->list, &lc->free);
+               element[i] = e;
+       }
+       if (i == e_count)
+               return lc;
+
+       /* else: could not allocate all elements, give up */
+       for (i--; i; i--) {
+               void *p = element[i];
+               kmem_cache_free(cache, p - e_off);
+       }
+       kfree(lc);
+out_fail:
+       kfree(element);
+       kfree(slot);
+       return NULL;
+}
+
+void lc_free_by_index(struct lru_cache *lc, unsigned i)
+{
+       void *p = lc->lc_element[i];
+       WARN_ON(!p);
+       if (p) {
+               p -= lc->element_off;
+               kmem_cache_free(lc->lc_cache, p);
+       }
+}
+
+/**
+ * lc_destroy - frees memory allocated by lc_create()
+ * @lc: the lru cache to destroy
+ */
+void lc_destroy(struct lru_cache *lc)
+{
+       unsigned i;
+       if (!lc)
+               return;
+       for (i = 0; i < lc->nr_elements; i++)
+               lc_free_by_index(lc, i);
+       kfree(lc->lc_element);
+       kfree(lc->lc_slot);
+       kfree(lc);
+}
+
+/**
+ * lc_reset - does a full reset for @lc and the hash table slots.
+ * @lc: the lru cache to operate on
+ *
+ * It is roughly the equivalent of re-allocating a fresh lru_cache object,
+ * basically a short cut to lc_destroy(lc); lc = lc_create(...);
+ */
+void lc_reset(struct lru_cache *lc)
+{
+       unsigned i;
+
+       INIT_LIST_HEAD(&lc->in_use);
+       INIT_LIST_HEAD(&lc->lru);
+       INIT_LIST_HEAD(&lc->free);
+       lc->used = 0;
+       lc->hits = 0;
+       lc->misses = 0;
+       lc->starving = 0;
+       lc->dirty = 0;
+       lc->changed = 0;
+       lc->flags = 0;
+       lc->changing_element = NULL;
+       lc->new_number = LC_FREE;
+       memset(lc->lc_slot, 0, sizeof(struct hlist_head) * lc->nr_elements);
+
+       for (i = 0; i < lc->nr_elements; i++) {
+               struct lc_element *e = lc->lc_element[i];
+               void *p = e;
+               p -= lc->element_off;
+               memset(p, 0, lc->element_size);
+               /* re-init it */
+               e->lc_index = i;
+               e->lc_number = LC_FREE;
+               list_add(&e->list, &lc->free);
+       }
+}
+
+/**
+ * lc_seq_printf_stats - print stats about @lc into @seq
+ * @seq: the seq_file to print into
+ * @lc: the lru cache to print statistics of
+ */
+size_t lc_seq_printf_stats(struct seq_file *seq, struct lru_cache *lc)
+{
+       /* NOTE:
+        * total calls to lc_get are
+        * (starving + hits + misses)
+        * misses include "dirty" count (update from an other thread in
+        * progress) and "changed", when this in fact lead to an successful
+        * update of the cache.
+        */
+       return seq_printf(seq, "\t%s: used:%u/%u "
+               "hits:%lu misses:%lu starving:%lu dirty:%lu changed:%lu\n",
+               lc->name, lc->used, lc->nr_elements,
+               lc->hits, lc->misses, lc->starving, lc->dirty, lc->changed);
+}
+
+static struct hlist_head *lc_hash_slot(struct lru_cache *lc, unsigned int enr)
+{
+       return  lc->lc_slot + (enr % lc->nr_elements);
+}
+
+
+/**
+ * lc_find - find element by label, if present in the hash table
+ * @lc: The lru_cache object
+ * @enr: element number
+ *
+ * Returns the pointer to an element, if the element with the requested
+ * "label" or element number is present in the hash table,
+ * or NULL if not found. Does not change the refcnt.
+ */
+struct lc_element *lc_find(struct lru_cache *lc, unsigned int enr)
+{
+       struct hlist_node *n;
+       struct lc_element *e;
+
+       BUG_ON(!lc);
+       BUG_ON(!lc->nr_elements);
+       hlist_for_each_entry(e, n, lc_hash_slot(lc, enr), colision) {
+               if (e->lc_number == enr)
+                       return e;
+       }
+       return NULL;
+}
+
+/* returned element will be "recycled" immediately */
+static struct lc_element *lc_evict(struct lru_cache *lc)
+{
+       struct list_head  *n;
+       struct lc_element *e;
+
+       if (list_empty(&lc->lru))
+               return NULL;
+
+       n = lc->lru.prev;
+       e = list_entry(n, struct lc_element, list);
+
+       PARANOIA_LC_ELEMENT(lc, e);
+
+       list_del(&e->list);
+       hlist_del(&e->colision);
+       return e;
+}
+
+/**
+ * lc_del - removes an element from the cache
+ * @lc: The lru_cache object
+ * @e: The element to remove
+ *
+ * @e must be unused (refcnt == 0). Moves @e from "lru" to "free" list,
+ * sets @e->enr to %LC_FREE.
+ */
+void lc_del(struct lru_cache *lc, struct lc_element *e)
+{
+       PARANOIA_ENTRY();
+       PARANOIA_LC_ELEMENT(lc, e);
+       BUG_ON(e->refcnt);
+
+       e->lc_number = LC_FREE;
+       hlist_del_init(&e->colision);
+       list_move(&e->list, &lc->free);
+       RETURN();
+}
+
+static struct lc_element *lc_get_unused_element(struct lru_cache *lc)
+{
+       struct list_head *n;
+
+       if (list_empty(&lc->free))
+               return lc_evict(lc);
+
+       n = lc->free.next;
+       list_del(n);
+       return list_entry(n, struct lc_element, list);
+}
+
+static int lc_unused_element_available(struct lru_cache *lc)
+{
+       if (!list_empty(&lc->free))
+               return 1; /* something on the free list */
+       if (!list_empty(&lc->lru))
+               return 1;  /* something to evict */
+
+       return 0;
+}
+
+
+/**
+ * lc_get - get element by label, maybe change the active set
+ * @lc: the lru cache to operate on
+ * @enr: the label to look up
+ *
+ * Finds an element in the cache, increases its usage count,
+ * "touches" and returns it.
+ *
+ * In case the requested number is not present, it needs to be added to the
+ * cache. Therefore it is possible that an other element becomes evicted from
+ * the cache. In either case, the user is notified so he is able to e.g. keep
+ * a persistent log of the cache changes, and therefore the objects in use.
+ *
+ * Return values:
+ *  NULL
+ *     The cache was marked %LC_STARVING,
+ *     or the requested label was not in the active set
+ *     and a changing transaction is still pending (@lc was marked %LC_DIRTY).
+ *     Or no unused or free element could be recycled (@lc will be marked as
+ *     %LC_STARVING, blocking further lc_get() operations).
+ *
+ *  pointer to the element with the REQUESTED element number.
+ *     In this case, it can be used right away
+ *
+ *  pointer to an UNUSED element with some different element number,
+ *          where that different number may also be %LC_FREE.
+ *
+ *          In this case, the cache is marked %LC_DIRTY (blocking further changes),
+ *          and the returned element pointer is removed from the lru list and
+ *          hash collision chains.  The user now should do whatever housekeeping
+ *          is necessary.
+ *          Then he must call lc_changed(lc,element_pointer), to finish
+ *          the change.
+ *
+ * NOTE: The user needs to check the lc_number on EACH use, so he recognizes
+ *       any cache set change.
+ */
+struct lc_element *lc_get(struct lru_cache *lc, unsigned int enr)
+{
+       struct lc_element *e;
+
+       PARANOIA_ENTRY();
+       if (lc->flags & LC_STARVING) {
+               ++lc->starving;
+               RETURN(NULL);
+       }
+
+       e = lc_find(lc, enr);
+       if (e) {
+               ++lc->hits;
+               if (e->refcnt++ == 0)
+                       lc->used++;
+               list_move(&e->list, &lc->in_use); /* Not evictable... */
+               RETURN(e);
+       }
+
+       ++lc->misses;
+
+       /* In case there is nothing available and we can not kick out
+        * the LRU element, we have to wait ...
+        */
+       if (!lc_unused_element_available(lc)) {
+               __set_bit(__LC_STARVING, &lc->flags);
+               RETURN(NULL);
+       }
+
+       /* it was not present in the active set.
+        * we are going to recycle an unused (or even "free") element.
+        * user may need to commit a transaction to record that change.
+        * we serialize on flags & TF_DIRTY */
+       if (test_and_set_bit(__LC_DIRTY, &lc->flags)) {
+               ++lc->dirty;
+               RETURN(NULL);
+       }
+
+       e = lc_get_unused_element(lc);
+       BUG_ON(!e);
+
+       clear_bit(__LC_STARVING, &lc->flags);
+       BUG_ON(++e->refcnt != 1);
+       lc->used++;
+
+       lc->changing_element = e;
+       lc->new_number = enr;
+
+       RETURN(e);
+}
+
+/* similar to lc_get,
+ * but only gets a new reference on an existing element.
+ * you either get the requested element, or NULL.
+ * will be consolidated into one function.
+ */
+struct lc_element *lc_try_get(struct lru_cache *lc, unsigned int enr)
+{
+       struct lc_element *e;
+
+       PARANOIA_ENTRY();
+       if (lc->flags & LC_STARVING) {
+               ++lc->starving;
+               RETURN(NULL);
+       }
+
+       e = lc_find(lc, enr);
+       if (e) {
+               ++lc->hits;
+               if (e->refcnt++ == 0)
+                       lc->used++;
+               list_move(&e->list, &lc->in_use); /* Not evictable... */
+       }
+       RETURN(e);
+}
+
+/**
+ * lc_changed - tell @lc that the change has been recorded
+ * @lc: the lru cache to operate on
+ * @e: the element pending label change
+ */
+void lc_changed(struct lru_cache *lc, struct lc_element *e)
+{
+       PARANOIA_ENTRY();
+       BUG_ON(e != lc->changing_element);
+       PARANOIA_LC_ELEMENT(lc, e);
+       ++lc->changed;
+       e->lc_number = lc->new_number;
+       list_add(&e->list, &lc->in_use);
+       hlist_add_head(&e->colision, lc_hash_slot(lc, lc->new_number));
+       lc->changing_element = NULL;
+       lc->new_number = LC_FREE;
+       clear_bit(__LC_DIRTY, &lc->flags);
+       smp_mb__after_clear_bit();
+       RETURN();
+}
+
+
+/**
+ * lc_put - give up refcnt of @e
+ * @lc: the lru cache to operate on
+ * @e: the element to put
+ *
+ * If refcnt reaches zero, the element is moved to the lru list,
+ * and a %LC_STARVING (if set) is cleared.
+ * Returns the new (post-decrement) refcnt.
+ */
+unsigned int lc_put(struct lru_cache *lc, struct lc_element *e)
+{
+       PARANOIA_ENTRY();
+       PARANOIA_LC_ELEMENT(lc, e);
+       BUG_ON(e->refcnt == 0);
+       BUG_ON(e == lc->changing_element);
+       if (--e->refcnt == 0) {
+               /* move it to the front of LRU. */
+               list_move(&e->list, &lc->lru);
+               lc->used--;
+               clear_bit(__LC_STARVING, &lc->flags);
+               smp_mb__after_clear_bit();
+       }
+       RETURN(e->refcnt);
+}
+
+/**
+ * lc_element_by_index
+ * @lc: the lru cache to operate on
+ * @i: the index of the element to return
+ */
+struct lc_element *lc_element_by_index(struct lru_cache *lc, unsigned i)
+{
+       BUG_ON(i >= lc->nr_elements);
+       BUG_ON(lc->lc_element[i] == NULL);
+       BUG_ON(lc->lc_element[i]->lc_index != i);
+       return lc->lc_element[i];
+}
+
+/**
+ * lc_index_of
+ * @lc: the lru cache to operate on
+ * @e: the element to query for its index position in lc->element
+ */
+unsigned int lc_index_of(struct lru_cache *lc, struct lc_element *e)
+{
+       PARANOIA_LC_ELEMENT(lc, e);
+       return e->lc_index;
+}
+
+/**
+ * lc_set - associate index with label
+ * @lc: the lru cache to operate on
+ * @enr: the label to set
+ * @index: the element index to associate label with.
+ *
+ * Used to initialize the active set to some previously recorded state.
+ */
+void lc_set(struct lru_cache *lc, unsigned int enr, int index)
+{
+       struct lc_element *e;
+
+       if (index < 0 || index >= lc->nr_elements)
+               return;
+
+       e = lc_element_by_index(lc, index);
+       e->lc_number = enr;
+
+       hlist_del_init(&e->colision);
+       hlist_add_head(&e->colision, lc_hash_slot(lc, enr));
+       list_move(&e->list, e->refcnt ? &lc->in_use : &lc->lru);
+}
+
+/**
+ * lc_dump - Dump a complete LRU cache to seq in textual form.
+ * @lc: the lru cache to operate on
+ * @seq: the &struct seq_file pointer to seq_printf into
+ * @utext: user supplied "heading" or other info
+ * @detail: function pointer the user may provide to dump further details
+ * of the object the lc_element is embedded in.
+ */
+void lc_seq_dump_details(struct seq_file *seq, struct lru_cache *lc, char *utext,
+            void (*detail) (struct seq_file *, struct lc_element *))
+{
+       unsigned int nr_elements = lc->nr_elements;
+       struct lc_element *e;
+       int i;
+
+       seq_printf(seq, "\tnn: lc_number refcnt %s\n ", utext);
+       for (i = 0; i < nr_elements; i++) {
+               e = lc_element_by_index(lc, i);
+               if (e->lc_number == LC_FREE) {
+                       seq_printf(seq, "\t%2d: FREE\n", i);
+               } else {
+                       seq_printf(seq, "\t%2d: %4u %4u    ", i,
+                                  e->lc_number, e->refcnt);
+                       detail(seq, e);
+               }
+       }
+}
+
+EXPORT_SYMBOL(lc_create);
+EXPORT_SYMBOL(lc_reset);
+EXPORT_SYMBOL(lc_destroy);
+EXPORT_SYMBOL(lc_set);
+EXPORT_SYMBOL(lc_del);
+EXPORT_SYMBOL(lc_try_get);
+EXPORT_SYMBOL(lc_find);
+EXPORT_SYMBOL(lc_get);
+EXPORT_SYMBOL(lc_put);
+EXPORT_SYMBOL(lc_changed);
+EXPORT_SYMBOL(lc_element_by_index);
+EXPORT_SYMBOL(lc_index_of);
+EXPORT_SYMBOL(lc_seq_printf_stats);
+EXPORT_SYMBOL(lc_seq_dump_details);
index 67a33a5..0e8ca03 100644 (file)
@@ -609,7 +609,7 @@ static void bdi_wb_shutdown(struct backing_dev_info *bdi)
         * it would never exet if it is currently stuck in the refrigerator.
         */
        list_for_each_entry(wb, &bdi->wb_list, list) {
-               wb->task->flags &= ~PF_FROZEN;
+               thaw_process(wb->task);
                kthread_stop(wb->task);
        }
 }
index 2c5d792..0b19943 100644 (file)
@@ -821,7 +821,6 @@ int write_cache_pages(struct address_space *mapping,
                      struct writeback_control *wbc, writepage_t writepage,
                      void *data)
 {
-       struct backing_dev_info *bdi = mapping->backing_dev_info;
        int ret = 0;
        int done = 0;
        struct pagevec pvec;
@@ -834,11 +833,6 @@ int write_cache_pages(struct address_space *mapping,
        int range_whole = 0;
        long nr_to_write = wbc->nr_to_write;
 
-       if (wbc->nonblocking && bdi_write_congested(bdi)) {
-               wbc->encountered_congestion = 1;
-               return 0;
-       }
-
        pagevec_init(&pvec, 0);
        if (wbc->range_cyclic) {
                writeback_index = mapping->writeback_index; /* prev offset */
@@ -957,12 +951,6 @@ continue_unlock:
                                        break;
                                }
                        }
-
-                       if (wbc->nonblocking && bdi_write_congested(bdi)) {
-                               wbc->encountered_congestion = 1;
-                               done = 1;
-                               break;
-                       }
                }
                pagevec_release(&pvec);
                cond_resched();
index e874447..44acce4 100644 (file)
@@ -635,19 +635,18 @@ struct net_device *alloc_trdev(int sizeof_priv)
 #ifdef CONFIG_SYSCTL
 static struct ctl_table tr_table[] = {
        {
-               .ctl_name       = NET_TR_RIF_TIMEOUT,
                .procname       = "rif_timeout",
                .data           = &sysctl_tr_rif_timeout,
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec
        },
-       { },
+       { },
 };
 
 static __initdata struct ctl_path tr_path[] = {
-       { .procname = "net", .ctl_name = CTL_NET, },
-       { .procname = "token-ring", .ctl_name = NET_TR, },
+       { .procname = "net", },
+       { .procname = "token-ring", },
        { }
 };
 #endif
index 8d237b1..04e9c0d 100644 (file)
 
 static struct ctl_table atalk_table[] = {
        {
-               .ctl_name       = NET_ATALK_AARP_EXPIRY_TIME,
                .procname       = "aarp-expiry-time",
                .data           = &sysctl_aarp_expiry_time,
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_jiffies,
-               .strategy       = sysctl_jiffies,
        },
        {
-               .ctl_name       = NET_ATALK_AARP_TICK_TIME,
                .procname       = "aarp-tick-time",
                .data           = &sysctl_aarp_tick_time,
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_jiffies,
-               .strategy       = sysctl_jiffies,
        },
        {
-               .ctl_name       = NET_ATALK_AARP_RETRANSMIT_LIMIT,
                .procname       = "aarp-retransmit-limit",
                .data           = &sysctl_aarp_retransmit_limit,
                .maxlen         = sizeof(int),
@@ -38,20 +33,18 @@ static struct ctl_table atalk_table[] = {
                .proc_handler   = proc_dointvec,
        },
        {
-               .ctl_name       = NET_ATALK_AARP_RESOLVE_TIME,
                .procname       = "aarp-resolve-time",
                .data           = &sysctl_aarp_resolve_time,
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_jiffies,
-               .strategy       = sysctl_jiffies,
        },
-       { },
+       { },
 };
 
 static struct ctl_path atalk_path[] = {
-       { .procname = "net", .ctl_name = CTL_NET, },
-       { .procname = "appletalk", .ctl_name = NET_ATALK, },
+       { .procname = "net", },
+       { .procname = "appletalk", },
        { }
 };
 
index 62ee3fb..5159be6 100644 (file)
@@ -34,156 +34,128 @@ static ctl_table *ax25_table;
 static int ax25_table_size;
 
 static struct ctl_path ax25_path[] = {
-       { .procname = "net", .ctl_name = CTL_NET, },
-       { .procname = "ax25", .ctl_name = NET_AX25, },
+       { .procname = "net", },
+       { .procname = "ax25", },
        { }
 };
 
 static const ctl_table ax25_param_table[] = {
        {
-               .ctl_name       = NET_AX25_IP_DEFAULT_MODE,
                .procname       = "ip_default_mode",
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .strategy       = sysctl_intvec,
                .extra1         = &min_ipdefmode,
                .extra2         = &max_ipdefmode
        },
        {
-               .ctl_name       = NET_AX25_DEFAULT_MODE,
                .procname       = "ax25_default_mode",
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .strategy       = sysctl_intvec,
                .extra1         = &min_axdefmode,
                .extra2         = &max_axdefmode
        },
        {
-               .ctl_name       = NET_AX25_BACKOFF_TYPE,
                .procname       = "backoff_type",
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .strategy       = sysctl_intvec,
                .extra1         = &min_backoff,
                .extra2         = &max_backoff
        },
        {
-               .ctl_name       = NET_AX25_CONNECT_MODE,
                .procname       = "connect_mode",
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .strategy       = sysctl_intvec,
                .extra1         = &min_conmode,
                .extra2         = &max_conmode
        },
        {
-               .ctl_name       = NET_AX25_STANDARD_WINDOW,
                .procname       = "standard_window_size",
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .strategy       = sysctl_intvec,
                .extra1         = &min_window,
                .extra2         = &max_window
        },
        {
-               .ctl_name       = NET_AX25_EXTENDED_WINDOW,
                .procname       = "extended_window_size",
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .strategy       = sysctl_intvec,
                .extra1         = &min_ewindow,
                .extra2         = &max_ewindow
        },
        {
-               .ctl_name       = NET_AX25_T1_TIMEOUT,
                .procname       = "t1_timeout",
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .strategy       = sysctl_intvec,
                .extra1         = &min_t1,
                .extra2         = &max_t1
        },
        {
-               .ctl_name       = NET_AX25_T2_TIMEOUT,
                .procname       = "t2_timeout",
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .strategy       = sysctl_intvec,
                .extra1         = &min_t2,
                .extra2         = &max_t2
        },
        {
-               .ctl_name       = NET_AX25_T3_TIMEOUT,
                .procname       = "t3_timeout",
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .strategy       = sysctl_intvec,
                .extra1         = &min_t3,
                .extra2         = &max_t3
        },
        {
-               .ctl_name       = NET_AX25_IDLE_TIMEOUT,
                .procname       = "idle_timeout",
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .strategy       = sysctl_intvec,
                .extra1         = &min_idle,
                .extra2         = &max_idle
        },
        {
-               .ctl_name       = NET_AX25_N2,
                .procname       = "maximum_retry_count",
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .strategy       = sysctl_intvec,
                .extra1         = &min_n2,
                .extra2         = &max_n2
        },
        {
-               .ctl_name       = NET_AX25_PACLEN,
                .procname       = "maximum_packet_length",
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .strategy       = sysctl_intvec,
                .extra1         = &min_paclen,
                .extra2         = &max_paclen
        },
        {
-               .ctl_name       = NET_AX25_PROTOCOL,
                .procname       = "protocol",
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .strategy       = sysctl_intvec,
                .extra1         = &min_proto,
                .extra2         = &max_proto
        },
 #ifdef CONFIG_AX25_DAMA_SLAVE
        {
-               .ctl_name       = NET_AX25_DAMA_SLAVE_TIMEOUT,
                .procname       = "dama_slave_timeout",
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .strategy       = sysctl_intvec,
                .extra1         = &min_ds_timeout,
                .extra2         = &max_ds_timeout
        },
 #endif
 
-       { .ctl_name = 0 }       /* that's all, folks! */
+       { }     /* that's all, folks! */
 };
 
 void ax25_register_sysctl(void)
@@ -212,11 +184,9 @@ void ax25_register_sysctl(void)
                        return;
                }
                ax25_table[n].child = ax25_dev->systable = child;
-               ax25_table[n].ctl_name     = n + 1;
                ax25_table[n].procname     = ax25_dev->dev->name;
                ax25_table[n].mode         = 0555;
 
-               child[AX25_MAX_VALUES].ctl_name = 0;    /* just in case... */
 
                for (k = 0; k < AX25_MAX_VALUES; k++)
                        child[k].data = &ax25_dev->values[k];
@@ -233,7 +203,7 @@ void ax25_unregister_sysctl(void)
        ctl_table *p;
        unregister_sysctl_table(ax25_table_header);
 
-       for (p = ax25_table; p->ctl_name; p++)
+       for (p = ax25_table; p->procname; p++)
                kfree(p->child);
        kfree(ax25_table);
 }
index a16a234..268e2e7 100644 (file)
@@ -1013,12 +1013,12 @@ static ctl_table brnf_table[] = {
                .mode           = 0644,
                .proc_handler   = brnf_sysctl_call_tables,
        },
-       { .ctl_name = 0 }
+       { }
 };
 
 static struct ctl_path brnf_path[] = {
-       { .procname = "net", .ctl_name = CTL_NET, },
-       { .procname = "bridge", .ctl_name = NET_BRIDGE, },
+       { .procname = "net", },
+       { .procname = "bridge", },
        { }
 };
 #endif
index a08a35b..f35377b 100644 (file)
@@ -2566,21 +2566,18 @@ static struct neigh_sysctl_table {
 } neigh_sysctl_template __read_mostly = {
        .neigh_vars = {
                {
-                       .ctl_name       = NET_NEIGH_MCAST_SOLICIT,
                        .procname       = "mcast_solicit",
                        .maxlen         = sizeof(int),
                        .mode           = 0644,
                        .proc_handler   = proc_dointvec,
                },
                {
-                       .ctl_name       = NET_NEIGH_UCAST_SOLICIT,
                        .procname       = "ucast_solicit",
                        .maxlen         = sizeof(int),
                        .mode           = 0644,
                        .proc_handler   = proc_dointvec,
                },
                {
-                       .ctl_name       = NET_NEIGH_APP_SOLICIT,
                        .procname       = "app_solicit",
                        .maxlen         = sizeof(int),
                        .mode           = 0644,
@@ -2593,38 +2590,30 @@ static struct neigh_sysctl_table {
                        .proc_handler   = proc_dointvec_userhz_jiffies,
                },
                {
-                       .ctl_name       = NET_NEIGH_REACHABLE_TIME,
                        .procname       = "base_reachable_time",
                        .maxlen         = sizeof(int),
                        .mode           = 0644,
                        .proc_handler   = proc_dointvec_jiffies,
-                       .strategy       = sysctl_jiffies,
                },
                {
-                       .ctl_name       = NET_NEIGH_DELAY_PROBE_TIME,
                        .procname       = "delay_first_probe_time",
                        .maxlen         = sizeof(int),
                        .mode           = 0644,
                        .proc_handler   = proc_dointvec_jiffies,
-                       .strategy       = sysctl_jiffies,
                },
                {
-                       .ctl_name       = NET_NEIGH_GC_STALE_TIME,
                        .procname       = "gc_stale_time",
                        .maxlen         = sizeof(int),
                        .mode           = 0644,
                        .proc_handler   = proc_dointvec_jiffies,
-                       .strategy       = sysctl_jiffies,
                },
                {
-                       .ctl_name       = NET_NEIGH_UNRES_QLEN,
                        .procname       = "unres_qlen",
                        .maxlen         = sizeof(int),
                        .mode           = 0644,
                        .proc_handler   = proc_dointvec,
                },
                {
-                       .ctl_name       = NET_NEIGH_PROXY_QLEN,
                        .procname       = "proxy_qlen",
                        .maxlen         = sizeof(int),
                        .mode           = 0644,
@@ -2649,45 +2638,36 @@ static struct neigh_sysctl_table {
                        .proc_handler   = proc_dointvec_userhz_jiffies,
                },
                {
-                       .ctl_name       = NET_NEIGH_RETRANS_TIME_MS,
                        .procname       = "retrans_time_ms",
                        .maxlen         = sizeof(int),
                        .mode           = 0644,
                        .proc_handler   = proc_dointvec_ms_jiffies,
-                       .strategy       = sysctl_ms_jiffies,
                },
                {
-                       .ctl_name       = NET_NEIGH_REACHABLE_TIME_MS,
                        .procname       = "base_reachable_time_ms",
                        .maxlen         = sizeof(int),
                        .mode           = 0644,
                        .proc_handler   = proc_dointvec_ms_jiffies,
-                       .strategy       = sysctl_ms_jiffies,
                },
                {
-                       .ctl_name       = NET_NEIGH_GC_INTERVAL,
                        .procname       = "gc_interval",
                        .maxlen         = sizeof(int),
                        .mode           = 0644,
                        .proc_handler   = proc_dointvec_jiffies,
-                       .strategy       = sysctl_jiffies,
                },
                {
-                       .ctl_name       = NET_NEIGH_GC_THRESH1,
                        .procname       = "gc_thresh1",
                        .maxlen         = sizeof(int),
                        .mode           = 0644,
                        .proc_handler   = proc_dointvec,
                },
                {
-                       .ctl_name       = NET_NEIGH_GC_THRESH2,
                        .procname       = "gc_thresh2",
                        .maxlen         = sizeof(int),
                        .mode           = 0644,
                        .proc_handler   = proc_dointvec,
                },
                {
-                       .ctl_name       = NET_NEIGH_GC_THRESH3,
                        .procname       = "gc_thresh3",
                        .maxlen         = sizeof(int),
                        .mode           = 0644,
@@ -2699,7 +2679,7 @@ static struct neigh_sysctl_table {
 
 int neigh_sysctl_register(struct net_device *dev, struct neigh_parms *p,
                          int p_id, int pdev_id, char *p_name,
-                         proc_handler *handler, ctl_handler *strategy)
+                         proc_handler *handler)
 {
        struct neigh_sysctl_table *t;
        const char *dev_name_source = NULL;
@@ -2710,10 +2690,10 @@ int neigh_sysctl_register(struct net_device *dev, struct neigh_parms *p,
 #define NEIGH_CTL_PATH_DEV     3
 
        struct ctl_path neigh_path[] = {
-               { .procname = "net",     .ctl_name = CTL_NET, },
-               { .procname = "proto",   .ctl_name = 0, },
-               { .procname = "neigh",   .ctl_name = 0, },
-               { .procname = "default", .ctl_name = NET_PROTO_CONF_DEFAULT, },
+               { .procname = "net",     },
+               { .procname = "proto",   },
+               { .procname = "neigh",   },
+               { .procname = "default", },
                { },
        };
 
@@ -2738,7 +2718,6 @@ int neigh_sysctl_register(struct net_device *dev, struct neigh_parms *p,
 
        if (dev) {
                dev_name_source = dev->name;
-               neigh_path[NEIGH_CTL_PATH_DEV].ctl_name = dev->ifindex;
                /* Terminate the table early */
                memset(&t->neigh_vars[14], 0, sizeof(t->neigh_vars[14]));
        } else {
@@ -2750,31 +2729,19 @@ int neigh_sysctl_register(struct net_device *dev, struct neigh_parms *p,
        }
 
 
-       if (handler || strategy) {
+       if (handler) {
                /* RetransTime */
                t->neigh_vars[3].proc_handler = handler;
-               t->neigh_vars[3].strategy = strategy;
                t->neigh_vars[3].extra1 = dev;
-               if (!strategy)
-                       t->neigh_vars[3].ctl_name = CTL_UNNUMBERED;
                /* ReachableTime */
                t->neigh_vars[4].proc_handler = handler;
-               t->neigh_vars[4].strategy = strategy;
                t->neigh_vars[4].extra1 = dev;
-               if (!strategy)
-                       t->neigh_vars[4].ctl_name = CTL_UNNUMBERED;
                /* RetransTime (in milliseconds)*/
                t->neigh_vars[12].proc_handler = handler;
-               t->neigh_vars[12].strategy = strategy;
                t->neigh_vars[12].extra1 = dev;
-               if (!strategy)
-                       t->neigh_vars[12].ctl_name = CTL_UNNUMBERED;
                /* ReachableTime (in milliseconds) */
                t->neigh_vars[13].proc_handler = handler;
-               t->neigh_vars[13].strategy = strategy;
                t->neigh_vars[13].extra1 = dev;
-               if (!strategy)
-                       t->neigh_vars[13].ctl_name = CTL_UNNUMBERED;
        }
 
        t->dev_name = kstrdup(dev_name_source, GFP_KERNEL);
@@ -2782,9 +2749,7 @@ int neigh_sysctl_register(struct net_device *dev, struct neigh_parms *p,
                goto free;
 
        neigh_path[NEIGH_CTL_PATH_DEV].procname = t->dev_name;
-       neigh_path[NEIGH_CTL_PATH_NEIGH].ctl_name = pdev_id;
        neigh_path[NEIGH_CTL_PATH_PROTO].procname = p_name;
-       neigh_path[NEIGH_CTL_PATH_PROTO].ctl_name = p_id;
 
        t->sysctl_header =
                register_net_sysctl_table(neigh_parms_net(p), neigh_path, t->neigh_vars);
index 8938fa7..0612487 100644 (file)
@@ -19,7 +19,6 @@
 static struct ctl_table net_core_table[] = {
 #ifdef CONFIG_NET
        {
-               .ctl_name       = NET_CORE_WMEM_MAX,
                .procname       = "wmem_max",
                .data           = &sysctl_wmem_max,
                .maxlen         = sizeof(int),
@@ -27,7 +26,6 @@ static struct ctl_table net_core_table[] = {
                .proc_handler   = proc_dointvec
        },
        {
-               .ctl_name       = NET_CORE_RMEM_MAX,
                .procname       = "rmem_max",
                .data           = &sysctl_rmem_max,
                .maxlen         = sizeof(int),
@@ -35,7 +33,6 @@ static struct ctl_table net_core_table[] = {
                .proc_handler   = proc_dointvec
        },
        {
-               .ctl_name       = NET_CORE_WMEM_DEFAULT,
                .procname       = "wmem_default",
                .data           = &sysctl_wmem_default,
                .maxlen         = sizeof(int),
@@ -43,7 +40,6 @@ static struct ctl_table net_core_table[] = {
                .proc_handler   = proc_dointvec
        },
        {
-               .ctl_name       = NET_CORE_RMEM_DEFAULT,
                .procname       = "rmem_default",
                .data           = &sysctl_rmem_default,
                .maxlen         = sizeof(int),
@@ -51,7 +47,6 @@ static struct ctl_table net_core_table[] = {
                .proc_handler   = proc_dointvec
        },
        {
-               .ctl_name       = NET_CORE_DEV_WEIGHT,
                .procname       = "dev_weight",
                .data           = &weight_p,
                .maxlen         = sizeof(int),
@@ -59,7 +54,6 @@ static struct ctl_table net_core_table[] = {
                .proc_handler   = proc_dointvec
        },
        {
-               .ctl_name       = NET_CORE_MAX_BACKLOG,
                .procname       = "netdev_max_backlog",
                .data           = &netdev_max_backlog,
                .maxlen         = sizeof(int),
@@ -67,16 +61,13 @@ static struct ctl_table net_core_table[] = {
                .proc_handler   = proc_dointvec
        },
        {
-               .ctl_name       = NET_CORE_MSG_COST,
                .procname       = "message_cost",
                .data           = &net_ratelimit_state.interval,
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_jiffies,
-               .strategy       = sysctl_jiffies,
        },
        {
-               .ctl_name       = NET_CORE_MSG_BURST,
                .procname       = "message_burst",
                .data           = &net_ratelimit_state.burst,
                .maxlen         = sizeof(int),
@@ -84,7 +75,6 @@ static struct ctl_table net_core_table[] = {
                .proc_handler   = proc_dointvec,
        },
        {
-               .ctl_name       = NET_CORE_OPTMEM_MAX,
                .procname       = "optmem_max",
                .data           = &sysctl_optmem_max,
                .maxlen         = sizeof(int),
@@ -93,7 +83,6 @@ static struct ctl_table net_core_table[] = {
        },
 #endif /* CONFIG_NET */
        {
-               .ctl_name       = NET_CORE_BUDGET,
                .procname       = "netdev_budget",
                .data           = &netdev_budget,
                .maxlen         = sizeof(int),
@@ -101,31 +90,29 @@ static struct ctl_table net_core_table[] = {
                .proc_handler   = proc_dointvec
        },
        {
-               .ctl_name       = NET_CORE_WARNINGS,
                .procname       = "warnings",
                .data           = &net_msg_warn,
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec
        },
-       { .ctl_name = 0 }
+       { }
 };
 
 static struct ctl_table netns_core_table[] = {
        {
-               .ctl_name       = NET_CORE_SOMAXCONN,
                .procname       = "somaxconn",
                .data           = &init_net.core.sysctl_somaxconn,
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec
        },
-       { .ctl_name = 0 }
+       { }
 };
 
 __net_initdata struct ctl_path net_core_path[] = {
-       { .procname = "net", .ctl_name = CTL_NET, },
-       { .procname = "core", .ctl_name = NET_CORE, },
+       { .procname = "net", },
+       { .procname = "core", },
        { },
 };
 
index a5a1856..5639438 100644 (file)
@@ -93,13 +93,13 @@ static struct ctl_table dccp_default_table[] = {
                .proc_handler   = proc_dointvec_ms_jiffies,
        },
 
-       { .ctl_name = 0, }
+       { }
 };
 
 static struct ctl_path dccp_path[] = {
-       { .procname = "net", .ctl_name = CTL_NET, },
-       { .procname = "dccp", .ctl_name = NET_DCCP, },
-       { .procname = "default", .ctl_name = NET_DCCP_DEFAULT, },
+       { .procname = "net", },
+       { .procname = "dccp", },
+       { .procname = "default", },
        { }
 };
 
index f20dec9..238af09 100644 (file)
@@ -89,7 +89,6 @@ static struct dn_dev_parms dn_dev_list[] =  {
        .t2 =           1,
        .t3 =           10,
        .name =         "ethernet",
-       .ctl_name =     NET_DECNET_CONF_ETHER,
        .up =           dn_eth_up,
        .down =         dn_eth_down,
        .timer3 =       dn_send_brd_hello,
@@ -101,7 +100,6 @@ static struct dn_dev_parms dn_dev_list[] =  {
        .t2 =           1,
        .t3 =           10,
        .name =         "ipgre",
-       .ctl_name =     NET_DECNET_CONF_GRE,
        .timer3 =       dn_send_brd_hello,
 },
 #if 0
@@ -112,7 +110,6 @@ static struct dn_dev_parms dn_dev_list[] =  {
        .t2 =           1,
        .t3 =           120,
        .name =         "x25",
-       .ctl_name =     NET_DECNET_CONF_X25,
        .timer3 =       dn_send_ptp_hello,
 },
 #endif
@@ -124,7 +121,6 @@ static struct dn_dev_parms dn_dev_list[] =  {
        .t2 =           1,
        .t3 =           10,
        .name =         "ppp",
-       .ctl_name =     NET_DECNET_CONF_PPP,
        .timer3 =       dn_send_brd_hello,
 },
 #endif
@@ -135,7 +131,6 @@ static struct dn_dev_parms dn_dev_list[] =  {
        .t2 =           1,
        .t3 =           120,
        .name =         "ddcmp",
-       .ctl_name =     NET_DECNET_CONF_DDCMP,
        .timer3 =       dn_send_ptp_hello,
 },
 {
@@ -145,7 +140,6 @@ static struct dn_dev_parms dn_dev_list[] =  {
        .t2 =           1,
        .t3 =           10,
        .name =         "loopback",
-       .ctl_name =     NET_DECNET_CONF_LOOPBACK,
        .timer3 =       dn_send_brd_hello,
 }
 };
@@ -166,10 +160,6 @@ static int max_priority[] = { 127 }; /* From DECnet spec */
 
 static int dn_forwarding_proc(ctl_table *, int,
                        void __user *, size_t *, loff_t *);
-static int dn_forwarding_sysctl(ctl_table *table,
-                       void __user *oldval, size_t __user *oldlenp,
-                       void __user *newval, size_t newlen);
-
 static struct dn_dev_sysctl_table {
        struct ctl_table_header *sysctl_header;
        ctl_table dn_dev_vars[5];
@@ -177,44 +167,36 @@ static struct dn_dev_sysctl_table {
        NULL,
        {
        {
-               .ctl_name = NET_DECNET_CONF_DEV_FORWARDING,
                .procname = "forwarding",
                .data = (void *)DN_DEV_PARMS_OFFSET(forwarding),
                .maxlen = sizeof(int),
                .mode = 0644,
                .proc_handler = dn_forwarding_proc,
-               .strategy = dn_forwarding_sysctl,
        },
        {
-               .ctl_name = NET_DECNET_CONF_DEV_PRIORITY,
                .procname = "priority",
                .data = (void *)DN_DEV_PARMS_OFFSET(priority),
                .maxlen = sizeof(int),
                .mode = 0644,
                .proc_handler = proc_dointvec_minmax,
-               .strategy = sysctl_intvec,
                .extra1 = &min_priority,
                .extra2 = &max_priority
        },
        {
-               .ctl_name = NET_DECNET_CONF_DEV_T2,
                .procname = "t2",
                .data = (void *)DN_DEV_PARMS_OFFSET(t2),
                .maxlen = sizeof(int),
                .mode = 0644,
                .proc_handler = proc_dointvec_minmax,
-               .strategy = sysctl_intvec,
                .extra1 = &min_t2,
                .extra2 = &max_t2
        },
        {
-               .ctl_name = NET_DECNET_CONF_DEV_T3,
                .procname = "t3",
                .data = (void *)DN_DEV_PARMS_OFFSET(t3),
                .maxlen = sizeof(int),
                .mode = 0644,
                .proc_handler = proc_dointvec_minmax,
-               .strategy = sysctl_intvec,
                .extra1 = &min_t3,
                .extra2 = &max_t3
        },
@@ -230,9 +212,9 @@ static void dn_dev_sysctl_register(struct net_device *dev, struct dn_dev_parms *
 #define DN_CTL_PATH_DEV        3
 
        struct ctl_path dn_ctl_path[] = {
-               { .procname = "net", .ctl_name = CTL_NET, },
-               { .procname = "decnet", .ctl_name = NET_DECNET, },
-               { .procname = "conf", .ctl_name = NET_DECNET_CONF, },
+               { .procname = "net",  },
+               { .procname = "decnet",  },
+               { .procname = "conf",  },
                { /* to be set */ },
                { },
        };
@@ -248,10 +230,8 @@ static void dn_dev_sysctl_register(struct net_device *dev, struct dn_dev_parms *
 
        if (dev) {
                dn_ctl_path[DN_CTL_PATH_DEV].procname = dev->name;
-               dn_ctl_path[DN_CTL_PATH_DEV].ctl_name = dev->ifindex;
        } else {
                dn_ctl_path[DN_CTL_PATH_DEV].procname = parms->name;
-               dn_ctl_path[DN_CTL_PATH_DEV].ctl_name = parms->ctl_name;
        }
 
        t->dn_dev_vars[0].extra1 = (void *)dev;
@@ -317,44 +297,6 @@ static int dn_forwarding_proc(ctl_table *table, int write,
 #endif
 }
 
-static int dn_forwarding_sysctl(ctl_table *table,
-                       void __user *oldval, size_t __user *oldlenp,
-                       void __user *newval, size_t newlen)
-{
-#ifdef CONFIG_DECNET_ROUTER
-       struct net_device *dev = table->extra1;
-       struct dn_dev *dn_db;
-       int value;
-
-       if (table->extra1 == NULL)
-               return -EINVAL;
-
-       dn_db = dev->dn_ptr;
-
-       if (newval && newlen) {
-               if (newlen != sizeof(int))
-                       return -EINVAL;
-
-               if (get_user(value, (int __user *)newval))
-                       return -EFAULT;
-               if (value < 0)
-                       return -EINVAL;
-               if (value > 2)
-                       return -EINVAL;
-
-               if (dn_db->parms.down)
-                       dn_db->parms.down(dev);
-               dn_db->parms.forwarding = value;
-               if (dn_db->parms.up)
-                       dn_db->parms.up(dev);
-       }
-
-       return 0;
-#else
-       return -EINVAL;
-#endif
-}
-
 #else /* CONFIG_SYSCTL */
 static void dn_dev_sysctl_unregister(struct dn_dev_parms *parms)
 {
index 2036568..be3eb8e 100644 (file)
@@ -131,39 +131,6 @@ static int parse_addr(__le16 *addr, char *str)
        return 0;
 }
 
-
-static int dn_node_address_strategy(ctl_table *table,
-                               void __user *oldval, size_t __user *oldlenp,
-                               void __user *newval, size_t newlen)
-{
-       size_t len;
-       __le16 addr;
-
-       if (oldval && oldlenp) {
-               if (get_user(len, oldlenp))
-                       return -EFAULT;
-               if (len) {
-                       if (len != sizeof(unsigned short))
-                               return -EINVAL;
-                       if (put_user(decnet_address, (__le16 __user *)oldval))
-                               return -EFAULT;
-               }
-       }
-       if (newval && newlen) {
-               if (newlen != sizeof(unsigned short))
-                       return -EINVAL;
-               if (get_user(addr, (__le16 __user *)newval))
-                       return -EFAULT;
-
-               dn_dev_devices_off();
-
-               decnet_address = addr;
-
-               dn_dev_devices_on();
-       }
-       return 0;
-}
-
 static int dn_node_address_handler(ctl_table *table, int write,
                                void __user *buffer,
                                size_t *lenp, loff_t *ppos)
@@ -215,64 +182,6 @@ static int dn_node_address_handler(ctl_table *table, int write,
        return 0;
 }
 
-
-static int dn_def_dev_strategy(ctl_table *table,
-                               void __user *oldval, size_t __user *oldlenp,
-                               void __user *newval, size_t newlen)
-{
-       size_t len;
-       struct net_device *dev;
-       char devname[17];
-       size_t namel;
-       int rv = 0;
-
-       devname[0] = 0;
-
-       if (oldval && oldlenp) {
-               if (get_user(len, oldlenp))
-                       return -EFAULT;
-               if (len) {
-                       dev = dn_dev_get_default();
-                       if (dev) {
-                               strcpy(devname, dev->name);
-                               dev_put(dev);
-                       }
-
-                       namel = strlen(devname) + 1;
-                       if (len > namel) len = namel;
-
-                       if (copy_to_user(oldval, devname, len))
-                               return -EFAULT;
-
-                       if (put_user(len, oldlenp))
-                               return -EFAULT;
-               }
-       }
-
-       if (newval && newlen) {
-               if (newlen > 16)
-                       return -E2BIG;
-
-               if (copy_from_user(devname, newval, newlen))
-                       return -EFAULT;
-
-               devname[newlen] = 0;
-
-               dev = dev_get_by_name(&init_net, devname);
-               if (dev == NULL)
-                       return -ENODEV;
-
-               rv = -ENODEV;
-               if (dev->dn_ptr != NULL)
-                       rv = dn_dev_set_default(dev, 1);
-               if (rv)
-                       dev_put(dev);
-       }
-
-       return rv;
-}
-
-
 static int dn_def_dev_handler(ctl_table *table, int write,
                                void __user *buffer,
                                size_t *lenp, loff_t *ppos)
@@ -338,138 +247,112 @@ static int dn_def_dev_handler(ctl_table *table, int write,
 
 static ctl_table dn_table[] = {
        {
-               .ctl_name = NET_DECNET_NODE_ADDRESS,
                .procname = "node_address",
                .maxlen = 7,
                .mode = 0644,
                .proc_handler = dn_node_address_handler,
-               .strategy = dn_node_address_strategy,
        },
        {
-               .ctl_name = NET_DECNET_NODE_NAME,
                .procname = "node_name",
                .data = node_name,
                .maxlen = 7,
                .mode = 0644,
                .proc_handler = proc_dostring,
-               .strategy = sysctl_string,
        },
        {
-               .ctl_name = NET_DECNET_DEFAULT_DEVICE,
                .procname = "default_device",
                .maxlen = 16,
                .mode = 0644,
                .proc_handler = dn_def_dev_handler,
-               .strategy = dn_def_dev_strategy,
        },
        {
-               .ctl_name = NET_DECNET_TIME_WAIT,
                .procname = "time_wait",
                .data = &decnet_time_wait,
                .maxlen = sizeof(int),
                .mode = 0644,
                .proc_handler = proc_dointvec_minmax,
-               .strategy = sysctl_intvec,
                .extra1 = &min_decnet_time_wait,
                .extra2 = &max_decnet_time_wait
        },
        {
-               .ctl_name = NET_DECNET_DN_COUNT,
                .procname = "dn_count",
                .data = &decnet_dn_count,
                .maxlen = sizeof(int),
                .mode = 0644,
                .proc_handler = proc_dointvec_minmax,
-               .strategy = sysctl_intvec,
                .extra1 = &min_state_count,
                .extra2 = &max_state_count
        },
        {
-               .ctl_name = NET_DECNET_DI_COUNT,
                .procname = "di_count",
                .data = &decnet_di_count,
                .maxlen = sizeof(int),
                .mode = 0644,
                .proc_handler = proc_dointvec_minmax,
-               .strategy = sysctl_intvec,
                .extra1 = &min_state_count,
                .extra2 = &max_state_count
        },
        {
-               .ctl_name = NET_DECNET_DR_COUNT,
                .procname = "dr_count",
                .data = &decnet_dr_count,
                .maxlen = sizeof(int),
                .mode = 0644,
                .proc_handler = proc_dointvec_minmax,
-               .strategy = sysctl_intvec,
                .extra1 = &min_state_count,
                .extra2 = &max_state_count
        },
        {
-               .ctl_name = NET_DECNET_DST_GC_INTERVAL,
                .procname = "dst_gc_interval",
                .data = &decnet_dst_gc_interval,
                .maxlen = sizeof(int),
                .mode = 0644,
                .proc_handler = proc_dointvec_minmax,
-               .strategy = sysctl_intvec,
                .extra1 = &min_decnet_dst_gc_interval,
                .extra2 = &max_decnet_dst_gc_interval
        },
        {
-               .ctl_name = NET_DECNET_NO_FC_MAX_CWND,
                .procname = "no_fc_max_cwnd",
                .data = &decnet_no_fc_max_cwnd,
                .maxlen = sizeof(int),
                .mode = 0644,
                .proc_handler = proc_dointvec_minmax,
-               .strategy = sysctl_intvec,
                .extra1 = &min_decnet_no_fc_max_cwnd,
                .extra2 = &max_decnet_no_fc_max_cwnd
        },
        {
-               .ctl_name = NET_DECNET_MEM,
                .procname = "decnet_mem",
                .data = &sysctl_decnet_mem,
                .maxlen = sizeof(sysctl_decnet_mem),
                .mode = 0644,
                .proc_handler = proc_dointvec,
-               .strategy = sysctl_intvec,
        },
        {
-               .ctl_name = NET_DECNET_RMEM,
                .procname = "decnet_rmem",
                .data = &sysctl_decnet_rmem,
                .maxlen = sizeof(sysctl_decnet_rmem),
                .mode = 0644,
                .proc_handler = proc_dointvec,
-               .strategy = sysctl_intvec,
        },
        {
-               .ctl_name = NET_DECNET_WMEM,
                .procname = "decnet_wmem",
                .data = &sysctl_decnet_wmem,
                .maxlen = sizeof(sysctl_decnet_wmem),
                .mode = 0644,
                .proc_handler = proc_dointvec,
-               .strategy = sysctl_intvec,
        },
        {
-               .ctl_name = NET_DECNET_DEBUG_LEVEL,
                .procname = "debug",
                .data = &decnet_debug_level,
                .maxlen = sizeof(int),
                .mode = 0644,
                .proc_handler = proc_dointvec,
-               .strategy = sysctl_intvec,
        },
-       {0}
+       { }
 };
 
 static struct ctl_path dn_path[] = {
-       { .procname = "net", .ctl_name = CTL_NET, },
-       { .procname = "decnet", .ctl_name = NET_DECNET, },
+       { .procname = "net", },
+       { .procname = "decnet", },
        { }
 };
 
index 4e80f33..c95cd93 100644 (file)
@@ -1240,7 +1240,7 @@ void __init arp_init(void)
        arp_proc_init();
 #ifdef CONFIG_SYSCTL
        neigh_sysctl_register(NULL, &arp_tbl.parms, NET_IPV4,
-                             NET_IPV4_NEIGH, "ipv4", NULL, NULL);
+                             NET_IPV4_NEIGH, "ipv4", NULL);
 #endif
        register_netdevice_notifier(&arp_netdev_notifier);
 }
index e312661..5cdbc10 100644 (file)
@@ -1311,58 +1311,6 @@ static int devinet_conf_proc(ctl_table *ctl, int write,
        return ret;
 }
 
-static int devinet_conf_sysctl(ctl_table *table,
-                              void __user *oldval, size_t __user *oldlenp,
-                              void __user *newval, size_t newlen)
-{
-       struct ipv4_devconf *cnf;
-       struct net *net;
-       int *valp = table->data;
-       int new;
-       int i;
-
-       if (!newval || !newlen)
-               return 0;
-
-       if (newlen != sizeof(int))
-               return -EINVAL;
-
-       if (get_user(new, (int __user *)newval))
-               return -EFAULT;
-
-       if (new == *valp)
-               return 0;
-
-       if (oldval && oldlenp) {
-               size_t len;
-
-               if (get_user(len, oldlenp))
-                       return -EFAULT;
-
-               if (len) {
-                       if (len > table->maxlen)
-                               len = table->maxlen;
-                       if (copy_to_user(oldval, valp, len))
-                               return -EFAULT;
-                       if (put_user(len, oldlenp))
-                               return -EFAULT;
-               }
-       }
-
-       *valp = new;
-
-       cnf = table->extra1;
-       net = table->extra2;
-       i = (int *)table->data - cnf->data;
-
-       set_bit(i, cnf->state);
-
-       if (cnf == net->ipv4.devconf_dflt)
-               devinet_copy_dflt_conf(net, i);
-
-       return 1;
-}
-
 static int devinet_sysctl_forward(ctl_table *ctl, int write,
                                  void __user *buffer,
                                  size_t *lenp, loff_t *ppos)
@@ -1408,47 +1356,28 @@ int ipv4_doint_and_flush(ctl_table *ctl, int write,
        return ret;
 }
 
-int ipv4_doint_and_flush_strategy(ctl_table *table,
-                                 void __user *oldval, size_t __user *oldlenp,
-                                 void __user *newval, size_t newlen)
-{
-       int ret = devinet_conf_sysctl(table, oldval, oldlenp, newval, newlen);
-       struct net *net = table->extra2;
-
-       if (ret == 1)
-               rt_cache_flush(net, 0);
-
-       return ret;
-}
-
-
-#define DEVINET_SYSCTL_ENTRY(attr, name, mval, proc, sysctl) \
+#define DEVINET_SYSCTL_ENTRY(attr, name, mval, proc) \
        { \
-               .ctl_name       = NET_IPV4_CONF_ ## attr, \
                .procname       = name, \
                .data           = ipv4_devconf.data + \
                                  NET_IPV4_CONF_ ## attr - 1, \
                .maxlen         = sizeof(int), \
                .mode           = mval, \
                .proc_handler   = proc, \
-               .strategy       = sysctl, \
                .extra1         = &ipv4_devconf, \
        }
 
 #define DEVINET_SYSCTL_RW_ENTRY(attr, name) \
-       DEVINET_SYSCTL_ENTRY(attr, name, 0644, devinet_conf_proc, \
-                            devinet_conf_sysctl)
+       DEVINET_SYSCTL_ENTRY(attr, name, 0644, devinet_conf_proc)
 
 #define DEVINET_SYSCTL_RO_ENTRY(attr, name) \
-       DEVINET_SYSCTL_ENTRY(attr, name, 0444, devinet_conf_proc, \
-                            devinet_conf_sysctl)
+       DEVINET_SYSCTL_ENTRY(attr, name, 0444, devinet_conf_proc)
 
-#define DEVINET_SYSCTL_COMPLEX_ENTRY(attr, name, proc, sysctl) \
-       DEVINET_SYSCTL_ENTRY(attr, name, 0644, proc, sysctl)
+#define DEVINET_SYSCTL_COMPLEX_ENTRY(attr, name, proc) \
+       DEVINET_SYSCTL_ENTRY(attr, name, 0644, proc)
 
 #define DEVINET_SYSCTL_FLUSHING_ENTRY(attr, name) \
-       DEVINET_SYSCTL_COMPLEX_ENTRY(attr, name, ipv4_doint_and_flush, \
-                                    ipv4_doint_and_flush_strategy)
+       DEVINET_SYSCTL_COMPLEX_ENTRY(attr, name, ipv4_doint_and_flush)
 
 static struct devinet_sysctl_table {
        struct ctl_table_header *sysctl_header;
@@ -1457,8 +1386,7 @@ static struct devinet_sysctl_table {
 } devinet_sysctl = {
        .devinet_vars = {
                DEVINET_SYSCTL_COMPLEX_ENTRY(FORWARDING, "forwarding",
-                                            devinet_sysctl_forward,
-                                            devinet_conf_sysctl),
+                                            devinet_sysctl_forward),
                DEVINET_SYSCTL_RO_ENTRY(MC_FORWARDING, "mc_forwarding"),
 
                DEVINET_SYSCTL_RW_ENTRY(ACCEPT_REDIRECTS, "accept_redirects"),
@@ -1490,7 +1418,7 @@ static struct devinet_sysctl_table {
 };
 
 static int __devinet_sysctl_register(struct net *net, char *dev_name,
-               int ctl_name, struct ipv4_devconf *p)
+                                       struct ipv4_devconf *p)
 {
        int i;
        struct devinet_sysctl_table *t;
@@ -1498,9 +1426,9 @@ static int __devinet_sysctl_register(struct net *net, char *dev_name,
 #define DEVINET_CTL_PATH_DEV   3
 
        struct ctl_path devinet_ctl_path[] = {
-               { .procname = "net", .ctl_name = CTL_NET, },
-               { .procname = "ipv4", .ctl_name = NET_IPV4, },
-               { .procname = "conf", .ctl_name = NET_IPV4_CONF, },
+               { .procname = "net",  },
+               { .procname = "ipv4", },
+               { .procname = "conf", },
                { /* to be set */ },
                { },
        };
@@ -1525,7 +1453,6 @@ static int __devinet_sysctl_register(struct net *net, char *dev_name,
                goto free;
 
        devinet_ctl_path[DEVINET_CTL_PATH_DEV].procname = t->dev_name;
-       devinet_ctl_path[DEVINET_CTL_PATH_DEV].ctl_name = ctl_name;
 
        t->sysctl_header = register_net_sysctl_table(net, devinet_ctl_path,
                        t->devinet_vars);
@@ -1559,9 +1486,9 @@ static void __devinet_sysctl_unregister(struct ipv4_devconf *cnf)
 static void devinet_sysctl_register(struct in_device *idev)
 {
        neigh_sysctl_register(idev->dev, idev->arp_parms, NET_IPV4,
-                       NET_IPV4_NEIGH, "ipv4", NULL, NULL);
+                       NET_IPV4_NEIGH, "ipv4", NULL);
        __devinet_sysctl_register(dev_net(idev->dev), idev->dev->name,
-                       idev->dev->ifindex, &idev->cnf);
+                                       &idev->cnf);
 }
 
 static void devinet_sysctl_unregister(struct in_device *idev)
@@ -1572,14 +1499,12 @@ static void devinet_sysctl_unregister(struct in_device *idev)
 
 static struct ctl_table ctl_forward_entry[] = {
        {
-               .ctl_name       = NET_IPV4_FORWARD,
                .procname       = "ip_forward",
                .data           = &ipv4_devconf.data[
                                        NET_IPV4_CONF_FORWARDING - 1],
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = devinet_sysctl_forward,
-               .strategy       = devinet_conf_sysctl,
                .extra1         = &ipv4_devconf,
                .extra2         = &init_net,
        },
@@ -1587,8 +1512,8 @@ static struct ctl_table ctl_forward_entry[] = {
 };
 
 static __net_initdata struct ctl_path net_ipv4_path[] = {
-       { .procname = "net", .ctl_name = CTL_NET, },
-       { .procname = "ipv4", .ctl_name = NET_IPV4, },
+       { .procname = "net", },
+       { .procname = "ipv4", },
        { },
 };
 #endif
@@ -1627,13 +1552,11 @@ static __net_init int devinet_init_net(struct net *net)
        }
 
 #ifdef CONFIG_SYSCTL
-       err = __devinet_sysctl_register(net, "all",
-                       NET_PROTO_CONF_ALL, all);
+       err = __devinet_sysctl_register(net, "all", all);
        if (err < 0)
                goto err_reg_all;
 
-       err = __devinet_sysctl_register(net, "default",
-                       NET_PROTO_CONF_DEFAULT, dflt);
+       err = __devinet_sysctl_register(net, "default", dflt);
        if (err < 0)
                goto err_reg_dflt;
 
index c473531..86964b3 100644 (file)
@@ -604,7 +604,6 @@ static int zero;
 
 static struct ctl_table ip4_frags_ns_ctl_table[] = {
        {
-               .ctl_name       = NET_IPV4_IPFRAG_HIGH_THRESH,
                .procname       = "ipfrag_high_thresh",
                .data           = &init_net.ipv4.frags.high_thresh,
                .maxlen         = sizeof(int),
@@ -612,7 +611,6 @@ static struct ctl_table ip4_frags_ns_ctl_table[] = {
                .proc_handler   = proc_dointvec
        },
        {
-               .ctl_name       = NET_IPV4_IPFRAG_LOW_THRESH,
                .procname       = "ipfrag_low_thresh",
                .data           = &init_net.ipv4.frags.low_thresh,
                .maxlen         = sizeof(int),
@@ -620,26 +618,22 @@ static struct ctl_table ip4_frags_ns_ctl_table[] = {
                .proc_handler   = proc_dointvec
        },
        {
-               .ctl_name       = NET_IPV4_IPFRAG_TIME,
                .procname       = "ipfrag_time",
                .data           = &init_net.ipv4.frags.timeout,
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_jiffies,
-               .strategy       = sysctl_jiffies
        },
        { }
 };
 
 static struct ctl_table ip4_frags_ctl_table[] = {
        {
-               .ctl_name       = NET_IPV4_IPFRAG_SECRET_INTERVAL,
                .procname       = "ipfrag_secret_interval",
                .data           = &ip4_frags.secret_interval,
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_jiffies,
-               .strategy       = sysctl_jiffies
        },
        {
                .procname       = "ipfrag_max_dist",
index f53cb8d..c14623f 100644 (file)
@@ -248,9 +248,9 @@ module_exit(ipv4_netfilter_fini);
 
 #ifdef CONFIG_SYSCTL
 struct ctl_path nf_net_ipv4_netfilter_sysctl_path[] = {
-       { .procname = "net", .ctl_name = CTL_NET, },
-       { .procname = "ipv4", .ctl_name = NET_IPV4, },
-       { .procname = "netfilter", .ctl_name = NET_IPV4_NETFILTER, },
+       { .procname = "net", },
+       { .procname = "ipv4", },
+       { .procname = "netfilter", },
        { }
 };
 EXPORT_SYMBOL_GPL(nf_net_ipv4_netfilter_sysctl_path);
index 49ad447..2855f1f 100644 (file)
@@ -515,14 +515,13 @@ static struct ctl_table_header *ipq_sysctl_header;
 
 static ctl_table ipq_table[] = {
        {
-               .ctl_name       = NET_IPQ_QMAX,
                .procname       = NET_IPQ_QMAX_NAME,
                .data           = &queue_maxlen,
                .maxlen         = sizeof(queue_maxlen),
                .mode           = 0644,
                .proc_handler   = proc_dointvec
        },
-       { .ctl_name = 0 }
+       { }
 };
 #endif
 
index 9cd423f..d171b12 100644 (file)
@@ -195,7 +195,6 @@ static int log_invalid_proto_max = 255;
 
 static ctl_table ip_ct_sysctl_table[] = {
        {
-               .ctl_name       = NET_IPV4_NF_CONNTRACK_MAX,
                .procname       = "ip_conntrack_max",
                .data           = &nf_conntrack_max,
                .maxlen         = sizeof(int),
@@ -203,7 +202,6 @@ static ctl_table ip_ct_sysctl_table[] = {
                .proc_handler   = proc_dointvec,
        },
        {
-               .ctl_name       = NET_IPV4_NF_CONNTRACK_COUNT,
                .procname       = "ip_conntrack_count",
                .data           = &init_net.ct.count,
                .maxlen         = sizeof(int),
@@ -211,7 +209,6 @@ static ctl_table ip_ct_sysctl_table[] = {
                .proc_handler   = proc_dointvec,
        },
        {
-               .ctl_name       = NET_IPV4_NF_CONNTRACK_BUCKETS,
                .procname       = "ip_conntrack_buckets",
                .data           = &nf_conntrack_htable_size,
                .maxlen         = sizeof(unsigned int),
@@ -219,7 +216,6 @@ static ctl_table ip_ct_sysctl_table[] = {
                .proc_handler   = proc_dointvec,
        },
        {
-               .ctl_name       = NET_IPV4_NF_CONNTRACK_CHECKSUM,
                .procname       = "ip_conntrack_checksum",
                .data           = &init_net.ct.sysctl_checksum,
                .maxlen         = sizeof(int),
@@ -227,19 +223,15 @@ static ctl_table ip_ct_sysctl_table[] = {
                .proc_handler   = proc_dointvec,
        },
        {
-               .ctl_name       = NET_IPV4_NF_CONNTRACK_LOG_INVALID,
                .procname       = "ip_conntrack_log_invalid",
                .data           = &init_net.ct.sysctl_log_invalid,
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .strategy       = sysctl_intvec,
                .extra1         = &log_invalid_proto_min,
                .extra2         = &log_invalid_proto_max,
        },
-       {
-               .ctl_name       = 0
-       }
+       { }
 };
 #endif /* CONFIG_SYSCTL && CONFIG_NF_CONNTRACK_PROC_COMPAT */
 
index e3dd936..7afd39b 100644 (file)
@@ -270,9 +270,7 @@ static struct ctl_table icmp_sysctl_table[] = {
                .mode           = 0644,
                .proc_handler   = proc_dointvec_jiffies,
        },
-       {
-               .ctl_name = 0
-       }
+       { }
 };
 #ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT
 static struct ctl_table icmp_compat_sysctl_table[] = {
@@ -283,9 +281,7 @@ static struct ctl_table icmp_compat_sysctl_table[] = {
                .mode           = 0644,
                .proc_handler   = proc_dointvec_jiffies,
        },
-       {
-               .ctl_name = 0
-       }
+       { }
 };
 #endif /* CONFIG_NF_CONNTRACK_PROC_COMPAT */
 #endif /* CONFIG_SYSCTL */
index 90cdcfc..e446496 100644 (file)
@@ -3058,23 +3058,6 @@ static int ipv4_sysctl_rtcache_flush(ctl_table *__ctl, int write,
        return -EINVAL;
 }
 
-static int ipv4_sysctl_rtcache_flush_strategy(ctl_table *table,
-                                               void __user *oldval,
-                                               size_t __user *oldlenp,
-                                               void __user *newval,
-                                               size_t newlen)
-{
-       int delay;
-       struct net *net;
-       if (newlen != sizeof(int))
-               return -EINVAL;
-       if (get_user(delay, (int __user *)newval))
-               return -EFAULT;
-       net = (struct net *)table->extra1;
-       rt_cache_flush(net, delay);
-       return 0;
-}
-
 static void rt_secret_reschedule(int old)
 {
        struct net *net;
@@ -3119,23 +3102,8 @@ static int ipv4_sysctl_rt_secret_interval(ctl_table *ctl, int write,
        return ret;
 }
 
-static int ipv4_sysctl_rt_secret_interval_strategy(ctl_table *table,
-                                                  void __user *oldval,
-                                                  size_t __user *oldlenp,
-                                                  void __user *newval,
-                                                  size_t newlen)
-{
-       int old = ip_rt_secret_interval;
-       int ret = sysctl_jiffies(table, oldval, oldlenp, newval, newlen);
-
-       rt_secret_reschedule(old);
-
-       return ret;
-}
-
 static ctl_table ipv4_route_table[] = {
        {
-               .ctl_name       = NET_IPV4_ROUTE_GC_THRESH,
                .procname       = "gc_thresh",
                .data           = &ipv4_dst_ops.gc_thresh,
                .maxlen         = sizeof(int),
@@ -3143,7 +3111,6 @@ static ctl_table ipv4_route_table[] = {
                .proc_handler   = proc_dointvec,
        },
        {
-               .ctl_name       = NET_IPV4_ROUTE_MAX_SIZE,
                .procname       = "max_size",
                .data           = &ip_rt_max_size,
                .maxlen         = sizeof(int),
@@ -3153,43 +3120,34 @@ static ctl_table ipv4_route_table[] = {
        {
                /*  Deprecated. Use gc_min_interval_ms */
 
-               .ctl_name       = NET_IPV4_ROUTE_GC_MIN_INTERVAL,
                .procname       = "gc_min_interval",
                .data           = &ip_rt_gc_min_interval,
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_jiffies,
-               .strategy       = sysctl_jiffies,
        },
        {
-               .ctl_name       = NET_IPV4_ROUTE_GC_MIN_INTERVAL_MS,
                .procname       = "gc_min_interval_ms",
                .data           = &ip_rt_gc_min_interval,
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_ms_jiffies,
-               .strategy       = sysctl_ms_jiffies,
        },
        {
-               .ctl_name       = NET_IPV4_ROUTE_GC_TIMEOUT,
                .procname       = "gc_timeout",
                .data           = &ip_rt_gc_timeout,
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_jiffies,
-               .strategy       = sysctl_jiffies,
        },
        {
-               .ctl_name       = NET_IPV4_ROUTE_GC_INTERVAL,
                .procname       = "gc_interval",
                .data           = &ip_rt_gc_interval,
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_jiffies,
-               .strategy       = sysctl_jiffies,
        },
        {
-               .ctl_name       = NET_IPV4_ROUTE_REDIRECT_LOAD,
                .procname       = "redirect_load",
                .data           = &ip_rt_redirect_load,
                .maxlen         = sizeof(int),
@@ -3197,7 +3155,6 @@ static ctl_table ipv4_route_table[] = {
                .proc_handler   = proc_dointvec,
        },
        {
-               .ctl_name       = NET_IPV4_ROUTE_REDIRECT_NUMBER,
                .procname       = "redirect_number",
                .data           = &ip_rt_redirect_number,
                .maxlen         = sizeof(int),
@@ -3205,7 +3162,6 @@ static ctl_table ipv4_route_table[] = {
                .proc_handler   = proc_dointvec,
        },
        {
-               .ctl_name       = NET_IPV4_ROUTE_REDIRECT_SILENCE,
                .procname       = "redirect_silence",
                .data           = &ip_rt_redirect_silence,
                .maxlen         = sizeof(int),
@@ -3213,7 +3169,6 @@ static ctl_table ipv4_route_table[] = {
                .proc_handler   = proc_dointvec,
        },
        {
-               .ctl_name       = NET_IPV4_ROUTE_ERROR_COST,
                .procname       = "error_cost",
                .data           = &ip_rt_error_cost,
                .maxlen         = sizeof(int),
@@ -3221,7 +3176,6 @@ static ctl_table ipv4_route_table[] = {
                .proc_handler   = proc_dointvec,
        },
        {
-               .ctl_name       = NET_IPV4_ROUTE_ERROR_BURST,
                .procname       = "error_burst",
                .data           = &ip_rt_error_burst,
                .maxlen         = sizeof(int),
@@ -3229,7 +3183,6 @@ static ctl_table ipv4_route_table[] = {
                .proc_handler   = proc_dointvec,
        },
        {
-               .ctl_name       = NET_IPV4_ROUTE_GC_ELASTICITY,
                .procname       = "gc_elasticity",
                .data           = &ip_rt_gc_elasticity,
                .maxlen         = sizeof(int),
@@ -3237,16 +3190,13 @@ static ctl_table ipv4_route_table[] = {
                .proc_handler   = proc_dointvec,
        },
        {
-               .ctl_name       = NET_IPV4_ROUTE_MTU_EXPIRES,
                .procname       = "mtu_expires",
                .data           = &ip_rt_mtu_expires,
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_jiffies,
-               .strategy       = sysctl_jiffies,
        },
        {
-               .ctl_name       = NET_IPV4_ROUTE_MIN_PMTU,
                .procname       = "min_pmtu",
                .data           = &ip_rt_min_pmtu,
                .maxlen         = sizeof(int),
@@ -3254,7 +3204,6 @@ static ctl_table ipv4_route_table[] = {
                .proc_handler   = proc_dointvec,
        },
        {
-               .ctl_name       = NET_IPV4_ROUTE_MIN_ADVMSS,
                .procname       = "min_adv_mss",
                .data           = &ip_rt_min_advmss,
                .maxlen         = sizeof(int),
@@ -3262,50 +3211,46 @@ static ctl_table ipv4_route_table[] = {
                .proc_handler   = proc_dointvec,
        },
        {
-               .ctl_name       = NET_IPV4_ROUTE_SECRET_INTERVAL,
                .procname       = "secret_interval",
                .data           = &ip_rt_secret_interval,
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = ipv4_sysctl_rt_secret_interval,
-               .strategy       = ipv4_sysctl_rt_secret_interval_strategy,
        },
-       { .ctl_name = 0 }
+       { }
 };
 
 static struct ctl_table empty[1];
 
 static struct ctl_table ipv4_skeleton[] =
 {
-       { .procname = "route", .ctl_name = NET_IPV4_ROUTE,
+       { .procname = "route", 
          .mode = 0555, .child = ipv4_route_table},
-       { .procname = "neigh", .ctl_name = NET_IPV4_NEIGH,
+       { .procname = "neigh", 
          .mode = 0555, .child = empty},
        { }
 };
 
 static __net_initdata struct ctl_path ipv4_path[] = {
-       { .procname = "net", .ctl_name = CTL_NET, },
-       { .procname = "ipv4", .ctl_name = NET_IPV4, },
+       { .procname = "net", },
+       { .procname = "ipv4", },
        { },
 };
 
 static struct ctl_table ipv4_route_flush_table[] = {
        {
-               .ctl_name       = NET_IPV4_ROUTE_FLUSH,
                .procname       = "flush",
                .maxlen         = sizeof(int),
                .mode           = 0200,
                .proc_handler   = ipv4_sysctl_rtcache_flush,
-               .strategy       = ipv4_sysctl_rtcache_flush_strategy,
        },
-       { .ctl_name = 0 },
+       { },
 };
 
 static __net_initdata struct ctl_path ipv4_route_path[] = {
-       { .procname = "net", .ctl_name = CTL_NET, },
-       { .procname = "ipv4", .ctl_name = NET_IPV4, },
-       { .procname = "route", .ctl_name = NET_IPV4_ROUTE, },
+       { .procname = "net", },
+       { .procname = "ipv4", },
+       { .procname = "route", },
        { },
 };
 
index 13f7ab6..7e3712c 100644 (file)
@@ -63,34 +63,6 @@ static int ipv4_local_port_range(ctl_table *table, int write,
        return ret;
 }
 
-/* Validate changes from sysctl interface. */
-static int ipv4_sysctl_local_port_range(ctl_table *table,
-                                        void __user *oldval,
-                                        size_t __user *oldlenp,
-                                       void __user *newval, size_t newlen)
-{
-       int ret;
-       int range[2];
-       ctl_table tmp = {
-               .data = &range,
-               .maxlen = sizeof(range),
-               .mode = table->mode,
-               .extra1 = &ip_local_port_range_min,
-               .extra2 = &ip_local_port_range_max,
-       };
-
-       inet_get_local_port_range(range, range + 1);
-       ret = sysctl_intvec(&tmp, oldval, oldlenp, newval, newlen);
-       if (ret == 0 && newval && newlen) {
-               if (range[1] < range[0])
-                       ret = -EINVAL;
-               else
-                       set_local_port_range(range);
-       }
-       return ret;
-}
-
-
 static int proc_tcp_congestion_control(ctl_table *ctl, int write,
                                       void __user *buffer, size_t *lenp, loff_t *ppos)
 {
@@ -109,25 +81,6 @@ static int proc_tcp_congestion_control(ctl_table *ctl, int write,
        return ret;
 }
 
-static int sysctl_tcp_congestion_control(ctl_table *table,
-                                        void __user *oldval,
-                                        size_t __user *oldlenp,
-                                        void __user *newval, size_t newlen)
-{
-       char val[TCP_CA_NAME_MAX];
-       ctl_table tbl = {
-               .data = val,
-               .maxlen = TCP_CA_NAME_MAX,
-       };
-       int ret;
-
-       tcp_get_default_congestion_control(val);
-       ret = sysctl_string(&tbl, oldval, oldlenp, newval, newlen);
-       if (ret == 1 && newval && newlen)
-               ret = tcp_set_default_congestion_control(val);
-       return ret;
-}
-
 static int proc_tcp_available_congestion_control(ctl_table *ctl,
                                                 int write,
                                                 void __user *buffer, size_t *lenp,
@@ -165,32 +118,8 @@ static int proc_allowed_congestion_control(ctl_table *ctl,
        return ret;
 }
 
-static int strategy_allowed_congestion_control(ctl_table *table,
-                                              void __user *oldval,
-                                              size_t __user *oldlenp,
-                                              void __user *newval,
-                                              size_t newlen)
-{
-       ctl_table tbl = { .maxlen = TCP_CA_BUF_MAX };
-       int ret;
-
-       tbl.data = kmalloc(tbl.maxlen, GFP_USER);
-       if (!tbl.data)
-               return -ENOMEM;
-
-       tcp_get_available_congestion_control(tbl.data, tbl.maxlen);
-       ret = sysctl_string(&tbl, oldval, oldlenp, newval, newlen);
-       if (ret == 1 && newval && newlen)
-               ret = tcp_set_allowed_congestion_control(tbl.data);
-       kfree(tbl.data);
-
-       return ret;
-
-}
-
 static struct ctl_table ipv4_table[] = {
        {
-               .ctl_name       = NET_IPV4_TCP_TIMESTAMPS,
                .procname       = "tcp_timestamps",
                .data           = &sysctl_tcp_timestamps,
                .maxlen         = sizeof(int),
@@ -198,7 +127,6 @@ static struct ctl_table ipv4_table[] = {
                .proc_handler   = proc_dointvec
        },
        {
-               .ctl_name       = NET_IPV4_TCP_WINDOW_SCALING,
                .procname       = "tcp_window_scaling",
                .data           = &sysctl_tcp_window_scaling,
                .maxlen         = sizeof(int),
@@ -206,7 +134,6 @@ static struct ctl_table ipv4_table[] = {
                .proc_handler   = proc_dointvec
        },
        {
-               .ctl_name       = NET_IPV4_TCP_SACK,
                .procname       = "tcp_sack",
                .data           = &sysctl_tcp_sack,
                .maxlen         = sizeof(int),
@@ -214,7 +141,6 @@ static struct ctl_table ipv4_table[] = {
                .proc_handler   = proc_dointvec
        },
        {
-               .ctl_name       = NET_IPV4_TCP_RETRANS_COLLAPSE,
                .procname       = "tcp_retrans_collapse",
                .data           = &sysctl_tcp_retrans_collapse,
                .maxlen         = sizeof(int),
@@ -222,17 +148,14 @@ static struct ctl_table ipv4_table[] = {
                .proc_handler   = proc_dointvec
        },
        {
-               .ctl_name       = NET_IPV4_DEFAULT_TTL,
                .procname       = "ip_default_ttl",
                .data           = &sysctl_ip_default_ttl,
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = ipv4_doint_and_flush,
-               .strategy       = ipv4_doint_and_flush_strategy,
                .extra2         = &init_net,
        },
        {
-               .ctl_name       = NET_IPV4_NO_PMTU_DISC,
                .procname       = "ip_no_pmtu_disc",
                .data           = &ipv4_config.no_pmtu_disc,
                .maxlen         = sizeof(int),
@@ -240,7 +163,6 @@ static struct ctl_table ipv4_table[] = {
                .proc_handler   = proc_dointvec
        },
        {
-               .ctl_name       = NET_IPV4_NONLOCAL_BIND,
                .procname       = "ip_nonlocal_bind",
                .data           = &sysctl_ip_nonlocal_bind,
                .maxlen         = sizeof(int),
@@ -248,7 +170,6 @@ static struct ctl_table ipv4_table[] = {
                .proc_handler   = proc_dointvec
        },
        {
-               .ctl_name       = NET_IPV4_TCP_SYN_RETRIES,
                .procname       = "tcp_syn_retries",
                .data           = &sysctl_tcp_syn_retries,
                .maxlen         = sizeof(int),
@@ -256,7 +177,6 @@ static struct ctl_table ipv4_table[] = {
                .proc_handler   = proc_dointvec
        },
        {
-               .ctl_name       = NET_TCP_SYNACK_RETRIES,
                .procname       = "tcp_synack_retries",
                .data           = &sysctl_tcp_synack_retries,
                .maxlen         = sizeof(int),
@@ -264,7 +184,6 @@ static struct ctl_table ipv4_table[] = {
                .proc_handler   = proc_dointvec
        },
        {
-               .ctl_name       = NET_TCP_MAX_ORPHANS,
                .procname       = "tcp_max_orphans",
                .data           = &sysctl_tcp_max_orphans,
                .maxlen         = sizeof(int),
@@ -272,7 +191,6 @@ static struct ctl_table ipv4_table[] = {
                .proc_handler   = proc_dointvec
        },
        {
-               .ctl_name       = NET_TCP_MAX_TW_BUCKETS,
                .procname       = "tcp_max_tw_buckets",
                .data           = &tcp_death_row.sysctl_max_tw_buckets,
                .maxlen         = sizeof(int),
@@ -280,7 +198,6 @@ static struct ctl_table ipv4_table[] = {
                .proc_handler   = proc_dointvec
        },
        {
-               .ctl_name       = NET_IPV4_DYNADDR,
                .procname       = "ip_dynaddr",
                .data           = &sysctl_ip_dynaddr,
                .maxlen         = sizeof(int),
@@ -288,16 +205,13 @@ static struct ctl_table ipv4_table[] = {
                .proc_handler   = proc_dointvec
        },
        {
-               .ctl_name       = NET_IPV4_TCP_KEEPALIVE_TIME,
                .procname       = "tcp_keepalive_time",
                .data           = &sysctl_tcp_keepalive_time,
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_jiffies,
-               .strategy       = sysctl_jiffies
        },
        {
-               .ctl_name       = NET_IPV4_TCP_KEEPALIVE_PROBES,
                .procname       = "tcp_keepalive_probes",
                .data           = &sysctl_tcp_keepalive_probes,
                .maxlen         = sizeof(int),
@@ -305,26 +219,21 @@ static struct ctl_table ipv4_table[] = {
                .proc_handler   = proc_dointvec
        },
        {
-               .ctl_name       = NET_IPV4_TCP_KEEPALIVE_INTVL,
                .procname       = "tcp_keepalive_intvl",
                .data           = &sysctl_tcp_keepalive_intvl,
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_jiffies,
-               .strategy       = sysctl_jiffies
        },
        {
-               .ctl_name       = NET_IPV4_TCP_RETRIES1,
                .procname       = "tcp_retries1",
                .data           = &sysctl_tcp_retries1,
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .strategy       = sysctl_intvec,
                .extra2         = &tcp_retr1_max
        },
        {
-               .ctl_name       = NET_IPV4_TCP_RETRIES2,
                .procname       = "tcp_retries2",
                .data           = &sysctl_tcp_retries2,
                .maxlen         = sizeof(int),
@@ -332,17 +241,14 @@ static struct ctl_table ipv4_table[] = {
                .proc_handler   = proc_dointvec
        },
        {
-               .ctl_name       = NET_IPV4_TCP_FIN_TIMEOUT,
                .procname       = "tcp_fin_timeout",
                .data           = &sysctl_tcp_fin_timeout,
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_jiffies,
-               .strategy       = sysctl_jiffies
        },
 #ifdef CONFIG_SYN_COOKIES
        {
-               .ctl_name       = NET_TCP_SYNCOOKIES,
                .procname       = "tcp_syncookies",
                .data           = &sysctl_tcp_syncookies,
                .maxlen         = sizeof(int),
@@ -351,7 +257,6 @@ static struct ctl_table ipv4_table[] = {
        },
 #endif
        {
-               .ctl_name       = NET_TCP_TW_RECYCLE,
                .procname       = "tcp_tw_recycle",
                .data           = &tcp_death_row.sysctl_tw_recycle,
                .maxlen         = sizeof(int),
@@ -359,7 +264,6 @@ static struct ctl_table ipv4_table[] = {
                .proc_handler   = proc_dointvec
        },
        {
-               .ctl_name       = NET_TCP_ABORT_ON_OVERFLOW,
                .procname       = "tcp_abort_on_overflow",
                .data           = &sysctl_tcp_abort_on_overflow,
                .maxlen         = sizeof(int),
@@ -367,7 +271,6 @@ static struct ctl_table ipv4_table[] = {
                .proc_handler   = proc_dointvec
        },
        {
-               .ctl_name       = NET_TCP_STDURG,
                .procname       = "tcp_stdurg",
                .data           = &sysctl_tcp_stdurg,
                .maxlen         = sizeof(int),
@@ -375,7 +278,6 @@ static struct ctl_table ipv4_table[] = {
                .proc_handler   = proc_dointvec
        },
        {
-               .ctl_name       = NET_TCP_RFC1337,
                .procname       = "tcp_rfc1337",
                .data           = &sysctl_tcp_rfc1337,
                .maxlen         = sizeof(int),
@@ -383,7 +285,6 @@ static struct ctl_table ipv4_table[] = {
                .proc_handler   = proc_dointvec
        },
        {
-               .ctl_name       = NET_TCP_MAX_SYN_BACKLOG,
                .procname       = "tcp_max_syn_backlog",
                .data           = &sysctl_max_syn_backlog,
                .maxlen         = sizeof(int),
@@ -391,17 +292,14 @@ static struct ctl_table ipv4_table[] = {
                .proc_handler   = proc_dointvec
        },
        {
-               .ctl_name       = NET_IPV4_LOCAL_PORT_RANGE,
                .procname       = "ip_local_port_range",
                .data           = &sysctl_local_ports.range,
                .maxlen         = sizeof(sysctl_local_ports.range),
                .mode           = 0644,
                .proc_handler   = ipv4_local_port_range,
-               .strategy       = ipv4_sysctl_local_port_range,
        },
 #ifdef CONFIG_IP_MULTICAST
        {
-               .ctl_name       = NET_IPV4_IGMP_MAX_MEMBERSHIPS,
                .procname       = "igmp_max_memberships",
                .data           = &sysctl_igmp_max_memberships,
                .maxlen         = sizeof(int),
@@ -411,7 +309,6 @@ static struct ctl_table ipv4_table[] = {
 
 #endif
        {
-               .ctl_name       = NET_IPV4_IGMP_MAX_MSF,
                .procname       = "igmp_max_msf",
                .data           = &sysctl_igmp_max_msf,
                .maxlen         = sizeof(int),
@@ -419,7 +316,6 @@ static struct ctl_table ipv4_table[] = {
                .proc_handler   = proc_dointvec
        },
        {
-               .ctl_name       = NET_IPV4_INET_PEER_THRESHOLD,
                .procname       = "inet_peer_threshold",
                .data           = &inet_peer_threshold,
                .maxlen         = sizeof(int),
@@ -427,43 +323,34 @@ static struct ctl_table ipv4_table[] = {
                .proc_handler   = proc_dointvec
        },
        {
-               .ctl_name       = NET_IPV4_INET_PEER_MINTTL,
                .procname       = "inet_peer_minttl",
                .data           = &inet_peer_minttl,
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_jiffies,
-               .strategy       = sysctl_jiffies
        },
        {
-               .ctl_name       = NET_IPV4_INET_PEER_MAXTTL,
                .procname       = "inet_peer_maxttl",
                .data           = &inet_peer_maxttl,
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_jiffies,
-               .strategy       = sysctl_jiffies
        },
        {
-               .ctl_name       = NET_IPV4_INET_PEER_GC_MINTIME,
                .procname       = "inet_peer_gc_mintime",
                .data           = &inet_peer_gc_mintime,
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_jiffies,
-               .strategy       = sysctl_jiffies
        },
        {
-               .ctl_name       = NET_IPV4_INET_PEER_GC_MAXTIME,
                .procname       = "inet_peer_gc_maxtime",
                .data           = &inet_peer_gc_maxtime,
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_jiffies,
-               .strategy       = sysctl_jiffies
        },
        {
-               .ctl_name       = NET_TCP_ORPHAN_RETRIES,
                .procname       = "tcp_orphan_retries",
                .data           = &sysctl_tcp_orphan_retries,
                .maxlen         = sizeof(int),
@@ -471,7 +358,6 @@ static struct ctl_table ipv4_table[] = {
                .proc_handler   = proc_dointvec
        },
        {
-               .ctl_name       = NET_TCP_FACK,
                .procname       = "tcp_fack",
                .data           = &sysctl_tcp_fack,
                .maxlen         = sizeof(int),
@@ -479,7 +365,6 @@ static struct ctl_table ipv4_table[] = {
                .proc_handler   = proc_dointvec
        },
        {
-               .ctl_name       = NET_TCP_REORDERING,
                .procname       = "tcp_reordering",
                .data           = &sysctl_tcp_reordering,
                .maxlen         = sizeof(int),
@@ -487,7 +372,6 @@ static struct ctl_table ipv4_table[] = {
                .proc_handler   = proc_dointvec
        },
        {
-               .ctl_name       = NET_TCP_ECN,
                .procname       = "tcp_ecn",
                .data           = &sysctl_tcp_ecn,
                .maxlen         = sizeof(int),
@@ -495,7 +379,6 @@ static struct ctl_table ipv4_table[] = {
                .proc_handler   = proc_dointvec
        },
        {
-               .ctl_name       = NET_TCP_DSACK,
                .procname       = "tcp_dsack",
                .data           = &sysctl_tcp_dsack,
                .maxlen         = sizeof(int),
@@ -503,7 +386,6 @@ static struct ctl_table ipv4_table[] = {
                .proc_handler   = proc_dointvec
        },
        {
-               .ctl_name       = NET_TCP_MEM,
                .procname       = "tcp_mem",
                .data           = &sysctl_tcp_mem,
                .maxlen         = sizeof(sysctl_tcp_mem),
@@ -511,7 +393,6 @@ static struct ctl_table ipv4_table[] = {
                .proc_handler   = proc_dointvec
        },
        {
-               .ctl_name       = NET_TCP_WMEM,
                .procname       = "tcp_wmem",
                .data           = &sysctl_tcp_wmem,
                .maxlen         = sizeof(sysctl_tcp_wmem),
@@ -519,7 +400,6 @@ static struct ctl_table ipv4_table[] = {
                .proc_handler   = proc_dointvec
        },
        {
-               .ctl_name       = NET_TCP_RMEM,
                .procname       = "tcp_rmem",
                .data           = &sysctl_tcp_rmem,
                .maxlen         = sizeof(sysctl_tcp_rmem),
@@ -527,7 +407,6 @@ static struct ctl_table ipv4_table[] = {
                .proc_handler   = proc_dointvec
        },
        {
-               .ctl_name       = NET_TCP_APP_WIN,
                .procname       = "tcp_app_win",
                .data           = &sysctl_tcp_app_win,
                .maxlen         = sizeof(int),
@@ -535,7 +414,6 @@ static struct ctl_table ipv4_table[] = {
                .proc_handler   = proc_dointvec
        },
        {
-               .ctl_name       = NET_TCP_ADV_WIN_SCALE,
                .procname       = "tcp_adv_win_scale",
                .data           = &sysctl_tcp_adv_win_scale,
                .maxlen         = sizeof(int),
@@ -543,7 +421,6 @@ static struct ctl_table ipv4_table[] = {
                .proc_handler   = proc_dointvec
        },
        {
-               .ctl_name       = NET_TCP_TW_REUSE,
                .procname       = "tcp_tw_reuse",
                .data           = &sysctl_tcp_tw_reuse,
                .maxlen         = sizeof(int),
@@ -551,7 +428,6 @@ static struct ctl_table ipv4_table[] = {
                .proc_handler   = proc_dointvec
        },
        {
-               .ctl_name       = NET_TCP_FRTO,
                .procname       = "tcp_frto",
                .data           = &sysctl_tcp_frto,
                .maxlen         = sizeof(int),
@@ -559,7 +435,6 @@ static struct ctl_table ipv4_table[] = {
                .proc_handler   = proc_dointvec
        },
        {
-               .ctl_name       = NET_TCP_FRTO_RESPONSE,
                .procname       = "tcp_frto_response",
                .data           = &sysctl_tcp_frto_response,
                .maxlen         = sizeof(int),
@@ -567,7 +442,6 @@ static struct ctl_table ipv4_table[] = {
                .proc_handler   = proc_dointvec
        },
        {
-               .ctl_name       = NET_TCP_LOW_LATENCY,
                .procname       = "tcp_low_latency",
                .data           = &sysctl_tcp_low_latency,
                .maxlen         = sizeof(int),
@@ -575,7 +449,6 @@ static struct ctl_table ipv4_table[] = {
                .proc_handler   = proc_dointvec
        },
        {
-               .ctl_name       = NET_TCP_NO_METRICS_SAVE,
                .procname       = "tcp_no_metrics_save",
                .data           = &sysctl_tcp_nometrics_save,
                .maxlen         = sizeof(int),
@@ -583,7 +456,6 @@ static struct ctl_table ipv4_table[] = {
                .proc_handler   = proc_dointvec,
        },
        {
-               .ctl_name       = NET_TCP_MODERATE_RCVBUF,
                .procname       = "tcp_moderate_rcvbuf",
                .data           = &sysctl_tcp_moderate_rcvbuf,
                .maxlen         = sizeof(int),
@@ -591,7 +463,6 @@ static struct ctl_table ipv4_table[] = {
                .proc_handler   = proc_dointvec,
        },
        {
-               .ctl_name       = NET_TCP_TSO_WIN_DIVISOR,
                .procname       = "tcp_tso_win_divisor",
                .data           = &sysctl_tcp_tso_win_divisor,
                .maxlen         = sizeof(int),
@@ -599,15 +470,12 @@ static struct ctl_table ipv4_table[] = {
                .proc_handler   = proc_dointvec,
        },
        {
-               .ctl_name       = NET_TCP_CONG_CONTROL,
                .procname       = "tcp_congestion_control",
                .mode           = 0644,
                .maxlen         = TCP_CA_NAME_MAX,
                .proc_handler   = proc_tcp_congestion_control,
-               .strategy       = sysctl_tcp_congestion_control,
        },
        {
-               .ctl_name       = NET_TCP_ABC,
                .procname       = "tcp_abc",
                .data           = &sysctl_tcp_abc,
                .maxlen         = sizeof(int),
@@ -615,7 +483,6 @@ static struct ctl_table ipv4_table[] = {
                .proc_handler   = proc_dointvec,
        },
        {
-               .ctl_name       = NET_TCP_MTU_PROBING,
                .procname       = "tcp_mtu_probing",
                .data           = &sysctl_tcp_mtu_probing,
                .maxlen         = sizeof(int),
@@ -623,7 +490,6 @@ static struct ctl_table ipv4_table[] = {
                .proc_handler   = proc_dointvec,
        },
        {
-               .ctl_name       = NET_TCP_BASE_MSS,
                .procname       = "tcp_base_mss",
                .data           = &sysctl_tcp_base_mss,
                .maxlen         = sizeof(int),
@@ -631,7 +497,6 @@ static struct ctl_table ipv4_table[] = {
                .proc_handler   = proc_dointvec,
        },
        {
-               .ctl_name       = NET_IPV4_TCP_WORKAROUND_SIGNED_WINDOWS,
                .procname       = "tcp_workaround_signed_windows",
                .data           = &sysctl_tcp_workaround_signed_windows,
                .maxlen         = sizeof(int),
@@ -640,7 +505,6 @@ static struct ctl_table ipv4_table[] = {
        },
 #ifdef CONFIG_NET_DMA
        {
-               .ctl_name       = NET_TCP_DMA_COPYBREAK,
                .procname       = "tcp_dma_copybreak",
                .data           = &sysctl_tcp_dma_copybreak,
                .maxlen         = sizeof(int),
@@ -649,7 +513,6 @@ static struct ctl_table ipv4_table[] = {
        },
 #endif
        {
-               .ctl_name       = NET_TCP_SLOW_START_AFTER_IDLE,
                .procname       = "tcp_slow_start_after_idle",
                .data           = &sysctl_tcp_slow_start_after_idle,
                .maxlen         = sizeof(int),
@@ -658,7 +521,6 @@ static struct ctl_table ipv4_table[] = {
        },
 #ifdef CONFIG_NETLABEL
        {
-               .ctl_name       = NET_CIPSOV4_CACHE_ENABLE,
                .procname       = "cipso_cache_enable",
                .data           = &cipso_v4_cache_enabled,
                .maxlen         = sizeof(int),
@@ -666,7 +528,6 @@ static struct ctl_table ipv4_table[] = {
                .proc_handler   = proc_dointvec,
        },
        {
-               .ctl_name       = NET_CIPSOV4_CACHE_BUCKET_SIZE,
                .procname       = "cipso_cache_bucket_size",
                .data           = &cipso_v4_cache_bucketsize,
                .maxlen         = sizeof(int),
@@ -674,7 +535,6 @@ static struct ctl_table ipv4_table[] = {
                .proc_handler   = proc_dointvec,
        },
        {
-               .ctl_name       = NET_CIPSOV4_RBM_OPTFMT,
                .procname       = "cipso_rbm_optfmt",
                .data           = &cipso_v4_rbm_optfmt,
                .maxlen         = sizeof(int),
@@ -682,7 +542,6 @@ static struct ctl_table ipv4_table[] = {
                .proc_handler   = proc_dointvec,
        },
        {
-               .ctl_name       = NET_CIPSOV4_RBM_STRICTVALID,
                .procname       = "cipso_rbm_strictvalid",
                .data           = &cipso_v4_rbm_strictvalid,
                .maxlen         = sizeof(int),
@@ -697,15 +556,12 @@ static struct ctl_table ipv4_table[] = {
                .proc_handler   = proc_tcp_available_congestion_control,
        },
        {
-               .ctl_name       = NET_TCP_ALLOWED_CONG_CONTROL,
                .procname       = "tcp_allowed_congestion_control",
                .maxlen         = TCP_CA_BUF_MAX,
                .mode           = 0644,
                .proc_handler   = proc_allowed_congestion_control,
-               .strategy       = strategy_allowed_congestion_control,
        },
        {
-               .ctl_name       = NET_TCP_MAX_SSTHRESH,
                .procname       = "tcp_max_ssthresh",
                .data           = &sysctl_tcp_max_ssthresh,
                .maxlen         = sizeof(int),
@@ -713,7 +569,6 @@ static struct ctl_table ipv4_table[] = {
                .proc_handler   = proc_dointvec,
        },
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "tcp_cookie_size",
                .data           = &sysctl_tcp_cookie_size,
                .maxlen         = sizeof(int),
@@ -721,41 +576,34 @@ static struct ctl_table ipv4_table[] = {
                .proc_handler   = proc_dointvec
        },
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "udp_mem",
                .data           = &sysctl_udp_mem,
                .maxlen         = sizeof(sysctl_udp_mem),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .strategy       = sysctl_intvec,
                .extra1         = &zero
        },
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "udp_rmem_min",
                .data           = &sysctl_udp_rmem_min,
                .maxlen         = sizeof(sysctl_udp_rmem_min),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .strategy       = sysctl_intvec,
                .extra1         = &zero
        },
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "udp_wmem_min",
                .data           = &sysctl_udp_wmem_min,
                .maxlen         = sizeof(sysctl_udp_wmem_min),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .strategy       = sysctl_intvec,
                .extra1         = &zero
        },
-       { .ctl_name = 0 }
+       { }
 };
 
 static struct ctl_table ipv4_net_table[] = {
        {
-               .ctl_name       = NET_IPV4_ICMP_ECHO_IGNORE_ALL,
                .procname       = "icmp_echo_ignore_all",
                .data           = &init_net.ipv4.sysctl_icmp_echo_ignore_all,
                .maxlen         = sizeof(int),
@@ -763,7 +611,6 @@ static struct ctl_table ipv4_net_table[] = {
                .proc_handler   = proc_dointvec
        },
        {
-               .ctl_name       = NET_IPV4_ICMP_ECHO_IGNORE_BROADCASTS,
                .procname       = "icmp_echo_ignore_broadcasts",
                .data           = &init_net.ipv4.sysctl_icmp_echo_ignore_broadcasts,
                .maxlen         = sizeof(int),
@@ -771,7 +618,6 @@ static struct ctl_table ipv4_net_table[] = {
                .proc_handler   = proc_dointvec
        },
        {
-               .ctl_name       = NET_IPV4_ICMP_IGNORE_BOGUS_ERROR_RESPONSES,
                .procname       = "icmp_ignore_bogus_error_responses",
                .data           = &init_net.ipv4.sysctl_icmp_ignore_bogus_error_responses,
                .maxlen         = sizeof(int),
@@ -779,7 +625,6 @@ static struct ctl_table ipv4_net_table[] = {
                .proc_handler   = proc_dointvec
        },
        {
-               .ctl_name       = NET_IPV4_ICMP_ERRORS_USE_INBOUND_IFADDR,
                .procname       = "icmp_errors_use_inbound_ifaddr",
                .data           = &init_net.ipv4.sysctl_icmp_errors_use_inbound_ifaddr,
                .maxlen         = sizeof(int),
@@ -787,16 +632,13 @@ static struct ctl_table ipv4_net_table[] = {
                .proc_handler   = proc_dointvec
        },
        {
-               .ctl_name       = NET_IPV4_ICMP_RATELIMIT,
                .procname       = "icmp_ratelimit",
                .data           = &init_net.ipv4.sysctl_icmp_ratelimit,
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_ms_jiffies,
-               .strategy       = sysctl_ms_jiffies
        },
        {
-               .ctl_name       = NET_IPV4_ICMP_RATEMASK,
                .procname       = "icmp_ratemask",
                .data           = &init_net.ipv4.sysctl_icmp_ratemask,
                .maxlen         = sizeof(int),
@@ -804,7 +646,6 @@ static struct ctl_table ipv4_net_table[] = {
                .proc_handler   = proc_dointvec
        },
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "rt_cache_rebuild_count",
                .data           = &init_net.ipv4.sysctl_rt_cache_rebuild_count,
                .maxlen         = sizeof(int),
@@ -815,8 +656,8 @@ static struct ctl_table ipv4_net_table[] = {
 };
 
 struct ctl_path net_ipv4_ctl_path[] = {
-       { .procname = "net", .ctl_name = CTL_NET, },
-       { .procname = "ipv4", .ctl_name = NET_IPV4, },
+       { .procname = "net", },
+       { .procname = "ipv4", },
        { },
 };
 EXPORT_SYMBOL_GPL(net_ipv4_ctl_path);
index 74fb2eb..8c08a28 100644 (file)
@@ -267,7 +267,6 @@ static struct xfrm_policy_afinfo xfrm4_policy_afinfo = {
 #ifdef CONFIG_SYSCTL
 static struct ctl_table xfrm4_policy_table[] = {
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "xfrm4_gc_thresh",
                .data           = &xfrm4_dst_ops.gc_thresh,
                .maxlen         = sizeof(int),
index b1ce8fc..de7a194 100644 (file)
@@ -4037,41 +4037,6 @@ int addrconf_sysctl_forward(ctl_table *ctl, int write,
        return ret;
 }
 
-static int addrconf_sysctl_forward_strategy(ctl_table *table,
-                                           void __user *oldval,
-                                           size_t __user *oldlenp,
-                                           void __user *newval, size_t newlen)
-{
-       int *valp = table->data;
-       int val = *valp;
-       int new;
-
-       if (!newval || !newlen)
-               return 0;
-       if (newlen != sizeof(int))
-               return -EINVAL;
-       if (get_user(new, (int __user *)newval))
-               return -EFAULT;
-       if (new == *valp)
-               return 0;
-       if (oldval && oldlenp) {
-               size_t len;
-               if (get_user(len, oldlenp))
-                       return -EFAULT;
-               if (len) {
-                       if (len > table->maxlen)
-                               len = table->maxlen;
-                       if (copy_to_user(oldval, valp, len))
-                               return -EFAULT;
-                       if (put_user(len, oldlenp))
-                               return -EFAULT;
-               }
-       }
-
-       *valp = new;
-       return addrconf_fixup_forwarding(table, valp, val);
-}
-
 static void dev_disable_change(struct inet6_dev *idev)
 {
        if (!idev || !idev->dev)
@@ -4148,16 +4113,13 @@ static struct addrconf_sysctl_table
        .sysctl_header = NULL,
        .addrconf_vars = {
                {
-                       .ctl_name       =       NET_IPV6_FORWARDING,
                        .procname       =       "forwarding",
                        .data           =       &ipv6_devconf.forwarding,
                        .maxlen         =       sizeof(int),
                        .mode           =       0644,
                        .proc_handler   =       addrconf_sysctl_forward,
-                       .strategy       =       addrconf_sysctl_forward_strategy,
                },
                {
-                       .ctl_name       =       NET_IPV6_HOP_LIMIT,
                        .procname       =       "hop_limit",
                        .data           =       &ipv6_devconf.hop_limit,
                        .maxlen         =       sizeof(int),
@@ -4165,7 +4127,6 @@ static struct addrconf_sysctl_table
                        .proc_handler   =       proc_dointvec,
                },
                {
-                       .ctl_name       =       NET_IPV6_MTU,
                        .procname       =       "mtu",
                        .data           =       &ipv6_devconf.mtu6,
                        .maxlen         =       sizeof(int),
@@ -4173,7 +4134,6 @@ static struct addrconf_sysctl_table
                        .proc_handler   =       proc_dointvec,
                },
                {
-                       .ctl_name       =       NET_IPV6_ACCEPT_RA,
                        .procname       =       "accept_ra",
                        .data           =       &ipv6_devconf.accept_ra,
                        .maxlen         =       sizeof(int),
@@ -4181,7 +4141,6 @@ static struct addrconf_sysctl_table
                        .proc_handler   =       proc_dointvec,
                },
                {
-                       .ctl_name       =       NET_IPV6_ACCEPT_REDIRECTS,
                        .procname       =       "accept_redirects",
                        .data           =       &ipv6_devconf.accept_redirects,
                        .maxlen         =       sizeof(int),
@@ -4189,7 +4148,6 @@ static struct addrconf_sysctl_table
                        .proc_handler   =       proc_dointvec,
                },
                {
-                       .ctl_name       =       NET_IPV6_AUTOCONF,
                        .procname       =       "autoconf",
                        .data           =       &ipv6_devconf.autoconf,
                        .maxlen         =       sizeof(int),
@@ -4197,7 +4155,6 @@ static struct addrconf_sysctl_table
                        .proc_handler   =       proc_dointvec,
                },
                {
-                       .ctl_name       =       NET_IPV6_DAD_TRANSMITS,
                        .procname       =       "dad_transmits",
                        .data           =       &ipv6_devconf.dad_transmits,
                        .maxlen         =       sizeof(int),
@@ -4205,7 +4162,6 @@ static struct addrconf_sysctl_table
                        .proc_handler   =       proc_dointvec,
                },
                {
-                       .ctl_name       =       NET_IPV6_RTR_SOLICITS,
                        .procname       =       "router_solicitations",
                        .data           =       &ipv6_devconf.rtr_solicits,
                        .maxlen         =       sizeof(int),
@@ -4213,25 +4169,20 @@ static struct addrconf_sysctl_table
                        .proc_handler   =       proc_dointvec,
                },
                {
-                       .ctl_name       =       NET_IPV6_RTR_SOLICIT_INTERVAL,
                        .procname       =       "router_solicitation_interval",
                        .data           =       &ipv6_devconf.rtr_solicit_interval,
                        .maxlen         =       sizeof(int),
                        .mode           =       0644,
                        .proc_handler   =       proc_dointvec_jiffies,
-                       .strategy       =       sysctl_jiffies,
                },
                {
-                       .ctl_name       =       NET_IPV6_RTR_SOLICIT_DELAY,
                        .procname       =       "router_solicitation_delay",
                        .data           =       &ipv6_devconf.rtr_solicit_delay,
                        .maxlen         =       sizeof(int),
                        .mode           =       0644,
                        .proc_handler   =       proc_dointvec_jiffies,
-                       .strategy       =       sysctl_jiffies,
                },
                {
-                       .ctl_name       =       NET_IPV6_FORCE_MLD_VERSION,
                        .procname       =       "force_mld_version",
                        .data           =       &ipv6_devconf.force_mld_version,
                        .maxlen         =       sizeof(int),
@@ -4240,7 +4191,6 @@ static struct addrconf_sysctl_table
                },
 #ifdef CONFIG_IPV6_PRIVACY
                {
-                       .ctl_name       =       NET_IPV6_USE_TEMPADDR,
                        .procname       =       "use_tempaddr",
                        .data           =       &ipv6_devconf.use_tempaddr,
                        .maxlen         =       sizeof(int),
@@ -4248,7 +4198,6 @@ static struct addrconf_sysctl_table
                        .proc_handler   =       proc_dointvec,
                },
                {
-                       .ctl_name       =       NET_IPV6_TEMP_VALID_LFT,
                        .procname       =       "temp_valid_lft",
                        .data           =       &ipv6_devconf.temp_valid_lft,
                        .maxlen         =       sizeof(int),
@@ -4256,7 +4205,6 @@ static struct addrconf_sysctl_table
                        .proc_handler   =       proc_dointvec,
                },
                {
-                       .ctl_name       =       NET_IPV6_TEMP_PREFERED_LFT,
                        .procname       =       "temp_prefered_lft",
                        .data           =       &ipv6_devconf.temp_prefered_lft,
                        .maxlen         =       sizeof(int),
@@ -4264,7 +4212,6 @@ static struct addrconf_sysctl_table
                        .proc_handler   =       proc_dointvec,
                },
                {
-                       .ctl_name       =       NET_IPV6_REGEN_MAX_RETRY,
                        .procname       =       "regen_max_retry",
                        .data           =       &ipv6_devconf.regen_max_retry,
                        .maxlen         =       sizeof(int),
@@ -4272,7 +4219,6 @@ static struct addrconf_sysctl_table
                        .proc_handler   =       proc_dointvec,
                },
                {
-                       .ctl_name       =       NET_IPV6_MAX_DESYNC_FACTOR,
                        .procname       =       "max_desync_factor",
                        .data           =       &ipv6_devconf.max_desync_factor,
                        .maxlen         =       sizeof(int),
@@ -4281,7 +4227,6 @@ static struct addrconf_sysctl_table
                },
 #endif
                {
-                       .ctl_name       =       NET_IPV6_MAX_ADDRESSES,
                        .procname       =       "max_addresses",
                        .data           =       &ipv6_devconf.max_addresses,
                        .maxlen         =       sizeof(int),
@@ -4289,7 +4234,6 @@ static struct addrconf_sysctl_table
                        .proc_handler   =       proc_dointvec,
                },
                {
-                       .ctl_name       =       NET_IPV6_ACCEPT_RA_DEFRTR,
                        .procname       =       "accept_ra_defrtr",
                        .data           =       &ipv6_devconf.accept_ra_defrtr,
                        .maxlen         =       sizeof(int),
@@ -4297,7 +4241,6 @@ static struct addrconf_sysctl_table
                        .proc_handler   =       proc_dointvec,
                },
                {
-                       .ctl_name       =       NET_IPV6_ACCEPT_RA_PINFO,
                        .procname       =       "accept_ra_pinfo",
                        .data           =       &ipv6_devconf.accept_ra_pinfo,
                        .maxlen         =       sizeof(int),
@@ -4306,7 +4249,6 @@ static struct addrconf_sysctl_table
                },
 #ifdef CONFIG_IPV6_ROUTER_PREF
                {
-                       .ctl_name       =       NET_IPV6_ACCEPT_RA_RTR_PREF,
                        .procname       =       "accept_ra_rtr_pref",
                        .data           =       &ipv6_devconf.accept_ra_rtr_pref,
                        .maxlen         =       sizeof(int),
@@ -4314,17 +4256,14 @@ static struct addrconf_sysctl_table
                        .proc_handler   =       proc_dointvec,
                },
                {
-                       .ctl_name       =       NET_IPV6_RTR_PROBE_INTERVAL,
                        .procname       =       "router_probe_interval",
                        .data           =       &ipv6_devconf.rtr_probe_interval,
                        .maxlen         =       sizeof(int),
                        .mode           =       0644,
                        .proc_handler   =       proc_dointvec_jiffies,
-                       .strategy       =       sysctl_jiffies,
                },
 #ifdef CONFIG_IPV6_ROUTE_INFO
                {
-                       .ctl_name       =       NET_IPV6_ACCEPT_RA_RT_INFO_MAX_PLEN,
                        .procname       =       "accept_ra_rt_info_max_plen",
                        .data           =       &ipv6_devconf.accept_ra_rt_info_max_plen,
                        .maxlen         =       sizeof(int),
@@ -4334,7 +4273,6 @@ static struct addrconf_sysctl_table
 #endif
 #endif
                {
-                       .ctl_name       =       NET_IPV6_PROXY_NDP,
                        .procname       =       "proxy_ndp",
                        .data           =       &ipv6_devconf.proxy_ndp,
                        .maxlen         =       sizeof(int),
@@ -4342,7 +4280,6 @@ static struct addrconf_sysctl_table
                        .proc_handler   =       proc_dointvec,
                },
                {
-                       .ctl_name       =       NET_IPV6_ACCEPT_SOURCE_ROUTE,
                        .procname       =       "accept_source_route",
                        .data           =       &ipv6_devconf.accept_source_route,
                        .maxlen         =       sizeof(int),
@@ -4351,7 +4288,6 @@ static struct addrconf_sysctl_table
                },
 #ifdef CONFIG_IPV6_OPTIMISTIC_DAD
                {
-                       .ctl_name       =       CTL_UNNUMBERED,
                        .procname       =       "optimistic_dad",
                        .data           =       &ipv6_devconf.optimistic_dad,
                        .maxlen         =       sizeof(int),
@@ -4362,7 +4298,6 @@ static struct addrconf_sysctl_table
 #endif
 #ifdef CONFIG_IPV6_MROUTE
                {
-                       .ctl_name       =       CTL_UNNUMBERED,
                        .procname       =       "mc_forwarding",
                        .data           =       &ipv6_devconf.mc_forwarding,
                        .maxlen         =       sizeof(int),
@@ -4371,16 +4306,13 @@ static struct addrconf_sysctl_table
                },
 #endif
                {
-                       .ctl_name       =       CTL_UNNUMBERED,
                        .procname       =       "disable_ipv6",
                        .data           =       &ipv6_devconf.disable_ipv6,
                        .maxlen         =       sizeof(int),
                        .mode           =       0644,
                        .proc_handler   =       addrconf_sysctl_disable,
-                       .strategy       =       sysctl_intvec,
                },
                {
-                       .ctl_name       =       CTL_UNNUMBERED,
                        .procname       =       "accept_dad",
                        .data           =       &ipv6_devconf.accept_dad,
                        .maxlen         =       sizeof(int),
@@ -4388,7 +4320,6 @@ static struct addrconf_sysctl_table
                        .proc_handler   =       proc_dointvec,
                },
                {
-                       .ctl_name       = CTL_UNNUMBERED,
                        .procname       = "force_tllao",
                        .data           = &ipv6_devconf.force_tllao,
                        .maxlen         = sizeof(int),
@@ -4396,13 +4327,13 @@ static struct addrconf_sysctl_table
                        .proc_handler   = proc_dointvec
                },
                {
-                       .ctl_name       =       0,      /* sentinel */
+                       /* sentinel */
                }
        },
 };
 
 static int __addrconf_sysctl_register(struct net *net, char *dev_name,
-               int ctl_name, struct inet6_dev *idev, struct ipv6_devconf *p)
+               struct inet6_dev *idev, struct ipv6_devconf *p)
 {
        int i;
        struct addrconf_sysctl_table *t;
@@ -4410,9 +4341,9 @@ static int __addrconf_sysctl_register(struct net *net, char *dev_name,
 #define ADDRCONF_CTL_PATH_DEV  3
 
        struct ctl_path addrconf_ctl_path[] = {
-               { .procname = "net", .ctl_name = CTL_NET, },
-               { .procname = "ipv6", .ctl_name = NET_IPV6, },
-               { .procname = "conf", .ctl_name = NET_IPV6_CONF, },
+               { .procname = "net", },
+               { .procname = "ipv6", },
+               { .procname = "conf", },
                { /* to be set */ },
                { },
        };
@@ -4438,7 +4369,6 @@ static int __addrconf_sysctl_register(struct net *net, char *dev_name,
                goto free;
 
        addrconf_ctl_path[ADDRCONF_CTL_PATH_DEV].procname = t->dev_name;
-       addrconf_ctl_path[ADDRCONF_CTL_PATH_DEV].ctl_name = ctl_name;
 
        t->sysctl_header = register_net_sysctl_table(net, addrconf_ctl_path,
                        t->addrconf_vars);
@@ -4474,10 +4404,9 @@ static void addrconf_sysctl_register(struct inet6_dev *idev)
 {
        neigh_sysctl_register(idev->dev, idev->nd_parms, NET_IPV6,
                              NET_IPV6_NEIGH, "ipv6",
-                             &ndisc_ifinfo_sysctl_change,
-                             ndisc_ifinfo_sysctl_strategy);
+                             &ndisc_ifinfo_sysctl_change);
        __addrconf_sysctl_register(dev_net(idev->dev), idev->dev->name,
-                       idev->dev->ifindex, idev, &idev->cnf);
+                                       idev, &idev->cnf);
 }
 
 static void addrconf_sysctl_unregister(struct inet6_dev *idev)
@@ -4516,13 +4445,11 @@ static int addrconf_init_net(struct net *net)
        net->ipv6.devconf_dflt = dflt;
 
 #ifdef CONFIG_SYSCTL
-       err = __addrconf_sysctl_register(net, "all", NET_PROTO_CONF_ALL,
-                       NULL, all);
+       err = __addrconf_sysctl_register(net, "all", NULL, all);
        if (err < 0)
                goto err_reg_all;
 
-       err = __addrconf_sysctl_register(net, "default", NET_PROTO_CONF_DEFAULT,
-                       NULL, dflt);
+       err = __addrconf_sysctl_register(net, "default", NULL, dflt);
        if (err < 0)
                goto err_reg_dflt;
 #endif
index f23ebbe..4ae661b 100644 (file)
@@ -942,15 +942,13 @@ EXPORT_SYMBOL(icmpv6_err_convert);
 #ifdef CONFIG_SYSCTL
 ctl_table ipv6_icmp_table_template[] = {
        {
-               .ctl_name       = NET_IPV6_ICMP_RATELIMIT,
                .procname       = "ratelimit",
                .data           = &init_net.ipv6.sysctl.icmpv6_time,
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_ms_jiffies,
-               .strategy       = sysctl_ms_jiffies
        },
-       { .ctl_name = 0 },
+       { },
 };
 
 struct ctl_table *ipv6_icmp_sysctl_init(struct net *net)
index 3507cfe..c458527 100644 (file)
@@ -1769,42 +1769,6 @@ int ndisc_ifinfo_sysctl_change(struct ctl_table *ctl, int write, void __user *bu
        return ret;
 }
 
-int ndisc_ifinfo_sysctl_strategy(ctl_table *ctl,
-                                void __user *oldval, size_t __user *oldlenp,
-                                void __user *newval, size_t newlen)
-{
-       struct net_device *dev = ctl->extra1;
-       struct inet6_dev *idev;
-       int ret;
-
-       if (ctl->ctl_name == NET_NEIGH_RETRANS_TIME ||
-           ctl->ctl_name == NET_NEIGH_REACHABLE_TIME)
-               ndisc_warn_deprecated_sysctl(ctl, "procfs", dev ? dev->name : "default");
-
-       switch (ctl->ctl_name) {
-       case NET_NEIGH_REACHABLE_TIME:
-               ret = sysctl_jiffies(ctl, oldval, oldlenp, newval, newlen);
-               break;
-       case NET_NEIGH_RETRANS_TIME_MS:
-       case NET_NEIGH_REACHABLE_TIME_MS:
-                ret = sysctl_ms_jiffies(ctl, oldval, oldlenp, newval, newlen);
-                break;
-       default:
-               ret = 0;
-       }
-
-       if (newval && newlen && ret > 0 &&
-           dev && (idev = in6_dev_get(dev)) != NULL) {
-               if (ctl->ctl_name == NET_NEIGH_REACHABLE_TIME ||
-                   ctl->ctl_name == NET_NEIGH_REACHABLE_TIME_MS)
-                       idev->nd_parms->reachable_time = neigh_rand_reach_time(idev->nd_parms->base_reachable_time);
-               idev->tstamp = jiffies;
-               inet6_ifinfo_notify(RTM_NEWLINK, idev);
-               in6_dev_put(idev);
-       }
-
-       return ret;
-}
 
 #endif
 
@@ -1858,8 +1822,7 @@ int __init ndisc_init(void)
 #ifdef CONFIG_SYSCTL
        err = neigh_sysctl_register(NULL, &nd_tbl.parms, NET_IPV6,
                                    NET_IPV6_NEIGH, "ipv6",
-                                   &ndisc_ifinfo_sysctl_change,
-                                   &ndisc_ifinfo_sysctl_strategy);
+                                   &ndisc_ifinfo_sysctl_change);
        if (err)
                goto out_unregister_pernet;
 #endif
index db4d572..7854052 100644 (file)
@@ -36,7 +36,6 @@
 
 #define IPQ_QMAX_DEFAULT 1024
 #define IPQ_PROC_FS_NAME "ip6_queue"
-#define NET_IPQ_QMAX 2088
 #define NET_IPQ_QMAX_NAME "ip6_queue_maxlen"
 
 typedef int (*ipq_cmpfn)(struct nf_queue_entry *, unsigned long);
@@ -517,14 +516,13 @@ static struct ctl_table_header *ipq_sysctl_header;
 
 static ctl_table ipq_table[] = {
        {
-               .ctl_name       = NET_IPQ_QMAX,
                .procname       = NET_IPQ_QMAX_NAME,
                .data           = &queue_maxlen,
                .maxlen         = sizeof(queue_maxlen),
                .mode           = 0644,
                .proc_handler   = proc_dointvec
        },
-       { .ctl_name = 0 }
+       { }
 };
 #endif
 
index 0f3df45..c7b8bd1 100644 (file)
@@ -277,9 +277,7 @@ static struct ctl_table icmpv6_sysctl_table[] = {
                .mode           = 0644,
                .proc_handler   = proc_dointvec_jiffies,
        },
-       {
-               .ctl_name       = 0
-       }
+       { }
 };
 #endif /* CONFIG_SYSCTL */
 
index f3aba25..e0b9424 100644 (file)
@@ -83,7 +83,6 @@ struct ctl_table nf_ct_ipv6_sysctl_table[] = {
                .proc_handler   = proc_dointvec_jiffies,
        },
        {
-               .ctl_name       = NET_NF_CONNTRACK_FRAG6_LOW_THRESH,
                .procname       = "nf_conntrack_frag6_low_thresh",
                .data           = &nf_init_frags.low_thresh,
                .maxlen         = sizeof(unsigned int),
@@ -91,14 +90,13 @@ struct ctl_table nf_ct_ipv6_sysctl_table[] = {
                .proc_handler   = proc_dointvec,
        },
        {
-               .ctl_name       = NET_NF_CONNTRACK_FRAG6_HIGH_THRESH,
                .procname       = "nf_conntrack_frag6_high_thresh",
                .data           = &nf_init_frags.high_thresh,
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec,
        },
-       { .ctl_name = 0 }
+       { }
 };
 #endif
 
index 45efc39..4d98549 100644 (file)
@@ -635,7 +635,6 @@ static const struct inet6_protocol frag_protocol =
 #ifdef CONFIG_SYSCTL
 static struct ctl_table ip6_frags_ns_ctl_table[] = {
        {
-               .ctl_name       = NET_IPV6_IP6FRAG_HIGH_THRESH,
                .procname       = "ip6frag_high_thresh",
                .data           = &init_net.ipv6.frags.high_thresh,
                .maxlen         = sizeof(int),
@@ -643,7 +642,6 @@ static struct ctl_table ip6_frags_ns_ctl_table[] = {
                .proc_handler   = proc_dointvec
        },
        {
-               .ctl_name       = NET_IPV6_IP6FRAG_LOW_THRESH,
                .procname       = "ip6frag_low_thresh",
                .data           = &init_net.ipv6.frags.low_thresh,
                .maxlen         = sizeof(int),
@@ -651,26 +649,22 @@ static struct ctl_table ip6_frags_ns_ctl_table[] = {
                .proc_handler   = proc_dointvec
        },
        {
-               .ctl_name       = NET_IPV6_IP6FRAG_TIME,
                .procname       = "ip6frag_time",
                .data           = &init_net.ipv6.frags.timeout,
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_jiffies,
-               .strategy       = sysctl_jiffies,
        },
        { }
 };
 
 static struct ctl_table ip6_frags_ctl_table[] = {
        {
-               .ctl_name       = NET_IPV6_IP6FRAG_SECRET_INTERVAL,
                .procname       = "ip6frag_secret_interval",
                .data           = &ip6_frags.secret_interval,
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_jiffies,
-               .strategy       = sysctl_jiffies
        },
        { }
 };
index df9432a..db3b273 100644 (file)
@@ -2547,7 +2547,6 @@ ctl_table ipv6_route_table_template[] = {
                .proc_handler   =       ipv6_sysctl_rtcache_flush
        },
        {
-               .ctl_name       =       NET_IPV6_ROUTE_GC_THRESH,
                .procname       =       "gc_thresh",
                .data           =       &ip6_dst_ops_template.gc_thresh,
                .maxlen         =       sizeof(int),
@@ -2555,7 +2554,6 @@ ctl_table ipv6_route_table_template[] = {
                .proc_handler   =       proc_dointvec,
        },
        {
-               .ctl_name       =       NET_IPV6_ROUTE_MAX_SIZE,
                .procname       =       "max_size",
                .data           =       &init_net.ipv6.sysctl.ip6_rt_max_size,
                .maxlen         =       sizeof(int),
@@ -2563,69 +2561,55 @@ ctl_table ipv6_route_table_template[] = {
                .proc_handler   =       proc_dointvec,
        },
        {
-               .ctl_name       =       NET_IPV6_ROUTE_GC_MIN_INTERVAL,
                .procname       =       "gc_min_interval",
                .data           =       &init_net.ipv6.sysctl.ip6_rt_gc_min_interval,
                .maxlen         =       sizeof(int),
                .mode           =       0644,
                .proc_handler   =       proc_dointvec_jiffies,
-               .strategy       =       sysctl_jiffies,
        },
        {
-               .ctl_name       =       NET_IPV6_ROUTE_GC_TIMEOUT,
                .procname       =       "gc_timeout",
                .data           =       &init_net.ipv6.sysctl.ip6_rt_gc_timeout,
                .maxlen         =       sizeof(int),
                .mode           =       0644,
                .proc_handler   =       proc_dointvec_jiffies,
-               .strategy       =       sysctl_jiffies,
        },
        {
-               .ctl_name       =       NET_IPV6_ROUTE_GC_INTERVAL,
                .procname       =       "gc_interval",
                .data           =       &init_net.ipv6.sysctl.ip6_rt_gc_interval,
                .maxlen         =       sizeof(int),
                .mode           =       0644,
                .proc_handler   =       proc_dointvec_jiffies,
-               .strategy       =       sysctl_jiffies,
        },
        {
-               .ctl_name       =       NET_IPV6_ROUTE_GC_ELASTICITY,
                .procname       =       "gc_elasticity",
                .data           =       &init_net.ipv6.sysctl.ip6_rt_gc_elasticity,
                .maxlen         =       sizeof(int),
                .mode           =       0644,
                .proc_handler   =       proc_dointvec_jiffies,
-               .strategy       =       sysctl_jiffies,
        },
        {
-               .ctl_name       =       NET_IPV6_ROUTE_MTU_EXPIRES,
                .procname       =       "mtu_expires",
                .data           =       &init_net.ipv6.sysctl.ip6_rt_mtu_expires,
                .maxlen         =       sizeof(int),
                .mode           =       0644,
                .proc_handler   =       proc_dointvec_jiffies,
-               .strategy       =       sysctl_jiffies,
        },
        {
-               .ctl_name       =       NET_IPV6_ROUTE_MIN_ADVMSS,
                .procname       =       "min_adv_mss",
                .data           =       &init_net.ipv6.sysctl.ip6_rt_min_advmss,
                .maxlen         =       sizeof(int),
                .mode           =       0644,
                .proc_handler   =       proc_dointvec_jiffies,
-               .strategy       =       sysctl_jiffies,
        },
        {
-               .ctl_name       =       NET_IPV6_ROUTE_GC_MIN_INTERVAL_MS,
                .procname       =       "gc_min_interval_ms",
                .data           =       &init_net.ipv6.sysctl.ip6_rt_gc_min_interval,
                .maxlen         =       sizeof(int),
                .mode           =       0644,
                .proc_handler   =       proc_dointvec_ms_jiffies,
-               .strategy       =       sysctl_ms_jiffies,
        },
-       { .ctl_name = 0 }
+       { }
 };
 
 struct ctl_table *ipv6_route_sysctl_init(struct net *net)
index 0dc6a4e..c690736 100644 (file)
 
 static ctl_table ipv6_table_template[] = {
        {
-               .ctl_name       = NET_IPV6_ROUTE,
                .procname       = "route",
                .maxlen         = 0,
                .mode           = 0555,
                .child          = ipv6_route_table_template
        },
        {
-               .ctl_name       = NET_IPV6_ICMP,
                .procname       = "icmp",
                .maxlen         = 0,
                .mode           = 0555,
                .child          = ipv6_icmp_table_template
        },
        {
-               .ctl_name       = NET_IPV6_BINDV6ONLY,
                .procname       = "bindv6only",
                .data           = &init_net.ipv6.sysctl.bindv6only,
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec
        },
-       { .ctl_name = 0 }
+       { }
 };
 
 static ctl_table ipv6_rotable[] = {
        {
-               .ctl_name       = NET_IPV6_MLD_MAX_MSF,
                .procname       = "mld_max_msf",
                .data           = &sysctl_mld_max_msf,
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec
        },
-       { .ctl_name = 0 }
+       { }
 };
 
 struct ctl_path net_ipv6_ctl_path[] = {
-       { .procname = "net", .ctl_name = CTL_NET, },
-       { .procname = "ipv6", .ctl_name = NET_IPV6, },
+       { .procname = "net", },
+       { .procname = "ipv6", },
        { },
 };
 EXPORT_SYMBOL_GPL(net_ipv6_ctl_path);
index 8ec3d45..7254e3f 100644 (file)
@@ -309,7 +309,6 @@ static void xfrm6_policy_fini(void)
 #ifdef CONFIG_SYSCTL
 static struct ctl_table xfrm6_policy_table[] = {
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "xfrm6_gc_thresh",
                .data           = &xfrm6_dst_ops.gc_thresh,
                .maxlen         = sizeof(int),
index 633fcab..bd6dca0 100644 (file)
@@ -18,19 +18,18 @@ extern int sysctl_ipx_pprop_broadcasting;
 
 static struct ctl_table ipx_table[] = {
        {
-               .ctl_name       = NET_IPX_PPROP_BROADCASTING,
                .procname       = "ipx_pprop_broadcasting",
                .data           = &sysctl_ipx_pprop_broadcasting,
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec,
        },
-       { },
+       { },
 };
 
 static struct ctl_path ipx_path[] = {
-       { .procname = "net", .ctl_name = CTL_NET, },
-       { .procname = "ipx", .ctl_name = NET_IPX, },
+       { .procname = "net", },
+       { .procname = "ipx", },
        { }
 };
 
index 5c86567..d0b70da 100644 (file)
@@ -113,26 +113,21 @@ static int do_discovery(ctl_table *table, int write,
 /* One file */
 static ctl_table irda_table[] = {
        {
-               .ctl_name       = NET_IRDA_DISCOVERY,
                .procname       = "discovery",
                .data           = &sysctl_discovery,
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = do_discovery,
-               .strategy       = sysctl_intvec
        },
        {
-               .ctl_name       = NET_IRDA_DEVNAME,
                .procname       = "devname",
                .data           = sysctl_devname,
                .maxlen         = 65,
                .mode           = 0644,
                .proc_handler   = do_devname,
-               .strategy       = sysctl_string
        },
 #ifdef CONFIG_IRDA_DEBUG
        {
-               .ctl_name       = NET_IRDA_DEBUG,
                .procname       = "debug",
                .data           = &irda_debug,
                .maxlen         = sizeof(int),
@@ -142,7 +137,6 @@ static ctl_table irda_table[] = {
 #endif
 #ifdef CONFIG_IRDA_FAST_RR
        {
-               .ctl_name       = NET_IRDA_FAST_POLL,
                .procname       = "fast_poll_increase",
                .data           = &sysctl_fast_poll_increase,
                .maxlen         = sizeof(int),
@@ -151,18 +145,15 @@ static ctl_table irda_table[] = {
        },
 #endif
        {
-               .ctl_name       = NET_IRDA_DISCOVERY_SLOTS,
                .procname       = "discovery_slots",
                .data           = &sysctl_discovery_slots,
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .strategy       = sysctl_intvec,
                .extra1         = &min_discovery_slots,
                .extra2         = &max_discovery_slots
        },
        {
-               .ctl_name       = NET_IRDA_DISCOVERY_TIMEOUT,
                .procname       = "discovery_timeout",
                .data           = &sysctl_discovery_timeout,
                .maxlen         = sizeof(int),
@@ -170,99 +161,83 @@ static ctl_table irda_table[] = {
                .proc_handler   = proc_dointvec
        },
        {
-               .ctl_name       = NET_IRDA_SLOT_TIMEOUT,
                .procname       = "slot_timeout",
                .data           = &sysctl_slot_timeout,
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .strategy       = sysctl_intvec,
                .extra1         = &min_slot_timeout,
                .extra2         = &max_slot_timeout
        },
        {
-               .ctl_name       = NET_IRDA_MAX_BAUD_RATE,
                .procname       = "max_baud_rate",
                .data           = &sysctl_max_baud_rate,
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .strategy       = sysctl_intvec,
                .extra1         = &min_max_baud_rate,
                .extra2         = &max_max_baud_rate
        },
        {
-               .ctl_name       = NET_IRDA_MIN_TX_TURN_TIME,
                .procname       = "min_tx_turn_time",
                .data           = &sysctl_min_tx_turn_time,
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .strategy       = sysctl_intvec,
                .extra1         = &min_min_tx_turn_time,
                .extra2         = &max_min_tx_turn_time
        },
        {
-               .ctl_name       = NET_IRDA_MAX_TX_DATA_SIZE,
                .procname       = "max_tx_data_size",
                .data           = &sysctl_max_tx_data_size,
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .strategy       = sysctl_intvec,
                .extra1         = &min_max_tx_data_size,
                .extra2         = &max_max_tx_data_size
        },
        {
-               .ctl_name       = NET_IRDA_MAX_TX_WINDOW,
                .procname       = "max_tx_window",
                .data           = &sysctl_max_tx_window,
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .strategy       = sysctl_intvec,
                .extra1         = &min_max_tx_window,
                .extra2         = &max_max_tx_window
        },
        {
-               .ctl_name       = NET_IRDA_MAX_NOREPLY_TIME,
                .procname       = "max_noreply_time",
                .data           = &sysctl_max_noreply_time,
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .strategy       = sysctl_intvec,
                .extra1         = &min_max_noreply_time,
                .extra2         = &max_max_noreply_time
        },
        {
-               .ctl_name       = NET_IRDA_WARN_NOREPLY_TIME,
                .procname       = "warn_noreply_time",
                .data           = &sysctl_warn_noreply_time,
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .strategy       = sysctl_intvec,
                .extra1         = &min_warn_noreply_time,
                .extra2         = &max_warn_noreply_time
        },
        {
-               .ctl_name       = NET_IRDA_LAP_KEEPALIVE_TIME,
                .procname       = "lap_keepalive_time",
                .data           = &sysctl_lap_keepalive_time,
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .strategy       = sysctl_intvec,
                .extra1         = &min_lap_keepalive_time,
                .extra2         = &max_lap_keepalive_time
        },
-       { .ctl_name = 0 }
+       { }
 };
 
 static struct ctl_path irda_path[] = {
-       { .procname = "net", .ctl_name = CTL_NET, },
-       { .procname = "irda", .ctl_name = NET_IRDA, },
+       { .procname = "net", },
+       { .procname = "irda", },
        { }
 };
 
index 57b9304..e2ebe35 100644 (file)
 
 static struct ctl_table llc2_timeout_table[] = {
        {
-               .ctl_name       = NET_LLC2_ACK_TIMEOUT,
                .procname       = "ack",
                .data           = &sysctl_llc2_ack_timeout,
                .maxlen         = sizeof(long),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_jiffies,
-               .strategy       = sysctl_jiffies,
        },
        {
-               .ctl_name       = NET_LLC2_BUSY_TIMEOUT,
                .procname       = "busy",
                .data           = &sysctl_llc2_busy_timeout,
                .maxlen         = sizeof(long),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_jiffies,
-               .strategy       = sysctl_jiffies,
        },
        {
-               .ctl_name       = NET_LLC2_P_TIMEOUT,
                .procname       = "p",
                .data           = &sysctl_llc2_p_timeout,
                .maxlen         = sizeof(long),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_jiffies,
-               .strategy       = sysctl_jiffies,
        },
        {
-               .ctl_name       = NET_LLC2_REJ_TIMEOUT,
                .procname       = "rej",
                .data           = &sysctl_llc2_rej_timeout,
                .maxlen         = sizeof(long),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_jiffies,
-               .strategy       = sysctl_jiffies,
        },
-       { },
+       { },
 };
 
 static struct ctl_table llc_station_table[] = {
        {
-               .ctl_name       = NET_LLC_STATION_ACK_TIMEOUT,
                .procname       = "ack_timeout",
                .data           = &sysctl_llc_station_ack_timeout,
                .maxlen         = sizeof(long),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_jiffies,
-               .strategy       = sysctl_jiffies,
        },
-       { },
+       { },
 };
 
 static struct ctl_table llc2_dir_timeout_table[] = {
        {
-               .ctl_name       = NET_LLC2,
                .procname       = "timeout",
                .mode           = 0555,
                .child          = llc2_timeout_table,
        },
-       { },
+       { },
 };
 
 static struct ctl_table llc_table[] = {
        {
-               .ctl_name       = NET_LLC2,
                .procname       = "llc2",
                .mode           = 0555,
                .child          = llc2_dir_timeout_table,
        },
        {
-               .ctl_name       = NET_LLC_STATION,
                .procname       = "station",
                .mode           = 0555,
                .child          = llc_station_table,
        },
-       { },
+       { },
 };
 
 static struct ctl_path llc_path[] = {
-       { .procname = "net", .ctl_name = CTL_NET, },
-       { .procname = "llc", .ctl_name = NET_LLC, },
+       { .procname = "net", },
+       { .procname = "llc", },
        { }
 };
 
index 5bb3473..60ec4e4 100644 (file)
@@ -273,8 +273,8 @@ void __init netfilter_init(void)
 
 #ifdef CONFIG_SYSCTL
 struct ctl_path nf_net_netfilter_sysctl_path[] = {
-       { .procname = "net", .ctl_name = CTL_NET, },
-       { .procname = "netfilter", .ctl_name = NET_NETFILTER, },
+       { .procname = "net", },
+       { .procname = "netfilter", },
        { }
 };
 EXPORT_SYMBOL_GPL(nf_net_netfilter_sysctl_path);
index 446e9bd..e55a686 100644 (file)
@@ -1706,12 +1706,12 @@ static struct ctl_table vs_vars[] = {
                .mode           = 0644,
                .proc_handler   = proc_dointvec,
        },
-       { .ctl_name = 0 }
+       { }
 };
 
 const struct ctl_path net_vs_ctl_path[] = {
-       { .procname = "net", .ctl_name = CTL_NET, },
-       { .procname = "ipv4", .ctl_name = NET_IPV4, },
+       { .procname = "net", },
+       { .procname = "ipv4", },
        { .procname = "vs", },
        { }
 };
index c1757f3..1b9370d 100644 (file)
@@ -121,7 +121,7 @@ static ctl_table vs_vars_table[] = {
                .mode           = 0644,
                .proc_handler   = proc_dointvec_jiffies,
        },
-       { .ctl_name = 0 }
+       { }
 };
 
 static struct ctl_table_header * sysctl_header;
index 715b57f..f7476b9 100644 (file)
@@ -302,7 +302,7 @@ static ctl_table vs_vars_table[] = {
                .mode           = 0644,
                .proc_handler   = proc_dointvec_jiffies,
        },
-       { .ctl_name = 0 }
+       { }
 };
 
 static struct ctl_table_header * sysctl_header;
index 4a1d94a..018f90d 100644 (file)
@@ -30,7 +30,6 @@ MODULE_PARM_DESC(acct, "Enable connection tracking flow accounting.");
 #ifdef CONFIG_SYSCTL
 static struct ctl_table acct_sysctl_table[] = {
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "nf_conntrack_acct",
                .data           = &init_net.ct.sysctl_acct,
                .maxlen         = sizeof(unsigned int),
index aee560b..d5a9bcd 100644 (file)
@@ -151,7 +151,6 @@ static int nf_ct_events_retry_timeout __read_mostly = 15*HZ;
 #ifdef CONFIG_SYSCTL
 static struct ctl_table event_sysctl_table[] = {
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "nf_conntrack_events",
                .data           = &init_net.ct.sysctl_events,
                .maxlen         = sizeof(unsigned int),
@@ -159,7 +158,6 @@ static struct ctl_table event_sysctl_table[] = {
                .proc_handler   = proc_dointvec,
        },
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "nf_conntrack_events_retry_timeout",
                .data           = &init_net.ct.sysctl_events_retry_timeout,
                .maxlen         = sizeof(unsigned int),
index 98916ef..dd37550 100644 (file)
@@ -703,64 +703,54 @@ static int dccp_nlattr_size(void)
 /* template, data assigned later */
 static struct ctl_table dccp_sysctl_table[] = {
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "nf_conntrack_dccp_timeout_request",
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_jiffies,
        },
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "nf_conntrack_dccp_timeout_respond",
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_jiffies,
        },
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "nf_conntrack_dccp_timeout_partopen",
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_jiffies,
        },
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "nf_conntrack_dccp_timeout_open",
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_jiffies,
        },
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "nf_conntrack_dccp_timeout_closereq",
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_jiffies,
        },
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "nf_conntrack_dccp_timeout_closing",
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_jiffies,
        },
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "nf_conntrack_dccp_timeout_timewait",
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_jiffies,
        },
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "nf_conntrack_dccp_loose",
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec,
        },
-       {
-               .ctl_name       = 0,
-       }
+       { }
 };
 #endif /* CONFIG_SYSCTL */
 
index 829374f..e2091d0 100644 (file)
@@ -69,9 +69,7 @@ static struct ctl_table generic_sysctl_table[] = {
                .mode           = 0644,
                .proc_handler   = proc_dointvec_jiffies,
        },
-       {
-               .ctl_name       = 0
-       }
+       { }
 };
 #ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT
 static struct ctl_table generic_compat_sysctl_table[] = {
@@ -82,9 +80,7 @@ static struct ctl_table generic_compat_sysctl_table[] = {
                .mode           = 0644,
                .proc_handler   = proc_dointvec_jiffies,
        },
-       {
-               .ctl_name       = 0
-       }
+       { }
 };
 #endif /* CONFIG_NF_CONNTRACK_PROC_COMPAT */
 #endif /* CONFIG_SYSCTL */
index c10e6f3..f9d930f 100644 (file)
@@ -595,9 +595,7 @@ static struct ctl_table sctp_sysctl_table[] = {
                .mode           = 0644,
                .proc_handler   = proc_dointvec_jiffies,
        },
-       {
-               .ctl_name = 0
-       }
+       { }
 };
 
 #ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT
@@ -651,9 +649,7 @@ static struct ctl_table sctp_compat_sysctl_table[] = {
                .mode           = 0644,
                .proc_handler   = proc_dointvec_jiffies,
        },
-       {
-               .ctl_name = 0
-       }
+       { }
 };
 #endif /* CONFIG_NF_CONNTRACK_PROC_COMPAT */
 #endif
index 37a8c74..3c96437 100644 (file)
@@ -1322,7 +1322,6 @@ static struct ctl_table tcp_sysctl_table[] = {
                .proc_handler   = proc_dointvec_jiffies,
        },
        {
-               .ctl_name       = NET_NF_CONNTRACK_TCP_LOOSE,
                .procname       = "nf_conntrack_tcp_loose",
                .data           = &nf_ct_tcp_loose,
                .maxlen         = sizeof(unsigned int),
@@ -1330,7 +1329,6 @@ static struct ctl_table tcp_sysctl_table[] = {
                .proc_handler   = proc_dointvec,
        },
        {
-               .ctl_name       = NET_NF_CONNTRACK_TCP_BE_LIBERAL,
                .procname       = "nf_conntrack_tcp_be_liberal",
                .data           = &nf_ct_tcp_be_liberal,
                .maxlen         = sizeof(unsigned int),
@@ -1338,16 +1336,13 @@ static struct ctl_table tcp_sysctl_table[] = {
                .proc_handler   = proc_dointvec,
        },
        {
-               .ctl_name       = NET_NF_CONNTRACK_TCP_MAX_RETRANS,
                .procname       = "nf_conntrack_tcp_max_retrans",
                .data           = &nf_ct_tcp_max_retrans,
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec,
        },
-       {
-               .ctl_name       = 0
-       }
+       { }
 };
 
 #ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT
@@ -1423,7 +1418,6 @@ static struct ctl_table tcp_compat_sysctl_table[] = {
                .proc_handler   = proc_dointvec_jiffies,
        },
        {
-               .ctl_name       = NET_IPV4_NF_CONNTRACK_TCP_LOOSE,
                .procname       = "ip_conntrack_tcp_loose",
                .data           = &nf_ct_tcp_loose,
                .maxlen         = sizeof(unsigned int),
@@ -1431,7 +1425,6 @@ static struct ctl_table tcp_compat_sysctl_table[] = {
                .proc_handler   = proc_dointvec,
        },
        {
-               .ctl_name       = NET_IPV4_NF_CONNTRACK_TCP_BE_LIBERAL,
                .procname       = "ip_conntrack_tcp_be_liberal",
                .data           = &nf_ct_tcp_be_liberal,
                .maxlen         = sizeof(unsigned int),
@@ -1439,16 +1432,13 @@ static struct ctl_table tcp_compat_sysctl_table[] = {
                .proc_handler   = proc_dointvec,
        },
        {
-               .ctl_name       = NET_IPV4_NF_CONNTRACK_TCP_MAX_RETRANS,
                .procname       = "ip_conntrack_tcp_max_retrans",
                .data           = &nf_ct_tcp_max_retrans,
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec,
        },
-       {
-               .ctl_name       = 0
-       }
+       { }
 };
 #endif /* CONFIG_NF_CONNTRACK_PROC_COMPAT */
 #endif /* CONFIG_SYSCTL */
index 70809d1..5c5518b 100644 (file)
@@ -154,9 +154,7 @@ static struct ctl_table udp_sysctl_table[] = {
                .mode           = 0644,
                .proc_handler   = proc_dointvec_jiffies,
        },
-       {
-               .ctl_name       = 0
-       }
+       { }
 };
 #ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT
 static struct ctl_table udp_compat_sysctl_table[] = {
@@ -174,9 +172,7 @@ static struct ctl_table udp_compat_sysctl_table[] = {
                .mode           = 0644,
                .proc_handler   = proc_dointvec_jiffies,
        },
-       {
-               .ctl_name       = 0
-       }
+       { }
 };
 #endif /* CONFIG_NF_CONNTRACK_PROC_COMPAT */
 #endif /* CONFIG_SYSCTL */
index 0badedc..458655b 100644 (file)
@@ -146,7 +146,6 @@ static unsigned int udplite_sysctl_table_users;
 static struct ctl_table_header *udplite_sysctl_header;
 static struct ctl_table udplite_sysctl_table[] = {
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "nf_conntrack_udplite_timeout",
                .data           = &nf_ct_udplite_timeout,
                .maxlen         = sizeof(unsigned int),
@@ -154,16 +153,13 @@ static struct ctl_table udplite_sysctl_table[] = {
                .proc_handler   = proc_dointvec_jiffies,
        },
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "nf_conntrack_udplite_timeout_stream",
                .data           = &nf_ct_udplite_timeout_stream,
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_jiffies,
        },
-       {
-               .ctl_name       = 0
-       }
+       { }
 };
 #endif /* CONFIG_SYSCTL */
 
index 1935153..028aba6 100644 (file)
@@ -340,7 +340,6 @@ static struct ctl_table_header *nf_ct_netfilter_header;
 
 static ctl_table nf_ct_sysctl_table[] = {
        {
-               .ctl_name       = NET_NF_CONNTRACK_MAX,
                .procname       = "nf_conntrack_max",
                .data           = &nf_conntrack_max,
                .maxlen         = sizeof(int),
@@ -348,7 +347,6 @@ static ctl_table nf_ct_sysctl_table[] = {
                .proc_handler   = proc_dointvec,
        },
        {
-               .ctl_name       = NET_NF_CONNTRACK_COUNT,
                .procname       = "nf_conntrack_count",
                .data           = &init_net.ct.count,
                .maxlen         = sizeof(int),
@@ -356,7 +354,6 @@ static ctl_table nf_ct_sysctl_table[] = {
                .proc_handler   = proc_dointvec,
        },
        {
-               .ctl_name       = NET_NF_CONNTRACK_BUCKETS,
                .procname       = "nf_conntrack_buckets",
                .data           = &nf_conntrack_htable_size,
                .maxlen         = sizeof(unsigned int),
@@ -364,7 +361,6 @@ static ctl_table nf_ct_sysctl_table[] = {
                .proc_handler   = proc_dointvec,
        },
        {
-               .ctl_name       = NET_NF_CONNTRACK_CHECKSUM,
                .procname       = "nf_conntrack_checksum",
                .data           = &init_net.ct.sysctl_checksum,
                .maxlen         = sizeof(unsigned int),
@@ -372,43 +368,39 @@ static ctl_table nf_ct_sysctl_table[] = {
                .proc_handler   = proc_dointvec,
        },
        {
-               .ctl_name       = NET_NF_CONNTRACK_LOG_INVALID,
                .procname       = "nf_conntrack_log_invalid",
                .data           = &init_net.ct.sysctl_log_invalid,
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .strategy       = sysctl_intvec,
                .extra1         = &log_invalid_proto_min,
                .extra2         = &log_invalid_proto_max,
        },
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "nf_conntrack_expect_max",
                .data           = &nf_ct_expect_max,
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec,
        },
-       { .ctl_name = 0 }
+       { }
 };
 
 #define NET_NF_CONNTRACK_MAX 2089
 
 static ctl_table nf_ct_netfilter_table[] = {
        {
-               .ctl_name       = NET_NF_CONNTRACK_MAX,
                .procname       = "nf_conntrack_max",
                .data           = &nf_conntrack_max,
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec,
        },
-       { .ctl_name = 0 }
+       { }
 };
 
 static struct ctl_path nf_ct_path[] = {
-       { .procname = "net", .ctl_name = CTL_NET, },
+       { .procname = "net", },
        { }
 };
 
index d65d348..015725a 100644 (file)
@@ -208,9 +208,9 @@ static const struct file_operations nflog_file_ops = {
 
 #ifdef CONFIG_SYSCTL
 static struct ctl_path nf_log_sysctl_path[] = {
-       { .procname = "net", .ctl_name = CTL_NET, },
-       { .procname = "netfilter", .ctl_name = NET_NETFILTER, },
-       { .procname = "nf_log", .ctl_name = CTL_UNNUMBERED, },
+       { .procname = "net", },
+       { .procname = "netfilter", },
+       { .procname = "nf_log", },
        { }
 };
 
@@ -265,7 +265,6 @@ static __init int netfilter_log_sysctl_init(void)
 
        for (i = NFPROTO_UNSPEC; i < NFPROTO_NUMPROTO; i++) {
                snprintf(nf_log_sysctl_fnames[i-NFPROTO_UNSPEC], 3, "%d", i);
-               nf_log_sysctl_table[i].ctl_name = CTL_UNNUMBERED;
                nf_log_sysctl_table[i].procname =
                        nf_log_sysctl_fnames[i-NFPROTO_UNSPEC];
                nf_log_sysctl_table[i].data = NULL;
index 7b49591..1e0fa9e 100644 (file)
@@ -36,143 +36,119 @@ static struct ctl_table_header *nr_table_header;
 
 static ctl_table nr_table[] = {
        {
-               .ctl_name       = NET_NETROM_DEFAULT_PATH_QUALITY,
                .procname       = "default_path_quality",
                .data           = &sysctl_netrom_default_path_quality,
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .strategy       = sysctl_intvec,
                .extra1         = &min_quality,
                .extra2         = &max_quality
        },
        {
-               .ctl_name       = NET_NETROM_OBSOLESCENCE_COUNT_INITIALISER,
                .procname       = "obsolescence_count_initialiser",
                .data           = &sysctl_netrom_obsolescence_count_initialiser,
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .strategy       = sysctl_intvec,
                .extra1         = &min_obs,
                .extra2         = &max_obs
        },
        {
-               .ctl_name       = NET_NETROM_NETWORK_TTL_INITIALISER,
                .procname       = "network_ttl_initialiser",
                .data           = &sysctl_netrom_network_ttl_initialiser,
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .strategy       = sysctl_intvec,
                .extra1         = &min_ttl,
                .extra2         = &max_ttl
        },
        {
-               .ctl_name       = NET_NETROM_TRANSPORT_TIMEOUT,
                .procname       = "transport_timeout",
                .data           = &sysctl_netrom_transport_timeout,
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .strategy       = sysctl_intvec,
                .extra1         = &min_t1,
                .extra2         = &max_t1
        },
        {
-               .ctl_name       = NET_NETROM_TRANSPORT_MAXIMUM_TRIES,
                .procname       = "transport_maximum_tries",
                .data           = &sysctl_netrom_transport_maximum_tries,
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .strategy       = sysctl_intvec,
                .extra1         = &min_n2,
                .extra2         = &max_n2
        },
        {
-               .ctl_name       = NET_NETROM_TRANSPORT_ACKNOWLEDGE_DELAY,
                .procname       = "transport_acknowledge_delay",
                .data           = &sysctl_netrom_transport_acknowledge_delay,
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .strategy       = sysctl_intvec,
                .extra1         = &min_t2,
                .extra2         = &max_t2
        },
        {
-               .ctl_name       = NET_NETROM_TRANSPORT_BUSY_DELAY,
                .procname       = "transport_busy_delay",
                .data           = &sysctl_netrom_transport_busy_delay,
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .strategy       = sysctl_intvec,
                .extra1         = &min_t4,
                .extra2         = &max_t4
        },
        {
-               .ctl_name       = NET_NETROM_TRANSPORT_REQUESTED_WINDOW_SIZE,
                .procname       = "transport_requested_window_size",
                .data           = &sysctl_netrom_transport_requested_window_size,
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .strategy       = sysctl_intvec,
                .extra1         = &min_window,
                .extra2         = &max_window
        },
        {
-               .ctl_name       = NET_NETROM_TRANSPORT_NO_ACTIVITY_TIMEOUT,
                .procname       = "transport_no_activity_timeout",
                .data           = &sysctl_netrom_transport_no_activity_timeout,
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .strategy       = sysctl_intvec,
                .extra1         = &min_idle,
                .extra2         = &max_idle
        },
        {
-               .ctl_name       = NET_NETROM_ROUTING_CONTROL,
                .procname       = "routing_control",
                .data           = &sysctl_netrom_routing_control,
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .strategy       = sysctl_intvec,
                .extra1         = &min_route,
                .extra2         = &max_route
        },
        {
-               .ctl_name       = NET_NETROM_LINK_FAILS_COUNT,
                .procname       = "link_fails_count",
                .data           = &sysctl_netrom_link_fails_count,
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .strategy       = sysctl_intvec,
                .extra1         = &min_fails,
                .extra2         = &max_fails
        },
        {
-               .ctl_name       = NET_NETROM_RESET,
                .procname       = "reset",
                .data           = &sysctl_netrom_reset_circuit,
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .strategy       = sysctl_intvec,
                .extra1         = &min_reset,
                .extra2         = &max_reset
        },
-       { .ctl_name = 0 }
+       { }
 };
 
 static struct ctl_path nr_path[] = {
-       { .procname = "net", .ctl_name = CTL_NET, },
-       { .procname = "netrom", .ctl_name = NET_NETROM, },
+       { .procname = "net", },
+       { .procname = "netrom", },
        { }
 };
 
index 2220f33..cea1c7d 100644 (file)
@@ -84,20 +84,18 @@ static int proc_local_port_range(ctl_table *table, int write,
 
 static struct ctl_table phonet_table[] = {
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "local_port_range",
                .data           = &local_port_range,
                .maxlen         = sizeof(local_port_range),
                .mode           = 0644,
                .proc_handler   = proc_local_port_range,
-               .strategy       = NULL,
        },
-       { .ctl_name = 0 }
+       { }
 };
 
 static struct ctl_path phonet_ctl_path[] = {
-       { .procname = "net", .ctl_name = CTL_NET, },
-       { .procname = "phonet", .ctl_name = CTL_UNNUMBERED, },
+       { .procname = "net", },
+       { .procname = "phonet", },
        { },
 };
 
index 84b5ffc..03f01cb 100644 (file)
@@ -67,68 +67,62 @@ unsigned int rds_ib_sysctl_flow_control = 0;
 
 ctl_table rds_ib_sysctl_table[] = {
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "max_send_wr",
                .data           = &rds_ib_sysctl_max_send_wr,
                .maxlen         = sizeof(unsigned long),
                .mode           = 0644,
-               .proc_handler   = &proc_doulongvec_minmax,
+               .proc_handler   = proc_doulongvec_minmax,
                .extra1         = &rds_ib_sysctl_max_wr_min,
                .extra2         = &rds_ib_sysctl_max_wr_max,
        },
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "max_recv_wr",
                .data           = &rds_ib_sysctl_max_recv_wr,
                .maxlen         = sizeof(unsigned long),
                .mode           = 0644,
-               .proc_handler   = &proc_doulongvec_minmax,
+               .proc_handler   = proc_doulongvec_minmax,
                .extra1         = &rds_ib_sysctl_max_wr_min,
                .extra2         = &rds_ib_sysctl_max_wr_max,
        },
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "max_unsignaled_wr",
                .data           = &rds_ib_sysctl_max_unsig_wrs,
                .maxlen         = sizeof(unsigned long),
                .mode           = 0644,
-               .proc_handler   = &proc_doulongvec_minmax,
+               .proc_handler   = proc_doulongvec_minmax,
                .extra1         = &rds_ib_sysctl_max_unsig_wr_min,
                .extra2         = &rds_ib_sysctl_max_unsig_wr_max,
        },
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "max_unsignaled_bytes",
                .data           = &rds_ib_sysctl_max_unsig_bytes,
                .maxlen         = sizeof(unsigned long),
                .mode           = 0644,
-               .proc_handler   = &proc_doulongvec_minmax,
+               .proc_handler   = proc_doulongvec_minmax,
                .extra1         = &rds_ib_sysctl_max_unsig_bytes_min,
                .extra2         = &rds_ib_sysctl_max_unsig_bytes_max,
        },
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "max_recv_allocation",
                .data           = &rds_ib_sysctl_max_recv_allocation,
                .maxlen         = sizeof(unsigned long),
                .mode           = 0644,
-               .proc_handler   = &proc_doulongvec_minmax,
+               .proc_handler   = proc_doulongvec_minmax,
        },
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "flow_control",
                .data           = &rds_ib_sysctl_flow_control,
                .maxlen         = sizeof(rds_ib_sysctl_flow_control),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec,
+               .proc_handler   = proc_dointvec,
        },
-       { .ctl_name = 0}
+       { }
 };
 
 static struct ctl_path rds_ib_sysctl_path[] = {
-       { .procname = "net", .ctl_name = CTL_NET, },
-       { .procname = "rds", .ctl_name = CTL_UNNUMBERED, },
-       { .procname = "ib", .ctl_name = CTL_UNNUMBERED, },
+       { .procname = "net", },
+       { .procname = "rds", },
+       { .procname = "ib", },
        { }
 };
 
index 9590678..1c4428a 100644 (file)
@@ -57,68 +57,62 @@ unsigned int rds_iw_sysctl_flow_control = 1;
 
 ctl_table rds_iw_sysctl_table[] = {
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "max_send_wr",
                .data           = &rds_iw_sysctl_max_send_wr,
                .maxlen         = sizeof(unsigned long),
                .mode           = 0644,
-               .proc_handler   = &proc_doulongvec_minmax,
+               .proc_handler   = proc_doulongvec_minmax,
                .extra1         = &rds_iw_sysctl_max_wr_min,
                .extra2         = &rds_iw_sysctl_max_wr_max,
        },
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "max_recv_wr",
                .data           = &rds_iw_sysctl_max_recv_wr,
                .maxlen         = sizeof(unsigned long),
                .mode           = 0644,
-               .proc_handler   = &proc_doulongvec_minmax,
+               .proc_handler   = proc_doulongvec_minmax,
                .extra1         = &rds_iw_sysctl_max_wr_min,
                .extra2         = &rds_iw_sysctl_max_wr_max,
        },
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "max_unsignaled_wr",
                .data           = &rds_iw_sysctl_max_unsig_wrs,
                .maxlen         = sizeof(unsigned long),
                .mode           = 0644,
-               .proc_handler   = &proc_doulongvec_minmax,
+               .proc_handler   = proc_doulongvec_minmax,
                .extra1         = &rds_iw_sysctl_max_unsig_wr_min,
                .extra2         = &rds_iw_sysctl_max_unsig_wr_max,
        },
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "max_unsignaled_bytes",
                .data           = &rds_iw_sysctl_max_unsig_bytes,
                .maxlen         = sizeof(unsigned long),
                .mode           = 0644,
-               .proc_handler   = &proc_doulongvec_minmax,
+               .proc_handler   = proc_doulongvec_minmax,
                .extra1         = &rds_iw_sysctl_max_unsig_bytes_min,
                .extra2         = &rds_iw_sysctl_max_unsig_bytes_max,
        },
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "max_recv_allocation",
                .data           = &rds_iw_sysctl_max_recv_allocation,
                .maxlen         = sizeof(unsigned long),
                .mode           = 0644,
-               .proc_handler   = &proc_doulongvec_minmax,
+               .proc_handler   = proc_doulongvec_minmax,
        },
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "flow_control",
                .data           = &rds_iw_sysctl_flow_control,
                .maxlen         = sizeof(rds_iw_sysctl_flow_control),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec,
+               .proc_handler   = proc_dointvec,
        },
-       { .ctl_name = 0}
+       { }
 };
 
 static struct ctl_path rds_iw_sysctl_path[] = {
-       { .procname = "net", .ctl_name = CTL_NET, },
-       { .procname = "rds", .ctl_name = CTL_UNNUMBERED, },
-       { .procname = "iw", .ctl_name = CTL_UNNUMBERED, },
+       { .procname = "net", },
+       { .procname = "rds", },
+       { .procname = "iw", },
        { }
 };
 
index 307dc5c..7829a20 100644 (file)
@@ -51,55 +51,50 @@ unsigned int rds_sysctl_ping_enable = 1;
 
 static ctl_table rds_sysctl_rds_table[] = {
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "reconnect_min_delay_ms",
                .data           = &rds_sysctl_reconnect_min_jiffies,
                .maxlen         = sizeof(unsigned long),
                .mode           = 0644,
-               .proc_handler   = &proc_doulongvec_ms_jiffies_minmax,
+               .proc_handler   = proc_doulongvec_ms_jiffies_minmax,
                .extra1         = &rds_sysctl_reconnect_min,
                .extra2         = &rds_sysctl_reconnect_max_jiffies,
        },
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "reconnect_max_delay_ms",
                .data           = &rds_sysctl_reconnect_max_jiffies,
                .maxlen         = sizeof(unsigned long),
                .mode           = 0644,
-               .proc_handler   = &proc_doulongvec_ms_jiffies_minmax,
+               .proc_handler   = proc_doulongvec_ms_jiffies_minmax,
                .extra1         = &rds_sysctl_reconnect_min_jiffies,
                .extra2         = &rds_sysctl_reconnect_max,
        },
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "max_unacked_packets",
                .data           = &rds_sysctl_max_unacked_packets,
                .maxlen         = sizeof(unsigned long),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec,
+               .proc_handler   = proc_dointvec,
        },
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "max_unacked_bytes",
                .data           = &rds_sysctl_max_unacked_bytes,
                .maxlen         = sizeof(unsigned long),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec,
+               .proc_handler   = proc_dointvec,
        },
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "ping_enable",
                .data           = &rds_sysctl_ping_enable,
                .maxlen         = sizeof(int),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec,
+               .proc_handler   = proc_dointvec,
        },
-       { .ctl_name = 0}
+       { }
 };
 
 static struct ctl_path rds_sysctl_path[] = {
-       { .procname = "net", .ctl_name = CTL_NET, },
-       { .procname = "rds", .ctl_name = CTL_UNNUMBERED, },
+       { .procname = "net", },
+       { .procname = "rds", },
        { }
 };
 
index 3bfe504..df6d9da 100644 (file)
@@ -26,121 +26,101 @@ static struct ctl_table_header *rose_table_header;
 
 static ctl_table rose_table[] = {
        {
-               .ctl_name       = NET_ROSE_RESTART_REQUEST_TIMEOUT,
                .procname       = "restart_request_timeout",
                .data           = &sysctl_rose_restart_request_timeout,
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .strategy       = sysctl_intvec,
                .extra1         = &min_timer,
                .extra2         = &max_timer
        },
        {
-               .ctl_name       = NET_ROSE_CALL_REQUEST_TIMEOUT,
                .procname       = "call_request_timeout",
                .data           = &sysctl_rose_call_request_timeout,
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .strategy       = sysctl_intvec,
                .extra1         = &min_timer,
                .extra2         = &max_timer
        },
        {
-               .ctl_name       = NET_ROSE_RESET_REQUEST_TIMEOUT,
                .procname       = "reset_request_timeout",
                .data           = &sysctl_rose_reset_request_timeout,
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .strategy       = sysctl_intvec,
                .extra1         = &min_timer,
                .extra2         = &max_timer
        },
        {
-               .ctl_name       = NET_ROSE_CLEAR_REQUEST_TIMEOUT,
                .procname       = "clear_request_timeout",
                .data           = &sysctl_rose_clear_request_timeout,
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .strategy       = sysctl_intvec,
                .extra1         = &min_timer,
                .extra2         = &max_timer
        },
        {
-               .ctl_name       = NET_ROSE_NO_ACTIVITY_TIMEOUT,
                .procname       = "no_activity_timeout",
                .data           = &sysctl_rose_no_activity_timeout,
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .strategy       = sysctl_intvec,
                .extra1         = &min_idle,
                .extra2         = &max_idle
        },
        {
-               .ctl_name       = NET_ROSE_ACK_HOLD_BACK_TIMEOUT,
                .procname       = "acknowledge_hold_back_timeout",
                .data           = &sysctl_rose_ack_hold_back_timeout,
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .strategy       = sysctl_intvec,
                .extra1         = &min_timer,
                .extra2         = &max_timer
        },
        {
-               .ctl_name       = NET_ROSE_ROUTING_CONTROL,
                .procname       = "routing_control",
                .data           = &sysctl_rose_routing_control,
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .strategy       = sysctl_intvec,
                .extra1         = &min_route,
                .extra2         = &max_route
        },
        {
-               .ctl_name       = NET_ROSE_LINK_FAIL_TIMEOUT,
                .procname       = "link_fail_timeout",
                .data           = &sysctl_rose_link_fail_timeout,
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .strategy       = sysctl_intvec,
                .extra1         = &min_ftimer,
                .extra2         = &max_ftimer
        },
        {
-               .ctl_name       = NET_ROSE_MAX_VCS,
                .procname       = "maximum_virtual_circuits",
                .data           = &sysctl_rose_maximum_vcs,
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .strategy       = sysctl_intvec,
                .extra1         = &min_maxvcs,
                .extra2         = &max_maxvcs
        },
        {
-               .ctl_name       = NET_ROSE_WINDOW_SIZE,
                .procname       = "window_size",
                .data           = &sysctl_rose_window_size,
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .strategy       = sysctl_intvec,
                .extra1         = &min_window,
                .extra2         = &max_window
        },
-       { .ctl_name = 0 }
+       { }
 };
 
 static struct ctl_path rose_path[] = {
-       { .procname = "net", .ctl_name = CTL_NET, },
-       { .procname = "rose", .ctl_name = NET_ROSE, },
+       { .procname = "net", },
+       { .procname = "rose", },
        { }
 };
 
index ae03ded..832590b 100644 (file)
@@ -60,180 +60,145 @@ extern int sysctl_sctp_wmem[3];
 
 static ctl_table sctp_table[] = {
        {
-               .ctl_name       = NET_SCTP_RTO_INITIAL,
                .procname       = "rto_initial",
                .data           = &sctp_rto_initial,
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .strategy       = sysctl_intvec,
                .extra1         = &one,
                .extra2         = &timer_max
        },
        {
-               .ctl_name       = NET_SCTP_RTO_MIN,
                .procname       = "rto_min",
                .data           = &sctp_rto_min,
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .strategy       = sysctl_intvec,
                .extra1         = &one,
                .extra2         = &timer_max
        },
        {
-               .ctl_name       = NET_SCTP_RTO_MAX,
                .procname       = "rto_max",
                .data           = &sctp_rto_max,
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .strategy       = sysctl_intvec,
                .extra1         = &one,
                .extra2         = &timer_max
        },
        {
-               .ctl_name       = NET_SCTP_VALID_COOKIE_LIFE,
                .procname       = "valid_cookie_life",
                .data           = &sctp_valid_cookie_life,
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .strategy       = sysctl_intvec,
                .extra1         = &one,
                .extra2         = &timer_max
        },
        {
-               .ctl_name       = NET_SCTP_MAX_BURST,
                .procname       = "max_burst",
                .data           = &sctp_max_burst,
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .strategy       = sysctl_intvec,
                .extra1         = &zero,
                .extra2         = &int_max
        },
        {
-               .ctl_name       = NET_SCTP_ASSOCIATION_MAX_RETRANS,
                .procname       = "association_max_retrans",
                .data           = &sctp_max_retrans_association,
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .strategy       = sysctl_intvec,
                .extra1         = &one,
                .extra2         = &int_max
        },
        {
-               .ctl_name       = NET_SCTP_SNDBUF_POLICY,
                .procname       = "sndbuf_policy",
                .data           = &sctp_sndbuf_policy,
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec,
-               .strategy       = sysctl_intvec
        },
        {
-               .ctl_name       = NET_SCTP_RCVBUF_POLICY,
                .procname       = "rcvbuf_policy",
                .data           = &sctp_rcvbuf_policy,
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec,
-               .strategy       = sysctl_intvec
        },
        {
-               .ctl_name       = NET_SCTP_PATH_MAX_RETRANS,
                .procname       = "path_max_retrans",
                .data           = &sctp_max_retrans_path,
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .strategy       = sysctl_intvec,
                .extra1         = &one,
                .extra2         = &int_max
        },
        {
-               .ctl_name       = NET_SCTP_MAX_INIT_RETRANSMITS,
                .procname       = "max_init_retransmits",
                .data           = &sctp_max_retrans_init,
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .strategy       = sysctl_intvec,
                .extra1         = &one,
                .extra2         = &int_max
        },
        {
-               .ctl_name       = NET_SCTP_HB_INTERVAL,
                .procname       = "hb_interval",
                .data           = &sctp_hb_interval,
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .strategy       = sysctl_intvec,
                .extra1         = &one,
                .extra2         = &timer_max
        },
        {
-               .ctl_name       = NET_SCTP_PRESERVE_ENABLE,
                .procname       = "cookie_preserve_enable",
                .data           = &sctp_cookie_preserve_enable,
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec,
-               .strategy       = sysctl_intvec
        },
        {
-               .ctl_name       = NET_SCTP_RTO_ALPHA,
                .procname       = "rto_alpha_exp_divisor",
                .data           = &sctp_rto_alpha,
                .maxlen         = sizeof(int),
                .mode           = 0444,
                .proc_handler   = proc_dointvec,
-               .strategy       = sysctl_intvec
        },
        {
-               .ctl_name       = NET_SCTP_RTO_BETA,
                .procname       = "rto_beta_exp_divisor",
                .data           = &sctp_rto_beta,
                .maxlen         = sizeof(int),
                .mode           = 0444,
                .proc_handler   = proc_dointvec,
-               .strategy       = sysctl_intvec
        },
        {
-               .ctl_name       = NET_SCTP_ADDIP_ENABLE,
                .procname       = "addip_enable",
                .data           = &sctp_addip_enable,
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec,
-               .strategy       = sysctl_intvec
        },
        {
-               .ctl_name       = NET_SCTP_PRSCTP_ENABLE,
                .procname       = "prsctp_enable",
                .data           = &sctp_prsctp_enable,
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec,
-               .strategy       = sysctl_intvec
        },
        {
-               .ctl_name       = NET_SCTP_SACK_TIMEOUT,
                .procname       = "sack_timeout",
                .data           = &sctp_sack_timeout,
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .strategy       = sysctl_intvec,
                .extra1         = &sack_timer_min,
                .extra2         = &sack_timer_max,
        },
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "sctp_mem",
                .data           = &sysctl_sctp_mem,
                .maxlen         = sizeof(sysctl_sctp_mem),
@@ -241,7 +206,6 @@ static ctl_table sctp_table[] = {
                .proc_handler   = proc_dointvec,
        },
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "sctp_rmem",
                .data           = &sysctl_sctp_rmem,
                .maxlen         = sizeof(sysctl_sctp_rmem),
@@ -249,7 +213,6 @@ static ctl_table sctp_table[] = {
                .proc_handler   = proc_dointvec,
        },
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "sctp_wmem",
                .data           = &sysctl_sctp_wmem,
                .maxlen         = sizeof(sysctl_sctp_wmem),
@@ -257,52 +220,44 @@ static ctl_table sctp_table[] = {
                .proc_handler   = proc_dointvec,
        },
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "auth_enable",
                .data           = &sctp_auth_enable,
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec,
-               .strategy       = sysctl_intvec
        },
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "addip_noauth_enable",
                .data           = &sctp_addip_noauth,
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec,
-               .strategy       = sysctl_intvec
        },
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "addr_scope_policy",
                .data           = &sctp_scope_policy,
                .maxlen         = sizeof(int),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec_minmax,
-               .strategy       = &sysctl_intvec,
+               .proc_handler   = proc_dointvec_minmax,
                .extra1         = &zero,
                .extra2         = &addr_scope_max,
        },
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "rwnd_update_shift",
                .data           = &sctp_rwnd_upd_shift,
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = &proc_dointvec_minmax,
-               .strategy       = &sysctl_intvec,
                .extra1         = &one,
                .extra2         = &rwnd_scale_max,
        },
 
-       { .ctl_name = 0 }
+       { /* sentinel */ }
 };
 
 static struct ctl_path sctp_path[] = {
-       { .procname = "net", .ctl_name = CTL_NET, },
-       { .procname = "sctp", .ctl_name = NET_SCTP, },
+       { .procname = "net", },
+       { .procname = "sctp", },
        { }
 };
 
index 42f9748..e65dcc6 100644 (file)
@@ -139,46 +139,45 @@ static ctl_table debug_table[] = {
                .data           = &rpc_debug,
                .maxlen         = sizeof(int),
                .mode           = 0644,
-               .proc_handler   = &proc_dodebug
+               .proc_handler   = proc_dodebug
        },
        {
                .procname       = "nfs_debug",
                .data           = &nfs_debug,
                .maxlen         = sizeof(int),
                .mode           = 0644,
-               .proc_handler   = &proc_dodebug
+               .proc_handler   = proc_dodebug
        },
        {
                .procname       = "nfsd_debug",
                .data           = &nfsd_debug,
                .maxlen         = sizeof(int),
                .mode           = 0644,
-               .proc_handler   = &proc_dodebug
+               .proc_handler   = proc_dodebug
        },
        {
                .procname       = "nlm_debug",
                .data           = &nlm_debug,
                .maxlen         = sizeof(int),
                .mode           = 0644,
-               .proc_handler   = &proc_dodebug
+               .proc_handler   = proc_dodebug
        },
        {
                .procname       = "transports",
                .maxlen         = 256,
                .mode           = 0444,
-               .proc_handler   = &proc_do_xprt,
+               .proc_handler   = proc_do_xprt,
        },
-       { .ctl_name = 0 }
+       { }
 };
 
 static ctl_table sunrpc_table[] = {
        {
-               .ctl_name       = CTL_SUNRPC,
                .procname       = "sunrpc",
                .mode           = 0555,
                .child          = debug_table
        },
-       { .ctl_name = 0 }
+       { }
 };
 
 #endif
index 35fb68b..5b8a8ff 100644 (file)
@@ -120,8 +120,7 @@ static ctl_table svcrdma_parm_table[] = {
                .data           = &svcrdma_max_requests,
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec_minmax,
-               .strategy       = &sysctl_intvec,
+               .proc_handler   = proc_dointvec_minmax,
                .extra1         = &min_max_requests,
                .extra2         = &max_max_requests
        },
@@ -130,8 +129,7 @@ static ctl_table svcrdma_parm_table[] = {
                .data           = &svcrdma_max_req_size,
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec_minmax,
-               .strategy       = &sysctl_intvec,
+               .proc_handler   = proc_dointvec_minmax,
                .extra1         = &min_max_inline,
                .extra2         = &max_max_inline
        },
@@ -140,8 +138,7 @@ static ctl_table svcrdma_parm_table[] = {
                .data           = &svcrdma_ord,
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec_minmax,
-               .strategy       = &sysctl_intvec,
+               .proc_handler   = proc_dointvec_minmax,
                .extra1         = &min_ord,
                .extra2         = &max_ord,
        },
@@ -151,67 +148,65 @@ static ctl_table svcrdma_parm_table[] = {
                .data           = &rdma_stat_read,
                .maxlen         = sizeof(atomic_t),
                .mode           = 0644,
-               .proc_handler   = &read_reset_stat,
+               .proc_handler   = read_reset_stat,
        },
        {
                .procname       = "rdma_stat_recv",
                .data           = &rdma_stat_recv,
                .maxlen         = sizeof(atomic_t),
                .mode           = 0644,
-               .proc_handler   = &read_reset_stat,
+               .proc_handler   = read_reset_stat,
        },
        {
                .procname       = "rdma_stat_write",
                .data           = &rdma_stat_write,
                .maxlen         = sizeof(atomic_t),
                .mode           = 0644,
-               .proc_handler   = &read_reset_stat,
+               .proc_handler   = read_reset_stat,
        },
        {
                .procname       = "rdma_stat_sq_starve",
                .data           = &rdma_stat_sq_starve,
                .maxlen         = sizeof(atomic_t),
                .mode           = 0644,
-               .proc_handler   = &read_reset_stat,
+               .proc_handler   = read_reset_stat,
        },
        {
                .procname       = "rdma_stat_rq_starve",
                .data           = &rdma_stat_rq_starve,
                .maxlen         = sizeof(atomic_t),
                .mode           = 0644,
-               .proc_handler   = &read_reset_stat,
+               .proc_handler   = read_reset_stat,
        },
        {
                .procname       = "rdma_stat_rq_poll",
                .data           = &rdma_stat_rq_poll,
                .maxlen         = sizeof(atomic_t),
                .mode           = 0644,
-               .proc_handler   = &read_reset_stat,
+               .proc_handler   = read_reset_stat,
        },
        {
                .procname       = "rdma_stat_rq_prod",
                .data           = &rdma_stat_rq_prod,
                .maxlen         = sizeof(atomic_t),
                .mode           = 0644,
-               .proc_handler   = &read_reset_stat,
+               .proc_handler   = read_reset_stat,
        },
        {
                .procname       = "rdma_stat_sq_poll",
                .data           = &rdma_stat_sq_poll,
                .maxlen         = sizeof(atomic_t),
                .mode           = 0644,
-               .proc_handler   = &read_reset_stat,
+               .proc_handler   = read_reset_stat,
        },
        {
                .procname       = "rdma_stat_sq_prod",
                .data           = &rdma_stat_sq_prod,
                .maxlen         = sizeof(atomic_t),
                .mode           = 0644,
-               .proc_handler   = &read_reset_stat,
-       },
-       {
-               .ctl_name = 0,
+               .proc_handler   = read_reset_stat,
        },
+       { },
 };
 
 static ctl_table svcrdma_table[] = {
@@ -220,21 +215,16 @@ static ctl_table svcrdma_table[] = {
                .mode           = 0555,
                .child          = svcrdma_parm_table
        },
-       {
-               .ctl_name = 0,
-       },
+       { },
 };
 
 static ctl_table svcrdma_root_table[] = {
        {
-               .ctl_name       = CTL_SUNRPC,
                .procname       = "sunrpc",
                .mode           = 0555,
                .child          = svcrdma_table
        },
-       {
-               .ctl_name = 0,
-       },
+       { },
 };
 
 void svc_rdma_cleanup(void)
index 9a63f66..7018eef 100644 (file)
@@ -86,79 +86,63 @@ static struct ctl_table_header *sunrpc_table_header;
 
 static ctl_table xr_tunables_table[] = {
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "rdma_slot_table_entries",
                .data           = &xprt_rdma_slot_table_entries,
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec_minmax,
-               .strategy       = &sysctl_intvec,
+               .proc_handler   = proc_dointvec_minmax,
                .extra1         = &min_slot_table_size,
                .extra2         = &max_slot_table_size
        },
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "rdma_max_inline_read",
                .data           = &xprt_rdma_max_inline_read,
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec,
-               .strategy       = &sysctl_intvec,
+               .proc_handler   = proc_dointvec,
        },
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "rdma_max_inline_write",
                .data           = &xprt_rdma_max_inline_write,
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec,
-               .strategy       = &sysctl_intvec,
+               .proc_handler   = proc_dointvec,
        },
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "rdma_inline_write_padding",
                .data           = &xprt_rdma_inline_write_padding,
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec_minmax,
-               .strategy       = &sysctl_intvec,
+               .proc_handler   = proc_dointvec_minmax,
                .extra1         = &zero,
                .extra2         = &max_padding,
        },
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "rdma_memreg_strategy",
                .data           = &xprt_rdma_memreg_strategy,
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec_minmax,
-               .strategy       = &sysctl_intvec,
+               .proc_handler   = proc_dointvec_minmax,
                .extra1         = &min_memreg,
                .extra2         = &max_memreg,
        },
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "rdma_pad_optimize",
                .data           = &xprt_rdma_pad_optimize,
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec,
-       },
-       {
-               .ctl_name = 0,
+               .proc_handler   = proc_dointvec,
        },
+       { },
 };
 
 static ctl_table sunrpc_table[] = {
        {
-               .ctl_name       = CTL_SUNRPC,
                .procname       = "sunrpc",
                .mode           = 0555,
                .child          = xr_tunables_table
        },
-       {
-               .ctl_name = 0,
-       },
+       { },
 };
 
 #endif
index 37c5475..04732d0 100644 (file)
@@ -81,46 +81,38 @@ static struct ctl_table_header *sunrpc_table_header;
  */
 static ctl_table xs_tunables_table[] = {
        {
-               .ctl_name       = CTL_SLOTTABLE_UDP,
                .procname       = "udp_slot_table_entries",
                .data           = &xprt_udp_slot_table_entries,
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec_minmax,
-               .strategy       = &sysctl_intvec,
+               .proc_handler   = proc_dointvec_minmax,
                .extra1         = &min_slot_table_size,
                .extra2         = &max_slot_table_size
        },
        {
-               .ctl_name       = CTL_SLOTTABLE_TCP,
                .procname       = "tcp_slot_table_entries",
                .data           = &xprt_tcp_slot_table_entries,
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec_minmax,
-               .strategy       = &sysctl_intvec,
+               .proc_handler   = proc_dointvec_minmax,
                .extra1         = &min_slot_table_size,
                .extra2         = &max_slot_table_size
        },
        {
-               .ctl_name       = CTL_MIN_RESVPORT,
                .procname       = "min_resvport",
                .data           = &xprt_min_resvport,
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec_minmax,
-               .strategy       = &sysctl_intvec,
+               .proc_handler   = proc_dointvec_minmax,
                .extra1         = &xprt_min_resvport_limit,
                .extra2         = &xprt_max_resvport_limit
        },
        {
-               .ctl_name       = CTL_MAX_RESVPORT,
                .procname       = "max_resvport",
                .data           = &xprt_max_resvport,
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec_minmax,
-               .strategy       = &sysctl_intvec,
+               .proc_handler   = proc_dointvec_minmax,
                .extra1         = &xprt_min_resvport_limit,
                .extra2         = &xprt_max_resvport_limit
        },
@@ -129,24 +121,18 @@ static ctl_table xs_tunables_table[] = {
                .data           = &xs_tcp_fin_timeout,
                .maxlen         = sizeof(xs_tcp_fin_timeout),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec_jiffies,
-               .strategy       = sysctl_jiffies
-       },
-       {
-               .ctl_name = 0,
+               .proc_handler   = proc_dointvec_jiffies,
        },
+       { },
 };
 
 static ctl_table sunrpc_table[] = {
        {
-               .ctl_name       = CTL_SUNRPC,
                .procname       = "sunrpc",
                .mode           = 0555,
                .child          = xs_tunables_table
        },
-       {
-               .ctl_name = 0,
-       },
+       { },
 };
 
 #endif
index 83c0930..708f5df 100644 (file)
 
 static ctl_table unix_table[] = {
        {
-               .ctl_name       = NET_UNIX_MAX_DGRAM_QLEN,
                .procname       = "max_dgram_qlen",
                .data           = &init_net.unx.sysctl_max_dgram_qlen,
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec
        },
-       { .ctl_name = 0 }
+       { }
 };
 
 static struct ctl_path unix_path[] = {
-       { .procname = "net", .ctl_name = CTL_NET, },
-       { .procname = "unix", .ctl_name = NET_UNIX, },
+       { .procname = "net", },
+       { .procname = "unix", },
        { },
 };
 
index a5d3416..d2efd29 100644 (file)
@@ -19,62 +19,51 @@ static struct ctl_table_header *x25_table_header;
 
 static struct ctl_table x25_table[] = {
        {
-               .ctl_name =     NET_X25_RESTART_REQUEST_TIMEOUT,
                .procname =     "restart_request_timeout",
                .data =         &sysctl_x25_restart_request_timeout,
                .maxlen =       sizeof(int),
                .mode =         0644,
                .proc_handler = proc_dointvec_minmax,
-               .strategy =     sysctl_intvec,
                .extra1 =       &min_timer,
                .extra2 =       &max_timer,
        },
        {
-               .ctl_name =     NET_X25_CALL_REQUEST_TIMEOUT,
                .procname =     "call_request_timeout",
                .data =         &sysctl_x25_call_request_timeout,
                .maxlen =       sizeof(int),
                .mode =         0644,
                .proc_handler = proc_dointvec_minmax,
-               .strategy =     sysctl_intvec,
                .extra1 =       &min_timer,
                .extra2 =       &max_timer,
        },
        {
-               .ctl_name =     NET_X25_RESET_REQUEST_TIMEOUT,
                .procname =     "reset_request_timeout",
                .data =         &sysctl_x25_reset_request_timeout,
                .maxlen =       sizeof(int),
                .mode =         0644,
                .proc_handler = proc_dointvec_minmax,
-               .strategy =     sysctl_intvec,
                .extra1 =       &min_timer,
                .extra2 =       &max_timer,
        },
        {
-               .ctl_name =     NET_X25_CLEAR_REQUEST_TIMEOUT,
                .procname =     "clear_request_timeout",
                .data =         &sysctl_x25_clear_request_timeout,
                .maxlen =       sizeof(int),
                .mode =         0644,
                .proc_handler = proc_dointvec_minmax,
-               .strategy =     sysctl_intvec,
                .extra1 =       &min_timer,
                .extra2 =       &max_timer,
        },
        {
-               .ctl_name =     NET_X25_ACK_HOLD_BACK_TIMEOUT,
                .procname =     "acknowledgement_hold_back_timeout",
                .data =         &sysctl_x25_ack_holdback_timeout,
                .maxlen =       sizeof(int),
                .mode =         0644,
                .proc_handler = proc_dointvec_minmax,
-               .strategy =     sysctl_intvec,
                .extra1 =       &min_timer,
                .extra2 =       &max_timer,
        },
        {
-               .ctl_name =     NET_X25_FORWARD,
                .procname =     "x25_forward",
                .data =         &sysctl_x25_forward,
                .maxlen =       sizeof(int),
@@ -85,8 +74,8 @@ static struct ctl_table x25_table[] = {
 };
 
 static struct ctl_path x25_path[] = {
-       { .procname = "net", .ctl_name = CTL_NET, },
-       { .procname = "x25", .ctl_name = NET_X25, },
+       { .procname = "net", },
+       { .procname = "x25", },
        { }
 };
 
index 2e6ffb6..2e221f2 100644 (file)
@@ -13,28 +13,24 @@ static void __xfrm_sysctl_init(struct net *net)
 #ifdef CONFIG_SYSCTL
 static struct ctl_table xfrm_table[] = {
        {
-               .ctl_name       = NET_CORE_AEVENT_ETIME,
                .procname       = "xfrm_aevent_etime",
                .maxlen         = sizeof(u32),
                .mode           = 0644,
                .proc_handler   = proc_dointvec
        },
        {
-               .ctl_name       = NET_CORE_AEVENT_RSEQTH,
                .procname       = "xfrm_aevent_rseqth",
                .maxlen         = sizeof(u32),
                .mode           = 0644,
                .proc_handler   = proc_dointvec
        },
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "xfrm_larval_drop",
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec
        },
        {
-               .ctl_name       = CTL_UNNUMBERED,
                .procname       = "xfrm_acq_expires",
                .maxlen         = sizeof(int),
                .mode           = 0644,
index b92bde3..e4be84a 100644 (file)
@@ -40,5 +40,11 @@ config SAMPLE_KRETPROBES
        default m
        depends on SAMPLE_KPROBES && KRETPROBES
 
+config SAMPLE_HW_BREAKPOINT
+       tristate "Build kernel hardware breakpoint examples -- loadable module only"
+       depends on HAVE_HW_BREAKPOINT && m
+       help
+         This builds kernel hardware breakpoint example modules.
+
 endif # SAMPLES
 
index 43343a0..0f15e6d 100644 (file)
@@ -1,3 +1,4 @@
 # Makefile for Linux samples code
 
-obj-$(CONFIG_SAMPLES)  += kobject/ kprobes/ tracepoints/ trace_events/
+obj-$(CONFIG_SAMPLES)  += kobject/ kprobes/ tracepoints/ trace_events/ \
+                          hw_breakpoint/
diff --git a/samples/hw_breakpoint/Makefile b/samples/hw_breakpoint/Makefile
new file mode 100644 (file)
index 0000000..0f5c31c
--- /dev/null
@@ -0,0 +1 @@
+obj-$(CONFIG_SAMPLE_HW_BREAKPOINT) += data_breakpoint.o
diff --git a/samples/hw_breakpoint/data_breakpoint.c b/samples/hw_breakpoint/data_breakpoint.c
new file mode 100644 (file)
index 0000000..2952550
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * data_breakpoint.c - Sample HW Breakpoint file to watch kernel data address
+ *
+ * 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.
+ *
+ * usage: insmod data_breakpoint.ko ksym=<ksym_name>
+ *
+ * This file is a kernel module that places a breakpoint over ksym_name kernel
+ * variable using Hardware Breakpoint register. The corresponding handler which
+ * prints a backtrace is invoked everytime a write operation is performed on
+ * that variable.
+ *
+ * Copyright (C) IBM Corporation, 2009
+ *
+ * Author: K.Prasad <prasad@linux.vnet.ibm.com>
+ */
+#include <linux/module.h>      /* Needed by all modules */
+#include <linux/kernel.h>      /* Needed for KERN_INFO */
+#include <linux/init.h>                /* Needed for the macros */
+#include <linux/kallsyms.h>
+
+#include <linux/perf_event.h>
+#include <linux/hw_breakpoint.h>
+
+struct perf_event **sample_hbp;
+
+static char ksym_name[KSYM_NAME_LEN] = "pid_max";
+module_param_string(ksym, ksym_name, KSYM_NAME_LEN, S_IRUGO);
+MODULE_PARM_DESC(ksym, "Kernel symbol to monitor; this module will report any"
+                       " write operations on the kernel symbol");
+
+static void sample_hbp_handler(struct perf_event *temp, void *data)
+{
+       printk(KERN_INFO "%s value is changed\n", ksym_name);
+       dump_stack();
+       printk(KERN_INFO "Dump stack from sample_hbp_handler\n");
+}
+
+static int __init hw_break_module_init(void)
+{
+       int ret;
+       DEFINE_BREAKPOINT_ATTR(attr);
+
+       attr.bp_addr = kallsyms_lookup_name(ksym_name);
+       attr.bp_len = HW_BREAKPOINT_LEN_4;
+       attr.bp_type = HW_BREAKPOINT_W | HW_BREAKPOINT_R;
+
+       sample_hbp = register_wide_hw_breakpoint(&attr, sample_hbp_handler);
+       if (IS_ERR(sample_hbp)) {
+               ret = PTR_ERR(sample_hbp);
+               goto fail;
+       }
+
+       printk(KERN_INFO "HW Breakpoint for %s write installed\n", ksym_name);
+
+       return 0;
+
+fail:
+       printk(KERN_INFO "Breakpoint registration failed\n");
+
+       return ret;
+}
+
+static void __exit hw_break_module_exit(void)
+{
+       unregister_wide_hw_breakpoint(sample_hbp);
+       printk(KERN_INFO "HW Breakpoint for %s write uninstalled\n", ksym_name);
+}
+
+module_init(hw_break_module_init);
+module_exit(hw_break_module_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("K.Prasad");
+MODULE_DESCRIPTION("ksym breakpoint");
index ea9f8a5..241310e 100755 (executable)
@@ -1852,10 +1852,17 @@ sub tracepoint_munge($) {
        my $tracepointname = 0;
        my $tracepointargs = 0;
 
-       if($prototype =~ m/TRACE_EVENT\((.*?),/) {
+       if ($prototype =~ m/TRACE_EVENT\((.*?),/) {
                $tracepointname = $1;
        }
-       if($prototype =~ m/TP_PROTO\((.*?)\)/) {
+       if ($prototype =~ m/DEFINE_SINGLE_EVENT\((.*?),/) {
+               $tracepointname = $1;
+       }
+       if ($prototype =~ m/DEFINE_EVENT\((.*?),(.*?),/) {
+               $tracepointname = $2;
+       }
+       $tracepointname =~ s/^\s+//; #strip leading whitespace
+       if ($prototype =~ m/TP_PROTO\((.*?)\)/) {
                $tracepointargs = $1;
        }
        if (($tracepointname eq 0) || ($tracepointargs eq 0)) {
@@ -1920,7 +1927,9 @@ sub process_state3_function($$) {
        if ($prototype =~ /SYSCALL_DEFINE/) {
                syscall_munge();
        }
-       if ($prototype =~ /TRACE_EVENT/) {
+       if ($prototype =~ /TRACE_EVENT/ || $prototype =~ /DEFINE_EVENT/ ||
+           $prototype =~ /DEFINE_SINGLE_EVENT/)
+       {
                tracepoint_munge($file);
        }
        dump_function($prototype, $file);
index 5e05dc0..ee32d18 100644 (file)
@@ -17,54 +17,49 @@ static const int zero, one = 1, max = INT_MAX;
 
 ctl_table key_sysctls[] = {
        {
-               .ctl_name = CTL_UNNUMBERED,
                .procname = "maxkeys",
                .data = &key_quota_maxkeys,
                .maxlen = sizeof(unsigned),
                .mode = 0644,
-               .proc_handler = &proc_dointvec_minmax,
+               .proc_handler = proc_dointvec_minmax,
                .extra1 = (void *) &one,
                .extra2 = (void *) &max,
        },
        {
-               .ctl_name = CTL_UNNUMBERED,
                .procname = "maxbytes",
                .data = &key_quota_maxbytes,
                .maxlen = sizeof(unsigned),
                .mode = 0644,
-               .proc_handler = &proc_dointvec_minmax,
+               .proc_handler = proc_dointvec_minmax,
                .extra1 = (void *) &one,
                .extra2 = (void *) &max,
        },
        {
-               .ctl_name = CTL_UNNUMBERED,
                .procname = "root_maxkeys",
                .data = &key_quota_root_maxkeys,
                .maxlen = sizeof(unsigned),
                .mode = 0644,
-               .proc_handler = &proc_dointvec_minmax,
+               .proc_handler = proc_dointvec_minmax,
                .extra1 = (void *) &one,
                .extra2 = (void *) &max,
        },
        {
-               .ctl_name = CTL_UNNUMBERED,
                .procname = "root_maxbytes",
                .data = &key_quota_root_maxbytes,
                .maxlen = sizeof(unsigned),
                .mode = 0644,
-               .proc_handler = &proc_dointvec_minmax,
+               .proc_handler = proc_dointvec_minmax,
                .extra1 = (void *) &one,
                .extra2 = (void *) &max,
        },
        {
-               .ctl_name = CTL_UNNUMBERED,
                .procname = "gc_delay",
                .data = &key_gc_delay,
                .maxlen = sizeof(unsigned),
                .mode = 0644,
-               .proc_handler = &proc_dointvec_minmax,
+               .proc_handler = proc_dointvec_minmax,
                .extra1 = (void *) &zero,
                .extra2 = (void *) &max,
        },
-       { .ctl_name = 0 }
+       { }
 };
index 5ae3a57..8346938 100644 (file)
@@ -1096,27 +1096,6 @@ static int tomoyo_check_single_path_permission2(struct tomoyo_domain_info *
 }
 
 /**
- * tomoyo_check_file_perm - Check permission for sysctl()'s "read" and "write".
- *
- * @domain:    Pointer to "struct tomoyo_domain_info".
- * @filename:  Filename to check.
- * @perm:      Mode ("read" or "write" or "read/write").
- * Returns 0 on success, negative value otherwise.
- */
-int tomoyo_check_file_perm(struct tomoyo_domain_info *domain,
-                          const char *filename, const u8 perm)
-{
-       struct tomoyo_path_info name;
-       const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE);
-
-       if (!mode)
-               return 0;
-       name.name = filename;
-       tomoyo_fill_path_info(&name);
-       return tomoyo_check_file_perm2(domain, &name, perm, "sysctl", mode);
-}
-
-/**
  * tomoyo_check_exec_perm - Check permission for "execute".
  *
  * @domain:   Pointer to "struct tomoyo_domain_info".
index 917f564..18369d4 100644 (file)
@@ -110,6 +110,15 @@ int tomoyo_realpath_from_path2(struct path *path, char *newname,
                spin_unlock(&dcache_lock);
                path_put(&root);
                path_put(&ns_root);
+               /* Prepend "/proc" prefix if using internal proc vfs mount. */
+               if (!IS_ERR(sp) && (path->mnt->mnt_parent == path->mnt) &&
+                   (strcmp(path->mnt->mnt_sb->s_type->name, "proc") == 0)) {
+                       sp -= 5;
+                       if (sp >= newname)
+                               memcpy(sp, "/proc", 5);
+                       else
+                               sp = ERR_PTR(-ENOMEM);
+               }
        }
        if (IS_ERR(sp))
                error = PTR_ERR(sp);
index 9548a09..8a00ade 100644 (file)
@@ -85,83 +85,6 @@ static int tomoyo_bprm_check_security(struct linux_binprm *bprm)
        return tomoyo_check_open_permission(domain, &bprm->file->f_path, 1);
 }
 
-#ifdef CONFIG_SYSCTL
-
-static int tomoyo_prepend(char **buffer, int *buflen, const char *str)
-{
-       int namelen = strlen(str);
-
-       if (*buflen < namelen)
-               return -ENOMEM;
-       *buflen -= namelen;
-       *buffer -= namelen;
-       memcpy(*buffer, str, namelen);
-       return 0;
-}
-
-/**
- * tomoyo_sysctl_path - return the realpath of a ctl_table.
- * @table: pointer to "struct ctl_table".
- *
- * Returns realpath(3) of the @table on success.
- * Returns NULL on failure.
- *
- * This function uses tomoyo_alloc(), so the caller must call tomoyo_free()
- * if this function didn't return NULL.
- */
-static char *tomoyo_sysctl_path(struct ctl_table *table)
-{
-       int buflen = TOMOYO_MAX_PATHNAME_LEN;
-       char *buf = tomoyo_alloc(buflen);
-       char *end = buf + buflen;
-       int error = -ENOMEM;
-
-       if (!buf)
-               return NULL;
-
-       *--end = '\0';
-       buflen--;
-       while (table) {
-               char num[32];
-               const char *sp = table->procname;
-
-               if (!sp) {
-                       memset(num, 0, sizeof(num));
-                       snprintf(num, sizeof(num) - 1, "=%d=", table->ctl_name);
-                       sp = num;
-               }
-               if (tomoyo_prepend(&end, &buflen, sp) ||
-                   tomoyo_prepend(&end, &buflen, "/"))
-                       goto out;
-               table = table->parent;
-       }
-       if (tomoyo_prepend(&end, &buflen, "/proc/sys"))
-               goto out;
-       error = tomoyo_encode(buf, end - buf, end);
- out:
-       if (!error)
-               return buf;
-       tomoyo_free(buf);
-       return NULL;
-}
-
-static int tomoyo_sysctl(struct ctl_table *table, int op)
-{
-       int error;
-       char *name;
-
-       op &= MAY_READ | MAY_WRITE;
-       if (!op)
-               return 0;
-       name = tomoyo_sysctl_path(table);
-       if (!name)
-               return -ENOMEM;
-       error = tomoyo_check_file_perm(tomoyo_domain(), name, op);
-       tomoyo_free(name);
-       return error;
-}
-#endif
-
 static int tomoyo_path_truncate(struct path *path, loff_t length,
                                unsigned int time_attrs)
 {
@@ -282,9 +205,6 @@ static struct security_operations tomoyo_security_ops = {
        .cred_transfer       = tomoyo_cred_transfer,
        .bprm_set_creds      = tomoyo_bprm_set_creds,
        .bprm_check_security = tomoyo_bprm_check_security,
-#ifdef CONFIG_SYSCTL
-       .sysctl              = tomoyo_sysctl,
-#endif
        .file_fcntl          = tomoyo_file_fcntl,
        .dentry_open         = tomoyo_dentry_open,
        .path_truncate       = tomoyo_path_truncate,
index cd6ba0b..ed75832 100644 (file)
@@ -18,8 +18,6 @@ struct inode;
 struct linux_binprm;
 struct pt_regs;
 
-int tomoyo_check_file_perm(struct tomoyo_domain_info *domain,
-                          const char *filename, const u8 perm);
 int tomoyo_check_exec_perm(struct tomoyo_domain_info *domain,
                           const struct tomoyo_path_info *filename);
 int tomoyo_check_open_permission(struct tomoyo_domain_info *domain,
index 439e15c..b3e53e6 100644 (file)
@@ -58,7 +58,7 @@ config SOUND_OSS_CORE_PRECLAIM
          Please read Documentation/feature-removal-schedule.txt for
          details.
 
-         If unusre, say Y.
+         If unsure, say Y.
 
 source "sound/oss/dmasound/Kconfig"
 
index 5a549ed..8c0c851 100644 (file)
@@ -3,7 +3,7 @@
 #
 
 obj-$(CONFIG_SND_ARMAACI)      += snd-aaci.o
-snd-aaci-objs                  := aaci.o devdma.o
+snd-aaci-objs                  := aaci.o
 
 obj-$(CONFIG_SND_PXA2XX_PCM)   += snd-pxa2xx-pcm.o
 snd-pxa2xx-pcm-objs            := pxa2xx-pcm.o
index 6c160a0..1497dce 100644 (file)
 #include <linux/interrupt.h>
 #include <linux/err.h>
 #include <linux/amba/bus.h>
-
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/sizes.h>
+#include <linux/io.h>
 
 #include <sound/core.h>
 #include <sound/initval.h>
@@ -30,7 +27,6 @@
 #include <sound/pcm_params.h>
 
 #include "aaci.h"
-#include "devdma.h"
 
 #define DRIVER_NAME    "aaci-pl041"
 
@@ -492,7 +488,7 @@ static int aaci_pcm_hw_free(struct snd_pcm_substream *substream)
        /*
         * Clear out the DMA and any allocated buffers.
         */
-       devdma_hw_free(NULL, substream);
+       snd_pcm_lib_free_pages(substream);
 
        return 0;
 }
@@ -509,20 +505,14 @@ static int aaci_pcm_hw_params(struct snd_pcm_substream *substream,
                aacirun->pcm_open = 0;
        }
 
-       err = devdma_hw_alloc(NULL, substream,
-                             params_buffer_bytes(params));
+       err = snd_pcm_lib_malloc_pages(substream,
+                                      params_buffer_bytes(params));
        if (err < 0)
                goto out;
 
-       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-               err = snd_ac97_pcm_open(aacirun->pcm, params_rate(params),
-                                       params_channels(params),
-                                       aacirun->pcm->r[0].slots);
-       else
-               err = snd_ac97_pcm_open(aacirun->pcm, params_rate(params),
-                                       params_channels(params),
-                                       aacirun->pcm->r[0].slots);
-
+       err = snd_ac97_pcm_open(aacirun->pcm, params_rate(params),
+                               params_channels(params),
+                               aacirun->pcm->r[0].slots);
        if (err)
                goto out;
 
@@ -538,7 +528,7 @@ static int aaci_pcm_prepare(struct snd_pcm_substream *substream)
        struct aaci_runtime *aacirun = runtime->private_data;
 
        aacirun->start  = (void *)runtime->dma_area;
-       aacirun->end    = aacirun->start + runtime->dma_bytes;
+       aacirun->end    = aacirun->start + snd_pcm_lib_buffer_bytes(substream);
        aacirun->ptr    = aacirun->start;
        aacirun->period =
        aacirun->bytes  = frames_to_bytes(runtime, runtime->period_size);
@@ -555,11 +545,6 @@ static snd_pcm_uframes_t aaci_pcm_pointer(struct snd_pcm_substream *substream)
        return bytes_to_frames(runtime, bytes);
 }
 
-static int aaci_pcm_mmap(struct snd_pcm_substream *substream, struct vm_area_struct *vma)
-{
-       return devdma_mmap(NULL, substream, vma);
-}
-
 
 /*
  * Playback specific ALSA stuff
@@ -726,7 +711,6 @@ static struct snd_pcm_ops aaci_playback_ops = {
        .prepare        = aaci_pcm_prepare,
        .trigger        = aaci_pcm_playback_trigger,
        .pointer        = aaci_pcm_pointer,
-       .mmap           = aaci_pcm_mmap,
 };
 
 static int aaci_pcm_capture_hw_params(struct snd_pcm_substream *substream,
@@ -854,7 +838,6 @@ static struct snd_pcm_ops aaci_capture_ops = {
        .prepare        = aaci_pcm_capture_prepare,
        .trigger        = aaci_pcm_capture_trigger,
        .pointer        = aaci_pcm_pointer,
-       .mmap           = aaci_pcm_mmap,
 };
 
 /*
@@ -1044,6 +1027,8 @@ static int __devinit aaci_init_pcm(struct aaci *aaci)
 
                snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &aaci_playback_ops);
                snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &aaci_capture_ops);
+               snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
+                                                     NULL, 0, 64 * 104);
        }
 
        return ret;
diff --git a/sound/arm/devdma.c b/sound/arm/devdma.c
deleted file mode 100644 (file)
index 9d1e666..0000000
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- *  linux/sound/arm/devdma.c
- *
- *  Copyright (C) 2003-2004 Russell King, All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- *  ARM DMA shim for ALSA.
- */
-#include <linux/device.h>
-#include <linux/dma-mapping.h>
-
-#include <sound/core.h>
-#include <sound/pcm.h>
-
-#include "devdma.h"
-
-void devdma_hw_free(struct device *dev, struct snd_pcm_substream *substream)
-{
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       struct snd_dma_buffer *buf = runtime->dma_buffer_p;
-
-       if (runtime->dma_area == NULL)
-               return;
-
-       if (buf != &substream->dma_buffer) {
-               dma_free_coherent(buf->dev.dev, buf->bytes, buf->area, buf->addr);
-               kfree(runtime->dma_buffer_p);
-       }
-
-       snd_pcm_set_runtime_buffer(substream, NULL);
-}
-
-int devdma_hw_alloc(struct device *dev, struct snd_pcm_substream *substream, size_t size)
-{
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       struct snd_dma_buffer *buf = runtime->dma_buffer_p;
-       int ret = 0;
-
-       if (buf) {
-               if (buf->bytes >= size)
-                       goto out;
-               devdma_hw_free(dev, substream);
-       }
-
-       if (substream->dma_buffer.area != NULL && substream->dma_buffer.bytes >= size) {
-               buf = &substream->dma_buffer;
-       } else {
-               buf = kmalloc(sizeof(struct snd_dma_buffer), GFP_KERNEL);
-               if (!buf)
-                       goto nomem;
-
-               buf->dev.type = SNDRV_DMA_TYPE_DEV;
-               buf->dev.dev = dev;
-               buf->area = dma_alloc_coherent(dev, size, &buf->addr, GFP_KERNEL);
-               buf->bytes = size;
-               buf->private_data = NULL;
-
-               if (!buf->area)
-                       goto free;
-       }
-       snd_pcm_set_runtime_buffer(substream, buf);
-       ret = 1;
- out:
-       runtime->dma_bytes = size;
-       return ret;
-
- free:
-       kfree(buf);
- nomem:
-       return -ENOMEM;
-}
-
-int devdma_mmap(struct device *dev, struct snd_pcm_substream *substream, struct vm_area_struct *vma)
-{
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       return dma_mmap_coherent(dev, vma, runtime->dma_area, runtime->dma_addr, runtime->dma_bytes);
-}
diff --git a/sound/arm/devdma.h b/sound/arm/devdma.h
deleted file mode 100644 (file)
index d025329..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-void devdma_hw_free(struct device *dev, struct snd_pcm_substream *substream);
-int devdma_hw_alloc(struct device *dev, struct snd_pcm_substream *substream, size_t size);
-int devdma_mmap(struct device *dev, struct snd_pcm_substream *substream, struct vm_area_struct *vma);
index a8b7fab..268ab74 100644 (file)
@@ -75,7 +75,7 @@ static int snd_ctl_open(struct inode *inode, struct file *file)
        ctl->card = card;
        ctl->prefer_pcm_subdevice = -1;
        ctl->prefer_rawmidi_subdevice = -1;
-       ctl->pid = current->pid;
+       ctl->pid = get_pid(task_pid(current));
        file->private_data = ctl;
        write_lock_irqsave(&card->ctl_files_rwlock, flags);
        list_add_tail(&ctl->list, &card->ctl_files);
@@ -125,6 +125,7 @@ static int snd_ctl_release(struct inode *inode, struct file *file)
                                control->vd[idx].owner = NULL;
        up_write(&card->controls_rwsem);
        snd_ctl_empty_read_queue(ctl);
+       put_pid(ctl->pid);
        kfree(ctl);
        module_put(card->module);
        snd_card_file_remove(card, file);
@@ -672,7 +673,7 @@ static int snd_ctl_elem_info(struct snd_ctl_file *ctl,
                        info->access |= SNDRV_CTL_ELEM_ACCESS_LOCK;
                        if (vd->owner == ctl)
                                info->access |= SNDRV_CTL_ELEM_ACCESS_OWNER;
-                       info->owner = vd->owner_pid;
+                       info->owner = pid_vnr(vd->owner->pid);
                } else {
                        info->owner = -1;
                }
@@ -827,7 +828,6 @@ static int snd_ctl_elem_lock(struct snd_ctl_file *file,
                        result = -EBUSY;
                else {
                        vd->owner = file;
-                       vd->owner_pid = current->pid;
                        result = 0;
                }
        }
@@ -858,7 +858,6 @@ static int snd_ctl_elem_unlock(struct snd_ctl_file *file,
                        result = -EPERM;
                else {
                        vd->owner = NULL;
-                       vd->owner_pid = 0;
                        result = 0;
                }
        }
@@ -1120,7 +1119,7 @@ static int snd_ctl_tlv_ioctl(struct snd_ctl_file *file,
                goto __kctl_end;
        }
        if (vd->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) {
-               if (file && vd->owner != NULL && vd->owner != file) {
+               if (vd->owner != NULL && vd->owner != file) {
                        err = -EPERM;
                        goto __kctl_end;
                }
index 79f0f16..950e19b 100644 (file)
@@ -85,16 +85,24 @@ EXPORT_SYMBOL(snd_dma_disable);
 unsigned int snd_dma_pointer(unsigned long dma, unsigned int size)
 {
        unsigned long flags;
-       unsigned int result;
+       unsigned int result, result1;
 
        flags = claim_dma_lock();
        clear_dma_ff(dma);
        if (!isa_dma_bridge_buggy)
                disable_dma(dma);
        result = get_dma_residue(dma);
+       /*
+        * HACK - read the counter again and choose higher value in order to
+        * avoid reading during counter lower byte roll over if the
+        * isa_dma_bridge_buggy is set.
+        */
+       result1 = get_dma_residue(dma);
        if (!isa_dma_bridge_buggy)
                enable_dma(dma);
        release_dma_lock(flags);
+       if (unlikely(result < result1))
+               result = result1;
 #ifdef CONFIG_SND_DEBUG
        if (result > size)
                snd_printk(KERN_ERR "pointer (0x%x) for DMA #%ld is greater than transfer size (0x%x)\n", result, dma, size);
index 7724238..54e2eb5 100644 (file)
@@ -1251,7 +1251,9 @@ static void snd_mixer_oss_build(struct snd_mixer_oss *mixer)
                { SOUND_MIXER_SYNTH,    "FM",                   0 }, /* fallback */
                { SOUND_MIXER_SYNTH,    "Music",                0 }, /* fallback */
                { SOUND_MIXER_PCM,      "PCM",                  0 },
-               { SOUND_MIXER_SPEAKER,  "PC Speaker",           0 },
+               { SOUND_MIXER_SPEAKER,  "Beep",                 0 },
+               { SOUND_MIXER_SPEAKER,  "PC Speaker",           0 }, /* fallback */
+               { SOUND_MIXER_SPEAKER,  "Speaker",              0 }, /* fallback */
                { SOUND_MIXER_LINE,     "Line",                 0 },
                { SOUND_MIXER_MIC,      "Mic",                  0 },
                { SOUND_MIXER_CD,       "CD",                   0 },
index c69c60b..6884ae0 100644 (file)
@@ -435,6 +435,7 @@ static void snd_pcm_substream_proc_status_read(struct snd_info_entry *entry,
                return;
        }
        snd_iprintf(buffer, "state: %s\n", snd_pcm_state_name(status.state));
+       snd_iprintf(buffer, "owner_pid   : %d\n", pid_vnr(substream->pid));
        snd_iprintf(buffer, "trigger_time: %ld.%09ld\n",
                status.trigger_tstamp.tv_sec, status.trigger_tstamp.tv_nsec);
        snd_iprintf(buffer, "tstamp      : %ld.%09ld\n",
@@ -809,7 +810,7 @@ int snd_pcm_attach_substream(struct snd_pcm *pcm, int stream,
        card = pcm->card;
        read_lock(&card->ctl_files_rwlock);
        list_for_each_entry(kctl, &card->ctl_files, list) {
-               if (kctl->pid == current->pid) {
+               if (kctl->pid == task_pid(current)) {
                        prefer_subdevice = kctl->prefer_pcm_subdevice;
                        if (prefer_subdevice != -1)
                                break;
@@ -900,6 +901,7 @@ int snd_pcm_attach_substream(struct snd_pcm *pcm, int stream,
        substream->private_data = pcm->private_data;
        substream->ref_count = 1;
        substream->f_flags = file->f_flags;
+       substream->pid = get_pid(task_pid(current));
        pstr->substream_opened++;
        *rsubstream = substream;
        return 0;
@@ -921,6 +923,8 @@ void snd_pcm_detach_substream(struct snd_pcm_substream *substream)
        kfree(runtime->hw_constraints.rules);
        kfree(runtime);
        substream->runtime = NULL;
+       put_pid(substream->pid);
+       substream->pid = NULL;
        substream->pstr->substream_opened--;
 }
 
index ab73edf..29ab46a 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/time.h>
 #include <linux/pm_qos_params.h>
 #include <linux/uio.h>
+#include <linux/dma-mapping.h>
 #include <sound/core.h>
 #include <sound/control.h>
 #include <sound/info.h>
@@ -3061,6 +3062,27 @@ static int snd_pcm_mmap_control(struct snd_pcm_substream *substream, struct file
 }
 #endif /* coherent mmap */
 
+static inline struct page *
+snd_pcm_default_page_ops(struct snd_pcm_substream *substream, unsigned long ofs)
+{
+       void *vaddr = substream->runtime->dma_area + ofs;
+#if defined(CONFIG_MIPS) && defined(CONFIG_DMA_NONCOHERENT)
+       if (substream->dma_buffer.dev.type == SNDRV_DMA_TYPE_DEV)
+               return virt_to_page(CAC_ADDR(vaddr));
+#endif
+#if defined(CONFIG_PPC32) && defined(CONFIG_NOT_COHERENT_CACHE)
+       if (substream->dma_buffer.dev.type == SNDRV_DMA_TYPE_DEV) {
+               dma_addr_t addr = substream->runtime->dma_addr + ofs;
+               addr -= get_dma_offset(substream->dma_buffer.dev.dev);
+               /* assume dma_handle set via pfn_to_phys() in
+                * mm/dma-noncoherent.c
+                */
+               return pfn_to_page(addr >> PAGE_SHIFT);
+       }
+#endif
+       return virt_to_page(vaddr);
+}
+
 /*
  * fault callback for mmapping a RAM page
  */
@@ -3071,7 +3093,6 @@ static int snd_pcm_mmap_data_fault(struct vm_area_struct *area,
        struct snd_pcm_runtime *runtime;
        unsigned long offset;
        struct page * page;
-       void *vaddr;
        size_t dma_bytes;
        
        if (substream == NULL)
@@ -3081,36 +3102,53 @@ static int snd_pcm_mmap_data_fault(struct vm_area_struct *area,
        dma_bytes = PAGE_ALIGN(runtime->dma_bytes);
        if (offset > dma_bytes - PAGE_SIZE)
                return VM_FAULT_SIGBUS;
-       if (substream->ops->page) {
+       if (substream->ops->page)
                page = substream->ops->page(substream, offset);
-               if (!page)
-                       return VM_FAULT_SIGBUS;
-       } else {
-               vaddr = runtime->dma_area + offset;
-               page = virt_to_page(vaddr);
-       }
+       else
+               page = snd_pcm_default_page_ops(substream, offset);
+       if (!page)
+               return VM_FAULT_SIGBUS;
        get_page(page);
        vmf->page = page;
        return 0;
 }
 
-static const struct vm_operations_struct snd_pcm_vm_ops_data =
-{
+static const struct vm_operations_struct snd_pcm_vm_ops_data = {
+       .open =         snd_pcm_mmap_data_open,
+       .close =        snd_pcm_mmap_data_close,
+};
+
+static const struct vm_operations_struct snd_pcm_vm_ops_data_fault = {
        .open =         snd_pcm_mmap_data_open,
        .close =        snd_pcm_mmap_data_close,
        .fault =        snd_pcm_mmap_data_fault,
 };
 
+#ifndef ARCH_HAS_DMA_MMAP_COHERENT
+/* This should be defined / handled globally! */
+#ifdef CONFIG_ARM
+#define ARCH_HAS_DMA_MMAP_COHERENT
+#endif
+#endif
+
 /*
  * mmap the DMA buffer on RAM
  */
 static int snd_pcm_default_mmap(struct snd_pcm_substream *substream,
                                struct vm_area_struct *area)
 {
-       area->vm_ops = &snd_pcm_vm_ops_data;
-       area->vm_private_data = substream;
        area->vm_flags |= VM_RESERVED;
-       atomic_inc(&substream->mmap_count);
+#ifdef ARCH_HAS_DMA_MMAP_COHERENT
+       if (!substream->ops->page &&
+           substream->dma_buffer.dev.type == SNDRV_DMA_TYPE_DEV)
+               return dma_mmap_coherent(substream->dma_buffer.dev.dev,
+                                        area,
+                                        substream->runtime->dma_area,
+                                        substream->runtime->dma_addr,
+                                        area->vm_end - area->vm_start);
+#endif /* ARCH_HAS_DMA_MMAP_COHERENT */
+       /* mmap with fault handler */
+       area->vm_ops = &snd_pcm_vm_ops_data_fault;
        return 0;
 }
 
@@ -3118,12 +3156,6 @@ static int snd_pcm_default_mmap(struct snd_pcm_substream *substream,
  * mmap the DMA buffer on I/O memory area
  */
 #if SNDRV_PCM_INFO_MMAP_IOMEM
-static const struct vm_operations_struct snd_pcm_vm_ops_data_mmio =
-{
-       .open =         snd_pcm_mmap_data_open,
-       .close =        snd_pcm_mmap_data_close,
-};
-
 int snd_pcm_lib_mmap_iomem(struct snd_pcm_substream *substream,
                           struct vm_area_struct *area)
 {
@@ -3133,8 +3165,6 @@ int snd_pcm_lib_mmap_iomem(struct snd_pcm_substream *substream,
 #ifdef pgprot_noncached
        area->vm_page_prot = pgprot_noncached(area->vm_page_prot);
 #endif
-       area->vm_ops = &snd_pcm_vm_ops_data_mmio;
-       area->vm_private_data = substream;
        area->vm_flags |= VM_IO;
        size = area->vm_end - area->vm_start;
        offset = area->vm_pgoff << PAGE_SHIFT;
@@ -3142,7 +3172,6 @@ int snd_pcm_lib_mmap_iomem(struct snd_pcm_substream *substream,
                                (substream->runtime->dma_addr + offset) >> PAGE_SHIFT,
                                size, area->vm_page_prot))
                return -EAGAIN;
-       atomic_inc(&substream->mmap_count);
        return 0;
 }
 
@@ -3159,6 +3188,7 @@ int snd_pcm_mmap_data(struct snd_pcm_substream *substream, struct file *file,
        long size;
        unsigned long offset;
        size_t dma_bytes;
+       int err;
 
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
                if (!(area->vm_flags & (VM_WRITE|VM_READ)))
@@ -3183,10 +3213,15 @@ int snd_pcm_mmap_data(struct snd_pcm_substream *substream, struct file *file,
        if (offset > dma_bytes - size)
                return -EINVAL;
 
+       area->vm_ops = &snd_pcm_vm_ops_data;
+       area->vm_private_data = substream;
        if (substream->ops->mmap)
-               return substream->ops->mmap(substream, area);
+               err = substream->ops->mmap(substream, area);
        else
-               return snd_pcm_default_mmap(substream, area);
+               err = snd_pcm_default_mmap(substream, area);
+       if (!err)
+               atomic_inc(&substream->mmap_count);
+       return err;
 }
 
 EXPORT_SYMBOL(snd_pcm_mmap_data);
index 70d6f25..2f76612 100644 (file)
@@ -242,8 +242,6 @@ static int assign_substream(struct snd_rawmidi *rmidi, int subdevice,
                return -ENXIO;
        if (subdevice >= 0 && subdevice >= s->substream_count)
                return -ENODEV;
-       if (s->substream_opened >= s->substream_count)
-               return -EAGAIN;
 
        list_for_each_entry(substream, &s->substreams, list) {
                if (substream->opened) {
@@ -280,9 +278,10 @@ static int open_substream(struct snd_rawmidi *rmidi,
                substream->active_sensing = 0;
                if (mode & SNDRV_RAWMIDI_LFLG_APPEND)
                        substream->append = 1;
+               substream->pid = get_pid(task_pid(current));
+               rmidi->streams[substream->stream].substream_opened++;
        }
        substream->use_count++;
-       rmidi->streams[substream->stream].substream_opened++;
        return 0;
 }
 
@@ -413,7 +412,7 @@ static int snd_rawmidi_open(struct inode *inode, struct file *file)
                subdevice = -1;
                read_lock(&card->ctl_files_rwlock);
                list_for_each_entry(kctl, &card->ctl_files, list) {
-                       if (kctl->pid == current->pid) {
+                       if (kctl->pid == task_pid(current)) {
                                subdevice = kctl->prefer_rawmidi_subdevice;
                                if (subdevice != -1)
                                        break;
@@ -466,7 +465,6 @@ static void close_substream(struct snd_rawmidi *rmidi,
                            struct snd_rawmidi_substream *substream,
                            int cleanup)
 {
-       rmidi->streams[substream->stream].substream_opened--;
        if (--substream->use_count)
                return;
 
@@ -491,6 +489,9 @@ static void close_substream(struct snd_rawmidi *rmidi,
        snd_rawmidi_runtime_free(substream);
        substream->opened = 0;
        substream->append = 0;
+       put_pid(substream->pid);
+       substream->pid = NULL;
+       rmidi->streams[substream->stream].substream_opened--;
 }
 
 static void rawmidi_release_priv(struct snd_rawmidi_file *rfile)
@@ -1338,6 +1339,9 @@ static void snd_rawmidi_proc_info_read(struct snd_info_entry *entry,
                                    substream->number,
                                    (unsigned long) substream->bytes);
                        if (substream->opened) {
+                               snd_iprintf(buffer,
+                                   "  Owner PID    : %d\n",
+                                   pid_vnr(substream->pid));
                                runtime = substream->runtime;
                                snd_iprintf(buffer,
                                    "  Mode         : %s\n"
@@ -1359,6 +1363,9 @@ static void snd_rawmidi_proc_info_read(struct snd_info_entry *entry,
                                    substream->number,
                                    (unsigned long) substream->bytes);
                        if (substream->opened) {
+                               snd_iprintf(buffer,
+                                           "  Owner PID    : %d\n",
+                                           pid_vnr(substream->pid));
                                runtime = substream->runtime;
                                snd_iprintf(buffer,
                                            "  Buffer size  : %lu\n"
index b60cef2..f165c77 100644 (file)
@@ -26,6 +26,7 @@ MODULE_ALIAS("platform:pcspkr");
 static int index = SNDRV_DEFAULT_IDX1; /* Index 0-MAX */
 static char *id = SNDRV_DEFAULT_STR1;  /* ID for this card */
 static int enable = SNDRV_DEFAULT_ENABLE1;     /* Enable this card */
+static int nopcm;      /* Disable PCM capability of the driver */
 
 module_param(index, int, 0444);
 MODULE_PARM_DESC(index, "Index value for pcsp soundcard.");
@@ -33,6 +34,8 @@ module_param(id, charp, 0444);
 MODULE_PARM_DESC(id, "ID string for pcsp soundcard.");
 module_param(enable, bool, 0444);
 MODULE_PARM_DESC(enable, "Enable PC-Speaker sound.");
+module_param(nopcm, bool, 0444);
+MODULE_PARM_DESC(nopcm, "Disable PC-Speaker PCM sound. Only beeps remain.");
 
 struct snd_pcsp pcsp_chip;
 
@@ -43,13 +46,16 @@ static int __devinit snd_pcsp_create(struct snd_card *card)
        int err;
        int div, min_div, order;
 
-       hrtimer_get_res(CLOCK_MONOTONIC, &tp);
-       if (tp.tv_sec || tp.tv_nsec > PCSP_MAX_PERIOD_NS) {
-               printk(KERN_ERR "PCSP: Timer resolution is not sufficient "
-                      "(%linS)\n", tp.tv_nsec);
-               printk(KERN_ERR "PCSP: Make sure you have HPET and ACPI "
-                      "enabled.\n");
-               return -EIO;
+       if (!nopcm) {
+               hrtimer_get_res(CLOCK_MONOTONIC, &tp);
+               if (tp.tv_sec || tp.tv_nsec > PCSP_MAX_PERIOD_NS) {
+                       printk(KERN_ERR "PCSP: Timer resolution is not sufficient "
+                               "(%linS)\n", tp.tv_nsec);
+                       printk(KERN_ERR "PCSP: Make sure you have HPET and ACPI "
+                               "enabled.\n");
+                       printk(KERN_ERR "PCSP: Turned into nopcm mode.\n");
+                       nopcm = 1;
+               }
        }
 
        if (loops_per_jiffy >= PCSP_MIN_LPJ && tp.tv_nsec <= PCSP_MIN_PERIOD_NS)
@@ -107,12 +113,14 @@ static int __devinit snd_card_pcsp_probe(int devnum, struct device *dev)
                snd_card_free(card);
                return err;
        }
-       err = snd_pcsp_new_pcm(&pcsp_chip);
-       if (err < 0) {
-               snd_card_free(card);
-               return err;
+       if (!nopcm) {
+               err = snd_pcsp_new_pcm(&pcsp_chip);
+               if (err < 0) {
+                       snd_card_free(card);
+                       return err;
+               }
        }
-       err = snd_pcsp_new_mixer(&pcsp_chip);
+       err = snd_pcsp_new_mixer(&pcsp_chip, nopcm);
        if (err < 0) {
                snd_card_free(card);
                return err;
index 174dd2f..1e12307 100644 (file)
@@ -83,6 +83,6 @@ extern enum hrtimer_restart pcsp_do_timer(struct hrtimer *handle);
 extern void pcsp_sync_stop(struct snd_pcsp *chip);
 
 extern int snd_pcsp_new_pcm(struct snd_pcsp *chip);
-extern int snd_pcsp_new_mixer(struct snd_pcsp *chip);
+extern int snd_pcsp_new_mixer(struct snd_pcsp *chip, int nopcm);
 
 #endif
index 903bc84..6f633f4 100644 (file)
@@ -119,24 +119,43 @@ static int pcsp_pcspkr_put(struct snd_kcontrol *kcontrol,
        .put =          pcsp_##ctl_type##_put, \
 }
 
-static struct snd_kcontrol_new __devinitdata snd_pcsp_controls[] = {
+static struct snd_kcontrol_new __devinitdata snd_pcsp_controls_pcm[] = {
        PCSP_MIXER_CONTROL(enable, "Master Playback Switch"),
        PCSP_MIXER_CONTROL(treble, "BaseFRQ Playback Volume"),
-       PCSP_MIXER_CONTROL(pcspkr, "PC Speaker Playback Switch"),
 };
 
-int __devinit snd_pcsp_new_mixer(struct snd_pcsp *chip)
+static struct snd_kcontrol_new __devinitdata snd_pcsp_controls_spkr[] = {
+       PCSP_MIXER_CONTROL(pcspkr, "Beep Playback Switch"),
+};
+
+static int __devinit snd_pcsp_ctls_add(struct snd_pcsp *chip,
+       struct snd_kcontrol_new *ctls, int num)
 {
-       struct snd_card *card = chip->card;
        int i, err;
+       struct snd_card *card = chip->card;
+       for (i = 0; i < num; i++) {
+               err = snd_ctl_add(card, snd_ctl_new1(ctls + i, chip));
+               if (err < 0)
+                       return err;
+       }
+       return 0;
+}
+
+int __devinit snd_pcsp_new_mixer(struct snd_pcsp *chip, int nopcm)
+{
+       int err;
+       struct snd_card *card = chip->card;
 
-       for (i = 0; i < ARRAY_SIZE(snd_pcsp_controls); i++) {
-               err = snd_ctl_add(card,
-                                snd_ctl_new1(snd_pcsp_controls + i,
-                                             chip));
+       if (!nopcm) {
+               err = snd_pcsp_ctls_add(chip, snd_pcsp_controls_pcm,
+                       ARRAY_SIZE(snd_pcsp_controls_pcm));
                if (err < 0)
                        return err;
        }
+       err = snd_pcsp_ctls_add(chip, snd_pcsp_controls_spkr,
+               ARRAY_SIZE(snd_pcsp_controls_spkr));
+       if (err < 0)
+               return err;
 
        strcpy(card->mixername, "PC-Speaker");
 
index 020a5d5..04ae870 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/slab.h>
 #include <linux/delay.h>
 #include <linux/init.h>
+#include <linux/bitrev.h>
 #include <asm/unaligned.h>
 #include <sound/core.h>
 #include <sound/control.h>
@@ -55,18 +56,6 @@ struct cs8427 {
        struct cs8427_stream capture;
 };
 
-static unsigned char swapbits(unsigned char val)
-{
-       int bit;
-       unsigned char res = 0;
-       for (bit = 0; bit < 8; bit++) {
-               res <<= 1;
-               res |= val & 1;
-               val >>= 1;
-       }
-       return res;
-}
-
 int snd_cs8427_reg_write(struct snd_i2c_device *device, unsigned char reg,
                         unsigned char val)
 {
@@ -149,7 +138,7 @@ static int snd_cs8427_send_corudata(struct snd_i2c_device *device,
        }
        data[0] = CS8427_REG_AUTOINC | CS8427_REG_CORU_DATABUF;
        for (idx = 0; idx < count; idx++)
-               data[idx + 1] = swapbits(ndata[idx]);
+               data[idx + 1] = bitrev8(ndata[idx]);
        if (snd_i2c_sendbytes(device, data, count + 1) != count + 1)
                return -EIO;
        return 1;
index 703d954..2dad40f 100644 (file)
@@ -5,6 +5,7 @@
 
 snd-ak4114-objs := ak4114.o
 snd-ak4117-objs := ak4117.o
+snd-ak4113-objs := ak4113.o
 snd-ak4xxx-adda-objs := ak4xxx-adda.o
 snd-pt2258-objs := pt2258.o
 snd-tea575x-tuner-objs := tea575x-tuner.o
@@ -12,5 +13,5 @@ snd-tea575x-tuner-objs := tea575x-tuner.o
 # Module Dependency
 obj-$(CONFIG_SND_PDAUDIOCF) += snd-ak4117.o
 obj-$(CONFIG_SND_ICE1712) += snd-ak4xxx-adda.o
-obj-$(CONFIG_SND_ICE1724) += snd-ak4114.o snd-ak4xxx-adda.o snd-pt2258.o
+obj-$(CONFIG_SND_ICE1724) += snd-ak4114.o snd-ak4113.o snd-ak4xxx-adda.o snd-pt2258.o
 obj-$(CONFIG_SND_FM801_TEA575X) += snd-tea575x-tuner.o
diff --git a/sound/i2c/other/ak4113.c b/sound/i2c/other/ak4113.c
new file mode 100644 (file)
index 0000000..fff62cc
--- /dev/null
@@ -0,0 +1,639 @@
+/*
+ *  Routines for control of the AK4113 via I2C/4-wire serial interface
+ *  IEC958 (S/PDIF) receiver by Asahi Kasei
+ *  Copyright (c) by Jaroslav Kysela <perex@perex.cz>
+ *  Copyright (c) by Pavel Hofman <pavel.hofman@ivitera.com>
+ *
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ *
+ */
+
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <sound/core.h>
+#include <sound/control.h>
+#include <sound/pcm.h>
+#include <sound/ak4113.h>
+#include <sound/asoundef.h>
+#include <sound/info.h>
+
+MODULE_AUTHOR("Pavel Hofman <pavel.hofman@ivitera.com>");
+MODULE_DESCRIPTION("AK4113 IEC958 (S/PDIF) receiver by Asahi Kasei");
+MODULE_LICENSE("GPL");
+
+#define AK4113_ADDR                    0x00 /* fixed address */
+
+static void ak4113_stats(struct work_struct *work);
+static void ak4113_init_regs(struct ak4113 *chip);
+
+
+static void reg_write(struct ak4113 *ak4113, unsigned char reg,
+               unsigned char val)
+{
+       ak4113->write(ak4113->private_data, reg, val);
+       if (reg < sizeof(ak4113->regmap))
+               ak4113->regmap[reg] = val;
+}
+
+static inline unsigned char reg_read(struct ak4113 *ak4113, unsigned char reg)
+{
+       return ak4113->read(ak4113->private_data, reg);
+}
+
+static void snd_ak4113_free(struct ak4113 *chip)
+{
+       chip->init = 1; /* don't schedule new work */
+       mb();
+       cancel_delayed_work(&chip->work);
+       flush_scheduled_work();
+       kfree(chip);
+}
+
+static int snd_ak4113_dev_free(struct snd_device *device)
+{
+       struct ak4113 *chip = device->device_data;
+       snd_ak4113_free(chip);
+       return 0;
+}
+
+int snd_ak4113_create(struct snd_card *card, ak4113_read_t *read,
+               ak4113_write_t *write, const unsigned char pgm[5],
+               void *private_data, struct ak4113 **r_ak4113)
+{
+       struct ak4113 *chip;
+       int err = 0;
+       unsigned char reg;
+       static struct snd_device_ops ops = {
+               .dev_free =     snd_ak4113_dev_free,
+       };
+
+       chip = kzalloc(sizeof(*chip), GFP_KERNEL);
+       if (chip == NULL)
+               return -ENOMEM;
+       spin_lock_init(&chip->lock);
+       chip->card = card;
+       chip->read = read;
+       chip->write = write;
+       chip->private_data = private_data;
+       INIT_DELAYED_WORK(&chip->work, ak4113_stats);
+
+       for (reg = 0; reg < AK4113_WRITABLE_REGS ; reg++)
+               chip->regmap[reg] = pgm[reg];
+       ak4113_init_regs(chip);
+
+       chip->rcs0 = reg_read(chip, AK4113_REG_RCS0) & ~(AK4113_QINT |
+                       AK4113_CINT | AK4113_STC);
+       chip->rcs1 = reg_read(chip, AK4113_REG_RCS1);
+       chip->rcs2 = reg_read(chip, AK4113_REG_RCS2);
+       err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops);
+       if (err < 0)
+               goto __fail;
+
+       if (r_ak4113)
+               *r_ak4113 = chip;
+       return 0;
+
+__fail:
+       snd_ak4113_free(chip);
+       return err < 0 ? err : -EIO;
+}
+EXPORT_SYMBOL_GPL(snd_ak4113_create);
+
+void snd_ak4113_reg_write(struct ak4113 *chip, unsigned char reg,
+               unsigned char mask, unsigned char val)
+{
+       if (reg >= AK4113_WRITABLE_REGS)
+               return;
+       reg_write(chip, reg, (chip->regmap[reg] & ~mask) | val);
+}
+EXPORT_SYMBOL_GPL(snd_ak4113_reg_write);
+
+static void ak4113_init_regs(struct ak4113 *chip)
+{
+       unsigned char old = chip->regmap[AK4113_REG_PWRDN], reg;
+
+       /* bring the chip to reset state and powerdown state */
+       reg_write(chip, AK4113_REG_PWRDN, old & ~(AK4113_RST|AK4113_PWN));
+       udelay(200);
+       /* release reset, but leave powerdown */
+       reg_write(chip, AK4113_REG_PWRDN, (old | AK4113_RST) & ~AK4113_PWN);
+       udelay(200);
+       for (reg = 1; reg < AK4113_WRITABLE_REGS; reg++)
+               reg_write(chip, reg, chip->regmap[reg]);
+       /* release powerdown, everything is initialized now */
+       reg_write(chip, AK4113_REG_PWRDN, old | AK4113_RST | AK4113_PWN);
+}
+
+void snd_ak4113_reinit(struct ak4113 *chip)
+{
+       chip->init = 1;
+       mb();
+       flush_scheduled_work();
+       ak4113_init_regs(chip);
+       /* bring up statistics / event queing */
+       chip->init = 0;
+       if (chip->kctls[0])
+               schedule_delayed_work(&chip->work, HZ / 10);
+}
+EXPORT_SYMBOL_GPL(snd_ak4113_reinit);
+
+static unsigned int external_rate(unsigned char rcs1)
+{
+       switch (rcs1 & (AK4113_FS0|AK4113_FS1|AK4113_FS2|AK4113_FS3)) {
+       case AK4113_FS_8000HZ:
+               return 8000;
+       case AK4113_FS_11025HZ:
+               return 11025;
+       case AK4113_FS_16000HZ:
+               return 16000;
+       case AK4113_FS_22050HZ:
+               return 22050;
+       case AK4113_FS_24000HZ:
+               return 24000;
+       case AK4113_FS_32000HZ:
+               return 32000;
+       case AK4113_FS_44100HZ:
+               return 44100;
+       case AK4113_FS_48000HZ:
+               return 48000;
+       case AK4113_FS_64000HZ:
+               return 64000;
+       case AK4113_FS_88200HZ:
+               return 88200;
+       case AK4113_FS_96000HZ:
+               return 96000;
+       case AK4113_FS_176400HZ:
+               return 176400;
+       case AK4113_FS_192000HZ:
+               return 192000;
+       default:
+               return 0;
+       }
+}
+
+static int snd_ak4113_in_error_info(struct snd_kcontrol *kcontrol,
+                                   struct snd_ctl_elem_info *uinfo)
+{
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       uinfo->count = 1;
+       uinfo->value.integer.min = 0;
+       uinfo->value.integer.max = LONG_MAX;
+       return 0;
+}
+
+static int snd_ak4113_in_error_get(struct snd_kcontrol *kcontrol,
+                                  struct snd_ctl_elem_value *ucontrol)
+{
+       struct ak4113 *chip = snd_kcontrol_chip(kcontrol);
+       long *ptr;
+
+       spin_lock_irq(&chip->lock);
+       ptr = (long *)(((char *)chip) + kcontrol->private_value);
+       ucontrol->value.integer.value[0] = *ptr;
+       *ptr = 0;
+       spin_unlock_irq(&chip->lock);
+       return 0;
+}
+
+#define snd_ak4113_in_bit_info         snd_ctl_boolean_mono_info
+
+static int snd_ak4113_in_bit_get(struct snd_kcontrol *kcontrol,
+                                struct snd_ctl_elem_value *ucontrol)
+{
+       struct ak4113 *chip = snd_kcontrol_chip(kcontrol);
+       unsigned char reg = kcontrol->private_value & 0xff;
+       unsigned char bit = (kcontrol->private_value >> 8) & 0xff;
+       unsigned char inv = (kcontrol->private_value >> 31) & 1;
+
+       ucontrol->value.integer.value[0] =
+               ((reg_read(chip, reg) & (1 << bit)) ? 1 : 0) ^ inv;
+       return 0;
+}
+
+static int snd_ak4113_rx_info(struct snd_kcontrol *kcontrol,
+                             struct snd_ctl_elem_info *uinfo)
+{
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       uinfo->count = 1;
+       uinfo->value.integer.min = 0;
+       uinfo->value.integer.max = 5;
+       return 0;
+}
+
+static int snd_ak4113_rx_get(struct snd_kcontrol *kcontrol,
+                            struct snd_ctl_elem_value *ucontrol)
+{
+       struct ak4113 *chip = snd_kcontrol_chip(kcontrol);
+
+       ucontrol->value.integer.value[0] =
+               (AK4113_IPS(chip->regmap[AK4113_REG_IO1]));
+       return 0;
+}
+
+static int snd_ak4113_rx_put(struct snd_kcontrol *kcontrol,
+                            struct snd_ctl_elem_value *ucontrol)
+{
+       struct ak4113 *chip = snd_kcontrol_chip(kcontrol);
+       int change;
+       u8 old_val;
+
+       spin_lock_irq(&chip->lock);
+       old_val = chip->regmap[AK4113_REG_IO1];
+       change = ucontrol->value.integer.value[0] != AK4113_IPS(old_val);
+       if (change)
+               reg_write(chip, AK4113_REG_IO1,
+                               (old_val & (~AK4113_IPS(0xff))) |
+                               (AK4113_IPS(ucontrol->value.integer.value[0])));
+       spin_unlock_irq(&chip->lock);
+       return change;
+}
+
+static int snd_ak4113_rate_info(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_info *uinfo)
+{
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       uinfo->count = 1;
+       uinfo->value.integer.min = 0;
+       uinfo->value.integer.max = 192000;
+       return 0;
+}
+
+static int snd_ak4113_rate_get(struct snd_kcontrol *kcontrol,
+                              struct snd_ctl_elem_value *ucontrol)
+{
+       struct ak4113 *chip = snd_kcontrol_chip(kcontrol);
+
+       ucontrol->value.integer.value[0] = external_rate(reg_read(chip,
+                               AK4113_REG_RCS1));
+       return 0;
+}
+
+static int snd_ak4113_spdif_info(struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_info *uinfo)
+{
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
+       uinfo->count = 1;
+       return 0;
+}
+
+static int snd_ak4113_spdif_get(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       struct ak4113 *chip = snd_kcontrol_chip(kcontrol);
+       unsigned i;
+
+       for (i = 0; i < AK4113_REG_RXCSB_SIZE; i++)
+               ucontrol->value.iec958.status[i] = reg_read(chip,
+                               AK4113_REG_RXCSB0 + i);
+       return 0;
+}
+
+static int snd_ak4113_spdif_mask_info(struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_info *uinfo)
+{
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
+       uinfo->count = 1;
+       return 0;
+}
+
+static int snd_ak4113_spdif_mask_get(struct snd_kcontrol *kcontrol,
+                                     struct snd_ctl_elem_value *ucontrol)
+{
+       memset(ucontrol->value.iec958.status, 0xff, AK4113_REG_RXCSB_SIZE);
+       return 0;
+}
+
+static int snd_ak4113_spdif_pinfo(struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_info *uinfo)
+{
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       uinfo->value.integer.min = 0;
+       uinfo->value.integer.max = 0xffff;
+       uinfo->count = 4;
+       return 0;
+}
+
+static int snd_ak4113_spdif_pget(struct snd_kcontrol *kcontrol,
+                                struct snd_ctl_elem_value *ucontrol)
+{
+       struct ak4113 *chip = snd_kcontrol_chip(kcontrol);
+       unsigned short tmp;
+
+       ucontrol->value.integer.value[0] = 0xf8f2;
+       ucontrol->value.integer.value[1] = 0x4e1f;
+       tmp = reg_read(chip, AK4113_REG_Pc0) |
+               (reg_read(chip, AK4113_REG_Pc1) << 8);
+       ucontrol->value.integer.value[2] = tmp;
+       tmp = reg_read(chip, AK4113_REG_Pd0) |
+               (reg_read(chip, AK4113_REG_Pd1) << 8);
+       ucontrol->value.integer.value[3] = tmp;
+       return 0;
+}
+
+static int snd_ak4113_spdif_qinfo(struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_info *uinfo)
+{
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
+       uinfo->count = AK4113_REG_QSUB_SIZE;
+       return 0;
+}
+
+static int snd_ak4113_spdif_qget(struct snd_kcontrol *kcontrol,
+                                struct snd_ctl_elem_value *ucontrol)
+{
+       struct ak4113 *chip = snd_kcontrol_chip(kcontrol);
+       unsigned i;
+
+       for (i = 0; i < AK4113_REG_QSUB_SIZE; i++)
+               ucontrol->value.bytes.data[i] = reg_read(chip,
+                               AK4113_REG_QSUB_ADDR + i);
+       return 0;
+}
+
+/* Don't forget to change AK4113_CONTROLS define!!! */
+static struct snd_kcontrol_new snd_ak4113_iec958_controls[] = {
+{
+       .iface =        SNDRV_CTL_ELEM_IFACE_PCM,
+       .name =         "IEC958 Parity Errors",
+       .access =       SNDRV_CTL_ELEM_ACCESS_READ |
+               SNDRV_CTL_ELEM_ACCESS_VOLATILE,
+       .info =         snd_ak4113_in_error_info,
+       .get =          snd_ak4113_in_error_get,
+       .private_value = offsetof(struct ak4113, parity_errors),
+},
+{
+       .iface =        SNDRV_CTL_ELEM_IFACE_PCM,
+       .name =         "IEC958 V-Bit Errors",
+       .access =       SNDRV_CTL_ELEM_ACCESS_READ |
+               SNDRV_CTL_ELEM_ACCESS_VOLATILE,
+       .info =         snd_ak4113_in_error_info,
+       .get =          snd_ak4113_in_error_get,
+       .private_value = offsetof(struct ak4113, v_bit_errors),
+},
+{
+       .iface =        SNDRV_CTL_ELEM_IFACE_PCM,
+       .name =         "IEC958 C-CRC Errors",
+       .access =       SNDRV_CTL_ELEM_ACCESS_READ |
+               SNDRV_CTL_ELEM_ACCESS_VOLATILE,
+       .info =         snd_ak4113_in_error_info,
+       .get =          snd_ak4113_in_error_get,
+       .private_value = offsetof(struct ak4113, ccrc_errors),
+},
+{
+       .iface =        SNDRV_CTL_ELEM_IFACE_PCM,
+       .name =         "IEC958 Q-CRC Errors",
+       .access =       SNDRV_CTL_ELEM_ACCESS_READ |
+               SNDRV_CTL_ELEM_ACCESS_VOLATILE,
+       .info =         snd_ak4113_in_error_info,
+       .get =          snd_ak4113_in_error_get,
+       .private_value = offsetof(struct ak4113, qcrc_errors),
+},
+{
+       .iface =        SNDRV_CTL_ELEM_IFACE_PCM,
+       .name =         "IEC958 External Rate",
+       .access =       SNDRV_CTL_ELEM_ACCESS_READ |
+               SNDRV_CTL_ELEM_ACCESS_VOLATILE,
+       .info =         snd_ak4113_rate_info,
+       .get =          snd_ak4113_rate_get,
+},
+{
+       .iface =        SNDRV_CTL_ELEM_IFACE_PCM,
+       .name =         SNDRV_CTL_NAME_IEC958("", CAPTURE, MASK),
+       .access =       SNDRV_CTL_ELEM_ACCESS_READ,
+       .info =         snd_ak4113_spdif_mask_info,
+       .get =          snd_ak4113_spdif_mask_get,
+},
+{
+       .iface =        SNDRV_CTL_ELEM_IFACE_PCM,
+       .name =         SNDRV_CTL_NAME_IEC958("", CAPTURE, DEFAULT),
+       .access =       SNDRV_CTL_ELEM_ACCESS_READ |
+               SNDRV_CTL_ELEM_ACCESS_VOLATILE,
+       .info =         snd_ak4113_spdif_info,
+       .get =          snd_ak4113_spdif_get,
+},
+{
+       .iface =        SNDRV_CTL_ELEM_IFACE_PCM,
+       .name =         "IEC958 Preample Capture Default",
+       .access =       SNDRV_CTL_ELEM_ACCESS_READ |
+               SNDRV_CTL_ELEM_ACCESS_VOLATILE,
+       .info =         snd_ak4113_spdif_pinfo,
+       .get =          snd_ak4113_spdif_pget,
+},
+{
+       .iface =        SNDRV_CTL_ELEM_IFACE_PCM,
+       .name =         "IEC958 Q-subcode Capture Default",
+       .access =       SNDRV_CTL_ELEM_ACCESS_READ |
+               SNDRV_CTL_ELEM_ACCESS_VOLATILE,
+       .info =         snd_ak4113_spdif_qinfo,
+       .get =          snd_ak4113_spdif_qget,
+},
+{
+       .iface =        SNDRV_CTL_ELEM_IFACE_PCM,
+       .name =         "IEC958 Audio",
+       .access =       SNDRV_CTL_ELEM_ACCESS_READ |
+               SNDRV_CTL_ELEM_ACCESS_VOLATILE,
+       .info =         snd_ak4113_in_bit_info,
+       .get =          snd_ak4113_in_bit_get,
+       .private_value = (1<<31) | (1<<8) | AK4113_REG_RCS0,
+},
+{
+       .iface =        SNDRV_CTL_ELEM_IFACE_PCM,
+       .name =         "IEC958 Non-PCM Bitstream",
+       .access =       SNDRV_CTL_ELEM_ACCESS_READ |
+               SNDRV_CTL_ELEM_ACCESS_VOLATILE,
+       .info =         snd_ak4113_in_bit_info,
+       .get =          snd_ak4113_in_bit_get,
+       .private_value = (0<<8) | AK4113_REG_RCS1,
+},
+{
+       .iface =        SNDRV_CTL_ELEM_IFACE_PCM,
+       .name =         "IEC958 DTS Bitstream",
+       .access =       SNDRV_CTL_ELEM_ACCESS_READ |
+               SNDRV_CTL_ELEM_ACCESS_VOLATILE,
+       .info =         snd_ak4113_in_bit_info,
+       .get =          snd_ak4113_in_bit_get,
+       .private_value = (1<<8) | AK4113_REG_RCS1,
+},
+{
+       .iface =        SNDRV_CTL_ELEM_IFACE_PCM,
+       .name =         "AK4113 Input Select",
+       .access =       SNDRV_CTL_ELEM_ACCESS_READ |
+               SNDRV_CTL_ELEM_ACCESS_WRITE,
+       .info =         snd_ak4113_rx_info,
+       .get =          snd_ak4113_rx_get,
+       .put =          snd_ak4113_rx_put,
+}
+};
+
+static void snd_ak4113_proc_regs_read(struct snd_info_entry *entry,
+               struct snd_info_buffer *buffer)
+{
+       struct ak4113 *ak4113 = entry->private_data;
+       int reg, val;
+       /* all ak4113 registers 0x00 - 0x1c */
+       for (reg = 0; reg < 0x1d; reg++) {
+               val = reg_read(ak4113, reg);
+               snd_iprintf(buffer, "0x%02x = 0x%02x\n", reg, val);
+       }
+}
+
+static void snd_ak4113_proc_init(struct ak4113 *ak4113)
+{
+       struct snd_info_entry *entry;
+       if (!snd_card_proc_new(ak4113->card, "ak4113", &entry))
+               snd_info_set_text_ops(entry, ak4113, snd_ak4113_proc_regs_read);
+}
+
+int snd_ak4113_build(struct ak4113 *ak4113,
+               struct snd_pcm_substream *cap_substream)
+{
+       struct snd_kcontrol *kctl;
+       unsigned int idx;
+       int err;
+
+       if (snd_BUG_ON(!cap_substream))
+               return -EINVAL;
+       ak4113->substream = cap_substream;
+       for (idx = 0; idx < AK4113_CONTROLS; idx++) {
+               kctl = snd_ctl_new1(&snd_ak4113_iec958_controls[idx], ak4113);
+               if (kctl == NULL)
+                       return -ENOMEM;
+               kctl->id.device = cap_substream->pcm->device;
+               kctl->id.subdevice = cap_substream->number;
+               err = snd_ctl_add(ak4113->card, kctl);
+               if (err < 0)
+                       return err;
+               ak4113->kctls[idx] = kctl;
+       }
+       snd_ak4113_proc_init(ak4113);
+       /* trigger workq */
+       schedule_delayed_work(&ak4113->work, HZ / 10);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(snd_ak4113_build);
+
+int snd_ak4113_external_rate(struct ak4113 *ak4113)
+{
+       unsigned char rcs1;
+
+       rcs1 = reg_read(ak4113, AK4113_REG_RCS1);
+       return external_rate(rcs1);
+}
+EXPORT_SYMBOL_GPL(snd_ak4113_external_rate);
+
+int snd_ak4113_check_rate_and_errors(struct ak4113 *ak4113, unsigned int flags)
+{
+       struct snd_pcm_runtime *runtime =
+               ak4113->substream ? ak4113->substream->runtime : NULL;
+       unsigned long _flags;
+       int res = 0;
+       unsigned char rcs0, rcs1, rcs2;
+       unsigned char c0, c1;
+
+       rcs1 = reg_read(ak4113, AK4113_REG_RCS1);
+       if (flags & AK4113_CHECK_NO_STAT)
+               goto __rate;
+       rcs0 = reg_read(ak4113, AK4113_REG_RCS0);
+       rcs2 = reg_read(ak4113, AK4113_REG_RCS2);
+       spin_lock_irqsave(&ak4113->lock, _flags);
+       if (rcs0 & AK4113_PAR)
+               ak4113->parity_errors++;
+       if (rcs0 & AK4113_V)
+               ak4113->v_bit_errors++;
+       if (rcs2 & AK4113_CCRC)
+               ak4113->ccrc_errors++;
+       if (rcs2 & AK4113_QCRC)
+               ak4113->qcrc_errors++;
+       c0 = (ak4113->rcs0 & (AK4113_QINT | AK4113_CINT | AK4113_STC |
+                               AK4113_AUDION | AK4113_AUTO | AK4113_UNLCK)) ^
+               (rcs0 & (AK4113_QINT | AK4113_CINT | AK4113_STC |
+                        AK4113_AUDION | AK4113_AUTO | AK4113_UNLCK));
+       c1 = (ak4113->rcs1 & (AK4113_DTSCD | AK4113_NPCM | AK4113_PEM |
+                               AK4113_DAT | 0xf0)) ^
+               (rcs1 & (AK4113_DTSCD | AK4113_NPCM | AK4113_PEM |
+                        AK4113_DAT | 0xf0));
+       ak4113->rcs0 = rcs0 & ~(AK4113_QINT | AK4113_CINT | AK4113_STC);
+       ak4113->rcs1 = rcs1;
+       ak4113->rcs2 = rcs2;
+       spin_unlock_irqrestore(&ak4113->lock, _flags);
+
+       if (rcs0 & AK4113_PAR)
+               snd_ctl_notify(ak4113->card, SNDRV_CTL_EVENT_MASK_VALUE,
+                               &ak4113->kctls[0]->id);
+       if (rcs0 & AK4113_V)
+               snd_ctl_notify(ak4113->card, SNDRV_CTL_EVENT_MASK_VALUE,
+                               &ak4113->kctls[1]->id);
+       if (rcs2 & AK4113_CCRC)
+               snd_ctl_notify(ak4113->card, SNDRV_CTL_EVENT_MASK_VALUE,
+                               &ak4113->kctls[2]->id);
+       if (rcs2 & AK4113_QCRC)
+               snd_ctl_notify(ak4113->card, SNDRV_CTL_EVENT_MASK_VALUE,
+                               &ak4113->kctls[3]->id);
+
+       /* rate change */
+       if (c1 & 0xf0)
+               snd_ctl_notify(ak4113->card, SNDRV_CTL_EVENT_MASK_VALUE,
+                               &ak4113->kctls[4]->id);
+
+       if ((c1 & AK4113_PEM) | (c0 & AK4113_CINT))
+               snd_ctl_notify(ak4113->card, SNDRV_CTL_EVENT_MASK_VALUE,
+                               &ak4113->kctls[6]->id);
+       if (c0 & AK4113_QINT)
+               snd_ctl_notify(ak4113->card, SNDRV_CTL_EVENT_MASK_VALUE,
+                               &ak4113->kctls[8]->id);
+
+       if (c0 & AK4113_AUDION)
+               snd_ctl_notify(ak4113->card, SNDRV_CTL_EVENT_MASK_VALUE,
+                               &ak4113->kctls[9]->id);
+       if (c1 & AK4113_NPCM)
+               snd_ctl_notify(ak4113->card, SNDRV_CTL_EVENT_MASK_VALUE,
+                               &ak4113->kctls[10]->id);
+       if (c1 & AK4113_DTSCD)
+               snd_ctl_notify(ak4113->card, SNDRV_CTL_EVENT_MASK_VALUE,
+                               &ak4113->kctls[11]->id);
+
+       if (ak4113->change_callback && (c0 | c1) != 0)
+               ak4113->change_callback(ak4113, c0, c1);
+
+__rate:
+       /* compare rate */
+       res = external_rate(rcs1);
+       if (!(flags & AK4113_CHECK_NO_RATE) && runtime &&
+                       (runtime->rate != res)) {
+               snd_pcm_stream_lock_irqsave(ak4113->substream, _flags);
+               if (snd_pcm_running(ak4113->substream)) {
+                       /*printk(KERN_DEBUG "rate changed (%i <- %i)\n",
+                        * runtime->rate, res); */
+                       snd_pcm_stop(ak4113->substream,
+                                       SNDRV_PCM_STATE_DRAINING);
+                       wake_up(&runtime->sleep);
+                       res = 1;
+               }
+               snd_pcm_stream_unlock_irqrestore(ak4113->substream, _flags);
+       }
+       return res;
+}
+EXPORT_SYMBOL_GPL(snd_ak4113_check_rate_and_errors);
+
+static void ak4113_stats(struct work_struct *work)
+{
+       struct ak4113 *chip = container_of(work, struct ak4113, work.work);
+
+       if (!chip->init)
+               snd_ak4113_check_rate_and_errors(chip, chip->check_flags);
+
+       schedule_delayed_work(&chip->work, HZ / 10);
+}
index ee47aba..1adb8a3 100644 (file)
@@ -19,7 +19,7 @@
  *   along with this program; if not, write to the Free Software
  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  *
- */      
+ */
 
 #include <asm/io.h>
 #include <linux/delay.h>
@@ -29,6 +29,7 @@
 #include <sound/control.h>
 #include <sound/tlv.h>
 #include <sound/ak4xxx-adda.h>
+#include <sound/info.h>
 
 MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>, Takashi Iwai <tiwai@suse.de>");
 MODULE_DESCRIPTION("Routines for control of AK452x / AK43xx  AD/DA converters");
@@ -52,26 +53,21 @@ EXPORT_SYMBOL(snd_akm4xxx_write);
 static void ak4524_reset(struct snd_akm4xxx *ak, int state)
 {
        unsigned int chip;
-       unsigned char reg, maxreg;
+       unsigned char reg;
 
-       if (ak->type == SND_AK4528)
-               maxreg = 0x06;
-       else
-               maxreg = 0x08;
        for (chip = 0; chip < ak->num_dacs/2; chip++) {
                snd_akm4xxx_write(ak, chip, 0x01, state ? 0x00 : 0x03);
                if (state)
                        continue;
                /* DAC volumes */
-               for (reg = 0x04; reg < maxreg; reg++)
+               for (reg = 0x04; reg < ak->total_regs; reg++)
                        snd_akm4xxx_write(ak, chip, reg,
                                          snd_akm4xxx_get(ak, chip, reg));
        }
 }
 
 /* reset procedure for AK4355 and AK4358 */
-static void ak435X_reset(struct snd_akm4xxx *ak, int state,
-               unsigned char total_regs)
+static void ak435X_reset(struct snd_akm4xxx *ak, int state)
 {
        unsigned char reg;
 
@@ -79,7 +75,7 @@ static void ak435X_reset(struct snd_akm4xxx *ak, int state,
                snd_akm4xxx_write(ak, 0, 0x01, 0x02); /* reset and soft-mute */
                return;
        }
-       for (reg = 0x00; reg < total_regs; reg++)
+       for (reg = 0x00; reg < ak->total_regs; reg++)
                if (reg != 0x01)
                        snd_akm4xxx_write(ak, 0, reg,
                                          snd_akm4xxx_get(ak, 0, reg));
@@ -91,12 +87,11 @@ static void ak4381_reset(struct snd_akm4xxx *ak, int state)
 {
        unsigned int chip;
        unsigned char reg;
-
        for (chip = 0; chip < ak->num_dacs/2; chip++) {
                snd_akm4xxx_write(ak, chip, 0x00, state ? 0x0c : 0x0f);
                if (state)
                        continue;
-               for (reg = 0x01; reg < 0x05; reg++)
+               for (reg = 0x01; reg < ak->total_regs; reg++)
                        snd_akm4xxx_write(ak, chip, reg,
                                          snd_akm4xxx_get(ak, chip, reg));
        }
@@ -113,16 +108,17 @@ void snd_akm4xxx_reset(struct snd_akm4xxx *ak, int state)
        switch (ak->type) {
        case SND_AK4524:
        case SND_AK4528:
+       case SND_AK4620:
                ak4524_reset(ak, state);
                break;
        case SND_AK4529:
                /* FIXME: needed for ak4529? */
                break;
        case SND_AK4355:
-               ak435X_reset(ak, state, 0x0b);
+               ak435X_reset(ak, state);
                break;
        case SND_AK4358:
-               ak435X_reset(ak, state, 0x10);
+               ak435X_reset(ak, state);
                break;
        case SND_AK4381:
                ak4381_reset(ak, state);
@@ -139,7 +135,7 @@ EXPORT_SYMBOL(snd_akm4xxx_reset);
  * Volume conversion table for non-linear volumes
  * from -63.5dB (mute) to 0dB step 0.5dB
  *
- * Used for AK4524 input/ouput attenuation, AK4528, and
+ * Used for AK4524/AK4620 input/ouput attenuation, AK4528, and
  * AK5365 input attenuation
  */
 static const unsigned char vol_cvt_datt[128] = {
@@ -259,8 +255,22 @@ void snd_akm4xxx_init(struct snd_akm4xxx *ak)
                0x00, 0x0f, /* 0: power-up, un-reset */
                0xff, 0xff
        };
+       static const unsigned char inits_ak4620[] = {
+               0x00, 0x07, /* 0: normal */
+               0x01, 0x00, /* 0: reset */
+               0x01, 0x02, /* 1: RSTAD */
+               0x01, 0x03, /* 1: RSTDA */
+               0x01, 0x0f, /* 1: normal */
+               0x02, 0x60, /* 2: 24bit I2S */
+               0x03, 0x01, /* 3: deemphasis off */
+               0x04, 0x00, /* 4: LIN muted */
+               0x05, 0x00, /* 5: RIN muted */
+               0x06, 0x00, /* 6: LOUT muted */
+               0x07, 0x00, /* 7: ROUT muted */
+               0xff, 0xff
+       };
 
-       int chip, num_chips;
+       int chip;
        const unsigned char *ptr, *inits;
        unsigned char reg, data;
 
@@ -270,42 +280,64 @@ void snd_akm4xxx_init(struct snd_akm4xxx *ak)
        switch (ak->type) {
        case SND_AK4524:
                inits = inits_ak4524;
-               num_chips = ak->num_dacs / 2;
+               ak->num_chips = ak->num_dacs / 2;
+               ak->name = "ak4524";
+               ak->total_regs = 0x08;
                break;
        case SND_AK4528:
                inits = inits_ak4528;
-               num_chips = ak->num_dacs / 2;
+               ak->num_chips = ak->num_dacs / 2;
+               ak->name = "ak4528";
+               ak->total_regs = 0x06;
                break;
        case SND_AK4529:
                inits = inits_ak4529;
-               num_chips = 1;
+               ak->num_chips = 1;
+               ak->name = "ak4529";
+               ak->total_regs = 0x0d;
                break;
        case SND_AK4355:
                inits = inits_ak4355;
-               num_chips = 1;
+               ak->num_chips = 1;
+               ak->name = "ak4355";
+               ak->total_regs = 0x0b;
                break;
        case SND_AK4358:
                inits = inits_ak4358;
-               num_chips = 1;
+               ak->num_chips = 1;
+               ak->name = "ak4358";
+               ak->total_regs = 0x10;
                break;
        case SND_AK4381:
                inits = inits_ak4381;
-               num_chips = ak->num_dacs / 2;
+               ak->num_chips = ak->num_dacs / 2;
+               ak->name = "ak4381";
+               ak->total_regs = 0x05;
                break;
        case SND_AK5365:
                /* FIXME: any init sequence? */
+               ak->num_chips = 1;
+               ak->name = "ak5365";
+               ak->total_regs = 0x08;
                return;
+       case SND_AK4620:
+               inits = inits_ak4620;
+               ak->num_chips = ak->num_dacs / 2;
+               ak->name = "ak4620";
+               ak->total_regs = 0x08;
+               break;
        default:
                snd_BUG();
                return;
        }
 
-       for (chip = 0; chip < num_chips; chip++) {
+       for (chip = 0; chip < ak->num_chips; chip++) {
                ptr = inits;
                while (*ptr != 0xff) {
                        reg = *ptr++;
                        data = *ptr++;
                        snd_akm4xxx_write(ak, chip, reg, data);
+                       udelay(10);
                }
        }
 }
@@ -688,6 +720,12 @@ static int build_dac_controls(struct snd_akm4xxx *ak)
                                AK_COMPOSE(idx/2, (idx%2) + 3, 0, 255);
                        knew.tlv.p = db_scale_linear;
                        break;
+               case SND_AK4620:
+                       /* register 6 & 7 */
+                       knew.private_value =
+                               AK_COMPOSE(idx/2, (idx%2) + 6, 0, 255);
+                       knew.tlv.p = db_scale_linear;
+                       break;
                default:
                        return -EINVAL;
                }
@@ -704,10 +742,12 @@ static int build_dac_controls(struct snd_akm4xxx *ak)
 
 static int build_adc_controls(struct snd_akm4xxx *ak)
 {
-       int idx, err, mixer_ch, num_stereo;
+       int idx, err, mixer_ch, num_stereo, max_steps;
        struct snd_kcontrol_new knew;
 
        mixer_ch = 0;
+       if (ak->type == SND_AK4528)
+               return 0;       /* no controls */
        for (idx = 0; idx < ak->num_adcs;) {
                memset(&knew, 0, sizeof(knew));
                if (! ak->adc_info || ! ak->adc_info[mixer_ch].name) {
@@ -733,13 +773,12 @@ static int build_adc_controls(struct snd_akm4xxx *ak)
                }
                /* register 4 & 5 */
                if (ak->type == SND_AK5365)
-                       knew.private_value =
-                               AK_COMPOSE(idx/2, (idx%2) + 4, 0, 151) |
-                               AK_VOL_CVT | AK_IPGA;
+                       max_steps = 152;
                else
-                       knew.private_value =
-                               AK_COMPOSE(idx/2, (idx%2) + 4, 0, 163) |
-                               AK_VOL_CVT | AK_IPGA;
+                       max_steps = 164;
+               knew.private_value =
+                       AK_COMPOSE(idx/2, (idx%2) + 4, 0, max_steps) |
+                       AK_VOL_CVT | AK_IPGA;
                knew.tlv.p = db_scale_vol_datt;
                err = snd_ctl_add(ak->card, snd_ctl_new1(&knew, ak));
                if (err < 0)
@@ -808,6 +847,7 @@ static int build_deemphasis(struct snd_akm4xxx *ak, int num_emphs)
                switch (ak->type) {
                case SND_AK4524:
                case SND_AK4528:
+               case SND_AK4620:
                        /* register 3 */
                        knew.private_value = AK_COMPOSE(idx, 3, 0, 0);
                        break;
@@ -834,6 +874,35 @@ static int build_deemphasis(struct snd_akm4xxx *ak, int num_emphs)
        return 0;
 }
 
+#ifdef CONFIG_PROC_FS
+static void proc_regs_read(struct snd_info_entry *entry,
+               struct snd_info_buffer *buffer)
+{
+       struct snd_akm4xxx *ak = (struct snd_akm4xxx *)entry->private_data;
+       int reg, val, chip;
+       for (chip = 0; chip < ak->num_chips; chip++) {
+               for (reg = 0; reg < ak->total_regs; reg++) {
+                       val =  snd_akm4xxx_get(ak, chip, reg);
+                       snd_iprintf(buffer, "chip %d: 0x%02x = 0x%02x\n", chip,
+                                       reg, val);
+               }
+       }
+}
+
+static int proc_init(struct snd_akm4xxx *ak)
+{
+       struct snd_info_entry *entry;
+       int err;
+       err = snd_card_proc_new(ak->card, ak->name, &entry);
+       if (err < 0)
+               return err;
+       snd_info_set_text_ops(entry, ak, proc_regs_read);
+       return 0;
+}
+#else /* !CONFIG_PROC_FS */
+static int proc_init(struct snd_akm4xxx *ak) {}
+#endif
+
 int snd_akm4xxx_build_controls(struct snd_akm4xxx *ak)
 {
        int err, num_emphs;
@@ -845,18 +914,21 @@ int snd_akm4xxx_build_controls(struct snd_akm4xxx *ak)
        err = build_adc_controls(ak);
        if (err < 0)
                return err;
-
        if (ak->type == SND_AK4355 || ak->type == SND_AK4358)
                num_emphs = 1;
+       else if (ak->type == SND_AK4620)
+               num_emphs = 0;
        else
                num_emphs = ak->num_dacs / 2;
        err = build_deemphasis(ak, num_emphs);
        if (err < 0)
                return err;
+       err = proc_init(ak);
+       if (err < 0)
+               return err;
 
        return 0;
 }
-       
 EXPORT_SYMBOL(snd_akm4xxx_build_controls);
 
 static int __init alsa_akm4xxx_module_init(void)
index d31c373..c4c6ef7 100644 (file)
@@ -225,7 +225,7 @@ static int vidioc_s_ctrl(struct file *file, void *priv,
        case V4L2_CID_AUDIO_MUTE:
                if (tea->ops->mute) {
                        tea->ops->mute(tea, ctrl->value);
-                       tea->mute = 1;
+                       tea->mute = ctrl->value;
                        return 0;
                }
        }
index 51a7e37..02fe81c 100644 (file)
@@ -372,15 +372,21 @@ config SND_SGALAXY
 
 config SND_SSCAPE
        tristate "Ensoniq SoundScape driver"
-       select SND_HWDEP
        select SND_MPU401_UART
        select SND_WSS_LIB
+       select FW_LOADER
        help
          Say Y here to include support for Ensoniq SoundScape 
-         soundcards.
+         and Ensoniq OEM soundcards.
 
          The PCM audio is supported on SoundScape Classic, Elite, PnP
-         and VIVO cards. The MIDI support is very experimental.
+         and VIVO cards. The supported OEM cards are SPEA Media FX and
+         Reveal SC-600.
+         The MIDI support is very experimental and requires binary
+         firmware files called "scope.cod" and "sndscape.co?" where the
+         ? is digit 0, 1, 2, 3 or 4. The firmware files can be found
+         in DOS or Windows driver packages. One has to put the firmware
+         files into the /lib/firmware directory.
 
          To compile this driver as a module, choose M here: the module
          will be called snd-sscape.
index 02f79d2..8246aae 100644 (file)
@@ -237,7 +237,7 @@ WSS_DOUBLE("Wavetable Capture Volume", 0,
                CMI8330_WAVGAIN, CMI8330_WAVGAIN, 4, 0, 15, 0),
 WSS_SINGLE("3D Control - Switch", 0,
                CMI8330_RMUX3D, 5, 1, 1),
-WSS_SINGLE("PC Speaker Playback Volume", 0,
+WSS_SINGLE("Beep Playback Volume", 0,
                CMI8330_OUTPUTVOL, 3, 3, 0),
 WSS_DOUBLE("FM Playback Switch", 0,
                CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 7, 7, 1, 1),
@@ -262,7 +262,7 @@ SB_DOUBLE("SB Line Playback Switch", SB_DSP4_OUTPUT_SW, SB_DSP4_OUTPUT_SW, 4, 3,
 SB_DOUBLE("SB Line Playback Volume", SB_DSP4_LINE_DEV, (SB_DSP4_LINE_DEV + 1), 3, 3, 31),
 SB_SINGLE("SB Mic Playback Switch", SB_DSP4_OUTPUT_SW, 0, 1),
 SB_SINGLE("SB Mic Playback Volume", SB_DSP4_MIC_DEV, 3, 31),
-SB_SINGLE("SB PC Speaker Volume", SB_DSP4_SPEAKER_DEV, 6, 3),
+SB_SINGLE("SB Beep Volume", SB_DSP4_SPEAKER_DEV, 6, 3),
 SB_DOUBLE("SB Capture Volume", SB_DSP4_IGAIN_DEV, (SB_DSP4_IGAIN_DEV + 1), 6, 6, 3),
 SB_DOUBLE("SB Playback Volume", SB_DSP4_OGAIN_DEV, (SB_DSP4_OGAIN_DEV + 1), 6, 6, 3),
 SB_SINGLE("SB Mic Auto Gain", SB_DSP4_MIC_AGC, 0, 1),
index a076a6c..93fa672 100644 (file)
@@ -394,21 +394,15 @@ static int __devinit snd_cs423x_probe(struct snd_card *card, int dev)
                        return -EBUSY;
                }
 
-       err = snd_wss_create(card, port[dev], cport[dev],
+       err = snd_cs4236_create(card, port[dev], cport[dev],
                             irq[dev],
                             dma1[dev], dma2[dev],
                             WSS_HW_DETECT3, 0, &chip);
        if (err < 0)
                return err;
+
+       acard->chip = chip;
        if (chip->hardware & WSS_HW_CS4236B_MASK) {
-               snd_wss_free(chip);
-               err = snd_cs4236_create(card,
-                                       port[dev], cport[dev],
-                                       irq[dev], dma1[dev], dma2[dev],
-                                       WSS_HW_DETECT, 0, &chip);
-               if (err < 0)
-                       return err;
-               acard->chip = chip;
 
                err = snd_cs4236_pcm(chip, 0, &pcm);
                if (err < 0)
@@ -418,7 +412,6 @@ static int __devinit snd_cs423x_probe(struct snd_card *card, int dev)
                if (err < 0)
                        return err;
        } else {
-               acard->chip = chip;
                err = snd_wss_pcm(chip, 0, &pcm);
                if (err < 0)
                        return err;
index 38835f3..c5adca3 100644 (file)
@@ -87,6 +87,8 @@
 #include <sound/core.h>
 #include <sound/wss.h>
 #include <sound/asoundef.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
 
 /*
  *
@@ -264,7 +266,10 @@ static void snd_cs4236_resume(struct snd_wss *chip)
 }
 
 #endif /* CONFIG_PM */
-
+/*
+ * This function does no fail if the chip is not CS4236B or compatible.
+ * It just an equivalent to the snd_wss_create() then.
+ */
 int snd_cs4236_create(struct snd_card *card,
                      unsigned long port,
                      unsigned long cport,
@@ -281,21 +286,17 @@ int snd_cs4236_create(struct snd_card *card,
        *rchip = NULL;
        if (hardware == WSS_HW_DETECT)
                hardware = WSS_HW_DETECT3;
-       if (cport < 0x100) {
-               snd_printk(KERN_ERR "please, specify control port "
-                          "for CS4236+ chips\n");
-               return -ENODEV;
-       }
+
        err = snd_wss_create(card, port, cport,
                             irq, dma1, dma2, hardware, hwshare, &chip);
        if (err < 0)
                return err;
 
-       if (!(chip->hardware & WSS_HW_CS4236B_MASK)) {
-               snd_printk(KERN_ERR "CS4236+: MODE3 and extended registers "
-                          "not available, hardware=0x%x\n", chip->hardware);
-               snd_device_free(card, chip);
-               return -ENODEV;
+       if ((chip->hardware & WSS_HW_CS4236B_MASK) == 0) {
+               snd_printd("chip is not CS4236+, hardware=0x%x\n",
+                          chip->hardware);
+               *rchip = chip;
+               return 0;
        }
 #if 0
        {
@@ -308,9 +309,16 @@ int snd_cs4236_create(struct snd_card *card,
                                   idx, snd_cs4236_ctrl_in(chip, idx));
        }
 #endif
+       if (cport < 0x100 || cport == SNDRV_AUTO_PORT) {
+               snd_printk(KERN_ERR "please, specify control port "
+                          "for CS4236+ chips\n");
+               snd_device_free(card, chip);
+               return -ENODEV;
+       }
        ver1 = snd_cs4236_ctrl_in(chip, 1);
        ver2 = snd_cs4236_ext_in(chip, CS4236_VERSION);
-       snd_printdd("CS4236: [0x%lx] C1 (version) = 0x%x, ext = 0x%x\n", cport, ver1, ver2);
+       snd_printdd("CS4236: [0x%lx] C1 (version) = 0x%x, ext = 0x%x\n",
+                       cport, ver1, ver2);
        if (ver1 != ver2) {
                snd_printk(KERN_ERR "CS4236+ chip detected, but "
                           "control port 0x%lx is not valid\n", cport);
@@ -321,13 +329,17 @@ int snd_cs4236_create(struct snd_card *card,
        snd_cs4236_ctrl_out(chip, 2, 0xff);
        snd_cs4236_ctrl_out(chip, 3, 0x00);
        snd_cs4236_ctrl_out(chip, 4, 0x80);
-       snd_cs4236_ctrl_out(chip, 5, ((IEC958_AES1_CON_PCM_CODER & 3) << 6) | IEC958_AES0_CON_EMPHASIS_NONE);
+       reg = ((IEC958_AES1_CON_PCM_CODER & 3) << 6) |
+             IEC958_AES0_CON_EMPHASIS_NONE;
+       snd_cs4236_ctrl_out(chip, 5, reg);
        snd_cs4236_ctrl_out(chip, 6, IEC958_AES1_CON_PCM_CODER >> 2);
        snd_cs4236_ctrl_out(chip, 7, 0x00);
-       /* 0x8c for C8 is valid for Turtle Beach Malibu - the IEC-958 output */
-       /* is working with this setup, other hardware should have */
-       /* different signal paths and this value should be selectable */
-       /* in the future */
+       /*
+        * 0x8c for C8 is valid for Turtle Beach Malibu - the IEC-958
+        * output is working with this setup, other hardware should
+        * have different signal paths and this value should be
+        * selectable in the future
+        */
        snd_cs4236_ctrl_out(chip, 8, 0x8c);
        chip->rate_constraint = snd_cs4236_xrate;
        chip->set_playback_format = snd_cs4236_playback_format;
@@ -339,9 +351,10 @@ int snd_cs4236_create(struct snd_card *card,
 
        /* initialize extended registers */
        for (reg = 0; reg < sizeof(snd_cs4236_ext_map); reg++)
-               snd_cs4236_ext_out(chip, CS4236_I23VAL(reg), snd_cs4236_ext_map[reg]);
+               snd_cs4236_ext_out(chip, CS4236_I23VAL(reg),
+                                  snd_cs4236_ext_map[reg]);
 
-        /* initialize compatible but more featured registers */
+       /* initialize compatible but more featured registers */
        snd_wss_out(chip, CS4231_LEFT_INPUT, 0x40);
        snd_wss_out(chip, CS4231_RIGHT_INPUT, 0x40);
        snd_wss_out(chip, CS4231_AUX1_LEFT_INPUT, 0xff);
@@ -387,6 +400,14 @@ int snd_cs4236_pcm(struct snd_wss *chip, int device, struct snd_pcm **rpcm)
   .get = snd_cs4236_get_single, .put = snd_cs4236_put_single, \
   .private_value = reg | (shift << 8) | (mask << 16) | (invert << 24) }
 
+#define CS4236_SINGLE_TLV(xname, xindex, reg, shift, mask, invert, xtlv) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
+  .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \
+  .info = snd_cs4236_info_single, \
+  .get = snd_cs4236_get_single, .put = snd_cs4236_put_single, \
+  .private_value = reg | (shift << 8) | (mask << 16) | (invert << 24), \
+  .tlv = { .p = (xtlv) } }
+
 static int snd_cs4236_info_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
 {
        int mask = (kcontrol->private_value >> 16) & 0xff;
@@ -490,6 +511,16 @@ static int snd_cs4236_put_singlec(struct snd_kcontrol *kcontrol, struct snd_ctl_
   .get = snd_cs4236_get_double, .put = snd_cs4236_put_double, \
   .private_value = left_reg | (right_reg << 8) | (shift_left << 16) | (shift_right << 19) | (mask << 24) | (invert << 22) }
 
+#define CS4236_DOUBLE_TLV(xname, xindex, left_reg, right_reg, shift_left, \
+                         shift_right, mask, invert, xtlv) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
+  .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \
+  .info = snd_cs4236_info_double, \
+  .get = snd_cs4236_get_double, .put = snd_cs4236_put_double, \
+  .private_value = left_reg | (right_reg << 8) | (shift_left << 16) | \
+                  (shift_right << 19) | (mask << 24) | (invert << 22), \
+  .tlv = { .p = (xtlv) } }
+
 static int snd_cs4236_info_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
 {
        int mask = (kcontrol->private_value >> 24) & 0xff;
@@ -560,12 +591,23 @@ static int snd_cs4236_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_e
        return change;
 }
 
-#define CS4236_DOUBLE1(xname, xindex, left_reg, right_reg, shift_left, shift_right, mask, invert) \
+#define CS4236_DOUBLE1(xname, xindex, left_reg, right_reg, shift_left, \
+                       shift_right, mask, invert) \
 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
   .info = snd_cs4236_info_double, \
   .get = snd_cs4236_get_double1, .put = snd_cs4236_put_double1, \
   .private_value = left_reg | (right_reg << 8) | (shift_left << 16) | (shift_right << 19) | (mask << 24) | (invert << 22) }
 
+#define CS4236_DOUBLE1_TLV(xname, xindex, left_reg, right_reg, shift_left, \
+                          shift_right, mask, invert, xtlv) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
+  .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \
+  .info = snd_cs4236_info_double, \
+  .get = snd_cs4236_get_double1, .put = snd_cs4236_put_double1, \
+  .private_value = left_reg | (right_reg << 8) | (shift_left << 16) | \
+                  (shift_right << 19) | (mask << 24) | (invert << 22), \
+  .tlv = { .p = (xtlv) } }
+
 static int snd_cs4236_get_double1(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
@@ -619,16 +661,18 @@ static int snd_cs4236_put_double1(struct snd_kcontrol *kcontrol, struct snd_ctl_
        return change;
 }
 
-#define CS4236_MASTER_DIGITAL(xname, xindex) \
+#define CS4236_MASTER_DIGITAL(xname, xindex, xtlv) \
 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
+  .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \
   .info = snd_cs4236_info_double, \
   .get = snd_cs4236_get_master_digital, .put = snd_cs4236_put_master_digital, \
-  .private_value = 71 << 24 }
+  .private_value = 71 << 24, \
+  .tlv = { .p = (xtlv) } }
 
 static inline int snd_cs4236_mixer_master_digital_invert_volume(int vol)
 {
        return (vol < 64) ? 63 - vol : 64 + (71 - vol);
-}        
+}
 
 static int snd_cs4236_get_master_digital(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 {
@@ -661,11 +705,13 @@ static int snd_cs4236_put_master_digital(struct snd_kcontrol *kcontrol, struct s
        return change;
 }
 
-#define CS4235_OUTPUT_ACCU(xname, xindex) \
+#define CS4235_OUTPUT_ACCU(xname, xindex, xtlv) \
 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
+  .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \
   .info = snd_cs4236_info_double, \
   .get = snd_cs4235_get_output_accu, .put = snd_cs4235_put_output_accu, \
-  .private_value = 3 << 24 }
+  .private_value = 3 << 24, \
+  .tlv = { .p = (xtlv) } }
 
 static inline int snd_cs4235_mixer_output_accu_get_volume(int vol)
 {
@@ -720,41 +766,56 @@ static int snd_cs4235_put_output_accu(struct snd_kcontrol *kcontrol, struct snd_
        return change;
 }
 
+static const DECLARE_TLV_DB_SCALE(db_scale_7bit, -9450, 150, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_6bit, -9450, 150, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_6bit_12db_max, -8250, 150, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_5bit_12db_max, -3450, 150, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_5bit_22db_max, -2400, 150, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_4bit, -4500, 300, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_2bit, -1800, 600, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_rec_gain, 0, 150, 0);
+
 static struct snd_kcontrol_new snd_cs4236_controls[] = {
 
 CS4236_DOUBLE("Master Digital Playback Switch", 0,
                CS4236_LEFT_MASTER, CS4236_RIGHT_MASTER, 7, 7, 1, 1),
 CS4236_DOUBLE("Master Digital Capture Switch", 0,
                CS4236_DAC_MUTE, CS4236_DAC_MUTE, 7, 6, 1, 1),
-CS4236_MASTER_DIGITAL("Master Digital Volume", 0),
+CS4236_MASTER_DIGITAL("Master Digital Volume", 0, db_scale_7bit),
 
-CS4236_DOUBLE("Capture Boost Volume", 0,
-               CS4236_LEFT_MIX_CTRL, CS4236_RIGHT_MIX_CTRL, 5, 5, 3, 1),
+CS4236_DOUBLE_TLV("Capture Boost Volume", 0,
+                 CS4236_LEFT_MIX_CTRL, CS4236_RIGHT_MIX_CTRL, 5, 5, 3, 1,
+                 db_scale_2bit),
 
 WSS_DOUBLE("PCM Playback Switch", 0,
                CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 7, 7, 1, 1),
-WSS_DOUBLE("PCM Playback Volume", 0,
-               CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 0, 0, 63, 1),
+WSS_DOUBLE_TLV("PCM Playback Volume", 0,
+               CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 0, 0, 63, 1,
+               db_scale_6bit),
 
 CS4236_DOUBLE("DSP Playback Switch", 0,
                CS4236_LEFT_DSP, CS4236_RIGHT_DSP, 7, 7, 1, 1),
-CS4236_DOUBLE("DSP Playback Volume", 0,
-               CS4236_LEFT_DSP, CS4236_RIGHT_DSP, 0, 0, 63, 1),
+CS4236_DOUBLE_TLV("DSP Playback Volume", 0,
+                 CS4236_LEFT_DSP, CS4236_RIGHT_DSP, 0, 0, 63, 1,
+                 db_scale_6bit),
 
 CS4236_DOUBLE("FM Playback Switch", 0,
                CS4236_LEFT_FM, CS4236_RIGHT_FM, 7, 7, 1, 1),
-CS4236_DOUBLE("FM Playback Volume", 0,
-               CS4236_LEFT_FM, CS4236_RIGHT_FM, 0, 0, 63, 1),
+CS4236_DOUBLE_TLV("FM Playback Volume", 0,
+                 CS4236_LEFT_FM, CS4236_RIGHT_FM, 0, 0, 63, 1,
+                 db_scale_6bit),
 
 CS4236_DOUBLE("Wavetable Playback Switch", 0,
                CS4236_LEFT_WAVE, CS4236_RIGHT_WAVE, 7, 7, 1, 1),
-CS4236_DOUBLE("Wavetable Playback Volume", 0,
-               CS4236_LEFT_WAVE, CS4236_RIGHT_WAVE, 0, 0, 63, 1),
+CS4236_DOUBLE_TLV("Wavetable Playback Volume", 0,
+                 CS4236_LEFT_WAVE, CS4236_RIGHT_WAVE, 0, 0, 63, 1,
+                 db_scale_6bit_12db_max),
 
 WSS_DOUBLE("Synth Playback Switch", 0,
                CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 7, 7, 1, 1),
-WSS_DOUBLE("Synth Volume", 0,
-               CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 0, 0, 31, 1),
+WSS_DOUBLE_TLV("Synth Volume", 0,
+               CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 0, 0, 31, 1,
+               db_scale_5bit_12db_max),
 WSS_DOUBLE("Synth Capture Switch", 0,
                CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 6, 6, 1, 1),
 WSS_DOUBLE("Synth Capture Bypass", 0,
@@ -764,14 +825,16 @@ CS4236_DOUBLE("Mic Playback Switch", 0,
                CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 6, 6, 1, 1),
 CS4236_DOUBLE("Mic Capture Switch", 0,
                CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 7, 7, 1, 1),
-CS4236_DOUBLE("Mic Volume", 0, CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 0, 0, 31, 1),
-CS4236_DOUBLE("Mic Playback Boost", 0,
+CS4236_DOUBLE_TLV("Mic Volume", 0, CS4236_LEFT_MIC, CS4236_RIGHT_MIC,
+                 0, 0, 31, 1, db_scale_5bit_22db_max),
+CS4236_DOUBLE("Mic Playback Boost (+20dB)", 0,
                CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 5, 5, 1, 0),
 
 WSS_DOUBLE("Line Playback Switch", 0,
                CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 7, 7, 1, 1),
-WSS_DOUBLE("Line Volume", 0,
-               CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 0, 0, 31, 1),
+WSS_DOUBLE_TLV("Line Volume", 0,
+               CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 0, 0, 31, 1,
+               db_scale_5bit_12db_max),
 WSS_DOUBLE("Line Capture Switch", 0,
                CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 6, 6, 1, 1),
 WSS_DOUBLE("Line Capture Bypass", 0,
@@ -779,57 +842,63 @@ WSS_DOUBLE("Line Capture Bypass", 0,
 
 WSS_DOUBLE("CD Playback Switch", 0,
                CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 7, 7, 1, 1),
-WSS_DOUBLE("CD Volume", 0,
-               CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 0, 0, 31, 1),
+WSS_DOUBLE_TLV("CD Volume", 0,
+               CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 0, 0, 31, 1,
+               db_scale_5bit_12db_max),
 WSS_DOUBLE("CD Capture Switch", 0,
                CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 6, 6, 1, 1),
 
 CS4236_DOUBLE1("Mono Output Playback Switch", 0,
                CS4231_MONO_CTRL, CS4236_RIGHT_MIX_CTRL, 6, 7, 1, 1),
-CS4236_DOUBLE1("Mono Playback Switch", 0,
+CS4236_DOUBLE1("Beep Playback Switch", 0,
                CS4231_MONO_CTRL, CS4236_LEFT_MIX_CTRL, 7, 7, 1, 1),
-WSS_SINGLE("Mono Playback Volume", 0, CS4231_MONO_CTRL, 0, 15, 1),
-WSS_SINGLE("Mono Playback Bypass", 0, CS4231_MONO_CTRL, 5, 1, 0),
+WSS_SINGLE_TLV("Beep Playback Volume", 0, CS4231_MONO_CTRL, 0, 15, 1,
+               db_scale_4bit),
+WSS_SINGLE("Beep Bypass Playback Switch", 0, CS4231_MONO_CTRL, 5, 1, 0),
 
-WSS_DOUBLE("Capture Volume", 0,
-               CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 0, 0, 15, 0),
+WSS_DOUBLE_TLV("Capture Volume", 0, CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT,
+               0, 0, 15, 0, db_scale_rec_gain),
 WSS_DOUBLE("Analog Loopback Capture Switch", 0,
                CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 7, 7, 1, 0),
 
-WSS_SINGLE("Digital Loopback Playback Switch", 0, CS4231_LOOPBACK, 0, 1, 0),
-CS4236_DOUBLE1("Digital Loopback Playback Volume", 0,
-               CS4231_LOOPBACK, CS4236_RIGHT_LOOPBACK, 2, 0, 63, 1)
+WSS_SINGLE("Loopback Digital Playback Switch", 0, CS4231_LOOPBACK, 0, 1, 0),
+CS4236_DOUBLE1_TLV("Loopback Digital Playback Volume", 0,
+                  CS4231_LOOPBACK, CS4236_RIGHT_LOOPBACK, 2, 0, 63, 1,
+                  db_scale_6bit),
 };
 
+static const DECLARE_TLV_DB_SCALE(db_scale_5bit_6db_max, -5600, 200, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_2bit_16db_max, -2400, 800, 0);
+
 static struct snd_kcontrol_new snd_cs4235_controls[] = {
 
-WSS_DOUBLE("Master Switch", 0,
+WSS_DOUBLE("Master Playback Switch", 0,
                CS4235_LEFT_MASTER, CS4235_RIGHT_MASTER, 7, 7, 1, 1),
-WSS_DOUBLE("Master Volume", 0,
-               CS4235_LEFT_MASTER, CS4235_RIGHT_MASTER, 0, 0, 31, 1),
-
-CS4235_OUTPUT_ACCU("Playback Volume", 0),
+WSS_DOUBLE_TLV("Master Playback Volume", 0,
+               CS4235_LEFT_MASTER, CS4235_RIGHT_MASTER, 0, 0, 31, 1,
+               db_scale_5bit_6db_max),
 
-CS4236_DOUBLE("Master Digital Playback Switch", 0,
-               CS4236_LEFT_MASTER, CS4236_RIGHT_MASTER, 7, 7, 1, 1),
-CS4236_DOUBLE("Master Digital Capture Switch", 0,
-               CS4236_DAC_MUTE, CS4236_DAC_MUTE, 7, 6, 1, 1),
-CS4236_MASTER_DIGITAL("Master Digital Volume", 0),
+CS4235_OUTPUT_ACCU("Playback Volume", 0, db_scale_2bit_16db_max),
 
-WSS_DOUBLE("Master Digital Playback Switch", 1,
+WSS_DOUBLE("Synth Playback Switch", 1,
                CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 7, 7, 1, 1),
-WSS_DOUBLE("Master Digital Capture Switch", 1,
+WSS_DOUBLE("Synth Capture Switch", 1,
                CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 6, 6, 1, 1),
-WSS_DOUBLE("Master Digital Volume", 1,
-               CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 0, 0, 31, 1),
+WSS_DOUBLE_TLV("Synth Volume", 1,
+               CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 0, 0, 31, 1,
+               db_scale_5bit_12db_max),
 
-CS4236_DOUBLE("Capture Volume", 0,
-               CS4236_LEFT_MIX_CTRL, CS4236_RIGHT_MIX_CTRL, 5, 5, 3, 1),
+CS4236_DOUBLE_TLV("Capture Volume", 0,
+                 CS4236_LEFT_MIX_CTRL, CS4236_RIGHT_MIX_CTRL, 5, 5, 3, 1,
+                 db_scale_2bit),
 
-WSS_DOUBLE("PCM Switch", 0,
+WSS_DOUBLE("PCM Playback Switch", 0,
                CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 7, 7, 1, 1),
-WSS_DOUBLE("PCM Volume", 0,
-               CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 0, 0, 63, 1),
+WSS_DOUBLE("PCM Capture Switch", 0,
+               CS4236_DAC_MUTE, CS4236_DAC_MUTE, 7, 6, 1, 1),
+WSS_DOUBLE_TLV("PCM Volume", 0,
+               CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 0, 0, 63, 1,
+               db_scale_6bit),
 
 CS4236_DOUBLE("DSP Switch", 0, CS4236_LEFT_DSP, CS4236_RIGHT_DSP, 7, 7, 1, 1),
 
@@ -842,29 +911,29 @@ CS4236_DOUBLE("Mic Capture Switch", 0,
                CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 7, 7, 1, 1),
 CS4236_DOUBLE("Mic Playback Switch", 0,
                CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 6, 6, 1, 1),
-CS4236_SINGLE("Mic Volume", 0, CS4236_LEFT_MIC, 0, 31, 1),
-CS4236_SINGLE("Mic Playback Boost", 0, CS4236_LEFT_MIC, 5, 1, 0),
+CS4236_SINGLE_TLV("Mic Volume", 0, CS4236_LEFT_MIC, 0, 31, 1,
+                 db_scale_5bit_22db_max),
+CS4236_SINGLE("Mic Boost (+20dB)", 0, CS4236_LEFT_MIC, 5, 1, 0),
 
-WSS_DOUBLE("Aux Playback Switch", 0,
+WSS_DOUBLE("Line Playback Switch", 0,
                CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 7, 7, 1, 1),
-WSS_DOUBLE("Aux Capture Switch", 0,
+WSS_DOUBLE("Line Capture Switch", 0,
                CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 6, 6, 1, 1),
-WSS_DOUBLE("Aux Volume", 0,
-               CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 0, 0, 31, 1),
+WSS_DOUBLE_TLV("Line Volume", 0,
+               CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 0, 0, 31, 1,
+               db_scale_5bit_12db_max),
 
-WSS_DOUBLE("Aux Playback Switch", 1,
+WSS_DOUBLE("CD Playback Switch", 1,
                CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 7, 7, 1, 1),
-WSS_DOUBLE("Aux Capture Switch", 1,
+WSS_DOUBLE("CD Capture Switch", 1,
                CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 6, 6, 1, 1),
-WSS_DOUBLE("Aux Volume", 1,
-               CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 0, 0, 31, 1),
-
-CS4236_DOUBLE1("Master Mono Switch", 0,
-               CS4231_MONO_CTRL, CS4236_RIGHT_MIX_CTRL, 6, 7, 1, 1),
+WSS_DOUBLE_TLV("CD Volume", 1,
+               CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 0, 0, 31, 1,
+               db_scale_5bit_12db_max),
 
-CS4236_DOUBLE1("Mono Switch", 0,
+CS4236_DOUBLE1("Beep Playback Switch", 0,
                CS4231_MONO_CTRL, CS4236_LEFT_MIX_CTRL, 7, 7, 1, 1),
-WSS_SINGLE("Mono Volume", 0, CS4231_MONO_CTRL, 0, 15, 1),
+WSS_SINGLE("Beep Playback Volume", 0, CS4231_MONO_CTRL, 0, 15, 1),
 
 WSS_DOUBLE("Analog Loopback Switch", 0,
                CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 7, 7, 1, 0),
index 4c6e14f..c76bb00 100644 (file)
@@ -982,7 +982,7 @@ ES1688_DOUBLE("CD Playback Volume", 0, ES1688_CD_DEV, ES1688_CD_DEV, 4, 0, 15, 0
 ES1688_DOUBLE("FM Playback Volume", 0, ES1688_FM_DEV, ES1688_FM_DEV, 4, 0, 15, 0),
 ES1688_DOUBLE("Mic Playback Volume", 0, ES1688_MIC_DEV, ES1688_MIC_DEV, 4, 0, 15, 0),
 ES1688_DOUBLE("Aux Playback Volume", 0, ES1688_AUX_DEV, ES1688_AUX_DEV, 4, 0, 15, 0),
-ES1688_SINGLE("PC Speaker Playback Volume", 0, ES1688_SPEAKER_DEV, 0, 7, 0),
+ES1688_SINGLE("Beep Playback Volume", 0, ES1688_SPEAKER_DEV, 0, 7, 0),
 ES1688_DOUBLE("Capture Volume", 0, ES1688_RECLEV_DEV, ES1688_RECLEV_DEV, 4, 0, 15, 0),
 ES1688_SINGLE("Capture Switch", 0, ES1688_REC_DEV, 4, 1, 1),
 {
index 8cfbff7..9a43baa 100644 (file)
 
 struct snd_es18xx {
        unsigned long port;             /* port of ESS chip */
-       unsigned long mpu_port;         /* MPU-401 port of ESS chip */
-       unsigned long fm_port;          /* FM port */
        unsigned long ctrl_port;        /* Control port of ESS chip */
        struct resource *res_port;
        struct resource *res_mpu_port;
@@ -116,12 +114,9 @@ struct snd_es18xx {
        unsigned short audio2_vol;      /* volume level of audio2 */
 
        unsigned short active;          /* active channel mask */
-       unsigned int dma1_size;
-       unsigned int dma2_size;
        unsigned int dma1_shift;
        unsigned int dma2_shift;
 
-       struct snd_card *card;
        struct snd_pcm *pcm;
        struct snd_pcm_substream *playback_a_substream;
        struct snd_pcm_substream *capture_a_substream;
@@ -136,14 +131,9 @@ struct snd_es18xx {
 
        spinlock_t reg_lock;
        spinlock_t mixer_lock;
-       spinlock_t ctrl_lock;
 #ifdef CONFIG_PM
        unsigned char pm_reg;
 #endif
-};
-
-struct snd_audiodrive {
-       struct snd_es18xx *chip;
 #ifdef CONFIG_PNP
        struct pnp_dev *dev;
        struct pnp_dev *devc;
@@ -359,7 +349,7 @@ static inline int snd_es18xx_mixer_writable(struct snd_es18xx *chip, unsigned ch
 }
 
 
-static int snd_es18xx_reset(struct snd_es18xx *chip)
+static int __devinit snd_es18xx_reset(struct snd_es18xx *chip)
 {
        int i;
         outb(0x03, chip->port + 0x06);
@@ -495,8 +485,6 @@ static int snd_es18xx_playback1_prepare(struct snd_es18xx *chip,
        unsigned int size = snd_pcm_lib_buffer_bytes(substream);
        unsigned int count = snd_pcm_lib_period_bytes(substream);
 
-       chip->dma2_size = size;
-
         snd_es18xx_rate_set(chip, substream, DAC2);
 
         /* Transfer Count Reload */
@@ -596,8 +584,6 @@ static int snd_es18xx_capture_prepare(struct snd_pcm_substream *substream)
        unsigned int size = snd_pcm_lib_buffer_bytes(substream);
        unsigned int count = snd_pcm_lib_period_bytes(substream);
 
-       chip->dma1_size = size;
-
        snd_es18xx_reset_fifo(chip);
 
         /* Set stereo/mono */
@@ -664,8 +650,6 @@ static int snd_es18xx_playback2_prepare(struct snd_es18xx *chip,
        unsigned int size = snd_pcm_lib_buffer_bytes(substream);
        unsigned int count = snd_pcm_lib_period_bytes(substream);
 
-       chip->dma1_size = size;
-
        snd_es18xx_reset_fifo(chip);
 
         /* Set stereo/mono */
@@ -755,7 +739,8 @@ static int snd_es18xx_playback_trigger(struct snd_pcm_substream *substream,
 
 static irqreturn_t snd_es18xx_interrupt(int irq, void *dev_id)
 {
-       struct snd_es18xx *chip = dev_id;
+       struct snd_card *card = dev_id;
+       struct snd_es18xx *chip = card->private_data;
        unsigned char status;
 
        if (chip->caps & ES18XX_CONTROL) {
@@ -805,12 +790,16 @@ static irqreturn_t snd_es18xx_interrupt(int irq, void *dev_id)
                int split = 0;
                if (chip->caps & ES18XX_HWV) {
                        split = snd_es18xx_mixer_read(chip, 0x64) & 0x80;
-                       snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, &chip->hw_switch->id);
-                       snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, &chip->hw_volume->id);
+                       snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE,
+                                       &chip->hw_switch->id);
+                       snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE,
+                                       &chip->hw_volume->id);
                }
                if (!split) {
-                       snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, &chip->master_switch->id);
-                       snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, &chip->master_volume->id);
+                       snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE,
+                                       &chip->master_switch->id);
+                       snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE,
+                                       &chip->master_volume->id);
                }
                /* ack interrupt */
                snd_es18xx_mixer_write(chip, 0x66, 0x00);
@@ -821,17 +810,18 @@ static irqreturn_t snd_es18xx_interrupt(int irq, void *dev_id)
 static snd_pcm_uframes_t snd_es18xx_playback_pointer(struct snd_pcm_substream *substream)
 {
         struct snd_es18xx *chip = snd_pcm_substream_chip(substream);
+       unsigned int size = snd_pcm_lib_buffer_bytes(substream);
        int pos;
 
        if (substream->number == 0 && (chip->caps & ES18XX_PCM2)) {
                if (!(chip->active & DAC2))
                        return 0;
-               pos = snd_dma_pointer(chip->dma2, chip->dma2_size);
+               pos = snd_dma_pointer(chip->dma2, size);
                return pos >> chip->dma2_shift;
        } else {
                if (!(chip->active & DAC1))
                        return 0;
-               pos = snd_dma_pointer(chip->dma1, chip->dma1_size);
+               pos = snd_dma_pointer(chip->dma1, size);
                return pos >> chip->dma1_shift;
        }
 }
@@ -839,11 +829,12 @@ static snd_pcm_uframes_t snd_es18xx_playback_pointer(struct snd_pcm_substream *s
 static snd_pcm_uframes_t snd_es18xx_capture_pointer(struct snd_pcm_substream *substream)
 {
         struct snd_es18xx *chip = snd_pcm_substream_chip(substream);
+       unsigned int size = snd_pcm_lib_buffer_bytes(substream);
        int pos;
 
         if (!(chip->active & ADC1))
                 return 0;
-       pos = snd_dma_pointer(chip->dma1, chip->dma1_size);
+       pos = snd_dma_pointer(chip->dma1, size);
        return pos >> chip->dma1_shift;
 }
 
@@ -974,9 +965,6 @@ static int snd_es18xx_capture_close(struct snd_pcm_substream *substream)
 
 static int snd_es18xx_info_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
 {
-       static char *texts4Source[4] = {
-               "Mic", "CD", "Line", "Master"
-       };
        static char *texts5Source[5] = {
                "Mic", "CD", "Line", "Master", "Mix"
        };
@@ -994,7 +982,8 @@ static int snd_es18xx_info_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_ele
                uinfo->value.enumerated.items = 4;
                if (uinfo->value.enumerated.item > 3)
                        uinfo->value.enumerated.item = 3;
-               strcpy(uinfo->value.enumerated.name, texts4Source[uinfo->value.enumerated.item]);
+               strcpy(uinfo->value.enumerated.name,
+                       texts5Source[uinfo->value.enumerated.item]);
                break;
        case 0x1887:
        case 0x1888:
@@ -1313,7 +1302,7 @@ ES18XX_DOUBLE("Aux Capture Volume", 0, 0x6c, 0x6c, 4, 0, 15, 0)
  * The chipset specific mixer controls
  */
 static struct snd_kcontrol_new snd_es18xx_opt_speaker =
-       ES18XX_SINGLE("PC Speaker Playback Volume", 0, 0x3c, 0, 7, 0);
+       ES18XX_SINGLE("Beep Playback Volume", 0, 0x3c, 0, 7, 0);
 
 static struct snd_kcontrol_new snd_es18xx_opt_1869[] = {
 ES18XX_SINGLE("Capture Switch", 0, 0x1c, 4, 1, 1),
@@ -1378,11 +1367,9 @@ ES18XX_SINGLE("Hardware Master Volume Split", 0, 0x64, 7, 1, 0),
 static int __devinit snd_es18xx_config_read(struct snd_es18xx *chip, unsigned char reg)
 {
        int data;
-       unsigned long flags;
-        spin_lock_irqsave(&chip->ctrl_lock, flags);
+
        outb(reg, chip->ctrl_port);
        data = inb(chip->ctrl_port + 1);
-        spin_unlock_irqrestore(&chip->ctrl_lock, flags);
        return data;
 }
 
@@ -1398,7 +1385,9 @@ static void __devinit snd_es18xx_config_write(struct snd_es18xx *chip,
 #endif
 }
 
-static int __devinit snd_es18xx_initialize(struct snd_es18xx *chip)
+static int __devinit snd_es18xx_initialize(struct snd_es18xx *chip,
+                                          unsigned long mpu_port,
+                                          unsigned long fm_port)
 {
        int mask = 0;
 
@@ -1412,15 +1401,15 @@ static int __devinit snd_es18xx_initialize(struct snd_es18xx *chip)
        if (chip->caps & ES18XX_CONTROL) {
                /* Hardware volume IRQ */
                snd_es18xx_config_write(chip, 0x27, chip->irq);
-               if (chip->fm_port > 0 && chip->fm_port != SNDRV_AUTO_PORT) {
+               if (fm_port > 0 && fm_port != SNDRV_AUTO_PORT) {
                        /* FM I/O */
-                       snd_es18xx_config_write(chip, 0x62, chip->fm_port >> 8);
-                       snd_es18xx_config_write(chip, 0x63, chip->fm_port & 0xff);
+                       snd_es18xx_config_write(chip, 0x62, fm_port >> 8);
+                       snd_es18xx_config_write(chip, 0x63, fm_port & 0xff);
                }
-               if (chip->mpu_port > 0 && chip->mpu_port != SNDRV_AUTO_PORT) {
+               if (mpu_port > 0 && mpu_port != SNDRV_AUTO_PORT) {
                        /* MPU-401 I/O */
-                       snd_es18xx_config_write(chip, 0x64, chip->mpu_port >> 8);
-                       snd_es18xx_config_write(chip, 0x65, chip->mpu_port & 0xff);
+                       snd_es18xx_config_write(chip, 0x64, mpu_port >> 8);
+                       snd_es18xx_config_write(chip, 0x65, mpu_port & 0xff);
                        /* MPU-401 IRQ */
                        snd_es18xx_config_write(chip, 0x28, chip->irq);
                }
@@ -1507,11 +1496,12 @@ static int __devinit snd_es18xx_initialize(struct snd_es18xx *chip)
                snd_es18xx_mixer_write(chip, 0x7A, 0x68);
                /* Enable and set hardware volume interrupt */
                snd_es18xx_mixer_write(chip, 0x64, 0x06);
-               if (chip->mpu_port > 0 && chip->mpu_port != SNDRV_AUTO_PORT) {
+               if (mpu_port > 0 && mpu_port != SNDRV_AUTO_PORT) {
                        /* MPU401 share irq with audio
                           Joystick enabled
                           FM enabled */
-                       snd_es18xx_mixer_write(chip, 0x40, 0x43 | (chip->mpu_port & 0xf0) >> 1);
+                       snd_es18xx_mixer_write(chip, 0x40,
+                                              0x43 | (mpu_port & 0xf0) >> 1);
                }
                snd_es18xx_mixer_write(chip, 0x7f, ((irqmask + 1) << 1) | 0x01);
        }
@@ -1629,7 +1619,9 @@ static int __devinit snd_es18xx_identify(struct snd_es18xx *chip)
        return 0;
 }
 
-static int __devinit snd_es18xx_probe(struct snd_es18xx *chip)
+static int __devinit snd_es18xx_probe(struct snd_es18xx *chip,
+                                       unsigned long mpu_port,
+                                       unsigned long fm_port)
 {
        if (snd_es18xx_identify(chip) < 0) {
                snd_printk(KERN_ERR PFX "[0x%lx] ESS chip not found\n", chip->port);
@@ -1650,8 +1642,6 @@ static int __devinit snd_es18xx_probe(struct snd_es18xx *chip)
                chip->caps = ES18XX_PCM2 | ES18XX_SPATIALIZER | ES18XX_RECMIX | ES18XX_NEW_RATE | ES18XX_AUXB | ES18XX_I2S | ES18XX_CONTROL | ES18XX_HWV;
                break;
        case 0x1887:
-               chip->caps = ES18XX_PCM2 | ES18XX_RECMIX | ES18XX_AUXB | ES18XX_DUPLEX_SAME;
-               break;
        case 0x1888:
                chip->caps = ES18XX_PCM2 | ES18XX_RECMIX | ES18XX_AUXB | ES18XX_DUPLEX_SAME;
                break;
@@ -1666,7 +1656,7 @@ static int __devinit snd_es18xx_probe(struct snd_es18xx *chip)
        if (chip->dma1 == chip->dma2)
                chip->caps &= ~(ES18XX_PCM2 | ES18XX_DUPLEX_SAME);
 
-        return snd_es18xx_initialize(chip);
+       return snd_es18xx_initialize(chip, mpu_port, fm_port);
 }
 
 static struct snd_pcm_ops snd_es18xx_playback_ops = {
@@ -1691,8 +1681,10 @@ static struct snd_pcm_ops snd_es18xx_capture_ops = {
        .pointer =      snd_es18xx_capture_pointer,
 };
 
-static int __devinit snd_es18xx_pcm(struct snd_es18xx *chip, int device, struct snd_pcm ** rpcm)
+static int __devinit snd_es18xx_pcm(struct snd_card *card, int device,
+                                   struct snd_pcm **rpcm)
 {
+       struct snd_es18xx *chip = card->private_data;
         struct snd_pcm *pcm;
        char str[16];
        int err;
@@ -1701,9 +1693,9 @@ static int __devinit snd_es18xx_pcm(struct snd_es18xx *chip, int device, struct
                *rpcm = NULL;
        sprintf(str, "ES%x", chip->version);
        if (chip->caps & ES18XX_PCM2)
-               err = snd_pcm_new(chip->card, str, device, 2, 1, &pcm);
+               err = snd_pcm_new(card, str, device, 2, 1, &pcm);
        else
-               err = snd_pcm_new(chip->card, str, device, 1, 1, &pcm);
+               err = snd_pcm_new(card, str, device, 1, 1, &pcm);
         if (err < 0)
                 return err;
 
@@ -1734,10 +1726,9 @@ static int __devinit snd_es18xx_pcm(struct snd_es18xx *chip, int device, struct
 #ifdef CONFIG_PM
 static int snd_es18xx_suspend(struct snd_card *card, pm_message_t state)
 {
-       struct snd_audiodrive *acard = card->private_data;
-       struct snd_es18xx *chip = acard->chip;
+       struct snd_es18xx *chip = card->private_data;
 
-       snd_power_change_state(chip->card, SNDRV_CTL_POWER_D3hot);
+       snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
 
        snd_pcm_suspend_all(chip->pcm);
 
@@ -1752,24 +1743,25 @@ static int snd_es18xx_suspend(struct snd_card *card, pm_message_t state)
 
 static int snd_es18xx_resume(struct snd_card *card)
 {
-       struct snd_audiodrive *acard = card->private_data;
-       struct snd_es18xx *chip = acard->chip;
+       struct snd_es18xx *chip = card->private_data;
 
        /* restore PM register, we won't wake till (not 0x07) i/o activity though */
        snd_es18xx_write(chip, ES18XX_PM, chip->pm_reg ^= ES18XX_PM_FM);
 
-       snd_power_change_state(chip->card, SNDRV_CTL_POWER_D0);
+       snd_power_change_state(card, SNDRV_CTL_POWER_D0);
        return 0;
 }
 #endif /* CONFIG_PM */
 
-static int snd_es18xx_free(struct snd_es18xx *chip)
+static int snd_es18xx_free(struct snd_card *card)
 {
+       struct snd_es18xx *chip = card->private_data;
+
        release_and_free_resource(chip->res_port);
        release_and_free_resource(chip->res_ctrl_port);
        release_and_free_resource(chip->res_mpu_port);
        if (chip->irq >= 0)
-               free_irq(chip->irq, (void *) chip);
+               free_irq(chip->irq, (void *) card);
        if (chip->dma1 >= 0) {
                disable_dma(chip->dma1);
                free_dma(chip->dma1);
@@ -1778,93 +1770,82 @@ static int snd_es18xx_free(struct snd_es18xx *chip)
                disable_dma(chip->dma2);
                free_dma(chip->dma2);
        }
-       kfree(chip);
        return 0;
 }
 
 static int snd_es18xx_dev_free(struct snd_device *device)
 {
-       struct snd_es18xx *chip = device->device_data;
-       return snd_es18xx_free(chip);
+       return snd_es18xx_free(device->card);
 }
 
 static int __devinit snd_es18xx_new_device(struct snd_card *card,
                                           unsigned long port,
                                           unsigned long mpu_port,
                                           unsigned long fm_port,
-                                          int irq, int dma1, int dma2,
-                                          struct snd_es18xx ** rchip)
+                                          int irq, int dma1, int dma2)
 {
-        struct snd_es18xx *chip;
+       struct snd_es18xx *chip = card->private_data;
        static struct snd_device_ops ops = {
                .dev_free =     snd_es18xx_dev_free,
         };
        int err;
 
-       *rchip = NULL;
-        chip = kzalloc(sizeof(*chip), GFP_KERNEL);
-       if (chip == NULL)
-               return -ENOMEM;
        spin_lock_init(&chip->reg_lock);
        spin_lock_init(&chip->mixer_lock);
-       spin_lock_init(&chip->ctrl_lock);
-        chip->card = card;
         chip->port = port;
-        chip->mpu_port = mpu_port;
-        chip->fm_port = fm_port;
         chip->irq = -1;
         chip->dma1 = -1;
         chip->dma2 = -1;
         chip->audio2_vol = 0x00;
        chip->active = 0;
 
-       if ((chip->res_port = request_region(port, 16, "ES18xx")) == NULL) {
-               snd_es18xx_free(chip);
+       chip->res_port = request_region(port, 16, "ES18xx");
+       if (chip->res_port == NULL) {
+               snd_es18xx_free(card);
                snd_printk(KERN_ERR PFX "unable to grap ports 0x%lx-0x%lx\n", port, port + 16 - 1);
                return -EBUSY;
        }
 
-       if (request_irq(irq, snd_es18xx_interrupt, IRQF_DISABLED, "ES18xx", (void *) chip)) {
-               snd_es18xx_free(chip);
+       if (request_irq(irq, snd_es18xx_interrupt, IRQF_DISABLED, "ES18xx",
+                       (void *) card)) {
+               snd_es18xx_free(card);
                snd_printk(KERN_ERR PFX "unable to grap IRQ %d\n", irq);
                return -EBUSY;
        }
        chip->irq = irq;
 
        if (request_dma(dma1, "ES18xx DMA 1")) {
-               snd_es18xx_free(chip);
+               snd_es18xx_free(card);
                snd_printk(KERN_ERR PFX "unable to grap DMA1 %d\n", dma1);
                return -EBUSY;
        }
        chip->dma1 = dma1;
 
        if (dma2 != dma1 && request_dma(dma2, "ES18xx DMA 2")) {
-               snd_es18xx_free(chip);
+               snd_es18xx_free(card);
                snd_printk(KERN_ERR PFX "unable to grap DMA2 %d\n", dma2);
                return -EBUSY;
        }
        chip->dma2 = dma2;
 
-        if (snd_es18xx_probe(chip) < 0) {
-                snd_es18xx_free(chip);
-                return -ENODEV;
-        }
-       if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) {
-               snd_es18xx_free(chip);
+       if (snd_es18xx_probe(chip, mpu_port, fm_port) < 0) {
+               snd_es18xx_free(card);
+               return -ENODEV;
+       }
+       err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops);
+       if (err < 0) {
+               snd_es18xx_free(card);
                return err;
        }
-        *rchip = chip;
         return 0;
 }
 
-static int __devinit snd_es18xx_mixer(struct snd_es18xx *chip)
+static int __devinit snd_es18xx_mixer(struct snd_card *card)
 {
-       struct snd_card *card;
+       struct snd_es18xx *chip = card->private_data;
        int err;
        unsigned int idx;
 
-       card = chip->card;
-
        strcpy(card->mixername, chip->pcm->name);
 
        for (idx = 0; idx < ARRAY_SIZE(snd_es18xx_base_controls); idx++) {
@@ -1986,7 +1967,7 @@ static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;        /* Index 0-MAX */
 static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;      /* ID for this card */
 static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_ISAPNP; /* Enable this card */
 #ifdef CONFIG_PNP
-static int isapnp[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 1};
+static int isapnp[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_ISAPNP;
 #endif
 static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;    /* 0x220,0x240,0x260,0x280 */
 #ifndef CONFIG_PNP
@@ -2063,11 +2044,11 @@ static int __devinit snd_audiodrive_pnp_init_main(int dev, struct pnp_dev *pdev)
        return 0;
 }
 
-static int __devinit snd_audiodrive_pnp(int dev, struct snd_audiodrive *acard,
+static int __devinit snd_audiodrive_pnp(int dev, struct snd_es18xx *chip,
                                        struct pnp_dev *pdev)
 {
-       acard->dev = pdev;
-       if (snd_audiodrive_pnp_init_main(dev, acard->dev) < 0)
+       chip->dev = pdev;
+       if (snd_audiodrive_pnp_init_main(dev, chip->dev) < 0)
                return -EBUSY;
        return 0;
 }
@@ -2093,26 +2074,26 @@ static struct pnp_card_device_id snd_audiodrive_pnpids[] = {
 
 MODULE_DEVICE_TABLE(pnp_card, snd_audiodrive_pnpids);
 
-static int __devinit snd_audiodrive_pnpc(int dev, struct snd_audiodrive *acard,
+static int __devinit snd_audiodrive_pnpc(int dev, struct snd_es18xx *chip,
                                        struct pnp_card_link *card,
                                        const struct pnp_card_device_id *id)
 {
-       acard->dev = pnp_request_card_device(card, id->devs[0].id, NULL);
-       if (acard->dev == NULL)
+       chip->dev = pnp_request_card_device(card, id->devs[0].id, NULL);
+       if (chip->dev == NULL)
                return -EBUSY;
 
-       acard->devc = pnp_request_card_device(card, id->devs[1].id, NULL);
-       if (acard->devc == NULL)
+       chip->devc = pnp_request_card_device(card, id->devs[1].id, NULL);
+       if (chip->devc == NULL)
                return -EBUSY;
 
        /* Control port initialization */
-       if (pnp_activate_dev(acard->devc) < 0) {
+       if (pnp_activate_dev(chip->devc) < 0) {
                snd_printk(KERN_ERR PFX "PnP control configure failure (out of resources?)\n");
                return -EAGAIN;
        }
        snd_printdd("pnp: port=0x%llx\n",
-                       (unsigned long long)pnp_port_start(acard->devc, 0));
-       if (snd_audiodrive_pnp_init_main(dev, acard->dev) < 0)
+                       (unsigned long long)pnp_port_start(chip->devc, 0));
+       if (snd_audiodrive_pnp_init_main(dev, chip->dev) < 0)
                return -EBUSY;
 
        return 0;
@@ -2128,24 +2109,20 @@ static int __devinit snd_audiodrive_pnpc(int dev, struct snd_audiodrive *acard,
 static int snd_es18xx_card_new(int dev, struct snd_card **cardp)
 {
        return snd_card_create(index[dev], id[dev], THIS_MODULE,
-                              sizeof(struct snd_audiodrive), cardp);
+                              sizeof(struct snd_es18xx), cardp);
 }
 
 static int __devinit snd_audiodrive_probe(struct snd_card *card, int dev)
 {
-       struct snd_audiodrive *acard = card->private_data;
-       struct snd_es18xx *chip;
+       struct snd_es18xx *chip = card->private_data;
        struct snd_opl3 *opl3;
        int err;
 
-       if ((err = snd_es18xx_new_device(card,
-                                        port[dev],
-                                        mpu_port[dev],
-                                        fm_port[dev],
-                                        irq[dev], dma1[dev], dma2[dev],
-                                        &chip)) < 0)
+       err = snd_es18xx_new_device(card,
+                                   port[dev], mpu_port[dev], fm_port[dev],
+                                   irq[dev], dma1[dev], dma2[dev]);
+       if (err < 0)
                return err;
-       acard->chip = chip;
 
        sprintf(card->driver, "ES%x", chip->version);
        
@@ -2161,26 +2138,32 @@ static int __devinit snd_audiodrive_probe(struct snd_card *card, int dev)
                        chip->port,
                        irq[dev], dma1[dev]);
 
-       if ((err = snd_es18xx_pcm(chip, 0, NULL)) < 0)
+       err = snd_es18xx_pcm(card, 0, NULL);
+       if (err < 0)
                return err;
 
-       if ((err = snd_es18xx_mixer(chip)) < 0)
+       err = snd_es18xx_mixer(card);
+       if (err < 0)
                return err;
 
        if (fm_port[dev] > 0 && fm_port[dev] != SNDRV_AUTO_PORT) {
-               if (snd_opl3_create(card, chip->fm_port, chip->fm_port + 2, OPL3_HW_OPL3, 0, &opl3) < 0) {
-                       snd_printk(KERN_WARNING PFX "opl3 not detected at 0x%lx\n", chip->fm_port);
+               if (snd_opl3_create(card, fm_port[dev], fm_port[dev] + 2,
+                                   OPL3_HW_OPL3, 0, &opl3) < 0) {
+                       snd_printk(KERN_WARNING PFX
+                                  "opl3 not detected at 0x%lx\n",
+                                  fm_port[dev]);
                } else {
-                       if ((err = snd_opl3_hwdep_new(opl3, 0, 1, NULL)) < 0)
+                       err = snd_opl3_hwdep_new(opl3, 0, 1, NULL);
+                       if (err < 0)
                                return err;
                }
        }
 
        if (mpu_port[dev] > 0 && mpu_port[dev] != SNDRV_AUTO_PORT) {
-               if ((err = snd_mpu401_uart_new(card, 0, MPU401_HW_ES18XX,
-                                              chip->mpu_port, 0,
-                                              irq[dev], 0,
-                                              &chip->rmidi)) < 0)
+               err = snd_mpu401_uart_new(card, 0, MPU401_HW_ES18XX,
+                                         mpu_port[dev], 0,
+                                         irq[dev], 0, &chip->rmidi);
+               if (err < 0)
                        return err;
        }
 
index 02e30d7..6123c75 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/init.h>
 #include <linux/err.h>
 #include <linux/isa.h>
+#include <linux/pnp.h>
 #include <linux/delay.h>
 #include <linux/slab.h>
 #include <linux/ioport.h>
@@ -40,7 +41,7 @@
 #define SNDRV_LEGACY_FIND_FREE_IRQ
 #define SNDRV_LEGACY_FIND_FREE_DMA
 #include <sound/initval.h>
-#include "miro.h"
+#include <sound/aci.h>
 
 MODULE_AUTHOR("Martin Langer <martin-langer@gmx.de>");
 MODULE_LICENSE("GPL");
@@ -60,6 +61,9 @@ static int dma1 = SNDRV_DEFAULT_DMA1;         /* 0,1,3 */
 static int dma2 = SNDRV_DEFAULT_DMA1;          /* 0,1,3 */
 static int wss;
 static int ide;
+#ifdef CONFIG_PNP
+static int isapnp = 1;                         /* Enable ISA PnP detection */
+#endif
 
 module_param(index, int, 0444);
 MODULE_PARM_DESC(index, "Index value for miro soundcard.");
@@ -83,6 +87,10 @@ module_param(wss, int, 0444);
 MODULE_PARM_DESC(wss, "wss mode");
 module_param(ide, int, 0444);
 MODULE_PARM_DESC(ide, "enable ide port");
+#ifdef CONFIG_PNP
+module_param(isapnp, bool, 0444);
+MODULE_PARM_DESC(isapnp, "Enable ISA PnP detection for specified soundcard.");
+#endif
 
 #define OPTi9XX_HW_DETECT      0
 #define OPTi9XX_HW_82C928      1
@@ -96,7 +104,6 @@ MODULE_PARM_DESC(ide, "enable ide port");
 
 #define OPTi9XX_MC_REG(n)      n
 
-
 struct snd_miro {
        unsigned short hardware;
        unsigned char password;
@@ -110,7 +117,6 @@ struct snd_miro {
        unsigned long pwd_reg;
 
        spinlock_t lock;
-       struct snd_card *card;
        struct snd_pcm *pcm;
 
        long wss_base;
@@ -118,23 +124,13 @@ struct snd_miro {
        int dma1;
        int dma2;
 
-       long fm_port;
-
        long mpu_port;
        int mpu_irq;
 
-       unsigned long aci_port;
-       int aci_vendor;
-       int aci_product;
-       int aci_version;
-       int aci_amp;
-       int aci_preamp;
-       int aci_solomode;
-
-       struct mutex aci_mutex;
+       struct snd_miro_aci *aci;
 };
 
-static void snd_miro_proc_init(struct snd_miro * miro);
+static struct snd_miro_aci aci_device;
 
 static char * snd_opti9xx_names[] = {
        "unkown",
@@ -143,17 +139,33 @@ static char * snd_opti9xx_names[] = {
        "82C930", "82C931", "82C933"
 };
 
+static int snd_miro_pnp_is_probed;
+
+#ifdef CONFIG_PNP
+
+static struct pnp_card_device_id snd_miro_pnpids[] = {
+       /* PCM20 and PCM12 in PnP mode */
+       { .id = "MIR0924",
+         .devs = { { "MIR0000" }, { "MIR0002" }, { "MIR0005" } }, },
+       { .id = "" }
+};
+
+MODULE_DEVICE_TABLE(pnp_card, snd_miro_pnpids);
+
+#endif /* CONFIG_PNP */
+
 /* 
  *  ACI control
  */
 
-static int aci_busy_wait(struct snd_miro * miro)
+static int aci_busy_wait(struct snd_miro_aci *aci)
 {
        long timeout;
        unsigned char byte;
 
-       for (timeout = 1; timeout <= ACI_MINTIME+30; timeout++) {
-               if (((byte=inb(miro->aci_port + ACI_REG_BUSY)) & 1) == 0) {
+       for (timeout = 1; timeout <= ACI_MINTIME + 30; timeout++) {
+               byte = inb(aci->aci_port + ACI_REG_BUSY);
+               if ((byte & 1) == 0) {
                        if (timeout >= ACI_MINTIME)
                                snd_printd("aci ready in round %ld.\n",
                                           timeout-ACI_MINTIME);
@@ -179,10 +191,10 @@ static int aci_busy_wait(struct snd_miro * miro)
        return -EBUSY;
 }
 
-static inline int aci_write(struct snd_miro * miro, unsigned char byte)
+static inline int aci_write(struct snd_miro_aci *aci, unsigned char byte)
 {
-       if (aci_busy_wait(miro) >= 0) {
-               outb(byte, miro->aci_port + ACI_REG_COMMAND);
+       if (aci_busy_wait(aci) >= 0) {
+               outb(byte, aci->aci_port + ACI_REG_COMMAND);
                return 0;
        } else {
                snd_printk(KERN_ERR "aci busy, aci_write(0x%x) stopped.\n", byte);
@@ -190,12 +202,12 @@ static inline int aci_write(struct snd_miro * miro, unsigned char byte)
        }
 }
 
-static inline int aci_read(struct snd_miro * miro)
+static inline int aci_read(struct snd_miro_aci *aci)
 {
        unsigned char byte;
 
-       if (aci_busy_wait(miro) >= 0) {
-               byte=inb(miro->aci_port + ACI_REG_STATUS);
+       if (aci_busy_wait(aci) >= 0) {
+               byte = inb(aci->aci_port + ACI_REG_STATUS);
                return byte;
        } else {
                snd_printk(KERN_ERR "aci busy, aci_read() stopped.\n");
@@ -203,39 +215,49 @@ static inline int aci_read(struct snd_miro * miro)
        }
 }
 
-static int aci_cmd(struct snd_miro * miro, int write1, int write2, int write3)
+int snd_aci_cmd(struct snd_miro_aci *aci, int write1, int write2, int write3)
 {
        int write[] = {write1, write2, write3};
        int value, i;
 
-       if (mutex_lock_interruptible(&miro->aci_mutex))
+       if (mutex_lock_interruptible(&aci->aci_mutex))
                return -EINTR;
 
        for (i=0; i<3; i++) {
                if (write[i]< 0 || write[i] > 255)
                        break;
                else {
-                       value = aci_write(miro, write[i]);
+                       value = aci_write(aci, write[i]);
                        if (value < 0)
                                goto out;
                }
        }
 
-       value = aci_read(miro);
+       value = aci_read(aci);
 
-out:   mutex_unlock(&miro->aci_mutex);
+out:   mutex_unlock(&aci->aci_mutex);
        return value;
 }
+EXPORT_SYMBOL(snd_aci_cmd);
+
+static int aci_getvalue(struct snd_miro_aci *aci, unsigned char index)
+{
+       return snd_aci_cmd(aci, ACI_STATUS, index, -1);
+}
 
-static int aci_getvalue(struct snd_miro * miro, unsigned char index)
+static int aci_setvalue(struct snd_miro_aci *aci, unsigned char index,
+                       int value)
 {
-       return aci_cmd(miro, ACI_STATUS, index, -1);
+       return snd_aci_cmd(aci, index, value, -1);
 }
 
-static int aci_setvalue(struct snd_miro * miro, unsigned char index, int value)
+struct snd_miro_aci *snd_aci_get_aci(void)
 {
-       return aci_cmd(miro, index, value, -1);
+       if (aci_device.aci_port == 0)
+               return NULL;
+       return &aci_device;
 }
+EXPORT_SYMBOL(snd_aci_get_aci);
 
 /*
  *  MIXER part
@@ -249,8 +271,10 @@ static int snd_miro_get_capture(struct snd_kcontrol *kcontrol,
        struct snd_miro *miro = snd_kcontrol_chip(kcontrol);
        int value;
 
-       if ((value = aci_getvalue(miro, ACI_S_GENERAL)) < 0) {
-               snd_printk(KERN_ERR "snd_miro_get_capture() failed: %d\n", value);
+       value = aci_getvalue(miro->aci, ACI_S_GENERAL);
+       if (value < 0) {
+               snd_printk(KERN_ERR "snd_miro_get_capture() failed: %d\n",
+                          value);
                return value;
        }
 
@@ -267,13 +291,15 @@ static int snd_miro_put_capture(struct snd_kcontrol *kcontrol,
 
        value = !(ucontrol->value.integer.value[0]);
 
-       if ((error = aci_setvalue(miro, ACI_SET_SOLOMODE, value)) < 0) {
-               snd_printk(KERN_ERR "snd_miro_put_capture() failed: %d\n", error);
+       error = aci_setvalue(miro->aci, ACI_SET_SOLOMODE, value);
+       if (error < 0) {
+               snd_printk(KERN_ERR "snd_miro_put_capture() failed: %d\n",
+                          error);
                return error;
        }
 
-       change = (value != miro->aci_solomode);
-       miro->aci_solomode = value;
+       change = (value != miro->aci->aci_solomode);
+       miro->aci->aci_solomode = value;
        
        return change;
 }
@@ -295,7 +321,7 @@ static int snd_miro_get_preamp(struct snd_kcontrol *kcontrol,
        struct snd_miro *miro = snd_kcontrol_chip(kcontrol);
        int value;
 
-       if (miro->aci_version <= 176) {
+       if (miro->aci->aci_version <= 176) {
 
                /* 
                   OSS says it's not readable with versions < 176.
@@ -303,12 +329,14 @@ static int snd_miro_get_preamp(struct snd_kcontrol *kcontrol,
                   which is a PCM12 with aci_version = 176.
                */
 
-               ucontrol->value.integer.value[0] = miro->aci_preamp;
+               ucontrol->value.integer.value[0] = miro->aci->aci_preamp;
                return 0;
        }
 
-       if ((value = aci_getvalue(miro, ACI_GET_PREAMP)) < 0) {
-               snd_printk(KERN_ERR "snd_miro_get_preamp() failed: %d\n", value);
+       value = aci_getvalue(miro->aci, ACI_GET_PREAMP);
+       if (value < 0) {
+               snd_printk(KERN_ERR "snd_miro_get_preamp() failed: %d\n",
+                          value);
                return value;
        }
        
@@ -325,13 +353,15 @@ static int snd_miro_put_preamp(struct snd_kcontrol *kcontrol,
 
        value = ucontrol->value.integer.value[0];
 
-       if ((error = aci_setvalue(miro, ACI_SET_PREAMP, value)) < 0) {
-               snd_printk(KERN_ERR "snd_miro_put_preamp() failed: %d\n", error);
+       error = aci_setvalue(miro->aci, ACI_SET_PREAMP, value);
+       if (error < 0) {
+               snd_printk(KERN_ERR "snd_miro_put_preamp() failed: %d\n",
+                          error);
                return error;
        }
 
-       change = (value != miro->aci_preamp);
-       miro->aci_preamp = value;
+       change = (value != miro->aci->aci_preamp);
+       miro->aci->aci_preamp = value;
 
        return change;
 }
@@ -342,7 +372,7 @@ static int snd_miro_get_amp(struct snd_kcontrol *kcontrol,
                            struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_miro *miro = snd_kcontrol_chip(kcontrol);
-       ucontrol->value.integer.value[0] = miro->aci_amp;
+       ucontrol->value.integer.value[0] = miro->aci->aci_amp;
 
        return 0;
 }
@@ -355,13 +385,14 @@ static int snd_miro_put_amp(struct snd_kcontrol *kcontrol,
 
        value = ucontrol->value.integer.value[0];
 
-       if ((error = aci_setvalue(miro, ACI_SET_POWERAMP, value)) < 0) {
+       error = aci_setvalue(miro->aci, ACI_SET_POWERAMP, value);
+       if (error < 0) {
                snd_printk(KERN_ERR "snd_miro_put_amp() to %d failed: %d\n", value, error);
                return error;
        }
 
-       change = (value != miro->aci_amp);
-       miro->aci_amp = value;
+       change = (value != miro->aci->aci_amp);
+       miro->aci->aci_amp = value;
 
        return change;
 }
@@ -410,12 +441,14 @@ static int snd_miro_get_double(struct snd_kcontrol *kcontrol,
        int right_reg = kcontrol->private_value & 0xff;
        int left_reg = right_reg + 1;
 
-       if ((right_val = aci_getvalue(miro, right_reg)) < 0) {
+       right_val = aci_getvalue(miro->aci, right_reg);
+       if (right_val < 0) {
                snd_printk(KERN_ERR "aci_getvalue(%d) failed: %d\n", right_reg, right_val);
                return right_val;
        }
 
-       if ((left_val = aci_getvalue(miro, left_reg)) < 0) {
+       left_val = aci_getvalue(miro->aci, left_reg);
+       if (left_val < 0) {
                snd_printk(KERN_ERR "aci_getvalue(%d) failed: %d\n", left_reg, left_val);
                return left_val;
        }
@@ -451,6 +484,7 @@ static int snd_miro_put_double(struct snd_kcontrol *kcontrol,
                               struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_miro *miro = snd_kcontrol_chip(kcontrol);
+       struct snd_miro_aci *aci = miro->aci;
        int left, right, left_old, right_old;
        int setreg_left, setreg_right, getreg_left, getreg_right;
        int change, error;
@@ -459,21 +493,21 @@ static int snd_miro_put_double(struct snd_kcontrol *kcontrol,
        right = ucontrol->value.integer.value[1];
 
        setreg_right = (kcontrol->private_value >> 8) & 0xff;
-       if (setreg_right == ACI_SET_MASTER) {
-               setreg_left = setreg_right + 1;
-       } else {
-               setreg_left = setreg_right + 8;
-       }
+       setreg_left = setreg_right + 8;
+       if (setreg_right == ACI_SET_MASTER)
+               setreg_left -= 7;
 
        getreg_right = kcontrol->private_value & 0xff;
        getreg_left = getreg_right + 1;
 
-       if ((left_old = aci_getvalue(miro, getreg_left)) < 0) {
+       left_old = aci_getvalue(aci, getreg_left);
+       if (left_old < 0) {
                snd_printk(KERN_ERR "aci_getvalue(%d) failed: %d\n", getreg_left, left_old);
                return left_old;
        }
 
-       if ((right_old = aci_getvalue(miro, getreg_right)) < 0) {
+       right_old = aci_getvalue(aci, getreg_right);
+       if (right_old < 0) {
                snd_printk(KERN_ERR "aci_getvalue(%d) failed: %d\n", getreg_right, right_old);
                return right_old;
        }
@@ -492,13 +526,15 @@ static int snd_miro_put_double(struct snd_kcontrol *kcontrol,
                        right_old = 0x80 - right_old;
 
                if (left >= 0) {
-                       if ((error = aci_setvalue(miro, setreg_left, left)) < 0) {
+                       error = aci_setvalue(aci, setreg_left, left);
+                       if (error < 0) {
                                snd_printk(KERN_ERR "aci_setvalue(%d) failed: %d\n",
                                           left, error);
                                return error;
                        }
                } else {
-                       if ((error = aci_setvalue(miro, setreg_left, 0x80 - left)) < 0) {
+                       error = aci_setvalue(aci, setreg_left, 0x80 - left);
+                       if (error < 0) {
                                snd_printk(KERN_ERR "aci_setvalue(%d) failed: %d\n",
                                           0x80 - left, error);
                                return error;
@@ -506,13 +542,15 @@ static int snd_miro_put_double(struct snd_kcontrol *kcontrol,
                }
 
                if (right >= 0) {
-                       if ((error = aci_setvalue(miro, setreg_right, right)) < 0) {
+                       error = aci_setvalue(aci, setreg_right, right);
+                       if (error < 0) {
                                snd_printk(KERN_ERR "aci_setvalue(%d) failed: %d\n",
                                           right, error);
                                return error;
                        }
                } else {
-                       if ((error = aci_setvalue(miro, setreg_right, 0x80 - right)) < 0) {
+                       error = aci_setvalue(aci, setreg_right, 0x80 - right);
+                       if (error < 0) {
                                snd_printk(KERN_ERR "aci_setvalue(%d) failed: %d\n",
                                           0x80 - right, error);
                                return error;
@@ -530,12 +568,14 @@ static int snd_miro_put_double(struct snd_kcontrol *kcontrol,
                left_old = 0x20 - left_old;
                right_old = 0x20 - right_old;
 
-               if ((error = aci_setvalue(miro, setreg_left, 0x20 - left)) < 0) {
+               error = aci_setvalue(aci, setreg_left, 0x20 - left);
+               if (error < 0) {
                        snd_printk(KERN_ERR "aci_setvalue(%d) failed: %d\n",
                                   0x20 - left, error);
                        return error;
                }
-               if ((error = aci_setvalue(miro, setreg_right, 0x20 - right)) < 0) {
+               error = aci_setvalue(aci, setreg_right, 0x20 - right);
+               if (error < 0) {
                        snd_printk(KERN_ERR "aci_setvalue(%d) failed: %d\n",
                                   0x20 - right, error);
                        return error;
@@ -633,11 +673,13 @@ static unsigned char aci_init_values[][2] __devinitdata = {
 static int __devinit snd_set_aci_init_values(struct snd_miro *miro)
 {
        int idx, error;
+       struct snd_miro_aci *aci = miro->aci;
 
        /* enable WSS on PCM1 */
 
-       if ((miro->aci_product == 'A') && wss) {
-               if ((error = aci_setvalue(miro, ACI_SET_WSS, wss)) < 0) {
+       if ((aci->aci_product == 'A') && wss) {
+               error = aci_setvalue(aci, ACI_SET_WSS, wss);
+               if (error < 0) {
                        snd_printk(KERN_ERR "enabling WSS mode failed\n");
                        return error;
                }
@@ -646,7 +688,8 @@ static int __devinit snd_set_aci_init_values(struct snd_miro *miro)
        /* enable IDE port */
 
        if (ide) {
-               if ((error = aci_setvalue(miro, ACI_SET_IDE, ide)) < 0) {
+               error = aci_setvalue(aci, ACI_SET_IDE, ide);
+               if (error < 0) {
                        snd_printk(KERN_ERR "enabling IDE port failed\n");
                        return error;
                }
@@ -654,32 +697,31 @@ static int __devinit snd_set_aci_init_values(struct snd_miro *miro)
 
        /* set common aci values */
 
-       for (idx = 0; idx < ARRAY_SIZE(aci_init_values); idx++)
-                if ((error = aci_setvalue(miro, aci_init_values[idx][0], 
-                                         aci_init_values[idx][1])) < 0) {
+       for (idx = 0; idx < ARRAY_SIZE(aci_init_values); idx++) {
+               error = aci_setvalue(aci, aci_init_values[idx][0],
+                                    aci_init_values[idx][1]);
+               if (error < 0) {
                        snd_printk(KERN_ERR "aci_setvalue(%d) failed: %d\n", 
                                   aci_init_values[idx][0], error);
                         return error;
                 }
-
-       miro->aci_amp = 0;
-       miro->aci_preamp = 0;
-       miro->aci_solomode = 1;
+       }
+       aci->aci_amp = 0;
+       aci->aci_preamp = 0;
+       aci->aci_solomode = 1;
 
        return 0;
 }
 
-static int __devinit snd_miro_mixer(struct snd_miro *miro)
+static int __devinit snd_miro_mixer(struct snd_card *card,
+                                   struct snd_miro *miro)
 {
-       struct snd_card *card;
        unsigned int idx;
        int err;
 
-       if (snd_BUG_ON(!miro || !miro->card))
+       if (snd_BUG_ON(!miro || !card))
                return -EINVAL;
 
-       card = miro->card;
-
        switch (miro->hardware) {
        case OPTi9XX_HW_82C924:
                strcpy(card->mixername, "ACI & OPTi924");
@@ -697,7 +739,8 @@ static int __devinit snd_miro_mixer(struct snd_miro *miro)
                        return err;
        }
 
-       if ((miro->aci_product == 'A') || (miro->aci_product == 'B')) {
+       if ((miro->aci->aci_product == 'A') ||
+           (miro->aci->aci_product == 'B')) {
                /* PCM1/PCM12 with power-amp and Line 2 */
                if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_miro_line_control[0], miro))) < 0)
                        return err;
@@ -705,16 +748,17 @@ static int __devinit snd_miro_mixer(struct snd_miro *miro)
                        return err;
        }
 
-       if ((miro->aci_product == 'B') || (miro->aci_product == 'C')) {
+       if ((miro->aci->aci_product == 'B') ||
+           (miro->aci->aci_product == 'C')) {
                /* PCM12/PCM20 with mic-preamp */
                if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_miro_preamp_control[0], miro))) < 0)
                        return err;
-               if (miro->aci_version >= 176)
+               if (miro->aci->aci_version >= 176)
                        if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_miro_capture_control[0], miro))) < 0)
                                return err;
        }
 
-       if (miro->aci_product == 'C') {
+       if (miro->aci->aci_product == 'C') {
                /* PCM20 with radio and 7 band equalizer */
                if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_miro_radio_control[0], miro))) < 0)
                        return err;
@@ -757,21 +801,26 @@ static int __devinit snd_miro_init(struct snd_miro *chip,
        chip->irq = -1;
        chip->dma1 = -1;
        chip->dma2 = -1;
-       chip->fm_port = -1;
        chip->mpu_port = -1;
        chip->mpu_irq = -1;
 
+       chip->pwd_reg = 3;
+
+#ifdef CONFIG_PNP
+       if (isapnp && chip->mc_base)
+               /* PnP resource gives the least 10 bits */
+               chip->mc_base |= 0xc00;
+       else
+#endif
+               chip->mc_base = 0xf8c;
+
        switch (hardware) {
        case OPTi9XX_HW_82C929:
-               chip->mc_base = 0xf8c;
                chip->password = 0xe3;
-               chip->pwd_reg = 3;
                break;
 
        case OPTi9XX_HW_82C924:
-               chip->mc_base = 0xf8c;
                chip->password = 0xe5;
-               chip->pwd_reg = 3;
                break;
 
        default:
@@ -853,14 +902,15 @@ static void snd_miro_proc_read(struct snd_info_entry * entry,
                               struct snd_info_buffer *buffer)
 {
        struct snd_miro *miro = (struct snd_miro *) entry->private_data;
+       struct snd_miro_aci *aci = miro->aci;
        char* model = "unknown";
 
        /* miroSOUND PCM1 pro, early PCM12 */
 
        if ((miro->hardware == OPTi9XX_HW_82C929) &&
-           (miro->aci_vendor == 'm') && 
-           (miro->aci_product == 'A')) {
-               switch(miro->aci_version) {
+           (aci->aci_vendor == 'm') &&
+           (aci->aci_product == 'A')) {
+               switch (aci->aci_version) {
                case 3:
                        model = "miroSOUND PCM1 pro";
                        break;
@@ -873,9 +923,9 @@ static void snd_miro_proc_read(struct snd_info_entry * entry,
        /* miroSOUND PCM12, PCM12 (Rev. E), PCM12 pnp */
 
        if ((miro->hardware == OPTi9XX_HW_82C924) &&
-           (miro->aci_vendor == 'm') && 
-           (miro->aci_product == 'B')) {
-               switch(miro->aci_version) {
+           (aci->aci_vendor == 'm') &&
+           (aci->aci_product == 'B')) {
+               switch (aci->aci_version) {
                case 4:
                        model = "miroSOUND PCM12";
                        break;
@@ -891,9 +941,9 @@ static void snd_miro_proc_read(struct snd_info_entry * entry,
        /* miroSOUND PCM20 radio */
 
        if ((miro->hardware == OPTi9XX_HW_82C924) &&
-           (miro->aci_vendor == 'm') && 
-           (miro->aci_product == 'C')) {
-               switch(miro->aci_version) {
+           (aci->aci_vendor == 'm') &&
+           (aci->aci_product == 'C')) {
+               switch (aci->aci_version) {
                case 7:
                        model = "miroSOUND PCM20 radio (Rev. E)";
                        break;
@@ -917,17 +967,17 @@ static void snd_miro_proc_read(struct snd_info_entry * entry,
 
        snd_iprintf(buffer, "ACI information:\n");
        snd_iprintf(buffer, "  vendor  : ");
-       switch(miro->aci_vendor) {
+       switch (aci->aci_vendor) {
        case 'm':
                snd_iprintf(buffer, "Miro\n");
                break;
        default:
-               snd_iprintf(buffer, "unknown (0x%x)\n", miro->aci_vendor);
+               snd_iprintf(buffer, "unknown (0x%x)\n", aci->aci_vendor);
                break;
        }
 
        snd_iprintf(buffer, "  product : ");
-       switch(miro->aci_product) {
+       switch (aci->aci_product) {
        case 'A':
                snd_iprintf(buffer, "miroSOUND PCM1 pro / (early) PCM12\n");
                break;
@@ -938,26 +988,27 @@ static void snd_miro_proc_read(struct snd_info_entry * entry,
                snd_iprintf(buffer, "miroSOUND PCM20 radio\n");
                break;
        default:
-               snd_iprintf(buffer, "unknown (0x%x)\n", miro->aci_product);
+               snd_iprintf(buffer, "unknown (0x%x)\n", aci->aci_product);
                break;
        }
 
        snd_iprintf(buffer, "  firmware: %d (0x%x)\n",
-                   miro->aci_version, miro->aci_version);
+                   aci->aci_version, aci->aci_version);
        snd_iprintf(buffer, "  port    : 0x%lx-0x%lx\n", 
-                   miro->aci_port, miro->aci_port+2);
+                   aci->aci_port, aci->aci_port+2);
        snd_iprintf(buffer, "  wss     : 0x%x\n", wss);
        snd_iprintf(buffer, "  ide     : 0x%x\n", ide);
-       snd_iprintf(buffer, "  solomode: 0x%x\n", miro->aci_solomode);
-       snd_iprintf(buffer, "  amp     : 0x%x\n", miro->aci_amp);
-       snd_iprintf(buffer, "  preamp  : 0x%x\n", miro->aci_preamp);
+       snd_iprintf(buffer, "  solomode: 0x%x\n", aci->aci_solomode);
+       snd_iprintf(buffer, "  amp     : 0x%x\n", aci->aci_amp);
+       snd_iprintf(buffer, "  preamp  : 0x%x\n", aci->aci_preamp);
 }
 
-static void __devinit snd_miro_proc_init(struct snd_miro * miro)
+static void __devinit snd_miro_proc_init(struct snd_card *card,
+                                        struct snd_miro *miro)
 {
        struct snd_info_entry *entry;
 
-       if (! snd_card_proc_new(miro->card, "miro", &entry))
+       if (!snd_card_proc_new(card, "miro", &entry))
                snd_info_set_text_ops(entry, miro, snd_miro_proc_read);
 }
 
@@ -974,37 +1025,40 @@ static int __devinit snd_miro_configure(struct snd_miro *chip)
        unsigned char mpu_irq_bits;
        unsigned long flags;
 
+       snd_miro_write_mask(chip, OPTi9XX_MC_REG(1), 0x80, 0x80);
+       snd_miro_write_mask(chip, OPTi9XX_MC_REG(2), 0x20, 0x20); /* OPL4 */
+       snd_miro_write_mask(chip, OPTi9XX_MC_REG(5), 0x02, 0x02);
+
        switch (chip->hardware) {
        case OPTi9XX_HW_82C924:
                snd_miro_write_mask(chip, OPTi9XX_MC_REG(6), 0x02, 0x02);
-               snd_miro_write_mask(chip, OPTi9XX_MC_REG(1), 0x80, 0x80);
-               snd_miro_write_mask(chip, OPTi9XX_MC_REG(2), 0x20, 0x20); /* OPL4 */
                snd_miro_write_mask(chip, OPTi9XX_MC_REG(3), 0xf0, 0xff);
-               snd_miro_write_mask(chip, OPTi9XX_MC_REG(5), 0x02, 0x02);
                break;
        case OPTi9XX_HW_82C929:
                /* untested init commands for OPTi929 */
-               snd_miro_write_mask(chip, OPTi9XX_MC_REG(1), 0x80, 0x80);
-               snd_miro_write_mask(chip, OPTi9XX_MC_REG(2), 0x20, 0x20); /* OPL4 */
                snd_miro_write_mask(chip, OPTi9XX_MC_REG(4), 0x00, 0x0c);
-               snd_miro_write_mask(chip, OPTi9XX_MC_REG(5), 0x02, 0x02);
                break;
        default:
                snd_printk(KERN_ERR "chip %d not supported\n", chip->hardware);
                return -EINVAL;
        }
 
-       switch (chip->wss_base) {
-       case 0x530:
+       /* PnP resource says it decodes only 10 bits of address */
+       switch (chip->wss_base & 0x3ff) {
+       case 0x130:
+               chip->wss_base = 0x530;
                wss_base_bits = 0x00;
                break;
-       case 0x604:
+       case 0x204:
+               chip->wss_base = 0x604;
                wss_base_bits = 0x03;
                break;
-       case 0xe80:
+       case 0x280:
+               chip->wss_base = 0xe80;
                wss_base_bits = 0x01;
                break;
-       case 0xf40:
+       case 0x340:
+               chip->wss_base = 0xf40;
                wss_base_bits = 0x02;
                break;
        default:
@@ -1122,75 +1176,92 @@ __skip_mpu:
        return 0;
 }
 
+static int __devinit snd_miro_opti_check(struct snd_miro *chip)
+{
+       unsigned char value;
+
+       chip->res_mc_base = request_region(chip->mc_base, chip->mc_base_size,
+                                          "OPTi9xx MC");
+       if (chip->res_mc_base == NULL)
+               return -ENOMEM;
+
+       value = snd_miro_read(chip, OPTi9XX_MC_REG(1));
+       if (value != 0xff && value != inb(chip->mc_base + OPTi9XX_MC_REG(1)))
+               if (value == snd_miro_read(chip, OPTi9XX_MC_REG(1)))
+                       return 0;
+
+       release_and_free_resource(chip->res_mc_base);
+       chip->res_mc_base = NULL;
+
+       return -ENODEV;
+}
+
 static int __devinit snd_card_miro_detect(struct snd_card *card,
                                          struct snd_miro *chip)
 {
        int i, err;
-       unsigned char value;
 
        for (i = OPTi9XX_HW_82C929; i <= OPTi9XX_HW_82C924; i++) {
 
                if ((err = snd_miro_init(chip, i)) < 0)
                        return err;
 
-               if ((chip->res_mc_base = request_region(chip->mc_base, chip->mc_base_size, "OPTi9xx MC")) == NULL)
-                       continue;
-
-               value = snd_miro_read(chip, OPTi9XX_MC_REG(1));
-               if ((value != 0xff) && (value != inb(chip->mc_base + 1)))
-                       if (value == snd_miro_read(chip, OPTi9XX_MC_REG(1)))
-                               return 1;
-
-               release_and_free_resource(chip->res_mc_base);
-               chip->res_mc_base = NULL;
-
+               err = snd_miro_opti_check(chip);
+               if (err == 0)
+                       return 1;
        }
 
        return -ENODEV;
 }
 
 static int __devinit snd_card_miro_aci_detect(struct snd_card *card,
-                                             struct snd_miro * miro)
+                                             struct snd_miro *miro)
 {
        unsigned char regval;
        int i;
+       struct snd_miro_aci *aci = &aci_device;
+
+       miro->aci = aci;
 
-       mutex_init(&miro->aci_mutex);
+       mutex_init(&aci->aci_mutex);
 
        /* get ACI port from OPTi9xx MC 4 */
 
-       miro->mc_base = 0xf8c;
        regval=inb(miro->mc_base + 4);
-       miro->aci_port = (regval & 0x10) ? 0x344: 0x354;
+       aci->aci_port = (regval & 0x10) ? 0x344 : 0x354;
 
-       if ((miro->res_aci_port = request_region(miro->aci_port, 3, "miro aci")) == NULL) {
+       miro->res_aci_port = request_region(aci->aci_port, 3, "miro aci");
+       if (miro->res_aci_port == NULL) {
                snd_printk(KERN_ERR "aci i/o area 0x%lx-0x%lx already used.\n", 
-                          miro->aci_port, miro->aci_port+2);
+                          aci->aci_port, aci->aci_port+2);
                return -ENOMEM;
        }
 
         /* force ACI into a known state */
        for (i = 0; i < 3; i++)
-               if (aci_cmd(miro, ACI_ERROR_OP, -1, -1) < 0) {
+               if (snd_aci_cmd(aci, ACI_ERROR_OP, -1, -1) < 0) {
                        snd_printk(KERN_ERR "can't force aci into known state.\n");
                        return -ENXIO;
                }
 
-       if ((miro->aci_vendor=aci_cmd(miro, ACI_READ_IDCODE, -1, -1)) < 0 ||
-           (miro->aci_product=aci_cmd(miro, ACI_READ_IDCODE, -1, -1)) < 0) {
-               snd_printk(KERN_ERR "can't read aci id on 0x%lx.\n", miro->aci_port);
+       aci->aci_vendor = snd_aci_cmd(aci, ACI_READ_IDCODE, -1, -1);
+       aci->aci_product = snd_aci_cmd(aci, ACI_READ_IDCODE, -1, -1);
+       if (aci->aci_vendor < 0 || aci->aci_product < 0) {
+               snd_printk(KERN_ERR "can't read aci id on 0x%lx.\n",
+                          aci->aci_port);
                return -ENXIO;
        }
 
-       if ((miro->aci_version=aci_cmd(miro, ACI_READ_VERSION, -1, -1)) < 0) {
+       aci->aci_version = snd_aci_cmd(aci, ACI_READ_VERSION, -1, -1);
+       if (aci->aci_version < 0) {
                snd_printk(KERN_ERR "can't read aci version on 0x%lx.\n", 
-                          miro->aci_port);
+                          aci->aci_port);
                return -ENXIO;
        }
 
-       if (aci_cmd(miro, ACI_INIT, -1, -1) < 0 ||
-           aci_cmd(miro, ACI_ERROR_OP, ACI_ERROR_OP, ACI_ERROR_OP) < 0 ||
-           aci_cmd(miro, ACI_ERROR_OP, ACI_ERROR_OP, ACI_ERROR_OP) < 0) {
+       if (snd_aci_cmd(aci, ACI_INIT, -1, -1) < 0 ||
+           snd_aci_cmd(aci, ACI_ERROR_OP, ACI_ERROR_OP, ACI_ERROR_OP) < 0 ||
+           snd_aci_cmd(aci, ACI_ERROR_OP, ACI_ERROR_OP, ACI_ERROR_OP) < 0) {
                snd_printk(KERN_ERR "can't initialize aci.\n"); 
                return -ENXIO;
        }
@@ -1201,157 +1272,80 @@ static int __devinit snd_card_miro_aci_detect(struct snd_card *card,
 static void snd_card_miro_free(struct snd_card *card)
 {
        struct snd_miro *miro = card->private_data;
-        
+
        release_and_free_resource(miro->res_aci_port);
+       if (miro->aci)
+               miro->aci->aci_port = 0;
        release_and_free_resource(miro->res_mc_base);
 }
 
-static int __devinit snd_miro_match(struct device *devptr, unsigned int n)
-{
-       return 1;
-}
-
-static int __devinit snd_miro_probe(struct device *devptr, unsigned int n)
+static int __devinit snd_miro_probe(struct snd_card *card)
 {
-       static long possible_ports[] = {0x530, 0xe80, 0xf40, 0x604, -1};
-       static long possible_mpu_ports[] = {0x330, 0x300, 0x310, 0x320, -1};
-       static int possible_irqs[] = {11, 9, 10, 7, -1};
-       static int possible_mpu_irqs[] = {10, 5, 9, 7, -1};
-       static int possible_dma1s[] = {3, 1, 0, -1};
-       static int possible_dma2s[][2] = {{1,-1}, {0,-1}, {-1,-1}, {0,-1}};
-
        int error;
-       struct snd_miro *miro;
+       struct snd_miro *miro = card->private_data;
        struct snd_wss *codec;
        struct snd_timer *timer;
-       struct snd_card *card;
        struct snd_pcm *pcm;
        struct snd_rawmidi *rmidi;
 
-       error = snd_card_create(index, id, THIS_MODULE,
-                               sizeof(struct snd_miro), &card);
-       if (error < 0)
-               return error;
-
-       card->private_free = snd_card_miro_free;
-       miro = card->private_data;
-       miro->card = card;
-
-       if ((error = snd_card_miro_aci_detect(card, miro)) < 0) {
-               snd_card_free(card);
-               snd_printk(KERN_ERR "unable to detect aci chip\n");
-               return -ENODEV;
+       if (!miro->res_mc_base) {
+               miro->res_mc_base = request_region(miro->mc_base,
+                                               miro->mc_base_size,
+                                               "miro (OPTi9xx MC)");
+               if (miro->res_mc_base == NULL) {
+                       snd_printk(KERN_ERR "request for OPTI9xx MC failed\n");
+                       return -ENOMEM;
+               }
        }
 
-       /* init proc interface */
-       snd_miro_proc_init(miro);
-
-       if ((error = snd_card_miro_detect(card, miro)) < 0) {
+       error = snd_card_miro_aci_detect(card, miro);
+       if (error < 0) {
                snd_card_free(card);
-               snd_printk(KERN_ERR "unable to detect OPTi9xx chip\n");
+               snd_printk(KERN_ERR "unable to detect aci chip\n");
                return -ENODEV;
        }
 
-       if (! miro->res_mc_base &&
-           (miro->res_mc_base = request_region(miro->mc_base, miro->mc_base_size,
-                                               "miro (OPTi9xx MC)")) == NULL) {
-               snd_card_free(card);
-               snd_printk(KERN_ERR "request for OPTI9xx MC failed\n");
-               return -ENOMEM;
-       }
-
        miro->wss_base = port;
-       miro->fm_port = fm_port;
        miro->mpu_port = mpu_port;
        miro->irq = irq;
        miro->mpu_irq = mpu_irq;
        miro->dma1 = dma1;
        miro->dma2 = dma2;
 
-       if (miro->wss_base == SNDRV_AUTO_PORT) {
-               if ((miro->wss_base = snd_legacy_find_free_ioport(possible_ports, 4)) < 0) {
-                       snd_card_free(card);
-                       snd_printk(KERN_ERR "unable to find a free WSS port\n");
-                       return -EBUSY;
-               }
-       }
-
-       if (miro->mpu_port == SNDRV_AUTO_PORT) {
-               if ((miro->mpu_port = snd_legacy_find_free_ioport(possible_mpu_ports, 2)) < 0) {
-                       snd_card_free(card);
-                       snd_printk(KERN_ERR "unable to find a free MPU401 port\n");
-                       return -EBUSY;
-               }
-       }
-       if (miro->irq == SNDRV_AUTO_IRQ) {
-               if ((miro->irq = snd_legacy_find_free_irq(possible_irqs)) < 0) {
-                       snd_card_free(card);
-                       snd_printk(KERN_ERR "unable to find a free IRQ\n");
-                       return -EBUSY;
-               }
-       }
-       if (miro->mpu_irq == SNDRV_AUTO_IRQ) {
-               if ((miro->mpu_irq = snd_legacy_find_free_irq(possible_mpu_irqs)) < 0) {
-                       snd_card_free(card);
-                       snd_printk(KERN_ERR "unable to find a free MPU401 IRQ\n");
-                       return -EBUSY;
-               }
-       }
-       if (miro->dma1 == SNDRV_AUTO_DMA) {
-               if ((miro->dma1 = snd_legacy_find_free_dma(possible_dma1s)) < 0) {
-                       snd_card_free(card);
-                       snd_printk(KERN_ERR "unable to find a free DMA1\n");
-                       return -EBUSY;
-               }
-       }
-       if (miro->dma2 == SNDRV_AUTO_DMA) {
-               if ((miro->dma2 = snd_legacy_find_free_dma(possible_dma2s[miro->dma1 % 4])) < 0) {
-                       snd_card_free(card);
-                       snd_printk(KERN_ERR "unable to find a free DMA2\n");
-                       return -EBUSY;
-               }
-       }
+       /* init proc interface */
+       snd_miro_proc_init(card, miro);
 
        error = snd_miro_configure(miro);
-       if (error) {
-               snd_card_free(card);
+       if (error)
                return error;
-       }
 
        error = snd_wss_create(card, miro->wss_base + 4, -1,
-                               miro->irq, miro->dma1, miro->dma2,
-                               WSS_HW_AD1845, 0, &codec);
-       if (error < 0) {
-               snd_card_free(card);
+                              miro->irq, miro->dma1, miro->dma2,
+                              WSS_HW_DETECT, 0, &codec);
+       if (error < 0)
                return error;
-       }
 
        error = snd_wss_pcm(codec, 0, &pcm);
-       if (error < 0)  {
-               snd_card_free(card);
+       if (error < 0)
                return error;
-       }
+
        error = snd_wss_mixer(codec);
-       if (error < 0) {
-               snd_card_free(card);
+       if (error < 0)
                return error;
-       }
+
        error = snd_wss_timer(codec, 0, &timer);
-       if (error < 0) {
-               snd_card_free(card);
+       if (error < 0)
                return error;
-       }
 
        miro->pcm = pcm;
 
-       if ((error = snd_miro_mixer(miro)) < 0) {
-               snd_card_free(card);
+       error = snd_miro_mixer(card, miro);
+       if (error < 0)
                return error;
-       }
 
-       if (miro->aci_vendor == 'm') {
+       if (miro->aci->aci_vendor == 'm') {
                /* It looks like a miro sound card. */
-               switch (miro->aci_product) {
+               switch (miro->aci->aci_product) {
                case 'A':
                        sprintf(card->shortname, 
                                "miroSOUND PCM1 pro / PCM12");
@@ -1380,30 +1374,131 @@ static int __devinit snd_miro_probe(struct device *devptr, unsigned int n)
                card->shortname, miro->name, pcm->name, miro->wss_base + 4,
                miro->irq, miro->dma1, miro->dma2);
 
-       if (miro->mpu_port <= 0 || miro->mpu_port == SNDRV_AUTO_PORT)
+       if (mpu_port <= 0 || mpu_port == SNDRV_AUTO_PORT)
                rmidi = NULL;
-       else
-               if ((error = snd_mpu401_uart_new(card, 0, MPU401_HW_MPU401,
-                               miro->mpu_port, 0, miro->mpu_irq, IRQF_DISABLED,
-                               &rmidi)))
-                       snd_printk(KERN_WARNING "no MPU-401 device at 0x%lx?\n", miro->mpu_port);
+       else {
+               error = snd_mpu401_uart_new(card, 0, MPU401_HW_MPU401,
+                               mpu_port, 0, miro->mpu_irq, IRQF_DISABLED,
+                               &rmidi);
+               if (error < 0)
+                       snd_printk(KERN_WARNING "no MPU-401 device at 0x%lx?\n",
+                                  mpu_port);
+       }
 
-       if (miro->fm_port > 0 && miro->fm_port != SNDRV_AUTO_PORT) {
+       if (fm_port > 0 && fm_port != SNDRV_AUTO_PORT) {
                struct snd_opl3 *opl3 = NULL;
                struct snd_opl4 *opl4;
-               if (snd_opl4_create(card, miro->fm_port, miro->fm_port - 8, 
+
+               if (snd_opl4_create(card, fm_port, fm_port - 8,
                                    2, &opl3, &opl4) < 0)
-                       snd_printk(KERN_WARNING "no OPL4 device at 0x%lx\n", miro->fm_port);
+                       snd_printk(KERN_WARNING "no OPL4 device at 0x%lx\n",
+                                  fm_port);
        }
 
-       if ((error = snd_set_aci_init_values(miro)) < 0) {
-               snd_card_free(card);
+       error = snd_set_aci_init_values(miro);
+       if (error < 0)
                 return error;
+
+       return snd_card_register(card);
+}
+
+static int __devinit snd_miro_isa_match(struct device *devptr, unsigned int n)
+{
+#ifdef CONFIG_PNP
+       if (snd_miro_pnp_is_probed)
+               return 0;
+       if (isapnp)
+               return 0;
+#endif
+       return 1;
+}
+
+static int __devinit snd_miro_isa_probe(struct device *devptr, unsigned int n)
+{
+       static long possible_ports[] = {0x530, 0xe80, 0xf40, 0x604, -1};
+       static long possible_mpu_ports[] = {0x330, 0x300, 0x310, 0x320, -1};
+       static int possible_irqs[] = {11, 9, 10, 7, -1};
+       static int possible_mpu_irqs[] = {10, 5, 9, 7, -1};
+       static int possible_dma1s[] = {3, 1, 0, -1};
+       static int possible_dma2s[][2] = { {1, -1}, {0, -1}, {-1, -1},
+                                          {0, -1} };
+
+       int error;
+       struct snd_miro *miro;
+       struct snd_card *card;
+
+       error = snd_card_create(index, id, THIS_MODULE,
+                               sizeof(struct snd_miro), &card);
+       if (error < 0)
+               return error;
+
+       card->private_free = snd_card_miro_free;
+       miro = card->private_data;
+
+       error = snd_card_miro_detect(card, miro);
+       if (error < 0) {
+               snd_card_free(card);
+               snd_printk(KERN_ERR "unable to detect OPTi9xx chip\n");
+               return -ENODEV;
+       }
+
+       if (port == SNDRV_AUTO_PORT) {
+               port = snd_legacy_find_free_ioport(possible_ports, 4);
+               if (port < 0) {
+                       snd_card_free(card);
+                       snd_printk(KERN_ERR "unable to find a free WSS port\n");
+                       return -EBUSY;
+               }
+       }
+
+       if (mpu_port == SNDRV_AUTO_PORT) {
+               mpu_port = snd_legacy_find_free_ioport(possible_mpu_ports, 2);
+               if (mpu_port < 0) {
+                       snd_card_free(card);
+                       snd_printk(KERN_ERR
+                                  "unable to find a free MPU401 port\n");
+                       return -EBUSY;
+               }
+       }
+
+       if (irq == SNDRV_AUTO_IRQ) {
+               irq = snd_legacy_find_free_irq(possible_irqs);
+               if (irq < 0) {
+                       snd_card_free(card);
+                       snd_printk(KERN_ERR "unable to find a free IRQ\n");
+                       return -EBUSY;
+               }
+       }
+       if (mpu_irq == SNDRV_AUTO_IRQ) {
+               mpu_irq = snd_legacy_find_free_irq(possible_mpu_irqs);
+               if (mpu_irq < 0) {
+                       snd_card_free(card);
+                       snd_printk(KERN_ERR
+                                  "unable to find a free MPU401 IRQ\n");
+                       return -EBUSY;
+               }
+       }
+       if (dma1 == SNDRV_AUTO_DMA) {
+               dma1 = snd_legacy_find_free_dma(possible_dma1s);
+               if (dma1 < 0) {
+                       snd_card_free(card);
+                       snd_printk(KERN_ERR "unable to find a free DMA1\n");
+                       return -EBUSY;
+               }
+       }
+       if (dma2 == SNDRV_AUTO_DMA) {
+               dma2 = snd_legacy_find_free_dma(possible_dma2s[dma1 % 4]);
+               if (dma2 < 0) {
+                       snd_card_free(card);
+                       snd_printk(KERN_ERR "unable to find a free DMA2\n");
+                       return -EBUSY;
+               }
        }
 
        snd_card_set_dev(card, devptr);
 
-       if ((error = snd_card_register(card))) {
+       error = snd_miro_probe(card);
+       if (error < 0) {
                snd_card_free(card);
                return error;
        }
@@ -1412,7 +1507,8 @@ static int __devinit snd_miro_probe(struct device *devptr, unsigned int n)
        return 0;
 }
 
-static int __devexit snd_miro_remove(struct device *devptr, unsigned int dev)
+static int __devexit snd_miro_isa_remove(struct device *devptr,
+                                        unsigned int dev)
 {
        snd_card_free(dev_get_drvdata(devptr));
        dev_set_drvdata(devptr, NULL);
@@ -1422,23 +1518,164 @@ static int __devexit snd_miro_remove(struct device *devptr, unsigned int dev)
 #define DEV_NAME "miro"
 
 static struct isa_driver snd_miro_driver = {
-       .match          = snd_miro_match,
-       .probe          = snd_miro_probe,
-       .remove         = __devexit_p(snd_miro_remove),
+       .match          = snd_miro_isa_match,
+       .probe          = snd_miro_isa_probe,
+       .remove         = __devexit_p(snd_miro_isa_remove),
        /* FIXME: suspend/resume */
        .driver         = {
                .name   = DEV_NAME
        },
 };
 
+#ifdef CONFIG_PNP
+
+static int __devinit snd_card_miro_pnp(struct snd_miro *chip,
+                                       struct pnp_card_link *card,
+                                       const struct pnp_card_device_id *pid)
+{
+       struct pnp_dev *pdev;
+       int err;
+       struct pnp_dev *devmpu;
+       struct pnp_dev *devmc;
+
+       pdev = pnp_request_card_device(card, pid->devs[0].id, NULL);
+       if (pdev == NULL)
+               return -EBUSY;
+
+       devmpu = pnp_request_card_device(card, pid->devs[1].id, NULL);
+       if (devmpu == NULL)
+               return -EBUSY;
+
+       devmc = pnp_request_card_device(card, pid->devs[2].id, NULL);
+       if (devmc == NULL)
+               return -EBUSY;
+
+       err = pnp_activate_dev(pdev);
+       if (err < 0) {
+               snd_printk(KERN_ERR "AUDIO pnp configure failure: %d\n", err);
+               return err;
+       }
+
+       err = pnp_activate_dev(devmc);
+       if (err < 0) {
+               snd_printk(KERN_ERR "OPL syntg pnp configure failure: %d\n",
+                                   err);
+               return err;
+       }
+
+       port = pnp_port_start(pdev, 1);
+       fm_port = pnp_port_start(pdev, 2) + 8;
+
+       /*
+        * The MC(0) is never accessed and the miroSOUND PCM20 card does not
+        * include it in the PnP resource range. OPTI93x include it.
+        */
+       chip->mc_base = pnp_port_start(devmc, 0) - 1;
+       chip->mc_base_size = pnp_port_len(devmc, 0) + 1;
+
+       irq = pnp_irq(pdev, 0);
+       dma1 = pnp_dma(pdev, 0);
+       dma2 = pnp_dma(pdev, 1);
+
+       if (mpu_port > 0) {
+               err = pnp_activate_dev(devmpu);
+               if (err < 0) {
+                       snd_printk(KERN_ERR "MPU401 pnp configure failure\n");
+                       mpu_port = -1;
+                       return err;
+               }
+               mpu_port = pnp_port_start(devmpu, 0);
+               mpu_irq = pnp_irq(devmpu, 0);
+       }
+       return 0;
+}
+
+static int __devinit snd_miro_pnp_probe(struct pnp_card_link *pcard,
+                                       const struct pnp_card_device_id *pid)
+{
+       struct snd_card *card;
+       int err;
+       struct snd_miro *miro;
+
+       if (snd_miro_pnp_is_probed)
+               return -EBUSY;
+       if (!isapnp)
+               return -ENODEV;
+       err = snd_card_create(index, id, THIS_MODULE,
+                               sizeof(struct snd_miro), &card);
+       if (err < 0)
+               return err;
+
+       card->private_free = snd_card_miro_free;
+       miro = card->private_data;
+
+       err = snd_card_miro_pnp(miro, pcard, pid);
+       if (err) {
+               snd_card_free(card);
+               return err;
+       }
+
+       /* only miroSOUND PCM20 and PCM12 == OPTi924 */
+       err = snd_miro_init(miro, OPTi9XX_HW_82C924);
+       if (err) {
+               snd_card_free(card);
+               return err;
+       }
+
+       err = snd_miro_opti_check(miro);
+       if (err) {
+               snd_printk(KERN_ERR "OPTI chip not found\n");
+               snd_card_free(card);
+               return err;
+       }
+
+       snd_card_set_dev(card, &pcard->card->dev);
+       err = snd_miro_probe(card);
+       if (err < 0) {
+               snd_card_free(card);
+               return err;
+       }
+       pnp_set_card_drvdata(pcard, card);
+       snd_miro_pnp_is_probed = 1;
+       return 0;
+}
+
+static void __devexit snd_miro_pnp_remove(struct pnp_card_link * pcard)
+{
+       snd_card_free(pnp_get_card_drvdata(pcard));
+       pnp_set_card_drvdata(pcard, NULL);
+       snd_miro_pnp_is_probed = 0;
+}
+
+static struct pnp_card_driver miro_pnpc_driver = {
+       .flags          = PNP_DRIVER_RES_DISABLE,
+       .name           = "miro",
+       .id_table       = snd_miro_pnpids,
+       .probe          = snd_miro_pnp_probe,
+       .remove         = __devexit_p(snd_miro_pnp_remove),
+};
+#endif
+
 static int __init alsa_card_miro_init(void)
 {
+#ifdef CONFIG_PNP
+       pnp_register_card_driver(&miro_pnpc_driver);
+       if (snd_miro_pnp_is_probed)
+               return 0;
+       pnp_unregister_card_driver(&miro_pnpc_driver);
+#endif
        return isa_register_driver(&snd_miro_driver, 1);
 }
 
 static void __exit alsa_card_miro_exit(void)
 {
-       isa_unregister_driver(&snd_miro_driver);
+       if (!snd_miro_pnp_is_probed) {
+               isa_unregister_driver(&snd_miro_driver);
+               return;
+       }
+#ifdef CONFIG_PNP
+       pnp_unregister_card_driver(&miro_pnpc_driver);
+#endif
 }
 
 module_init(alsa_card_miro_init)
index 5cd5553..d08c389 100644 (file)
@@ -141,15 +141,7 @@ struct snd_opti9xx {
 
        spinlock_t lock;
 
-       long wss_base;
        int irq;
-       int dma1;
-       int dma2;
-
-       long fm_port;
-
-       long mpu_port;
-       int mpu_irq;
 
 #ifdef CONFIG_PNP
        struct pnp_dev *dev;
@@ -216,13 +208,7 @@ static int __devinit snd_opti9xx_init(struct snd_opti9xx *chip,
 
        spin_lock_init(&chip->lock);
 
-       chip->wss_base = -1;
        chip->irq = -1;
-       chip->dma1 = -1;
-       chip->dma2 = -1;
-       chip->fm_port = -1;
-       chip->mpu_port = -1;
-       chip->mpu_irq = -1;
 
        switch (hardware) {
 #ifndef OPTi93X
@@ -348,7 +334,10 @@ static void snd_opti9xx_write(struct snd_opti9xx *chip, unsigned char reg,
                (snd_opti9xx_read(chip, reg) & ~(mask)) | ((value) & (mask)))
 
 
-static int __devinit snd_opti9xx_configure(struct snd_opti9xx *chip)
+static int __devinit snd_opti9xx_configure(struct snd_opti9xx *chip,
+                                          long wss_base,
+                                          int irq, int dma1, int dma2,
+                                          long mpu_port, int mpu_irq)
 {
        unsigned char wss_base_bits;
        unsigned char irq_bits;
@@ -416,7 +405,7 @@ static int __devinit snd_opti9xx_configure(struct snd_opti9xx *chip)
                return -EINVAL;
        }
 
-       switch (chip->wss_base) {
+       switch (wss_base) {
        case 0x530:
                wss_base_bits = 0x00;
                break;
@@ -430,14 +419,13 @@ static int __devinit snd_opti9xx_configure(struct snd_opti9xx *chip)
                wss_base_bits = 0x02;
                break;
        default:
-               snd_printk(KERN_WARNING "WSS port 0x%lx not valid\n",
-                          chip->wss_base);
+               snd_printk(KERN_WARNING "WSS port 0x%lx not valid\n", wss_base);
                goto __skip_base;
        }
        snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(1), wss_base_bits << 4, 0x30);
 
 __skip_base:
-       switch (chip->irq) {
+       switch (irq) {
 //#ifdef OPTi93X
        case 5:
                irq_bits = 0x05;
@@ -456,11 +444,11 @@ __skip_base:
                irq_bits = 0x04;
                break;
        default:
-               snd_printk(KERN_WARNING "WSS irq # %d not valid\n", chip->irq);
+               snd_printk(KERN_WARNING "WSS irq # %d not valid\n", irq);
                goto __skip_resources;
        }
 
-       switch (chip->dma1) {
+       switch (dma1) {
        case 0:
                dma_bits = 0x01;
                break;
@@ -471,38 +459,36 @@ __skip_base:
                dma_bits = 0x03;
                break;
        default:
-               snd_printk(KERN_WARNING "WSS dma1 # %d not valid\n",
-                          chip->dma1);
+               snd_printk(KERN_WARNING "WSS dma1 # %d not valid\n", dma1);
                goto __skip_resources;
        }
 
 #if defined(CS4231) || defined(OPTi93X)
-       if (chip->dma1 == chip->dma2) {
+       if (dma1 == dma2) {
                snd_printk(KERN_ERR "don't want to share dmas\n");
                return -EBUSY;
        }
 
-       switch (chip->dma2) {
+       switch (dma2) {
        case 0:
        case 1:
                break;
        default:
-               snd_printk(KERN_WARNING "WSS dma2 # %d not valid\n",
-                          chip->dma2);
+               snd_printk(KERN_WARNING "WSS dma2 # %d not valid\n", dma2);
                goto __skip_resources;
        }
        dma_bits |= 0x04;
 #endif /* CS4231 || OPTi93X */
 
 #ifndef OPTi93X
-        outb(irq_bits << 3 | dma_bits, chip->wss_base);
+        outb(irq_bits << 3 | dma_bits, wss_base);
 #else /* OPTi93X */
        snd_opti9xx_write(chip, OPTi9XX_MC_REG(3), (irq_bits << 3 | dma_bits));
 #endif /* OPTi93X */
 
 __skip_resources:
        if (chip->hardware > OPTi9XX_HW_82C928) {
-               switch (chip->mpu_port) {
+               switch (mpu_port) {
                case 0:
                case -1:
                        break;
@@ -520,12 +506,11 @@ __skip_resources:
                        break;
                default:
                        snd_printk(KERN_WARNING
-                                  "MPU-401 port 0x%lx not valid\n",
-                               chip->mpu_port);
+                                  "MPU-401 port 0x%lx not valid\n", mpu_port);
                        goto __skip_mpu;
                }
 
-               switch (chip->mpu_irq) {
+               switch (mpu_irq) {
                case 5:
                        mpu_irq_bits = 0x02;
                        break;
@@ -540,12 +525,12 @@ __skip_resources:
                        break;
                default:
                        snd_printk(KERN_WARNING "MPU-401 irq # %d not valid\n",
-                               chip->mpu_irq);
+                               mpu_irq);
                        goto __skip_mpu;
                }
 
                snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(6),
-                       (chip->mpu_port <= 0) ? 0x00 :
+                       (mpu_port <= 0) ? 0x00 :
                                0x80 | mpu_port_bits << 5 | mpu_irq_bits << 3,
                        0xf8);
        }
@@ -701,6 +686,7 @@ static int __devinit snd_opti9xx_probe(struct snd_card *card)
 {
        static long possible_ports[] = {0x530, 0xe80, 0xf40, 0x604, -1};
        int error;
+       int xdma2;
        struct snd_opti9xx *chip = card->private_data;
        struct snd_wss *codec;
 #ifdef CS4231
@@ -715,31 +701,25 @@ static int __devinit snd_opti9xx_probe(struct snd_card *card)
                                                "OPTi9xx MC")) == NULL)
                return -ENOMEM;
 
-       chip->wss_base = port;
-       chip->fm_port = fm_port;
-       chip->mpu_port = mpu_port;
-       chip->irq = irq;
-       chip->mpu_irq = mpu_irq;
-       chip->dma1 = dma1;
 #if defined(CS4231) || defined(OPTi93X)
-       chip->dma2 = dma2;
+       xdma2 = dma2;
 #else
-       chip->dma2 = -1;
+       xdma2 = -1;
 #endif
 
-       if (chip->wss_base == SNDRV_AUTO_PORT) {
-               chip->wss_base = snd_legacy_find_free_ioport(possible_ports, 4);
-               if (chip->wss_base < 0) {
+       if (port == SNDRV_AUTO_PORT) {
+               port = snd_legacy_find_free_ioport(possible_ports, 4);
+               if (port < 0) {
                        snd_printk(KERN_ERR "unable to find a free WSS port\n");
                        return -EBUSY;
                }
        }
-       error = snd_opti9xx_configure(chip);
+       error = snd_opti9xx_configure(chip, port, irq, dma1, xdma2,
+                                     mpu_port, mpu_irq);
        if (error)
                return error;
 
-       error = snd_wss_create(card, chip->wss_base + 4, -1,
-                              chip->irq, chip->dma1, chip->dma2,
+       error = snd_wss_create(card, port + 4, -1, irq, dma1, xdma2,
 #ifdef OPTi93X
                               WSS_HW_OPTI93X, WSS_HWSHARE_IRQ,
 #else
@@ -763,35 +743,35 @@ static int __devinit snd_opti9xx_probe(struct snd_card *card)
                return error;
 #endif
 #ifdef OPTi93X
-       error = request_irq(chip->irq, snd_opti93x_interrupt,
+       error = request_irq(irq, snd_opti93x_interrupt,
                            IRQF_DISABLED, DEV_NAME" - WSS", codec);
        if (error < 0) {
                snd_printk(KERN_ERR "opti9xx: can't grab IRQ %d\n", chip->irq);
                return error;
        }
 #endif
+       chip->irq = irq;
        strcpy(card->driver, chip->name);
        sprintf(card->shortname, "OPTi %s", card->driver);
 #if defined(CS4231) || defined(OPTi93X)
        sprintf(card->longname, "%s, %s at 0x%lx, irq %d, dma %d&%d",
-               card->shortname, pcm->name, chip->wss_base + 4,
-               chip->irq, chip->dma1, chip->dma2);
+               card->shortname, pcm->name, port + 4, irq, dma1, xdma2);
 #else
        sprintf(card->longname, "%s, %s at 0x%lx, irq %d, dma %d",
-               card->shortname, pcm->name, chip->wss_base + 4,
-               chip->irq, chip->dma1);
+               card->shortname, pcm->name, port + 4, irq, dma1);
 #endif /* CS4231 || OPTi93X */
 
-       if (chip->mpu_port <= 0 || chip->mpu_port == SNDRV_AUTO_PORT)
+       if (mpu_port <= 0 || mpu_port == SNDRV_AUTO_PORT)
                rmidi = NULL;
-       else
-               if ((error = snd_mpu401_uart_new(card, 0, MPU401_HW_MPU401,
-                               chip->mpu_port, 0, chip->mpu_irq, IRQF_DISABLED,
-                               &rmidi)))
+       else {
+               error = snd_mpu401_uart_new(card, 0, MPU401_HW_MPU401,
+                               mpu_port, 0, mpu_irq, IRQF_DISABLED, &rmidi);
+               if (error)
                        snd_printk(KERN_WARNING "no MPU-401 device at 0x%lx?\n",
-                                  chip->mpu_port);
+                                  mpu_port);
+       }
 
-       if (chip->fm_port > 0 && chip->fm_port != SNDRV_AUTO_PORT) {
+       if (fm_port > 0 && fm_port != SNDRV_AUTO_PORT) {
                struct snd_opl3 *opl3 = NULL;
 #ifndef OPTi93X
                if (chip->hardware == OPTi9XX_HW_82C928 ||
@@ -801,9 +781,7 @@ static int __devinit snd_opti9xx_probe(struct snd_card *card)
                        /* assume we have an OPL4 */
                        snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(2),
                                               0x20, 0x20);
-                       if (snd_opl4_create(card,
-                                           chip->fm_port,
-                                           chip->fm_port - 8,
+                       if (snd_opl4_create(card, fm_port, fm_port - 8,
                                            2, &opl3, &opl4) < 0) {
                                /* no luck, use OPL3 instead */
                                snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(2),
@@ -811,12 +789,10 @@ static int __devinit snd_opti9xx_probe(struct snd_card *card)
                        }
                }
 #endif /* !OPTi93X */
-               if (!opl3 && snd_opl3_create(card,
-                                            chip->fm_port,
-                                            chip->fm_port + 2,
+               if (!opl3 && snd_opl3_create(card, fm_port, fm_port + 2,
                                             OPL3_HW_AUTO, 0, &opl3) < 0) {
                        snd_printk(KERN_WARNING "no OPL device at 0x%lx-0x%lx\n",
-                                  chip->fm_port, chip->fm_port + 4 - 1);
+                                  fm_port, fm_port + 4 - 1);
                }
                if (opl3) {
                        error = snd_opl3_hwdep_new(opl3, 0, 1, &synth);
index 475220b..318ff0c 100644 (file)
@@ -631,7 +631,7 @@ static struct sbmix_elem snd_sb16_ctl_mic_play_switch =
 static struct sbmix_elem snd_sb16_ctl_mic_play_vol =
        SB_SINGLE("Mic Playback Volume", SB_DSP4_MIC_DEV, 3, 31);
 static struct sbmix_elem snd_sb16_ctl_pc_speaker_vol =
-       SB_SINGLE("PC Speaker Volume", SB_DSP4_SPEAKER_DEV, 6, 3);
+       SB_SINGLE("Beep Volume", SB_DSP4_SPEAKER_DEV, 6, 3);
 static struct sbmix_elem snd_sb16_ctl_capture_vol =
        SB_DOUBLE("Capture Volume", SB_DSP4_IGAIN_DEV, (SB_DSP4_IGAIN_DEV + 1), 6, 6, 3);
 static struct sbmix_elem snd_sb16_ctl_play_vol =
@@ -689,7 +689,7 @@ static struct sbmix_elem snd_dt019x_ctl_cd_play_vol =
 static struct sbmix_elem snd_dt019x_ctl_mic_play_vol =
        SB_SINGLE("Mic Playback Volume", SB_DT019X_MIC_DEV, 4, 7);
 static struct sbmix_elem snd_dt019x_ctl_pc_speaker_vol =
-       SB_SINGLE("PC Speaker Volume", SB_DT019X_SPKR_DEV, 0,  7);
+       SB_SINGLE("Beep Volume", SB_DT019X_SPKR_DEV, 0,  7);
 static struct sbmix_elem snd_dt019x_ctl_line_play_vol =
        SB_DOUBLE("Line Playback Volume", SB_DT019X_LINE_DEV, SB_DT019X_LINE_DEV, 4,0, 15);
 static struct sbmix_elem snd_dt019x_ctl_pcm_play_switch =
index 6618712..e2d5d2d 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *   Low-level ALSA driver for the ENSONIQ SoundScape PnP
+ *   Low-level ALSA driver for the ENSONIQ SoundScape
  *   Copyright (c) by Chris Rankin
  *
  *   This driver was written in part using information obtained from
 #include <linux/err.h>
 #include <linux/isa.h>
 #include <linux/delay.h>
+#include <linux/firmware.h>
 #include <linux/pnp.h>
 #include <linux/spinlock.h>
 #include <linux/moduleparam.h>
 #include <asm/dma.h>
 #include <sound/core.h>
-#include <sound/hwdep.h>
 #include <sound/wss.h>
 #include <sound/mpu401.h>
 #include <sound/initval.h>
 
-#include <sound/sscape_ioctl.h>
-
 
 MODULE_AUTHOR("Chris Rankin");
-MODULE_DESCRIPTION("ENSONIQ SoundScape PnP driver");
+MODULE_DESCRIPTION("ENSONIQ SoundScape driver");
 MODULE_LICENSE("GPL");
-
-static int index[SNDRV_CARDS] __devinitdata = SNDRV_DEFAULT_IDX;
-static char* id[SNDRV_CARDS] __devinitdata = SNDRV_DEFAULT_STR;
-static long port[SNDRV_CARDS] __devinitdata = SNDRV_DEFAULT_PORT;
-static long wss_port[SNDRV_CARDS] __devinitdata = SNDRV_DEFAULT_PORT;
-static int irq[SNDRV_CARDS] __devinitdata = SNDRV_DEFAULT_IRQ;
-static int mpu_irq[SNDRV_CARDS] __devinitdata = SNDRV_DEFAULT_IRQ;
-static int dma[SNDRV_CARDS] __devinitdata = SNDRV_DEFAULT_DMA;
-static int dma2[SNDRV_CARDS] __devinitdata = SNDRV_DEFAULT_DMA;
+MODULE_FIRMWARE("sndscape.co0");
+MODULE_FIRMWARE("sndscape.co1");
+MODULE_FIRMWARE("sndscape.co2");
+MODULE_FIRMWARE("sndscape.co3");
+MODULE_FIRMWARE("sndscape.co4");
+MODULE_FIRMWARE("scope.cod");
+
+static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
+static char* id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
+static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
+static long wss_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
+static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;
+static int mpu_irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;
+static int dma[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;
+static int dma2[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;
+static bool joystick[SNDRV_CARDS];
 
 module_param_array(index, int, NULL, 0444);
 MODULE_PARM_DESC(index, "Index number for SoundScape soundcard");
@@ -75,6 +80,9 @@ MODULE_PARM_DESC(dma, "DMA # for SoundScape driver.");
 module_param_array(dma2, int, NULL, 0444);
 MODULE_PARM_DESC(dma2, "DMA2 # for SoundScape driver.");
 
+module_param_array(joystick, bool, NULL, 0444);
+MODULE_PARM_DESC(joystick, "Enable gameport.");
+
 #ifdef CONFIG_PNP
 static int isa_registered;
 static int pnp_registered;
@@ -101,14 +109,14 @@ MODULE_DEVICE_TABLE(pnp_card, sscape_pnpids);
 #define RX_READY 0x01
 #define TX_READY 0x02
 
-#define CMD_ACK           0x80
-#define CMD_SET_MIDI_VOL  0x84
-#define CMD_GET_MIDI_VOL  0x85
-#define CMD_XXX_MIDI_VOL  0x86
-#define CMD_SET_EXTMIDI   0x8a
-#define CMD_GET_EXTMIDI   0x8b
-#define CMD_SET_MT32      0x8c
-#define CMD_GET_MT32      0x8d
+#define CMD_ACK                        0x80
+#define CMD_SET_MIDI_VOL       0x84
+#define CMD_GET_MIDI_VOL       0x85
+#define CMD_XXX_MIDI_VOL       0x86
+#define CMD_SET_EXTMIDI                0x8a
+#define CMD_GET_EXTMIDI                0x8b
+#define CMD_SET_MT32           0x8c
+#define CMD_GET_MT32           0x8d
 
 enum GA_REG {
        GA_INTSTAT_REG = 0,
@@ -127,7 +135,8 @@ enum GA_REG {
 
 
 enum card_type {
-       SSCAPE,
+       MEDIA_FX,       /* Sequoia S-1000 */
+       SSCAPE,         /* Sequoia S-2000 */
        SSCAPE_PNP,
        SSCAPE_VIVO,
 };
@@ -140,16 +149,7 @@ struct soundscape {
        struct resource *io_res;
        struct resource *wss_res;
        struct snd_wss *chip;
-       struct snd_mpu401 *mpu;
-       struct snd_hwdep *hw;
 
-       /*
-        * The MIDI device won't work until we've loaded
-        * its firmware via a hardware-dependent device IOCTL
-        */
-       spinlock_t fwlock;
-       int hw_in_use;
-       unsigned long midi_usage;
        unsigned char midi_vol;
 };
 
@@ -161,28 +161,21 @@ static inline struct soundscape *get_card_soundscape(struct snd_card *c)
        return (struct soundscape *) (c->private_data);
 }
 
-static inline struct soundscape *get_mpu401_soundscape(struct snd_mpu401 * mpu)
-{
-       return (struct soundscape *) (mpu->private_data);
-}
-
-static inline struct soundscape *get_hwdep_soundscape(struct snd_hwdep * hw)
-{
-       return (struct soundscape *) (hw->private_data);
-}
-
-
 /*
  * Allocates some kernel memory that we can use for DMA.
  * I think this means that the memory has to map to
  * contiguous pages of physical memory.
  */
-static struct snd_dma_buffer *get_dmabuf(struct snd_dma_buffer *buf, unsigned long size)
+static struct snd_dma_buffer *get_dmabuf(struct snd_dma_buffer *buf,
+                                        unsigned long size)
 {
        if (buf) {
-               if (snd_dma_alloc_pages_fallback(SNDRV_DMA_TYPE_DEV, snd_dma_isa_data(),
+               if (snd_dma_alloc_pages_fallback(SNDRV_DMA_TYPE_DEV,
+                                                snd_dma_isa_data(),
                                                 size, buf) < 0) {
-                       snd_printk(KERN_ERR "sscape: Failed to allocate %lu bytes for DMA\n", size);
+                       snd_printk(KERN_ERR "sscape: Failed to allocate "
+                                           "%lu bytes for DMA\n",
+                                           size);
                        return NULL;
                }
        }
@@ -199,13 +192,13 @@ static void free_dmabuf(struct snd_dma_buffer *buf)
                snd_dma_free_pages(buf);
 }
 
-
 /*
  * This function writes to the SoundScape's control registers,
  * but doesn't do any locking. It's up to the caller to do that.
  * This is why this function is "unsafe" ...
  */
-static inline void sscape_write_unsafe(unsigned io_base, enum GA_REG reg, unsigned char val)
+static inline void sscape_write_unsafe(unsigned io_base, enum GA_REG reg,
+                                      unsigned char val)
 {
        outb(reg, ODIE_ADDR_IO(io_base));
        outb(val, ODIE_DATA_IO(io_base));
@@ -215,7 +208,8 @@ static inline void sscape_write_unsafe(unsigned io_base, enum GA_REG reg, unsign
  * Write to the SoundScape's control registers, and do the
  * necessary locking ...
  */
-static void sscape_write(struct soundscape *s, enum GA_REG reg, unsigned char val)
+static void sscape_write(struct soundscape *s, enum GA_REG reg,
+                        unsigned char val)
 {
        unsigned long flags;
 
@@ -228,7 +222,8 @@ static void sscape_write(struct soundscape *s, enum GA_REG reg, unsigned char va
  * Read from the SoundScape's control registers, but leave any
  * locking to the caller. This is why the function is "unsafe" ...
  */
-static inline unsigned char sscape_read_unsafe(unsigned io_base, enum GA_REG reg)
+static inline unsigned char sscape_read_unsafe(unsigned io_base,
+                                              enum GA_REG reg)
 {
        outb(reg, ODIE_ADDR_IO(io_base));
        return inb(ODIE_DATA_IO(io_base));
@@ -257,9 +252,8 @@ static inline void set_midi_mode_unsafe(unsigned io_base)
 static inline int host_read_unsafe(unsigned io_base)
 {
        int data = -1;
-       if ((inb(HOST_CTRL_IO(io_base)) & RX_READY) != 0) {
+       if ((inb(HOST_CTRL_IO(io_base)) & RX_READY) != 0)
                data = inb(HOST_DATA_IO(io_base));
-       }
 
        return data;
 }
@@ -301,7 +295,7 @@ static inline int host_write_unsafe(unsigned io_base, unsigned char data)
  * Also leaves all locking-issues to the caller ...
  */
 static int host_write_ctrl_unsafe(unsigned io_base, unsigned char data,
-                                  unsigned timeout)
+                                 unsigned timeout)
 {
        int err;
 
@@ -320,7 +314,7 @@ static int host_write_ctrl_unsafe(unsigned io_base, unsigned char data,
  *
  * NOTE: This check is based upon observation, not documentation.
  */
-static inline int verify_mpu401(const struct snd_mpu401 * mpu)
+static inline int verify_mpu401(const struct snd_mpu401 *mpu)
 {
        return ((inb(MPU401C(mpu)) & 0xc0) == 0x80);
 }
@@ -328,7 +322,7 @@ static inline int verify_mpu401(const struct snd_mpu401 * mpu)
 /*
  * This is apparently the standard way to initailise an MPU-401
  */
-static inline void initialise_mpu401(const struct snd_mpu401 * mpu)
+static inline void initialise_mpu401(const struct snd_mpu401 *mpu)
 {
        outb(0, MPU401D(mpu));
 }
@@ -338,9 +332,10 @@ static inline void initialise_mpu401(const struct snd_mpu401 * mpu)
  * The AD1845 detection fails if we *don't* do this, so I
  * think that this is a good idea ...
  */
-static inline void activate_ad1845_unsafe(unsigned io_base)
+static void activate_ad1845_unsafe(unsigned io_base)
 {
-       sscape_write_unsafe(io_base, GA_HMCTL_REG, (sscape_read_unsafe(io_base, GA_HMCTL_REG) & 0xcf) | 0x10);
+       unsigned char val = sscape_read_unsafe(io_base, GA_HMCTL_REG);
+       sscape_write_unsafe(io_base, GA_HMCTL_REG, (val & 0xcf) | 0x10);
        sscape_write_unsafe(io_base, GA_CDCFG_REG, 0x80);
 }
 
@@ -359,24 +354,27 @@ static void soundscape_free(struct snd_card *c)
  * Tell the SoundScape to begin a DMA tranfer using the given channel.
  * All locking issues are left to the caller.
  */
-static inline void sscape_start_dma_unsafe(unsigned io_base, enum GA_REG reg)
+static void sscape_start_dma_unsafe(unsigned io_base, enum GA_REG reg)
 {
-       sscape_write_unsafe(io_base, reg, sscape_read_unsafe(io_base, reg) | 0x01);
-       sscape_write_unsafe(io_base, reg, sscape_read_unsafe(io_base, reg) & 0xfe);
+       sscape_write_unsafe(io_base, reg,
+                           sscape_read_unsafe(io_base, reg) | 0x01);
+       sscape_write_unsafe(io_base, reg,
+                           sscape_read_unsafe(io_base, reg) & 0xfe);
 }
 
 /*
  * Wait for a DMA transfer to complete. This is a "limited busy-wait",
  * and all locking issues are left to the caller.
  */
-static int sscape_wait_dma_unsafe(unsigned io_base, enum GA_REG reg, unsigned timeout)
+static int sscape_wait_dma_unsafe(unsigned io_base, enum GA_REG reg,
+                                 unsigned timeout)
 {
        while (!(sscape_read_unsafe(io_base, reg) & 0x01) && (timeout != 0)) {
                udelay(100);
                --timeout;
        } /* while */
 
-       return (sscape_read_unsafe(io_base, reg) & 0x01);
+       return sscape_read_unsafe(io_base, reg) & 0x01;
 }
 
 /*
@@ -392,12 +390,12 @@ static int obp_startup_ack(struct soundscape *s, unsigned timeout)
 
        do {
                unsigned long flags;
-               unsigned char x;
+               int x;
 
                spin_lock_irqsave(&s->lock, flags);
-               x = inb(HOST_DATA_IO(s->io_base));
+               x = host_read_unsafe(s->io_base);
                spin_unlock_irqrestore(&s->lock, flags);
-               if ((x & 0xfe) == 0xfe)
+               if (x == 0xfe || x == 0xff)
                        return 1;
 
                msleep(10);
@@ -419,10 +417,10 @@ static int host_startup_ack(struct soundscape *s, unsigned timeout)
 
        do {
                unsigned long flags;
-               unsigned char x;
+               int x;
 
                spin_lock_irqsave(&s->lock, flags);
-               x = inb(HOST_DATA_IO(s->io_base));
+               x = host_read_unsafe(s->io_base);
                spin_unlock_irqrestore(&s->lock, flags);
                if (x == 0xfe)
                        return 1;
@@ -436,15 +434,15 @@ static int host_startup_ack(struct soundscape *s, unsigned timeout)
 /*
  * Upload a byte-stream into the SoundScape using DMA channel A.
  */
-static int upload_dma_data(struct soundscape *s,
-                           const unsigned char __user *data,
-                           size_t size)
+static int upload_dma_data(struct soundscape *s, const unsigned char *data,
+                          size_t size)
 {
        unsigned long flags;
        struct snd_dma_buffer dma;
        int ret;
+       unsigned char val;
 
-       if (!get_dmabuf(&dma, PAGE_ALIGN(size)))
+       if (!get_dmabuf(&dma, PAGE_ALIGN(32 * 1024)))
                return -ENOMEM;
 
        spin_lock_irqsave(&s->lock, flags);
@@ -452,70 +450,57 @@ static int upload_dma_data(struct soundscape *s,
        /*
         * Reset the board ...
         */
-       sscape_write_unsafe(s->io_base, GA_HMCTL_REG, sscape_read_unsafe(s->io_base, GA_HMCTL_REG) & 0x3f);
+       val = sscape_read_unsafe(s->io_base, GA_HMCTL_REG);
+       sscape_write_unsafe(s->io_base, GA_HMCTL_REG, val & 0x3f);
 
        /*
         * Enable the DMA channels and configure them ...
         */
-       sscape_write_unsafe(s->io_base, GA_DMACFG_REG, 0x50);
-       sscape_write_unsafe(s->io_base, GA_DMAA_REG, (s->chip->dma1 << 4) | DMA_8BIT);
+       val = (s->chip->dma1 << 4) | DMA_8BIT;
+       sscape_write_unsafe(s->io_base, GA_DMAA_REG, val);
        sscape_write_unsafe(s->io_base, GA_DMAB_REG, 0x20);
 
        /*
         * Take the board out of reset ...
         */
-       sscape_write_unsafe(s->io_base, GA_HMCTL_REG, sscape_read_unsafe(s->io_base, GA_HMCTL_REG) | 0x80);
+       val = sscape_read_unsafe(s->io_base, GA_HMCTL_REG);
+       sscape_write_unsafe(s->io_base, GA_HMCTL_REG, val | 0x80);
 
        /*
-        * Upload the user's data (firmware?) to the SoundScape
+        * Upload the firmware to the SoundScape
         * board through the DMA channel ...
         */
        while (size != 0) {
                unsigned long len;
 
-               /*
-                * Apparently, copying to/from userspace can sleep.
-                * We are therefore forbidden from holding any
-                * spinlocks while we copy ...
-                */
-               spin_unlock_irqrestore(&s->lock, flags);
-
-               /*
-                * Remember that the data that we want to DMA
-                * comes from USERSPACE. We have already verified
-                * the userspace pointer ...
-                */
                len = min(size, dma.bytes);
-               len -= __copy_from_user(dma.area, data, len);
+               memcpy(dma.area, data, len);
                data += len;
                size -= len;
 
-               /*
-                * Grab that spinlock again, now that we've
-                * finished copying!
-                */
-               spin_lock_irqsave(&s->lock, flags);
-
                snd_dma_program(s->chip->dma1, dma.addr, len, DMA_MODE_WRITE);
                sscape_start_dma_unsafe(s->io_base, GA_DMAA_REG);
                if (!sscape_wait_dma_unsafe(s->io_base, GA_DMAA_REG, 5000)) {
                        /*
-                        * Don't forget to release this spinlock we're holding ...
+                        * Don't forget to release this spinlock we're holding
                         */
                        spin_unlock_irqrestore(&s->lock, flags);
 
-                       snd_printk(KERN_ERR "sscape: DMA upload has timed out\n");
+                       snd_printk(KERN_ERR
+                                       "sscape: DMA upload has timed out\n");
                        ret = -EAGAIN;
                        goto _release_dma;
                }
        } /* while */
 
        set_host_mode_unsafe(s->io_base);
+       outb(0x0, s->io_base);
 
        /*
         * Boot the board ... (I think)
         */
-       sscape_write_unsafe(s->io_base, GA_HMCTL_REG, sscape_read_unsafe(s->io_base, GA_HMCTL_REG) | 0x40);
+       val = sscape_read_unsafe(s->io_base, GA_HMCTL_REG);
+       sscape_write_unsafe(s->io_base, GA_HMCTL_REG, val | 0x40);
        spin_unlock_irqrestore(&s->lock, flags);
 
        /*
@@ -525,10 +510,12 @@ static int upload_dma_data(struct soundscape *s,
         */
        ret = 0;
        if (!obp_startup_ack(s, 5000)) {
-               snd_printk(KERN_ERR "sscape: No response from on-board processor after upload\n");
+               snd_printk(KERN_ERR "sscape: No response "
+                                   "from on-board processor after upload\n");
                ret = -EAGAIN;
        } else if (!host_startup_ack(s, 5000)) {
-               snd_printk(KERN_ERR "sscape: SoundScape failed to initialise\n");
+               snd_printk(KERN_ERR
+                               "sscape: SoundScape failed to initialise\n");
                ret = -EAGAIN;
        }
 
@@ -536,7 +523,7 @@ _release_dma:
        /*
         * NOTE!!! We are NOT holding any spinlocks at this point !!!
         */
-       sscape_write(s, GA_DMAA_REG, (s->ic_type == IC_ODIE ? 0x70 : 0x40));
+       sscape_write(s, GA_DMAA_REG, (s->ic_type == IC_OPUS ? 0x40 : 0x70));
        free_dmabuf(&dma);
 
        return ret;
@@ -546,167 +533,76 @@ _release_dma:
  * Upload the bootblock(?) into the SoundScape. The only
  * purpose of this block of code seems to be to tell
  * us which version of the microcode we should be using.
- *
- * NOTE: The boot-block data resides in USER-SPACE!!!
- *       However, we have already verified its memory
- *       addresses by the time we get here.
  */
-static int sscape_upload_bootblock(struct soundscape *sscape, struct sscape_bootblock __user *bb)
+static int sscape_upload_bootblock(struct snd_card *card)
 {
+       struct soundscape *sscape = get_card_soundscape(card);
        unsigned long flags;
+       const struct firmware *init_fw = NULL;
        int data = 0;
        int ret;
 
-       ret = upload_dma_data(sscape, bb->code, sizeof(bb->code));
-
-       spin_lock_irqsave(&sscape->lock, flags);
-       if (ret == 0) {
-               data = host_read_ctrl_unsafe(sscape->io_base, 100);
-       }
-       set_midi_mode_unsafe(sscape->io_base);
-       spin_unlock_irqrestore(&sscape->lock, flags);
-
-       if (ret == 0) {
-               if (data < 0) {
-                       snd_printk(KERN_ERR "sscape: timeout reading firmware version\n");
-                       ret = -EAGAIN;
-               }
-               else if (__copy_to_user(&bb->version, &data, sizeof(bb->version))) {
-                       ret = -EFAULT;
-               }
+       ret = request_firmware(&init_fw, "scope.cod", card->dev);
+       if (ret < 0) {
+               snd_printk(KERN_ERR "sscape: Error loading scope.cod");
+               return ret;
        }
+       ret = upload_dma_data(sscape, init_fw->data, init_fw->size);
 
-       return ret;
-}
-
-/*
- * Upload the microcode into the SoundScape. The
- * microcode is 64K of data, and if we try to copy
- * it into a local variable then we will SMASH THE
- * KERNEL'S STACK! We therefore leave it in USER
- * SPACE, and save ourselves from copying it at all.
- */
-static int sscape_upload_microcode(struct soundscape *sscape,
-                                   const struct sscape_microcode __user *mc)
-{
-       unsigned long flags;
-       char __user *code;
-       int err;
+       release_firmware(init_fw);
 
-       /*
-        * We are going to have to copy this data into a special
-        * DMA-able buffer before we can upload it. We shall therefore
-        * just check that the data pointer is valid for now.
-        *
-        * NOTE: This buffer is 64K long! That's WAY too big to
-        *       copy into a stack-temporary anyway.
-        */
-       if ( get_user(code, &mc->code) ||
-            !access_ok(VERIFY_READ, code, SSCAPE_MICROCODE_SIZE) )
-               return -EFAULT;
+       spin_lock_irqsave(&sscape->lock, flags);
+       if (ret == 0)
+               data = host_read_ctrl_unsafe(sscape->io_base, 100);
 
-       if ((err = upload_dma_data(sscape, code, SSCAPE_MICROCODE_SIZE)) == 0) {
-               snd_printk(KERN_INFO "sscape: MIDI firmware loaded\n");
-       }
+       if (data & 0x10)
+               sscape_write_unsafe(sscape->io_base, GA_SMCFGA_REG, 0x2f);
 
-       spin_lock_irqsave(&sscape->lock, flags);
-       set_midi_mode_unsafe(sscape->io_base);
        spin_unlock_irqrestore(&sscape->lock, flags);
 
-       initialise_mpu401(sscape->mpu);
+       data &= 0xf;
+       if (ret == 0 && data > 7) {
+               snd_printk(KERN_ERR
+                               "sscape: timeout reading firmware version\n");
+               ret = -EAGAIN;
+       }
 
-       return err;
+       return (ret == 0) ? data : ret;
 }
 
 /*
- * Hardware-specific device functions, to implement special
- * IOCTLs for the SoundScape card. This is how we upload
- * the microcode into the card, for example, and so we
- * must ensure that no two processes can open this device
- * simultaneously, and that we can't open it at all if
- * someone is using the MIDI device.
+ * Upload the microcode into the SoundScape.
  */
-static int sscape_hw_open(struct snd_hwdep * hw, struct file *file)
+static int sscape_upload_microcode(struct snd_card *card, int version)
 {
-       register struct soundscape *sscape = get_hwdep_soundscape(hw);
-       unsigned long flags;
+       struct soundscape *sscape = get_card_soundscape(card);
+       const struct firmware *init_fw = NULL;
+       char name[14];
        int err;
 
-       spin_lock_irqsave(&sscape->fwlock, flags);
+       snprintf(name, sizeof(name), "sndscape.co%d", version);
 
-       if ((sscape->midi_usage != 0) || sscape->hw_in_use) {
-               err = -EBUSY;
-       } else {
-               sscape->hw_in_use = 1;
-               err = 0;
+       err = request_firmware(&init_fw, name, card->dev);
+       if (err < 0) {
+               snd_printk(KERN_ERR "sscape: Error loading sndscape.co%d",
+                               version);
+               return err;
        }
+       err = upload_dma_data(sscape, init_fw->data, init_fw->size);
+       if (err == 0)
+               snd_printk(KERN_INFO "sscape: MIDI firmware loaded %d KBs\n",
+                               init_fw->size >> 10);
 
-       spin_unlock_irqrestore(&sscape->fwlock, flags);
-       return err;
-}
-
-static int sscape_hw_release(struct snd_hwdep * hw, struct file *file)
-{
-       register struct soundscape *sscape = get_hwdep_soundscape(hw);
-       unsigned long flags;
-
-       spin_lock_irqsave(&sscape->fwlock, flags);
-       sscape->hw_in_use = 0;
-       spin_unlock_irqrestore(&sscape->fwlock, flags);
-       return 0;
-}
-
-static int sscape_hw_ioctl(struct snd_hwdep * hw, struct file *file,
-                           unsigned int cmd, unsigned long arg)
-{
-       struct soundscape *sscape = get_hwdep_soundscape(hw);
-       int err = -EBUSY;
-
-       switch (cmd) {
-       case SND_SSCAPE_LOAD_BOOTB:
-               {
-                       register struct sscape_bootblock __user *bb = (struct sscape_bootblock __user *) arg;
-
-                       /*
-                        * We are going to have to copy this data into a special
-                        * DMA-able buffer before we can upload it. We shall therefore
-                        * just check that the data pointer is valid for now ...
-                        */
-                       if ( !access_ok(VERIFY_READ, bb->code, sizeof(bb->code)) )
-                               return -EFAULT;
-
-                       /*
-                        * Now check that we can write the firmware version number too...
-                        */
-                       if ( !access_ok(VERIFY_WRITE, &bb->version, sizeof(bb->version)) )
-                               return -EFAULT;
-
-                       err = sscape_upload_bootblock(sscape, bb);
-               }
-               break;
-
-       case SND_SSCAPE_LOAD_MCODE:
-               {
-                       register const struct sscape_microcode __user *mc = (const struct sscape_microcode __user *) arg;
-
-                       err = sscape_upload_microcode(sscape, mc);
-               }
-               break;
-
-       default:
-               err = -EINVAL;
-               break;
-       } /* switch */
+       release_firmware(init_fw);
 
        return err;
 }
 
-
 /*
  * Mixer control for the SoundScape's MIDI device.
  */
 static int sscape_midi_info(struct snd_kcontrol *ctl,
-                            struct snd_ctl_elem_info *uinfo)
+                           struct snd_ctl_elem_info *uinfo)
 {
        uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
        uinfo->count = 1;
@@ -716,7 +612,7 @@ static int sscape_midi_info(struct snd_kcontrol *ctl,
 }
 
 static int sscape_midi_get(struct snd_kcontrol *kctl,
-                           struct snd_ctl_elem_value *uctl)
+                          struct snd_ctl_elem_value *uctl)
 {
        struct snd_wss *chip = snd_kcontrol_chip(kctl);
        struct snd_card *card = chip->card;
@@ -730,16 +626,18 @@ static int sscape_midi_get(struct snd_kcontrol *kctl,
 }
 
 static int sscape_midi_put(struct snd_kcontrol *kctl,
-                           struct snd_ctl_elem_value *uctl)
+                          struct snd_ctl_elem_value *uctl)
 {
        struct snd_wss *chip = snd_kcontrol_chip(kctl);
        struct snd_card *card = chip->card;
-       register struct soundscape *s = get_card_soundscape(card);
+       struct soundscape *s = get_card_soundscape(card);
        unsigned long flags;
        int change;
+       unsigned char new_val;
 
        spin_lock_irqsave(&s->lock, flags);
 
+       new_val = uctl->value.integer.value[0] & 127;
        /*
         * We need to put the board into HOST mode before we
         * can send any volume-changing HOST commands ...
@@ -752,15 +650,16 @@ static int sscape_midi_put(struct snd_kcontrol *kctl,
         * and then perform another volume-related command. Perhaps the
         * first command is an "open" and the second command is a "close"?
         */
-       if (s->midi_vol == ((unsigned char) uctl->value.integer. value[0] & 127)) {
+       if (s->midi_vol == new_val) {
                change = 0;
                goto __skip_change;
        }
-       change = (host_write_ctrl_unsafe(s->io_base, CMD_SET_MIDI_VOL, 100)
-                 && host_write_ctrl_unsafe(s->io_base, ((unsigned char) uctl->value.integer. value[0]) & 127, 100)
-                 && host_write_ctrl_unsafe(s->io_base, CMD_XXX_MIDI_VOL, 100));
-       s->midi_vol = (unsigned char) uctl->value.integer.value[0] & 127;
-      __skip_change:
+       change = host_write_ctrl_unsafe(s->io_base, CMD_SET_MIDI_VOL, 100)
+                && host_write_ctrl_unsafe(s->io_base, new_val, 100)
+                && host_write_ctrl_unsafe(s->io_base, CMD_XXX_MIDI_VOL, 100)
+                && host_write_ctrl_unsafe(s->io_base, new_val, 100);
+       s->midi_vol = new_val;
+__skip_change:
 
        /*
         * Take the board out of HOST mode and back into MIDI mode ...
@@ -784,20 +683,25 @@ static struct snd_kcontrol_new midi_mixer_ctl = {
  * These IRQs are encoded as bit patterns so that they can be
  * written to the control registers.
  */
-static unsigned __devinit get_irq_config(int irq)
+static unsigned __devinit get_irq_config(int sscape_type, int irq)
 {
        static const int valid_irq[] = { 9, 5, 7, 10 };
+       static const int old_irq[] = { 9, 7, 5, 15 };
        unsigned cfg;
 
-       for (cfg = 0; cfg < ARRAY_SIZE(valid_irq); ++cfg) {
-               if (irq == valid_irq[cfg])
-                       return cfg;
-       } /* for */
+       if (sscape_type == MEDIA_FX) {
+               for (cfg = 0; cfg < ARRAY_SIZE(old_irq); ++cfg)
+                       if (irq == old_irq[cfg])
+                               return cfg;
+       } else {
+               for (cfg = 0; cfg < ARRAY_SIZE(valid_irq); ++cfg)
+                       if (irq == valid_irq[cfg])
+                               return cfg;
+       }
 
        return INVALID_IRQ;
 }
 
-
 /*
  * Perform certain arcane port-checks to see whether there
  * is a SoundScape board lurking behind the given ports.
@@ -842,11 +746,38 @@ static int __devinit detect_sscape(struct soundscape *s, long wss_io)
        if (s->type != SSCAPE_VIVO && (d & 0x9f) != 0x0e)
                goto _done;
 
-       d  = sscape_read_unsafe(s->io_base, GA_HMCTL_REG) & 0x3f;
-       sscape_write_unsafe(s->io_base, GA_HMCTL_REG, d | 0xc0);
+       if (s->ic_type == IC_OPUS)
+               activate_ad1845_unsafe(s->io_base);
 
        if (s->type == SSCAPE_VIVO)
                wss_io += 4;
+
+       d  = sscape_read_unsafe(s->io_base, GA_HMCTL_REG);
+       sscape_write_unsafe(s->io_base, GA_HMCTL_REG, d | 0xc0);
+
+       /* wait for WSS codec */
+       for (d = 0; d < 500; d++) {
+               if ((inb(wss_io) & 0x80) == 0)
+                       break;
+               spin_unlock_irqrestore(&s->lock, flags);
+               msleep(1);
+               spin_lock_irqsave(&s->lock, flags);
+       }
+
+       if ((inb(wss_io) & 0x80) != 0)
+               goto _done;
+
+       if (inb(wss_io + 2) == 0xff)
+               goto _done;
+
+       d  = sscape_read_unsafe(s->io_base, GA_HMCTL_REG) & 0x3f;
+       sscape_write_unsafe(s->io_base, GA_HMCTL_REG, d);
+
+       if ((inb(wss_io) & 0x80) != 0)
+               s->type = MEDIA_FX;
+
+       d = sscape_read_unsafe(s->io_base, GA_HMCTL_REG);
+       sscape_write_unsafe(s->io_base, GA_HMCTL_REG, d | 0xc0);
        /* wait for WSS codec */
        for (d = 0; d < 500; d++) {
                if ((inb(wss_io) & 0x80) == 0)
@@ -855,14 +786,13 @@ static int __devinit detect_sscape(struct soundscape *s, long wss_io)
                msleep(1);
                spin_lock_irqsave(&s->lock, flags);
        }
-       snd_printd(KERN_INFO "init delay = %d ms\n", d);
 
        /*
         * SoundScape successfully detected!
         */
        retval = 1;
 
-       _done:
+_done:
        spin_unlock_irqrestore(&s->lock, flags);
        return retval;
 }
@@ -873,63 +803,35 @@ static int __devinit detect_sscape(struct soundscape *s, long wss_io)
  * to crash the machine. Also check that someone isn't using the hardware
  * IOCTL device.
  */
-static int mpu401_open(struct snd_mpu401 * mpu)
+static int mpu401_open(struct snd_mpu401 *mpu)
 {
-       int err;
-
        if (!verify_mpu401(mpu)) {
-               snd_printk(KERN_ERR "sscape: MIDI disabled, please load firmware\n");
-               err = -ENODEV;
-       } else {
-               register struct soundscape *sscape = get_mpu401_soundscape(mpu);
-               unsigned long flags;
-
-               spin_lock_irqsave(&sscape->fwlock, flags);
-
-               if (sscape->hw_in_use || (sscape->midi_usage == ULONG_MAX)) {
-                       err = -EBUSY;
-               } else {
-                       ++(sscape->midi_usage);
-                       err = 0;
-               }
-
-               spin_unlock_irqrestore(&sscape->fwlock, flags);
+               snd_printk(KERN_ERR "sscape: MIDI disabled, "
+                                   "please load firmware\n");
+               return -ENODEV;
        }
 
-       return err;
-}
-
-static void mpu401_close(struct snd_mpu401 * mpu)
-{
-       register struct soundscape *sscape = get_mpu401_soundscape(mpu);
-       unsigned long flags;
-
-       spin_lock_irqsave(&sscape->fwlock, flags);
-       --(sscape->midi_usage);
-       spin_unlock_irqrestore(&sscape->fwlock, flags);
+       return 0;
 }
 
 /*
  * Initialse an MPU-401 subdevice for MIDI support on the SoundScape.
  */
-static int __devinit create_mpu401(struct snd_card *card, int devnum, unsigned long port, int irq)
+static int __devinit create_mpu401(struct snd_card *card, int devnum,
+                                  unsigned long port, int irq)
 {
        struct soundscape *sscape = get_card_soundscape(card);
        struct snd_rawmidi *rawmidi;
        int err;
 
-       if ((err = snd_mpu401_uart_new(card, devnum,
-                                      MPU401_HW_MPU401,
-                                      port, MPU401_INFO_INTEGRATED,
-                                      irq, IRQF_DISABLED,
-                                      &rawmidi)) == 0) {
-               struct snd_mpu401 *mpu = (struct snd_mpu401 *) rawmidi->private_data;
+       err = snd_mpu401_uart_new(card, devnum, MPU401_HW_MPU401, port,
+                                 MPU401_INFO_INTEGRATED, irq, IRQF_DISABLED,
+                                 &rawmidi);
+       if (err == 0) {
+               struct snd_mpu401 *mpu = rawmidi->private_data;
                mpu->open_input = mpu401_open;
                mpu->open_output = mpu401_open;
-               mpu->close_input = mpu401_close;
-               mpu->close_output = mpu401_close;
                mpu->private_data = sscape;
-               sscape->mpu = mpu;
 
                initialise_mpu401(mpu);
        }
@@ -950,32 +852,34 @@ static int __devinit create_ad1845(struct snd_card *card, unsigned port,
        register struct soundscape *sscape = get_card_soundscape(card);
        struct snd_wss *chip;
        int err;
+       int codec_type = WSS_HW_DETECT;
 
-       if (sscape->type == SSCAPE_VIVO)
-               port += 4;
+       switch (sscape->type) {
+       case MEDIA_FX:
+       case SSCAPE:
+               /*
+                * There are some freak examples of early Soundscape cards
+                * with CS4231 instead of AD1848/CS4248. Unfortunately, the
+                * CS4231 works only in CS4248 compatibility mode on
+                * these cards so force it.
+                */
+               if (sscape->ic_type != IC_OPUS)
+                       codec_type = WSS_HW_AD1848;
+               break;
 
-       if (dma1 == dma2)
-               dma2 = -1;
+       case SSCAPE_VIVO:
+               port += 4;
+               break;
+       default:
+               break;
+       }
 
        err = snd_wss_create(card, port, -1, irq, dma1, dma2,
-                            WSS_HW_DETECT, WSS_HWSHARE_DMA1, &chip);
+                            codec_type, WSS_HWSHARE_DMA1, &chip);
        if (!err) {
                unsigned long flags;
                struct snd_pcm *pcm;
 
-/*
- * It turns out that the PLAYBACK_ENABLE bit is set
- * by the lowlevel driver ...
- *
-#define AD1845_IFACE_CONFIG  \
-           (CS4231_AUTOCALIB | CS4231_RECORD_ENABLE | CS4231_PLAYBACK_ENABLE)
-    snd_wss_mce_up(chip);
-    spin_lock_irqsave(&chip->reg_lock, flags);
-    snd_wss_out(chip, CS4231_IFACE_CTRL, AD1845_IFACE_CONFIG);
-    spin_unlock_irqrestore(&chip->reg_lock, flags);
-    snd_wss_mce_down(chip);
- */
-
                if (sscape->type != SSCAPE_VIVO) {
                        /*
                         * The input clock frequency on the SoundScape must
@@ -1022,17 +926,10 @@ static int __devinit create_ad1845(struct snd_card *card, unsigned port,
                        }
                }
 
-               strcpy(card->driver, "SoundScape");
-               strcpy(card->shortname, pcm->name);
-               snprintf(card->longname, sizeof(card->longname),
-                        "%s at 0x%lx, IRQ %d, DMA1 %d, DMA2 %d\n",
-                        pcm->name, chip->port, chip->irq,
-                        chip->dma1, chip->dma2);
-
                sscape->chip = chip;
        }
 
-       _error:
+_error:
        return err;
 }
 
@@ -1051,21 +948,8 @@ static int __devinit create_sscape(int dev, struct snd_card *card)
        struct resource *wss_res;
        unsigned long flags;
        int err;
-
-       /*
-        * Check that the user didn't pass us garbage data ...
-        */
-       irq_cfg = get_irq_config(irq[dev]);
-       if (irq_cfg == INVALID_IRQ) {
-               snd_printk(KERN_ERR "sscape: Invalid IRQ %d\n", irq[dev]);
-               return -ENXIO;
-       }
-
-       mpu_irq_cfg = get_irq_config(mpu_irq[dev]);
-       if (mpu_irq_cfg == INVALID_IRQ) {
-               printk(KERN_ERR "sscape: Invalid IRQ %d\n", mpu_irq[dev]);
-               return -ENXIO;
-       }
+       int val;
+       const char *name;
 
        /*
         * Grab IO ports that we will need to probe so that we
@@ -1098,41 +982,51 @@ static int __devinit create_sscape(int dev, struct snd_card *card)
        }
 
        spin_lock_init(&sscape->lock);
-       spin_lock_init(&sscape->fwlock);
        sscape->io_res = io_res;
        sscape->wss_res = wss_res;
        sscape->io_base = port[dev];
 
        if (!detect_sscape(sscape, wss_port[dev])) {
-               printk(KERN_ERR "sscape: hardware not detected at 0x%x\n", sscape->io_base);
+               printk(KERN_ERR "sscape: hardware not detected at 0x%x\n",
+                       sscape->io_base);
                err = -ENODEV;
                goto _release_dma;
        }
 
-       printk(KERN_INFO "sscape: hardware detected at 0x%x, using IRQ %d, DMA %d\n",
-                        sscape->io_base, irq[dev], dma[dev]);
+       switch (sscape->type) {
+       case MEDIA_FX:
+               name = "MediaFX/SoundFX";
+               break;
+       case SSCAPE:
+               name = "Soundscape";
+               break;
+       case SSCAPE_PNP:
+               name = "Soundscape PnP";
+               break;
+       case SSCAPE_VIVO:
+               name = "Soundscape VIVO";
+               break;
+       default:
+               name = "unknown Soundscape";
+               break;
+       }
 
-       if (sscape->type != SSCAPE_VIVO) {
-               /*
-                * Now create the hardware-specific device so that we can
-                * load the microcode into the on-board processor.
-                * We cannot use the MPU-401 MIDI system until this firmware
-                * has been loaded into the card.
-                */
-               err = snd_hwdep_new(card, "MC68EC000", 0, &(sscape->hw));
-               if (err < 0) {
-                       printk(KERN_ERR "sscape: Failed to create "
-                                       "firmware device\n");
-                       goto _release_dma;
-               }
-               strlcpy(sscape->hw->name, "SoundScape M68K",
-                       sizeof(sscape->hw->name));
-               sscape->hw->name[sizeof(sscape->hw->name) - 1] = '\0';
-               sscape->hw->iface = SNDRV_HWDEP_IFACE_SSCAPE;
-               sscape->hw->ops.open = sscape_hw_open;
-               sscape->hw->ops.release = sscape_hw_release;
-               sscape->hw->ops.ioctl = sscape_hw_ioctl;
-               sscape->hw->private_data = sscape;
+       printk(KERN_INFO "sscape: %s card detected at 0x%x, using IRQ %d, DMA %d\n",
+                        name, sscape->io_base, irq[dev], dma[dev]);
+
+       /*
+        * Check that the user didn't pass us garbage data ...
+        */
+       irq_cfg = get_irq_config(sscape->type, irq[dev]);
+       if (irq_cfg == INVALID_IRQ) {
+               snd_printk(KERN_ERR "sscape: Invalid IRQ %d\n", irq[dev]);
+               return -ENXIO;
+       }
+
+       mpu_irq_cfg = get_irq_config(sscape->type, mpu_irq[dev]);
+       if (mpu_irq_cfg == INVALID_IRQ) {
+               snd_printk(KERN_ERR "sscape: Invalid IRQ %d\n", mpu_irq[dev]);
+               return -ENXIO;
        }
 
        /*
@@ -1141,9 +1035,6 @@ static int __devinit create_sscape(int dev, struct snd_card *card)
         */
        spin_lock_irqsave(&sscape->lock, flags);
 
-       activate_ad1845_unsafe(sscape->io_base);
-
-       sscape_write_unsafe(sscape->io_base, GA_INTENA_REG, 0x00); /* disable */
        sscape_write_unsafe(sscape->io_base, GA_SMCFGA_REG, 0x2e);
        sscape_write_unsafe(sscape->io_base, GA_SMCFGB_REG, 0x00);
 
@@ -1151,15 +1042,23 @@ static int __devinit create_sscape(int dev, struct snd_card *card)
         * Enable and configure the DMA channels ...
         */
        sscape_write_unsafe(sscape->io_base, GA_DMACFG_REG, 0x50);
-       dma_cfg = (sscape->ic_type == IC_ODIE ? 0x70 : 0x40);
+       dma_cfg = (sscape->ic_type == IC_OPUS ? 0x40 : 0x70);
        sscape_write_unsafe(sscape->io_base, GA_DMAA_REG, dma_cfg);
        sscape_write_unsafe(sscape->io_base, GA_DMAB_REG, 0x20);
 
-       sscape_write_unsafe(sscape->io_base,
-                           GA_INTCFG_REG, 0xf0 | (mpu_irq_cfg << 2) | mpu_irq_cfg);
+       mpu_irq_cfg |= mpu_irq_cfg << 2;
+       val = sscape_read_unsafe(sscape->io_base, GA_HMCTL_REG) & 0xF7;
+       if (joystick[dev])
+               val |= 8;
+       sscape_write_unsafe(sscape->io_base, GA_HMCTL_REG, val | 0x10);
+       sscape_write_unsafe(sscape->io_base, GA_INTCFG_REG, 0xf0 | mpu_irq_cfg);
        sscape_write_unsafe(sscape->io_base,
                            GA_CDCFG_REG, 0x09 | DMA_8BIT
                            | (dma[dev] << 4) | (irq_cfg << 1));
+       /*
+        * Enable the master IRQ ...
+        */
+       sscape_write_unsafe(sscape->io_base, GA_INTENA_REG, 0x80);
 
        spin_unlock_irqrestore(&sscape->lock, flags);
 
@@ -1170,32 +1069,56 @@ static int __devinit create_sscape(int dev, struct snd_card *card)
        err = create_ad1845(card, wss_port[dev], irq[dev],
                            dma[dev], dma2[dev]);
        if (err < 0) {
-               printk(KERN_ERR "sscape: No AD1845 device at 0x%lx, IRQ %d\n",
-                      wss_port[dev], irq[dev]);
+               snd_printk(KERN_ERR
+                               "sscape: No AD1845 device at 0x%lx, IRQ %d\n",
+                               wss_port[dev], irq[dev]);
                goto _release_dma;
        }
+       strcpy(card->driver, "SoundScape");
+       strcpy(card->shortname, name);
+       snprintf(card->longname, sizeof(card->longname),
+                "%s at 0x%lx, IRQ %d, DMA1 %d, DMA2 %d\n",
+                name, sscape->chip->port, sscape->chip->irq,
+                sscape->chip->dma1, sscape->chip->dma2);
+
 #define MIDI_DEVNUM  0
        if (sscape->type != SSCAPE_VIVO) {
-               err = create_mpu401(card, MIDI_DEVNUM, port[dev], mpu_irq[dev]);
-               if (err < 0) {
-                       printk(KERN_ERR "sscape: Failed to create "
-                                       "MPU-401 device at 0x%lx\n",
-                                       port[dev]);
-                       goto _release_dma;
-               }
+               err = sscape_upload_bootblock(card);
+               if (err >= 0)
+                       err = sscape_upload_microcode(card, err);
 
-               /*
-                * Enable the master IRQ ...
-                */
-               sscape_write(sscape, GA_INTENA_REG, 0x80);
+               if (err == 0) {
+                       err = create_mpu401(card, MIDI_DEVNUM, port[dev],
+                                           mpu_irq[dev]);
+                       if (err < 0) {
+                               snd_printk(KERN_ERR "sscape: Failed to create "
+                                               "MPU-401 device at 0x%lx\n",
+                                               port[dev]);
+                               goto _release_dma;
+                       }
 
-               /*
-                * Initialize mixer
-                */
-               sscape->midi_vol = 0;
-               host_write_ctrl_unsafe(sscape->io_base, CMD_SET_MIDI_VOL, 100);
-               host_write_ctrl_unsafe(sscape->io_base, 0, 100);
-               host_write_ctrl_unsafe(sscape->io_base, CMD_XXX_MIDI_VOL, 100);
+                       /*
+                        * Initialize mixer
+                        */
+                       spin_lock_irqsave(&sscape->lock, flags);
+                       sscape->midi_vol = 0;
+                       host_write_ctrl_unsafe(sscape->io_base,
+                                               CMD_SET_MIDI_VOL, 100);
+                       host_write_ctrl_unsafe(sscape->io_base,
+                                               sscape->midi_vol, 100);
+                       host_write_ctrl_unsafe(sscape->io_base,
+                                               CMD_XXX_MIDI_VOL, 100);
+                       host_write_ctrl_unsafe(sscape->io_base,
+                                               sscape->midi_vol, 100);
+                       host_write_ctrl_unsafe(sscape->io_base,
+                                               CMD_SET_EXTMIDI, 100);
+                       host_write_ctrl_unsafe(sscape->io_base,
+                                               0, 100);
+                       host_write_ctrl_unsafe(sscape->io_base, CMD_ACK, 100);
+
+                       set_midi_mode_unsafe(sscape->io_base);
+                       spin_unlock_irqrestore(&sscape->lock, flags);
+               }
        }
 
        /*
@@ -1231,7 +1154,8 @@ static int __devinit snd_sscape_match(struct device *pdev, unsigned int i)
            mpu_irq[i] == SNDRV_AUTO_IRQ ||
            dma[i] == SNDRV_AUTO_DMA) {
                printk(KERN_INFO
-                      "sscape: insufficient parameters, need IO, IRQ, MPU-IRQ and DMA\n");
+                      "sscape: insufficient parameters, "
+                      "need IO, IRQ, MPU-IRQ and DMA\n");
                return 0;
        }
 
@@ -1253,13 +1177,15 @@ static int __devinit snd_sscape_probe(struct device *pdev, unsigned int dev)
        sscape->type = SSCAPE;
 
        dma[dev] &= 0x03;
+       snd_card_set_dev(card, pdev);
+
        ret = create_sscape(dev, card);
        if (ret < 0)
                goto _release_card;
 
-       snd_card_set_dev(card, pdev);
-       if ((ret = snd_card_register(card)) < 0) {
-               printk(KERN_ERR "sscape: Failed to register sound card\n");
+       ret = snd_card_register(card);
+       if (ret < 0) {
+               snd_printk(KERN_ERR "sscape: Failed to register sound card\n");
                goto _release_card;
        }
        dev_set_drvdata(pdev, card);
@@ -1311,36 +1237,20 @@ static int __devinit sscape_pnp_detect(struct pnp_card_link *pcard,
         * Allow this function to fail *quietly* if all the ISA PnP
         * devices were configured using module parameters instead.
         */
-       if ((idx = get_next_autoindex(idx)) >= SNDRV_CARDS)
+       idx = get_next_autoindex(idx);
+       if (idx >= SNDRV_CARDS)
                return -ENOSPC;
 
        /*
-        * We have found a candidate ISA PnP card. Now we
-        * have to check that it has the devices that we
-        * expect it to have.
-        *
-        * We will NOT try and autoconfigure all of the resources
-        * needed and then activate the card as we are assuming that
-        * has already been done at boot-time using /proc/isapnp.
-        * We shall simply try to give each active card the resources
-        * that it wants. This is a sensible strategy for a modular
-        * system where unused modules are unloaded regularly.
-        *
-        * This strategy is utterly useless if we compile the driver
-        * into the kernel, of course.
-        */
-       // printk(KERN_INFO "sscape: %s\n", card->name);
-
-       /*
         * Check that we still have room for another sound card ...
         */
        dev = pnp_request_card_device(pcard, pid->devs[0].id, NULL);
-       if (! dev)
+       if (!dev)
                return -ENODEV;
 
        if (!pnp_is_active(dev)) {
                if (pnp_activate_dev(dev) < 0) {
-                       printk(KERN_INFO "sscape: device is inactive\n");
+                       snd_printk(KERN_INFO "sscape: device is inactive\n");
                        return -EBUSY;
                }
        }
@@ -1378,14 +1288,15 @@ static int __devinit sscape_pnp_detect(struct pnp_card_link *pcard,
                wss_port[idx] = pnp_port_start(dev, 1);
                dma2[idx] = pnp_dma(dev, 1);
        }
+       snd_card_set_dev(card, &pcard->card->dev);
 
        ret = create_sscape(idx, card);
        if (ret < 0)
                goto _release_card;
 
-       snd_card_set_dev(card, &pcard->card->dev);
-       if ((ret = snd_card_register(card)) < 0) {
-               printk(KERN_ERR "sscape: Failed to register sound card\n");
+       ret = snd_card_register(card);
+       if (ret < 0) {
+               snd_printk(KERN_ERR "sscape: Failed to register sound card\n");
                goto _release_card;
        }
 
index 5d2ba1b..5b9d6c1 100644 (file)
@@ -1682,7 +1682,7 @@ static void snd_wss_resume(struct snd_wss *chip)
 }
 #endif /* CONFIG_PM */
 
-int snd_wss_free(struct snd_wss *chip)
+static int snd_wss_free(struct snd_wss *chip)
 {
        release_and_free_resource(chip->res_port);
        release_and_free_resource(chip->res_cport);
@@ -1705,7 +1705,6 @@ int snd_wss_free(struct snd_wss *chip)
        kfree(chip);
        return 0;
 }
-EXPORT_SYMBOL(snd_wss_free);
 
 static int snd_wss_dev_free(struct snd_device *device)
 {
@@ -2198,84 +2197,61 @@ EXPORT_SYMBOL(snd_wss_put_double);
 static const DECLARE_TLV_DB_SCALE(db_scale_6bit, -9450, 150, 0);
 static const DECLARE_TLV_DB_SCALE(db_scale_5bit_12db_max, -3450, 150, 0);
 static const DECLARE_TLV_DB_SCALE(db_scale_rec_gain, 0, 150, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_4bit, -4500, 300, 0);
 
-static struct snd_kcontrol_new snd_ad1848_controls[] = {
-WSS_DOUBLE("PCM Playback Switch", 0, CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT,
-          7, 7, 1, 1),
+static struct snd_kcontrol_new snd_wss_controls[] = {
+WSS_DOUBLE("PCM Playback Switch", 0,
+               CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 7, 7, 1, 1),
 WSS_DOUBLE_TLV("PCM Playback Volume", 0,
-              CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 0, 0, 63, 1,
-              db_scale_6bit),
+               CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 0, 0, 63, 1,
+               db_scale_6bit),
 WSS_DOUBLE("Aux Playback Switch", 0,
-          CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 7, 7, 1, 1),
+               CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 7, 7, 1, 1),
 WSS_DOUBLE_TLV("Aux Playback Volume", 0,
-              CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 0, 0, 31, 1,
-              db_scale_5bit_12db_max),
+               CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 0, 0, 31, 1,
+               db_scale_5bit_12db_max),
 WSS_DOUBLE("Aux Playback Switch", 1,
-          CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 7, 7, 1, 1),
+               CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 7, 7, 1, 1),
 WSS_DOUBLE_TLV("Aux Playback Volume", 1,
-              CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 0, 0, 31, 1,
-              db_scale_5bit_12db_max),
+               CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 0, 0, 31, 1,
+               db_scale_5bit_12db_max),
 WSS_DOUBLE_TLV("Capture Volume", 0, CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT,
                0, 0, 15, 0, db_scale_rec_gain),
 {
-       .name = "Capture Source",
        .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       .name = "Capture Source",
        .info = snd_wss_info_mux,
        .get = snd_wss_get_mux,
        .put = snd_wss_put_mux,
 },
-WSS_SINGLE("Loopback Capture Switch", 0, CS4231_LOOPBACK, 0, 1, 0),
-WSS_SINGLE_TLV("Loopback Capture Volume", 0, CS4231_LOOPBACK, 1, 63, 0,
-              db_scale_6bit),
-};
-
-static struct snd_kcontrol_new snd_wss_controls[] = {
-WSS_DOUBLE("PCM Playback Switch", 0,
-               CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 7, 7, 1, 1),
-WSS_DOUBLE("PCM Playback Volume", 0,
-               CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 0, 0, 63, 1),
+WSS_DOUBLE("Mic Boost (+20dB)", 0,
+               CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 5, 5, 1, 0),
+WSS_SINGLE("Loopback Capture Switch", 0,
+               CS4231_LOOPBACK, 0, 1, 0),
+WSS_SINGLE_TLV("Loopback Capture Volume", 0, CS4231_LOOPBACK, 2, 63, 1,
+               db_scale_6bit),
 WSS_DOUBLE("Line Playback Switch", 0,
                CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 7, 7, 1, 1),
-WSS_DOUBLE("Line Playback Volume", 0,
-               CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 0, 0, 31, 1),
-WSS_DOUBLE("Aux Playback Switch", 0,
-               CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 7, 7, 1, 1),
-WSS_DOUBLE("Aux Playback Volume", 0,
-               CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 0, 0, 31, 1),
-WSS_DOUBLE("Aux Playback Switch", 1,
-               CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 7, 7, 1, 1),
-WSS_DOUBLE("Aux Playback Volume", 1,
-               CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 0, 0, 31, 1),
-WSS_SINGLE("Mono Playback Switch", 0,
+WSS_DOUBLE_TLV("Line Playback Volume", 0,
+               CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 0, 0, 31, 1,
+               db_scale_5bit_12db_max),
+WSS_SINGLE("Beep Playback Switch", 0,
                CS4231_MONO_CTRL, 7, 1, 1),
-WSS_SINGLE("Mono Playback Volume", 0,
-               CS4231_MONO_CTRL, 0, 15, 1),
+WSS_SINGLE_TLV("Beep Playback Volume", 0,
+               CS4231_MONO_CTRL, 0, 15, 1,
+               db_scale_4bit),
 WSS_SINGLE("Mono Output Playback Switch", 0,
                CS4231_MONO_CTRL, 6, 1, 1),
-WSS_SINGLE("Mono Output Playback Bypass", 0,
+WSS_SINGLE("Beep Bypass Playback Switch", 0,
                CS4231_MONO_CTRL, 5, 1, 0),
-WSS_DOUBLE("Capture Volume", 0,
-               CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 0, 0, 15, 0),
-{
-       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-       .name = "Capture Source",
-       .info = snd_wss_info_mux,
-       .get = snd_wss_get_mux,
-       .put = snd_wss_put_mux,
-},
-WSS_DOUBLE("Mic Boost", 0,
-               CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 5, 5, 1, 0),
-WSS_SINGLE("Loopback Capture Switch", 0,
-               CS4231_LOOPBACK, 0, 1, 0),
-WSS_SINGLE("Loopback Capture Volume", 0,
-               CS4231_LOOPBACK, 2, 63, 1)
 };
 
 static struct snd_kcontrol_new snd_opti93x_controls[] = {
 WSS_DOUBLE("Master Playback Switch", 0,
                OPTi93X_OUT_LEFT, OPTi93X_OUT_RIGHT, 7, 7, 1, 1),
-WSS_DOUBLE("Master Playback Volume", 0,
-               OPTi93X_OUT_LEFT, OPTi93X_OUT_RIGHT, 1, 1, 31, 1),
+WSS_DOUBLE_TLV("Master Playback Volume", 0,
+               OPTi93X_OUT_LEFT, OPTi93X_OUT_RIGHT, 1, 1, 31, 1,
+               db_scale_6bit),
 WSS_DOUBLE("PCM Playback Switch", 0,
                CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 7, 7, 1, 1),
 WSS_DOUBLE("PCM Playback Volume", 0,
@@ -2334,22 +2310,21 @@ int snd_wss_mixer(struct snd_wss *chip)
                        if (err < 0)
                                return err;
                }
-       else if (chip->hardware & WSS_HW_AD1848_MASK)
-               for (idx = 0; idx < ARRAY_SIZE(snd_ad1848_controls); idx++) {
-                       err = snd_ctl_add(card,
-                                       snd_ctl_new1(&snd_ad1848_controls[idx],
-                                                    chip));
-                       if (err < 0)
-                               return err;
-               }
-       else
-               for (idx = 0; idx < ARRAY_SIZE(snd_wss_controls); idx++) {
+       else {
+               int count = ARRAY_SIZE(snd_wss_controls);
+
+               /* Use only the first 11 entries on AD1848 */
+               if (chip->hardware & WSS_HW_AD1848_MASK)
+                       count = 11;
+
+               for (idx = 0; idx < count; idx++) {
                        err = snd_ctl_add(card,
                                        snd_ctl_new1(&snd_wss_controls[idx],
                                                     chip));
                        if (err < 0)
                                return err;
                }
+       }
        return 0;
 }
 EXPORT_SYMBOL(snd_wss_mixer);
index bcf2a06..135a2b7 100644 (file)
@@ -287,18 +287,6 @@ config SOUND_DMAP
 
          Say Y unless you have 16MB or more RAM or a PCI sound card.
 
-config SOUND_SSCAPE
-       tristate "Ensoniq SoundScape support"
-       help
-         Answer Y if you have a sound card based on the Ensoniq SoundScape
-         chipset. Such cards are being manufactured at least by Ensoniq, Spea
-         and Reveal (Reveal makes also other cards).
-
-         If you compile the driver into the kernel, you have to add
-         "sscape=<io>,<irq>,<dma>,<mpuio>,<mpuirq>" to the kernel command
-         line.
-
-
 config SOUND_VMIDI
        tristate "Loopback MIDI device support"
        help
index e0ae4d4..567b8a7 100644 (file)
@@ -13,7 +13,6 @@ obj-$(CONFIG_SOUND_SH_DAC_AUDIO)      += sh_dac_audio.o
 obj-$(CONFIG_SOUND_AEDSP16)    += aedsp16.o
 obj-$(CONFIG_SOUND_PSS)                += pss.o ad1848.o mpu401.o
 obj-$(CONFIG_SOUND_TRIX)       += trix.o ad1848.o sb_lib.o uart401.o
-obj-$(CONFIG_SOUND_SSCAPE)     += sscape.o ad1848.o mpu401.o
 obj-$(CONFIG_SOUND_MSS)                += ad1848.o
 obj-$(CONFIG_SOUND_PAS)                += pas2.o sb.o sb_lib.o uart401.o
 obj-$(CONFIG_SOUND_SB)         += sb.o sb_lib.o uart401.o
index b69c05b..7df48a2 100644 (file)
@@ -838,7 +838,7 @@ static int dma_ioctl(int dev, unsigned int cmd, void __user *arg)
                                        if ((err = audio_devs[dev]->d->prepare_for_input(dev,
                                                     dmap_in->fragment_size, dmap_in->nbufs)) < 0) {
                                                spin_unlock_irqrestore(&dmap_in->lock,flags);
-                                               return -err;
+                                               return err;
                                        }
                                        dmap_in->dma_mode = DMODE_INPUT;
                                        audio_devs[dev]->enable_bits |= PCM_ENABLE_INPUT;
index 9e45098..3bc7104 100644 (file)
@@ -426,7 +426,7 @@ midi_synth_open(int dev, int mode)
        int             err;
        struct midi_input_info *inc;
 
-       if (orig_dev < 0 || orig_dev > num_midis || midi_devs[orig_dev] == NULL)
+       if (orig_dev < 0 || orig_dev >= num_midis || midi_devs[orig_dev] == NULL)
                return -ENXIO;
 
        midi2synth[orig_dev] = dev;
index 734b8f9..0af9d24 100644 (file)
@@ -770,7 +770,7 @@ static int mpu_synth_ioctl(int dev, unsigned int cmd, void __user *arg)
 
        midi_dev = synth_devs[dev]->midi_dev;
 
-       if (midi_dev < 0 || midi_dev > num_midis || midi_devs[midi_dev] == NULL)
+       if (midi_dev < 0 || midi_dev >= num_midis || midi_devs[midi_dev] == NULL)
                return -ENXIO;
 
        devc = &dev_conf[midi_dev];
index b2ed875..4153752 100644 (file)
@@ -164,9 +164,6 @@ static ssize_t dac_audio_write(struct file *file, const char *buf, size_t count,
        int free;
        int nbytes;
 
-       if (count < 0)
-               return -EINVAL;
-
        if (!count) {
                dac_audio_sync();
                return 0;
diff --git a/sound/oss/sscape.c b/sound/oss/sscape.c
deleted file mode 100644 (file)
index 30c36d1..0000000
+++ /dev/null
@@ -1,1480 +0,0 @@
-/*
- * sound/oss/sscape.c
- *
- * Low level driver for Ensoniq SoundScape
- *
- *
- * Copyright (C) by Hannu Savolainen 1993-1997
- *
- * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
- * Version 2 (June 1991). See the "COPYING" file distributed with this software
- * for more info.
- *
- *
- * Thomas Sailer       : ioctl code reworked (vmalloc/vfree removed)
- * Sergey Smitienko    : ensoniq p'n'p support
- * Christoph Hellwig   : adapted to module_init/module_exit
- * Bartlomiej Zolnierkiewicz : added __init to attach_sscape()
- * Chris Rankin                : Specify that this module owns the coprocessor
- * Arnaldo C. de Melo  : added missing restore_flags in sscape_pnp_upload_file
- */
-
-#include <linux/init.h>
-#include <linux/module.h>
-
-#include "sound_config.h"
-#include "sound_firmware.h"
-
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/signal.h>
-#include <linux/fcntl.h>
-#include <linux/ctype.h>
-#include <linux/stddef.h>
-#include <linux/kmod.h>
-#include <asm/dma.h>
-#include <asm/io.h>
-#include <linux/wait.h>
-#include <linux/slab.h>
-#include <linux/ioport.h>
-#include <linux/delay.h>
-#include <linux/proc_fs.h>
-#include <linux/mm.h>
-#include <linux/spinlock.h>
-
-#include "coproc.h"
-
-#include "ad1848.h"
-#include "mpu401.h"
-
-/*
- *    I/O ports
- */
-#define MIDI_DATA       0
-#define MIDI_CTRL       1
-#define HOST_CTRL       2
-#define TX_READY       0x02
-#define RX_READY       0x01
-#define HOST_DATA       3
-#define ODIE_ADDR       4
-#define ODIE_DATA       5
-
-/*
- *    Indirect registers
- */
-
-#define GA_INTSTAT_REG 0
-#define GA_INTENA_REG  1
-#define GA_DMAA_REG    2
-#define GA_DMAB_REG    3
-#define GA_INTCFG_REG  4
-#define GA_DMACFG_REG  5
-#define GA_CDCFG_REG   6
-#define GA_SMCFGA_REG  7
-#define GA_SMCFGB_REG  8
-#define GA_HMCTL_REG   9
-
-/*
- * DMA channel identifiers (A and B)
- */
-
-#define SSCAPE_DMA_A   0
-#define SSCAPE_DMA_B   1
-
-#define PORT(name)     (devc->base+name)
-
-/*
- * Host commands recognized by the OBP microcode
- */
-#define CMD_GEN_HOST_ACK       0x80
-#define CMD_GEN_MPU_ACK                0x81
-#define CMD_GET_BOARD_TYPE     0x82
-#define CMD_SET_CONTROL                0x88    /* Old firmware only */
-#define CMD_GET_CONTROL                0x89    /* Old firmware only */
-#define CTL_MASTER_VOL         0
-#define CTL_MIC_MODE           2
-#define CTL_SYNTH_VOL          4
-#define CTL_WAVE_VOL           7
-#define CMD_SET_EXTMIDI                0x8a
-#define CMD_GET_EXTMIDI                0x8b
-#define CMD_SET_MT32           0x8c
-#define CMD_GET_MT32           0x8d
-
-#define CMD_ACK                        0x80
-
-#define        IC_ODIE                 1
-#define        IC_OPUS                 2
-
-typedef struct sscape_info
-{
-       int     base, irq, dma;
-       
-       int     codec, codec_irq;       /* required to setup pnp cards*/
-       int     codec_type;
-       int     ic_type;
-       char*   raw_buf;
-       unsigned long   raw_buf_phys;
-       int     buffsize;               /* -------------------------- */
-       spinlock_t lock;
-       int     ok;     /* Properly detected */
-       int     failed;
-       int     dma_allocated;
-       int     codec_audiodev;
-       int     opened;
-       int     *osp;
-       int     my_audiodev;
-} sscape_info;
-
-static struct sscape_info adev_info = {
-       0
-};
-
-static struct sscape_info *devc = &adev_info;
-static int sscape_mididev = -1;
-
-/* Some older cards have assigned interrupt bits differently than new ones */
-static char valid_interrupts_old[] = {
-       9, 7, 5, 15
-};
-
-static char valid_interrupts_new[] = {
-       9, 5, 7, 10
-};
-
-static char *valid_interrupts = valid_interrupts_new;
-
-/*
- *     See the bottom of the driver. This can be set by spea =0/1.
- */
-#ifdef REVEAL_SPEA
-static char old_hardware = 1;
-#else
-static char old_hardware;
-#endif
-
-static void sleep(unsigned howlong)
-{
-       current->state = TASK_INTERRUPTIBLE;
-       schedule_timeout(howlong);
-}
-
-static unsigned char sscape_read(struct sscape_info *devc, int reg)
-{
-       unsigned long flags;
-       unsigned char val;
-
-       spin_lock_irqsave(&devc->lock,flags);
-       outb(reg, PORT(ODIE_ADDR));
-       val = inb(PORT(ODIE_DATA));
-       spin_unlock_irqrestore(&devc->lock,flags);
-       return val;
-}
-
-static void __sscape_write(int reg, int data)
-{
-       outb(reg, PORT(ODIE_ADDR));
-       outb(data, PORT(ODIE_DATA));
-}
-
-static void sscape_write(struct sscape_info *devc, int reg, int data)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&devc->lock,flags);
-       __sscape_write(reg, data);
-       spin_unlock_irqrestore(&devc->lock,flags);
-}
-
-static unsigned char sscape_pnp_read_codec(sscape_info* devc, unsigned char reg)
-{
-       unsigned char res;
-       unsigned long flags;
-
-       spin_lock_irqsave(&devc->lock,flags);
-       outb( reg, devc -> codec);
-       res = inb (devc -> codec + 1);
-       spin_unlock_irqrestore(&devc->lock,flags);
-       return res;
-
-}
-
-static void sscape_pnp_write_codec(sscape_info* devc, unsigned char reg, unsigned char data)
-{
-       unsigned long flags;
-       
-       spin_lock_irqsave(&devc->lock,flags);
-       outb( reg, devc -> codec);
-       outb( data, devc -> codec + 1);
-       spin_unlock_irqrestore(&devc->lock,flags);
-}
-
-static void host_open(struct sscape_info *devc)
-{
-       outb((0x00), PORT(HOST_CTRL));  /* Put the board to the host mode */
-}
-
-static void host_close(struct sscape_info *devc)
-{
-       outb((0x03), PORT(HOST_CTRL));  /* Put the board to the MIDI mode */
-}
-
-static int host_write(struct sscape_info *devc, unsigned char *data, int count)
-{
-       unsigned long flags;
-       int i, timeout_val;
-
-       spin_lock_irqsave(&devc->lock,flags);
-       /*
-        * Send the command and data bytes
-        */
-
-       for (i = 0; i < count; i++)
-       {
-               for (timeout_val = 10000; timeout_val > 0; timeout_val--)
-                       if (inb(PORT(HOST_CTRL)) & TX_READY)
-                               break;
-
-               if (timeout_val <= 0)
-               {
-                               spin_unlock_irqrestore(&devc->lock,flags);
-                           return 0;
-               }
-               outb(data[i], PORT(HOST_DATA));
-       }
-       spin_unlock_irqrestore(&devc->lock,flags);
-       return 1;
-}
-
-static int host_read(struct sscape_info *devc)
-{
-       unsigned long flags;
-       int timeout_val;
-       unsigned char data;
-
-       spin_lock_irqsave(&devc->lock,flags);
-       /*
-        * Read a byte
-        */
-
-       for (timeout_val = 10000; timeout_val > 0; timeout_val--)
-               if (inb(PORT(HOST_CTRL)) & RX_READY)
-                       break;
-
-       if (timeout_val <= 0)
-       {
-               spin_unlock_irqrestore(&devc->lock,flags);
-               return -1;
-       }
-       data = inb(PORT(HOST_DATA));
-       spin_unlock_irqrestore(&devc->lock,flags);
-       return data;
-}
-
-#if 0 /* unused */
-static int host_command1(struct sscape_info *devc, int cmd)
-{
-       unsigned char buf[10];
-       buf[0] = (unsigned char) (cmd & 0xff);
-       return host_write(devc, buf, 1);
-}
-#endif /* unused */
-
-
-static int host_command2(struct sscape_info *devc, int cmd, int parm1)
-{
-       unsigned char buf[10];
-
-       buf[0] = (unsigned char) (cmd & 0xff);
-       buf[1] = (unsigned char) (parm1 & 0xff);
-
-       return host_write(devc, buf, 2);
-}
-
-static int host_command3(struct sscape_info *devc, int cmd, int parm1, int parm2)
-{
-       unsigned char buf[10];
-
-       buf[0] = (unsigned char) (cmd & 0xff);
-       buf[1] = (unsigned char) (parm1 & 0xff);
-       buf[2] = (unsigned char) (parm2 & 0xff);
-       return host_write(devc, buf, 3);
-}
-
-static void set_mt32(struct sscape_info *devc, int value)
-{
-       host_open(devc);
-       host_command2(devc, CMD_SET_MT32, value ? 1 : 0);
-       if (host_read(devc) != CMD_ACK)
-       {
-               /* printk( "SNDSCAPE: Setting MT32 mode failed\n"); */
-       }
-       host_close(devc);
-}
-
-static void set_control(struct sscape_info *devc, int ctrl, int value)
-{
-       host_open(devc);
-       host_command3(devc, CMD_SET_CONTROL, ctrl, value);
-       if (host_read(devc) != CMD_ACK)
-       {
-               /* printk( "SNDSCAPE: Setting control (%d) failed\n",  ctrl); */
-       }
-       host_close(devc);
-}
-
-static void do_dma(struct sscape_info *devc, int dma_chan, unsigned long buf, int blk_size, int mode)
-{
-       unsigned char temp;
-
-       if (dma_chan != SSCAPE_DMA_A)
-       {
-               printk(KERN_WARNING "soundscape: Tried to use DMA channel  != A. Why?\n");
-               return;
-       }
-       audio_devs[devc->codec_audiodev]->flags &= ~DMA_AUTOMODE;
-       DMAbuf_start_dma(devc->codec_audiodev, buf, blk_size, mode);
-       audio_devs[devc->codec_audiodev]->flags |= DMA_AUTOMODE;
-
-       temp = devc->dma << 4;  /* Setup DMA channel select bits */
-       if (devc->dma <= 3)
-               temp |= 0x80;   /* 8 bit DMA channel */
-
-       temp |= 1;              /* Trigger DMA */
-       sscape_write(devc, GA_DMAA_REG, temp);
-       temp &= 0xfe;           /* Clear DMA trigger */
-       sscape_write(devc, GA_DMAA_REG, temp);
-}
-
-static int verify_mpu(struct sscape_info *devc)
-{
-       /*
-        * The SoundScape board could be in three modes (MPU, 8250 and host).
-        * If the card is not in the MPU mode, enabling the MPU driver will
-        * cause infinite loop (the driver believes that there is always some
-        * received data in the buffer.
-        *
-        * Detect this by looking if there are more than 10 received MIDI bytes
-        * (0x00) in the buffer.
-        */
-
-       int i;
-
-       for (i = 0; i < 10; i++)
-       {
-               if (inb(devc->base + HOST_CTRL) & 0x80)
-                       return 1;
-
-               if (inb(devc->base) != 0x00)
-                       return 1;
-       }
-       printk(KERN_WARNING "SoundScape: The device is not in the MPU-401 mode\n");
-       return 0;
-}
-
-static int sscape_coproc_open(void *dev_info, int sub_device)
-{
-       if (sub_device == COPR_MIDI)
-       {
-               set_mt32(devc, 0);
-               if (!verify_mpu(devc))
-                       return -EIO;
-       }
-       return 0;
-}
-
-static void sscape_coproc_close(void *dev_info, int sub_device)
-{
-       struct sscape_info *devc = dev_info;
-       unsigned long   flags;
-
-       spin_lock_irqsave(&devc->lock,flags);
-       if (devc->dma_allocated)
-       {
-               __sscape_write(GA_DMAA_REG, 0x20);      /* DMA channel disabled */
-               devc->dma_allocated = 0;
-       }
-       spin_unlock_irqrestore(&devc->lock,flags);
-       return;
-}
-
-static void sscape_coproc_reset(void *dev_info)
-{
-}
-
-static int sscape_download_boot(struct sscape_info *devc, unsigned char *block, int size, int flag)
-{
-       unsigned long flags;
-       unsigned char temp;
-       volatile int done, timeout_val;
-       static unsigned char codec_dma_bits;
-
-       if (flag & CPF_FIRST)
-       {
-               /*
-                * First block. Have to allocate DMA and to reset the board
-                * before continuing.
-                */
-
-               spin_lock_irqsave(&devc->lock,flags);
-               codec_dma_bits = sscape_read(devc, GA_CDCFG_REG);
-
-               if (devc->dma_allocated == 0)
-                       devc->dma_allocated = 1;
-
-               spin_unlock_irqrestore(&devc->lock,flags);
-
-               sscape_write(devc, GA_HMCTL_REG, 
-                       (temp = sscape_read(devc, GA_HMCTL_REG)) & 0x3f);       /*Reset */
-
-               for (timeout_val = 10000; timeout_val > 0; timeout_val--)
-                       sscape_read(devc, GA_HMCTL_REG);        /* Delay */
-
-               /* Take board out of reset */
-               sscape_write(devc, GA_HMCTL_REG,
-                       (temp = sscape_read(devc, GA_HMCTL_REG)) | 0x80);
-       }
-       /*
-        * Transfer one code block using DMA
-        */
-       if (audio_devs[devc->codec_audiodev]->dmap_out->raw_buf == NULL)
-       {
-               printk(KERN_WARNING "soundscape: DMA buffer not available\n");
-               return 0;
-       }
-       memcpy(audio_devs[devc->codec_audiodev]->dmap_out->raw_buf, block, size);
-
-       spin_lock_irqsave(&devc->lock,flags);
-       
-       /******** INTERRUPTS DISABLED NOW ********/
-       
-       do_dma(devc, SSCAPE_DMA_A,
-              audio_devs[devc->codec_audiodev]->dmap_out->raw_buf_phys,
-              size, DMA_MODE_WRITE);
-
-       /*
-        * Wait until transfer completes.
-        */
-       
-       done = 0;
-       timeout_val = 30;
-       while (!done && timeout_val-- > 0)
-       {
-               int resid;
-
-               if (HZ / 50)
-                       sleep(HZ / 50);
-               clear_dma_ff(devc->dma);
-               if ((resid = get_dma_residue(devc->dma)) == 0)
-                       done = 1;
-       }
-
-       spin_unlock_irqrestore(&devc->lock,flags);
-       if (!done)
-               return 0;
-
-       if (flag & CPF_LAST)
-       {
-               /*
-                * Take the board out of reset
-                */
-               outb((0x00), PORT(HOST_CTRL));
-               outb((0x00), PORT(MIDI_CTRL));
-
-               temp = sscape_read(devc, GA_HMCTL_REG);
-               temp |= 0x40;
-               sscape_write(devc, GA_HMCTL_REG, temp); /* Kickstart the board */
-
-               /*
-                * Wait until the ODB wakes up
-                */
-               spin_lock_irqsave(&devc->lock,flags);
-               done = 0;
-               timeout_val = 5 * HZ;
-               while (!done && timeout_val-- > 0)
-               {
-                       unsigned char x;
-                       
-                       sleep(1);
-                       x = inb(PORT(HOST_DATA));
-                       if (x == 0xff || x == 0xfe)             /* OBP startup acknowledge */
-                       {
-                               DDB(printk("Soundscape: Acknowledge = %x\n", x));
-                               done = 1;
-                       }
-               }
-               sscape_write(devc, GA_CDCFG_REG, codec_dma_bits);
-
-               spin_unlock_irqrestore(&devc->lock,flags);
-               if (!done)
-               {
-                       printk(KERN_ERR "soundscape: The OBP didn't respond after code download\n");
-                       return 0;
-               }
-               spin_lock_irqsave(&devc->lock,flags);
-               done = 0;
-               timeout_val = 5 * HZ;
-               while (!done && timeout_val-- > 0)
-               {
-                       sleep(1);
-                       if (inb(PORT(HOST_DATA)) == 0xfe)       /* Host startup acknowledge */
-                               done = 1;
-               }
-               spin_unlock_irqrestore(&devc->lock,flags);
-               if (!done)
-               {
-                       printk(KERN_ERR "soundscape: OBP Initialization failed.\n");
-                       return 0;
-               }
-               printk(KERN_INFO "SoundScape board initialized OK\n");
-               set_control(devc, CTL_MASTER_VOL, 100);
-               set_control(devc, CTL_SYNTH_VOL, 100);
-
-#ifdef SSCAPE_DEBUG3
-               /*
-                * Temporary debugging aid. Print contents of the registers after
-                * downloading the code.
-                */
-               {
-                       int i;
-
-                       for (i = 0; i < 13; i++)
-                               printk("I%d = %02x (new value)\n", i, sscape_read(devc, i));
-               }
-#endif
-
-       }
-       return 1;
-}
-
-static int download_boot_block(void *dev_info, copr_buffer * buf)
-{
-       if (buf->len <= 0 || buf->len > sizeof(buf->data))
-               return -EINVAL;
-
-       if (!sscape_download_boot(devc, buf->data, buf->len, buf->flags))
-       {
-               printk(KERN_ERR "soundscape: Unable to load microcode block to the OBP.\n");
-               return -EIO;
-       }
-       return 0;
-}
-
-static int sscape_coproc_ioctl(void *dev_info, unsigned int cmd, void __user *arg, int local)
-{
-       copr_buffer *buf;
-       int err;
-
-       switch (cmd) 
-       {
-               case SNDCTL_COPR_RESET:
-                       sscape_coproc_reset(dev_info);
-                       return 0;
-
-               case SNDCTL_COPR_LOAD:
-                       buf = (copr_buffer *) vmalloc(sizeof(copr_buffer));
-                       if (buf == NULL)
-                               return -ENOSPC;
-                       if (copy_from_user(buf, arg, sizeof(copr_buffer))) 
-                       {
-                               vfree(buf);
-                               return -EFAULT;
-                       }
-                       err = download_boot_block(dev_info, buf);
-                       vfree(buf);
-                       return err;
-               
-               default:
-                       return -EINVAL;
-       }
-}
-
-static coproc_operations sscape_coproc_operations =
-{
-       "SoundScape M68K",
-       THIS_MODULE,
-       sscape_coproc_open,
-       sscape_coproc_close,
-       sscape_coproc_ioctl,
-       sscape_coproc_reset,
-       &adev_info
-};
-
-static struct resource *sscape_ports;
-static int sscape_is_pnp;
-
-static void __init attach_sscape(struct address_info *hw_config)
-{
-#ifndef SSCAPE_REGS
-       /*
-        * Config register values for Spea/V7 Media FX and Ensoniq S-2000.
-        * These values are card
-        * dependent. If you have another SoundScape based card, you have to
-        * find the correct values. Do the following:
-        *  - Compile this driver with SSCAPE_DEBUG1 defined.
-        *  - Shut down and power off your machine.
-        *  - Boot with DOS so that the SSINIT.EXE program is run.
-        *  - Warm boot to {Linux|SYSV|BSD} and write down the lines displayed
-        *    when detecting the SoundScape.
-        *  - Modify the following list to use the values printed during boot.
-        *    Undefine the SSCAPE_DEBUG1
-        */
-#define SSCAPE_REGS { \
-/* I0 */       0x00, \
-/* I1 */       0xf0, /* Note! Ignored. Set always to 0xf0 */ \
-/* I2 */       0x20, /* Note! Ignored. Set always to 0x20 */ \
-/* I3 */       0x20, /* Note! Ignored. Set always to 0x20 */ \
-/* I4 */       0xf5, /* Ignored */ \
-/* I5 */       0x10, \
-/* I6 */       0x00, \
-/* I7 */       0x2e, /* I7 MEM config A. Likely to vary between models */ \
-/* I8 */       0x00, /* I8 MEM config B. Likely to vary between models */ \
-/* I9 */       0x40 /* Ignored */ \
-       }
-#endif
-
-       unsigned long   flags;
-       static unsigned char regs[10] = SSCAPE_REGS;
-
-       int i, irq_bits = 0xff;
-
-       if (old_hardware)
-       {
-               valid_interrupts = valid_interrupts_old;
-               conf_printf("Ensoniq SoundScape (old)", hw_config);
-       }
-       else
-               conf_printf("Ensoniq SoundScape", hw_config);
-
-       for (i = 0; i < 4; i++)
-       {
-               if (hw_config->irq == valid_interrupts[i])
-               {
-                       irq_bits = i;
-                       break;
-               }
-       }
-       if (hw_config->irq > 15 || (regs[4] = irq_bits == 0xff))
-       {
-               printk(KERN_ERR "Invalid IRQ%d\n", hw_config->irq);
-               release_region(devc->base, 2);
-               release_region(devc->base + 2, 6);
-               if (sscape_is_pnp)
-                       release_region(devc->codec, 2);
-               return;
-       }
-       
-       if (!sscape_is_pnp) {
-       
-               spin_lock_irqsave(&devc->lock,flags);
-               /* Host interrupt enable */
-               sscape_write(devc, 1, 0xf0);    /* All interrupts enabled */
-               /* DMA A status/trigger register */
-               sscape_write(devc, 2, 0x20);    /* DMA channel disabled */
-               /* DMA B status/trigger register */
-               sscape_write(devc, 3, 0x20);    /* DMA channel disabled */
-               /* Host interrupt config reg */
-               sscape_write(devc, 4, 0xf0 | (irq_bits << 2) | irq_bits);
-               /* Don't destroy CD-ROM DMA config bits (0xc0) */
-               sscape_write(devc, 5, (regs[5] & 0x3f) | (sscape_read(devc, 5) & 0xc0));
-               /* CD-ROM config (WSS codec actually) */
-               sscape_write(devc, 6, regs[6]);
-               sscape_write(devc, 7, regs[7]);
-               sscape_write(devc, 8, regs[8]);
-               /* Master control reg. Don't modify CR-ROM bits. Disable SB emul */
-               sscape_write(devc, 9, (sscape_read(devc, 9) & 0xf0) | 0x08);
-               spin_unlock_irqrestore(&devc->lock,flags);
-       }
-#ifdef SSCAPE_DEBUG2
-       /*
-        * Temporary debugging aid. Print contents of the registers after
-        * changing them.
-        */
-       {
-               int i;
-
-               for (i = 0; i < 13; i++)
-                       printk("I%d = %02x (new value)\n", i, sscape_read(devc, i));
-       }
-#endif
-
-       if (probe_mpu401(hw_config, sscape_ports))
-               hw_config->always_detect = 1;
-       hw_config->name = "SoundScape";
-
-       hw_config->irq *= -1;   /* Negative value signals IRQ sharing */
-       attach_mpu401(hw_config, THIS_MODULE);
-       hw_config->irq *= -1;   /* Restore it */
-
-       if (hw_config->slots[1] != -1)  /* The MPU driver installed itself */
-       {
-               sscape_mididev = hw_config->slots[1];
-               midi_devs[hw_config->slots[1]]->coproc = &sscape_coproc_operations;
-       }
-       sscape_write(devc, GA_INTENA_REG, 0x80);        /* Master IRQ enable */
-       devc->ok = 1;
-       devc->failed = 0;
-}
-
-static int detect_ga(sscape_info * devc)
-{
-       unsigned char save;
-
-       DDB(printk("Entered Soundscape detect_ga(%x)\n", devc->base));
-
-       /*
-        * First check that the address register of "ODIE" is
-        * there and that it has exactly 4 writable bits.
-        * First 4 bits
-        */
-       
-       if ((save = inb(PORT(ODIE_ADDR))) & 0xf0)
-       {
-               DDB(printk("soundscape: Detect error A\n"));
-               return 0;
-       }
-       outb((0x00), PORT(ODIE_ADDR));
-       if (inb(PORT(ODIE_ADDR)) != 0x00)
-       {
-               DDB(printk("soundscape: Detect error B\n"));
-               return 0;
-       }
-       outb((0xff), PORT(ODIE_ADDR));
-       if (inb(PORT(ODIE_ADDR)) != 0x0f)
-       {
-               DDB(printk("soundscape: Detect error C\n"));
-               return 0;
-       }
-       outb((save), PORT(ODIE_ADDR));
-
-       /*
-        * Now verify that some indirect registers return zero on some bits.
-        * This may break the driver with some future revisions of "ODIE" but...
-        */
-
-       if (sscape_read(devc, 0) & 0x0c)
-       {
-               DDB(printk("soundscape: Detect error D (%x)\n", sscape_read(devc, 0)));
-               return 0;
-       }
-       if (sscape_read(devc, 1) & 0x0f)
-       {
-               DDB(printk("soundscape: Detect error E\n"));
-               return 0;
-       }
-       if (sscape_read(devc, 5) & 0x0f)
-       {
-               DDB(printk("soundscape: Detect error F\n"));
-               return 0;
-       }
-       return 1;
-}
-
-static int sscape_read_host_ctrl(sscape_info* devc)
-{
-       return host_read(devc);
-}
-
-static void sscape_write_host_ctrl2(sscape_info *devc, int a, int b)
-{
-       host_command2(devc, a, b);
-}
-
-static int sscape_alloc_dma(sscape_info *devc)
-{
-       char *start_addr, *end_addr;
-       int dma_pagesize;
-       int sz, size;
-       struct page *page;
-
-       if (devc->raw_buf != NULL) return 0;    /* Already done */
-       dma_pagesize = (devc->dma < 4) ? (64 * 1024) : (128 * 1024);
-       devc->raw_buf = NULL;
-       devc->buffsize = 8192*4;
-       if (devc->buffsize > dma_pagesize) devc->buffsize = dma_pagesize;
-       start_addr = NULL;
-       /*
-        * Now loop until we get a free buffer. Try to get smaller buffer if
-        * it fails. Don't accept smaller than 8k buffer for performance
-        * reasons.
-        */
-       while (start_addr == NULL && devc->buffsize > PAGE_SIZE) {
-               for (sz = 0, size = PAGE_SIZE; size < devc->buffsize; sz++, size <<= 1);
-               devc->buffsize = PAGE_SIZE * (1 << sz);
-               start_addr = (char *) __get_free_pages(GFP_ATOMIC|GFP_DMA, sz);
-               if (start_addr == NULL) devc->buffsize /= 2;
-       }
-
-       if (start_addr == NULL) {
-               printk(KERN_ERR "sscape pnp init error: Couldn't allocate DMA buffer\n");
-               return 0;
-       } else {
-               /* make some checks */
-               end_addr = start_addr + devc->buffsize - 1;             
-               /* now check if it fits into the same dma-pagesize */
-
-               if (((long) start_addr & ~(dma_pagesize - 1)) != ((long) end_addr & ~(dma_pagesize - 1))
-                   || end_addr >= (char *) (MAX_DMA_ADDRESS)) {
-                       printk(KERN_ERR "sscape pnp: Got invalid address 0x%lx for %db DMA-buffer\n", (long) start_addr, devc->buffsize);
-                       return 0;
-               }
-       }
-       devc->raw_buf = start_addr;
-       devc->raw_buf_phys = virt_to_bus(start_addr);
-
-       for (page = virt_to_page(start_addr); page <= virt_to_page(end_addr); page++)
-               SetPageReserved(page);
-       return 1;
-}
-
-static void sscape_free_dma(sscape_info *devc)
-{
-       int sz, size;
-       unsigned long start_addr, end_addr;
-       struct page *page;
-
-       if (devc->raw_buf == NULL) return;
-       for (sz = 0, size = PAGE_SIZE; size < devc->buffsize; sz++, size <<= 1);
-       start_addr = (unsigned long) devc->raw_buf;
-       end_addr = start_addr + devc->buffsize;
-
-       for (page = virt_to_page(start_addr); page <= virt_to_page(end_addr); page++)
-               ClearPageReserved(page);
-
-       free_pages((unsigned long) devc->raw_buf, sz);
-       devc->raw_buf = NULL;
-}
-
-/* Intel version !!!!!!!!! */
-
-static int sscape_start_dma(int chan, unsigned long physaddr, int count, int dma_mode)
-{
-       unsigned long flags;
-
-       flags = claim_dma_lock();
-       disable_dma(chan);
-       clear_dma_ff(chan);
-       set_dma_mode(chan, dma_mode);
-       set_dma_addr(chan, physaddr);
-       set_dma_count(chan, count);
-       enable_dma(chan);
-       release_dma_lock(flags);
-       return 0;
-}
-
-static void sscape_pnp_start_dma(sscape_info* devc, int arg )
-{
-       int reg;
-       if (arg == 0) reg = 2;
-       else reg = 3;
-
-       sscape_write(devc, reg, sscape_read( devc, reg) | 0x01);
-       sscape_write(devc, reg, sscape_read( devc, reg) & 0xFE);
-}
-
-static int sscape_pnp_wait_dma (sscape_info* devc, int arg )
-{
-       int             reg;
-       unsigned long   i;
-       unsigned char   d;
-
-       if (arg == 0) reg = 2;
-       else reg = 3;
-
-       sleep ( 1 );
-       i = 0;
-       do {
-               d = sscape_read(devc, reg) & 1;
-               if ( d == 1)  break;
-               i++;
-       } while (i < 500000);
-       d = sscape_read(devc, reg) & 1; 
-       return d;
-}
-
-static int     sscape_pnp_alloc_dma(sscape_info* devc)
-{
-       /* printk(KERN_INFO "sscape: requesting dma\n"); */
-       if (request_dma(devc -> dma, "sscape")) return 0;
-       /* printk(KERN_INFO "sscape: dma channel allocated\n"); */
-       if (!sscape_alloc_dma(devc)) {
-               free_dma(devc -> dma);
-               return 0;
-       };
-       return 1;
-}
-
-static void    sscape_pnp_free_dma(sscape_info* devc)
-{
-       sscape_free_dma( devc);
-       free_dma(devc -> dma ); 
-       /* printk(KERN_INFO "sscape: dma released\n"); */
-}
-
-static int     sscape_pnp_upload_file(sscape_info* devc, char* fn)
-{      
-       int             done = 0;
-       int             timeout_val;
-       char*           data,*dt;
-       int             len,l;
-       unsigned long   flags;
-
-       sscape_write( devc, 9, sscape_read(devc, 9 )  & 0x3F );
-       sscape_write( devc, 2, (devc -> dma << 4) | 0x80 );
-       sscape_write( devc, 3, 0x20 );
-       sscape_write( devc, 9, sscape_read( devc, 9 )  | 0x80 );
-       
-       len = mod_firmware_load(fn, &data);
-       if (len == 0) {
-                   printk(KERN_ERR "sscape: file not found: %s\n", fn);
-                   return 0;
-       }
-       dt = data;
-       spin_lock_irqsave(&devc->lock,flags);
-       while ( len > 0 ) {
-               if (len > devc -> buffsize) l = devc->buffsize;
-               else l = len;
-               len -= l;               
-               memcpy(devc->raw_buf, dt, l); dt += l;
-               sscape_start_dma(devc->dma, devc->raw_buf_phys, l, 0x48);
-               sscape_pnp_start_dma ( devc, 0 );
-               if (sscape_pnp_wait_dma ( devc, 0 ) == 0) {
-                       spin_unlock_irqrestore(&devc->lock,flags);
-                       return 0;
-               }
-       }
-       
-       spin_unlock_irqrestore(&devc->lock,flags);
-       vfree(data);
-       
-       outb(0, devc -> base + 2);
-       outb(0, devc -> base);
-
-       sscape_write ( devc, 9, sscape_read( devc, 9 ) | 0x40);
-
-       timeout_val = 5 * HZ; 
-       while (!done && timeout_val-- > 0)
-       {
-               unsigned char x;
-               sleep(1);
-               x = inb( devc -> base + 3);
-               if (x == 0xff || x == 0xfe)             /* OBP startup acknowledge */
-               {
-                       //printk(KERN_ERR "Soundscape: Acknowledge = %x\n", x);
-                       done = 1;
-               }
-       }
-       timeout_val = 5 * HZ;
-       done = 0;
-       while (!done && timeout_val-- > 0)
-       {
-               unsigned char x;
-               sleep(1);
-               x = inb( devc -> base + 3);
-               if (x == 0xfe)          /* OBP startup acknowledge */
-               {
-                       //printk(KERN_ERR "Soundscape: Acknowledge = %x\n", x);
-                       done = 1;
-               }
-       }
-
-       if ( !done ) printk(KERN_ERR "soundscape: OBP Initialization failed.\n");
-
-       sscape_write( devc, 2, devc->ic_type == IC_ODIE ? 0x70 : 0x40);
-       sscape_write( devc, 3, (devc -> dma << 4) + 0x80);
-       return 1;
-}
-
-static void __init sscape_pnp_init_hw(sscape_info* devc)
-{      
-       unsigned char midi_irq = 0, sb_irq = 0;
-       unsigned i;
-       static  char code_file_name[23] = "/sndscape/sndscape.cox";
-       
-       int sscape_joystic_enable       = 0x7f;
-       int sscape_mic_enable           = 0;
-       int sscape_ext_midi             = 0;            
-
-       if ( !sscape_pnp_alloc_dma(devc) ) {
-               printk(KERN_ERR "sscape: faild to allocate dma\n");
-               return;
-       }
-
-       for (i = 0; i < 4; i++) {
-               if ( devc -> irq   == valid_interrupts[i] ) 
-                       midi_irq = i;
-               if ( devc -> codec_irq == valid_interrupts[i] ) 
-                       sb_irq = i;
-       }
-
-       sscape_write( devc, 5, 0x50);
-       sscape_write( devc, 7, 0x2e);
-       sscape_write( devc, 8, 0x00);
-
-       sscape_write( devc, 2, devc->ic_type == IC_ODIE ? 0x70 : 0x40);
-       sscape_write( devc, 3, ( devc -> dma << 4) | 0x80);
-
-       sscape_write (devc, 4, 0xF0 | (midi_irq<<2) | midi_irq);
-
-       i = 0x10; //sscape_read(devc, 9) & (devc->ic_type == IC_ODIE ? 0xf0 : 0xc0);
-       if (sscape_joystic_enable) i |= 8;
-       
-       sscape_write (devc, 9, i);
-       sscape_write (devc, 6, 0x80);
-       sscape_write (devc, 1, 0x80);
-
-       if (devc -> codec_type == 2) {
-               sscape_pnp_write_codec( devc, 0x0C, 0x50);
-               sscape_pnp_write_codec( devc, 0x10, sscape_pnp_read_codec( devc, 0x10) & 0x3F);
-               sscape_pnp_write_codec( devc, 0x11, sscape_pnp_read_codec( devc, 0x11) | 0xC0);
-               sscape_pnp_write_codec( devc, 29, 0x20);
-       }
-
-       if (sscape_pnp_upload_file(devc, "/sndscape/scope.cod") == 0 ) {
-               printk(KERN_ERR "sscape: faild to upload file /sndscape/scope.cod\n");
-               sscape_pnp_free_dma(devc);
-               return;
-       }
-
-       i = sscape_read_host_ctrl( devc );
-       
-       if ( (i & 0x0F) >  7 ) {
-               printk(KERN_ERR "sscape: scope.cod faild\n");
-               sscape_pnp_free_dma(devc);
-               return;
-       }
-       if ( i & 0x10 ) sscape_write( devc, 7, 0x2F);
-       code_file_name[21] = (char) ( i & 0x0F) + 0x30;
-       if (sscape_pnp_upload_file( devc, code_file_name) == 0) {
-               printk(KERN_ERR "sscape: faild to upload file %s\n", code_file_name);
-               sscape_pnp_free_dma(devc);
-               return;
-       }
-       
-       if (devc->ic_type != IC_ODIE) {
-               sscape_pnp_write_codec( devc, 10, (sscape_pnp_read_codec(devc, 10) & 0x7f) |
-                ( sscape_mic_enable == 0 ? 0x00 : 0x80) );
-       }
-       sscape_write_host_ctrl2( devc, 0x84, 0x64 );  /* MIDI volume */
-       sscape_write_host_ctrl2( devc, 0x86, 0x64 );  /* MIDI volume?? */
-       sscape_write_host_ctrl2( devc, 0x8A, sscape_ext_midi);
-
-       sscape_pnp_write_codec ( devc, 6, 0x3f ); //WAV_VOL
-       sscape_pnp_write_codec ( devc, 7, 0x3f ); //WAV_VOL
-       sscape_pnp_write_codec ( devc, 2, 0x1F ); //WD_CDXVOLL
-       sscape_pnp_write_codec ( devc, 3, 0x1F ); //WD_CDXVOLR
-
-       if (devc -> codec_type == 1) {
-               sscape_pnp_write_codec ( devc, 4, 0x1F );
-               sscape_pnp_write_codec ( devc, 5, 0x1F );
-               sscape_write_host_ctrl2( devc, 0x88, sscape_mic_enable);
-       } else {
-               int t;
-               sscape_pnp_write_codec ( devc, 0x10, 0x1F << 1);
-               sscape_pnp_write_codec ( devc, 0x11, 0xC0 | (0x1F << 1));
-
-               t = sscape_pnp_read_codec( devc, 0x00) & 0xDF;
-               if ( (sscape_mic_enable == 0)) t |= 0;
-               else t |= 0x20;
-               sscape_pnp_write_codec ( devc, 0x00, t);
-               t = sscape_pnp_read_codec( devc, 0x01) & 0xDF;
-               if ( (sscape_mic_enable == 0) ) t |= 0;
-               else t |= 0x20;
-               sscape_pnp_write_codec ( devc, 0x01, t);
-               sscape_pnp_write_codec ( devc, 0x40 | 29 , 0x20);
-               outb(0, devc -> codec);
-       }
-       if (devc -> ic_type == IC_OPUS ) {
-               int i = sscape_read( devc, 9 );
-               sscape_write( devc, 9, i | 3 );
-               sscape_write( devc, 3, 0x40);
-
-               if (request_region(0x228, 1, "sscape setup junk")) {
-                       outb(0, 0x228);
-                       release_region(0x228,1);
-               }
-               sscape_write( devc, 3, (devc -> dma << 4) | 0x80);
-               sscape_write( devc, 9, i );
-       }
-       
-       host_close ( devc );
-       sscape_pnp_free_dma(devc);
-}
-
-static int __init detect_sscape_pnp(sscape_info* devc)
-{
-       long     i, irq_bits = 0xff;
-       unsigned int d;
-
-       DDB(printk("Entered detect_sscape_pnp(%x)\n", devc->base));
-
-       if (!request_region(devc->codec, 2, "sscape codec")) {
-               printk(KERN_ERR "detect_sscape_pnp: port %x is not free\n", devc->codec);       
-               return 0;
-       }
-
-       if ((inb(devc->base + 2) & 0x78) != 0)
-               goto fail;
-
-       d = inb ( devc -> base + 4) & 0xF0;
-       if (d & 0x80)
-               goto fail;
-       
-       if (d == 0) {
-               devc->codec_type = 1;
-               devc->ic_type = IC_ODIE;
-       } else if ( (d & 0x60) != 0) {
-               devc->codec_type = 2;
-               devc->ic_type = IC_OPUS;
-       } else if ( (d & 0x40) != 0) {  /* WTF? */
-               devc->codec_type = 2;
-               devc->ic_type = IC_ODIE;
-       } else
-               goto fail;
-       
-       sscape_is_pnp = 1;
-               
-       outb(0xFA, devc -> base+4);
-       if  ((inb( devc -> base+4) & 0x9F) != 0x0A)
-               goto fail;
-       outb(0xFE, devc -> base+4);
-       if  ( (inb(devc -> base+4) & 0x9F) != 0x0E)
-               goto fail;
-       if  ( (inb(devc -> base+5) & 0x9F) != 0x0E)
-               goto fail;
-
-       if (devc->codec_type == 2) {
-               if (devc->codec != devc->base + 8) {
-                       printk("soundscape warning: incorrect codec port specified\n");
-                       goto fail;
-               }
-               d = 0x10 | (sscape_read(devc, 9)  & 0xCF);
-               sscape_write(devc, 9, d);
-               sscape_write(devc, 6, 0x80);
-       } else {
-               //todo: check codec is not base + 8
-       }
-
-       d  = (sscape_read(devc, 9) & 0x3F) | 0xC0;
-       sscape_write(devc, 9, d);
-
-       for (i = 0; i < 550000; i++)
-               if ( !(inb(devc -> codec) & 0x80) ) break;
-
-       d = inb(devc -> codec);
-       if (d & 0x80)
-               goto fail;
-       if ( inb(devc -> codec + 2) == 0xFF)
-               goto fail;
-
-       sscape_write(devc, 9, sscape_read(devc, 9)  & 0x3F );
-
-       d  = inb(devc -> codec) & 0x80;
-       if ( d == 0) {
-               printk(KERN_INFO "soundscape: hardware detected\n");
-               valid_interrupts = valid_interrupts_new;
-       } else  {
-               printk(KERN_INFO "soundscape: board looks like media fx\n");
-               valid_interrupts = valid_interrupts_old;
-               old_hardware = 1;
-       }
-
-       sscape_write( devc, 9, 0xC0 | (sscape_read(devc, 9)  & 0x3F) );
-
-       for (i = 0; i < 550000; i++)
-               if ( !(inb(devc -> codec) & 0x80)) 
-                       break;
-               
-       sscape_pnp_init_hw(devc);
-
-       for (i = 0; i < 4; i++)
-       {
-               if (devc->codec_irq == valid_interrupts[i]) {
-                       irq_bits = i;
-                       break;
-               }
-       }       
-       sscape_write(devc, GA_INTENA_REG, 0x00);
-       sscape_write(devc, GA_DMACFG_REG, 0x50);
-       sscape_write(devc, GA_DMAA_REG, 0x70);
-       sscape_write(devc, GA_DMAB_REG, 0x20);
-       sscape_write(devc, GA_INTCFG_REG, 0xf0);
-       sscape_write(devc, GA_CDCFG_REG, 0x89 | (devc->dma << 4) | (irq_bits << 1));
-
-       sscape_pnp_write_codec( devc, 0, sscape_pnp_read_codec( devc, 0) | 0x20);
-       sscape_pnp_write_codec( devc, 0, sscape_pnp_read_codec( devc, 1) | 0x20);
-
-       return 1;
-fail:
-       release_region(devc->codec, 2);
-       return 0;
-}
-
-static int __init probe_sscape(struct address_info *hw_config)
-{
-       devc->base = hw_config->io_base;
-       devc->irq = hw_config->irq;
-       devc->dma = hw_config->dma;
-       devc->osp = hw_config->osp;
-
-#ifdef SSCAPE_DEBUG1
-       /*
-        * Temporary debugging aid. Print contents of the registers before
-        * changing them.
-        */
-       {
-               int i;
-
-               for (i = 0; i < 13; i++)
-                       printk("I%d = %02x (old value)\n", i, sscape_read(devc, i));
-       }
-#endif
-       devc->failed = 1;
-
-       sscape_ports = request_region(devc->base, 2, "mpu401");
-       if (!sscape_ports)
-               return 0;
-
-       if (!request_region(devc->base + 2, 6, "SoundScape")) {
-               release_region(devc->base, 2);
-               return 0;
-       }
-
-       if (!detect_ga(devc)) {
-               if (detect_sscape_pnp(devc))
-                       return 1;
-               release_region(devc->base, 2);
-               release_region(devc->base + 2, 6);
-               return 0;
-       }
-
-       if (old_hardware)       /* Check that it's really an old Spea/Reveal card. */
-       {
-               unsigned char   tmp;
-               int             cc;
-
-               if (!((tmp = sscape_read(devc, GA_HMCTL_REG)) & 0xc0))
-               {
-                       sscape_write(devc, GA_HMCTL_REG, tmp | 0x80);
-                       for (cc = 0; cc < 200000; ++cc)
-                               inb(devc->base + ODIE_ADDR);
-               }
-       }
-       return 1;
-}
-
-static int __init init_ss_ms_sound(struct address_info *hw_config)
-{
-       int i, irq_bits = 0xff;
-       int ad_flags = 0;
-       struct resource *ports;
-       
-       if (devc->failed)
-       {
-               printk(KERN_ERR "soundscape: Card not detected\n");
-               return 0;
-       }
-       if (devc->ok == 0)
-       {
-               printk(KERN_ERR "soundscape: Invalid initialization order.\n");
-               return 0;
-       }
-       for (i = 0; i < 4; i++)
-       {
-               if (hw_config->irq == valid_interrupts[i])
-               {
-                       irq_bits = i;
-                       break;
-               }
-       }
-       if (irq_bits == 0xff) {
-               printk(KERN_ERR "soundscape: Invalid MSS IRQ%d\n", hw_config->irq);
-               return 0;
-       }
-       
-       if (old_hardware)
-               ad_flags = 0x12345677;  /* Tell that we may have a CS4248 chip (Spea-V7 Media FX) */
-       else if (sscape_is_pnp)
-               ad_flags = 0x87654321;  /* Tell that we have a soundscape pnp with 1845 chip */
-
-       ports = request_region(hw_config->io_base, 4, "ad1848");
-       if (!ports) {
-               printk(KERN_ERR "soundscape: ports busy\n");
-               return 0;
-       }
-
-       if (!ad1848_detect(ports, &ad_flags, hw_config->osp)) {
-               release_region(hw_config->io_base, 4);
-               return 0;
-       }
-
-       if (!sscape_is_pnp)  /*pnp is already setup*/
-       {
-               /*
-                * Setup the DMA polarity.
-                */
-               sscape_write(devc, GA_DMACFG_REG, 0x50);
-       
-               /*
-                * Take the gate-array off of the DMA channel.
-                */
-               sscape_write(devc, GA_DMAB_REG, 0x20);
-       
-               /*
-                * Init the AD1848 (CD-ROM) config reg.
-                */
-               sscape_write(devc, GA_CDCFG_REG, 0x89 | (hw_config->dma << 4) | (irq_bits << 1));
-       }
-       
-       if (hw_config->irq == devc->irq)
-               printk(KERN_WARNING "soundscape: Warning! The WSS mode can't share IRQ with MIDI\n");
-                               
-       hw_config->slots[0] = ad1848_init(
-                       sscape_is_pnp ? "SoundScape" : "SoundScape PNP",
-                       ports,
-                       hw_config->irq,
-                       hw_config->dma,
-                       hw_config->dma,
-                       0,
-                       devc->osp,
-                       THIS_MODULE);
-
-                                         
-       if (hw_config->slots[0] != -1)  /* The AD1848 driver installed itself */
-       {
-               audio_devs[hw_config->slots[0]]->coproc = &sscape_coproc_operations;
-               devc->codec_audiodev = hw_config->slots[0];
-               devc->my_audiodev = hw_config->slots[0];
-
-               /* Set proper routings here (what are they) */
-               AD1848_REROUTE(SOUND_MIXER_LINE1, SOUND_MIXER_LINE);
-       }
-               
-#ifdef SSCAPE_DEBUG5
-       /*
-        * Temporary debugging aid. Print contents of the registers
-        * after the AD1848 device has been initialized.
-        */
-       {
-               int i;
-
-               for (i = 0; i < 13; i++)
-                       printk("I%d = %02x\n", i, sscape_read(devc, i));
-       }
-#endif
-       return 1;
-}
-
-static void __exit unload_sscape(struct address_info *hw_config)
-{
-       release_region(devc->base + 2, 6);
-       unload_mpu401(hw_config);
-       if (sscape_is_pnp)
-               release_region(devc->codec, 2);
-}
-
-static void __exit unload_ss_ms_sound(struct address_info *hw_config)
-{
-       ad1848_unload(hw_config->io_base,
-                     hw_config->irq,
-                     devc->dma,
-                     devc->dma,
-                     0);
-       sound_unload_audiodev(hw_config->slots[0]);
-}
-
-static struct address_info cfg;
-static struct address_info cfg_mpu;
-
-static int __initdata spea = -1;
-static int mss = 0;
-static int __initdata dma = -1;
-static int __initdata irq = -1;
-static int __initdata io = -1;
-static int __initdata mpu_irq = -1;
-static int __initdata mpu_io = -1;
-
-module_param(dma, int, 0);
-module_param(irq, int, 0);
-module_param(io, int, 0);
-module_param(spea, int, 0);            /* spea=0/1 set the old_hardware */
-module_param(mpu_irq, int, 0);
-module_param(mpu_io, int, 0);
-module_param(mss, int, 0);
-
-static int __init init_sscape(void)
-{
-       printk(KERN_INFO "Soundscape driver Copyright (C) by Hannu Savolainen 1993-1996\n");
-       
-       cfg.irq = irq;
-       cfg.dma = dma;
-       cfg.io_base = io;
-
-       cfg_mpu.irq = mpu_irq;
-       cfg_mpu.io_base = mpu_io;
-       /* WEH - Try to get right dma channel */
-        cfg_mpu.dma = dma;
-       
-       devc->codec = cfg.io_base;
-       devc->codec_irq = cfg.irq;
-       devc->codec_type = 0;
-       devc->ic_type = 0;
-       devc->raw_buf = NULL;
-       spin_lock_init(&devc->lock);
-
-       if (cfg.dma == -1 || cfg.irq == -1 || cfg.io_base == -1) {
-               printk(KERN_ERR "DMA, IRQ, and IO port must be specified.\n");
-               return -EINVAL;
-       }
-       
-       if (cfg_mpu.irq == -1 && cfg_mpu.io_base != -1) {
-               printk(KERN_ERR "MPU_IRQ must be specified if MPU_IO is set.\n");
-               return -EINVAL;
-       }
-       
-       if(spea != -1) {
-               old_hardware = spea;
-               printk(KERN_INFO "Forcing %s hardware support.\n",
-                       spea?"new":"old");
-       }       
-       if (probe_sscape(&cfg_mpu) == 0)
-               return -ENODEV;
-
-       attach_sscape(&cfg_mpu);
-       
-       mss = init_ss_ms_sound(&cfg);
-
-       return 0;
-}
-
-static void __exit cleanup_sscape(void)
-{
-       if (mss)
-               unload_ss_ms_sound(&cfg);
-       unload_sscape(&cfg_mpu);
-}
-
-module_init(init_sscape);
-module_exit(cleanup_sscape);
-
-#ifndef MODULE
-static int __init setup_sscape(char *str)
-{
-       /* io, irq, dma, mpu_io, mpu_irq */
-       int ints[6];
-       
-       str = get_options(str, ARRAY_SIZE(ints), ints);
-       
-       io      = ints[1];
-       irq     = ints[2];
-       dma     = ints[3];
-       mpu_io  = ints[4];
-       mpu_irq = ints[5];
-
-       return 1;
-}
-
-__setup("sscape=", setup_sscape);
-#endif
-MODULE_LICENSE("GPL");
index 75c602b..351654c 100644 (file)
@@ -570,6 +570,7 @@ config SND_ICE1712
        tristate "ICEnsemble ICE1712 (Envy24)"
        select SND_MPU401_UART
        select SND_AC97_CODEC
+       select BITREVERSE
        help
          Say Y here to include support for soundcards based on the
          ICE1712 (Envy24) chip.
index 78288db..20cb60a 100644 (file)
@@ -603,8 +603,8 @@ AC97_SINGLE("Tone Control - Treble", AC97_MASTER_TONE, 0, 15, 1)
 };
 
 static const struct snd_kcontrol_new snd_ac97_controls_pc_beep[2] = {
-AC97_SINGLE("PC Speaker Playback Switch", AC97_PC_BEEP, 15, 1, 1),
-AC97_SINGLE("PC Speaker Playback Volume", AC97_PC_BEEP, 1, 15, 1)
+AC97_SINGLE("Beep Playback Switch", AC97_PC_BEEP, 15, 1, 1),
+AC97_SINGLE("Beep Playback Volume", AC97_PC_BEEP, 1, 15, 1)
 };
 
 static const struct snd_kcontrol_new snd_ac97_controls_mic_boost =
@@ -1393,7 +1393,7 @@ static int snd_ac97_mixer_build(struct snd_ac97 * ac97)
                }
        }
        
-       /* build PC Speaker controls */
+       /* build Beep controls */
        if (!(ac97->flags & AC97_HAS_NO_PC_BEEP) && 
                ((ac97->flags & AC97_HAS_PC_BEEP) ||
            snd_ac97_try_volume_mix(ac97, AC97_PC_BEEP))) {
index 7337abd..139cf3b 100644 (file)
@@ -800,12 +800,12 @@ AC97_SINGLE("Mono Switch", AC97_MASTER_TONE, 7, 1, 1),
 AC97_SINGLE("Mono ZC Switch", AC97_MASTER_TONE, 6, 1, 0),
 AC97_SINGLE("Mono Volume", AC97_MASTER_TONE, 0, 31, 1),
 
-AC97_SINGLE("PC Beep to Headphone Switch", AC97_AUX, 15, 1, 1),
-AC97_SINGLE("PC Beep to Headphone Volume", AC97_AUX, 12, 7, 1),
-AC97_SINGLE("PC Beep to Master Switch", AC97_AUX, 11, 1, 1),
-AC97_SINGLE("PC Beep to Master Volume", AC97_AUX, 8, 7, 1),
-AC97_SINGLE("PC Beep to Mono Switch", AC97_AUX, 7, 1, 1),
-AC97_SINGLE("PC Beep to Mono Volume", AC97_AUX, 4, 7, 1),
+AC97_SINGLE("Beep to Headphone Switch", AC97_AUX, 15, 1, 1),
+AC97_SINGLE("Beep to Headphone Volume", AC97_AUX, 12, 7, 1),
+AC97_SINGLE("Beep to Master Switch", AC97_AUX, 11, 1, 1),
+AC97_SINGLE("Beep to Master Volume", AC97_AUX, 8, 7, 1),
+AC97_SINGLE("Beep to Mono Switch", AC97_AUX, 7, 1, 1),
+AC97_SINGLE("Beep to Mono Volume", AC97_AUX, 4, 7, 1),
 
 AC97_SINGLE("Voice to Headphone Switch", AC97_PCM, 15, 1, 1),
 AC97_SINGLE("Voice to Headphone Volume", AC97_PCM, 12, 7, 1),
index 8451a01..69867ac 100644 (file)
@@ -830,8 +830,8 @@ static struct snd_kcontrol_new snd_azf3328_mixer_controls[] __devinitdata = {
        AZF3328_MIXER_SWITCH("Mic Boost (+20dB)", IDX_MIXER_MIC, 6, 0),
        AZF3328_MIXER_SWITCH("Line Playback Switch", IDX_MIXER_LINEIN, 15, 1),
        AZF3328_MIXER_VOL_STEREO("Line Playback Volume", IDX_MIXER_LINEIN, 0x1f, 1),
-       AZF3328_MIXER_SWITCH("PC Speaker Playback Switch", IDX_MIXER_PCBEEP, 15, 1),
-       AZF3328_MIXER_VOL_SPECIAL("PC Speaker Playback Volume", IDX_MIXER_PCBEEP, 0x0f, 1, 1),
+       AZF3328_MIXER_SWITCH("Beep Playback Switch", IDX_MIXER_PCBEEP, 15, 1),
+       AZF3328_MIXER_VOL_SPECIAL("Beep Playback Volume", IDX_MIXER_PCBEEP, 0x0f, 1, 1),
        AZF3328_MIXER_SWITCH("Video Playback Switch", IDX_MIXER_VIDEO, 15, 1),
        AZF3328_MIXER_VOL_STEREO("Video Playback Volume", IDX_MIXER_VIDEO, 0x1f, 1),
        AZF3328_MIXER_SWITCH("Aux Playback Switch", IDX_MIXER_AUX, 15, 1),
index c8c6f43..8f443a9 100644 (file)
@@ -792,8 +792,8 @@ int __devinit snd_ca0106_mixer(struct snd_ca0106 *emu)
                "Phone Playback Volume",
                "Video Playback Switch",
                "Video Playback Volume",
-               "PC Speaker Playback Switch",
-               "PC Speaker Playback Volume",
+               "Beep Playback Switch",
+               "Beep Playback Volume",
                "Mono Output Select",
                "Capture Source",
                "Capture Switch",
index c62b7d1..15523e6 100644 (file)
@@ -304,7 +304,7 @@ static void snd_ca0106_proc_reg_write32(struct snd_info_entry *entry,
         while (!snd_info_get_line(buffer, line, sizeof(line))) {
                 if (sscanf(line, "%x %x", &reg, &val) != 2)
                         continue;
-                if ((reg < 0x40) && (reg >=0) && (val <= 0xffffffff) ) {
+               if (reg < 0x40 && val <= 0xffffffff) {
                        spin_lock_irqsave(&emu->emu_lock, flags);
                        outl(val, emu->port + (reg & 0xfffffffc));
                        spin_unlock_irqrestore(&emu->emu_lock, flags);
@@ -405,7 +405,7 @@ static void snd_ca0106_proc_reg_write(struct snd_info_entry *entry,
         while (!snd_info_get_line(buffer, line, sizeof(line))) {
                 if (sscanf(line, "%x %x %x", &reg, &channel_id, &val) != 3)
                         continue;
-                if ((reg < 0x80) && (reg >=0) && (val <= 0xffffffff) && (channel_id >=0) && (channel_id <= 3) )
+               if (reg < 0x80 && val <= 0xffffffff && channel_id <= 3)
                         snd_ca0106_ptr_write(emu, reg, channel_id, val);
         }
 }
index ddcd4a9..a312bae 100644 (file)
@@ -2302,7 +2302,7 @@ static struct snd_kcontrol_new snd_cmipci_mixers[] __devinitdata = {
        CMIPCI_SB_VOL_MONO("Mic Playback Volume", SB_DSP4_MIC_DEV, 3, 31),
        CMIPCI_SB_SW_MONO("Mic Playback Switch", 0),
        CMIPCI_DOUBLE("Mic Capture Switch", SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 0, 0, 1, 0, 0),
-       CMIPCI_SB_VOL_MONO("PC Speaker Playback Volume", SB_DSP4_SPEAKER_DEV, 6, 3),
+       CMIPCI_SB_VOL_MONO("Beep Playback Volume", SB_DSP4_SPEAKER_DEV, 6, 3),
        CMIPCI_MIXER_VOL_STEREO("Aux Playback Volume", CM_REG_AUX_VOL, 4, 0, 15),
        CMIPCI_MIXER_SW_STEREO("Aux Playback Switch", CM_REG_MIXER2, CM_VAUXLM_SHIFT, CM_VAUXRM_SHIFT, 0),
        CMIPCI_MIXER_SW_STEREO("Aux Capture Switch", CM_REG_MIXER2, CM_RAUXLEN_SHIFT, CM_RAUXREN_SHIFT, 0),
@@ -2310,7 +2310,7 @@ static struct snd_kcontrol_new snd_cmipci_mixers[] __devinitdata = {
        CMIPCI_MIXER_VOL_MONO("Mic Capture Volume", CM_REG_MIXER2, CM_VADMIC_SHIFT, 7),
        CMIPCI_SB_VOL_MONO("Phone Playback Volume", CM_REG_EXTENT_IND, 5, 7),
        CMIPCI_DOUBLE("Phone Playback Switch", CM_REG_EXTENT_IND, CM_REG_EXTENT_IND, 4, 4, 1, 0, 0),
-       CMIPCI_DOUBLE("PC Speaker Playback Switch", CM_REG_EXTENT_IND, CM_REG_EXTENT_IND, 3, 3, 1, 0, 0),
+       CMIPCI_DOUBLE("Beep Playback Switch", CM_REG_EXTENT_IND, CM_REG_EXTENT_IND, 3, 3, 1, 0, 0),
        CMIPCI_DOUBLE("Mic Boost Capture Switch", CM_REG_EXTENT_IND, CM_REG_EXTENT_IND, 0, 0, 1, 0, 0),
 };
 
index 7545464..cb65bd0 100644 (file)
@@ -240,7 +240,7 @@ static int select_rom(unsigned int pitch)
        } else if (pitch == 0x02000000) {
                /* pitch == 2 */
                return 3;
-       } else if (pitch >= 0x0 && pitch <= 0x08000000) {
+       } else if (pitch <= 0x08000000) {
                /* 0 <= pitch <= 8 */
                return 0;
        } else {
index 36e08bd..6b8ae7b 100644 (file)
@@ -1040,8 +1040,7 @@ static void snd_emu10k1x_proc_reg_write(struct snd_info_entry *entry,
                if (sscanf(line, "%x %x %x", &reg, &channel_id, &val) != 3)
                        continue;
 
-               if ((reg < 0x49) && (reg >= 0) && (val <= 0xffffffff) 
-                   && (channel_id >= 0) && (channel_id <= 2) )
+               if (reg < 0x49 && val <= 0xffffffff && channel_id <= 2)
                        snd_emu10k1x_ptr_write(emu, reg, channel_id, val);
        }
 }
index b0fb6c9..05afe06 100644 (file)
@@ -1818,8 +1818,8 @@ int __devinit snd_emu10k1_mixer(struct snd_emu10k1 *emu,
                "Master Playback Switch", "Master Capture Switch",
                "Master Playback Volume", "Master Capture Volume",
                "Wave Master Playback Volume", "Master Playback Volume",
-               "PC Speaker Playback Switch", "PC Speaker Capture Switch",
-               "PC Speaker Playback Volume", "PC Speaker Capture Volume",
+               "Beep Playback Switch", "Beep Capture Switch",
+               "Beep Playback Volume", "Beep Capture Volume",
                "Phone Playback Switch", "Phone Capture Switch",
                "Phone Playback Volume", "Phone Capture Volume",
                "Mic Playback Switch", "Mic Capture Switch",
index 216f974..baa7cd5 100644 (file)
@@ -451,7 +451,7 @@ static void snd_emu_proc_io_reg_write(struct snd_info_entry *entry,
        while (!snd_info_get_line(buffer, line, sizeof(line))) {
                if (sscanf(line, "%x %x", &reg, &val) != 2)
                        continue;
-               if ((reg < 0x40) && (reg >= 0) && (val <= 0xffffffff) ) {
+               if (reg < 0x40 && val <= 0xffffffff) {
                        spin_lock_irqsave(&emu->emu_lock, flags);
                        outl(val, emu->port + (reg & 0xfffffffc));
                        spin_unlock_irqrestore(&emu->emu_lock, flags);
@@ -527,7 +527,7 @@ static void snd_emu_proc_ptr_reg_write(struct snd_info_entry *entry,
        while (!snd_info_get_line(buffer, line, sizeof(line))) {
                if (sscanf(line, "%x %x %x", &reg, &channel_id, &val) != 3)
                        continue;
-               if ((reg < 0xa0) && (reg >= 0) && (val <= 0xffffffff) && (channel_id >= 0) && (channel_id <= 3) )
+               if (reg < 0xa0 && val <= 0xffffffff && channel_id <= 3)
                        snd_ptr_write(emu, iobase, reg, channel_id, val);
        }
 }
index c1a5aa1..5ef7080 100644 (file)
@@ -256,7 +256,7 @@ int snd_emu1010_fpga_write(struct snd_emu10k1 * emu, u32 reg, u32 value)
        if (reg > 0x3f)
                return 1;
        reg += 0x40; /* 0x40 upwards are registers. */
-       if (value < 0 || value > 0x3f) /* 0 to 0x3f are values */
+       if (value > 0x3f) /* 0 to 0x3f are values */
                return 1;
        spin_lock_irqsave(&emu->emu_lock, flags);
        outl(reg, emu->port + A_IOCFG);
index 820318e..fb83e1f 100644 (file)
@@ -1387,7 +1387,7 @@ ES1938_DOUBLE_TLV("Aux Playback Volume", 0, 0x3a, 0x3a, 4, 0, 15, 0,
                  db_scale_line),
 ES1938_DOUBLE_TLV("Capture Volume", 0, 0xb4, 0xb4, 4, 0, 15, 0,
                  db_scale_capture),
-ES1938_SINGLE("PC Speaker Volume", 0, 0x3c, 0, 7, 0),
+ES1938_SINGLE("Beep Volume", 0, 0x3c, 0, 7, 0),
 ES1938_SINGLE("Record Monitor", 0, 0xa8, 3, 1, 0),
 ES1938_SINGLE("Capture Switch", 0, 0x1c, 4, 1, 1),
 {
index 60cdb9e..83508b3 100644 (file)
@@ -55,7 +55,7 @@ static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;    /* Enable this card *
  *    1 = MediaForte 256-PCS
  *    2 = MediaForte 256-PCPR
  *    3 = MediaForte 64-PCR
- *   16 = setup tuner only (this is additional bit), i.e. SF-64-PCR FM card
+ *   16 = setup tuner only (this is additional bit), i.e. SF64-PCR FM card
  *  High 16-bits are video (radio) device number + 1
  */
 static int tea575x_tuner[SNDRV_CARDS];
@@ -67,7 +67,10 @@ MODULE_PARM_DESC(id, "ID string for the FM801 soundcard.");
 module_param_array(enable, bool, NULL, 0444);
 MODULE_PARM_DESC(enable, "Enable FM801 soundcard.");
 module_param_array(tea575x_tuner, int, NULL, 0444);
-MODULE_PARM_DESC(tea575x_tuner, "Enable TEA575x tuner.");
+MODULE_PARM_DESC(tea575x_tuner, "TEA575x tuner access method (1 = SF256-PCS, 2=SF256-PCPR, 3=SF64-PCR, +16=tuner-only).");
+
+#define TUNER_ONLY             (1<<4)
+#define TUNER_TYPE_MASK                (~TUNER_ONLY & 0xFFFF)
 
 /*
  *  Direct registers
@@ -160,7 +163,7 @@ struct fm801 {
        unsigned int multichannel: 1,   /* multichannel support */
                     secondary: 1;      /* secondary codec */
        unsigned char secondary_addr;   /* address of the secondary codec */
-       unsigned int tea575x_tuner;     /* tuner flags */
+       unsigned int tea575x_tuner;     /* tuner access method & flags */
 
        unsigned short ply_ctrl; /* playback control */
        unsigned short cap_ctrl; /* capture control */
@@ -1287,7 +1290,7 @@ static int snd_fm801_chip_init(struct fm801 *chip, int resume)
 {
        unsigned short cmdw;
 
-       if (chip->tea575x_tuner & 0x0010)
+       if (chip->tea575x_tuner & TUNER_ONLY)
                goto __ac97_ok;
 
        /* codec cold reset + AC'97 warm reset */
@@ -1296,11 +1299,13 @@ static int snd_fm801_chip_init(struct fm801 *chip, int resume)
        udelay(100);
        outw(0, FM801_REG(chip, CODEC_CTRL));
 
-       if (wait_for_codec(chip, 0, AC97_RESET, msecs_to_jiffies(750)) < 0) {
-               snd_printk(KERN_ERR "Primary AC'97 codec not found\n");
-               if (! resume)
-                       return -EIO;
-       }
+       if (wait_for_codec(chip, 0, AC97_RESET, msecs_to_jiffies(750)) < 0)
+               if (!resume) {
+                       snd_printk(KERN_INFO "Primary AC'97 codec not found, "
+                                           "assume SF64-PCR (tuner-only)\n");
+                       chip->tea575x_tuner = 3 | TUNER_ONLY;
+                       goto __ac97_ok;
+               }
 
        if (chip->multichannel) {
                if (chip->secondary_addr) {
@@ -1414,7 +1419,7 @@ static int __devinit snd_fm801_create(struct snd_card *card,
                return err;
        }
        chip->port = pci_resource_start(pci, 0);
-       if ((tea575x_tuner & 0x0010) == 0) {
+       if ((tea575x_tuner & TUNER_ONLY) == 0) {
                if (request_irq(pci->irq, snd_fm801_interrupt, IRQF_SHARED,
                                "FM801", chip)) {
                        snd_printk(KERN_ERR "unable to grab IRQ %d\n", chip->irq);
@@ -1429,6 +1434,14 @@ static int __devinit snd_fm801_create(struct snd_card *card,
                chip->multichannel = 1;
 
        snd_fm801_chip_init(chip, 0);
+       /* init might set tuner access method */
+       tea575x_tuner = chip->tea575x_tuner;
+
+       if (chip->irq >= 0 && (tea575x_tuner & TUNER_ONLY)) {
+               pci_clear_master(pci);
+               free_irq(chip->irq, chip);
+               chip->irq = -1;
+       }
 
        if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) {
                snd_fm801_free(chip);
@@ -1438,12 +1451,13 @@ static int __devinit snd_fm801_create(struct snd_card *card,
        snd_card_set_dev(card, &pci->dev);
 
 #ifdef TEA575X_RADIO
-       if (tea575x_tuner > 0 && (tea575x_tuner & 0x000f) < 4) {
+       if ((tea575x_tuner & TUNER_TYPE_MASK) > 0 &&
+           (tea575x_tuner & TUNER_TYPE_MASK) < 4) {
                chip->tea.dev_nr = tea575x_tuner >> 16;
                chip->tea.card = card;
                chip->tea.freq_fixup = 10700;
                chip->tea.private_data = chip;
-               chip->tea.ops = &snd_fm801_tea_ops[(tea575x_tuner & 0x000f) - 1];
+               chip->tea.ops = &snd_fm801_tea_ops[(tea575x_tuner & TUNER_TYPE_MASK) - 1];
                snd_tea575x_init(&chip->tea);
        }
 #endif
@@ -1483,7 +1497,7 @@ static int __devinit snd_card_fm801_probe(struct pci_dev *pci,
        sprintf(card->longname, "%s at 0x%lx, irq %i",
                card->shortname, chip->port, chip->irq);
 
-       if (tea575x_tuner[dev] & 0x0010)
+       if (chip->tea575x_tuner & TUNER_ONLY)
                goto __fm801_tuner_only;
 
        if ((err = snd_fm801_pcm(chip, 0, NULL)) < 0) {
index 55545e0..556cff9 100644 (file)
@@ -38,9 +38,20 @@ config SND_HDA_INPUT_BEEP
          Say Y here to build a digital beep interface for HD-audio
          driver. This interface is used to generate digital beeps.
 
+config SND_HDA_INPUT_BEEP_MODE
+       int "Digital beep registration mode (0=off, 1=on, 2=mute sw on/off)"
+       depends on SND_HDA_INPUT_BEEP=y
+       default "1"
+       range 0 2
+       help
+         Set 0 to disable the digital beep interface for HD-audio by default.
+         Set 1 to always enable the digital beep interface for HD-audio by
+         default. Set 2 to control the beep device registration to input
+         layer using a "Beep Switch" in mixer applications.
+
 config SND_HDA_INPUT_JACK
        bool "Support jack plugging notification via input layer"
-       depends on INPUT=y || INPUT=SND_HDA_INTEL
+       depends on INPUT=y || INPUT=SND
        select SND_JACK
        help
          Say Y here to enable the jack plugging notification via
index 3f51a98..5fe34a8 100644 (file)
@@ -113,23 +113,25 @@ static int snd_hda_beep_event(struct input_dev *dev, unsigned int type,
        return 0;
 }
 
-int snd_hda_attach_beep_device(struct hda_codec *codec, int nid)
+static void snd_hda_do_detach(struct hda_beep *beep)
+{
+       input_unregister_device(beep->dev);
+       beep->dev = NULL;
+       cancel_work_sync(&beep->beep_work);
+       /* turn off beep for sure */
+       snd_hda_codec_write_cache(beep->codec, beep->nid, 0,
+                                 AC_VERB_SET_BEEP_CONTROL, 0);
+}
+
+static int snd_hda_do_attach(struct hda_beep *beep)
 {
        struct input_dev *input_dev;
-       struct hda_beep *beep;
+       struct hda_codec *codec = beep->codec;
        int err;
 
-       if (!snd_hda_get_bool_hint(codec, "beep"))
-               return 0; /* disabled explicitly */
-
-       beep = kzalloc(sizeof(*beep), GFP_KERNEL);
-       if (beep == NULL)
-               return -ENOMEM;
-       snprintf(beep->phys, sizeof(beep->phys),
-               "card%d/codec#%d/beep0", codec->bus->card->number, codec->addr);
        input_dev = input_allocate_device();
        if (!input_dev) {
-               kfree(beep);
+               printk(KERN_INFO "hda_beep: unable to allocate input device\n");
                return -ENOMEM;
        }
 
@@ -151,21 +153,96 @@ int snd_hda_attach_beep_device(struct hda_codec *codec, int nid)
        err = input_register_device(input_dev);
        if (err < 0) {
                input_free_device(input_dev);
-               kfree(beep);
+               printk(KERN_INFO "hda_beep: unable to register input device\n");
                return err;
        }
+       beep->dev = input_dev;
+       return 0;
+}
+
+static void snd_hda_do_register(struct work_struct *work)
+{
+       struct hda_beep *beep =
+               container_of(work, struct hda_beep, register_work);
+
+       mutex_lock(&beep->mutex);
+       if (beep->enabled && !beep->dev)
+               snd_hda_do_attach(beep);
+       mutex_unlock(&beep->mutex);
+}
+
+static void snd_hda_do_unregister(struct work_struct *work)
+{
+       struct hda_beep *beep =
+               container_of(work, struct hda_beep, unregister_work.work);
+
+       mutex_lock(&beep->mutex);
+       if (!beep->enabled && beep->dev)
+               snd_hda_do_detach(beep);
+       mutex_unlock(&beep->mutex);
+}
 
+int snd_hda_enable_beep_device(struct hda_codec *codec, int enable)
+{
+       struct hda_beep *beep = codec->beep;
+       enable = !!enable;
+       if (beep == NULL)
+               return 0;
+       if (beep->enabled != enable) {
+               beep->enabled = enable;
+               if (!enable) {
+                       /* turn off beep */
+                       snd_hda_codec_write_cache(beep->codec, beep->nid, 0,
+                                                 AC_VERB_SET_BEEP_CONTROL, 0);
+               }
+               if (beep->mode == HDA_BEEP_MODE_SWREG) {
+                       if (enable) {
+                               cancel_delayed_work(&beep->unregister_work);
+                               schedule_work(&beep->register_work);
+                       } else {
+                               schedule_delayed_work(&beep->unregister_work,
+                                                                          HZ);
+                       }
+               }
+               return 1;
+       }
+       return 0;
+}
+EXPORT_SYMBOL_HDA(snd_hda_enable_beep_device);
+
+int snd_hda_attach_beep_device(struct hda_codec *codec, int nid)
+{
+       struct hda_beep *beep;
+
+       if (!snd_hda_get_bool_hint(codec, "beep"))
+               return 0; /* disabled explicitly by hints */
+       if (codec->beep_mode == HDA_BEEP_MODE_OFF)
+               return 0; /* disabled by module option */
+
+       beep = kzalloc(sizeof(*beep), GFP_KERNEL);
+       if (beep == NULL)
+               return -ENOMEM;
+       snprintf(beep->phys, sizeof(beep->phys),
+               "card%d/codec#%d/beep0", codec->bus->card->number, codec->addr);
        /* enable linear scale */
        snd_hda_codec_write(codec, nid, 0,
                AC_VERB_SET_DIGI_CONVERT_2, 0x01);
 
        beep->nid = nid;
-       beep->dev = input_dev;
        beep->codec = codec;
-       beep->enabled = 1;
+       beep->mode = codec->beep_mode;
        codec->beep = beep;
 
+       INIT_WORK(&beep->register_work, &snd_hda_do_register);
+       INIT_DELAYED_WORK(&beep->unregister_work, &snd_hda_do_unregister);
        INIT_WORK(&beep->beep_work, &snd_hda_generate_beep);
+       mutex_init(&beep->mutex);
+
+       if (beep->mode == HDA_BEEP_MODE_ON) {
+               beep->enabled = 1;
+               snd_hda_do_register(&beep->register_work);
+       }
+
        return 0;
 }
 EXPORT_SYMBOL_HDA(snd_hda_attach_beep_device);
@@ -174,11 +251,12 @@ void snd_hda_detach_beep_device(struct hda_codec *codec)
 {
        struct hda_beep *beep = codec->beep;
        if (beep) {
-               cancel_work_sync(&beep->beep_work);
-
-               input_unregister_device(beep->dev);
-               kfree(beep);
+               cancel_work_sync(&beep->register_work);
+               cancel_delayed_work(&beep->unregister_work);
+               if (beep->enabled)
+                       snd_hda_do_detach(beep);
                codec->beep = NULL;
+               kfree(beep);
        }
 }
 EXPORT_SYMBOL_HDA(snd_hda_detach_beep_device);
index 0c3de78..f1de1ba 100644 (file)
 
 #include "hda_codec.h"
 
+#define HDA_BEEP_MODE_OFF      0
+#define HDA_BEEP_MODE_ON       1
+#define HDA_BEEP_MODE_SWREG    2
+
 /* beep information */
 struct hda_beep {
        struct input_dev *dev;
        struct hda_codec *codec;
+       unsigned int mode;
        char phys[32];
        int tone;
        hda_nid_t nid;
        unsigned int enabled:1;
+       unsigned int request_enable:1;
        unsigned int linear_tone:1;     /* linear tone for IDT/STAC codec */
+       struct work_struct register_work; /* registration work */
+       struct delayed_work unregister_work; /* unregistration work */
        struct work_struct beep_work; /* scheduled task for beep event */
+       struct mutex mutex;
 };
 
 #ifdef CONFIG_SND_HDA_INPUT_BEEP
+int snd_hda_enable_beep_device(struct hda_codec *codec, int enable);
 int snd_hda_attach_beep_device(struct hda_codec *codec, int nid);
 void snd_hda_detach_beep_device(struct hda_codec *codec);
 #else
index af989f6..9cfdb77 100644 (file)
@@ -30,6 +30,7 @@
 #include <sound/tlv.h>
 #include <sound/initval.h>
 #include "hda_local.h"
+#include "hda_beep.h"
 #include <sound/hda_hwdep.h>
 
 /*
@@ -93,6 +94,13 @@ static void hda_keep_power_on(struct hda_codec *codec);
 static inline void hda_keep_power_on(struct hda_codec *codec) {}
 #endif
 
+/**
+ * snd_hda_get_jack_location - Give a location string of the jack
+ * @cfg: pin default config value
+ *
+ * Parse the pin default config value and returns the string of the
+ * jack location, e.g. "Rear", "Front", etc.
+ */
 const char *snd_hda_get_jack_location(u32 cfg)
 {
        static char *bases[7] = {
@@ -120,6 +128,13 @@ const char *snd_hda_get_jack_location(u32 cfg)
 }
 EXPORT_SYMBOL_HDA(snd_hda_get_jack_location);
 
+/**
+ * snd_hda_get_jack_connectivity - Give a connectivity string of the jack
+ * @cfg: pin default config value
+ *
+ * Parse the pin default config value and returns the string of the
+ * jack connectivity, i.e. external or internal connection.
+ */
 const char *snd_hda_get_jack_connectivity(u32 cfg)
 {
        static char *jack_locations[4] = { "Ext", "Int", "Sep", "Oth" };
@@ -128,6 +143,13 @@ const char *snd_hda_get_jack_connectivity(u32 cfg)
 }
 EXPORT_SYMBOL_HDA(snd_hda_get_jack_connectivity);
 
+/**
+ * snd_hda_get_jack_type - Give a type string of the jack
+ * @cfg: pin default config value
+ *
+ * Parse the pin default config value and returns the string of the
+ * jack type, i.e. the purpose of the jack, such as Line-Out or CD.
+ */
 const char *snd_hda_get_jack_type(u32 cfg)
 {
        static char *jack_types[16] = {
@@ -515,6 +537,7 @@ static int snd_hda_bus_dev_register(struct snd_device *device)
        struct hda_codec *codec;
        list_for_each_entry(codec, &bus->codec_list, list) {
                snd_hda_hwdep_add_sysfs(codec);
+               snd_hda_hwdep_add_power_sysfs(codec);
        }
        return 0;
 }
@@ -820,6 +843,16 @@ int snd_hda_add_pincfg(struct hda_codec *codec, struct snd_array *list,
        return 0;
 }
 
+/**
+ * snd_hda_codec_set_pincfg - Override a pin default configuration
+ * @codec: the HDA codec
+ * @nid: NID to set the pin config
+ * @cfg: the pin default config value
+ *
+ * Override a pin default configuration value in the cache.
+ * This value can be read by snd_hda_codec_get_pincfg() in a higher
+ * priority than the real hardware value.
+ */
 int snd_hda_codec_set_pincfg(struct hda_codec *codec,
                             hda_nid_t nid, unsigned int cfg)
 {
@@ -827,7 +860,15 @@ int snd_hda_codec_set_pincfg(struct hda_codec *codec,
 }
 EXPORT_SYMBOL_HDA(snd_hda_codec_set_pincfg);
 
-/* get the current pin config value of the given pin NID */
+/**
+ * snd_hda_codec_get_pincfg - Obtain a pin-default configuration
+ * @codec: the HDA codec
+ * @nid: NID to get the pin config
+ *
+ * Get the current pin config value of the given pin NID.
+ * If the pincfg value is cached or overridden via sysfs or driver,
+ * returns the cached value.
+ */
 unsigned int snd_hda_codec_get_pincfg(struct hda_codec *codec, hda_nid_t nid)
 {
        struct hda_pincfg *pin;
@@ -944,7 +985,7 @@ int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr
        mutex_init(&codec->control_mutex);
        init_hda_cache(&codec->amp_cache, sizeof(struct hda_amp_info));
        init_hda_cache(&codec->cmd_cache, sizeof(struct hda_cache_head));
-       snd_array_init(&codec->mixers, sizeof(struct snd_kcontrol *), 32);
+       snd_array_init(&codec->mixers, sizeof(struct hda_nid_item), 60);
        snd_array_init(&codec->init_pins, sizeof(struct hda_pincfg), 16);
        snd_array_init(&codec->driver_pins, sizeof(struct hda_pincfg), 16);
        if (codec->bus->modelname) {
@@ -1026,6 +1067,15 @@ int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr
 }
 EXPORT_SYMBOL_HDA(snd_hda_codec_new);
 
+/**
+ * snd_hda_codec_configure - (Re-)configure the HD-audio codec
+ * @codec: the HDA codec
+ *
+ * Start parsing of the given codec tree and (re-)initialize the whole
+ * patch instance.
+ *
+ * Returns 0 if successful or a negative error code.
+ */
 int snd_hda_codec_configure(struct hda_codec *codec)
 {
        int err;
@@ -1088,6 +1138,11 @@ void snd_hda_codec_setup_stream(struct hda_codec *codec, hda_nid_t nid,
 }
 EXPORT_SYMBOL_HDA(snd_hda_codec_setup_stream);
 
+/**
+ * snd_hda_codec_cleanup_stream - clean up the codec for closing
+ * @codec: the CODEC to clean up
+ * @nid: the NID to clean up
+ */
 void snd_hda_codec_cleanup_stream(struct hda_codec *codec, hda_nid_t nid)
 {
        if (!nid)
@@ -1163,8 +1218,17 @@ get_alloc_amp_hash(struct hda_codec *codec, u32 key)
        return (struct hda_amp_info *)get_alloc_hash(&codec->amp_cache, key);
 }
 
-/*
- * query AMP capabilities for the given widget and direction
+/**
+ * query_amp_caps - query AMP capabilities
+ * @codec: the HD-auio codec
+ * @nid: the NID to query
+ * @direction: either #HDA_INPUT or #HDA_OUTPUT
+ *
+ * Query AMP capabilities for the given widget and direction.
+ * Returns the obtained capability bits.
+ *
+ * When cap bits have been already read, this doesn't read again but
+ * returns the cached value.
  */
 u32 query_amp_caps(struct hda_codec *codec, hda_nid_t nid, int direction)
 {
@@ -1187,6 +1251,19 @@ u32 query_amp_caps(struct hda_codec *codec, hda_nid_t nid, int direction)
 }
 EXPORT_SYMBOL_HDA(query_amp_caps);
 
+/**
+ * snd_hda_override_amp_caps - Override the AMP capabilities
+ * @codec: the CODEC to clean up
+ * @nid: the NID to clean up
+ * @direction: either #HDA_INPUT or #HDA_OUTPUT
+ * @caps: the capability bits to set
+ *
+ * Override the cached AMP caps bits value by the given one.
+ * This function is useful if the driver needs to adjust the AMP ranges,
+ * e.g. limit to 0dB, etc.
+ *
+ * Returns zero if successful or a negative error code.
+ */
 int snd_hda_override_amp_caps(struct hda_codec *codec, hda_nid_t nid, int dir,
                              unsigned int caps)
 {
@@ -1222,6 +1299,17 @@ static unsigned int read_pin_cap(struct hda_codec *codec, hda_nid_t nid)
        return snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP);
 }
 
+/**
+ * snd_hda_query_pin_caps - Query PIN capabilities
+ * @codec: the HD-auio codec
+ * @nid: the NID to query
+ *
+ * Query PIN capabilities for the given widget.
+ * Returns the obtained capability bits.
+ *
+ * When cap bits have been already read, this doesn't read again but
+ * returns the cached value.
+ */
 u32 snd_hda_query_pin_caps(struct hda_codec *codec, hda_nid_t nid)
 {
        return query_caps_hash(codec, nid, HDA_HASH_PINCAP_KEY(nid),
@@ -1229,6 +1317,40 @@ u32 snd_hda_query_pin_caps(struct hda_codec *codec, hda_nid_t nid)
 }
 EXPORT_SYMBOL_HDA(snd_hda_query_pin_caps);
 
+/**
+ * snd_hda_pin_sense - execute pin sense measurement
+ * @codec: the CODEC to sense
+ * @nid: the pin NID to sense
+ *
+ * Execute necessary pin sense measurement and return its Presence Detect,
+ * Impedance, ELD Valid etc. status bits.
+ */
+u32 snd_hda_pin_sense(struct hda_codec *codec, hda_nid_t nid)
+{
+       u32 pincap = snd_hda_query_pin_caps(codec, nid);
+
+       if (pincap & AC_PINCAP_TRIG_REQ) /* need trigger? */
+               snd_hda_codec_read(codec, nid, 0, AC_VERB_SET_PIN_SENSE, 0);
+
+       return snd_hda_codec_read(codec, nid, 0,
+                                 AC_VERB_GET_PIN_SENSE, 0);
+}
+EXPORT_SYMBOL_HDA(snd_hda_pin_sense);
+
+/**
+ * snd_hda_jack_detect - query pin Presence Detect status
+ * @codec: the CODEC to sense
+ * @nid: the pin NID to sense
+ *
+ * Query and return the pin's Presence Detect status.
+ */
+int snd_hda_jack_detect(struct hda_codec *codec, hda_nid_t nid)
+{
+        u32 sense = snd_hda_pin_sense(codec, nid);
+        return !!(sense & AC_PINSENSE_PRESENCE);
+}
+EXPORT_SYMBOL_HDA(snd_hda_jack_detect);
+
 /*
  * read the current volume to info
  * if the cache exists, read the cache value.
@@ -1269,8 +1391,15 @@ static void put_vol_mute(struct hda_codec *codec, struct hda_amp_info *info,
        info->vol[ch] = val;
 }
 
-/*
- * read AMP value.  The volume is between 0 to 0x7f, 0x80 = mute bit.
+/**
+ * snd_hda_codec_amp_read - Read AMP value
+ * @codec: HD-audio codec
+ * @nid: NID to read the AMP value
+ * @ch: channel (left=0 or right=1)
+ * @direction: #HDA_INPUT or #HDA_OUTPUT
+ * @index: the index value (only for input direction)
+ *
+ * Read AMP value.  The volume is between 0 to 0x7f, 0x80 = mute bit.
  */
 int snd_hda_codec_amp_read(struct hda_codec *codec, hda_nid_t nid, int ch,
                           int direction, int index)
@@ -1283,8 +1412,18 @@ int snd_hda_codec_amp_read(struct hda_codec *codec, hda_nid_t nid, int ch,
 }
 EXPORT_SYMBOL_HDA(snd_hda_codec_amp_read);
 
-/*
- * update the AMP value, mask = bit mask to set, val = the value
+/**
+ * snd_hda_codec_amp_update - update the AMP value
+ * @codec: HD-audio codec
+ * @nid: NID to read the AMP value
+ * @ch: channel (left=0 or right=1)
+ * @direction: #HDA_INPUT or #HDA_OUTPUT
+ * @idx: the index value (only for input direction)
+ * @mask: bit mask to set
+ * @val: the bits value to set
+ *
+ * Update the AMP value with a bit mask.
+ * Returns 0 if the value is unchanged, 1 if changed.
  */
 int snd_hda_codec_amp_update(struct hda_codec *codec, hda_nid_t nid, int ch,
                             int direction, int idx, int mask, int val)
@@ -1303,8 +1442,17 @@ int snd_hda_codec_amp_update(struct hda_codec *codec, hda_nid_t nid, int ch,
 }
 EXPORT_SYMBOL_HDA(snd_hda_codec_amp_update);
 
-/*
- * update the AMP stereo with the same mask and value
+/**
+ * snd_hda_codec_amp_stereo - update the AMP stereo values
+ * @codec: HD-audio codec
+ * @nid: NID to read the AMP value
+ * @direction: #HDA_INPUT or #HDA_OUTPUT
+ * @idx: the index value (only for input direction)
+ * @mask: bit mask to set
+ * @val: the bits value to set
+ *
+ * Update the AMP values like snd_hda_codec_amp_update(), but for a
+ * stereo widget with the same mask and value.
  */
 int snd_hda_codec_amp_stereo(struct hda_codec *codec, hda_nid_t nid,
                             int direction, int idx, int mask, int val)
@@ -1318,7 +1466,12 @@ int snd_hda_codec_amp_stereo(struct hda_codec *codec, hda_nid_t nid,
 EXPORT_SYMBOL_HDA(snd_hda_codec_amp_stereo);
 
 #ifdef SND_HDA_NEEDS_RESUME
-/* resume the all amp commands from the cache */
+/**
+ * snd_hda_codec_resume_amp - Resume all AMP commands from the cache
+ * @codec: HD-audio codec
+ *
+ * Resume the all amp commands from the cache.
+ */
 void snd_hda_codec_resume_amp(struct hda_codec *codec)
 {
        struct hda_amp_info *buffer = codec->amp_cache.buf.list;
@@ -1344,7 +1497,12 @@ void snd_hda_codec_resume_amp(struct hda_codec *codec)
 EXPORT_SYMBOL_HDA(snd_hda_codec_resume_amp);
 #endif /* SND_HDA_NEEDS_RESUME */
 
-/* volume */
+/**
+ * snd_hda_mixer_amp_volume_info - Info callback for a standard AMP mixer
+ *
+ * The control element is supposed to have the private_value field
+ * set up via HDA_COMPOSE_AMP_VAL*() or related macros.
+ */
 int snd_hda_mixer_amp_volume_info(struct snd_kcontrol *kcontrol,
                                  struct snd_ctl_elem_info *uinfo)
 {
@@ -1400,6 +1558,12 @@ update_amp_value(struct hda_codec *codec, hda_nid_t nid,
                                        HDA_AMP_VOLMASK, val);
 }
 
+/**
+ * snd_hda_mixer_amp_volume_get - Get callback for a standard AMP mixer volume
+ *
+ * The control element is supposed to have the private_value field
+ * set up via HDA_COMPOSE_AMP_VAL*() or related macros.
+ */
 int snd_hda_mixer_amp_volume_get(struct snd_kcontrol *kcontrol,
                                 struct snd_ctl_elem_value *ucontrol)
 {
@@ -1419,6 +1583,12 @@ int snd_hda_mixer_amp_volume_get(struct snd_kcontrol *kcontrol,
 }
 EXPORT_SYMBOL_HDA(snd_hda_mixer_amp_volume_get);
 
+/**
+ * snd_hda_mixer_amp_volume_put - Put callback for a standard AMP mixer volume
+ *
+ * The control element is supposed to have the private_value field
+ * set up via HDA_COMPOSE_AMP_VAL*() or related macros.
+ */
 int snd_hda_mixer_amp_volume_put(struct snd_kcontrol *kcontrol,
                                 struct snd_ctl_elem_value *ucontrol)
 {
@@ -1443,6 +1613,12 @@ int snd_hda_mixer_amp_volume_put(struct snd_kcontrol *kcontrol,
 }
 EXPORT_SYMBOL_HDA(snd_hda_mixer_amp_volume_put);
 
+/**
+ * snd_hda_mixer_amp_volume_put - TLV callback for a standard AMP mixer volume
+ *
+ * The control element is supposed to have the private_value field
+ * set up via HDA_COMPOSE_AMP_VAL*() or related macros.
+ */
 int snd_hda_mixer_amp_tlv(struct snd_kcontrol *kcontrol, int op_flag,
                          unsigned int size, unsigned int __user *_tlv)
 {
@@ -1472,8 +1648,16 @@ int snd_hda_mixer_amp_tlv(struct snd_kcontrol *kcontrol, int op_flag,
 }
 EXPORT_SYMBOL_HDA(snd_hda_mixer_amp_tlv);
 
-/*
- * set (static) TLV for virtual master volume; recalculated as max 0dB
+/**
+ * snd_hda_set_vmaster_tlv - Set TLV for a virtual master control
+ * @codec: HD-audio codec
+ * @nid: NID of a reference widget
+ * @dir: #HDA_INPUT or #HDA_OUTPUT
+ * @tlv: TLV data to be stored, at least 4 elements
+ *
+ * Set (static) TLV data for a virtual master volume using the AMP caps
+ * obtained from the reference NID.
+ * The volume range is recalculated as if the max volume is 0dB.
  */
 void snd_hda_set_vmaster_tlv(struct hda_codec *codec, hda_nid_t nid, int dir,
                             unsigned int *tlv)
@@ -1507,6 +1691,13 @@ _snd_hda_find_mixer_ctl(struct hda_codec *codec,
        return snd_ctl_find_id(codec->bus->card, &id);
 }
 
+/**
+ * snd_hda_find_mixer_ctl - Find a mixer control element with the given name
+ * @codec: HD-audio codec
+ * @name: ctl id name string
+ *
+ * Get the control element with the given id string and IFACE_MIXER.
+ */
 struct snd_kcontrol *snd_hda_find_mixer_ctl(struct hda_codec *codec,
                                            const char *name)
 {
@@ -1514,30 +1705,57 @@ struct snd_kcontrol *snd_hda_find_mixer_ctl(struct hda_codec *codec,
 }
 EXPORT_SYMBOL_HDA(snd_hda_find_mixer_ctl);
 
-/* Add a control element and assign to the codec */
-int snd_hda_ctl_add(struct hda_codec *codec, struct snd_kcontrol *kctl)
+/**
+ * snd_hda_ctl-add - Add a control element and assign to the codec
+ * @codec: HD-audio codec
+ * @nid: corresponding NID (optional)
+ * @kctl: the control element to assign
+ *
+ * Add the given control element to an array inside the codec instance.
+ * All control elements belonging to a codec are supposed to be added
+ * by this function so that a proper clean-up works at the free or
+ * reconfiguration time.
+ *
+ * If non-zero @nid is passed, the NID is assigned to the control element.
+ * The assignment is shown in the codec proc file.
+ *
+ * snd_hda_ctl_add() checks the control subdev id field whether
+ * #HDA_SUBDEV_NID_FLAG bit is set.  If set (and @nid is zero), the lower
+ * bits value is taken as the NID to assign.
+ */
+int snd_hda_ctl_add(struct hda_codec *codec, hda_nid_t nid,
+                   struct snd_kcontrol *kctl)
 {
        int err;
-       struct snd_kcontrol **knewp;
+       struct hda_nid_item *item;
 
+       if (kctl->id.subdevice & HDA_SUBDEV_NID_FLAG) {
+               if (nid == 0)
+                       nid = kctl->id.subdevice & 0xffff;
+               kctl->id.subdevice = 0;
+       }
        err = snd_ctl_add(codec->bus->card, kctl);
        if (err < 0)
                return err;
-       knewp = snd_array_new(&codec->mixers);
-       if (!knewp)
+       item = snd_array_new(&codec->mixers);
+       if (!item)
                return -ENOMEM;
-       *knewp = kctl;
+       item->kctl = kctl;
+       item->nid = nid;
        return 0;
 }
 EXPORT_SYMBOL_HDA(snd_hda_ctl_add);
 
-/* Clear all controls assigned to the given codec */
+/**
+ * snd_hda_ctls_clear - Clear all controls assigned to the given codec
+ * @codec: HD-audio codec
+ */
 void snd_hda_ctls_clear(struct hda_codec *codec)
 {
        int i;
-       struct snd_kcontrol **kctls = codec->mixers.list;
+       struct hda_nid_item *items = codec->mixers.list;
        for (i = 0; i < codec->mixers.used; i++)
-               snd_ctl_remove(codec->bus->card, kctls[i]);
+               snd_ctl_remove(codec->bus->card, items[i].kctl);
        snd_array_free(&codec->mixers);
 }
 
@@ -1563,6 +1781,16 @@ static void hda_unlock_devices(struct snd_card *card)
        spin_unlock(&card->files_lock);
 }
 
+/**
+ * snd_hda_codec_reset - Clear all objects assigned to the codec
+ * @codec: HD-audio codec
+ *
+ * This frees the all PCM and control elements assigned to the codec, and
+ * clears the caches and restores the pin default configurations.
+ *
+ * When a device is being used, it returns -EBSY.  If successfully freed,
+ * returns zero.
+ */
 int snd_hda_codec_reset(struct hda_codec *codec)
 {
        struct snd_card *card = codec->bus->card;
@@ -1626,7 +1854,22 @@ int snd_hda_codec_reset(struct hda_codec *codec)
        return 0;
 }
 
-/* create a virtual master control and add slaves */
+/**
+ * snd_hda_add_vmaster - create a virtual master control and add slaves
+ * @codec: HD-audio codec
+ * @name: vmaster control name
+ * @tlv: TLV data (optional)
+ * @slaves: slave control names (optional)
+ *
+ * Create a virtual master control with the given name.  The TLV data
+ * must be either NULL or a valid data.
+ *
+ * @slaves is a NULL-terminated array of strings, each of which is a
+ * slave control name.  All controls with these names are assigned to
+ * the new virtual master control.
+ *
+ * This function returns zero if successful or a negative error code.
+ */
 int snd_hda_add_vmaster(struct hda_codec *codec, char *name,
                        unsigned int *tlv, const char **slaves)
 {
@@ -1643,7 +1886,7 @@ int snd_hda_add_vmaster(struct hda_codec *codec, char *name,
        kctl = snd_ctl_make_virtual_master(name, tlv);
        if (!kctl)
                return -ENOMEM;
-       err = snd_hda_ctl_add(codec, kctl);
+       err = snd_hda_ctl_add(codec, 0, kctl);
        if (err < 0)
                return err;
        
@@ -1668,7 +1911,12 @@ int snd_hda_add_vmaster(struct hda_codec *codec, char *name,
 }
 EXPORT_SYMBOL_HDA(snd_hda_add_vmaster);
 
-/* switch */
+/**
+ * snd_hda_mixer_amp_switch_info - Info callback for a standard AMP mixer switch
+ *
+ * The control element is supposed to have the private_value field
+ * set up via HDA_COMPOSE_AMP_VAL*() or related macros.
+ */
 int snd_hda_mixer_amp_switch_info(struct snd_kcontrol *kcontrol,
                                  struct snd_ctl_elem_info *uinfo)
 {
@@ -1682,6 +1930,12 @@ int snd_hda_mixer_amp_switch_info(struct snd_kcontrol *kcontrol,
 }
 EXPORT_SYMBOL_HDA(snd_hda_mixer_amp_switch_info);
 
+/**
+ * snd_hda_mixer_amp_switch_get - Get callback for a standard AMP mixer switch
+ *
+ * The control element is supposed to have the private_value field
+ * set up via HDA_COMPOSE_AMP_VAL*() or related macros.
+ */
 int snd_hda_mixer_amp_switch_get(struct snd_kcontrol *kcontrol,
                                 struct snd_ctl_elem_value *ucontrol)
 {
@@ -1702,6 +1956,12 @@ int snd_hda_mixer_amp_switch_get(struct snd_kcontrol *kcontrol,
 }
 EXPORT_SYMBOL_HDA(snd_hda_mixer_amp_switch_get);
 
+/**
+ * snd_hda_mixer_amp_switch_put - Put callback for a standard AMP mixer switch
+ *
+ * The control element is supposed to have the private_value field
+ * set up via HDA_COMPOSE_AMP_VAL*() or related macros.
+ */
 int snd_hda_mixer_amp_switch_put(struct snd_kcontrol *kcontrol,
                                 struct snd_ctl_elem_value *ucontrol)
 {
@@ -1733,6 +1993,25 @@ int snd_hda_mixer_amp_switch_put(struct snd_kcontrol *kcontrol,
 }
 EXPORT_SYMBOL_HDA(snd_hda_mixer_amp_switch_put);
 
+#ifdef CONFIG_SND_HDA_INPUT_BEEP
+/**
+ * snd_hda_mixer_amp_switch_put_beep - Put callback for a beep AMP switch
+ *
+ * This function calls snd_hda_enable_beep_device(), which behaves differently
+ * depending on beep_mode option.
+ */
+int snd_hda_mixer_amp_switch_put_beep(struct snd_kcontrol *kcontrol,
+                                     struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       long *valp = ucontrol->value.integer.value;
+
+       snd_hda_enable_beep_device(codec, *valp);
+       return snd_hda_mixer_amp_switch_put(kcontrol, ucontrol);
+}
+EXPORT_SYMBOL_HDA(snd_hda_mixer_amp_switch_put_beep);
+#endif /* CONFIG_SND_HDA_INPUT_BEEP */
+
 /*
  * bound volume controls
  *
@@ -1742,6 +2021,12 @@ EXPORT_SYMBOL_HDA(snd_hda_mixer_amp_switch_put);
 #define AMP_VAL_IDX_SHIFT      19
 #define AMP_VAL_IDX_MASK       (0x0f<<19)
 
+/**
+ * snd_hda_mixer_bind_switch_get - Get callback for a bound volume control
+ *
+ * The control element is supposed to have the private_value field
+ * set up via HDA_BIND_MUTE*() macros.
+ */
 int snd_hda_mixer_bind_switch_get(struct snd_kcontrol *kcontrol,
                                  struct snd_ctl_elem_value *ucontrol)
 {
@@ -1759,6 +2044,12 @@ int snd_hda_mixer_bind_switch_get(struct snd_kcontrol *kcontrol,
 }
 EXPORT_SYMBOL_HDA(snd_hda_mixer_bind_switch_get);
 
+/**
+ * snd_hda_mixer_bind_switch_put - Put callback for a bound volume control
+ *
+ * The control element is supposed to have the private_value field
+ * set up via HDA_BIND_MUTE*() macros.
+ */
 int snd_hda_mixer_bind_switch_put(struct snd_kcontrol *kcontrol,
                                  struct snd_ctl_elem_value *ucontrol)
 {
@@ -1783,8 +2074,11 @@ int snd_hda_mixer_bind_switch_put(struct snd_kcontrol *kcontrol,
 }
 EXPORT_SYMBOL_HDA(snd_hda_mixer_bind_switch_put);
 
-/*
- * generic bound volume/swtich controls
+/**
+ * snd_hda_mixer_bind_ctls_info - Info callback for a generic bound control
+ *
+ * The control element is supposed to have the private_value field
+ * set up via HDA_BIND_VOL() or HDA_BIND_SW() macros.
  */
 int snd_hda_mixer_bind_ctls_info(struct snd_kcontrol *kcontrol,
                                 struct snd_ctl_elem_info *uinfo)
@@ -1803,6 +2097,12 @@ int snd_hda_mixer_bind_ctls_info(struct snd_kcontrol *kcontrol,
 }
 EXPORT_SYMBOL_HDA(snd_hda_mixer_bind_ctls_info);
 
+/**
+ * snd_hda_mixer_bind_ctls_get - Get callback for a generic bound control
+ *
+ * The control element is supposed to have the private_value field
+ * set up via HDA_BIND_VOL() or HDA_BIND_SW() macros.
+ */
 int snd_hda_mixer_bind_ctls_get(struct snd_kcontrol *kcontrol,
                                struct snd_ctl_elem_value *ucontrol)
 {
@@ -1820,6 +2120,12 @@ int snd_hda_mixer_bind_ctls_get(struct snd_kcontrol *kcontrol,
 }
 EXPORT_SYMBOL_HDA(snd_hda_mixer_bind_ctls_get);
 
+/**
+ * snd_hda_mixer_bind_ctls_put - Put callback for a generic bound control
+ *
+ * The control element is supposed to have the private_value field
+ * set up via HDA_BIND_VOL() or HDA_BIND_SW() macros.
+ */
 int snd_hda_mixer_bind_ctls_put(struct snd_kcontrol *kcontrol,
                                struct snd_ctl_elem_value *ucontrol)
 {
@@ -1843,6 +2149,12 @@ int snd_hda_mixer_bind_ctls_put(struct snd_kcontrol *kcontrol,
 }
 EXPORT_SYMBOL_HDA(snd_hda_mixer_bind_ctls_put);
 
+/**
+ * snd_hda_mixer_bind_tlv - TLV callback for a generic bound control
+ *
+ * The control element is supposed to have the private_value field
+ * set up via HDA_BIND_VOL() macro.
+ */
 int snd_hda_mixer_bind_tlv(struct snd_kcontrol *kcontrol, int op_flag,
                           unsigned int size, unsigned int __user *tlv)
 {
@@ -2126,7 +2438,7 @@ int snd_hda_create_spdif_out_ctls(struct hda_codec *codec, hda_nid_t nid)
                        return -ENOMEM;
                kctl->id.index = idx;
                kctl->private_value = nid;
-               err = snd_hda_ctl_add(codec, kctl);
+               err = snd_hda_ctl_add(codec, nid, kctl);
                if (err < 0)
                        return err;
        }
@@ -2165,14 +2477,19 @@ static struct snd_kcontrol_new spdif_share_sw = {
        .put = spdif_share_sw_put,
 };
 
+/**
+ * snd_hda_create_spdif_share_sw - create Default PCM switch
+ * @codec: the HDA codec
+ * @mout: multi-out instance
+ */
 int snd_hda_create_spdif_share_sw(struct hda_codec *codec,
                                  struct hda_multi_out *mout)
 {
        if (!mout->dig_out_nid)
                return 0;
        /* ATTENTION: here mout is passed as private_data, instead of codec */
-       return snd_hda_ctl_add(codec,
-                          snd_ctl_new1(&spdif_share_sw, mout));
+       return snd_hda_ctl_add(codec, mout->dig_out_nid,
+                             snd_ctl_new1(&spdif_share_sw, mout));
 }
 EXPORT_SYMBOL_HDA(snd_hda_create_spdif_share_sw);
 
@@ -2276,7 +2593,7 @@ int snd_hda_create_spdif_in_ctls(struct hda_codec *codec, hda_nid_t nid)
                if (!kctl)
                        return -ENOMEM;
                kctl->private_value = nid;
-               err = snd_hda_ctl_add(codec, kctl);
+               err = snd_hda_ctl_add(codec, nid, kctl);
                if (err < 0)
                        return err;
        }
@@ -2332,7 +2649,12 @@ int snd_hda_codec_write_cache(struct hda_codec *codec, hda_nid_t nid,
 }
 EXPORT_SYMBOL_HDA(snd_hda_codec_write_cache);
 
-/* resume the all commands from the cache */
+/**
+ * snd_hda_codec_resume_cache - Resume the all commands from the cache
+ * @codec: HD-audio codec
+ *
+ * Execute all verbs recorded in the command caches to resume.
+ */
 void snd_hda_codec_resume_cache(struct hda_codec *codec)
 {
        struct hda_cache_head *buffer = codec->cmd_cache.buf.list;
@@ -2452,9 +2774,11 @@ static void hda_call_codec_suspend(struct hda_codec *codec)
                            codec->afg ? codec->afg : codec->mfg,
                            AC_PWRST_D3);
 #ifdef CONFIG_SND_HDA_POWER_SAVE
+       snd_hda_update_power_acct(codec);
        cancel_delayed_work(&codec->power_work);
        codec->power_on = 0;
        codec->power_transition = 0;
+       codec->power_jiffies = jiffies;
 #endif
 }
 
@@ -2756,8 +3080,12 @@ static int snd_hda_query_supported_pcm(struct hda_codec *codec, hda_nid_t nid,
 }
 
 /**
- * snd_hda_is_supported_format - check whether the given node supports
- * the format val
+ * snd_hda_is_supported_format - Check the validity of the format
+ * @codec: HD-audio codec
+ * @nid: NID to check
+ * @format: the HD-audio format value to check
+ *
+ * Check whether the given node supports the format value.
  *
  * Returns 1 if supported, 0 if not.
  */
@@ -2877,51 +3205,36 @@ static int set_pcm_default_values(struct hda_codec *codec,
        return 0;
 }
 
+/* global */
+const char *snd_hda_pcm_type_name[HDA_PCM_NTYPES] = {
+       "Audio", "SPDIF", "HDMI", "Modem"
+};
+
 /*
  * get the empty PCM device number to assign
  */
 static int get_empty_pcm_device(struct hda_bus *bus, int type)
 {
-       static const char *dev_name[HDA_PCM_NTYPES] = {
-               "Audio", "SPDIF", "HDMI", "Modem"
-       };
-       /* starting device index for each PCM type */
-       static int dev_idx[HDA_PCM_NTYPES] = {
-               [HDA_PCM_TYPE_AUDIO] = 0,
-               [HDA_PCM_TYPE_SPDIF] = 1,
-               [HDA_PCM_TYPE_HDMI] = 3,
-               [HDA_PCM_TYPE_MODEM] = 6
+       /* audio device indices; not linear to keep compatibility */
+       static int audio_idx[HDA_PCM_NTYPES][5] = {
+               [HDA_PCM_TYPE_AUDIO] = { 0, 2, 4, 5, -1 },
+               [HDA_PCM_TYPE_SPDIF] = { 1, -1 },
+               [HDA_PCM_TYPE_HDMI]  = { 3, 7, 8, 9, -1 },
+               [HDA_PCM_TYPE_MODEM] = { 6, -1 },
        };
-       /* normal audio device indices; not linear to keep compatibility */
-       static int audio_idx[4] = { 0, 2, 4, 5 };
-       int i, dev;
-
-       switch (type) {
-       case HDA_PCM_TYPE_AUDIO:
-               for (i = 0; i < ARRAY_SIZE(audio_idx); i++) {
-                       dev = audio_idx[i];
-                       if (!test_bit(dev, bus->pcm_dev_bits))
-                               goto ok;
-               }
-               snd_printk(KERN_WARNING "Too many audio devices\n");
-               return -EAGAIN;
-       case HDA_PCM_TYPE_SPDIF:
-       case HDA_PCM_TYPE_HDMI:
-       case HDA_PCM_TYPE_MODEM:
-               dev = dev_idx[type];
-               if (test_bit(dev, bus->pcm_dev_bits)) {
-                       snd_printk(KERN_WARNING "%s already defined\n",
-                                  dev_name[type]);
-                       return -EAGAIN;
-               }
-               break;
-       default:
+       int i;
+
+       if (type >= HDA_PCM_NTYPES) {
                snd_printk(KERN_WARNING "Invalid PCM type %d\n", type);
                return -EINVAL;
        }
- ok:
-       set_bit(dev, bus->pcm_dev_bits);
-       return dev;
+
+       for (i = 0; audio_idx[type][i] >= 0 ; i++)
+               if (!test_and_set_bit(audio_idx[type][i], bus->pcm_dev_bits))
+                       return audio_idx[type][i];
+
+       snd_printk(KERN_WARNING "Too many %s devices\n", snd_hda_pcm_type_name[type]);
+       return -EAGAIN;
 }
 
 /*
@@ -3159,14 +3472,14 @@ EXPORT_SYMBOL_HDA(snd_hda_check_board_codec_sid_config);
  */
 int snd_hda_add_new_ctls(struct hda_codec *codec, struct snd_kcontrol_new *knew)
 {
-       int err;
+       int err;
 
        for (; knew->name; knew++) {
                struct snd_kcontrol *kctl;
                kctl = snd_ctl_new1(knew, codec);
                if (!kctl)
                        return -ENOMEM;
-               err = snd_hda_ctl_add(codec, kctl);
+               err = snd_hda_ctl_add(codec, 0, kctl);
                if (err < 0) {
                        if (!codec->addr)
                                return err;
@@ -3174,7 +3487,7 @@ int snd_hda_add_new_ctls(struct hda_codec *codec, struct snd_kcontrol_new *knew)
                        if (!kctl)
                                return -ENOMEM;
                        kctl->id.device = codec->addr;
-                       err = snd_hda_ctl_add(codec, kctl);
+                       err = snd_hda_ctl_add(codec, 0, kctl);
                        if (err < 0)
                                return err;
                }
@@ -3207,8 +3520,27 @@ static void hda_keep_power_on(struct hda_codec *codec)
 {
        codec->power_count++;
        codec->power_on = 1;
+       codec->power_jiffies = jiffies;
 }
 
+/* update the power on/off account with the current jiffies */
+void snd_hda_update_power_acct(struct hda_codec *codec)
+{
+       unsigned long delta = jiffies - codec->power_jiffies;
+       if (codec->power_on)
+               codec->power_on_acct += delta;
+       else
+               codec->power_off_acct += delta;
+       codec->power_jiffies += delta;
+}
+
+/**
+ * snd_hda_power_up - Power-up the codec
+ * @codec: HD-audio codec
+ *
+ * Increment the power-up counter and power up the hardware really when
+ * not turned on yet.
+ */ 
 void snd_hda_power_up(struct hda_codec *codec)
 {
        struct hda_bus *bus = codec->bus;
@@ -3217,7 +3549,9 @@ void snd_hda_power_up(struct hda_codec *codec)
        if (codec->power_on || codec->power_transition)
                return;
 
+       snd_hda_update_power_acct(codec);
        codec->power_on = 1;
+       codec->power_jiffies = jiffies;
        if (bus->ops.pm_notify)
                bus->ops.pm_notify(bus);
        hda_call_codec_resume(codec);
@@ -3229,9 +3563,13 @@ EXPORT_SYMBOL_HDA(snd_hda_power_up);
 #define power_save(codec)      \
        ((codec)->bus->power_save ? *(codec)->bus->power_save : 0)
 
-#define power_save(codec)      \
-       ((codec)->bus->power_save ? *(codec)->bus->power_save : 0)
-
+/**
+ * snd_hda_power_down - Power-down the codec
+ * @codec: HD-audio codec
+ *
+ * Decrement the power-up counter and schedules the power-off work if
+ * the counter rearches to zero.
+ */ 
 void snd_hda_power_down(struct hda_codec *codec)
 {
        --codec->power_count;
@@ -3245,6 +3583,19 @@ void snd_hda_power_down(struct hda_codec *codec)
 }
 EXPORT_SYMBOL_HDA(snd_hda_power_down);
 
+/**
+ * snd_hda_check_amp_list_power - Check the amp list and update the power
+ * @codec: HD-audio codec
+ * @check: the object containing an AMP list and the status
+ * @nid: NID to check / update
+ *
+ * Check whether the given NID is in the amp list.  If it's in the list,
+ * check the current AMP status, and update the the power-status according
+ * to the mute status.
+ *
+ * This function is supposed to be set or called from the check_power_status
+ * patch ops.
+ */ 
 int snd_hda_check_amp_list_power(struct hda_codec *codec,
                                 struct hda_loopback_check *check,
                                 hda_nid_t nid)
@@ -3286,6 +3637,10 @@ EXPORT_SYMBOL_HDA(snd_hda_check_amp_list_power);
 /*
  * Channel mode helper
  */
+
+/**
+ * snd_hda_ch_mode_info - Info callback helper for the channel mode enum
+ */
 int snd_hda_ch_mode_info(struct hda_codec *codec,
                         struct snd_ctl_elem_info *uinfo,
                         const struct hda_channel_mode *chmode,
@@ -3302,6 +3657,9 @@ int snd_hda_ch_mode_info(struct hda_codec *codec,
 }
 EXPORT_SYMBOL_HDA(snd_hda_ch_mode_info);
 
+/**
+ * snd_hda_ch_mode_get - Get callback helper for the channel mode enum
+ */
 int snd_hda_ch_mode_get(struct hda_codec *codec,
                        struct snd_ctl_elem_value *ucontrol,
                        const struct hda_channel_mode *chmode,
@@ -3320,6 +3678,9 @@ int snd_hda_ch_mode_get(struct hda_codec *codec,
 }
 EXPORT_SYMBOL_HDA(snd_hda_ch_mode_get);
 
+/**
+ * snd_hda_ch_mode_put - Put callback helper for the channel mode enum
+ */
 int snd_hda_ch_mode_put(struct hda_codec *codec,
                        struct snd_ctl_elem_value *ucontrol,
                        const struct hda_channel_mode *chmode,
@@ -3344,6 +3705,10 @@ EXPORT_SYMBOL_HDA(snd_hda_ch_mode_put);
 /*
  * input MUX helper
  */
+
+/**
+ * snd_hda_input_mux_info_info - Info callback helper for the input-mux enum
+ */
 int snd_hda_input_mux_info(const struct hda_input_mux *imux,
                           struct snd_ctl_elem_info *uinfo)
 {
@@ -3362,6 +3727,9 @@ int snd_hda_input_mux_info(const struct hda_input_mux *imux,
 }
 EXPORT_SYMBOL_HDA(snd_hda_input_mux_info);
 
+/**
+ * snd_hda_input_mux_info_put - Put callback helper for the input-mux enum
+ */
 int snd_hda_input_mux_put(struct hda_codec *codec,
                          const struct hda_input_mux *imux,
                          struct snd_ctl_elem_value *ucontrol,
@@ -3421,8 +3789,29 @@ static void cleanup_dig_out_stream(struct hda_codec *codec, hda_nid_t nid)
        }
 }
 
-/*
- * open the digital out in the exclusive mode
+/**
+ * snd_hda_bus_reboot_notify - call the reboot notifier of each codec
+ * @bus: HD-audio bus
+ */
+void snd_hda_bus_reboot_notify(struct hda_bus *bus)
+{
+       struct hda_codec *codec;
+
+       if (!bus)
+               return;
+       list_for_each_entry(codec, &bus->codec_list, list) {
+#ifdef CONFIG_SND_HDA_POWER_SAVE
+               if (!codec->power_on)
+                       continue;
+#endif
+               if (codec->patch_ops.reboot_notify)
+                       codec->patch_ops.reboot_notify(codec);
+       }
+}
+EXPORT_SYMBOL_HDA(snd_hda_bus_reboot_notify);
+
+/**
+ * snd_hda_multi_out_dig_open - open the digital out in the exclusive mode
  */
 int snd_hda_multi_out_dig_open(struct hda_codec *codec,
                               struct hda_multi_out *mout)
@@ -3437,6 +3826,9 @@ int snd_hda_multi_out_dig_open(struct hda_codec *codec,
 }
 EXPORT_SYMBOL_HDA(snd_hda_multi_out_dig_open);
 
+/**
+ * snd_hda_multi_out_dig_prepare - prepare the digital out stream
+ */
 int snd_hda_multi_out_dig_prepare(struct hda_codec *codec,
                                  struct hda_multi_out *mout,
                                  unsigned int stream_tag,
@@ -3450,6 +3842,9 @@ int snd_hda_multi_out_dig_prepare(struct hda_codec *codec,
 }
 EXPORT_SYMBOL_HDA(snd_hda_multi_out_dig_prepare);
 
+/**
+ * snd_hda_multi_out_dig_cleanup - clean-up the digital out stream
+ */
 int snd_hda_multi_out_dig_cleanup(struct hda_codec *codec,
                                  struct hda_multi_out *mout)
 {
@@ -3460,8 +3855,8 @@ int snd_hda_multi_out_dig_cleanup(struct hda_codec *codec,
 }
 EXPORT_SYMBOL_HDA(snd_hda_multi_out_dig_cleanup);
 
-/*
- * release the digital out
+/**
+ * snd_hda_multi_out_dig_close - release the digital out stream
  */
 int snd_hda_multi_out_dig_close(struct hda_codec *codec,
                                struct hda_multi_out *mout)
@@ -3473,8 +3868,12 @@ int snd_hda_multi_out_dig_close(struct hda_codec *codec,
 }
 EXPORT_SYMBOL_HDA(snd_hda_multi_out_dig_close);
 
-/*
- * set up more restrictions for analog out
+/**
+ * snd_hda_multi_out_analog_open - open analog outputs
+ *
+ * Open analog outputs and set up the hw-constraints.
+ * If the digital outputs can be opened as slave, open the digital
+ * outputs, too.
  */
 int snd_hda_multi_out_analog_open(struct hda_codec *codec,
                                  struct hda_multi_out *mout,
@@ -3519,9 +3918,11 @@ int snd_hda_multi_out_analog_open(struct hda_codec *codec,
 }
 EXPORT_SYMBOL_HDA(snd_hda_multi_out_analog_open);
 
-/*
- * set up the i/o for analog out
- * when the digital out is available, copy the front out to digital out, too.
+/**
+ * snd_hda_multi_out_analog_prepare - Preapre the analog outputs.
+ *
+ * Set up the i/o for analog out.
+ * When the digital out is available, copy the front out to digital out, too.
  */
 int snd_hda_multi_out_analog_prepare(struct hda_codec *codec,
                                     struct hda_multi_out *mout,
@@ -3578,8 +3979,8 @@ int snd_hda_multi_out_analog_prepare(struct hda_codec *codec,
 }
 EXPORT_SYMBOL_HDA(snd_hda_multi_out_analog_prepare);
 
-/*
- * clean up the setting for analog out
+/**
+ * snd_hda_multi_out_analog_cleanup - clean up the setting for analog out
  */
 int snd_hda_multi_out_analog_cleanup(struct hda_codec *codec,
                                     struct hda_multi_out *mout)
@@ -3965,8 +4366,14 @@ EXPORT_SYMBOL_HDA(snd_hda_resume);
  * generic arrays
  */
 
-/* get a new element from the given array
- * if it exceeds the pre-allocated array size, re-allocate the array
+/**
+ * snd_array_new - get a new element from the given array
+ * @array: the array object
+ * 
+ * Get a new element from the given array.  If it exceeds the
+ * pre-allocated array size, re-allocate the array.
+ *
+ * Returns NULL if allocation failed.
  */
 void *snd_array_new(struct snd_array *array)
 {
@@ -3990,7 +4397,10 @@ void *snd_array_new(struct snd_array *array)
 }
 EXPORT_SYMBOL_HDA(snd_array_new);
 
-/* free the given array elements */
+/**
+ * snd_array_free - free the given array elements
+ * @array: the array object
+ */
 void snd_array_free(struct snd_array *array)
 {
        kfree(array->list);
@@ -4000,7 +4410,12 @@ void snd_array_free(struct snd_array *array)
 }
 EXPORT_SYMBOL_HDA(snd_array_free);
 
-/*
+/**
+ * snd_print_pcm_rates - Print the supported PCM rates to the string buffer
+ * @pcm: PCM caps bits
+ * @buf: the string buffer to write
+ * @buflen: the max buffer length
+ *
  * used by hda_proc.c and hda_eld.c
  */
 void snd_print_pcm_rates(int pcm, char *buf, int buflen)
@@ -4019,6 +4434,14 @@ void snd_print_pcm_rates(int pcm, char *buf, int buflen)
 }
 EXPORT_SYMBOL_HDA(snd_print_pcm_rates);
 
+/**
+ * snd_print_pcm_bits - Print the supported PCM fmt bits to the string buffer
+ * @pcm: PCM caps bits
+ * @buf: the string buffer to write
+ * @buflen: the max buffer length
+ *
+ * used by hda_proc.c and hda_eld.c
+ */
 void snd_print_pcm_bits(int pcm, char *buf, int buflen)
 {
        static unsigned int bits[] = { 8, 16, 20, 24, 32 };
index 99552fb..2d62761 100644 (file)
@@ -286,6 +286,10 @@ enum {
 #define AC_PWRST_D1SUP                 (1<<1)
 #define AC_PWRST_D2SUP                 (1<<2)
 #define AC_PWRST_D3SUP                 (1<<3)
+#define AC_PWRST_D3COLDSUP             (1<<4)
+#define AC_PWRST_S3D3COLDSUP           (1<<29)
+#define AC_PWRST_CLKSTOP               (1<<30)
+#define AC_PWRST_EPSS                  (1U<<31)
 
 /* Power state values */
 #define AC_PWRST_SETTING               (0xf<<0)
@@ -674,6 +678,7 @@ struct hda_codec_ops {
 #ifdef CONFIG_SND_HDA_POWER_SAVE
        int (*check_power_status)(struct hda_codec *codec, hda_nid_t nid);
 #endif
+       void (*reboot_notify)(struct hda_codec *codec);
 };
 
 /* record for amp information cache */
@@ -771,6 +776,7 @@ struct hda_codec {
 
        /* beep device */
        struct hda_beep *beep;
+       unsigned int beep_mode;
 
        /* widget capabilities cache */
        unsigned int num_nodes;
@@ -811,6 +817,9 @@ struct hda_codec {
        unsigned int power_transition :1; /* power-state in transition */
        int power_count;        /* current (global) power refcount */
        struct delayed_work power_work; /* delayed task for powerdown */
+       unsigned long power_on_acct;
+       unsigned long power_off_acct;
+       unsigned long power_jiffies;
 #endif
 
        /* codec-specific additional proc output */
@@ -910,6 +919,7 @@ int snd_hda_is_supported_format(struct hda_codec *codec, hda_nid_t nid,
  * Misc
  */
 void snd_hda_get_codec_name(struct hda_codec *codec, char *name, int namelen);
+void snd_hda_bus_reboot_notify(struct hda_bus *bus);
 
 /*
  * power management
@@ -933,6 +943,7 @@ const char *snd_hda_get_jack_location(u32 cfg);
 void snd_hda_power_up(struct hda_codec *codec);
 void snd_hda_power_down(struct hda_codec *codec);
 #define snd_hda_codec_needs_resume(codec) codec->power_count
+void snd_hda_update_power_acct(struct hda_codec *codec);
 #else
 static inline void snd_hda_power_up(struct hda_codec *codec) {}
 static inline void snd_hda_power_down(struct hda_codec *codec) {}
index 9446a5a..4228f2f 100644 (file)
@@ -309,17 +309,12 @@ out_fail:
        return -EINVAL;
 }
 
-static int hdmi_present_sense(struct hda_codec *codec, hda_nid_t nid)
-{
-       return snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_PIN_SENSE, 0);
-}
-
 static int hdmi_eld_valid(struct hda_codec *codec, hda_nid_t nid)
 {
        int eldv;
        int present;
 
-       present = hdmi_present_sense(codec, nid);
+       present = snd_hda_pin_sense(codec, nid);
        eldv    = (present & AC_PINSENSE_ELDV);
        present = (present & AC_PINSENSE_PRESENCE);
 
@@ -477,6 +472,8 @@ static void hdmi_print_eld_info(struct snd_info_entry *entry,
                [4 ... 7] = "reserved"
        };
 
+       snd_iprintf(buffer, "monitor_present\t\t%d\n", e->monitor_present);
+       snd_iprintf(buffer, "eld_valid\t\t%d\n", e->eld_valid);
        snd_iprintf(buffer, "monitor_name\t\t%s\n", e->monitor_name);
        snd_iprintf(buffer, "connection_type\t\t%s\n",
                                eld_connection_type_names[e->conn_type]);
@@ -518,7 +515,11 @@ static void hdmi_write_eld_info(struct snd_info_entry *entry,
                 *      monitor_name manufacture_id product_id
                 *      eld_version edid_version
                 */
-               if (!strcmp(name, "connection_type"))
+               if (!strcmp(name, "monitor_present"))
+                       e->monitor_present = val;
+               else if (!strcmp(name, "eld_valid"))
+                       e->eld_valid = val;
+               else if (!strcmp(name, "connection_type"))
                        e->conn_type = val;
                else if (!strcmp(name, "port_id"))
                        e->port_id = val;
@@ -560,13 +561,14 @@ static void hdmi_write_eld_info(struct snd_info_entry *entry,
 }
 
 
-int snd_hda_eld_proc_new(struct hda_codec *codec, struct hdmi_eld *eld)
+int snd_hda_eld_proc_new(struct hda_codec *codec, struct hdmi_eld *eld,
+                        int index)
 {
        char name[32];
        struct snd_info_entry *entry;
        int err;
 
-       snprintf(name, sizeof(name), "eld#%d", codec->addr);
+       snprintf(name, sizeof(name), "eld#%d.%d", codec->addr, index);
        err = snd_card_proc_new(codec->bus->card, name, &entry);
        if (err < 0)
                return err;
index b36f6c5..092c6a7 100644 (file)
@@ -727,7 +727,8 @@ static int create_mixer(struct hda_codec *codec, struct hda_gnode *node,
                if (is_loopback)
                        add_input_loopback(codec, node->nid, HDA_INPUT, index);
                snd_printdd("[%s] NID=0x%x, DIR=IN, IDX=0x%x\n", name, node->nid, index);
-               err = snd_hda_ctl_add(codec, snd_ctl_new1(&knew, codec));
+               err = snd_hda_ctl_add(codec, node->nid,
+                                       snd_ctl_new1(&knew, codec));
                if (err < 0)
                        return err;
                created = 1;
@@ -737,7 +738,8 @@ static int create_mixer(struct hda_codec *codec, struct hda_gnode *node,
                if (is_loopback)
                        add_input_loopback(codec, node->nid, HDA_OUTPUT, 0);
                snd_printdd("[%s] NID=0x%x, DIR=OUT\n", name, node->nid);
-               err = snd_hda_ctl_add(codec, snd_ctl_new1(&knew, codec));
+               err = snd_hda_ctl_add(codec, node->nid,
+                                       snd_ctl_new1(&knew, codec));
                if (err < 0)
                        return err;
                created = 1;
@@ -751,7 +753,8 @@ static int create_mixer(struct hda_codec *codec, struct hda_gnode *node,
            (node->amp_in_caps & AC_AMPCAP_NUM_STEPS)) {
                knew = (struct snd_kcontrol_new)HDA_CODEC_VOLUME(name, node->nid, index, HDA_INPUT);
                snd_printdd("[%s] NID=0x%x, DIR=IN, IDX=0x%x\n", name, node->nid, index);
-               err = snd_hda_ctl_add(codec, snd_ctl_new1(&knew, codec));
+               err = snd_hda_ctl_add(codec, node->nid,
+                                       snd_ctl_new1(&knew, codec));
                if (err < 0)
                        return err;
                created = 1;
@@ -759,7 +762,8 @@ static int create_mixer(struct hda_codec *codec, struct hda_gnode *node,
                   (node->amp_out_caps & AC_AMPCAP_NUM_STEPS)) {
                knew = (struct snd_kcontrol_new)HDA_CODEC_VOLUME(name, node->nid, 0, HDA_OUTPUT);
                snd_printdd("[%s] NID=0x%x, DIR=OUT\n", name, node->nid);
-               err = snd_hda_ctl_add(codec, snd_ctl_new1(&knew, codec));
+               err = snd_hda_ctl_add(codec, node->nid,
+                                       snd_ctl_new1(&knew, codec));
                if (err < 0)
                        return err;
                created = 1;
@@ -857,7 +861,7 @@ static int build_input_controls(struct hda_codec *codec)
        }
 
        /* create input MUX if multiple sources are available */
-       err = snd_hda_ctl_add(codec, snd_ctl_new1(&cap_sel, codec));
+       err = snd_hda_ctl_add(codec, 0, snd_ctl_new1(&cap_sel, codec));
        if (err < 0)
                return err;
 
@@ -875,7 +879,8 @@ static int build_input_controls(struct hda_codec *codec)
                        HDA_CODEC_VOLUME(name, adc_node->nid,
                                         spec->input_mux.items[i].index,
                                         HDA_INPUT);
-               err = snd_hda_ctl_add(codec, snd_ctl_new1(&knew, codec));
+               err = snd_hda_ctl_add(codec, adc_node->nid,
+                                       snd_ctl_new1(&knew, codec));
                if (err < 0)
                        return err;
        }
index cc24e67..d243286 100644 (file)
@@ -154,6 +154,44 @@ int /*__devinit*/ snd_hda_create_hwdep(struct hda_codec *codec)
        return 0;
 }
 
+#ifdef CONFIG_SND_HDA_POWER_SAVE
+static ssize_t power_on_acct_show(struct device *dev,
+                                 struct device_attribute *attr,
+                                 char *buf)
+{
+       struct snd_hwdep *hwdep = dev_get_drvdata(dev);
+       struct hda_codec *codec = hwdep->private_data;
+       snd_hda_update_power_acct(codec);
+       return sprintf(buf, "%u\n", jiffies_to_msecs(codec->power_on_acct));
+}
+
+static ssize_t power_off_acct_show(struct device *dev,
+                                  struct device_attribute *attr,
+                                  char *buf)
+{
+       struct snd_hwdep *hwdep = dev_get_drvdata(dev);
+       struct hda_codec *codec = hwdep->private_data;
+       snd_hda_update_power_acct(codec);
+       return sprintf(buf, "%u\n", jiffies_to_msecs(codec->power_off_acct));
+}
+
+static struct device_attribute power_attrs[] = {
+       __ATTR_RO(power_on_acct),
+       __ATTR_RO(power_off_acct),
+};
+
+int snd_hda_hwdep_add_power_sysfs(struct hda_codec *codec)
+{
+       struct snd_hwdep *hwdep = codec->hwdep;
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(power_attrs); i++)
+               snd_add_device_sysfs_file(SNDRV_DEVICE_TYPE_HWDEP, hwdep->card,
+                                         hwdep->device, &power_attrs[i]);
+       return 0;
+}
+#endif /* CONFIG_SND_HDA_POWER_SAVE */
+
 #ifdef CONFIG_SND_HDA_RECONFIG
 
 /*
index 6517f58..d822bfc 100644 (file)
@@ -60,10 +60,14 @@ static int bdl_pos_adj[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = -1};
 static int probe_mask[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = -1};
 static int probe_only[SNDRV_CARDS];
 static int single_cmd;
-static int enable_msi;
+static int enable_msi = -1;
 #ifdef CONFIG_SND_HDA_PATCH_LOADER
 static char *patch[SNDRV_CARDS];
 #endif
+#ifdef CONFIG_SND_HDA_INPUT_BEEP
+static int beep_mode[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] =
+                                       CONFIG_SND_HDA_INPUT_BEEP_MODE};
+#endif
 
 module_param_array(index, int, NULL, 0444);
 MODULE_PARM_DESC(index, "Index value for Intel HD audio interface.");
@@ -91,6 +95,11 @@ MODULE_PARM_DESC(enable_msi, "Enable Message Signaled Interrupt (MSI)");
 module_param_array(patch, charp, NULL, 0444);
 MODULE_PARM_DESC(patch, "Patch file for Intel HD audio interface.");
 #endif
+#ifdef CONFIG_SND_HDA_INPUT_BEEP
+module_param_array(beep_mode, int, NULL, 0444);
+MODULE_PARM_DESC(beep_mode, "Select HDA Beep registration mode "
+                           "(0=off, 1=on, 2=mute switch on/off) (default=1).");
+#endif
 
 #ifdef CONFIG_SND_HDA_POWER_SAVE
 static int power_save = CONFIG_SND_HDA_POWER_SAVE_DEFAULT;
@@ -404,6 +413,7 @@ struct azx {
        unsigned short codec_mask;
        int  codec_probe_mask; /* copied from probe_mask option */
        struct hda_bus *bus;
+       unsigned int beep_mode;
 
        /* CORB/RIRB */
        struct azx_rb corb;
@@ -677,6 +687,14 @@ static unsigned int azx_rirb_get_response(struct hda_bus *bus,
                }
        }
 
+       if (!chip->polling_mode) {
+               snd_printk(KERN_WARNING SFX "azx_get_response timeout, "
+                          "switching to polling mode: last cmd=0x%08x\n",
+                          chip->last_cmd[addr]);
+               chip->polling_mode = 1;
+               goto again;
+       }
+
        if (chip->msi) {
                snd_printk(KERN_WARNING SFX "No response from codec, "
                           "disabling MSI: last cmd=0x%08x\n",
@@ -692,14 +710,6 @@ static unsigned int azx_rirb_get_response(struct hda_bus *bus,
                goto again;
        }
 
-       if (!chip->polling_mode) {
-               snd_printk(KERN_WARNING SFX "azx_get_response timeout, "
-                          "switching to polling mode: last cmd=0x%08x\n",
-                          chip->last_cmd[addr]);
-               chip->polling_mode = 1;
-               goto again;
-       }
-
        if (chip->probing) {
                /* If this critical timeout happens during the codec probing
                 * phase, this is likely an access to a non-existing codec
@@ -1404,6 +1414,7 @@ static int __devinit azx_codec_create(struct azx *chip, const char *model)
                        err = snd_hda_codec_new(chip->bus, c, &codec);
                        if (err < 0)
                                continue;
+                       codec->beep_mode = chip->beep_mode;
                        codecs++;
                }
        }
@@ -2154,6 +2165,7 @@ static int azx_resume(struct pci_dev *pci)
 static int azx_halt(struct notifier_block *nb, unsigned long event, void *buf)
 {
        struct azx *chip = container_of(nb, struct azx, reboot_notifier);
+       snd_hda_bus_reboot_notify(chip->bus);
        azx_stop_chip(chip);
        return NOTIFY_OK;
 }
@@ -2221,7 +2233,9 @@ static int azx_dev_free(struct snd_device *device)
 static struct snd_pci_quirk position_fix_list[] __devinitdata = {
        SND_PCI_QUIRK(0x1028, 0x01cc, "Dell D820", POS_FIX_LPIB),
        SND_PCI_QUIRK(0x1028, 0x01de, "Dell Precision 390", POS_FIX_LPIB),
+       SND_PCI_QUIRK(0x103c, 0x306d, "HP dv3", POS_FIX_LPIB),
        SND_PCI_QUIRK(0x1043, 0x813d, "ASUS P5AD2", POS_FIX_LPIB),
+       SND_PCI_QUIRK(0x1462, 0x1002, "MSI Wind U115", POS_FIX_LPIB),
        {}
 };
 
@@ -2304,11 +2318,9 @@ static void __devinit check_probe_mask(struct azx *chip, int dev)
 }
 
 /*
- * white-list for enable_msi
+ * white/black-list for enable_msi
  */
-static struct snd_pci_quirk msi_white_list[] __devinitdata = {
-       SND_PCI_QUIRK(0x103c, 0x30f7, "HP Pavilion dv4t-1300", 1),
-       SND_PCI_QUIRK(0x103c, 0x3607, "HP Compa CQ40", 1),
+static struct snd_pci_quirk msi_black_list[] __devinitdata = {
        {}
 };
 
@@ -2316,10 +2328,12 @@ static void __devinit check_msi(struct azx *chip)
 {
        const struct snd_pci_quirk *q;
 
-       chip->msi = enable_msi;
-       if (chip->msi)
+       if (enable_msi >= 0) {
+               chip->msi = !!enable_msi;
                return;
-       q = snd_pci_quirk_lookup(chip->pci, msi_white_list);
+       }
+       chip->msi = 1;  /* enable MSI as default */
+       q = snd_pci_quirk_lookup(chip->pci, msi_black_list);
        if (q) {
                printk(KERN_INFO
                       "hda_intel: msi for device %04x:%04x set to %d\n",
@@ -2578,6 +2592,10 @@ static int __devinit azx_probe(struct pci_dev *pci,
                goto out_free;
        card->private_data = chip;
 
+#ifdef CONFIG_SND_HDA_INPUT_BEEP
+       chip->beep_mode = beep_mode[dev];
+#endif
+
        /* create codec instances */
        err = azx_codec_create(chip, model[dev]);
        if (err < 0)
index 5f1dcc5..5778ae8 100644 (file)
 #ifndef __SOUND_HDA_LOCAL_H
 #define __SOUND_HDA_LOCAL_H
 
+/* We abuse kcontrol_new.subdev field to pass the NID corresponding to
+ * the given new control.  If id.subdev has a bit flag HDA_SUBDEV_NID_FLAG,
+ * snd_hda_ctl_add() takes the lower-bit subdev value as a valid NID.
+ * 
+ * Note that the subdevice field is cleared again before the real registration
+ * in snd_hda_ctl_add(), so that this value won't appear in the outside.
+ */
+#define HDA_SUBDEV_NID_FLAG    (1U << 31)
+
 /*
  * for mixer controls
  */
@@ -33,6 +42,7 @@
 /* mono volume with index (index=0,1,...) (channel=1,2) */
 #define HDA_CODEC_VOLUME_MONO_IDX(xname, xcidx, nid, channel, xindex, direction) \
        { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xcidx,  \
+         .subdevice = HDA_SUBDEV_NID_FLAG | (nid), \
          .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \
                    SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
                    SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK, \
@@ -53,6 +63,7 @@
 /* mono mute switch with index (index=0,1,...) (channel=1,2) */
 #define HDA_CODEC_MUTE_MONO_IDX(xname, xcidx, nid, channel, xindex, direction) \
        { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xcidx, \
+         .subdevice = HDA_SUBDEV_NID_FLAG | (nid), \
          .info = snd_hda_mixer_amp_switch_info, \
          .get = snd_hda_mixer_amp_switch_get, \
          .put = snd_hda_mixer_amp_switch_put, \
 /* stereo mute switch */
 #define HDA_CODEC_MUTE(xname, nid, xindex, direction) \
        HDA_CODEC_MUTE_MONO(xname, nid, 3, xindex, direction)
+#ifdef CONFIG_SND_HDA_INPUT_BEEP
+/* special beep mono mute switch with index (index=0,1,...) (channel=1,2) */
+#define HDA_CODEC_MUTE_BEEP_MONO_IDX(xname, xcidx, nid, channel, xindex, direction) \
+       { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xcidx, \
+         .subdevice = HDA_SUBDEV_NID_FLAG | (nid), \
+         .info = snd_hda_mixer_amp_switch_info, \
+         .get = snd_hda_mixer_amp_switch_get, \
+         .put = snd_hda_mixer_amp_switch_put_beep, \
+         .private_value = HDA_COMPOSE_AMP_VAL(nid, channel, xindex, direction) }
+#else
+/* no digital beep - just the standard one */
+#define HDA_CODEC_MUTE_BEEP_MONO_IDX(xname, xcidx, nid, ch, xidx, dir) \
+       HDA_CODEC_MUTE_MONO_IDX(xname, xcidx, nid, ch, xidx, dir)
+#endif /* CONFIG_SND_HDA_INPUT_BEEP */
+/* special beep mono mute switch */
+#define HDA_CODEC_MUTE_BEEP_MONO(xname, nid, channel, xindex, direction) \
+       HDA_CODEC_MUTE_BEEP_MONO_IDX(xname, 0, nid, channel, xindex, direction)
+/* special beep stereo mute switch */
+#define HDA_CODEC_MUTE_BEEP(xname, nid, xindex, direction) \
+       HDA_CODEC_MUTE_BEEP_MONO(xname, nid, 3, xindex, direction)
+
+extern const char *snd_hda_pcm_type_name[];
 
 int snd_hda_mixer_amp_volume_info(struct snd_kcontrol *kcontrol,
                                  struct snd_ctl_elem_info *uinfo);
@@ -81,6 +114,10 @@ int snd_hda_mixer_amp_switch_get(struct snd_kcontrol *kcontrol,
                                 struct snd_ctl_elem_value *ucontrol);
 int snd_hda_mixer_amp_switch_put(struct snd_kcontrol *kcontrol,
                                 struct snd_ctl_elem_value *ucontrol);
+#ifdef CONFIG_SND_HDA_INPUT_BEEP
+int snd_hda_mixer_amp_switch_put_beep(struct snd_kcontrol *kcontrol,
+                                     struct snd_ctl_elem_value *ucontrol);
+#endif
 /* lowlevel accessor with caching; use carefully */
 int snd_hda_codec_amp_read(struct hda_codec *codec, hda_nid_t nid, int ch,
                           int direction, int index);
@@ -424,8 +461,16 @@ u32 query_amp_caps(struct hda_codec *codec, hda_nid_t nid, int direction);
 int snd_hda_override_amp_caps(struct hda_codec *codec, hda_nid_t nid, int dir,
                              unsigned int caps);
 u32 snd_hda_query_pin_caps(struct hda_codec *codec, hda_nid_t nid);
+u32 snd_hda_pin_sense(struct hda_codec *codec, hda_nid_t nid);
+int snd_hda_jack_detect(struct hda_codec *codec, hda_nid_t nid);
 
-int snd_hda_ctl_add(struct hda_codec *codec, struct snd_kcontrol *kctl);
+struct hda_nid_item {
+       struct snd_kcontrol *kctl;
+       hda_nid_t nid;
+};
+
+int snd_hda_ctl_add(struct hda_codec *codec, hda_nid_t nid,
+                   struct snd_kcontrol *kctl);
 void snd_hda_ctls_clear(struct hda_codec *codec);
 
 /*
@@ -437,6 +482,15 @@ int snd_hda_create_hwdep(struct hda_codec *codec);
 static inline int snd_hda_create_hwdep(struct hda_codec *codec) { return 0; }
 #endif
 
+#if defined(CONFIG_SND_HDA_POWER_SAVE) && defined(CONFIG_SND_HDA_HWDEP)
+int snd_hda_hwdep_add_power_sysfs(struct hda_codec *codec);
+#else
+static inline int snd_hda_hwdep_add_power_sysfs(struct hda_codec *codec)
+{
+       return 0;
+}
+#endif
+
 #ifdef CONFIG_SND_HDA_RECONFIG
 int snd_hda_hwdep_add_sysfs(struct hda_codec *codec);
 #else
@@ -490,7 +544,8 @@ int snd_hda_check_amp_list_power(struct hda_codec *codec,
  * AMP control callbacks
  */
 /* retrieve parameters from private_value */
-#define get_amp_nid(kc)                ((kc)->private_value & 0xffff)
+#define get_amp_nid_(pv)       ((pv) & 0xffff)
+#define get_amp_nid(kc)                get_amp_nid_((kc)->private_value)
 #define get_amp_channels(kc)   (((kc)->private_value >> 16) & 0x3)
 #define get_amp_direction(kc)  (((kc)->private_value >> 18) & 0x1)
 #define get_amp_index(kc)      (((kc)->private_value >> 19) & 0xf)
@@ -516,9 +571,11 @@ struct cea_sad {
  * ELD: EDID Like Data
  */
 struct hdmi_eld {
+       bool    monitor_present;
+       bool    eld_valid;
        int     eld_size;
        int     baseline_len;
-       int     eld_ver;        /* (eld_ver == 0) indicates invalid ELD */
+       int     eld_ver;
        int     cea_edid_ver;
        char    monitor_name[ELD_MAX_MNL + 1];
        int     manufacture_id;
@@ -541,11 +598,13 @@ int snd_hdmi_get_eld(struct hdmi_eld *, struct hda_codec *, hda_nid_t);
 void snd_hdmi_show_eld(struct hdmi_eld *eld);
 
 #ifdef CONFIG_PROC_FS
-int snd_hda_eld_proc_new(struct hda_codec *codec, struct hdmi_eld *eld);
+int snd_hda_eld_proc_new(struct hda_codec *codec, struct hdmi_eld *eld,
+                        int index);
 void snd_hda_eld_proc_free(struct hda_codec *codec, struct hdmi_eld *eld);
 #else
 static inline int snd_hda_eld_proc_new(struct hda_codec *codec,
-                                      struct hdmi_eld *eld)
+                                      struct hdmi_eld *eld,
+                                      int index)
 {
        return 0;
 }
index 95f24e4..09476fc 100644 (file)
 #include "hda_codec.h"
 #include "hda_local.h"
 
+static char *bits_names(unsigned int bits, char *names[], int size)
+{
+       int i, n;
+       static char buf[128];
+
+       for (i = 0, n = 0; i < size; i++) {
+               if (bits & (1U<<i) && names[i])
+                       n += snprintf(buf + n, sizeof(buf) - n, " %s",
+                                     names[i]);
+       }
+       buf[n] = '\0';
+
+       return buf;
+}
+
 static const char *get_wid_type_name(unsigned int wid_value)
 {
        static char *names[16] = {
@@ -46,6 +61,41 @@ static const char *get_wid_type_name(unsigned int wid_value)
                return "UNKNOWN Widget";
 }
 
+static void print_nid_mixers(struct snd_info_buffer *buffer,
+                            struct hda_codec *codec, hda_nid_t nid)
+{
+       int i;
+       struct hda_nid_item *items = codec->mixers.list;
+       struct snd_kcontrol *kctl;
+       for (i = 0; i < codec->mixers.used; i++) {
+               if (items[i].nid == nid) {
+                       kctl = items[i].kctl;
+                       snd_iprintf(buffer,
+                         "  Control: name=\"%s\", index=%i, device=%i\n",
+                         kctl->id.name, kctl->id.index, kctl->id.device);
+               }
+       }
+}
+
+static void print_nid_pcms(struct snd_info_buffer *buffer,
+                          struct hda_codec *codec, hda_nid_t nid)
+{
+       int pcm, type;
+       struct hda_pcm *cpcm;
+       for (pcm = 0; pcm < codec->num_pcms; pcm++) {
+               cpcm = &codec->pcm_info[pcm];
+               for (type = 0; type < 2; type++) {
+                       if (cpcm->stream[type].nid != nid || cpcm->pcm == NULL)
+                               continue;
+                       snd_iprintf(buffer, "  Device: name=\"%s\", "
+                                   "type=\"%s\", device=%i\n",
+                                   cpcm->name,
+                                   snd_hda_pcm_type_name[cpcm->pcm_type],
+                                   cpcm->pcm->device);
+               }
+       }
+}
+
 static void print_amp_caps(struct snd_info_buffer *buffer,
                           struct hda_codec *codec, hda_nid_t nid, int dir)
 {
@@ -363,8 +413,24 @@ static const char *get_pwr_state(u32 state)
 static void print_power_state(struct snd_info_buffer *buffer,
                              struct hda_codec *codec, hda_nid_t nid)
 {
+       static char *names[] = {
+               [ilog2(AC_PWRST_D0SUP)]         = "D0",
+               [ilog2(AC_PWRST_D1SUP)]         = "D1",
+               [ilog2(AC_PWRST_D2SUP)]         = "D2",
+               [ilog2(AC_PWRST_D3SUP)]         = "D3",
+               [ilog2(AC_PWRST_D3COLDSUP)]     = "D3cold",
+               [ilog2(AC_PWRST_S3D3COLDSUP)]   = "S3D3cold",
+               [ilog2(AC_PWRST_CLKSTOP)]       = "CLKSTOP",
+               [ilog2(AC_PWRST_EPSS)]          = "EPSS",
+       };
+
+       int sup = snd_hda_param_read(codec, nid, AC_PAR_POWER_STATE);
        int pwr = snd_hda_codec_read(codec, nid, 0,
                                     AC_VERB_GET_POWER_STATE, 0);
+       if (sup)
+               snd_iprintf(buffer, "  Power states: %s\n",
+                           bits_names(sup, names, ARRAY_SIZE(names)));
+
        snd_iprintf(buffer, "  Power: setting=%s, actual=%s\n",
                    get_pwr_state(pwr & AC_PWRST_SETTING),
                    get_pwr_state((pwr & AC_PWRST_ACTUAL) >>
@@ -457,6 +523,7 @@ static void print_gpio(struct snd_info_buffer *buffer,
                            (data & (1<<i)) ? 1 : 0,
                            (unsol & (1<<i)) ? 1 : 0);
        /* FIXME: add GPO and GPI pin information */
+       print_nid_mixers(buffer, codec, nid);
 }
 
 static void print_codec_info(struct snd_info_entry *entry,
@@ -536,6 +603,9 @@ static void print_codec_info(struct snd_info_entry *entry,
                        snd_iprintf(buffer, " CP");
                snd_iprintf(buffer, "\n");
 
+               print_nid_mixers(buffer, codec, nid);
+               print_nid_pcms(buffer, codec, nid);
+
                /* volume knob is a special widget that always have connection
                 * list
                 */
index 2d603f6..455a049 100644 (file)
@@ -156,15 +156,19 @@ static const char *ad_slave_sws[] = {
 
 static void ad198x_free_kctls(struct hda_codec *codec);
 
+#ifdef CONFIG_SND_HDA_INPUT_BEEP
 /* additional beep mixers; the actual parameters are overwritten at build */
 static struct snd_kcontrol_new ad_beep_mixer[] = {
        HDA_CODEC_VOLUME("Beep Playback Volume", 0, 0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Beep Playback Switch", 0, 0, HDA_OUTPUT),
+       HDA_CODEC_MUTE_BEEP("Beep Playback Switch", 0, 0, HDA_OUTPUT),
        { } /* end */
 };
 
 #define set_beep_amp(spec, nid, idx, dir) \
        ((spec)->beep_amp = HDA_COMPOSE_AMP_VAL(nid, 1, idx, dir)) /* mono */
+#else
+#define set_beep_amp(spec, nid, idx, dir) /* NOP */
+#endif
 
 static int ad198x_build_controls(struct hda_codec *codec)
 {
@@ -194,6 +198,7 @@ static int ad198x_build_controls(struct hda_codec *codec)
        }
 
        /* create beep controls if needed */
+#ifdef CONFIG_SND_HDA_INPUT_BEEP
        if (spec->beep_amp) {
                struct snd_kcontrol_new *knew;
                for (knew = ad_beep_mixer; knew->name; knew++) {
@@ -202,11 +207,14 @@ static int ad198x_build_controls(struct hda_codec *codec)
                        if (!kctl)
                                return -ENOMEM;
                        kctl->private_value = spec->beep_amp;
-                       err = snd_hda_ctl_add(codec, kctl);
+                       err = snd_hda_ctl_add(codec,
+                                               get_amp_nid_(spec->beep_amp),
+                                               kctl);
                        if (err < 0)
                                return err;
                }
        }
+#endif
 
        /* if we have no master control, let's create it */
        if (!snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) {
@@ -712,10 +720,10 @@ static struct snd_kcontrol_new ad1986a_laptop_intmic_mixers[] = {
 static void ad1986a_automic(struct hda_codec *codec)
 {
        unsigned int present;
-       present = snd_hda_codec_read(codec, 0x1f, 0, AC_VERB_GET_PIN_SENSE, 0);
+       present = snd_hda_jack_detect(codec, 0x1f);
        /* 0 = 0x1f, 2 = 0x1d, 4 = mixed */
        snd_hda_codec_write(codec, 0x0f, 0, AC_VERB_SET_CONNECT_SEL,
-                           (present & AC_PINSENSE_PRESENCE) ? 0 : 2);
+                           present ? 0 : 2);
 }
 
 #define AD1986A_MIC_EVENT              0x36
@@ -754,10 +762,8 @@ static void ad1986a_update_hp(struct hda_codec *codec)
 static void ad1986a_hp_automute(struct hda_codec *codec)
 {
        struct ad198x_spec *spec = codec->spec;
-       unsigned int present;
 
-       present = snd_hda_codec_read(codec, 0x1a, 0, AC_VERB_GET_PIN_SENSE, 0);
-       spec->jack_present = !!(present & 0x80000000);
+       spec->jack_present = snd_hda_jack_detect(codec, 0x1a);
        if (spec->inv_jack_detect)
                spec->jack_present = !spec->jack_present;
        ad1986a_update_hp(codec);
@@ -1547,8 +1553,7 @@ static void ad1981_hp_automute(struct hda_codec *codec)
 {
        unsigned int present;
 
-       present = snd_hda_codec_read(codec, 0x06, 0,
-                                    AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
+       present = snd_hda_jack_detect(codec, 0x06);
        snd_hda_codec_amp_stereo(codec, 0x05, HDA_OUTPUT, 0,
                                 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
 }
@@ -1568,8 +1573,7 @@ static void ad1981_hp_automic(struct hda_codec *codec)
        };
        unsigned int present;
 
-       present = snd_hda_codec_read(codec, 0x08, 0,
-                                AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
+       present = snd_hda_jack_detect(codec, 0x08);
        if (present)
                snd_hda_sequence_write(codec, mic_jack_on);
        else
@@ -2524,7 +2528,7 @@ static void ad1988_laptop_unsol_event(struct hda_codec *codec, unsigned int res)
 {
        if ((res >> 26) != AD1988_HP_EVENT)
                return;
-       if (snd_hda_codec_read(codec, 0x11, 0, AC_VERB_GET_PIN_SENSE, 0) & (1 << 31))
+       if (snd_hda_jack_detect(codec, 0x11))
                snd_hda_sequence_write(codec, ad1988_laptop_hp_on);
        else
                snd_hda_sequence_write(codec, ad1988_laptop_hp_off);
@@ -2569,6 +2573,8 @@ static int add_control(struct ad198x_spec *spec, int type, const char *name,
        knew->name = kstrdup(name, GFP_KERNEL);
        if (! knew->name)
                return -ENOMEM;
+       if (get_amp_nid_(val))
+               knew->subdevice = HDA_SUBDEV_NID_FLAG | get_amp_nid_(val);
        knew->private_value = val;
        return 0;
 }
@@ -3768,8 +3774,7 @@ static void ad1884a_hp_automute(struct hda_codec *codec)
 {
        unsigned int present;
 
-       present = snd_hda_codec_read(codec, 0x11, 0,
-                                    AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
+       present = snd_hda_jack_detect(codec, 0x11);
        snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
                                 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
        snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_EAPD_BTLENABLE,
@@ -3781,8 +3786,7 @@ static void ad1884a_hp_automic(struct hda_codec *codec)
 {
        unsigned int present;
 
-       present = snd_hda_codec_read(codec, 0x14, 0,
-                                    AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
+       present = snd_hda_jack_detect(codec, 0x14);
        snd_hda_codec_write(codec, 0x0c, 0, AC_VERB_SET_CONNECT_SEL,
                            present ? 0 : 1);
 }
@@ -3817,13 +3821,9 @@ static void ad1884a_laptop_automute(struct hda_codec *codec)
 {
        unsigned int present;
 
-       present = snd_hda_codec_read(codec, 0x11, 0, AC_VERB_GET_PIN_SENSE, 0);
-       present &= AC_PINSENSE_PRESENCE;
-       if (!present) {
-               present = snd_hda_codec_read(codec, 0x12, 0,
-                                            AC_VERB_GET_PIN_SENSE, 0);
-               present &= AC_PINSENSE_PRESENCE;
-       }
+       present = snd_hda_jack_detect(codec, 0x11);
+       if (!present)
+               present = snd_hda_jack_detect(codec, 0x12);
        snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
                                 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
        snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_EAPD_BTLENABLE,
@@ -3835,11 +3835,9 @@ static void ad1884a_laptop_automic(struct hda_codec *codec)
 {
        unsigned int idx;
 
-       if (snd_hda_codec_read(codec, 0x14, 0, AC_VERB_GET_PIN_SENSE, 0) &
-           AC_PINSENSE_PRESENCE)
+       if (snd_hda_jack_detect(codec, 0x14))
                idx = 0;
-       else if (snd_hda_codec_read(codec, 0x1c, 0, AC_VERB_GET_PIN_SENSE, 0) &
-                AC_PINSENSE_PRESENCE)
+       else if (snd_hda_jack_detect(codec, 0x1c))
                idx = 4;
        else
                idx = 1;
@@ -4008,8 +4006,7 @@ static void ad1984a_thinkpad_automute(struct hda_codec *codec)
 {
        unsigned int present;
 
-       present = snd_hda_codec_read(codec, 0x11, 0, AC_VERB_GET_PIN_SENSE, 0)
-               & AC_PINSENSE_PRESENCE;
+       present = snd_hda_jack_detect(codec, 0x11);
        snd_hda_codec_amp_stereo(codec, 0x12, HDA_OUTPUT, 0,
                                 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
 }
@@ -4117,14 +4114,12 @@ static struct snd_kcontrol_new ad1984a_touchsmart_mixers[] = {
 /* switch to external mic if plugged */
 static void ad1984a_touchsmart_automic(struct hda_codec *codec)
 {
-       if (snd_hda_codec_read(codec, 0x1c, 0,
-                                    AC_VERB_GET_PIN_SENSE, 0) & 0x80000000) {
+       if (snd_hda_jack_detect(codec, 0x1c))
                snd_hda_codec_write(codec, 0x0c, 0,
                                     AC_VERB_SET_CONNECT_SEL, 0x4);
-       } else {
+       else
                snd_hda_codec_write(codec, 0x0c, 0,
                                     AC_VERB_SET_CONNECT_SEL, 0x5);
-       }
 }
 
 
index d08353d..af47801 100644 (file)
@@ -144,7 +144,7 @@ static int _add_switch(struct hda_codec *codec, hda_nid_t nid, const char *pfx,
        struct snd_kcontrol_new knew =
                HDA_CODEC_MUTE_MONO(namestr, nid, chan, 0, type);
        sprintf(namestr, "%s %s Switch", pfx, dirstr[dir]);
-       return snd_hda_ctl_add(codec, snd_ctl_new1(&knew, codec));
+       return snd_hda_ctl_add(codec, nid, snd_ctl_new1(&knew, codec));
 }
 
 static int _add_volume(struct hda_codec *codec, hda_nid_t nid, const char *pfx,
@@ -155,7 +155,7 @@ static int _add_volume(struct hda_codec *codec, hda_nid_t nid, const char *pfx,
        struct snd_kcontrol_new knew =
                HDA_CODEC_VOLUME_MONO(namestr, nid, chan, 0, type);
        sprintf(namestr, "%s %s Volume", pfx, dirstr[dir]);
-       return snd_hda_ctl_add(codec, snd_ctl_new1(&knew, codec));
+       return snd_hda_ctl_add(codec, nid, snd_ctl_new1(&knew, codec));
 }
 
 #define add_out_switch(codec, nid, pfx)        _add_switch(codec, nid, pfx, 3, 0)
index 8ba3068..2439e84 100644 (file)
@@ -500,7 +500,7 @@ static int add_mute(struct hda_codec *codec, const char *name, int index,
        knew.private_value = pval;
        snprintf(tmp, sizeof(tmp), "%s %s Switch", name, dir_sfx[dir]);
        *kctlp = snd_ctl_new1(&knew, codec);
-       return snd_hda_ctl_add(codec, *kctlp);
+       return snd_hda_ctl_add(codec, get_amp_nid_(pval), *kctlp);
 }
 
 static int add_volume(struct hda_codec *codec, const char *name,
@@ -513,7 +513,7 @@ static int add_volume(struct hda_codec *codec, const char *name,
        knew.private_value = pval;
        snprintf(tmp, sizeof(tmp), "%s %s Volume", name, dir_sfx[dir]);
        *kctlp = snd_ctl_new1(&knew, codec);
-       return snd_hda_ctl_add(codec, *kctlp);
+       return snd_hda_ctl_add(codec, get_amp_nid_(pval), *kctlp);
 }
 
 static void fix_volume_caps(struct hda_codec *codec, hda_nid_t dac)
@@ -536,14 +536,14 @@ static int add_vmaster(struct hda_codec *codec, hda_nid_t dac)
 
        spec->vmaster_sw =
                snd_ctl_make_virtual_master("Master Playback Switch", NULL);
-       err = snd_hda_ctl_add(codec, spec->vmaster_sw);
+       err = snd_hda_ctl_add(codec, dac, spec->vmaster_sw);
        if (err < 0)
                return err;
 
        snd_hda_set_vmaster_tlv(codec, dac, HDA_OUTPUT, tlv);
        spec->vmaster_vol =
                snd_ctl_make_virtual_master("Master Playback Volume", tlv);
-       err = snd_hda_ctl_add(codec, spec->vmaster_vol);
+       err = snd_hda_ctl_add(codec, dac, spec->vmaster_vol);
        if (err < 0)
                return err;
        return 0;
@@ -756,13 +756,13 @@ static int build_input(struct hda_codec *codec)
                if (!kctl)
                        return -ENOMEM;
                kctl->private_value = (long)spec->capture_bind[i];
-               err = snd_hda_ctl_add(codec, kctl);
+               err = snd_hda_ctl_add(codec, 0, kctl);
                if (err < 0)
                        return err;
        }
        
        if (spec->num_inputs > 1 && !spec->mic_detect) {
-               err = snd_hda_ctl_add(codec,
+               err = snd_hda_ctl_add(codec, 0,
                                      snd_ctl_new1(&cs_capture_source, codec));
                if (err < 0)
                        return err;
@@ -807,7 +807,7 @@ static void cs_automute(struct hda_codec *codec)
 {
        struct cs_spec *spec = codec->spec;
        struct auto_pin_cfg *cfg = &spec->autocfg;
-       unsigned int caps, present, hp_present;
+       unsigned int caps, hp_present;
        hda_nid_t nid;
        int i;
 
@@ -817,12 +817,7 @@ static void cs_automute(struct hda_codec *codec)
                caps = snd_hda_query_pin_caps(codec, nid);
                if (!(caps & AC_PINCAP_PRES_DETECT))
                        continue;
-               if (caps & AC_PINCAP_TRIG_REQ)
-                       snd_hda_codec_read(codec, nid, 0,
-                                          AC_VERB_SET_PIN_SENSE, 0);
-               present = snd_hda_codec_read(codec, nid, 0,
-                                            AC_VERB_GET_PIN_SENSE, 0);
-               hp_present |= (present & AC_PINSENSE_PRESENCE) != 0;
+               hp_present = snd_hda_jack_detect(codec, nid);
                if (hp_present)
                        break;
        }
@@ -844,15 +839,11 @@ static void cs_automic(struct hda_codec *codec)
        struct cs_spec *spec = codec->spec;
        struct auto_pin_cfg *cfg = &spec->autocfg;
        hda_nid_t nid;
-       unsigned int caps, present;
+       unsigned int present;
        
        nid = cfg->input_pins[spec->automic_idx];
-       caps = snd_hda_query_pin_caps(codec, nid);
-       if (caps & AC_PINCAP_TRIG_REQ)
-               snd_hda_codec_read(codec, nid, 0, AC_VERB_SET_PIN_SENSE, 0);
-       present = snd_hda_codec_read(codec, nid, 0,
-                                    AC_VERB_GET_PIN_SENSE, 0);
-       if (present & AC_PINSENSE_PRESENCE)
+       present = snd_hda_jack_detect(codec, nid);
+       if (present)
                change_cur_input(codec, spec->automic_idx, 0);
        else {
                unsigned int imic = (spec->automic_idx == AUTO_PIN_MIC) ?
index 780e1a7..85c81fe 100644 (file)
@@ -197,8 +197,8 @@ static struct snd_kcontrol_new cmi9880_basic_mixer[] = {
        HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0, HDA_INPUT),
        HDA_CODEC_MUTE("Capture Switch", 0x08, 0, HDA_INPUT),
        HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0, HDA_INPUT),
-       HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x23, 0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x23, 0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("Beep Playback Volume", 0x23, 0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Beep Playback Switch", 0x23, 0, HDA_OUTPUT),
        { } /* end */
 };
 
index 905859d..a09c03c 100644 (file)
@@ -397,9 +397,7 @@ static void conexant_report_jack(struct hda_codec *codec, hda_nid_t nid)
                for (i = 0; i < spec->jacks.used; i++) {
                        if (jacks->nid == nid) {
                                unsigned int present;
-                               present = snd_hda_codec_read(codec, nid, 0,
-                                               AC_VERB_GET_PIN_SENSE, 0) &
-                                       AC_PINSENSE_PRESENCE;
+                               present = snd_hda_jack_detect(codec, nid);
 
                                present = (present) ? jacks->type : 0 ;
 
@@ -750,8 +748,7 @@ static void cxt5045_hp_automic(struct hda_codec *codec)
        };
        unsigned int present;
 
-       present = snd_hda_codec_read(codec, 0x12, 0,
-                                    AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
+       present = snd_hda_jack_detect(codec, 0x12);
        if (present)
                snd_hda_sequence_write(codec, mic_jack_on);
        else
@@ -765,8 +762,7 @@ static void cxt5045_hp_automute(struct hda_codec *codec)
        struct conexant_spec *spec = codec->spec;
        unsigned int bits;
 
-       spec->hp_present = snd_hda_codec_read(codec, 0x11, 0,
-                                    AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
+       spec->hp_present = snd_hda_jack_detect(codec, 0x11);
 
        bits = (spec->hp_present || !spec->cur_eapd) ? HDA_AMP_MUTE : 0; 
        snd_hda_codec_amp_stereo(codec, 0x10, HDA_OUTPUT, 0,
@@ -1175,9 +1171,10 @@ static int patch_cxt5045(struct hda_codec *codec)
 
        switch (codec->subsystem_id >> 16) {
        case 0x103c:
-               /* HP laptop has a really bad sound over 0dB on NID 0x17.
-                * Fix max PCM level to 0 dB
-                * (originall it has 0x2b steps with 0dB offset 0x14)
+       case 0x1734:
+               /* HP & Fujitsu-Siemens laptops have really bad sound over 0dB
+                * on NID 0x17. Fix max PCM level to 0 dB
+                * (originally it has 0x2b steps with 0dB offset 0x14)
                 */
                snd_hda_override_amp_caps(codec, 0x17, HDA_INPUT,
                                          (0x14 << AC_AMPCAP_OFFSET_SHIFT) |
@@ -1243,8 +1240,7 @@ static void cxt5047_hp_automute(struct hda_codec *codec)
        struct conexant_spec *spec = codec->spec;
        unsigned int bits;
 
-       spec->hp_present = snd_hda_codec_read(codec, 0x13, 0,
-                                    AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
+       spec->hp_present = snd_hda_jack_detect(codec, 0x13);
 
        bits = (spec->hp_present || !spec->cur_eapd) ? HDA_AMP_MUTE : 0;
        /* See the note in cxt5047_hp_master_sw_put */
@@ -1267,8 +1263,7 @@ static void cxt5047_hp_automic(struct hda_codec *codec)
        };
        unsigned int present;
 
-       present = snd_hda_codec_read(codec, 0x15, 0,
-                                    AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
+       present = snd_hda_jack_detect(codec, 0x15);
        if (present)
                snd_hda_sequence_write(codec, mic_jack_on);
        else
@@ -1415,16 +1410,7 @@ static struct snd_kcontrol_new cxt5047_test_mixer[] = {
                .get = conexant_mux_enum_get,
                .put = conexant_mux_enum_put,
        },
-       HDA_CODEC_VOLUME("Input-1 Volume", 0x1a, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE("Input-1 Switch", 0x1a, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Input-2 Volume", 0x1a, 0x1, HDA_INPUT),
-       HDA_CODEC_MUTE("Input-2 Switch", 0x1a, 0x1, HDA_INPUT),
-       HDA_CODEC_VOLUME("Input-3 Volume", 0x1a, 0x2, HDA_INPUT),
-       HDA_CODEC_MUTE("Input-3 Switch", 0x1a, 0x2, HDA_INPUT),
-       HDA_CODEC_VOLUME("Input-4 Volume", 0x1a, 0x3, HDA_INPUT),
-       HDA_CODEC_MUTE("Input-4 Switch", 0x1a, 0x3, HDA_INPUT),
-       HDA_CODEC_VOLUME("Input-5 Volume", 0x1a, 0x4, HDA_INPUT),
-       HDA_CODEC_MUTE("Input-5 Switch", 0x1a, 0x4, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost Volume", 0x1a, 0x0, HDA_OUTPUT),
 
        { } /* end */
 };
@@ -1621,9 +1607,7 @@ static void cxt5051_portb_automic(struct hda_codec *codec)
 
        if (spec->no_auto_mic)
                return;
-       present = snd_hda_codec_read(codec, 0x17, 0,
-                                    AC_VERB_GET_PIN_SENSE, 0) &
-               AC_PINSENSE_PRESENCE;
+       present = snd_hda_jack_detect(codec, 0x17);
        snd_hda_codec_write(codec, 0x14, 0,
                            AC_VERB_SET_CONNECT_SEL,
                            present ? 0x01 : 0x00);
@@ -1638,9 +1622,7 @@ static void cxt5051_portc_automic(struct hda_codec *codec)
 
        if (spec->no_auto_mic)
                return;
-       present = snd_hda_codec_read(codec, 0x18, 0,
-                                    AC_VERB_GET_PIN_SENSE, 0) &
-               AC_PINSENSE_PRESENCE;
+       present = snd_hda_jack_detect(codec, 0x18);
        if (present)
                spec->cur_adc_idx = 1;
        else
@@ -1661,9 +1643,7 @@ static void cxt5051_hp_automute(struct hda_codec *codec)
 {
        struct conexant_spec *spec = codec->spec;
 
-       spec->hp_present = snd_hda_codec_read(codec, 0x16, 0,
-                                    AC_VERB_GET_PIN_SENSE, 0) &
-               AC_PINSENSE_PRESENCE;
+       spec->hp_present = snd_hda_jack_detect(codec, 0x16);
        cxt5051_update_speaker(codec);
 }
 
@@ -2011,8 +1991,47 @@ static void cxt5066_automic(struct hda_codec *codec)
        };
        unsigned int present;
 
-       present = snd_hda_codec_read(codec, 0x1a, 0,
-                                    AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
+       present = snd_hda_jack_detect(codec, 0x1a);
+       if (present) {
+               snd_printdd("CXT5066: external microphone detected\n");
+               snd_hda_sequence_write(codec, ext_mic_present);
+       } else {
+               snd_printdd("CXT5066: external microphone absent\n");
+               snd_hda_sequence_write(codec, ext_mic_absent);
+       }
+}
+
+/* toggle input of built-in digital mic and mic jack appropriately */
+static void cxt5066_vostro_automic(struct hda_codec *codec)
+{
+       struct conexant_spec *spec = codec->spec;
+       unsigned int present;
+
+       struct hda_verb ext_mic_present[] = {
+               /* enable external mic, port B */
+               {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, spec->ext_mic_bias},
+
+               /* switch to external mic input */
+               {0x17, AC_VERB_SET_CONNECT_SEL, 0},
+               {0x14, AC_VERB_SET_CONNECT_SEL, 0},
+
+               /* disable internal digital mic */
+               {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
+               {}
+       };
+       static struct hda_verb ext_mic_absent[] = {
+               /* enable internal mic, port C */
+               {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+
+               /* switch to internal mic input */
+               {0x14, AC_VERB_SET_CONNECT_SEL, 2},
+
+               /* disable external mic, port B */
+               {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
+               {}
+       };
+
+       present = snd_hda_jack_detect(codec, 0x1a);
        if (present) {
                snd_printdd("CXT5066: external microphone detected\n");
                snd_hda_sequence_write(codec, ext_mic_present);
@@ -2029,12 +2048,10 @@ static void cxt5066_hp_automute(struct hda_codec *codec)
        unsigned int portA, portD;
 
        /* Port A */
-       portA = snd_hda_codec_read(codec, 0x19, 0, AC_VERB_GET_PIN_SENSE, 0)
-               & AC_PINSENSE_PRESENCE;
+       portA = snd_hda_jack_detect(codec, 0x19);
 
        /* Port D */
-       portD = (snd_hda_codec_read(codec, 0x1c, 0, AC_VERB_GET_PIN_SENSE, 0)
-               & AC_PINSENSE_PRESENCE) << 1;
+       portD = snd_hda_jack_detect(codec, 0x1c);
 
        spec->hp_present = !!(portA | portD);
        snd_printdd("CXT5066: hp automute portA=%x portD=%x present=%d\n",
@@ -2056,6 +2073,20 @@ static void cxt5066_unsol_event(struct hda_codec *codec, unsigned int res)
        }
 }
 
+/* unsolicited event for jack sensing */
+static void cxt5066_vostro_event(struct hda_codec *codec, unsigned int res)
+{
+       snd_printdd("CXT5066_vostro: unsol event %x (%x)\n", res, res >> 26);
+       switch (res >> 26) {
+       case CONEXANT_HP_EVENT:
+               cxt5066_hp_automute(codec);
+               break;
+       case CONEXANT_MIC_EVENT:
+               cxt5066_vostro_automic(codec);
+               break;
+       }
+}
+
 static const struct hda_input_mux cxt5066_analog_mic_boost = {
        .num_items = 5,
        .items = {
@@ -2297,6 +2328,67 @@ static struct hda_verb cxt5066_init_verbs_olpc[] = {
        { } /* end */
 };
 
+static struct hda_verb cxt5066_init_verbs_vostro[] = {
+       /* Port A: headphones */
+       {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
+       {0x19, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */
+
+       /* Port B: external microphone */
+       {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
+
+       /* Port C: unused */
+       {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
+
+       /* Port D: unused */
+       {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
+
+       /* Port E: unused, but has primary EAPD */
+       {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
+       {0x1d, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */
+
+       /* Port F: unused */
+       {0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
+
+       /* Port G: internal speakers */
+       {0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x1f, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */
+
+       /* DAC1 */
+       {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+
+       /* DAC2: unused */
+       {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+
+       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
+       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
+       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
+       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
+       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
+       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
+
+       /* Digital microphone port */
+       {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+
+       /* Audio input selectors */
+       {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x3},
+       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
+
+       /* Disable SPDIF */
+       {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
+       {0x22, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
+
+       /* enable unsolicited events for Port A and B */
+       {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_HP_EVENT},
+       {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_MIC_EVENT},
+       { } /* end */
+};
+
 static struct hda_verb cxt5066_init_verbs_portd_lo[] = {
        {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
        { } /* end */
@@ -2318,6 +2410,7 @@ enum {
        CXT5066_LAPTOP,                 /* Laptops w/ EAPD support */
        CXT5066_DELL_LAPTOP,    /* Dell Laptop */
        CXT5066_OLPC_XO_1_5,    /* OLPC XO 1.5 */
+       CXT5066_DELL_VOSTO,     /* Dell Vostro 1015i */
        CXT5066_MODELS
 };
 
@@ -2325,6 +2418,7 @@ static const char *cxt5066_models[CXT5066_MODELS] = {
        [CXT5066_LAPTOP]                = "laptop",
        [CXT5066_DELL_LAPTOP]   = "dell-laptop",
        [CXT5066_OLPC_XO_1_5]   = "olpc-xo-1_5",
+       [CXT5066_DELL_VOSTO]    = "dell-vostro"
 };
 
 static struct snd_pci_quirk cxt5066_cfg_tbl[] = {
@@ -2333,6 +2427,7 @@ static struct snd_pci_quirk cxt5066_cfg_tbl[] = {
        SND_PCI_QUIRK(0x1028, 0x02f5, "Dell",
                      CXT5066_DELL_LAPTOP),
        SND_PCI_QUIRK(0x152d, 0x0833, "OLPC XO-1.5", CXT5066_OLPC_XO_1_5),
+       SND_PCI_QUIRK(0x1028, 0x0402, "Dell Vostro", CXT5066_DELL_VOSTO),
        {}
 };
 
@@ -2400,6 +2495,19 @@ static int patch_cxt5066(struct hda_codec *codec)
                /* input source automatically selected */
                spec->input_mux = NULL;
                break;
+       case CXT5066_DELL_VOSTO:
+               codec->patch_ops.unsol_event = cxt5066_vostro_event;
+               spec->init_verbs[0] = cxt5066_init_verbs_vostro;
+               spec->mixers[spec->num_mixers++] = cxt5066_mixer_master_olpc;
+               spec->mixers[spec->num_mixers++] = cxt5066_mixers;
+               spec->port_d_mode = 0;
+
+               /* no S/PDIF out */
+               spec->multiout.dig_out_nid = 0;
+
+               /* input source automatically selected */
+               spec->input_mux = NULL;
+               break;
        }
 
        return 0;
@@ -2417,6 +2525,8 @@ static struct hda_codec_preset snd_hda_preset_conexant[] = {
          .patch = patch_cxt5051 },
        { .id = 0x14f15066, .name = "CX20582 (Pebble)",
          .patch = patch_cxt5066 },
+       { .id = 0x14f15067, .name = "CX20583 (Pebble HSF)",
+         .patch = patch_cxt5066 },
        {} /* terminator */
 };
 
@@ -2424,6 +2534,7 @@ MODULE_ALIAS("snd-hda-codec-id:14f15045");
 MODULE_ALIAS("snd-hda-codec-id:14f15047");
 MODULE_ALIAS("snd-hda-codec-id:14f15051");
 MODULE_ALIAS("snd-hda-codec-id:14f15066");
+MODULE_ALIAS("snd-hda-codec-id:14f15067");
 
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("Conexant HD-audio codec");
index 01a18ed..928df59 100644 (file)
 #include "hda_codec.h"
 #include "hda_local.h"
 
-static hda_nid_t cvt_nid;      /* audio converter */
-static hda_nid_t pin_nid;      /* HDMI output pin */
+/*
+ * The HDMI/DisplayPort configuration can be highly dynamic. A graphics device
+ * could support two independent pipes, each of them can be connected to one or
+ * more ports (DVI, HDMI or DisplayPort).
+ *
+ * The HDA correspondence of pipes/ports are converter/pin nodes.
+ */
+#define INTEL_HDMI_CVTS        2
+#define INTEL_HDMI_PINS        3
 
-#define INTEL_HDMI_EVENT_TAG           0x08
+static char *intel_hdmi_pcm_names[INTEL_HDMI_CVTS] = {
+       "INTEL HDMI 0",
+       "INTEL HDMI 1",
+};
 
 struct intel_hdmi_spec {
-       struct hda_multi_out multiout;
-       struct hda_pcm pcm_rec;
-       struct hdmi_eld sink_eld;
+       int num_cvts;
+       int num_pins;
+       hda_nid_t cvt[INTEL_HDMI_CVTS+1];  /* audio sources */
+       hda_nid_t pin[INTEL_HDMI_PINS+1];  /* audio sinks */
+
+       /*
+        * source connection for each pin
+        */
+       hda_nid_t pin_cvt[INTEL_HDMI_PINS+1];
+
+       /*
+        * HDMI sink attached to each pin
+        */
+       struct hdmi_eld sink_eld[INTEL_HDMI_PINS];
+
+       /*
+        * export one pcm per pipe
+        */
+       struct hda_pcm  pcm_rec[INTEL_HDMI_CVTS];
 };
 
 struct hdmi_audio_infoframe {
@@ -184,40 +210,186 @@ static struct cea_channel_speaker_allocation channel_allocations[] = {
 { .ca_index = 0x31,  .speakers = { FRW,  FLW,  RR,  RL,  FC,  LFE,  FR,  FL } },
 };
 
+
+/*
+ * HDA/HDMI auto parsing
+ */
+
+static int hda_node_index(hda_nid_t *nids, hda_nid_t nid)
+{
+       int i;
+
+       for (i = 0; nids[i]; i++)
+               if (nids[i] == nid)
+                       return i;
+
+       snd_printk(KERN_WARNING "HDMI: nid %d not registered\n", nid);
+       return -EINVAL;
+}
+
+static int intel_hdmi_read_pin_conn(struct hda_codec *codec, hda_nid_t pin_nid)
+{
+       struct intel_hdmi_spec *spec = codec->spec;
+       hda_nid_t conn_list[HDA_MAX_CONNECTIONS];
+       int conn_len, curr;
+       int index;
+
+       if (!(get_wcaps(codec, pin_nid) & AC_WCAP_CONN_LIST)) {
+               snd_printk(KERN_WARNING
+                          "HDMI: pin %d wcaps %#x "
+                          "does not support connection list\n",
+                          pin_nid, get_wcaps(codec, pin_nid));
+               return -EINVAL;
+       }
+
+       conn_len = snd_hda_get_connections(codec, pin_nid, conn_list,
+                                          HDA_MAX_CONNECTIONS);
+       if (conn_len > 1)
+               curr = snd_hda_codec_read(codec, pin_nid, 0,
+                                         AC_VERB_GET_CONNECT_SEL, 0);
+       else
+               curr = 0;
+
+       index = hda_node_index(spec->pin, pin_nid);
+       if (index < 0)
+               return -EINVAL;
+
+       spec->pin_cvt[index] = conn_list[curr];
+
+       return 0;
+}
+
+static void hdmi_get_show_eld(struct hda_codec *codec, hda_nid_t pin_nid,
+                             struct hdmi_eld *eld)
+{
+       if (!snd_hdmi_get_eld(eld, codec, pin_nid))
+               snd_hdmi_show_eld(eld);
+}
+
+static void hdmi_present_sense(struct hda_codec *codec, hda_nid_t pin_nid,
+                              struct hdmi_eld *eld)
+{
+       int present = snd_hda_pin_sense(codec, pin_nid);
+
+       eld->monitor_present    = !!(present & AC_PINSENSE_PRESENCE);
+       eld->eld_valid          = !!(present & AC_PINSENSE_ELDV);
+
+       if (present & AC_PINSENSE_ELDV)
+               hdmi_get_show_eld(codec, pin_nid, eld);
+}
+
+static int intel_hdmi_add_pin(struct hda_codec *codec, hda_nid_t pin_nid)
+{
+       struct intel_hdmi_spec *spec = codec->spec;
+
+       if (spec->num_pins >= INTEL_HDMI_PINS) {
+               snd_printk(KERN_WARNING
+                          "HDMI: no space for pin %d \n", pin_nid);
+               return -EINVAL;
+       }
+
+       hdmi_present_sense(codec, pin_nid, &spec->sink_eld[spec->num_pins]);
+
+       spec->pin[spec->num_pins] = pin_nid;
+       spec->num_pins++;
+
+       /*
+        * It is assumed that converter nodes come first in the node list and
+        * hence have been registered and usable now.
+        */
+       return intel_hdmi_read_pin_conn(codec, pin_nid);
+}
+
+static int intel_hdmi_add_cvt(struct hda_codec *codec, hda_nid_t nid)
+{
+       struct intel_hdmi_spec *spec = codec->spec;
+
+       if (spec->num_cvts >= INTEL_HDMI_CVTS) {
+               snd_printk(KERN_WARNING
+                          "HDMI: no space for converter %d \n", nid);
+               return -EINVAL;
+       }
+
+       spec->cvt[spec->num_cvts] = nid;
+       spec->num_cvts++;
+
+       return 0;
+}
+
+static int intel_hdmi_parse_codec(struct hda_codec *codec)
+{
+       hda_nid_t nid;
+       int i, nodes;
+
+       nodes = snd_hda_get_sub_nodes(codec, codec->afg, &nid);
+       if (!nid || nodes < 0) {
+               snd_printk(KERN_WARNING "HDMI: failed to get afg sub nodes\n");
+               return -EINVAL;
+       }
+
+       for (i = 0; i < nodes; i++, nid++) {
+               unsigned int caps;
+               unsigned int type;
+
+               caps = snd_hda_param_read(codec, nid, AC_PAR_AUDIO_WIDGET_CAP);
+               type = get_wcaps_type(caps);
+
+               if (!(caps & AC_WCAP_DIGITAL))
+                       continue;
+
+               switch (type) {
+               case AC_WID_AUD_OUT:
+                       if (intel_hdmi_add_cvt(codec, nid) < 0)
+                               return -EINVAL;
+                       break;
+               case AC_WID_PIN:
+                       caps = snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP);
+                       if (!(caps & AC_PINCAP_HDMI))
+                               continue;
+                       if (intel_hdmi_add_pin(codec, nid) < 0)
+                               return -EINVAL;
+                       break;
+               }
+       }
+
+       return 0;
+}
+
 /*
  * HDMI routines
  */
 
 #ifdef BE_PARANOID
-static void hdmi_get_dip_index(struct hda_codec *codec, hda_nid_t nid,
+static void hdmi_get_dip_index(struct hda_codec *codec, hda_nid_t pin_nid,
                                int *packet_index, int *byte_index)
 {
        int val;
 
-       val = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_HDMI_DIP_INDEX, 0);
+       val = snd_hda_codec_read(codec, pin_nid, 0,
+                                AC_VERB_GET_HDMI_DIP_INDEX, 0);
 
        *packet_index = val >> 5;
        *byte_index = val & 0x1f;
 }
 #endif
 
-static void hdmi_set_dip_index(struct hda_codec *codec, hda_nid_t nid,
+static void hdmi_set_dip_index(struct hda_codec *codec, hda_nid_t pin_nid,
                                int packet_index, int byte_index)
 {
        int val;
 
        val = (packet_index << 5) | (byte_index & 0x1f);
 
-       snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_HDMI_DIP_INDEX, val);
+       snd_hda_codec_write(codec, pin_nid, 0, AC_VERB_SET_HDMI_DIP_INDEX, val);
 }
 
-static void hdmi_write_dip_byte(struct hda_codec *codec, hda_nid_t nid,
+static void hdmi_write_dip_byte(struct hda_codec *codec, hda_nid_t pin_nid,
                                unsigned char val)
 {
-       snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_HDMI_DIP_DATA, val);
+       snd_hda_codec_write(codec, pin_nid, 0, AC_VERB_SET_HDMI_DIP_DATA, val);
 }
 
-static void hdmi_enable_output(struct hda_codec *codec)
+static void hdmi_enable_output(struct hda_codec *codec, hda_nid_t pin_nid)
 {
        /* Unmute */
        if (get_wcaps(codec, pin_nid) & AC_WCAP_OUT_AMP)
@@ -231,7 +403,8 @@ static void hdmi_enable_output(struct hda_codec *codec)
 /*
  * Enable Audio InfoFrame Transmission
  */
-static void hdmi_start_infoframe_trans(struct hda_codec *codec)
+static void hdmi_start_infoframe_trans(struct hda_codec *codec,
+                                      hda_nid_t pin_nid)
 {
        hdmi_set_dip_index(codec, pin_nid, 0x0, 0x0);
        snd_hda_codec_write(codec, pin_nid, 0, AC_VERB_SET_HDMI_DIP_XMIT,
@@ -241,59 +414,49 @@ static void hdmi_start_infoframe_trans(struct hda_codec *codec)
 /*
  * Disable Audio InfoFrame Transmission
  */
-static void hdmi_stop_infoframe_trans(struct hda_codec *codec)
+static void hdmi_stop_infoframe_trans(struct hda_codec *codec,
+                                     hda_nid_t pin_nid)
 {
        hdmi_set_dip_index(codec, pin_nid, 0x0, 0x0);
        snd_hda_codec_write(codec, pin_nid, 0, AC_VERB_SET_HDMI_DIP_XMIT,
                                                AC_DIPXMIT_DISABLE);
 }
 
-static int hdmi_get_channel_count(struct hda_codec *codec)
+static int hdmi_get_channel_count(struct hda_codec *codec, hda_nid_t nid)
 {
-       return 1 + snd_hda_codec_read(codec, cvt_nid, 0,
+       return 1 + snd_hda_codec_read(codec, nid, 0,
                                        AC_VERB_GET_CVT_CHAN_COUNT, 0);
 }
 
-static void hdmi_set_channel_count(struct hda_codec *codec, int chs)
+static void hdmi_set_channel_count(struct hda_codec *codec,
+                                  hda_nid_t nid, int chs)
 {
-       snd_hda_codec_write(codec, cvt_nid, 0,
-                                       AC_VERB_SET_CVT_CHAN_COUNT, chs - 1);
-
-       if (chs != hdmi_get_channel_count(codec))
-               snd_printd(KERN_INFO "HDMI channel count: expect %d, get %d\n",
-                                       chs, hdmi_get_channel_count(codec));
+       if (chs != hdmi_get_channel_count(codec, nid))
+               snd_hda_codec_write(codec, nid, 0,
+                                   AC_VERB_SET_CVT_CHAN_COUNT, chs - 1);
 }
 
-static void hdmi_debug_channel_mapping(struct hda_codec *codec)
+static void hdmi_debug_channel_mapping(struct hda_codec *codec, hda_nid_t nid)
 {
 #ifdef CONFIG_SND_DEBUG_VERBOSE
        int i;
        int slot;
 
        for (i = 0; i < 8; i++) {
-               slot = snd_hda_codec_read(codec, cvt_nid, 0,
+               slot = snd_hda_codec_read(codec, nid, 0,
                                                AC_VERB_GET_HDMI_CHAN_SLOT, i);
                printk(KERN_DEBUG "HDMI: ASP channel %d => slot %d\n",
-                                               slot >> 4, slot & 0x7);
+                                               slot >> 4, slot & 0xf);
        }
 #endif
 }
 
-static void hdmi_parse_eld(struct hda_codec *codec)
-{
-       struct intel_hdmi_spec *spec = codec->spec;
-       struct hdmi_eld *eld = &spec->sink_eld;
-
-       if (!snd_hdmi_get_eld(eld, codec, pin_nid))
-               snd_hdmi_show_eld(eld);
-}
-
 
 /*
  * Audio InfoFrame routines
  */
 
-static void hdmi_debug_dip_size(struct hda_codec *codec)
+static void hdmi_debug_dip_size(struct hda_codec *codec, hda_nid_t pin_nid)
 {
 #ifdef CONFIG_SND_DEBUG_VERBOSE
        int i;
@@ -310,7 +473,7 @@ static void hdmi_debug_dip_size(struct hda_codec *codec)
 #endif
 }
 
-static void hdmi_clear_dip_buffers(struct hda_codec *codec)
+static void hdmi_clear_dip_buffers(struct hda_codec *codec, hda_nid_t pin_nid)
 {
 #ifdef BE_PARANOID
        int i, j;
@@ -339,23 +502,35 @@ static void hdmi_clear_dip_buffers(struct hda_codec *codec)
 #endif
 }
 
-static void hdmi_fill_audio_infoframe(struct hda_codec *codec,
-                                       struct hdmi_audio_infoframe *ai)
+static void hdmi_checksum_audio_infoframe(struct hdmi_audio_infoframe *ai)
 {
-       u8 *params = (u8 *)ai;
+       u8 *bytes = (u8 *)ai;
        u8 sum = 0;
        int i;
 
-       hdmi_debug_dip_size(codec);
-       hdmi_clear_dip_buffers(codec); /* be paranoid */
+       ai->checksum = 0;
+
+       for (i = 0; i < sizeof(*ai); i++)
+               sum += bytes[i];
 
-       for (i = 0; i < sizeof(ai); i++)
-               sum += params[i];
        ai->checksum = - sum;
+}
+
+static void hdmi_fill_audio_infoframe(struct hda_codec *codec,
+                                     hda_nid_t pin_nid,
+                                     struct hdmi_audio_infoframe *ai)
+{
+       u8 *bytes = (u8 *)ai;
+       int i;
+
+       hdmi_debug_dip_size(codec, pin_nid);
+       hdmi_clear_dip_buffers(codec, pin_nid); /* be paranoid */
+
+       hdmi_checksum_audio_infoframe(ai);
 
        hdmi_set_dip_index(codec, pin_nid, 0x0, 0x0);
-       for (i = 0; i < sizeof(ai); i++)
-               hdmi_write_dip_byte(codec, pin_nid, params[i]);
+       for (i = 0; i < sizeof(*ai); i++)
+               hdmi_write_dip_byte(codec, pin_nid, bytes[i]);
 }
 
 /*
@@ -386,11 +561,11 @@ static void init_channel_allocations(void)
  *
  * TODO: it could select the wrong CA from multiple candidates.
 */
-static int hdmi_setup_channel_allocation(struct hda_codec *codec,
+static int hdmi_setup_channel_allocation(struct hda_codec *codec, hda_nid_t nid,
                                         struct hdmi_audio_infoframe *ai)
 {
        struct intel_hdmi_spec *spec = codec->spec;
-       struct hdmi_eld *eld = &spec->sink_eld;
+       struct hdmi_eld *eld;
        int i;
        int spk_mask = 0;
        int channels = 1 + (ai->CC02_CT47 & 0x7);
@@ -402,6 +577,11 @@ static int hdmi_setup_channel_allocation(struct hda_codec *codec,
        if (channels <= 2)
                return 0;
 
+       i = hda_node_index(spec->pin_cvt, nid);
+       if (i < 0)
+               return 0;
+       eld = &spec->sink_eld[i];
+
        /*
         * HDMI sink's ELD info cannot always be retrieved for now, e.g.
         * in console or for audio devices. Assume the highest speakers
@@ -439,8 +619,8 @@ static int hdmi_setup_channel_allocation(struct hda_codec *codec,
        return ai->CA;
 }
 
-static void hdmi_setup_channel_mapping(struct hda_codec *codec,
-                                       struct hdmi_audio_infoframe *ai)
+static void hdmi_setup_channel_mapping(struct hda_codec *codec, hda_nid_t nid,
+                                      struct hdmi_audio_infoframe *ai)
 {
        int i;
 
@@ -453,17 +633,41 @@ static void hdmi_setup_channel_mapping(struct hda_codec *codec,
         */
 
        for (i = 0; i < 8; i++)
-               snd_hda_codec_write(codec, cvt_nid, 0,
+               snd_hda_codec_write(codec, nid, 0,
                                    AC_VERB_SET_HDMI_CHAN_SLOT,
                                    (i << 4) | i);
 
-       hdmi_debug_channel_mapping(codec);
+       hdmi_debug_channel_mapping(codec, nid);
 }
 
+static bool hdmi_infoframe_uptodate(struct hda_codec *codec, hda_nid_t pin_nid,
+                                   struct hdmi_audio_infoframe *ai)
+{
+       u8 *bytes = (u8 *)ai;
+       u8 val;
+       int i;
+
+       if (snd_hda_codec_read(codec, pin_nid, 0, AC_VERB_GET_HDMI_DIP_XMIT, 0)
+                                                           != AC_DIPXMIT_BEST)
+               return false;
+
+       hdmi_set_dip_index(codec, pin_nid, 0x0, 0x0);
+       for (i = 0; i < sizeof(*ai); i++) {
+               val = snd_hda_codec_read(codec, pin_nid, 0,
+                                        AC_VERB_GET_HDMI_DIP_DATA, 0);
+               if (val != bytes[i])
+                       return false;
+       }
 
-static void hdmi_setup_audio_infoframe(struct hda_codec *codec,
+       return true;
+}
+
+static void hdmi_setup_audio_infoframe(struct hda_codec *codec, hda_nid_t nid,
                                        struct snd_pcm_substream *substream)
 {
+       struct intel_hdmi_spec *spec = codec->spec;
+       hda_nid_t pin_nid;
+       int i;
        struct hdmi_audio_infoframe ai = {
                .type           = 0x84,
                .ver            = 0x01,
@@ -471,11 +675,22 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec,
                .CC02_CT47      = substream->runtime->channels - 1,
        };
 
-       hdmi_setup_channel_allocation(codec, &ai);
-       hdmi_setup_channel_mapping(codec, &ai);
+       hdmi_setup_channel_allocation(codec, nid, &ai);
+       hdmi_setup_channel_mapping(codec, nid, &ai);
 
-       hdmi_fill_audio_infoframe(codec, &ai);
-       hdmi_start_infoframe_trans(codec);
+       for (i = 0; i < spec->num_pins; i++) {
+               if (spec->pin_cvt[i] != nid)
+                       continue;
+               if (!spec->sink_eld[i].monitor_present)
+                       continue;
+
+               pin_nid = spec->pin[i];
+               if (!hdmi_infoframe_uptodate(codec, pin_nid, &ai)) {
+                       hdmi_stop_infoframe_trans(codec, pin_nid);
+                       hdmi_fill_audio_infoframe(codec, pin_nid, &ai);
+                       hdmi_start_infoframe_trans(codec, pin_nid);
+               }
+       }
 }
 
 
@@ -485,27 +700,39 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec,
 
 static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res)
 {
+       struct intel_hdmi_spec *spec = codec->spec;
+       int tag = res >> AC_UNSOL_RES_TAG_SHIFT;
        int pind = !!(res & AC_UNSOL_RES_PD);
        int eldv = !!(res & AC_UNSOL_RES_ELDV);
+       int index;
 
        printk(KERN_INFO
-               "HDMI hot plug event: Presence_Detect=%d ELD_Valid=%d\n",
-               pind, eldv);
+               "HDMI hot plug event: Pin=%d Presence_Detect=%d ELD_Valid=%d\n",
+               tag, pind, eldv);
+
+       index = hda_node_index(spec->pin, tag);
+       if (index < 0)
+               return;
+
+       spec->sink_eld[index].monitor_present = pind;
+       spec->sink_eld[index].eld_valid = eldv;
 
        if (pind && eldv) {
-               hdmi_parse_eld(codec);
+               hdmi_get_show_eld(codec, spec->pin[index], &spec->sink_eld[index]);
                /* TODO: do real things about ELD */
        }
 }
 
 static void hdmi_non_intrinsic_event(struct hda_codec *codec, unsigned int res)
 {
+       int tag = res >> AC_UNSOL_RES_TAG_SHIFT;
        int subtag = (res & AC_UNSOL_RES_SUBTAG) >> AC_UNSOL_RES_SUBTAG_SHIFT;
        int cp_state = !!(res & AC_UNSOL_RES_CP_STATE);
        int cp_ready = !!(res & AC_UNSOL_RES_CP_READY);
 
        printk(KERN_INFO
-               "HDMI content protection event: SUBTAG=0x%x CP_STATE=%d CP_READY=%d\n",
+               "HDMI CP event: PIN=%d SUBTAG=0x%x CP_STATE=%d CP_READY=%d\n",
+               tag,
                subtag,
                cp_state,
                cp_ready);
@@ -520,10 +747,11 @@ static void hdmi_non_intrinsic_event(struct hda_codec *codec, unsigned int res)
 
 static void intel_hdmi_unsol_event(struct hda_codec *codec, unsigned int res)
 {
+       struct intel_hdmi_spec *spec = codec->spec;
        int tag = res >> AC_UNSOL_RES_TAG_SHIFT;
        int subtag = (res & AC_UNSOL_RES_SUBTAG) >> AC_UNSOL_RES_SUBTAG_SHIFT;
 
-       if (tag != INTEL_HDMI_EVENT_TAG) {
+       if (hda_node_index(spec->pin, tag) < 0) {
                snd_printd(KERN_INFO "Unexpected HDMI event tag 0x%x\n", tag);
                return;
        }
@@ -538,24 +766,29 @@ static void intel_hdmi_unsol_event(struct hda_codec *codec, unsigned int res)
  * Callbacks
  */
 
-static int intel_hdmi_playback_pcm_open(struct hda_pcm_stream *hinfo,
-                                       struct hda_codec *codec,
-                                       struct snd_pcm_substream *substream)
+static void hdmi_setup_stream(struct hda_codec *codec, hda_nid_t nid,
+                             u32 stream_tag, int format)
 {
-       struct intel_hdmi_spec *spec = codec->spec;
-
-       return snd_hda_multi_out_dig_open(codec, &spec->multiout);
-}
+       int tag;
+       int fmt;
 
-static int intel_hdmi_playback_pcm_close(struct hda_pcm_stream *hinfo,
-                                        struct hda_codec *codec,
-                                        struct snd_pcm_substream *substream)
-{
-       struct intel_hdmi_spec *spec = codec->spec;
+       tag = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONV, 0) >> 4;
+       fmt = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_STREAM_FORMAT, 0);
 
-       hdmi_stop_infoframe_trans(codec);
+       snd_printdd("hdmi_setup_stream: "
+                   "NID=0x%x, %sstream=0x%x, %sformat=0x%x\n",
+                   nid,
+                   tag == stream_tag ? "" : "new-",
+                   stream_tag,
+                   fmt == format ? "" : "new-",
+                   format);
 
-       return snd_hda_multi_out_dig_close(codec, &spec->multiout);
+       if (tag != stream_tag)
+               snd_hda_codec_write(codec, nid, 0,
+                                   AC_VERB_SET_CHANNEL_STREAMID, stream_tag << 4);
+       if (fmt != format)
+               snd_hda_codec_write(codec, nid, 0,
+                                   AC_VERB_SET_STREAM_FORMAT, format);
 }
 
 static int intel_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
@@ -564,43 +797,53 @@ static int intel_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
                                           unsigned int format,
                                           struct snd_pcm_substream *substream)
 {
-       struct intel_hdmi_spec *spec = codec->spec;
-
-       snd_hda_multi_out_dig_prepare(codec, &spec->multiout, stream_tag,
-                                            format, substream);
+       hdmi_set_channel_count(codec, hinfo->nid,
+                              substream->runtime->channels);
 
-       hdmi_set_channel_count(codec, substream->runtime->channels);
+       hdmi_setup_audio_infoframe(codec, hinfo->nid, substream);
 
-       hdmi_setup_audio_infoframe(codec, substream);
+       hdmi_setup_stream(codec, hinfo->nid, stream_tag, format);
+       return 0;
+}
 
+static int intel_hdmi_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
+                                          struct hda_codec *codec,
+                                          struct snd_pcm_substream *substream)
+{
        return 0;
 }
 
 static struct hda_pcm_stream intel_hdmi_pcm_playback = {
        .substreams = 1,
        .channels_min = 2,
-       .channels_max = 8,
        .ops = {
-               .open    = intel_hdmi_playback_pcm_open,
-               .close   = intel_hdmi_playback_pcm_close,
-               .prepare = intel_hdmi_playback_pcm_prepare
+               .prepare = intel_hdmi_playback_pcm_prepare,
+               .cleanup = intel_hdmi_playback_pcm_cleanup,
        },
 };
 
 static int intel_hdmi_build_pcms(struct hda_codec *codec)
 {
        struct intel_hdmi_spec *spec = codec->spec;
-       struct hda_pcm *info = &spec->pcm_rec;
+       struct hda_pcm *info = spec->pcm_rec;
+       int i;
 
-       codec->num_pcms = 1;
+       codec->num_pcms = spec->num_cvts;
        codec->pcm_info = info;
 
-       /* NID to query formats and rates and setup streams */
-       intel_hdmi_pcm_playback.nid = cvt_nid;
+       for (i = 0; i < codec->num_pcms; i++, info++) {
+               unsigned int chans;
 
-       info->name = "INTEL HDMI";
-       info->pcm_type = HDA_PCM_TYPE_HDMI;
-       info->stream[SNDRV_PCM_STREAM_PLAYBACK] = intel_hdmi_pcm_playback;
+               chans = get_wcaps(codec, spec->cvt[i]);
+               chans = get_wcaps_channels(chans);
+
+               info->name = intel_hdmi_pcm_names[i];
+               info->pcm_type = HDA_PCM_TYPE_HDMI;
+               info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
+                                                       intel_hdmi_pcm_playback;
+               info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->cvt[i];
+               info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = chans;
+       }
 
        return 0;
 }
@@ -609,29 +852,39 @@ static int intel_hdmi_build_controls(struct hda_codec *codec)
 {
        struct intel_hdmi_spec *spec = codec->spec;
        int err;
+       int i;
 
-       err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid);
-       if (err < 0)
-               return err;
+       for (i = 0; i < codec->num_pcms; i++) {
+               err = snd_hda_create_spdif_out_ctls(codec, spec->cvt[i]);
+               if (err < 0)
+                       return err;
+       }
 
        return 0;
 }
 
 static int intel_hdmi_init(struct hda_codec *codec)
 {
-       hdmi_enable_output(codec);
+       struct intel_hdmi_spec *spec = codec->spec;
+       int i;
 
-       snd_hda_codec_write(codec, pin_nid, 0,
-                           AC_VERB_SET_UNSOLICITED_ENABLE,
-                           AC_USRSP_EN | INTEL_HDMI_EVENT_TAG);
+       for (i = 0; spec->pin[i]; i++) {
+               hdmi_enable_output(codec, spec->pin[i]);
+               snd_hda_codec_write(codec, spec->pin[i], 0,
+                                   AC_VERB_SET_UNSOLICITED_ENABLE,
+                                   AC_USRSP_EN | spec->pin[i]);
+       }
        return 0;
 }
 
 static void intel_hdmi_free(struct hda_codec *codec)
 {
        struct intel_hdmi_spec *spec = codec->spec;
+       int i;
+
+       for (i = 0; i < spec->num_pins; i++)
+               snd_hda_eld_proc_free(codec, &spec->sink_eld[i]);
 
-       snd_hda_eld_proc_free(codec, &spec->sink_eld);
        kfree(spec);
 }
 
@@ -643,49 +896,38 @@ static struct hda_codec_ops intel_hdmi_patch_ops = {
        .unsol_event            = intel_hdmi_unsol_event,
 };
 
-static int do_patch_intel_hdmi(struct hda_codec *codec)
+static int patch_intel_hdmi(struct hda_codec *codec)
 {
        struct intel_hdmi_spec *spec;
+       int i;
 
        spec = kzalloc(sizeof(*spec), GFP_KERNEL);
        if (spec == NULL)
                return -ENOMEM;
 
-       spec->multiout.num_dacs = 0;      /* no analog */
-       spec->multiout.max_channels = 8;
-       spec->multiout.dig_out_nid = cvt_nid;
-
        codec->spec = spec;
+       if (intel_hdmi_parse_codec(codec) < 0) {
+               codec->spec = NULL;
+               kfree(spec);
+               return -EINVAL;
+       }
        codec->patch_ops = intel_hdmi_patch_ops;
 
-       snd_hda_eld_proc_new(codec, &spec->sink_eld);
+       for (i = 0; i < spec->num_pins; i++)
+               snd_hda_eld_proc_new(codec, &spec->sink_eld[i], i);
 
        init_channel_allocations();
 
        return 0;
 }
 
-static int patch_intel_hdmi(struct hda_codec *codec)
-{
-       cvt_nid = 0x02;
-       pin_nid = 0x03;
-       return do_patch_intel_hdmi(codec);
-}
-
-static int patch_intel_hdmi_ibexpeak(struct hda_codec *codec)
-{
-       cvt_nid = 0x02;
-       pin_nid = 0x04;
-       return do_patch_intel_hdmi(codec);
-}
-
 static struct hda_codec_preset snd_hda_preset_intelhdmi[] = {
        { .id = 0x808629fb, .name = "G45 DEVCL",  .patch = patch_intel_hdmi },
        { .id = 0x80862801, .name = "G45 DEVBLC", .patch = patch_intel_hdmi },
        { .id = 0x80862802, .name = "G45 DEVCTG", .patch = patch_intel_hdmi },
        { .id = 0x80862803, .name = "G45 DEVELK", .patch = patch_intel_hdmi },
        { .id = 0x80862804, .name = "G45 DEVIBX", .patch = patch_intel_hdmi },
-       { .id = 0x80860054, .name = "Q57 DEVIBX", .patch = patch_intel_hdmi_ibexpeak },
+       { .id = 0x80860054, .name = "Q57 DEVIBX", .patch = patch_intel_hdmi },
        { .id = 0x10951392, .name = "SiI1392 HDMI",     .patch = patch_intel_hdmi },
        {} /* terminator */
 };
index 7058371..d967836 100644 (file)
@@ -961,18 +961,12 @@ static void alc_fix_pll_init(struct hda_codec *codec, hda_nid_t nid,
 static void alc_automute_pin(struct hda_codec *codec)
 {
        struct alc_spec *spec = codec->spec;
-       unsigned int present, pincap;
        unsigned int nid = spec->autocfg.hp_pins[0];
        int i;
 
        if (!nid)
                return;
-       pincap = snd_hda_query_pin_caps(codec, nid);
-       if (pincap & AC_PINCAP_TRIG_REQ) /* need trigger? */
-               snd_hda_codec_read(codec, nid, 0, AC_VERB_SET_PIN_SENSE, 0);
-       present = snd_hda_codec_read(codec, nid, 0,
-                                    AC_VERB_GET_PIN_SENSE, 0);
-       spec->jack_present = (present & AC_PINSENSE_PRESENCE) != 0;
+       spec->jack_present = snd_hda_jack_detect(codec, nid);
        for (i = 0; i < ARRAY_SIZE(spec->autocfg.speaker_pins); i++) {
                nid = spec->autocfg.speaker_pins[i];
                if (!nid)
@@ -1012,9 +1006,7 @@ static void alc_mic_automute(struct hda_codec *codec)
 
        cap_nid = spec->capsrc_nids ? spec->capsrc_nids[0] : spec->adc_nids[0];
 
-       present = snd_hda_codec_read(codec, spec->ext_mic.pin, 0,
-                                    AC_VERB_GET_PIN_SENSE, 0);
-       present &= AC_PINSENSE_PRESENCE;
+       present = snd_hda_jack_detect(codec, spec->ext_mic.pin);
        if (present) {
                alive = &spec->ext_mic;
                dead = &spec->int_mic;
@@ -1402,6 +1394,17 @@ static void alc_pick_fixup(struct hda_codec *codec,
                add_verb(codec->spec, fix->verbs);
 }
 
+static int alc_read_coef_idx(struct hda_codec *codec,
+                       unsigned int coef_idx)
+{
+       unsigned int val;
+       snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX,
+                               coef_idx);
+       val = snd_hda_codec_read(codec, 0x20, 0,
+                               AC_VERB_GET_PROC_COEF, 0);
+       return val;
+}
+
 /*
  * ALC888
  */
@@ -1513,7 +1516,7 @@ static struct hda_verb alc888_fujitsu_xa3530_verbs[] = {
 static void alc_automute_amp(struct hda_codec *codec)
 {
        struct alc_spec *spec = codec->spec;
-       unsigned int val, mute, pincap;
+       unsigned int mute;
        hda_nid_t nid;
        int i;
 
@@ -1522,13 +1525,7 @@ static void alc_automute_amp(struct hda_codec *codec)
                nid = spec->autocfg.hp_pins[i];
                if (!nid)
                        break;
-               pincap = snd_hda_query_pin_caps(codec, nid);
-               if (pincap & AC_PINCAP_TRIG_REQ) /* need trigger? */
-                       snd_hda_codec_read(codec, nid, 0,
-                                          AC_VERB_SET_PIN_SENSE, 0);
-               val = snd_hda_codec_read(codec, nid, 0,
-                                        AC_VERB_GET_PIN_SENSE, 0);
-               if (val & AC_PINSENSE_PRESENCE) {
+               if (snd_hda_jack_detect(codec, nid)) {
                        spec->jack_present = 1;
                        break;
                }
@@ -1786,6 +1783,8 @@ static void alc888_acer_aspire_4930g_setup(struct hda_codec *codec)
 
        spec->autocfg.hp_pins[0] = 0x15;
        spec->autocfg.speaker_pins[0] = 0x14;
+       spec->autocfg.speaker_pins[1] = 0x16;
+       spec->autocfg.speaker_pins[2] = 0x17;
 }
 
 static void alc888_acer_aspire_6530g_setup(struct hda_codec *codec)
@@ -2410,12 +2409,14 @@ static const char *alc_slave_sws[] = {
 
 static void alc_free_kctls(struct hda_codec *codec);
 
+#ifdef CONFIG_SND_HDA_INPUT_BEEP
 /* additional beep mixers; the actual parameters are overwritten at build */
 static struct snd_kcontrol_new alc_beep_mixer[] = {
        HDA_CODEC_VOLUME("Beep Playback Volume", 0, 0, HDA_INPUT),
-       HDA_CODEC_MUTE("Beep Playback Switch", 0, 0, HDA_INPUT),
+       HDA_CODEC_MUTE_BEEP("Beep Playback Switch", 0, 0, HDA_INPUT),
        { } /* end */
 };
+#endif
 
 static int alc_build_controls(struct hda_codec *codec)
 {
@@ -2452,6 +2453,7 @@ static int alc_build_controls(struct hda_codec *codec)
                        return err;
        }
 
+#ifdef CONFIG_SND_HDA_INPUT_BEEP
        /* create beep controls if needed */
        if (spec->beep_amp) {
                struct snd_kcontrol_new *knew;
@@ -2461,11 +2463,13 @@ static int alc_build_controls(struct hda_codec *codec)
                        if (!kctl)
                                return -ENOMEM;
                        kctl->private_value = spec->beep_amp;
-                       err = snd_hda_ctl_add(codec, kctl);
+                       err = snd_hda_ctl_add(codec,
+                                       get_amp_nid_(spec->beep_amp), kctl);
                        if (err < 0)
                                return err;
                }
        }
+#endif
 
        /* if we have no master control, let's create it */
        if (!spec->no_analog &&
@@ -2779,8 +2783,7 @@ static void alc880_uniwill_mic_automute(struct hda_codec *codec)
        unsigned int present;
        unsigned char bits;
 
-       present = snd_hda_codec_read(codec, 0x18, 0,
-                                    AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
+       present = snd_hda_jack_detect(codec, 0x18);
        bits = present ? HDA_AMP_MUTE : 0;
        snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1, HDA_AMP_MUTE, bits);
 }
@@ -3480,7 +3483,7 @@ static int alc_build_pcms(struct hda_codec *codec)
        snprintf(spec->stream_name_analog, sizeof(spec->stream_name_analog),
                 "%s Analog", codec->chip_name);
        info->name = spec->stream_name_analog;
-       
+
        if (spec->stream_analog_playback) {
                if (snd_BUG_ON(!spec->multiout.dac_nids))
                        return -EINVAL;
@@ -4322,10 +4325,26 @@ static int add_control(struct alc_spec *spec, int type, const char *name,
        knew->name = kstrdup(name, GFP_KERNEL);
        if (!knew->name)
                return -ENOMEM;
+       if (get_amp_nid_(val))
+               knew->subdevice = HDA_SUBDEV_NID_FLAG | get_amp_nid_(val);
        knew->private_value = val;
        return 0;
 }
 
+static int add_control_with_pfx(struct alc_spec *spec, int type,
+                               const char *pfx, const char *dir,
+                               const char *sfx, unsigned long val)
+{
+       char name[32];
+       snprintf(name, sizeof(name), "%s %s %s", pfx, dir, sfx);
+       return add_control(spec, type, name, val);
+}
+
+#define add_pb_vol_ctrl(spec, type, pfx, val) \
+       add_control_with_pfx(spec, type, pfx, "Playback", "Volume", val)
+#define add_pb_sw_ctrl(spec, type, pfx, val) \
+       add_control_with_pfx(spec, type, pfx, "Playback", "Switch", val)
+
 #define alc880_is_fixed_pin(nid)       ((nid) >= 0x14 && (nid) <= 0x17)
 #define alc880_fixed_pin_idx(nid)      ((nid) - 0x14)
 #define alc880_is_multi_pin(nid)       ((nid) >= 0x18)
@@ -4379,7 +4398,6 @@ static int alc880_auto_fill_dac_nids(struct alc_spec *spec,
 static int alc880_auto_create_multi_out_ctls(struct alc_spec *spec,
                                             const struct auto_pin_cfg *cfg)
 {
-       char name[32];
        static const char *chname[4] = {
                "Front", "Surround", NULL /*CLFE*/, "Side"
        };
@@ -4392,26 +4410,26 @@ static int alc880_auto_create_multi_out_ctls(struct alc_spec *spec,
                nid = alc880_idx_to_mixer(alc880_dac_to_idx(spec->multiout.dac_nids[i]));
                if (i == 2) {
                        /* Center/LFE */
-                       err = add_control(spec, ALC_CTL_WIDGET_VOL,
-                                         "Center Playback Volume",
+                       err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL,
+                                             "Center",
                                          HDA_COMPOSE_AMP_VAL(nid, 1, 0,
                                                              HDA_OUTPUT));
                        if (err < 0)
                                return err;
-                       err = add_control(spec, ALC_CTL_WIDGET_VOL,
-                                         "LFE Playback Volume",
+                       err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL,
+                                             "LFE",
                                          HDA_COMPOSE_AMP_VAL(nid, 2, 0,
                                                              HDA_OUTPUT));
                        if (err < 0)
                                return err;
-                       err = add_control(spec, ALC_CTL_BIND_MUTE,
-                                         "Center Playback Switch",
+                       err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE,
+                                            "Center",
                                          HDA_COMPOSE_AMP_VAL(nid, 1, 2,
                                                              HDA_INPUT));
                        if (err < 0)
                                return err;
-                       err = add_control(spec, ALC_CTL_BIND_MUTE,
-                                         "LFE Playback Switch",
+                       err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE,
+                                            "LFE",
                                          HDA_COMPOSE_AMP_VAL(nid, 2, 2,
                                                              HDA_INPUT));
                        if (err < 0)
@@ -4423,14 +4441,12 @@ static int alc880_auto_create_multi_out_ctls(struct alc_spec *spec,
                                pfx = "Speaker";
                        else
                                pfx = chname[i];
-                       sprintf(name, "%s Playback Volume", pfx);
-                       err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
+                       err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx,
                                          HDA_COMPOSE_AMP_VAL(nid, 3, 0,
                                                              HDA_OUTPUT));
                        if (err < 0)
                                return err;
-                       sprintf(name, "%s Playback Switch", pfx);
-                       err = add_control(spec, ALC_CTL_BIND_MUTE, name,
+                       err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE, pfx,
                                          HDA_COMPOSE_AMP_VAL(nid, 3, 2,
                                                              HDA_INPUT));
                        if (err < 0)
@@ -4446,7 +4462,6 @@ static int alc880_auto_create_extra_out(struct alc_spec *spec, hda_nid_t pin,
 {
        hda_nid_t nid;
        int err;
-       char name[32];
 
        if (!pin)
                return 0;
@@ -4460,21 +4475,18 @@ static int alc880_auto_create_extra_out(struct alc_spec *spec, hda_nid_t pin,
                        spec->multiout.extra_out_nid[0] = nid;
                /* control HP volume/switch on the output mixer amp */
                nid = alc880_idx_to_mixer(alc880_fixed_pin_idx(pin));
-               sprintf(name, "%s Playback Volume", pfx);
-               err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
+               err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx,
                                  HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
                if (err < 0)
                        return err;
-               sprintf(name, "%s Playback Switch", pfx);
-               err = add_control(spec, ALC_CTL_BIND_MUTE, name,
+               err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE, pfx,
                                  HDA_COMPOSE_AMP_VAL(nid, 3, 2, HDA_INPUT));
                if (err < 0)
                        return err;
        } else if (alc880_is_multi_pin(pin)) {
                /* set manual connection */
                /* we have only a switch on HP-out PIN */
-               sprintf(name, "%s Playback Switch", pfx);
-               err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
+               err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx,
                                  HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
                if (err < 0)
                        return err;
@@ -4487,16 +4499,13 @@ static int new_analog_input(struct alc_spec *spec, hda_nid_t pin,
                            const char *ctlname,
                            int idx, hda_nid_t mix_nid)
 {
-       char name[32];
        int err;
 
-       sprintf(name, "%s Playback Volume", ctlname);
-       err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
+       err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, ctlname,
                          HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT));
        if (err < 0)
                return err;
-       sprintf(name, "%s Playback Switch", ctlname);
-       err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
+       err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, ctlname,
                          HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT));
        if (err < 0)
                return err;
@@ -4773,8 +4782,12 @@ static void set_capture_mixer(struct hda_codec *codec)
        }
 }
 
+#ifdef CONFIG_SND_HDA_INPUT_BEEP
 #define set_beep_amp(spec, nid, idx, dir) \
        ((spec)->beep_amp = HDA_COMPOSE_AMP_VAL(nid, 3, idx, dir))
+#else
+#define set_beep_amp(spec, nid, idx, dir) /* NOP */
+#endif
 
 /*
  * OK, here we have finally the patch for ALC880
@@ -5087,11 +5100,8 @@ static struct hda_verb alc260_hp_unsol_verbs[] = {
 static void alc260_hp_automute(struct hda_codec *codec)
 {
        struct alc_spec *spec = codec->spec;
-       unsigned int present;
 
-       present = snd_hda_codec_read(codec, 0x10, 0,
-                                    AC_VERB_GET_PIN_SENSE, 0);
-       spec->jack_present = (present & AC_PINSENSE_PRESENCE) != 0;
+       spec->jack_present = snd_hda_jack_detect(codec, 0x10);
        alc260_hp_master_update(codec, 0x0f, 0x10, 0x11);
 }
 
@@ -5156,11 +5166,8 @@ static struct hda_verb alc260_hp_3013_unsol_verbs[] = {
 static void alc260_hp_3013_automute(struct hda_codec *codec)
 {
        struct alc_spec *spec = codec->spec;
-       unsigned int present;
 
-       present = snd_hda_codec_read(codec, 0x15, 0,
-                                    AC_VERB_GET_PIN_SENSE, 0);
-       spec->jack_present = (present & AC_PINSENSE_PRESENCE) != 0;
+       spec->jack_present = snd_hda_jack_detect(codec, 0x15);
        alc260_hp_master_update(codec, 0x15, 0x10, 0x11);
 }
 
@@ -5173,12 +5180,8 @@ static void alc260_hp_3013_unsol_event(struct hda_codec *codec,
 
 static void alc260_hp_3012_automute(struct hda_codec *codec)
 {
-       unsigned int present, bits;
-
-       present = snd_hda_codec_read(codec, 0x10, 0,
-                       AC_VERB_GET_PIN_SENSE, 0) & AC_PINSENSE_PRESENCE;
+       unsigned int bits = snd_hda_jack_detect(codec, 0x10) ? 0 : PIN_OUT;
 
-       bits = present ? 0 : PIN_OUT;
        snd_hda_codec_write(codec, 0x0f, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
                            bits);
        snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
@@ -5748,8 +5751,7 @@ static void alc260_replacer_672v_automute(struct hda_codec *codec)
         unsigned int present;
 
        /* speaker --> GPIO Data 0, hp or spdif --> GPIO data 1 */
-        present = snd_hda_codec_read(codec, 0x0f, 0,
-                                     AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
+       present = snd_hda_jack_detect(codec, 0x0f);
        if (present) {
                snd_hda_codec_write_cache(codec, 0x01, 0,
                                          AC_VERB_SET_GPIO_DATA, 1);
@@ -5989,7 +5991,6 @@ static int alc260_add_playback_controls(struct alc_spec *spec, hda_nid_t nid,
 {
        hda_nid_t nid_vol;
        unsigned long vol_val, sw_val;
-       char name[32];
        int err;
 
        if (nid >= 0x0f && nid < 0x11) {
@@ -6009,14 +6010,12 @@ static int alc260_add_playback_controls(struct alc_spec *spec, hda_nid_t nid,
 
        if (!(*vol_bits & (1 << nid_vol))) {
                /* first control for the volume widget */
-               snprintf(name, sizeof(name), "%s Playback Volume", pfx);
-               err = add_control(spec, ALC_CTL_WIDGET_VOL, name, vol_val);
+               err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx, vol_val);
                if (err < 0)
                        return err;
                *vol_bits |= (1 << nid_vol);
        }
-       snprintf(name, sizeof(name), "%s Playback Switch", pfx);
-       err = add_control(spec, ALC_CTL_WIDGET_MUTE, name, sw_val);
+       err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx, sw_val);
        if (err < 0)
                return err;
        return 1;
@@ -7336,8 +7335,8 @@ static struct snd_kcontrol_new alc882_macpro_mixer[] = {
        HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT),
        HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT),
        /* FIXME: this looks suspicious...
-       HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x02, HDA_INPUT),
-       HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x02, HDA_INPUT),
+       HDA_CODEC_VOLUME("Beep Playback Volume", 0x0b, 0x02, HDA_INPUT),
+       HDA_CODEC_MUTE("Beep Playback Switch", 0x0b, 0x02, HDA_INPUT),
        */
        { } /* end */
 };
@@ -8184,12 +8183,8 @@ static void alc883_mitac_setup(struct hda_codec *codec)
 /*
 static void alc883_mitac_mic_automute(struct hda_codec *codec)
 {
-       unsigned int present;
-       unsigned char bits;
+       unsigned char bits = snd_hda_jack_detect(codec, 0x18) ? HDA_AMP_MUTE : 0;
 
-       present = snd_hda_codec_read(codec, 0x18, 0,
-                                    AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
-       bits = present ? HDA_AMP_MUTE : 0;
        snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1, HDA_AMP_MUTE, bits);
 }
 */
@@ -8411,10 +8406,8 @@ static struct hda_channel_mode alc888_3st_hp_modes[3] = {
 /* toggle front-jack and RCA according to the hp-jack state */
 static void alc888_lenovo_ms7195_front_automute(struct hda_codec *codec)
 {
-       unsigned int present;
+       unsigned int present = snd_hda_jack_detect(codec, 0x1b);
 
-       present = snd_hda_codec_read(codec, 0x1b, 0,
-                                    AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
        snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
                                 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
        snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
@@ -8424,10 +8417,8 @@ static void alc888_lenovo_ms7195_front_automute(struct hda_codec *codec)
 /* toggle RCA according to the front-jack state */
 static void alc888_lenovo_ms7195_rca_automute(struct hda_codec *codec)
 {
-       unsigned int present;
+       unsigned int present = snd_hda_jack_detect(codec, 0x14);
 
-       present = snd_hda_codec_read(codec, 0x14, 0,
-                                    AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
        snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
                                 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
 }
@@ -8468,8 +8459,7 @@ static void alc883_clevo_m720_mic_automute(struct hda_codec *codec)
 {
        unsigned int present;
 
-       present = snd_hda_codec_read(codec, 0x18, 0,
-                                    AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
+       present = snd_hda_jack_detect(codec, 0x18);
        snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1,
                                 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
 }
@@ -8520,24 +8510,16 @@ static void alc883_haier_w66_setup(struct hda_codec *codec)
 
 static void alc883_lenovo_101e_ispeaker_automute(struct hda_codec *codec)
 {
-       unsigned int present;
-       unsigned char bits;
+       int bits = snd_hda_jack_detect(codec, 0x14) ? HDA_AMP_MUTE : 0;
 
-       present = snd_hda_codec_read(codec, 0x14, 0, AC_VERB_GET_PIN_SENSE, 0)
-               & AC_PINSENSE_PRESENCE;
-       bits = present ? HDA_AMP_MUTE : 0;
        snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
                                 HDA_AMP_MUTE, bits);
 }
 
 static void alc883_lenovo_101e_all_automute(struct hda_codec *codec)
 {
-       unsigned int present;
-       unsigned char bits;
+       int bits = snd_hda_jack_detect(codec, 0x1b) ? HDA_AMP_MUTE : 0;
 
-       present = snd_hda_codec_read(codec, 0x1b, 0,
-                                    AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
-       bits = present ? HDA_AMP_MUTE : 0;
        snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
                                 HDA_AMP_MUTE, bits);
        snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
@@ -8688,8 +8670,7 @@ static void alc889A_mb31_automute(struct hda_codec *codec)
        /* Mute only in 2ch or 4ch mode */
        if (snd_hda_codec_read(codec, 0x15, 0, AC_VERB_GET_CONNECT_SEL, 0)
            == 0x00) {
-               present = snd_hda_codec_read(codec, 0x15, 0,
-                       AC_VERB_GET_PIN_SENSE, 0) & AC_PINSENSE_PRESENCE;
+               present = snd_hda_jack_detect(codec, 0x15);
                snd_hda_codec_amp_stereo(codec, 0x14,  HDA_OUTPUT, 0,
                        HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
                snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
@@ -10032,10 +10013,8 @@ static void alc262_hp_master_update(struct hda_codec *codec)
 static void alc262_hp_bpc_automute(struct hda_codec *codec)
 {
        struct alc_spec *spec = codec->spec;
-       unsigned int presence;
-       presence = snd_hda_codec_read(codec, 0x1b, 0,
-                                     AC_VERB_GET_PIN_SENSE, 0);
-       spec->jack_present = !!(presence & AC_PINSENSE_PRESENCE);
+
+       spec->jack_present = snd_hda_jack_detect(codec, 0x1b);
        alc262_hp_master_update(codec);
 }
 
@@ -10049,10 +10028,8 @@ static void alc262_hp_bpc_unsol_event(struct hda_codec *codec, unsigned int res)
 static void alc262_hp_wildwest_automute(struct hda_codec *codec)
 {
        struct alc_spec *spec = codec->spec;
-       unsigned int presence;
-       presence = snd_hda_codec_read(codec, 0x15, 0,
-                                     AC_VERB_GET_PIN_SENSE, 0);
-       spec->jack_present = !!(presence & AC_PINSENSE_PRESENCE);
+
+       spec->jack_present = snd_hda_jack_detect(codec, 0x15);
        alc262_hp_master_update(codec);
 }
 
@@ -10286,13 +10263,8 @@ static void alc262_hippo_automute(struct hda_codec *codec)
 {
        struct alc_spec *spec = codec->spec;
        hda_nid_t hp_nid = spec->autocfg.hp_pins[0];
-       unsigned int present;
 
-       /* need to execute and sync at first */
-       snd_hda_codec_read(codec, hp_nid, 0, AC_VERB_SET_PIN_SENSE, 0);
-       present = snd_hda_codec_read(codec, hp_nid, 0,
-                                    AC_VERB_GET_PIN_SENSE, 0);
-       spec->jack_present = (present & 0x80000000) != 0;
+       spec->jack_present = snd_hda_jack_detect(codec, hp_nid);
        alc262_hippo_master_update(codec);
 }
 
@@ -10618,21 +10590,8 @@ static void alc262_fujitsu_automute(struct hda_codec *codec, int force)
        unsigned int mute;
 
        if (force || !spec->sense_updated) {
-               unsigned int present;
-               /* need to execute and sync at first */
-               snd_hda_codec_read(codec, 0x14, 0, AC_VERB_SET_PIN_SENSE, 0);
-               /* check laptop HP jack */
-               present = snd_hda_codec_read(codec, 0x14, 0,
-                                            AC_VERB_GET_PIN_SENSE, 0);
-               /* need to execute and sync at first */
-               snd_hda_codec_read(codec, 0x1b, 0, AC_VERB_SET_PIN_SENSE, 0);
-               /* check docking HP jack */
-               present |= snd_hda_codec_read(codec, 0x1b, 0,
-                                             AC_VERB_GET_PIN_SENSE, 0);
-               if (present & AC_PINSENSE_PRESENCE)
-                       spec->jack_present = 1;
-               else
-                       spec->jack_present = 0;
+               spec->jack_present = snd_hda_jack_detect(codec, 0x14) ||
+                                    snd_hda_jack_detect(codec, 0x1b);
                spec->sense_updated = 1;
        }
        /* unmute internal speaker only if both HPs are unplugged and
@@ -10677,12 +10636,7 @@ static void alc262_lenovo_3000_automute(struct hda_codec *codec, int force)
        unsigned int mute;
 
        if (force || !spec->sense_updated) {
-               unsigned int present_int_hp;
-               /* need to execute and sync at first */
-               snd_hda_codec_read(codec, 0x1b, 0, AC_VERB_SET_PIN_SENSE, 0);
-               present_int_hp = snd_hda_codec_read(codec, 0x1b, 0,
-                                       AC_VERB_GET_PIN_SENSE, 0);
-               spec->jack_present = (present_int_hp & 0x80000000) != 0;
+               spec->jack_present = snd_hda_jack_detect(codec, 0x1b);
                spec->sense_updated = 1;
        }
        if (spec->jack_present) {
@@ -10874,12 +10828,7 @@ static void alc262_ultra_automute(struct hda_codec *codec)
        mute = 0;
        /* auto-mute only when HP is used as HP */
        if (!spec->cur_mux[0]) {
-               unsigned int present;
-               /* need to execute and sync at first */
-               snd_hda_codec_read(codec, 0x15, 0, AC_VERB_SET_PIN_SENSE, 0);
-               present = snd_hda_codec_read(codec, 0x15, 0,
-                                            AC_VERB_GET_PIN_SENSE, 0);
-               spec->jack_present = (present & AC_PINSENSE_PRESENCE) != 0;
+               spec->jack_present = snd_hda_jack_detect(codec, 0x15);
                if (spec->jack_present)
                        mute = HDA_AMP_MUTE;
        }
@@ -10956,7 +10905,6 @@ static int alc262_check_volbit(hda_nid_t nid)
 static int alc262_add_out_vol_ctl(struct alc_spec *spec, hda_nid_t nid,
                                  const char *pfx, int *vbits)
 {
-       char name[32];
        unsigned long val;
        int vbit;
 
@@ -10966,28 +10914,25 @@ static int alc262_add_out_vol_ctl(struct alc_spec *spec, hda_nid_t nid,
        if (*vbits & vbit) /* a volume control for this mixer already there */
                return 0;
        *vbits |= vbit;
-       snprintf(name, sizeof(name), "%s Playback Volume", pfx);
        if (vbit == 2)
                val = HDA_COMPOSE_AMP_VAL(0x0e, 2, 0, HDA_OUTPUT);
        else
                val = HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT);
-       return add_control(spec, ALC_CTL_WIDGET_VOL, name, val);
+       return add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx, val);
 }
 
 static int alc262_add_out_sw_ctl(struct alc_spec *spec, hda_nid_t nid,
                                 const char *pfx)
 {
-       char name[32];
        unsigned long val;
 
        if (!nid)
                return 0;
-       snprintf(name, sizeof(name), "%s Playback Switch", pfx);
        if (nid == 0x16)
                val = HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT);
        else
                val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
-       return add_control(spec, ALC_CTL_WIDGET_MUTE, name, val);
+       return add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx, val);
 }
 
 /* add playback controls from the parsed DAC table */
@@ -11463,8 +11408,10 @@ static struct snd_pci_quirk alc262_cfg_tbl[] = {
        SND_PCI_QUIRK(0x104d, 0x9025, "Sony VAIO Z21MN", ALC262_TOSHIBA_S06),
        SND_PCI_QUIRK(0x104d, 0x9035, "Sony VAIO VGN-FW170J", ALC262_AUTO),
        SND_PCI_QUIRK(0x104d, 0x9047, "Sony VAIO Type G", ALC262_AUTO),
+#if 0 /* disable the quirk since model=auto works better in recent versions */
        SND_PCI_QUIRK_MASK(0x104d, 0xff00, 0x9000, "Sony VAIO",
                           ALC262_SONY_ASSAMD),
+#endif
        SND_PCI_QUIRK(0x1179, 0x0001, "Toshiba dynabook SS RX1",
                      ALC262_TOSHIBA_RX1),
        SND_PCI_QUIRK(0x1179, 0xff7b, "Toshiba S06", ALC262_TOSHIBA_S06),
@@ -11923,10 +11870,7 @@ static void alc268_acer_automute(struct hda_codec *codec, int force)
        unsigned int mute;
 
        if (force || !spec->sense_updated) {
-               unsigned int present;
-               present = snd_hda_codec_read(codec, 0x14, 0,
-                                        AC_VERB_GET_PIN_SENSE, 0);
-               spec->jack_present = (present & 0x80000000) != 0;
+               spec->jack_present = snd_hda_jack_detect(codec, 0x14);
                spec->sense_updated = 1;
        }
        if (spec->jack_present)
@@ -12045,8 +11989,7 @@ static void alc268_aspire_one_speaker_automute(struct hda_codec *codec)
        unsigned int present;
        unsigned char bits;
 
-       present = snd_hda_codec_read(codec, 0x15, 0,
-                               AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
+       present = snd_hda_jack_detect(codec, 0x15);
        bits = present ? AMP_IN_MUTE(0) : 0;
        snd_hda_codec_amp_stereo(codec, 0x0f, HDA_INPUT, 0,
                                AMP_IN_MUTE(0), bits);
@@ -12327,11 +12270,9 @@ static struct snd_kcontrol_new alc268_test_mixer[] = {
 static int alc268_new_analog_output(struct alc_spec *spec, hda_nid_t nid,
                                    const char *ctlname, int idx)
 {
-       char name[32];
        hda_nid_t dac;
        int err;
 
-       sprintf(name, "%s Playback Volume", ctlname);
        switch (nid) {
        case 0x14:
        case 0x16:
@@ -12345,7 +12286,7 @@ static int alc268_new_analog_output(struct alc_spec *spec, hda_nid_t nid,
        }
        if (spec->multiout.dac_nids[0] != dac &&
            spec->multiout.dac_nids[1] != dac) {
-               err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
+               err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, ctlname,
                                  HDA_COMPOSE_AMP_VAL(dac, 3, idx,
                                                      HDA_OUTPUT));
                if (err < 0)
@@ -12353,12 +12294,11 @@ static int alc268_new_analog_output(struct alc_spec *spec, hda_nid_t nid,
                spec->multiout.dac_nids[spec->multiout.num_dacs++] = dac;
        }
 
-       sprintf(name, "%s Playback Switch", ctlname);
        if (nid != 0x16)
-               err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
+               err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, ctlname,
                          HDA_COMPOSE_AMP_VAL(nid, 3, idx, HDA_OUTPUT));
        else /* mono */
-               err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
+               err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, ctlname,
                          HDA_COMPOSE_AMP_VAL(nid, 2, idx, HDA_OUTPUT));
        if (err < 0)
                return err;
@@ -12388,8 +12328,7 @@ static int alc268_auto_create_multi_out_ctls(struct alc_spec *spec,
 
        nid = cfg->speaker_pins[0];
        if (nid == 0x1d) {
-               err = add_control(spec, ALC_CTL_WIDGET_VOL,
-                                 "Speaker Playback Volume",
+               err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, "Speaker",
                                  HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
                if (err < 0)
                        return err;
@@ -12407,8 +12346,7 @@ static int alc268_auto_create_multi_out_ctls(struct alc_spec *spec,
 
        nid = cfg->line_out_pins[1] | cfg->line_out_pins[2];
        if (nid == 0x16) {
-               err = add_control(spec, ALC_CTL_WIDGET_MUTE,
-                                 "Mono Playback Switch",
+               err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, "Mono",
                                  HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT));
                if (err < 0)
                        return err;
@@ -13034,8 +12972,7 @@ static void alc269_quanta_fl1_speaker_automute(struct hda_codec *codec)
        unsigned int present;
        unsigned char bits;
 
-       present = snd_hda_codec_read(codec, 0x15, 0,
-                       AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
+       present = snd_hda_jack_detect(codec, 0x15);
        bits = present ? AMP_IN_MUTE(0) : 0;
        snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
                        AMP_IN_MUTE(0), bits);
@@ -13060,12 +12997,10 @@ static void alc269_lifebook_speaker_automute(struct hda_codec *codec)
        unsigned char bits;
 
        /* Check laptop headphone socket */
-       present = snd_hda_codec_read(codec, 0x15, 0,
-                       AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
+       present = snd_hda_jack_detect(codec, 0x15);
 
        /* Check port replicator headphone socket */
-       present |= snd_hda_codec_read(codec, 0x1a, 0,
-                       AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
+       present |= snd_hda_jack_detect(codec, 0x1a);
 
        bits = present ? AMP_IN_MUTE(0) : 0;
        snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
@@ -13089,11 +13024,8 @@ static void alc269_lifebook_mic_autoswitch(struct hda_codec *codec)
        unsigned int present_laptop;
        unsigned int present_dock;
 
-       present_laptop = snd_hda_codec_read(codec, 0x18, 0,
-                               AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
-
-       present_dock = snd_hda_codec_read(codec, 0x1b, 0,
-                               AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
+       present_laptop  = snd_hda_jack_detect(codec, 0x18);
+       present_dock    = snd_hda_jack_detect(codec, 0x1b);
 
        /* Laptop mic port overrides dock mic port, design decision */
        if (present_dock)
@@ -13178,8 +13110,7 @@ static void alc269_speaker_automute(struct hda_codec *codec)
        unsigned int present;
        unsigned char bits;
 
-       present = snd_hda_codec_read(codec, 0x15, 0,
-                               AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
+       present = snd_hda_jack_detect(codec, 0x15);
        bits = present ? AMP_IN_MUTE(0) : 0;
        snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
                                AMP_IN_MUTE(0), bits);
@@ -13525,6 +13456,15 @@ static int patch_alc269(struct hda_codec *codec)
 
        alc_fix_pll_init(codec, 0x20, 0x04, 15);
 
+       if ((alc_read_coef_idx(codec, 0) & 0x00f0) == 0x0010){
+               kfree(codec->chip_name);
+               codec->chip_name = kstrdup("ALC259", GFP_KERNEL);
+               if (!codec->chip_name) {
+                       alc_free(codec);
+                       return -ENOMEM;
+               }
+       }
+
        board_config = snd_hda_check_board_config(codec, ALC269_MODEL_LAST,
                                                  alc269_models,
                                                  alc269_cfg_tbl);
@@ -14157,10 +14097,8 @@ static struct hda_verb alc861_toshiba_init_verbs[] = {
 /* toggle speaker-output according to the hp-jack state */
 static void alc861_toshiba_automute(struct hda_codec *codec)
 {
-       unsigned int present;
+       unsigned int present = snd_hda_jack_detect(codec, 0x0f);
 
-       present = snd_hda_codec_read(codec, 0x0f, 0,
-                                    AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
        snd_hda_codec_amp_stereo(codec, 0x16, HDA_INPUT, 0,
                                 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
        snd_hda_codec_amp_stereo(codec, 0x1a, HDA_INPUT, 3,
@@ -14260,9 +14198,7 @@ static int alc861_auto_fill_dac_nids(struct hda_codec *codec,
 static int alc861_create_out_sw(struct hda_codec *codec, const char *pfx,
                                hda_nid_t nid, unsigned int chs)
 {
-       char name[32];
-       snprintf(name, sizeof(name), "%s Playback Switch", pfx);
-       return add_control(codec->spec, ALC_CTL_WIDGET_MUTE, name,
+       return add_pb_sw_ctrl(codec->spec, ALC_CTL_WIDGET_MUTE, pfx,
                           HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT));
 }
 
@@ -14627,6 +14563,27 @@ static struct alc_config_preset alc861_presets[] = {
        },
 };
 
+/* Pin config fixes */
+enum {
+       PINFIX_FSC_AMILO_PI1505,
+};
+
+static struct alc_pincfg alc861_fsc_amilo_pi1505_pinfix[] = {
+       { 0x0b, 0x0221101f }, /* HP */
+       { 0x0f, 0x90170310 }, /* speaker */
+       { }
+};
+
+static const struct alc_fixup alc861_fixups[] = {
+       [PINFIX_FSC_AMILO_PI1505] = {
+               .pins = alc861_fsc_amilo_pi1505_pinfix
+       },
+};
+
+static struct snd_pci_quirk alc861_fixup_tbl[] = {
+       SND_PCI_QUIRK(0x1734, 0x10c7, "FSC Amilo Pi1505", PINFIX_FSC_AMILO_PI1505),
+       {}
+};
 
 static int patch_alc861(struct hda_codec *codec)
 {
@@ -14650,6 +14607,8 @@ static int patch_alc861(struct hda_codec *codec)
                board_config = ALC861_AUTO;
        }
 
+       alc_pick_fixup(codec, alc861_fixup_tbl, alc861_fixups);
+
        if (board_config == ALC861_AUTO) {
                /* automatic parse from the BIOS config */
                err = alc861_parse_auto_config(codec);
@@ -15067,9 +15026,9 @@ static void alc861vd_lenovo_mic_automute(struct hda_codec *codec)
        unsigned int present;
        unsigned char bits;
 
-       present = snd_hda_codec_read(codec, 0x18, 0,
-                                    AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
+       present = snd_hda_jack_detect(codec, 0x18);
        bits = present ? HDA_AMP_MUTE : 0;
+
        snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1,
                                 HDA_AMP_MUTE, bits);
 }
@@ -15386,7 +15345,6 @@ static void alc861vd_auto_init_analog_input(struct hda_codec *codec)
 static int alc861vd_auto_create_multi_out_ctls(struct alc_spec *spec,
                                             const struct auto_pin_cfg *cfg)
 {
-       char name[32];
        static const char *chname[4] = {"Front", "Surround", "CLFE", "Side"};
        hda_nid_t nid_v, nid_s;
        int i, err;
@@ -15403,26 +15361,26 @@ static int alc861vd_auto_create_multi_out_ctls(struct alc_spec *spec,
 
                if (i == 2) {
                        /* Center/LFE */
-                       err = add_control(spec, ALC_CTL_WIDGET_VOL,
-                                         "Center Playback Volume",
+                       err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL,
+                                             "Center",
                                          HDA_COMPOSE_AMP_VAL(nid_v, 1, 0,
                                                              HDA_OUTPUT));
                        if (err < 0)
                                return err;
-                       err = add_control(spec, ALC_CTL_WIDGET_VOL,
-                                         "LFE Playback Volume",
+                       err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL,
+                                             "LFE",
                                          HDA_COMPOSE_AMP_VAL(nid_v, 2, 0,
                                                              HDA_OUTPUT));
                        if (err < 0)
                                return err;
-                       err = add_control(spec, ALC_CTL_BIND_MUTE,
-                                         "Center Playback Switch",
+                       err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE,
+                                            "Center",
                                          HDA_COMPOSE_AMP_VAL(nid_s, 1, 2,
                                                              HDA_INPUT));
                        if (err < 0)
                                return err;
-                       err = add_control(spec, ALC_CTL_BIND_MUTE,
-                                         "LFE Playback Switch",
+                       err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE,
+                                            "LFE",
                                          HDA_COMPOSE_AMP_VAL(nid_s, 2, 2,
                                                              HDA_INPUT));
                        if (err < 0)
@@ -15437,8 +15395,7 @@ static int alc861vd_auto_create_multi_out_ctls(struct alc_spec *spec,
                                        pfx = "PCM";
                        } else
                                pfx = chname[i];
-                       sprintf(name, "%s Playback Volume", pfx);
-                       err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
+                       err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx,
                                          HDA_COMPOSE_AMP_VAL(nid_v, 3, 0,
                                                              HDA_OUTPUT));
                        if (err < 0)
@@ -15446,8 +15403,7 @@ static int alc861vd_auto_create_multi_out_ctls(struct alc_spec *spec,
                        if (cfg->line_outs == 1 &&
                            cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
                                pfx = "Speaker";
-                       sprintf(name, "%s Playback Switch", pfx);
-                       err = add_control(spec, ALC_CTL_BIND_MUTE, name,
+                       err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE, pfx,
                                          HDA_COMPOSE_AMP_VAL(nid_s, 3, 2,
                                                              HDA_INPUT));
                        if (err < 0)
@@ -15465,7 +15421,6 @@ static int alc861vd_auto_create_extra_out(struct alc_spec *spec,
 {
        hda_nid_t nid_v, nid_s;
        int err;
-       char name[32];
 
        if (!pin)
                return 0;
@@ -15483,21 +15438,18 @@ static int alc861vd_auto_create_extra_out(struct alc_spec *spec,
                nid_s = alc861vd_idx_to_mixer_switch(
                                alc880_fixed_pin_idx(pin));
 
-               sprintf(name, "%s Playback Volume", pfx);
-               err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
+               err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx,
                                  HDA_COMPOSE_AMP_VAL(nid_v, 3, 0, HDA_OUTPUT));
                if (err < 0)
                        return err;
-               sprintf(name, "%s Playback Switch", pfx);
-               err = add_control(spec, ALC_CTL_BIND_MUTE, name,
+               err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE, pfx,
                                  HDA_COMPOSE_AMP_VAL(nid_s, 3, 2, HDA_INPUT));
                if (err < 0)
                        return err;
        } else if (alc880_is_multi_pin(pin)) {
                /* set manual connection */
                /* we have only a switch on HP-out PIN */
-               sprintf(name, "%s Playback Switch", pfx);
-               err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
+               err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx,
                                  HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
                if (err < 0)
                        return err;
@@ -16387,9 +16339,9 @@ static void alc662_lenovo_101e_ispeaker_automute(struct hda_codec *codec)
        unsigned int present;
        unsigned char bits;
 
-       present = snd_hda_codec_read(codec, 0x14, 0,
-                                    AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
+       present = snd_hda_jack_detect(codec, 0x14);
        bits = present ? HDA_AMP_MUTE : 0;
+
        snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
                                 HDA_AMP_MUTE, bits);
 }
@@ -16399,9 +16351,9 @@ static void alc662_lenovo_101e_all_automute(struct hda_codec *codec)
        unsigned int present;
        unsigned char bits;
 
-       present = snd_hda_codec_read(codec, 0x1b, 0,
-                                    AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
+       present = snd_hda_jack_detect(codec, 0x1b);
        bits = present ? HDA_AMP_MUTE : 0;
+
        snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
                                 HDA_AMP_MUTE, bits);
        snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
@@ -16460,9 +16412,7 @@ static void alc663_m51va_speaker_automute(struct hda_codec *codec)
        unsigned int present;
        unsigned char bits;
 
-       present = snd_hda_codec_read(codec, 0x21, 0,
-                       AC_VERB_GET_PIN_SENSE, 0)
-                       & AC_PINSENSE_PRESENCE;
+       present = snd_hda_jack_detect(codec, 0x21);
        bits = present ? HDA_AMP_MUTE : 0;
        snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
                                AMP_IN_MUTE(0), bits);
@@ -16475,9 +16425,7 @@ static void alc663_21jd_two_speaker_automute(struct hda_codec *codec)
        unsigned int present;
        unsigned char bits;
 
-       present = snd_hda_codec_read(codec, 0x21, 0,
-                       AC_VERB_GET_PIN_SENSE, 0)
-                       & AC_PINSENSE_PRESENCE;
+       present = snd_hda_jack_detect(codec, 0x21);
        bits = present ? HDA_AMP_MUTE : 0;
        snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
                                AMP_IN_MUTE(0), bits);
@@ -16494,9 +16442,7 @@ static void alc663_15jd_two_speaker_automute(struct hda_codec *codec)
        unsigned int present;
        unsigned char bits;
 
-       present = snd_hda_codec_read(codec, 0x15, 0,
-                       AC_VERB_GET_PIN_SENSE, 0)
-                       & AC_PINSENSE_PRESENCE;
+       present = snd_hda_jack_detect(codec, 0x15);
        bits = present ? HDA_AMP_MUTE : 0;
        snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
                                AMP_IN_MUTE(0), bits);
@@ -16513,9 +16459,7 @@ static void alc662_f5z_speaker_automute(struct hda_codec *codec)
        unsigned int present;
        unsigned char bits;
 
-       present = snd_hda_codec_read(codec, 0x1b, 0,
-                       AC_VERB_GET_PIN_SENSE, 0)
-                       & AC_PINSENSE_PRESENCE;
+       present = snd_hda_jack_detect(codec, 0x1b);
        bits = present ? 0 : PIN_OUT;
        snd_hda_codec_write(codec, 0x14, 0,
                         AC_VERB_SET_PIN_WIDGET_CONTROL, bits);
@@ -16525,12 +16469,8 @@ static void alc663_two_hp_m1_speaker_automute(struct hda_codec *codec)
 {
        unsigned int present1, present2;
 
-       present1 = snd_hda_codec_read(codec, 0x21, 0,
-                       AC_VERB_GET_PIN_SENSE, 0)
-                       & AC_PINSENSE_PRESENCE;
-       present2 = snd_hda_codec_read(codec, 0x15, 0,
-                       AC_VERB_GET_PIN_SENSE, 0)
-                       & AC_PINSENSE_PRESENCE;
+       present1 = snd_hda_jack_detect(codec, 0x21);
+       present2 = snd_hda_jack_detect(codec, 0x15);
 
        if (present1 || present2) {
                snd_hda_codec_write_cache(codec, 0x14, 0,
@@ -16545,12 +16485,8 @@ static void alc663_two_hp_m2_speaker_automute(struct hda_codec *codec)
 {
        unsigned int present1, present2;
 
-       present1 = snd_hda_codec_read(codec, 0x1b, 0,
-                               AC_VERB_GET_PIN_SENSE, 0)
-                               & AC_PINSENSE_PRESENCE;
-       present2 = snd_hda_codec_read(codec, 0x15, 0,
-                               AC_VERB_GET_PIN_SENSE, 0)
-                               & AC_PINSENSE_PRESENCE;
+       present1 = snd_hda_jack_detect(codec, 0x1b);
+       present2 = snd_hda_jack_detect(codec, 0x15);
 
        if (present1 || present2) {
                snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
@@ -16710,9 +16646,7 @@ static void alc663_g71v_hp_automute(struct hda_codec *codec)
        unsigned int present;
        unsigned char bits;
 
-       present = snd_hda_codec_read(codec, 0x21, 0,
-                                    AC_VERB_GET_PIN_SENSE, 0)
-               & AC_PINSENSE_PRESENCE;
+       present = snd_hda_jack_detect(codec, 0x21);
        bits = present ? HDA_AMP_MUTE : 0;
        snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
                                 HDA_AMP_MUTE, bits);
@@ -16725,9 +16659,7 @@ static void alc663_g71v_front_automute(struct hda_codec *codec)
        unsigned int present;
        unsigned char bits;
 
-       present = snd_hda_codec_read(codec, 0x15, 0,
-                                    AC_VERB_GET_PIN_SENSE, 0)
-               & AC_PINSENSE_PRESENCE;
+       present = snd_hda_jack_detect(codec, 0x15);
        bits = present ? HDA_AMP_MUTE : 0;
        snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
                                 HDA_AMP_MUTE, bits);
@@ -17264,21 +17196,17 @@ static int alc662_auto_fill_dac_nids(struct hda_codec *codec,
        return 0;
 }
 
-static int alc662_add_vol_ctl(struct alc_spec *spec, const char *pfx,
+static inline int alc662_add_vol_ctl(struct alc_spec *spec, const char *pfx,
                              hda_nid_t nid, unsigned int chs)
 {
-       char name[32];
-       sprintf(name, "%s Playback Volume", pfx);
-       return add_control(spec, ALC_CTL_WIDGET_VOL, name,
+       return add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx,
                           HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT));
 }
 
-static int alc662_add_sw_ctl(struct alc_spec *spec, const char *pfx,
+static inline int alc662_add_sw_ctl(struct alc_spec *spec, const char *pfx,
                             hda_nid_t nid, unsigned int chs)
 {
-       char name[32];
-       sprintf(name, "%s Playback Switch", pfx);
-       return add_control(spec, ALC_CTL_WIDGET_MUTE, name,
+       return add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx,
                           HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_INPUT));
 }
 
@@ -17356,13 +17284,11 @@ static int alc662_auto_create_extra_out(struct hda_codec *codec, hda_nid_t pin,
                return 0;
        nid = alc662_look_for_dac(codec, pin);
        if (!nid) {
-               char name[32];
                /* the corresponding DAC is already occupied */
                if (!(get_wcaps(codec, pin) & AC_WCAP_OUT_AMP))
                        return 0; /* no way */
                /* create a switch only */
-               sprintf(name, "%s Playback Switch", pfx);
-               return add_control(spec, ALC_CTL_WIDGET_MUTE, name,
+               return add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx,
                                   HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
        }
 
@@ -17538,6 +17464,15 @@ static int patch_alc662(struct hda_codec *codec)
 
        alc_fix_pll_init(codec, 0x20, 0x04, 15);
 
+       if (alc_read_coef_idx(codec, 0)==0x8020){
+               kfree(codec->chip_name);
+               codec->chip_name = kstrdup("ALC661", GFP_KERNEL);
+               if (!codec->chip_name) {
+                       alc_free(codec);
+                       return -ENOMEM;
+               }
+       }
+
        board_config = snd_hda_check_board_config(codec, ALC662_MODEL_LAST,
                                                  alc662_models,
                                                  alc662_cfg_tbl);
@@ -17604,6 +17539,20 @@ static int patch_alc662(struct hda_codec *codec)
        return 0;
 }
 
+static int patch_alc888(struct hda_codec *codec)
+{
+       if ((alc_read_coef_idx(codec, 0) & 0x00f0)==0x0030){
+               kfree(codec->chip_name);
+               codec->chip_name = kstrdup("ALC888-VD", GFP_KERNEL);
+               if (!codec->chip_name) {
+                       alc_free(codec);
+                       return -ENOMEM;
+               }
+               return patch_alc662(codec);
+       }
+       return patch_alc882(codec);
+}
+
 /*
  * patch entries
  */
@@ -17635,8 +17584,9 @@ static struct hda_codec_preset snd_hda_preset_realtek[] = {
        { .id = 0x10ec0887, .name = "ALC887", .patch = patch_alc882 },
        { .id = 0x10ec0888, .rev = 0x100101, .name = "ALC1200",
          .patch = patch_alc882 },
-       { .id = 0x10ec0888, .name = "ALC888", .patch = patch_alc882 },
+       { .id = 0x10ec0888, .name = "ALC888", .patch = patch_alc888 },
        { .id = 0x10ec0889, .name = "ALC889", .patch = patch_alc882 },
+       { .id = 0x10ec0892, .name = "ALC892", .patch = patch_alc662 },
        {} /* terminator */
 };
 
index 86de305..6b0bc04 100644 (file)
@@ -93,6 +93,7 @@ enum {
        STAC_92HD83XXX_REF,
        STAC_92HD83XXX_PWR_REF,
        STAC_DELL_S14,
+       STAC_92HD83XXX_HP,
        STAC_92HD83XXX_MODELS
 };
 
@@ -1085,7 +1086,7 @@ static int stac92xx_build_controls(struct hda_codec *codec)
        if (!spec->auto_mic && spec->num_dmuxes > 0 &&
            snd_hda_get_bool_hint(codec, "separate_dmux") == 1) {
                stac_dmux_mixer.count = spec->num_dmuxes;
-               err = snd_hda_ctl_add(codec,
+               err = snd_hda_ctl_add(codec, 0,
                                  snd_ctl_new1(&stac_dmux_mixer, codec));
                if (err < 0)
                        return err;
@@ -1101,7 +1102,7 @@ static int stac92xx_build_controls(struct hda_codec *codec)
                        spec->spdif_mute = 1;
                }
                stac_smux_mixer.count = spec->num_smuxes;
-               err = snd_hda_ctl_add(codec,
+               err = snd_hda_ctl_add(codec, 0,
                                  snd_ctl_new1(&stac_smux_mixer, codec));
                if (err < 0)
                        return err;
@@ -1624,6 +1625,7 @@ static const char *stac92hd83xxx_models[STAC_92HD83XXX_MODELS] = {
        [STAC_92HD83XXX_REF] = "ref",
        [STAC_92HD83XXX_PWR_REF] = "mic-ref",
        [STAC_DELL_S14] = "dell-s14",
+       [STAC_92HD83XXX_HP] = "hp",
 };
 
 static struct snd_pci_quirk stac92hd83xxx_cfg_tbl[] = {
@@ -1634,6 +1636,8 @@ static struct snd_pci_quirk stac92hd83xxx_cfg_tbl[] = {
                      "DFI LanParty", STAC_92HD83XXX_REF),
        SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x02ba,
                      "unknown Dell", STAC_DELL_S14),
+       SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_HP, 0xff00, 0x3600,
+                     "HP", STAC_92HD83XXX_HP),
        {} /* terminator */
 };
 
@@ -2648,6 +2652,7 @@ static int stac92xx_clfe_switch_put(struct snd_kcontrol *kcontrol,
 enum {
        STAC_CTL_WIDGET_VOL,
        STAC_CTL_WIDGET_MUTE,
+       STAC_CTL_WIDGET_MUTE_BEEP,
        STAC_CTL_WIDGET_MONO_MUX,
        STAC_CTL_WIDGET_HP_SWITCH,
        STAC_CTL_WIDGET_IO_SWITCH,
@@ -2658,6 +2663,7 @@ enum {
 static struct snd_kcontrol_new stac92xx_control_templates[] = {
        HDA_CODEC_VOLUME(NULL, 0, 0, 0),
        HDA_CODEC_MUTE(NULL, 0, 0, 0),
+       HDA_CODEC_MUTE_BEEP(NULL, 0, 0, 0),
        STAC_MONO_MUX,
        STAC_CODEC_HP_SWITCH(NULL),
        STAC_CODEC_IO_SWITCH(NULL, 0),
@@ -2669,7 +2675,8 @@ static struct snd_kcontrol_new stac92xx_control_templates[] = {
 static struct snd_kcontrol_new *
 stac_control_new(struct sigmatel_spec *spec,
                 struct snd_kcontrol_new *ktemp,
-                const char *name)
+                const char *name,
+                hda_nid_t nid)
 {
        struct snd_kcontrol_new *knew;
 
@@ -2685,6 +2692,8 @@ stac_control_new(struct sigmatel_spec *spec,
                spec->kctls.alloced--;
                return NULL;
        }
+       if (nid)
+               knew->subdevice = HDA_SUBDEV_NID_FLAG | nid;
        return knew;
 }
 
@@ -2693,7 +2702,8 @@ static int stac92xx_add_control_temp(struct sigmatel_spec *spec,
                                     int idx, const char *name,
                                     unsigned long val)
 {
-       struct snd_kcontrol_new *knew = stac_control_new(spec, ktemp, name);
+       struct snd_kcontrol_new *knew = stac_control_new(spec, ktemp, name,
+                                                        get_amp_nid_(val));
        if (!knew)
                return -ENOMEM;
        knew->index = idx;
@@ -2764,7 +2774,7 @@ static int stac92xx_add_input_source(struct sigmatel_spec *spec)
        if (!spec->num_adcs || imux->num_items <= 1)
                return 0; /* no need for input source control */
        knew = stac_control_new(spec, &stac_input_src_temp,
-                               stac_input_src_temp.name);
+                               stac_input_src_temp.name, 0);
        if (!knew)
                return -ENOMEM;
        knew->count = spec->num_adcs;
@@ -3221,12 +3231,15 @@ static int stac92xx_auto_create_beep_ctls(struct hda_codec *codec,
 {
        struct sigmatel_spec *spec = codec->spec;
        u32 caps = query_amp_caps(codec, nid, HDA_OUTPUT);
-       int err;
+       int err, type = STAC_CTL_WIDGET_MUTE_BEEP;
+
+       if (spec->anabeep_nid == nid)
+               type = STAC_CTL_WIDGET_MUTE;
 
        /* check for mute support for the the amp */
        if ((caps & AC_AMPCAP_MUTE) >> AC_AMPCAP_MUTE_SHIFT) {
-               err = stac92xx_add_control(spec, STAC_CTL_WIDGET_MUTE,
-                       "PC Beep Playback Switch",
+               err = stac92xx_add_control(spec, type,
+                       "Beep Playback Switch",
                        HDA_COMPOSE_AMP_VAL(nid, 1, 0, HDA_OUTPUT));
                        if (err < 0)
                                return err;
@@ -3235,7 +3248,7 @@ static int stac92xx_auto_create_beep_ctls(struct hda_codec *codec,
        /* check to see if there is volume support for the amp */
        if ((caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT) {
                err = stac92xx_add_control(spec, STAC_CTL_WIDGET_VOL,
-                       "PC Beep Playback Volume",
+                       "Beep Playback Volume",
                        HDA_COMPOSE_AMP_VAL(nid, 1, 0, HDA_OUTPUT));
                        if (err < 0)
                                return err;
@@ -3258,12 +3271,7 @@ static int stac92xx_dig_beep_switch_put(struct snd_kcontrol *kcontrol,
                                        struct snd_ctl_elem_value *ucontrol)
 {
        struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       int enabled = !!ucontrol->value.integer.value[0];
-       if (codec->beep->enabled != enabled) {
-               codec->beep->enabled = enabled;
-               return 1;
-       }
-       return 0;
+       return snd_hda_enable_beep_device(codec, ucontrol->value.integer.value[0]);
 }
 
 static struct snd_kcontrol_new stac92xx_dig_beep_ctrl = {
@@ -3276,7 +3284,7 @@ static struct snd_kcontrol_new stac92xx_dig_beep_ctrl = {
 static int stac92xx_beep_switch_ctl(struct hda_codec *codec)
 {
        return stac92xx_add_control_temp(codec->spec, &stac92xx_dig_beep_ctrl,
-                                        0, "PC Beep Playback Switch", 0);
+                                        0, "Beep Playback Switch", 0);
 }
 #endif
 
@@ -3631,6 +3639,26 @@ static void stac92xx_auto_init_hp_out(struct hda_codec *codec)
        }
 }
 
+static int is_dual_headphones(struct hda_codec *codec)
+{
+       struct sigmatel_spec *spec = codec->spec;
+       int i, valid_hps;
+
+       if (spec->autocfg.line_out_type != AUTO_PIN_SPEAKER_OUT ||
+           spec->autocfg.hp_outs <= 1)
+               return 0;
+       valid_hps = 0;
+       for (i = 0; i < spec->autocfg.hp_outs; i++) {
+               hda_nid_t nid = spec->autocfg.hp_pins[i];
+               unsigned int cfg = snd_hda_codec_get_pincfg(codec, nid);
+               if (get_defcfg_location(cfg) & AC_JACK_LOC_SEPARATE)
+                       continue;
+               valid_hps++;
+       }
+       return (valid_hps > 1);
+}
+
+
 static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out, hda_nid_t dig_in)
 {
        struct sigmatel_spec *spec = codec->spec;
@@ -3647,8 +3675,7 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out
        /* If we have no real line-out pin and multiple hp-outs, HPs should
         * be set up as multi-channel outputs.
         */
-       if (spec->autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT &&
-           spec->autocfg.hp_outs > 1) {
+       if (is_dual_headphones(codec)) {
                /* Copy hp_outs to line_outs, backup line_outs in
                 * speaker_outs so that the following routines can handle
                 * HP pins as primary outputs.
@@ -4329,6 +4356,28 @@ static void stac92xx_free_kctls(struct hda_codec *codec)
        snd_array_free(&spec->kctls);
 }
 
+static void stac92xx_shutup(struct hda_codec *codec)
+{
+       struct sigmatel_spec *spec = codec->spec;
+       int i;
+       hda_nid_t nid;
+
+       /* reset each pin before powering down DAC/ADC to avoid click noise */
+       nid = codec->start_nid;
+       for (i = 0; i < codec->num_nodes; i++, nid++) {
+               unsigned int wcaps = get_wcaps(codec, nid);
+               unsigned int wid_type = get_wcaps_type(wcaps);
+               if (wid_type == AC_WID_PIN)
+                       snd_hda_codec_read(codec, nid, 0,
+                               AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
+       }
+
+       if (spec->eapd_mask)
+               stac_gpio_set(codec, spec->gpio_mask,
+                               spec->gpio_dir, spec->gpio_data &
+                               ~spec->eapd_mask);
+}
+
 static void stac92xx_free(struct hda_codec *codec)
 {
        struct sigmatel_spec *spec = codec->spec;
@@ -4336,6 +4385,7 @@ static void stac92xx_free(struct hda_codec *codec)
        if (! spec)
                return;
 
+       stac92xx_shutup(codec);
        stac92xx_free_jacks(codec);
        snd_array_free(&spec->events);
 
@@ -4386,12 +4436,16 @@ static void stac92xx_reset_pinctl(struct hda_codec *codec, hda_nid_t nid,
                                          pin_ctl & ~flag);
 }
 
-static int get_pin_presence(struct hda_codec *codec, hda_nid_t nid)
+static inline int get_pin_presence(struct hda_codec *codec, hda_nid_t nid)
 {
        if (!nid)
                return 0;
-       if (snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_PIN_SENSE, 0x00)
-           & (1 << 31))
+       /* NOTE: we can't use snd_hda_jack_detect() here because STAC/IDT
+        * codecs behave wrongly when SET_PIN_SENSE is triggered, although
+        * the pincap gives TRIG_REQ bit.
+        */
+       if (snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_PIN_SENSE, 0) &
+           AC_PINSENSE_PRESENCE)
                return 1;
        return 0;
 }
@@ -4791,28 +4845,28 @@ static int stac92xx_hp_check_power_status(struct hda_codec *codec,
 
        return 0;
 }
-#endif
 
-static int stac92xx_suspend(struct hda_codec *codec, pm_message_t state)
+static int idt92hd83xxx_hp_check_power_status(struct hda_codec *codec,
+                                             hda_nid_t nid)
 {
        struct sigmatel_spec *spec = codec->spec;
-       int i;
-       hda_nid_t nid;
 
-       /* reset each pin before powering down DAC/ADC to avoid click noise */
-       nid = codec->start_nid;
-       for (i = 0; i < codec->num_nodes; i++, nid++) {
-               unsigned int wcaps = get_wcaps(codec, nid);
-               unsigned int wid_type = get_wcaps_type(wcaps);
-               if (wid_type == AC_WID_PIN)
-                       snd_hda_codec_read(codec, nid, 0,
-                               AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
-       }
+       if (nid != 0x13)
+               return 0;
+       if (snd_hda_codec_amp_read(codec, nid, 0, HDA_OUTPUT, 0) & HDA_AMP_MUTE)
+               spec->gpio_data |= spec->gpio_led; /* mute LED on */
+       else
+               spec->gpio_data &= ~spec->gpio_led; /* mute LED off */
+       stac_gpio_set(codec, spec->gpio_mask, spec->gpio_dir, spec->gpio_data);
 
-       if (spec->eapd_mask)
-               stac_gpio_set(codec, spec->gpio_mask,
-                               spec->gpio_dir, spec->gpio_data &
-                               ~spec->eapd_mask);
+       return 0;
+}
+
+#endif
+
+static int stac92xx_suspend(struct hda_codec *codec, pm_message_t state)
+{
+       stac92xx_shutup(codec);
        return 0;
 }
 #endif
@@ -4827,6 +4881,7 @@ static struct hda_codec_ops stac92xx_patch_ops = {
        .suspend = stac92xx_suspend,
        .resume = stac92xx_resume,
 #endif
+       .reboot_notify = stac92xx_shutup,
 };
 
 static int patch_stac9200(struct hda_codec *codec)
@@ -5172,6 +5227,22 @@ again:
                break;
        }
 
+       codec->patch_ops = stac92xx_patch_ops;
+
+       if (spec->board_config == STAC_92HD83XXX_HP)
+               spec->gpio_led = 0x01;
+
+#ifdef CONFIG_SND_HDA_POWER_SAVE
+       if (spec->gpio_led) {
+               spec->gpio_mask |= spec->gpio_led;
+               spec->gpio_dir |= spec->gpio_led;
+               spec->gpio_data |= spec->gpio_led;
+               /* register check_power_status callback. */
+               codec->patch_ops.check_power_status =
+                       idt92hd83xxx_hp_check_power_status;
+       }
+#endif 
+
        err = stac92xx_parse_auto_config(codec, 0x1d, 0);
        if (!err) {
                if (spec->board_config < 0) {
@@ -5207,8 +5278,6 @@ again:
        snd_hda_codec_write_cache(codec, nid, 0,
                        AC_VERB_SET_CONNECT_SEL, num_dacs);
 
-       codec->patch_ops = stac92xx_patch_ops;
-
        codec->proc_widget_hook = stac92hd_proc_hook;
 
        return 0;
index ee89db9..b70e26a 100644 (file)
@@ -1,10 +1,10 @@
 /*
  * Universal Interface for Intel High Definition Audio Codec
  *
- * HD audio interface patch for VIA VT1702/VT1708/VT1709 codec
+ * HD audio interface patch for VIA VT17xx/VT18xx/VT20xx codec
  *
- * Copyright (c) 2006-2008 Lydia Wang <lydiawang@viatech.com>
- *                        Takashi Iwai <tiwai@suse.de>
+ *  (C) 2006-2009 VIA Technology, Inc.
+ *  (C) 2006-2008 Takashi Iwai <tiwai@suse.de>
  *
  *  This driver is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
  */
 
 /* * * * * * * * * * * * * * Release History * * * * * * * * * * * * * * * * */
-/*                                                                           */
+/*                                                                          */
 /* 2006-03-03  Lydia Wang  Create the basic patch to support VT1708 codec    */
-/* 2006-03-14  Lydia Wang  Modify hard code for some pin widget nid          */
-/* 2006-08-02  Lydia Wang  Add support to VT1709 codec                       */
+/* 2006-03-14  Lydia Wang  Modify hard code for some pin widget nid         */
+/* 2006-08-02  Lydia Wang  Add support to VT1709 codec                      */
 /* 2006-09-08  Lydia Wang  Fix internal loopback recording source select bug */
-/* 2007-09-12  Lydia Wang  Add EAPD enable during driver initialization      */
-/* 2007-09-17  Lydia Wang  Add VT1708B codec support                        */
+/* 2007-09-12  Lydia Wang  Add EAPD enable during driver initialization             */
+/* 2007-09-17  Lydia Wang  Add VT1708B codec support                       */
 /* 2007-11-14  Lydia Wang  Add VT1708A codec HP and CD pin connect config    */
 /* 2008-02-03  Lydia Wang  Fix Rear channels and Back channels inverse issue */
-/* 2008-03-06  Lydia Wang  Add VT1702 codec and VT1708S codec support        */
-/* 2008-04-09  Lydia Wang  Add mute front speaker when HP plugin             */
-/* 2008-04-09  Lydia Wang  Add Independent HP feature                        */
+/* 2008-03-06  Lydia Wang  Add VT1702 codec and VT1708S codec support       */
+/* 2008-04-09  Lydia Wang  Add mute front speaker when HP plugin            */
+/* 2008-04-09  Lydia Wang  Add Independent HP feature                       */
 /* 2008-05-28  Lydia Wang  Add second S/PDIF Out support for VT1702         */
-/* 2008-09-15  Logan Li    Add VT1708S Mic Boost workaround/backdoor        */
-/*                                                                           */
+/* 2008-09-15  Logan Li           Add VT1708S Mic Boost workaround/backdoor         */
+/* 2009-02-16  Logan Li           Add support for VT1718S                           */
+/* 2009-03-13  Logan Li           Add support for VT1716S                           */
+/* 2009-04-14  Lydai Wang  Add support for VT1828S and VT2020               */
+/* 2009-07-08  Lydia Wang  Add support for VT2002P                          */
+/* 2009-07-21  Lydia Wang  Add support for VT1812                           */
+/* 2009-09-19  Lydia Wang  Add support for VT1818S                          */
+/*                                                                          */
 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
 
 
 #define VT1702_HP_NID          0x17
 #define VT1702_DIGOUT_NID      0x11
 
-#define IS_VT1708_VENDORID(x)          ((x) >= 0x11061708 && (x) <= 0x1106170b)
-#define IS_VT1709_10CH_VENDORID(x)     ((x) >= 0x1106e710 && (x) <= 0x1106e713)
-#define IS_VT1709_6CH_VENDORID(x)      ((x) >= 0x1106e714 && (x) <= 0x1106e717)
-#define IS_VT1708B_8CH_VENDORID(x)     ((x) >= 0x1106e720 && (x) <= 0x1106e723)
-#define IS_VT1708B_4CH_VENDORID(x)     ((x) >= 0x1106e724 && (x) <= 0x1106e727)
-#define IS_VT1708S_VENDORID(x)         ((x) >= 0x11060397 && (x) <= 0x11067397)
-#define IS_VT1702_VENDORID(x)          ((x) >= 0x11060398 && (x) <= 0x11067398)
-
 enum VIA_HDA_CODEC {
        UNKNOWN = -1,
        VT1708,
@@ -92,12 +90,76 @@ enum VIA_HDA_CODEC {
        VT1708B_8CH,
        VT1708B_4CH,
        VT1708S,
+       VT1708BCE,
        VT1702,
+       VT1718S,
+       VT1716S,
+       VT2002P,
+       VT1812,
        CODEC_TYPES,
 };
 
-static enum VIA_HDA_CODEC get_codec_type(u32 vendor_id)
+struct via_spec {
+       /* codec parameterization */
+       struct snd_kcontrol_new *mixers[6];
+       unsigned int num_mixers;
+
+       struct hda_verb *init_verbs[5];
+       unsigned int num_iverbs;
+
+       char *stream_name_analog;
+       struct hda_pcm_stream *stream_analog_playback;
+       struct hda_pcm_stream *stream_analog_capture;
+
+       char *stream_name_digital;
+       struct hda_pcm_stream *stream_digital_playback;
+       struct hda_pcm_stream *stream_digital_capture;
+
+       /* playback */
+       struct hda_multi_out multiout;
+       hda_nid_t slave_dig_outs[2];
+
+       /* capture */
+       unsigned int num_adc_nids;
+       hda_nid_t *adc_nids;
+       hda_nid_t mux_nids[3];
+       hda_nid_t dig_in_nid;
+       hda_nid_t dig_in_pin;
+
+       /* capture source */
+       const struct hda_input_mux *input_mux;
+       unsigned int cur_mux[3];
+
+       /* PCM information */
+       struct hda_pcm pcm_rec[3];
+
+       /* dynamic controls, init_verbs and input_mux */
+       struct auto_pin_cfg autocfg;
+       struct snd_array kctls;
+       struct hda_input_mux private_imux[2];
+       hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS];
+
+       /* HP mode source */
+       const struct hda_input_mux *hp_mux;
+       unsigned int hp_independent_mode;
+       unsigned int hp_independent_mode_index;
+       unsigned int smart51_enabled;
+       unsigned int dmic_enabled;
+       enum VIA_HDA_CODEC codec_type;
+
+       /* work to check hp jack state */
+       struct hda_codec *codec;
+       struct delayed_work vt1708_hp_work;
+       int vt1708_jack_detectect;
+       int vt1708_hp_present;
+#ifdef CONFIG_SND_HDA_POWER_SAVE
+       struct hda_loopback_check loopback;
+#endif
+};
+
+static enum VIA_HDA_CODEC get_codec_type(struct hda_codec *codec)
 {
+       u32 vendor_id = codec->vendor_id;
        u16 ven_id = vendor_id >> 16;
        u16 dev_id = vendor_id & 0xffff;
        enum VIA_HDA_CODEC codec_type;
@@ -111,9 +173,11 @@ static enum VIA_HDA_CODEC get_codec_type(u32 vendor_id)
                codec_type = VT1709_10CH;
        else if (dev_id >= 0xe714 && dev_id <= 0xe717)
                codec_type = VT1709_6CH;
-       else if (dev_id >= 0xe720 && dev_id <= 0xe723)
+       else if (dev_id >= 0xe720 && dev_id <= 0xe723) {
                codec_type = VT1708B_8CH;
-       else if (dev_id >= 0xe724 && dev_id <= 0xe727)
+               if (snd_hda_param_read(codec, 0x16, AC_PAR_CONNLIST_LEN) == 0x7)
+                       codec_type = VT1708BCE;
+       } else if (dev_id >= 0xe724 && dev_id <= 0xe727)
                codec_type = VT1708B_4CH;
        else if ((dev_id & 0xfff) == 0x397
                 && (dev_id >> 12) < 8)
@@ -121,6 +185,19 @@ static enum VIA_HDA_CODEC get_codec_type(u32 vendor_id)
        else if ((dev_id & 0xfff) == 0x398
                 && (dev_id >> 12) < 8)
                codec_type = VT1702;
+       else if ((dev_id & 0xfff) == 0x428
+                && (dev_id >> 12) < 8)
+               codec_type = VT1718S;
+       else if (dev_id == 0x0433 || dev_id == 0xa721)
+               codec_type = VT1716S;
+       else if (dev_id == 0x0441 || dev_id == 0x4441)
+               codec_type = VT1718S;
+       else if (dev_id == 0x0438 || dev_id == 0x4438)
+               codec_type = VT2002P;
+       else if (dev_id == 0x0448)
+               codec_type = VT1812;
+       else if (dev_id == 0x0440)
+               codec_type = VT1708S;
        else
                codec_type = UNKNOWN;
        return codec_type;
@@ -128,10 +205,16 @@ static enum VIA_HDA_CODEC get_codec_type(u32 vendor_id)
 
 #define VIA_HP_EVENT           0x01
 #define VIA_GPIO_EVENT         0x02
+#define VIA_JACK_EVENT         0x04
+#define VIA_MONO_EVENT         0x08
+#define VIA_SPEAKER_EVENT      0x10
+#define VIA_BIND_HP_EVENT      0x20
 
 enum {
        VIA_CTL_WIDGET_VOL,
        VIA_CTL_WIDGET_MUTE,
+       VIA_CTL_WIDGET_ANALOG_MUTE,
+       VIA_CTL_WIDGET_BIND_PIN_MUTE,
 };
 
 enum {
@@ -141,99 +224,162 @@ enum {
        AUTO_SEQ_SIDE
 };
 
-/* Some VT1708S based boards gets the micboost setting wrong, so we have
- * to apply some brute-force and re-write the TLV's by software. */
-static int mic_boost_tlv(struct snd_kcontrol *kcontrol, int op_flag,
-                        unsigned int size, unsigned int __user *_tlv)
+static void analog_low_current_mode(struct hda_codec *codec, int stream_idle);
+static void set_jack_power_state(struct hda_codec *codec);
+static int is_aa_path_mute(struct hda_codec *codec);
+
+static void vt1708_start_hp_work(struct via_spec *spec)
 {
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       hda_nid_t nid = get_amp_nid(kcontrol);
+       if (spec->codec_type != VT1708 || spec->autocfg.hp_pins[0] == 0)
+               return;
+       snd_hda_codec_write(spec->codec, 0x1, 0, 0xf81,
+                           !spec->vt1708_jack_detectect);
+       if (!delayed_work_pending(&spec->vt1708_hp_work))
+               schedule_delayed_work(&spec->vt1708_hp_work,
+                                     msecs_to_jiffies(100));
+}
 
-       if (get_codec_type(codec->vendor_id) == VT1708S
-           && (nid == 0x1a || nid == 0x1e)) {
-               if (size < 4 * sizeof(unsigned int))
-                       return -ENOMEM;
-               if (put_user(1, _tlv))  /* SNDRV_CTL_TLVT_DB_SCALE */
-                       return -EFAULT;
-               if (put_user(2 * sizeof(unsigned int), _tlv + 1))
-                       return -EFAULT;
-               if (put_user(0, _tlv + 2)) /* offset = 0 */
-                       return -EFAULT;
-               if (put_user(1000, _tlv + 3)) /* step size = 10 dB */
-                       return -EFAULT;
-       }
-       return 0;
+static void vt1708_stop_hp_work(struct via_spec *spec)
+{
+       if (spec->codec_type != VT1708 || spec->autocfg.hp_pins[0] == 0)
+               return;
+       if (snd_hda_get_bool_hint(spec->codec, "analog_loopback_hp_detect") == 1
+           && !is_aa_path_mute(spec->codec))
+               return;
+       snd_hda_codec_write(spec->codec, 0x1, 0, 0xf81,
+                           !spec->vt1708_jack_detectect);
+       cancel_delayed_work(&spec->vt1708_hp_work);
+       flush_scheduled_work();
 }
 
-static int mic_boost_volume_info(struct snd_kcontrol *kcontrol,
-                                struct snd_ctl_elem_info *uinfo)
+
+static int analog_input_switch_put(struct snd_kcontrol *kcontrol,
+                                  struct snd_ctl_elem_value *ucontrol)
 {
+       int change = snd_hda_mixer_amp_switch_put(kcontrol, ucontrol);
        struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       hda_nid_t nid = get_amp_nid(kcontrol);
 
-       if (get_codec_type(codec->vendor_id) == VT1708S
-           && (nid == 0x1a || nid == 0x1e)) {
-               uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
-               uinfo->count = 2;
-               uinfo->value.integer.min = 0;
-               uinfo->value.integer.max = 3;
+       set_jack_power_state(codec);
+       analog_low_current_mode(snd_kcontrol_chip(kcontrol), -1);
+       if (snd_hda_get_bool_hint(codec, "analog_loopback_hp_detect") == 1) {
+               if (is_aa_path_mute(codec))
+                       vt1708_start_hp_work(codec->spec);
+               else
+                       vt1708_stop_hp_work(codec->spec);
        }
-       return 0;
+       return change;
 }
 
-static struct snd_kcontrol_new vt1708_control_templates[] = {
-       HDA_CODEC_VOLUME(NULL, 0, 0, 0),
-       HDA_CODEC_MUTE(NULL, 0, 0, 0),
-};
-
-
-struct via_spec {
-       /* codec parameterization */
-       struct snd_kcontrol_new *mixers[3];
-       unsigned int num_mixers;
-
-       struct hda_verb *init_verbs[5];
-       unsigned int num_iverbs;
-
-       char *stream_name_analog;
-       struct hda_pcm_stream *stream_analog_playback;
-       struct hda_pcm_stream *stream_analog_capture;
-
-       char *stream_name_digital;
-       struct hda_pcm_stream *stream_digital_playback;
-       struct hda_pcm_stream *stream_digital_capture;
+/* modify .put = snd_hda_mixer_amp_switch_put */
+#define ANALOG_INPUT_MUTE                                              \
+       {               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,            \
+                       .name = NULL,                                   \
+                       .index = 0,                                     \
+                       .info = snd_hda_mixer_amp_switch_info,          \
+                       .get = snd_hda_mixer_amp_switch_get,            \
+                       .put = analog_input_switch_put,                 \
+                       .private_value = HDA_COMPOSE_AMP_VAL(0, 3, 0, 0) }
 
-       /* playback */
-       struct hda_multi_out multiout;
-       hda_nid_t slave_dig_outs[2];
+static void via_hp_bind_automute(struct hda_codec *codec);
 
-       /* capture */
-       unsigned int num_adc_nids;
-       hda_nid_t *adc_nids;
-       hda_nid_t mux_nids[3];
-       hda_nid_t dig_in_nid;
-       hda_nid_t dig_in_pin;
+static int bind_pin_switch_put(struct snd_kcontrol *kcontrol,
+                              struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct via_spec *spec = codec->spec;
+       int i;
+       int change = 0;
 
-       /* capture source */
-       const struct hda_input_mux *input_mux;
-       unsigned int cur_mux[3];
+       long *valp = ucontrol->value.integer.value;
+       int lmute, rmute;
+       if (strstr(kcontrol->id.name, "Switch") == NULL) {
+               snd_printd("Invalid control!\n");
+               return change;
+       }
+       change = snd_hda_mixer_amp_switch_put(kcontrol,
+                                             ucontrol);
+       /* Get mute value */
+       lmute = *valp ? 0 : HDA_AMP_MUTE;
+       valp++;
+       rmute = *valp ? 0 : HDA_AMP_MUTE;
+
+       /* Set hp pins */
+       if (!spec->hp_independent_mode) {
+               for (i = 0; i < spec->autocfg.hp_outs; i++) {
+                       snd_hda_codec_amp_update(
+                               codec, spec->autocfg.hp_pins[i],
+                               0, HDA_OUTPUT, 0, HDA_AMP_MUTE,
+                               lmute);
+                       snd_hda_codec_amp_update(
+                               codec, spec->autocfg.hp_pins[i],
+                               1, HDA_OUTPUT, 0, HDA_AMP_MUTE,
+                               rmute);
+               }
+       }
 
-       /* PCM information */
-       struct hda_pcm pcm_rec[3];
+       if (!lmute && !rmute) {
+               /* Line Outs */
+               for (i = 0; i < spec->autocfg.line_outs; i++)
+                       snd_hda_codec_amp_stereo(
+                               codec, spec->autocfg.line_out_pins[i],
+                               HDA_OUTPUT, 0, HDA_AMP_MUTE, 0);
+               /* Speakers */
+               for (i = 0; i < spec->autocfg.speaker_outs; i++)
+                       snd_hda_codec_amp_stereo(
+                               codec, spec->autocfg.speaker_pins[i],
+                               HDA_OUTPUT, 0, HDA_AMP_MUTE, 0);
+               /* unmute */
+               via_hp_bind_automute(codec);
 
-       /* dynamic controls, init_verbs and input_mux */
-       struct auto_pin_cfg autocfg;
-       struct snd_array kctls;
-       struct hda_input_mux private_imux[2];
-       hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS];
+       } else {
+               if (lmute) {
+                       /* Mute all left channels */
+                       for (i = 1; i < spec->autocfg.line_outs; i++)
+                               snd_hda_codec_amp_update(
+                                       codec,
+                                       spec->autocfg.line_out_pins[i],
+                                       0, HDA_OUTPUT, 0, HDA_AMP_MUTE,
+                                       lmute);
+                       for (i = 0; i < spec->autocfg.speaker_outs; i++)
+                               snd_hda_codec_amp_update(
+                                       codec,
+                                       spec->autocfg.speaker_pins[i],
+                                       0, HDA_OUTPUT, 0, HDA_AMP_MUTE,
+                                       lmute);
+               }
+               if (rmute) {
+                       /* mute all right channels */
+                       for (i = 1; i < spec->autocfg.line_outs; i++)
+                               snd_hda_codec_amp_update(
+                                       codec,
+                                       spec->autocfg.line_out_pins[i],
+                                       1, HDA_OUTPUT, 0, HDA_AMP_MUTE,
+                                       rmute);
+                       for (i = 0; i < spec->autocfg.speaker_outs; i++)
+                               snd_hda_codec_amp_update(
+                                       codec,
+                                       spec->autocfg.speaker_pins[i],
+                                       1, HDA_OUTPUT, 0, HDA_AMP_MUTE,
+                                       rmute);
+               }
+       }
+       return change;
+}
 
-       /* HP mode source */
-       const struct hda_input_mux *hp_mux;
-       unsigned int hp_independent_mode;
+#define BIND_PIN_MUTE                                                  \
+       {               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,            \
+                       .name = NULL,                                   \
+                       .index = 0,                                     \
+                       .info = snd_hda_mixer_amp_switch_info,          \
+                       .get = snd_hda_mixer_amp_switch_get,            \
+                       .put = bind_pin_switch_put,                     \
+                       .private_value = HDA_COMPOSE_AMP_VAL(0, 3, 0, 0) }
 
-#ifdef CONFIG_SND_HDA_POWER_SAVE
-       struct hda_loopback_check loopback;
-#endif
+static struct snd_kcontrol_new via_control_templates[] = {
+       HDA_CODEC_VOLUME(NULL, 0, 0, 0),
+       HDA_CODEC_MUTE(NULL, 0, 0, 0),
+       ANALOG_INPUT_MUTE,
+       BIND_PIN_MUTE,
 };
 
 static hda_nid_t vt1708_adc_nids[2] = {
@@ -261,6 +407,27 @@ static hda_nid_t vt1702_adc_nids[3] = {
        0x12, 0x20, 0x1F
 };
 
+static hda_nid_t vt1718S_adc_nids[2] = {
+       /* ADC1-2 */
+       0x10, 0x11
+};
+
+static hda_nid_t vt1716S_adc_nids[2] = {
+       /* ADC1-2 */
+       0x13, 0x14
+};
+
+static hda_nid_t vt2002P_adc_nids[2] = {
+       /* ADC1-2 */
+       0x10, 0x11
+};
+
+static hda_nid_t vt1812_adc_nids[2] = {
+       /* ADC1-2 */
+       0x10, 0x11
+};
+
+
 /* add dynamic controls */
 static int via_add_control(struct via_spec *spec, int type, const char *name,
                           unsigned long val)
@@ -271,10 +438,12 @@ static int via_add_control(struct via_spec *spec, int type, const char *name,
        knew = snd_array_new(&spec->kctls);
        if (!knew)
                return -ENOMEM;
-       *knew = vt1708_control_templates[type];
+       *knew = via_control_templates[type];
        knew->name = kstrdup(name, GFP_KERNEL);
        if (!knew->name)
                return -ENOMEM;
+       if (get_amp_nid_(val))
+               knew->subdevice = HDA_SUBDEV_NID_FLAG | get_amp_nid_(val);
        knew->private_value = val;
        return 0;
 }
@@ -293,8 +462,8 @@ static void via_free_kctls(struct hda_codec *codec)
 }
 
 /* create input playback/capture controls for the given pin */
-static int via_new_analog_input(struct via_spec *spec, hda_nid_t pin,
-                               const char *ctlname, int idx, int mix_nid)
+static int via_new_analog_input(struct via_spec *spec, const char *ctlname,
+                               int idx, int mix_nid)
 {
        char name[32];
        int err;
@@ -305,7 +474,7 @@ static int via_new_analog_input(struct via_spec *spec, hda_nid_t pin,
        if (err < 0)
                return err;
        sprintf(name, "%s Playback Switch", ctlname);
-       err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
+       err = via_add_control(spec, VIA_CTL_WIDGET_ANALOG_MUTE, name,
                              HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT));
        if (err < 0)
                return err;
@@ -322,7 +491,7 @@ static void via_auto_set_output_and_unmute(struct hda_codec *codec,
        snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
                            AMP_OUT_UNMUTE);
        if (snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_EAPD)
-               snd_hda_codec_write(codec, nid, 0, 
+               snd_hda_codec_write(codec, nid, 0,
                                    AC_VERB_SET_EAPD_BTLENABLE, 0x02);
 }
 
@@ -343,10 +512,13 @@ static void via_auto_init_hp_out(struct hda_codec *codec)
 {
        struct via_spec *spec = codec->spec;
        hda_nid_t pin;
+       int i;
 
-       pin = spec->autocfg.hp_pins[0];
-       if (pin) /* connect to front */
-               via_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
+       for (i = 0; i < spec->autocfg.hp_outs; i++) {
+               pin = spec->autocfg.hp_pins[i];
+               if (pin) /* connect to front */
+                       via_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
+       }
 }
 
 static void via_auto_init_analog_input(struct hda_codec *codec)
@@ -364,6 +536,502 @@ static void via_auto_init_analog_input(struct hda_codec *codec)
 
        }
 }
+
+static int is_smart51_pins(struct via_spec *spec, hda_nid_t pin);
+
+static void set_pin_power_state(struct hda_codec *codec, hda_nid_t nid,
+                               unsigned int *affected_parm)
+{
+       unsigned parm;
+       unsigned def_conf = snd_hda_codec_get_pincfg(codec, nid);
+       unsigned no_presence = (def_conf & AC_DEFCFG_MISC)
+               >> AC_DEFCFG_MISC_SHIFT
+               & AC_DEFCFG_MISC_NO_PRESENCE; /* do not support pin sense */
+       unsigned present = snd_hda_jack_detect(codec, nid);
+       struct via_spec *spec = codec->spec;
+       if ((spec->smart51_enabled && is_smart51_pins(spec, nid))
+           || ((no_presence || present)
+               && get_defcfg_connect(def_conf) != AC_JACK_PORT_NONE)) {
+               *affected_parm = AC_PWRST_D0; /* if it's connected */
+               parm = AC_PWRST_D0;
+       } else
+               parm = AC_PWRST_D3;
+
+       snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_POWER_STATE, parm);
+}
+
+static void set_jack_power_state(struct hda_codec *codec)
+{
+       struct via_spec *spec = codec->spec;
+       int imux_is_smixer;
+       unsigned int parm;
+
+       if (spec->codec_type == VT1702) {
+               imux_is_smixer = snd_hda_codec_read(
+                       codec, 0x13, 0, AC_VERB_GET_CONNECT_SEL, 0x00) == 3;
+               /* inputs */
+               /* PW 1/2/5 (14h/15h/18h) */
+               parm = AC_PWRST_D3;
+               set_pin_power_state(codec, 0x14, &parm);
+               set_pin_power_state(codec, 0x15, &parm);
+               set_pin_power_state(codec, 0x18, &parm);
+               if (imux_is_smixer)
+                       parm = AC_PWRST_D0; /* SW0 = stereo mixer (idx 3) */
+               /* SW0 (13h), AIW 0/1/2 (12h/1fh/20h) */
+               snd_hda_codec_write(codec, 0x13, 0, AC_VERB_SET_POWER_STATE,
+                                   parm);
+               snd_hda_codec_write(codec, 0x12, 0, AC_VERB_SET_POWER_STATE,
+                                   parm);
+               snd_hda_codec_write(codec, 0x1f, 0, AC_VERB_SET_POWER_STATE,
+                                   parm);
+               snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_POWER_STATE,
+                                   parm);
+
+               /* outputs */
+               /* PW 3/4 (16h/17h) */
+               parm = AC_PWRST_D3;
+               set_pin_power_state(codec, 0x16, &parm);
+               set_pin_power_state(codec, 0x17, &parm);
+               /* MW0 (1ah), AOW 0/1 (10h/1dh) */
+               snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_POWER_STATE,
+                                   imux_is_smixer ? AC_PWRST_D0 : parm);
+               snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE,
+                                   parm);
+               snd_hda_codec_write(codec, 0x1d, 0, AC_VERB_SET_POWER_STATE,
+                                   parm);
+       } else if (spec->codec_type == VT1708B_8CH
+                  || spec->codec_type == VT1708B_4CH
+                  || spec->codec_type == VT1708S) {
+               /* SW0 (17h) = stereo mixer */
+               int is_8ch = spec->codec_type != VT1708B_4CH;
+               imux_is_smixer = snd_hda_codec_read(
+                       codec, 0x17, 0, AC_VERB_GET_CONNECT_SEL, 0x00)
+                       == ((spec->codec_type == VT1708S)  ? 5 : 0);
+               /* inputs */
+               /* PW 1/2/5 (1ah/1bh/1eh) */
+               parm = AC_PWRST_D3;
+               set_pin_power_state(codec, 0x1a, &parm);
+               set_pin_power_state(codec, 0x1b, &parm);
+               set_pin_power_state(codec, 0x1e, &parm);
+               if (imux_is_smixer)
+                       parm = AC_PWRST_D0;
+               /* SW0 (17h), AIW 0/1 (13h/14h) */
+               snd_hda_codec_write(codec, 0x17, 0, AC_VERB_SET_POWER_STATE,
+                                   parm);
+               snd_hda_codec_write(codec, 0x13, 0, AC_VERB_SET_POWER_STATE,
+                                   parm);
+               snd_hda_codec_write(codec, 0x14, 0, AC_VERB_SET_POWER_STATE,
+                                   parm);
+
+               /* outputs */
+               /* PW0 (19h), SW1 (18h), AOW1 (11h) */
+               parm = AC_PWRST_D3;
+               set_pin_power_state(codec, 0x19, &parm);
+               snd_hda_codec_write(codec, 0x18, 0, AC_VERB_SET_POWER_STATE,
+                                   parm);
+               snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_POWER_STATE,
+                                   parm);
+
+               /* PW6 (22h), SW2 (26h), AOW2 (24h) */
+               if (is_8ch) {
+                       parm = AC_PWRST_D3;
+                       set_pin_power_state(codec, 0x22, &parm);
+                       snd_hda_codec_write(codec, 0x26, 0,
+                                           AC_VERB_SET_POWER_STATE, parm);
+                       snd_hda_codec_write(codec, 0x24, 0,
+                                           AC_VERB_SET_POWER_STATE, parm);
+               }
+
+               /* PW 3/4/7 (1ch/1dh/23h) */
+               parm = AC_PWRST_D3;
+               /* force to D0 for internal Speaker */
+               set_pin_power_state(codec, 0x1c, &parm);
+               set_pin_power_state(codec, 0x1d, &parm);
+               if (is_8ch)
+                       set_pin_power_state(codec, 0x23, &parm);
+               /* MW0 (16h), Sw3 (27h), AOW 0/3 (10h/25h) */
+               snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_POWER_STATE,
+                                   imux_is_smixer ? AC_PWRST_D0 : parm);
+               snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE,
+                                   parm);
+               if (is_8ch) {
+                       snd_hda_codec_write(codec, 0x25, 0,
+                                           AC_VERB_SET_POWER_STATE, parm);
+                       snd_hda_codec_write(codec, 0x27, 0,
+                                           AC_VERB_SET_POWER_STATE, parm);
+               }
+       }  else if (spec->codec_type == VT1718S) {
+               /* MUX6 (1eh) = stereo mixer */
+               imux_is_smixer = snd_hda_codec_read(
+                       codec, 0x1e, 0, AC_VERB_GET_CONNECT_SEL, 0x00) == 5;
+               /* inputs */
+               /* PW 5/6/7 (29h/2ah/2bh) */
+               parm = AC_PWRST_D3;
+               set_pin_power_state(codec, 0x29, &parm);
+               set_pin_power_state(codec, 0x2a, &parm);
+               set_pin_power_state(codec, 0x2b, &parm);
+               if (imux_is_smixer)
+                       parm = AC_PWRST_D0;
+               /* MUX6/7 (1eh/1fh), AIW 0/1 (10h/11h) */
+               snd_hda_codec_write(codec, 0x1e, 0, AC_VERB_SET_POWER_STATE,
+                                   parm);
+               snd_hda_codec_write(codec, 0x1f, 0, AC_VERB_SET_POWER_STATE,
+                                   parm);
+               snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE,
+                                   parm);
+               snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_POWER_STATE,
+                                   parm);
+
+               /* outputs */
+               /* PW3 (27h), MW2 (1ah), AOW3 (bh) */
+               parm = AC_PWRST_D3;
+               set_pin_power_state(codec, 0x27, &parm);
+               snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_POWER_STATE,
+                                   parm);
+               snd_hda_codec_write(codec, 0xb, 0, AC_VERB_SET_POWER_STATE,
+                                   parm);
+
+               /* PW2 (26h), AOW2 (ah) */
+               parm = AC_PWRST_D3;
+               set_pin_power_state(codec, 0x26, &parm);
+               snd_hda_codec_write(codec, 0xa, 0, AC_VERB_SET_POWER_STATE,
+                                   parm);
+
+               /* PW0/1 (24h/25h) */
+               parm = AC_PWRST_D3;
+               set_pin_power_state(codec, 0x24, &parm);
+               set_pin_power_state(codec, 0x25, &parm);
+               if (!spec->hp_independent_mode) /* check for redirected HP */
+                       set_pin_power_state(codec, 0x28, &parm);
+               snd_hda_codec_write(codec, 0x8, 0, AC_VERB_SET_POWER_STATE,
+                                   parm);
+               snd_hda_codec_write(codec, 0x9, 0, AC_VERB_SET_POWER_STATE,
+                                   parm);
+               /* MW9 (21h), Mw2 (1ah), AOW0 (8h) */
+               snd_hda_codec_write(codec, 0x21, 0, AC_VERB_SET_POWER_STATE,
+                                   imux_is_smixer ? AC_PWRST_D0 : parm);
+               if (spec->hp_independent_mode) {
+                       /* PW4 (28h), MW3 (1bh), MUX1(34h), AOW4 (ch) */
+                       parm = AC_PWRST_D3;
+                       set_pin_power_state(codec, 0x28, &parm);
+                       snd_hda_codec_write(codec, 0x1b, 0,
+                                           AC_VERB_SET_POWER_STATE, parm);
+                       snd_hda_codec_write(codec, 0x34, 0,
+                                           AC_VERB_SET_POWER_STATE, parm);
+                       snd_hda_codec_write(codec, 0xc, 0,
+                                           AC_VERB_SET_POWER_STATE, parm);
+               }
+       } else if (spec->codec_type == VT1716S) {
+               unsigned int mono_out, present;
+               /* SW0 (17h) = stereo mixer */
+               imux_is_smixer = snd_hda_codec_read(
+                       codec, 0x17, 0, AC_VERB_GET_CONNECT_SEL, 0x00) ==  5;
+               /* inputs */
+               /* PW 1/2/5 (1ah/1bh/1eh) */
+               parm = AC_PWRST_D3;
+               set_pin_power_state(codec, 0x1a, &parm);
+               set_pin_power_state(codec, 0x1b, &parm);
+               set_pin_power_state(codec, 0x1e, &parm);
+               if (imux_is_smixer)
+                       parm = AC_PWRST_D0;
+               /* SW0 (17h), AIW0(13h) */
+               snd_hda_codec_write(codec, 0x17, 0, AC_VERB_SET_POWER_STATE,
+                                   parm);
+               snd_hda_codec_write(codec, 0x13, 0, AC_VERB_SET_POWER_STATE,
+                                   parm);
+
+               parm = AC_PWRST_D3;
+               set_pin_power_state(codec, 0x1e, &parm);
+               /* PW11 (22h) */
+               if (spec->dmic_enabled)
+                       set_pin_power_state(codec, 0x22, &parm);
+               else
+                       snd_hda_codec_write(
+                               codec, 0x22, 0,
+                               AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
+
+               /* SW2(26h), AIW1(14h) */
+               snd_hda_codec_write(codec, 0x26, 0, AC_VERB_SET_POWER_STATE,
+                                   parm);
+               snd_hda_codec_write(codec, 0x14, 0, AC_VERB_SET_POWER_STATE,
+                                   parm);
+
+               /* outputs */
+               /* PW0 (19h), SW1 (18h), AOW1 (11h) */
+               parm = AC_PWRST_D3;
+               set_pin_power_state(codec, 0x19, &parm);
+               /* Smart 5.1 PW2(1bh) */
+               if (spec->smart51_enabled)
+                       set_pin_power_state(codec, 0x1b, &parm);
+               snd_hda_codec_write(codec, 0x18, 0, AC_VERB_SET_POWER_STATE,
+                                   parm);
+               snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_POWER_STATE,
+                                   parm);
+
+               /* PW7 (23h), SW3 (27h), AOW3 (25h) */
+               parm = AC_PWRST_D3;
+               set_pin_power_state(codec, 0x23, &parm);
+               /* Smart 5.1 PW1(1ah) */
+               if (spec->smart51_enabled)
+                       set_pin_power_state(codec, 0x1a, &parm);
+               snd_hda_codec_write(codec, 0x27, 0, AC_VERB_SET_POWER_STATE,
+                                   parm);
+
+               /* Smart 5.1 PW5(1eh) */
+               if (spec->smart51_enabled)
+                       set_pin_power_state(codec, 0x1e, &parm);
+               snd_hda_codec_write(codec, 0x25, 0, AC_VERB_SET_POWER_STATE,
+                                   parm);
+
+               /* Mono out */
+               /* SW4(28h)->MW1(29h)-> PW12 (2ah)*/
+               present = snd_hda_jack_detect(codec, 0x1c);
+               if (present)
+                       mono_out = 0;
+               else {
+                       present = snd_hda_jack_detect(codec, 0x1d);
+                       if (!spec->hp_independent_mode && present)
+                               mono_out = 0;
+                       else
+                               mono_out = 1;
+               }
+               parm = mono_out ? AC_PWRST_D0 : AC_PWRST_D3;
+               snd_hda_codec_write(codec, 0x28, 0, AC_VERB_SET_POWER_STATE,
+                                   parm);
+               snd_hda_codec_write(codec, 0x29, 0, AC_VERB_SET_POWER_STATE,
+                                   parm);
+               snd_hda_codec_write(codec, 0x2a, 0, AC_VERB_SET_POWER_STATE,
+                                   parm);
+
+               /* PW 3/4 (1ch/1dh) */
+               parm = AC_PWRST_D3;
+               set_pin_power_state(codec, 0x1c, &parm);
+               set_pin_power_state(codec, 0x1d, &parm);
+               /* HP Independent Mode, power on AOW3 */
+               if (spec->hp_independent_mode)
+                       snd_hda_codec_write(codec, 0x25, 0,
+                                           AC_VERB_SET_POWER_STATE, parm);
+
+               /* force to D0 for internal Speaker */
+               /* MW0 (16h), AOW0 (10h) */
+               snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_POWER_STATE,
+                                   imux_is_smixer ? AC_PWRST_D0 : parm);
+               snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE,
+                                   mono_out ? AC_PWRST_D0 : parm);
+       } else if (spec->codec_type == VT2002P) {
+               unsigned int present;
+               /* MUX9 (1eh) = stereo mixer */
+               imux_is_smixer = snd_hda_codec_read(
+                       codec, 0x1e, 0, AC_VERB_GET_CONNECT_SEL, 0x00) == 3;
+               /* inputs */
+               /* PW 5/6/7 (29h/2ah/2bh) */
+               parm = AC_PWRST_D3;
+               set_pin_power_state(codec, 0x29, &parm);
+               set_pin_power_state(codec, 0x2a, &parm);
+               set_pin_power_state(codec, 0x2b, &parm);
+               if (imux_is_smixer)
+                       parm = AC_PWRST_D0;
+               /* MUX9/10 (1eh/1fh), AIW 0/1 (10h/11h) */
+               snd_hda_codec_write(codec, 0x1e, 0,
+                                   AC_VERB_SET_POWER_STATE, parm);
+               snd_hda_codec_write(codec, 0x1f, 0,
+                                   AC_VERB_SET_POWER_STATE, parm);
+               snd_hda_codec_write(codec, 0x10, 0,
+                                   AC_VERB_SET_POWER_STATE, parm);
+               snd_hda_codec_write(codec, 0x11, 0,
+                                   AC_VERB_SET_POWER_STATE, parm);
+
+               /* outputs */
+               /* AOW0 (8h)*/
+               snd_hda_codec_write(codec, 0x8, 0,
+                                   AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
+
+               /* PW4 (26h), MW4 (1ch), MUX4(37h) */
+               parm = AC_PWRST_D3;
+               set_pin_power_state(codec, 0x26, &parm);
+               snd_hda_codec_write(codec, 0x1c, 0,
+                                   AC_VERB_SET_POWER_STATE, parm);
+               snd_hda_codec_write(codec, 0x37,
+                                   0, AC_VERB_SET_POWER_STATE, parm);
+
+               /* PW1 (25h), MW1 (19h), MUX1(35h), AOW1 (9h) */
+               parm = AC_PWRST_D3;
+               set_pin_power_state(codec, 0x25, &parm);
+               snd_hda_codec_write(codec, 0x19, 0,
+                                   AC_VERB_SET_POWER_STATE, parm);
+               snd_hda_codec_write(codec, 0x35, 0,
+                                   AC_VERB_SET_POWER_STATE, parm);
+               if (spec->hp_independent_mode)  {
+                       snd_hda_codec_write(codec, 0x9, 0,
+                                           AC_VERB_SET_POWER_STATE, parm);
+               }
+
+               /* Class-D */
+               /* PW0 (24h), MW0(18h), MUX0(34h) */
+               present = snd_hda_jack_detect(codec, 0x25);
+               parm = AC_PWRST_D3;
+               set_pin_power_state(codec, 0x24, &parm);
+               if (present) {
+                       snd_hda_codec_write(
+                               codec, 0x18, 0,
+                               AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
+                       snd_hda_codec_write(
+                               codec, 0x34, 0,
+                               AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
+               } else {
+                       snd_hda_codec_write(
+                               codec, 0x18, 0,
+                               AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
+                       snd_hda_codec_write(
+                               codec, 0x34, 0,
+                               AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
+               }
+
+               /* Mono Out */
+               /* PW15 (31h), MW8(17h), MUX8(3bh) */
+               present = snd_hda_jack_detect(codec, 0x26);
+               parm = AC_PWRST_D3;
+               set_pin_power_state(codec, 0x31, &parm);
+               if (present) {
+                       snd_hda_codec_write(
+                               codec, 0x17, 0,
+                               AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
+                       snd_hda_codec_write(
+                               codec, 0x3b, 0,
+                               AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
+               } else {
+                       snd_hda_codec_write(
+                               codec, 0x17, 0,
+                               AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
+                       snd_hda_codec_write(
+                               codec, 0x3b, 0,
+                               AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
+               }
+
+               /* MW9 (21h) */
+               if (imux_is_smixer || !is_aa_path_mute(codec))
+                       snd_hda_codec_write(
+                               codec, 0x21, 0,
+                               AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
+               else
+                       snd_hda_codec_write(
+                               codec, 0x21, 0,
+                               AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
+       } else if (spec->codec_type == VT1812) {
+               unsigned int present;
+               /* MUX10 (1eh) = stereo mixer */
+               imux_is_smixer = snd_hda_codec_read(
+                       codec, 0x1e, 0, AC_VERB_GET_CONNECT_SEL, 0x00) == 5;
+               /* inputs */
+               /* PW 5/6/7 (29h/2ah/2bh) */
+               parm = AC_PWRST_D3;
+               set_pin_power_state(codec, 0x29, &parm);
+               set_pin_power_state(codec, 0x2a, &parm);
+               set_pin_power_state(codec, 0x2b, &parm);
+               if (imux_is_smixer)
+                       parm = AC_PWRST_D0;
+               /* MUX10/11 (1eh/1fh), AIW 0/1 (10h/11h) */
+               snd_hda_codec_write(codec, 0x1e, 0,
+                                   AC_VERB_SET_POWER_STATE, parm);
+               snd_hda_codec_write(codec, 0x1f, 0,
+                                   AC_VERB_SET_POWER_STATE, parm);
+               snd_hda_codec_write(codec, 0x10, 0,
+                                   AC_VERB_SET_POWER_STATE, parm);
+               snd_hda_codec_write(codec, 0x11, 0,
+                                   AC_VERB_SET_POWER_STATE, parm);
+
+               /* outputs */
+               /* AOW0 (8h)*/
+               snd_hda_codec_write(codec, 0x8, 0,
+                                   AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
+
+               /* PW4 (28h), MW4 (18h), MUX4(38h) */
+               parm = AC_PWRST_D3;
+               set_pin_power_state(codec, 0x28, &parm);
+               snd_hda_codec_write(codec, 0x18, 0,
+                                   AC_VERB_SET_POWER_STATE, parm);
+               snd_hda_codec_write(codec, 0x38, 0,
+                                   AC_VERB_SET_POWER_STATE, parm);
+
+               /* PW1 (25h), MW1 (15h), MUX1(35h), AOW1 (9h) */
+               parm = AC_PWRST_D3;
+               set_pin_power_state(codec, 0x25, &parm);
+               snd_hda_codec_write(codec, 0x15, 0,
+                                   AC_VERB_SET_POWER_STATE, parm);
+               snd_hda_codec_write(codec, 0x35, 0,
+                                   AC_VERB_SET_POWER_STATE, parm);
+               if (spec->hp_independent_mode)  {
+                       snd_hda_codec_write(codec, 0x9, 0,
+                                           AC_VERB_SET_POWER_STATE, parm);
+               }
+
+               /* Internal Speaker */
+               /* PW0 (24h), MW0(14h), MUX0(34h) */
+               present = snd_hda_jack_detect(codec, 0x25);
+               parm = AC_PWRST_D3;
+               set_pin_power_state(codec, 0x24, &parm);
+               if (present) {
+                       snd_hda_codec_write(codec, 0x14, 0,
+                                           AC_VERB_SET_POWER_STATE,
+                                           AC_PWRST_D3);
+                       snd_hda_codec_write(codec, 0x34, 0,
+                                           AC_VERB_SET_POWER_STATE,
+                                           AC_PWRST_D3);
+               } else {
+                       snd_hda_codec_write(codec, 0x14, 0,
+                                           AC_VERB_SET_POWER_STATE,
+                                           AC_PWRST_D0);
+                       snd_hda_codec_write(codec, 0x34, 0,
+                                           AC_VERB_SET_POWER_STATE,
+                                           AC_PWRST_D0);
+               }
+               /* Mono Out */
+               /* PW13 (31h), MW13(1ch), MUX13(3ch), MW14(3eh) */
+               present = snd_hda_jack_detect(codec, 0x28);
+               parm = AC_PWRST_D3;
+               set_pin_power_state(codec, 0x31, &parm);
+               if (present) {
+                       snd_hda_codec_write(codec, 0x1c, 0,
+                                           AC_VERB_SET_POWER_STATE,
+                                           AC_PWRST_D3);
+                       snd_hda_codec_write(codec, 0x3c, 0,
+                                           AC_VERB_SET_POWER_STATE,
+                                           AC_PWRST_D3);
+                       snd_hda_codec_write(codec, 0x3e, 0,
+                                           AC_VERB_SET_POWER_STATE,
+                                           AC_PWRST_D3);
+               } else {
+                       snd_hda_codec_write(codec, 0x1c, 0,
+                                           AC_VERB_SET_POWER_STATE,
+                                           AC_PWRST_D0);
+                       snd_hda_codec_write(codec, 0x3c, 0,
+                                           AC_VERB_SET_POWER_STATE,
+                                           AC_PWRST_D0);
+                       snd_hda_codec_write(codec, 0x3e, 0,
+                                           AC_VERB_SET_POWER_STATE,
+                                           AC_PWRST_D0);
+               }
+
+               /* PW15 (33h), MW15 (1dh), MUX15(3dh) */
+               parm = AC_PWRST_D3;
+               set_pin_power_state(codec, 0x33, &parm);
+               snd_hda_codec_write(codec, 0x1d, 0,
+                                   AC_VERB_SET_POWER_STATE, parm);
+               snd_hda_codec_write(codec, 0x3d, 0,
+                                   AC_VERB_SET_POWER_STATE, parm);
+
+               /* MW9 (21h) */
+               if (imux_is_smixer || !is_aa_path_mute(codec))
+                       snd_hda_codec_write(
+                               codec, 0x21, 0,
+                               AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
+               else
+                       snd_hda_codec_write(
+                               codec, 0x21, 0,
+                               AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
+       }
+}
+
 /*
  * input MUX handling
  */
@@ -395,6 +1063,14 @@ static int via_mux_enum_put(struct snd_kcontrol *kcontrol,
 
        if (!spec->mux_nids[adc_idx])
                return -EINVAL;
+       /* switch to D0 beofre change index */
+       if (snd_hda_codec_read(codec, spec->mux_nids[adc_idx], 0,
+                              AC_VERB_GET_POWER_STATE, 0x00) != AC_PWRST_D0)
+               snd_hda_codec_write(codec, spec->mux_nids[adc_idx], 0,
+                                   AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
+       /* update jack power state */
+       set_jack_power_state(codec);
+
        return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
                                     spec->mux_nids[adc_idx],
                                     &spec->cur_mux[adc_idx]);
@@ -413,16 +1089,74 @@ static int via_independent_hp_get(struct snd_kcontrol *kcontrol,
 {
        struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
        struct via_spec *spec = codec->spec;
-       hda_nid_t nid = spec->autocfg.hp_pins[0];
-       unsigned int pinsel = snd_hda_codec_read(codec, nid, 0,
-                                                AC_VERB_GET_CONNECT_SEL,
-                                                0x00);
-
+       hda_nid_t nid;
+       unsigned int pinsel;
+
+       switch (spec->codec_type) {
+       case VT1718S:
+               nid = 0x34;
+               break;
+       case VT2002P:
+               nid = 0x35;
+               break;
+       case VT1812:
+               nid = 0x3d;
+               break;
+       default:
+               nid = spec->autocfg.hp_pins[0];
+               break;
+       }
+       /* use !! to translate conn sel 2 for VT1718S */
+       pinsel = !!snd_hda_codec_read(codec, nid, 0,
+                                     AC_VERB_GET_CONNECT_SEL,
+                                     0x00);
        ucontrol->value.enumerated.item[0] = pinsel;
 
        return 0;
 }
 
+static void activate_ctl(struct hda_codec *codec, const char *name, int active)
+{
+       struct snd_kcontrol *ctl = snd_hda_find_mixer_ctl(codec, name);
+       if (ctl) {
+               ctl->vd[0].access &= ~SNDRV_CTL_ELEM_ACCESS_INACTIVE;
+               ctl->vd[0].access |= active
+                       ? 0 : SNDRV_CTL_ELEM_ACCESS_INACTIVE;
+               snd_ctl_notify(codec->bus->card,
+                              SNDRV_CTL_EVENT_MASK_VALUE, &ctl->id);
+       }
+}
+
+static int update_side_mute_status(struct hda_codec *codec)
+{
+       /* mute side channel */
+       struct via_spec *spec = codec->spec;
+       unsigned int parm = spec->hp_independent_mode
+               ? AMP_OUT_MUTE : AMP_OUT_UNMUTE;
+       hda_nid_t sw3;
+
+       switch (spec->codec_type) {
+       case VT1708:
+               sw3 = 0x1b;
+               break;
+       case VT1709_10CH:
+               sw3 = 0x29;
+               break;
+       case VT1708B_8CH:
+       case VT1708S:
+               sw3 = 0x27;
+               break;
+       default:
+               sw3 = 0;
+               break;
+       }
+
+       if (sw3)
+               snd_hda_codec_write(codec, sw3, 0, AC_VERB_SET_AMP_GAIN_MUTE,
+                                   parm);
+       return 0;
+}
+
 static int via_independent_hp_put(struct snd_kcontrol *kcontrol,
                                  struct snd_ctl_elem_value *ucontrol)
 {
@@ -430,47 +1164,46 @@ static int via_independent_hp_put(struct snd_kcontrol *kcontrol,
        struct via_spec *spec = codec->spec;
        hda_nid_t nid = spec->autocfg.hp_pins[0];
        unsigned int pinsel = ucontrol->value.enumerated.item[0];
-       unsigned int con_nid = snd_hda_codec_read(codec, nid, 0,
-                                        AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
-
-       if (con_nid == spec->multiout.hp_nid) {
-               if (pinsel == 0) {
-                       if (!spec->hp_independent_mode) {
-                               if (spec->multiout.num_dacs > 1)
-                                       spec->multiout.num_dacs -= 1;
-                               spec->hp_independent_mode = 1;
-                       }
-               } else if (pinsel == 1) {
-                      if (spec->hp_independent_mode) {
-                               if (spec->multiout.num_dacs > 1)
-                                       spec->multiout.num_dacs += 1;
-                               spec->hp_independent_mode = 0;
-                      }
-               }
-       } else {
-               if (pinsel == 0) {
-                       if (spec->hp_independent_mode) {
-                               if (spec->multiout.num_dacs > 1)
-                                       spec->multiout.num_dacs += 1;
-                               spec->hp_independent_mode = 0;
-                       }
-               } else if (pinsel == 1) {
-                      if (!spec->hp_independent_mode) {
-                               if (spec->multiout.num_dacs > 1)
-                                       spec->multiout.num_dacs -= 1;
-                               spec->hp_independent_mode = 1;
-                      }
-               }
+       /* Get Independent Mode index of headphone pin widget */
+       spec->hp_independent_mode = spec->hp_independent_mode_index == pinsel
+               ? 1 : 0;
+
+       switch (spec->codec_type) {
+       case VT1718S:
+               nid = 0x34;
+               pinsel = pinsel ? 2 : 0; /* indep HP use AOW4 (index 2) */
+               spec->multiout.num_dacs = 4;
+               break;
+       case VT2002P:
+               nid = 0x35;
+               break;
+       case VT1812:
+               nid = 0x3d;
+               break;
+       default:
+               nid = spec->autocfg.hp_pins[0];
+               break;
+       }
+       snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, pinsel);
+
+       if (spec->multiout.hp_nid && spec->multiout.hp_nid
+           != spec->multiout.dac_nids[HDA_FRONT])
+               snd_hda_codec_setup_stream(codec, spec->multiout.hp_nid,
+                                          0, 0, 0);
+
+       update_side_mute_status(codec);
+       /* update HP volume/swtich active state */
+       if (spec->codec_type == VT1708S
+           || spec->codec_type == VT1702
+           || spec->codec_type == VT1718S
+           || spec->codec_type == VT1716S
+           || spec->codec_type == VT2002P
+           || spec->codec_type == VT1812) {
+               activate_ctl(codec, "Headphone Playback Volume",
+                            spec->hp_independent_mode);
+               activate_ctl(codec, "Headphone Playback Switch",
+                            spec->hp_independent_mode);
        }
-       snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL,
-                           pinsel);
-
-       if (spec->multiout.hp_nid &&
-           spec->multiout.hp_nid != spec->multiout.dac_nids[HDA_FRONT])
-                       snd_hda_codec_setup_stream(codec,
-                                                  spec->multiout.hp_nid,
-                                                  0, 0, 0);
-
        return 0;
 }
 
@@ -486,6 +1219,175 @@ static struct snd_kcontrol_new via_hp_mixer[] = {
        { } /* end */
 };
 
+static void notify_aa_path_ctls(struct hda_codec *codec)
+{
+       int i;
+       struct snd_ctl_elem_id id;
+       const char *labels[] = {"Mic", "Front Mic", "Line"};
+
+       memset(&id, 0, sizeof(id));
+       id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+       for (i = 0; i < ARRAY_SIZE(labels); i++) {
+               sprintf(id.name, "%s Playback Volume", labels[i]);
+               snd_ctl_notify(codec->bus->card, SNDRV_CTL_EVENT_MASK_VALUE,
+                              &id);
+       }
+}
+
+static void mute_aa_path(struct hda_codec *codec, int mute)
+{
+       struct via_spec *spec = codec->spec;
+       hda_nid_t  nid_mixer;
+       int start_idx;
+       int end_idx;
+       int i;
+       /* get nid of MW0 and start & end index */
+       switch (spec->codec_type) {
+       case VT1708:
+               nid_mixer = 0x17;
+               start_idx = 2;
+               end_idx = 4;
+               break;
+       case VT1709_10CH:
+       case VT1709_6CH:
+               nid_mixer = 0x18;
+               start_idx = 2;
+               end_idx = 4;
+               break;
+       case VT1708B_8CH:
+       case VT1708B_4CH:
+       case VT1708S:
+       case VT1716S:
+               nid_mixer = 0x16;
+               start_idx = 2;
+               end_idx = 4;
+               break;
+       default:
+               return;
+       }
+       /* check AA path's mute status */
+       for (i = start_idx; i <= end_idx; i++) {
+               int val = mute ? HDA_AMP_MUTE : HDA_AMP_UNMUTE;
+               snd_hda_codec_amp_stereo(codec, nid_mixer, HDA_INPUT, i,
+                                        HDA_AMP_MUTE, val);
+       }
+}
+static int is_smart51_pins(struct via_spec *spec, hda_nid_t pin)
+{
+       int res = 0;
+       int index;
+       for (index = AUTO_PIN_MIC; index < AUTO_PIN_FRONT_LINE; index++) {
+               if (pin == spec->autocfg.input_pins[index]) {
+                       res = 1;
+                       break;
+               }
+       }
+       return res;
+}
+
+static int via_smart51_info(struct snd_kcontrol *kcontrol,
+                           struct snd_ctl_elem_info *uinfo)
+{
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+       uinfo->count = 1;
+       uinfo->value.integer.min = 0;
+       uinfo->value.integer.max = 1;
+       return 0;
+}
+
+static int via_smart51_get(struct snd_kcontrol *kcontrol,
+                          struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct via_spec *spec = codec->spec;
+       int index[] = { AUTO_PIN_MIC, AUTO_PIN_FRONT_MIC, AUTO_PIN_LINE };
+       int on = 1;
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(index); i++) {
+               hda_nid_t nid = spec->autocfg.input_pins[index[i]];
+               if (nid) {
+                       int ctl =
+                           snd_hda_codec_read(codec, nid, 0,
+                                              AC_VERB_GET_PIN_WIDGET_CONTROL,
+                                              0);
+                       if (i == AUTO_PIN_FRONT_MIC
+                           && spec->hp_independent_mode
+                           && spec->codec_type != VT1718S)
+                               continue; /* ignore FMic for independent HP */
+                       if (ctl & AC_PINCTL_IN_EN
+                           && !(ctl & AC_PINCTL_OUT_EN))
+                               on = 0;
+               }
+       }
+       *ucontrol->value.integer.value = on;
+       return 0;
+}
+
+static int via_smart51_put(struct snd_kcontrol *kcontrol,
+                          struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct via_spec *spec = codec->spec;
+       int out_in = *ucontrol->value.integer.value
+               ? AC_PINCTL_OUT_EN : AC_PINCTL_IN_EN;
+       int index[] = { AUTO_PIN_MIC, AUTO_PIN_FRONT_MIC, AUTO_PIN_LINE };
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(index); i++) {
+               hda_nid_t nid = spec->autocfg.input_pins[index[i]];
+               if (i == AUTO_PIN_FRONT_MIC
+                   && spec->hp_independent_mode
+                   && spec->codec_type != VT1718S)
+                       continue; /* don't retask FMic for independent HP */
+               if (nid) {
+                       unsigned int parm = snd_hda_codec_read(
+                               codec, nid, 0,
+                               AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
+                       parm &= ~(AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN);
+                       parm |= out_in;
+                       snd_hda_codec_write(codec, nid, 0,
+                                           AC_VERB_SET_PIN_WIDGET_CONTROL,
+                                           parm);
+                       if (out_in == AC_PINCTL_OUT_EN) {
+                               mute_aa_path(codec, 1);
+                               notify_aa_path_ctls(codec);
+                       }
+                       if (spec->codec_type == VT1718S)
+                               snd_hda_codec_amp_stereo(
+                                       codec, nid, HDA_OUTPUT, 0, HDA_AMP_MUTE,
+                                       HDA_AMP_UNMUTE);
+               }
+               if (i == AUTO_PIN_FRONT_MIC) {
+                       if (spec->codec_type == VT1708S
+                           || spec->codec_type == VT1716S) {
+                               /* input = index 1 (AOW3) */
+                               snd_hda_codec_write(
+                                       codec, nid, 0,
+                                       AC_VERB_SET_CONNECT_SEL, 1);
+                               snd_hda_codec_amp_stereo(
+                                       codec, nid, HDA_OUTPUT,
+                                       0, HDA_AMP_MUTE, HDA_AMP_UNMUTE);
+                       }
+               }
+       }
+       spec->smart51_enabled = *ucontrol->value.integer.value;
+       set_jack_power_state(codec);
+       return 1;
+}
+
+static struct snd_kcontrol_new via_smart51_mixer[] = {
+       {
+        .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+        .name = "Smart 5.1",
+        .count = 1,
+        .info = via_smart51_info,
+        .get = via_smart51_get,
+        .put = via_smart51_put,
+        },
+       {}                      /* end */
+};
+
 /* capture mixer elements */
 static struct snd_kcontrol_new vt1708_capture_mixer[] = {
        HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_INPUT),
@@ -506,15 +1408,121 @@ static struct snd_kcontrol_new vt1708_capture_mixer[] = {
        },
        { } /* end */
 };
-/*
- * generic initialization of ADC, input mixers and output mixers
- */
-static struct hda_verb vt1708_volume_init_verbs[] = {
-       /*
-        * Unmute ADC0-1 and set the default input to mic-in
-        */
-       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+
+/* check AA path's mute statue */
+static int is_aa_path_mute(struct hda_codec *codec)
+{
+       int mute = 1;
+       hda_nid_t  nid_mixer;
+       int start_idx;
+       int end_idx;
+       int i;
+       struct via_spec *spec = codec->spec;
+       /* get nid of MW0 and start & end index */
+       switch (spec->codec_type) {
+       case VT1708B_8CH:
+       case VT1708B_4CH:
+       case VT1708S:
+       case VT1716S:
+               nid_mixer = 0x16;
+               start_idx = 2;
+               end_idx = 4;
+               break;
+       case VT1702:
+               nid_mixer = 0x1a;
+               start_idx = 1;
+               end_idx = 3;
+               break;
+       case VT1718S:
+               nid_mixer = 0x21;
+               start_idx = 1;
+               end_idx = 3;
+               break;
+       case VT2002P:
+       case VT1812:
+               nid_mixer = 0x21;
+               start_idx = 0;
+               end_idx = 2;
+               break;
+       default:
+               return 0;
+       }
+       /* check AA path's mute status */
+       for (i = start_idx; i <= end_idx; i++) {
+               unsigned int con_list = snd_hda_codec_read(
+                       codec, nid_mixer, 0, AC_VERB_GET_CONNECT_LIST, i/4*4);
+               int shift = 8 * (i % 4);
+               hda_nid_t nid_pin = (con_list & (0xff << shift)) >> shift;
+               unsigned int defconf = snd_hda_codec_get_pincfg(codec, nid_pin);
+               if (get_defcfg_connect(defconf) == AC_JACK_PORT_COMPLEX) {
+                       /* check mute status while the pin is connected */
+                       int mute_l = snd_hda_codec_amp_read(codec, nid_mixer, 0,
+                                                           HDA_INPUT, i) >> 7;
+                       int mute_r = snd_hda_codec_amp_read(codec, nid_mixer, 1,
+                                                           HDA_INPUT, i) >> 7;
+                       if (!mute_l || !mute_r) {
+                               mute = 0;
+                               break;
+                       }
+               }
+       }
+       return mute;
+}
+
+/* enter/exit analog low-current mode */
+static void analog_low_current_mode(struct hda_codec *codec, int stream_idle)
+{
+       struct via_spec *spec = codec->spec;
+       static int saved_stream_idle = 1; /* saved stream idle status */
+       int enable = is_aa_path_mute(codec);
+       unsigned int verb = 0;
+       unsigned int parm = 0;
+
+       if (stream_idle == -1)  /* stream status did not change */
+               enable = enable && saved_stream_idle;
+       else {
+               enable = enable && stream_idle;
+               saved_stream_idle = stream_idle;
+       }
+
+       /* decide low current mode's verb & parameter */
+       switch (spec->codec_type) {
+       case VT1708B_8CH:
+       case VT1708B_4CH:
+               verb = 0xf70;
+               parm = enable ? 0x02 : 0x00; /* 0x02: 2/3x, 0x00: 1x */
+               break;
+       case VT1708S:
+       case VT1718S:
+       case VT1716S:
+               verb = 0xf73;
+               parm = enable ? 0x51 : 0xe1; /* 0x51: 4/28x, 0xe1: 1x */
+               break;
+       case VT1702:
+               verb = 0xf73;
+               parm = enable ? 0x01 : 0x1d; /* 0x01: 4/40x, 0x1d: 1x */
+               break;
+       case VT2002P:
+       case VT1812:
+               verb = 0xf93;
+               parm = enable ? 0x00 : 0xe0; /* 0x00: 4/40x, 0xe0: 1x */
+               break;
+       default:
+               return;         /* other codecs are not supported */
+       }
+       /* send verb */
+       snd_hda_codec_write(codec, codec->afg, 0, verb, parm);
+}
+
+/*
+ * generic initialization of ADC, input mixers and output mixers
+ */
+static struct hda_verb vt1708_volume_init_verbs[] = {
+       /*
+        * Unmute ADC0-1 and set the default input to mic-in
+        */
+       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
 
 
        /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
@@ -534,9 +1542,9 @@ static struct hda_verb vt1708_volume_init_verbs[] = {
        {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
        {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
        {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-       
-       /* Setup default input to PW4 */
-       {0x20, AC_VERB_SET_CONNECT_SEL, 0x1},
+
+       /* Setup default input MW0 to PW4 */
+       {0x20, AC_VERB_SET_CONNECT_SEL, 0},
        /* PW9 Output enable */
        {0x25, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
        { }
@@ -547,30 +1555,13 @@ static int via_playback_pcm_open(struct hda_pcm_stream *hinfo,
                                 struct snd_pcm_substream *substream)
 {
        struct via_spec *spec = codec->spec;
+       int idle = substream->pstr->substream_opened == 1
+               && substream->ref_count == 0;
+       analog_low_current_mode(codec, idle);
        return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream,
                                             hinfo);
 }
 
-static int via_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
-                                   struct hda_codec *codec,
-                                   unsigned int stream_tag,
-                                   unsigned int format,
-                                   struct snd_pcm_substream *substream)
-{
-       struct via_spec *spec = codec->spec;
-       return snd_hda_multi_out_analog_prepare(codec, &spec->multiout,
-                                               stream_tag, format, substream);
-}
-
-static int via_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
-                                   struct hda_codec *codec,
-                                   struct snd_pcm_substream *substream)
-{
-       struct via_spec *spec = codec->spec;
-       return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
-}
-
-
 static void playback_multi_pcm_prep_0(struct hda_codec *codec,
                                      unsigned int stream_tag,
                                      unsigned int format,
@@ -615,8 +1606,8 @@ static void playback_multi_pcm_prep_0(struct hda_codec *codec,
        snd_hda_codec_setup_stream(codec, nids[HDA_FRONT], stream_tag,
                                   0, format);
 
-       if (mout->hp_nid && mout->hp_nid != nids[HDA_FRONT] &&
-           !spec->hp_independent_mode)
+       if (mout->hp_nid && mout->hp_nid != nids[HDA_FRONT]
+           && !spec->hp_independent_mode)
                /* headphone out will just decode front left/right (stereo) */
                snd_hda_codec_setup_stream(codec, mout->hp_nid, stream_tag,
                                           0, format);
@@ -658,7 +1649,7 @@ static int via_playback_multi_pcm_prepare(struct hda_pcm_stream *hinfo,
                        snd_hda_codec_setup_stream(codec, mout->hp_nid,
                                                   stream_tag, 0, format);
        }
-
+       vt1708_start_hp_work(spec);
        return 0;
 }
 
@@ -698,7 +1689,7 @@ static int via_playback_multi_pcm_cleanup(struct hda_pcm_stream *hinfo,
                        snd_hda_codec_setup_stream(codec, mout->hp_nid,
                                                   0, 0, 0);
        }
-
+       vt1708_stop_hp_work(spec);
        return 0;
 }
 
@@ -779,7 +1770,7 @@ static struct hda_pcm_stream vt1708_pcm_analog_playback = {
 };
 
 static struct hda_pcm_stream vt1708_pcm_analog_s16_playback = {
-       .substreams = 1,
+       .substreams = 2,
        .channels_min = 2,
        .channels_max = 8,
        .nid = 0x10, /* NID to query formats and rates */
@@ -790,8 +1781,8 @@ static struct hda_pcm_stream vt1708_pcm_analog_s16_playback = {
        .formats = SNDRV_PCM_FMTBIT_S16_LE,
        .ops = {
                .open = via_playback_pcm_open,
-               .prepare = via_playback_pcm_prepare,
-               .cleanup = via_playback_pcm_cleanup
+               .prepare = via_playback_multi_pcm_prepare,
+               .cleanup = via_playback_multi_pcm_cleanup
        },
 };
 
@@ -853,6 +1844,11 @@ static int via_build_controls(struct hda_codec *codec)
                if (err < 0)
                        return err;
        }
+
+       /* init power states */
+       set_jack_power_state(codec);
+       analog_low_current_mode(codec, 1);
+
        via_free_kctls(codec); /* no longer needed */
        return 0;
 }
@@ -866,8 +1862,10 @@ static int via_build_pcms(struct hda_codec *codec)
        codec->pcm_info = info;
 
        info->name = spec->stream_name_analog;
-       info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *(spec->stream_analog_playback);
-       info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dac_nids[0];
+       info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
+               *(spec->stream_analog_playback);
+       info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid =
+               spec->multiout.dac_nids[0];
        info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_analog_capture);
        info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0];
 
@@ -904,20 +1902,58 @@ static void via_free(struct hda_codec *codec)
                return;
 
        via_free_kctls(codec);
+       vt1708_stop_hp_work(spec);
        kfree(codec->spec);
 }
 
 /* mute internal speaker if HP is plugged */
 static void via_hp_automute(struct hda_codec *codec)
 {
-       unsigned int present;
+       unsigned int present = 0;
+       struct via_spec *spec = codec->spec;
+
+       present = snd_hda_jack_detect(codec, spec->autocfg.hp_pins[0]);
+
+       if (!spec->hp_independent_mode) {
+               struct snd_ctl_elem_id id;
+               /* auto mute */
+               snd_hda_codec_amp_stereo(
+                       codec, spec->autocfg.line_out_pins[0], HDA_OUTPUT, 0,
+                       HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
+               /* notify change */
+               memset(&id, 0, sizeof(id));
+               id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+               strcpy(id.name, "Front Playback Switch");
+               snd_ctl_notify(codec->bus->card, SNDRV_CTL_EVENT_MASK_VALUE,
+                              &id);
+       }
+}
+
+/* mute mono out if HP or Line out is plugged */
+static void via_mono_automute(struct hda_codec *codec)
+{
+       unsigned int hp_present, lineout_present;
        struct via_spec *spec = codec->spec;
 
-       present = snd_hda_codec_read(codec, spec->autocfg.hp_pins[0], 0,
-                                    AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
-       snd_hda_codec_amp_stereo(codec, spec->autocfg.line_out_pins[0],
-                                HDA_OUTPUT, 0, HDA_AMP_MUTE,
-                                present ? HDA_AMP_MUTE : 0);
+       if (spec->codec_type != VT1716S)
+               return;
+
+       lineout_present = snd_hda_jack_detect(codec,
+                                             spec->autocfg.line_out_pins[0]);
+
+       /* Mute Mono Out if Line Out is plugged */
+       if (lineout_present) {
+               snd_hda_codec_amp_stereo(
+                       codec, 0x2A, HDA_OUTPUT, 0, HDA_AMP_MUTE, HDA_AMP_MUTE);
+               return;
+       }
+
+       hp_present = snd_hda_jack_detect(codec, spec->autocfg.hp_pins[0]);
+
+       if (!spec->hp_independent_mode)
+               snd_hda_codec_amp_stereo(
+                       codec, 0x2A, HDA_OUTPUT, 0, HDA_AMP_MUTE,
+                       hp_present ? HDA_AMP_MUTE : 0);
 }
 
 static void via_gpio_control(struct hda_codec *codec)
@@ -968,15 +2004,83 @@ static void via_gpio_control(struct hda_codec *codec)
        }
 }
 
+/* mute Internal-Speaker if HP is plugged */
+static void via_speaker_automute(struct hda_codec *codec)
+{
+       unsigned int hp_present;
+       struct via_spec *spec = codec->spec;
+
+       if (spec->codec_type != VT2002P && spec->codec_type != VT1812)
+               return;
+
+       hp_present = snd_hda_jack_detect(codec, spec->autocfg.hp_pins[0]);
+
+       if (!spec->hp_independent_mode) {
+               struct snd_ctl_elem_id id;
+               snd_hda_codec_amp_stereo(
+                       codec, spec->autocfg.speaker_pins[0], HDA_OUTPUT, 0,
+                       HDA_AMP_MUTE, hp_present ? HDA_AMP_MUTE : 0);
+               /* notify change */
+               memset(&id, 0, sizeof(id));
+               id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+               strcpy(id.name, "Speaker Playback Switch");
+               snd_ctl_notify(codec->bus->card, SNDRV_CTL_EVENT_MASK_VALUE,
+                              &id);
+       }
+}
+
+/* mute line-out and internal speaker if HP is plugged */
+static void via_hp_bind_automute(struct hda_codec *codec)
+{
+       /* use long instead of int below just to avoid an internal compiler
+        * error with gcc 4.0.x
+        */
+       unsigned long hp_present, present = 0;
+       struct via_spec *spec = codec->spec;
+       int i;
+
+       if (!spec->autocfg.hp_pins[0] || !spec->autocfg.line_out_pins[0])
+               return;
+
+       hp_present = snd_hda_jack_detect(codec, spec->autocfg.hp_pins[0]);
+
+       present = snd_hda_jack_detect(codec, spec->autocfg.line_out_pins[0]);
+
+       if (!spec->hp_independent_mode) {
+               /* Mute Line-Outs */
+               for (i = 0; i < spec->autocfg.line_outs; i++)
+                       snd_hda_codec_amp_stereo(
+                               codec, spec->autocfg.line_out_pins[i],
+                               HDA_OUTPUT, 0,
+                               HDA_AMP_MUTE, hp_present ? HDA_AMP_MUTE : 0);
+               if (hp_present)
+                       present = hp_present;
+       }
+       /* Speakers */
+       for (i = 0; i < spec->autocfg.speaker_outs; i++)
+               snd_hda_codec_amp_stereo(
+                       codec, spec->autocfg.speaker_pins[i], HDA_OUTPUT, 0,
+                       HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
+}
+
+
 /* unsolicited event for jack sensing */
 static void via_unsol_event(struct hda_codec *codec,
                                  unsigned int res)
 {
        res >>= 26;
-       if (res == VIA_HP_EVENT)
+       if (res & VIA_HP_EVENT)
                via_hp_automute(codec);
-       else if (res == VIA_GPIO_EVENT)
+       if (res & VIA_GPIO_EVENT)
                via_gpio_control(codec);
+       if (res & VIA_JACK_EVENT)
+               set_jack_power_state(codec);
+       if (res & VIA_MONO_EVENT)
+               via_mono_automute(codec);
+       if (res & VIA_SPEAKER_EVENT)
+               via_speaker_automute(codec);
+       if (res & VIA_BIND_HP_EVENT)
+               via_hp_bind_automute(codec);
 }
 
 static int via_init(struct hda_codec *codec)
@@ -986,6 +2090,10 @@ static int via_init(struct hda_codec *codec)
        for (i = 0; i < spec->num_iverbs; i++)
                snd_hda_sequence_write(codec, spec->init_verbs[i]);
 
+       spec->codec_type = get_codec_type(codec);
+       if (spec->codec_type == VT1708BCE)
+               spec->codec_type = VT1708S; /* VT1708BCE & VT1708S are almost
+                                              same */
        /* Lydia Add for EAPD enable */
        if (!spec->dig_in_nid) { /* No Digital In connection */
                if (spec->dig_in_pin) {
@@ -1003,8 +2111,17 @@ static int via_init(struct hda_codec *codec)
        if (spec->slave_dig_outs[0])
                codec->slave_dig_outs = spec->slave_dig_outs;
 
-       return 0;
+       return 0;
+}
+
+#ifdef SND_HDA_NEEDS_RESUME
+static int via_suspend(struct hda_codec *codec, pm_message_t state)
+{
+       struct via_spec *spec = codec->spec;
+       vt1708_stop_hp_work(spec);
+       return 0;
 }
+#endif
 
 #ifdef CONFIG_SND_HDA_POWER_SAVE
 static int via_check_power_status(struct hda_codec *codec, hda_nid_t nid)
@@ -1021,6 +2138,9 @@ static struct hda_codec_ops via_patch_ops = {
        .build_pcms = via_build_pcms,
        .init = via_init,
        .free = via_free,
+#ifdef SND_HDA_NEEDS_RESUME
+       .suspend = via_suspend,
+#endif
 #ifdef CONFIG_SND_HDA_POWER_SAVE
        .check_power_status = via_check_power_status,
 #endif
@@ -1036,8 +2156,8 @@ static int vt1708_auto_fill_dac_nids(struct via_spec *spec,
        spec->multiout.num_dacs = cfg->line_outs;
 
        spec->multiout.dac_nids = spec->private_dac_nids;
-       
-       for(i = 0; i < 4; i++) {
+
+       for (i = 0; i < 4; i++) {
                nid = cfg->line_out_pins[i];
                if (nid) {
                        /* config dac list */
@@ -1067,7 +2187,7 @@ static int vt1708_auto_create_multi_out_ctls(struct via_spec *spec,
 {
        char name[32];
        static const char *chname[4] = { "Front", "Surround", "C/LFE", "Side" };
-       hda_nid_t nid, nid_vol = 0;
+       hda_nid_t nid, nid_vol, nid_vols[] = {0x17, 0x19, 0x1a, 0x1b};
        int i, err;
 
        for (i = 0; i <= AUTO_SEQ_SIDE; i++) {
@@ -1075,9 +2195,8 @@ static int vt1708_auto_create_multi_out_ctls(struct via_spec *spec,
 
                if (!nid)
                        continue;
-               
-               if (i != AUTO_SEQ_FRONT)
-                       nid_vol = 0x18 + i;
+
+               nid_vol = nid_vols[i];
 
                if (i == AUTO_SEQ_CENLFE) {
                        /* Center/LFE */
@@ -1105,21 +2224,21 @@ static int vt1708_auto_create_multi_out_ctls(struct via_spec *spec,
                                                                  HDA_OUTPUT));
                        if (err < 0)
                                return err;
-               } else if (i == AUTO_SEQ_FRONT){
+               } else if (i == AUTO_SEQ_FRONT) {
                        /* add control to mixer index 0 */
                        err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
                                              "Master Front Playback Volume",
-                                             HDA_COMPOSE_AMP_VAL(0x17, 3, 0,
+                                             HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
                                                                  HDA_INPUT));
                        if (err < 0)
                                return err;
                        err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
                                              "Master Front Playback Switch",
-                                             HDA_COMPOSE_AMP_VAL(0x17, 3, 0,
+                                             HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
                                                                  HDA_INPUT));
                        if (err < 0)
                                return err;
-                       
+
                        /* add control to PW3 */
                        sprintf(name, "%s Playback Volume", chname[i]);
                        err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
@@ -1178,6 +2297,7 @@ static int vt1708_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
                return 0;
 
        spec->multiout.hp_nid = VT1708_HP_NID; /* AOW3 */
+       spec->hp_independent_mode_index = 1;
 
        err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
                              "Headphone Playback Volume",
@@ -1218,7 +2338,7 @@ static int vt1708_auto_create_analog_input_ctls(struct via_spec *spec,
                case 0x1d: /* Mic */
                        idx = 2;
                        break;
-                               
+
                case 0x1e: /* Line In */
                        idx = 3;
                        break;
@@ -1231,8 +2351,7 @@ static int vt1708_auto_create_analog_input_ctls(struct via_spec *spec,
                        idx = 1;
                        break;
                }
-               err = via_new_analog_input(spec, cfg->input_pins[i], labels[i],
-                                          idx, 0x17);
+               err = via_new_analog_input(spec, labels[i], idx, 0x17);
                if (err < 0)
                        return err;
                imux->items[imux->num_items].label = labels[i];
@@ -1260,16 +2379,60 @@ static void vt1708_set_pinconfig_connect(struct hda_codec *codec, hda_nid_t nid)
        def_conf = snd_hda_codec_get_pincfg(codec, nid);
        seqassoc = (unsigned char) get_defcfg_association(def_conf);
        seqassoc = (seqassoc << 4) | get_defcfg_sequence(def_conf);
-       if (get_defcfg_connect(def_conf) == AC_JACK_PORT_NONE) {
-               if (seqassoc == 0xff) {
-                       def_conf = def_conf & (~(AC_JACK_PORT_BOTH << 30));
-                       snd_hda_codec_set_pincfg(codec, nid, def_conf);
-               }
+       if (get_defcfg_connect(def_conf) == AC_JACK_PORT_NONE
+           && (seqassoc == 0xf0 || seqassoc == 0xff)) {
+               def_conf = def_conf & (~(AC_JACK_PORT_BOTH << 30));
+               snd_hda_codec_set_pincfg(codec, nid, def_conf);
        }
 
        return;
 }
 
+static int vt1708_jack_detectect_get(struct snd_kcontrol *kcontrol,
+                                    struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct via_spec *spec = codec->spec;
+
+       if (spec->codec_type != VT1708)
+               return 0;
+       spec->vt1708_jack_detectect =
+               !((snd_hda_codec_read(codec, 0x1, 0, 0xf84, 0) >> 8) & 0x1);
+       ucontrol->value.integer.value[0] = spec->vt1708_jack_detectect;
+       return 0;
+}
+
+static int vt1708_jack_detectect_put(struct snd_kcontrol *kcontrol,
+                                    struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct via_spec *spec = codec->spec;
+       int change;
+
+       if (spec->codec_type != VT1708)
+               return 0;
+       spec->vt1708_jack_detectect = ucontrol->value.integer.value[0];
+       change = (0x1 & (snd_hda_codec_read(codec, 0x1, 0, 0xf84, 0) >> 8))
+               == !spec->vt1708_jack_detectect;
+       if (spec->vt1708_jack_detectect) {
+               mute_aa_path(codec, 1);
+               notify_aa_path_ctls(codec);
+       }
+       return change;
+}
+
+static struct snd_kcontrol_new vt1708_jack_detectect[] = {
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "Jack Detect",
+               .count = 1,
+               .info = snd_ctl_boolean_mono_info,
+               .get = vt1708_jack_detectect_get,
+               .put = vt1708_jack_detectect_put,
+       },
+       {} /* end */
+};
+
 static int vt1708_parse_auto_config(struct hda_codec *codec)
 {
        struct via_spec *spec = codec->spec;
@@ -1297,6 +2460,10 @@ static int vt1708_parse_auto_config(struct hda_codec *codec)
        err = vt1708_auto_create_analog_input_ctls(spec, &spec->autocfg);
        if (err < 0)
                return err;
+       /* add jack detect on/off control */
+       err = snd_hda_add_new_ctls(codec, vt1708_jack_detectect);
+       if (err < 0)
+               return err;
 
        spec->multiout.max_channels = spec->multiout.num_dacs * 2;
 
@@ -1316,19 +2483,44 @@ static int vt1708_parse_auto_config(struct hda_codec *codec)
        if (spec->hp_mux)
                spec->mixers[spec->num_mixers++] = via_hp_mixer;
 
+       spec->mixers[spec->num_mixers++] = via_smart51_mixer;
        return 1;
 }
 
 /* init callback for auto-configuration model -- overriding the default init */
 static int via_auto_init(struct hda_codec *codec)
 {
+       struct via_spec *spec = codec->spec;
+
        via_init(codec);
        via_auto_init_multi_out(codec);
        via_auto_init_hp_out(codec);
        via_auto_init_analog_input(codec);
+       if (spec->codec_type == VT2002P || spec->codec_type == VT1812) {
+               via_hp_bind_automute(codec);
+       } else {
+               via_hp_automute(codec);
+               via_speaker_automute(codec);
+       }
+
        return 0;
 }
 
+static void vt1708_update_hp_jack_state(struct work_struct *work)
+{
+       struct via_spec *spec = container_of(work, struct via_spec,
+                                            vt1708_hp_work.work);
+       if (spec->codec_type != VT1708)
+               return;
+       /* if jack state toggled */
+       if (spec->vt1708_hp_present
+           != snd_hda_jack_detect(spec->codec, spec->autocfg.hp_pins[0])) {
+               spec->vt1708_hp_present ^= 1;
+               via_hp_automute(spec->codec);
+       }
+       vt1708_start_hp_work(spec);
+}
+
 static int get_mux_nids(struct hda_codec *codec)
 {
        struct via_spec *spec = codec->spec;
@@ -1378,7 +2570,7 @@ static int patch_vt1708(struct hda_codec *codec)
                       "from BIOS.  Using genenic mode...\n");
        }
 
-       
+
        spec->stream_name_analog = "VT1708 Analog";
        spec->stream_analog_playback = &vt1708_pcm_analog_playback;
        /* disable 32bit format on VT1708 */
@@ -1390,7 +2582,7 @@ static int patch_vt1708(struct hda_codec *codec)
        spec->stream_digital_playback = &vt1708_pcm_digital_playback;
        spec->stream_digital_capture = &vt1708_pcm_digital_capture;
 
-       
+
        if (!spec->adc_nids && spec->input_mux) {
                spec->adc_nids = vt1708_adc_nids;
                spec->num_adc_nids = ARRAY_SIZE(vt1708_adc_nids);
@@ -1405,7 +2597,8 @@ static int patch_vt1708(struct hda_codec *codec)
 #ifdef CONFIG_SND_HDA_POWER_SAVE
        spec->loopback.amplist = vt1708_loopbacks;
 #endif
-
+       spec->codec = codec;
+       INIT_DELAYED_WORK(&spec->vt1708_hp_work, vt1708_update_hp_jack_state);
        return 0;
 }
 
@@ -1433,7 +2626,8 @@ static struct snd_kcontrol_new vt1709_capture_mixer[] = {
 };
 
 static struct hda_verb vt1709_uniwill_init_verbs[] = {
-       {0x20, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_HP_EVENT},
+       {0x20, AC_VERB_SET_UNSOLICITED_ENABLE,
+        AC_USRSP_EN | VIA_HP_EVENT | VIA_JACK_EVENT},
        { }
 };
 
@@ -1473,8 +2667,8 @@ static struct hda_verb vt1709_10ch_volume_init_verbs[] = {
        {0x1f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
        {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
 
-       /* Set input of PW4 as AOW4 */
-       {0x20, AC_VERB_SET_CONNECT_SEL, 0x1},
+       /* Set input of PW4 as MW0 */
+       {0x20, AC_VERB_SET_CONNECT_SEL, 0},
        /* PW9 Output enable */
        {0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
        { }
@@ -1487,8 +2681,8 @@ static struct hda_pcm_stream vt1709_10ch_pcm_analog_playback = {
        .nid = 0x10, /* NID to query formats and rates */
        .ops = {
                .open = via_playback_pcm_open,
-               .prepare = via_playback_pcm_prepare,
-               .cleanup = via_playback_pcm_cleanup
+               .prepare = via_playback_multi_pcm_prepare,
+               .cleanup = via_playback_multi_pcm_cleanup,
        },
 };
 
@@ -1499,8 +2693,8 @@ static struct hda_pcm_stream vt1709_6ch_pcm_analog_playback = {
        .nid = 0x10, /* NID to query formats and rates */
        .ops = {
                .open = via_playback_pcm_open,
-               .prepare = via_playback_pcm_prepare,
-               .cleanup = via_playback_pcm_cleanup
+               .prepare = via_playback_multi_pcm_prepare,
+               .cleanup = via_playback_multi_pcm_cleanup,
        },
 };
 
@@ -1575,11 +2769,11 @@ static int vt1709_auto_fill_dac_nids(struct via_spec *spec,
                spec->multiout.dac_nids[cfg->line_outs] = 0x28; /* AOW4 */
 
        } else if (cfg->line_outs == 3) { /* 6 channels */
-               for(i = 0; i < cfg->line_outs; i++) {
+               for (i = 0; i < cfg->line_outs; i++) {
                        nid = cfg->line_out_pins[i];
                        if (nid) {
                                /* config dac list */
-                               switch(i) {
+                               switch (i) {
                                case AUTO_SEQ_FRONT:
                                        /* AOW0 */
                                        spec->multiout.dac_nids[i] = 0x10;
@@ -1608,56 +2802,58 @@ static int vt1709_auto_create_multi_out_ctls(struct via_spec *spec,
 {
        char name[32];
        static const char *chname[4] = { "Front", "Surround", "C/LFE", "Side" };
-       hda_nid_t nid = 0;
+       hda_nid_t nid, nid_vol, nid_vols[] = {0x18, 0x1a, 0x1b, 0x29};
        int i, err;
 
        for (i = 0; i <= AUTO_SEQ_SIDE; i++) {
                nid = cfg->line_out_pins[i];
 
-               if (!nid)       
+               if (!nid)
                        continue;
 
+               nid_vol = nid_vols[i];
+
                if (i == AUTO_SEQ_CENLFE) {
                        /* Center/LFE */
                        err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
                                              "Center Playback Volume",
-                                             HDA_COMPOSE_AMP_VAL(0x1b, 1, 0,
+                                             HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0,
                                                                  HDA_OUTPUT));
                        if (err < 0)
                                return err;
                        err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
                                              "LFE Playback Volume",
-                                             HDA_COMPOSE_AMP_VAL(0x1b, 2, 0,
+                                             HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0,
                                                                  HDA_OUTPUT));
                        if (err < 0)
                                return err;
                        err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
                                              "Center Playback Switch",
-                                             HDA_COMPOSE_AMP_VAL(0x1b, 1, 0,
+                                             HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0,
                                                                  HDA_OUTPUT));
                        if (err < 0)
                                return err;
                        err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
                                              "LFE Playback Switch",
-                                             HDA_COMPOSE_AMP_VAL(0x1b, 2, 0,
+                                             HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0,
                                                                  HDA_OUTPUT));
                        if (err < 0)
                                return err;
-               } else if (i == AUTO_SEQ_FRONT){
-                       /* add control to mixer index 0 */
+               } else if (i == AUTO_SEQ_FRONT) {
+                       /* ADD control to mixer index 0 */
                        err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
                                              "Master Front Playback Volume",
-                                             HDA_COMPOSE_AMP_VAL(0x18, 3, 0,
+                                             HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
                                                                  HDA_INPUT));
                        if (err < 0)
                                return err;
                        err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
                                              "Master Front Playback Switch",
-                                             HDA_COMPOSE_AMP_VAL(0x18, 3, 0,
+                                             HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
                                                                  HDA_INPUT));
                        if (err < 0)
                                return err;
-                       
+
                        /* add control to PW3 */
                        sprintf(name, "%s Playback Volume", chname[i]);
                        err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
@@ -1674,26 +2870,26 @@ static int vt1709_auto_create_multi_out_ctls(struct via_spec *spec,
                } else if (i == AUTO_SEQ_SURROUND) {
                        sprintf(name, "%s Playback Volume", chname[i]);
                        err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
-                                             HDA_COMPOSE_AMP_VAL(0x1a, 3, 0,
+                                             HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
                                                                  HDA_OUTPUT));
                        if (err < 0)
                                return err;
                        sprintf(name, "%s Playback Switch", chname[i]);
                        err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
-                                             HDA_COMPOSE_AMP_VAL(0x1a, 3, 0,
+                                             HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
                                                                  HDA_OUTPUT));
                        if (err < 0)
                                return err;
                } else if (i == AUTO_SEQ_SIDE) {
                        sprintf(name, "%s Playback Volume", chname[i]);
                        err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
-                                             HDA_COMPOSE_AMP_VAL(0x29, 3, 0,
+                                             HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
                                                                  HDA_OUTPUT));
                        if (err < 0)
                                return err;
                        sprintf(name, "%s Playback Switch", chname[i]);
                        err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
-                                             HDA_COMPOSE_AMP_VAL(0x29, 3, 0,
+                                             HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
                                                                  HDA_OUTPUT));
                        if (err < 0)
                                return err;
@@ -1714,6 +2910,7 @@ static int vt1709_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
                spec->multiout.hp_nid = VT1709_HP_DAC_NID;
        else if (spec->multiout.num_dacs == 3) /* 6 channels */
                spec->multiout.hp_nid = 0;
+       spec->hp_independent_mode_index = 1;
 
        err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
                              "Headphone Playback Volume",
@@ -1752,7 +2949,7 @@ static int vt1709_auto_create_analog_input_ctls(struct via_spec *spec,
                case 0x1d: /* Mic */
                        idx = 2;
                        break;
-                               
+
                case 0x1e: /* Line In */
                        idx = 3;
                        break;
@@ -1765,8 +2962,7 @@ static int vt1709_auto_create_analog_input_ctls(struct via_spec *spec,
                        idx = 1;
                        break;
                }
-               err = via_new_analog_input(spec, cfg->input_pins[i], labels[i],
-                                          idx, 0x18);
+               err = via_new_analog_input(spec, labels[i], idx, 0x18);
                if (err < 0)
                        return err;
                imux->items[imux->num_items].label = labels[i];
@@ -1816,6 +3012,7 @@ static int vt1709_parse_auto_config(struct hda_codec *codec)
        if (spec->hp_mux)
                spec->mixers[spec->num_mixers++] = via_hp_mixer;
 
+       spec->mixers[spec->num_mixers++] = via_smart51_mixer;
        return 1;
 }
 
@@ -1861,7 +3058,7 @@ static int patch_vt1709_10ch(struct hda_codec *codec)
        spec->stream_digital_playback = &vt1709_pcm_digital_playback;
        spec->stream_digital_capture = &vt1709_pcm_digital_capture;
 
-       
+
        if (!spec->adc_nids && spec->input_mux) {
                spec->adc_nids = vt1709_adc_nids;
                spec->num_adc_nids = ARRAY_SIZE(vt1709_adc_nids);
@@ -1955,7 +3152,7 @@ static int patch_vt1709_6ch(struct hda_codec *codec)
        spec->stream_digital_playback = &vt1709_pcm_digital_playback;
        spec->stream_digital_capture = &vt1709_pcm_digital_capture;
 
-       
+
        if (!spec->adc_nids && spec->input_mux) {
                spec->adc_nids = vt1709_adc_nids;
                spec->num_adc_nids = ARRAY_SIZE(vt1709_adc_nids);
@@ -2024,7 +3221,7 @@ static struct hda_verb vt1708B_8ch_volume_init_verbs[] = {
        {0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
 
        /* Setup default input to PW4 */
-       {0x1d, AC_VERB_SET_CONNECT_SEL, 0x1},
+       {0x1d, AC_VERB_SET_CONNECT_SEL, 0},
        /* PW9 Output enable */
        {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
        /* PW10 Input enable */
@@ -2068,10 +3265,29 @@ static struct hda_verb vt1708B_4ch_volume_init_verbs[] = {
 };
 
 static struct hda_verb vt1708B_uniwill_init_verbs[] = {
-       {0x1D, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_HP_EVENT},
+       {0x1d, AC_VERB_SET_UNSOLICITED_ENABLE,
+        AC_USRSP_EN | VIA_HP_EVENT | VIA_JACK_EVENT},
+       {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
+       {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
+       {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
+       {0x1c, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
+       {0x1e, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
+       {0x22, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
+       {0x23, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
        { }
 };
 
+static int via_pcm_open_close(struct hda_pcm_stream *hinfo,
+                             struct hda_codec *codec,
+                             struct snd_pcm_substream *substream)
+{
+       int idle = substream->pstr->substream_opened == 1
+               && substream->ref_count == 0;
+
+       analog_low_current_mode(codec, idle);
+       return 0;
+}
+
 static struct hda_pcm_stream vt1708B_8ch_pcm_analog_playback = {
        .substreams = 2,
        .channels_min = 2,
@@ -2080,7 +3296,8 @@ static struct hda_pcm_stream vt1708B_8ch_pcm_analog_playback = {
        .ops = {
                .open = via_playback_pcm_open,
                .prepare = via_playback_multi_pcm_prepare,
-               .cleanup = via_playback_multi_pcm_cleanup
+               .cleanup = via_playback_multi_pcm_cleanup,
+               .close = via_pcm_open_close
        },
 };
 
@@ -2102,8 +3319,10 @@ static struct hda_pcm_stream vt1708B_pcm_analog_capture = {
        .channels_max = 2,
        .nid = 0x13, /* NID to query formats and rates */
        .ops = {
+               .open = via_pcm_open_close,
                .prepare = via_capture_pcm_prepare,
-               .cleanup = via_capture_pcm_cleanup
+               .cleanup = via_capture_pcm_cleanup,
+               .close = via_pcm_open_close
        },
 };
 
@@ -2260,6 +3479,7 @@ static int vt1708B_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
                return 0;
 
        spec->multiout.hp_nid = VT1708B_HP_NID; /* AOW3 */
+       spec->hp_independent_mode_index = 1;
 
        err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
                              "Headphone Playback Volume",
@@ -2313,8 +3533,7 @@ static int vt1708B_auto_create_analog_input_ctls(struct via_spec *spec,
                        idx = 1;
                        break;
                }
-               err = via_new_analog_input(spec, cfg->input_pins[i], labels[i],
-                                          idx, 0x16);
+               err = via_new_analog_input(spec, labels[i], idx, 0x16);
                if (err < 0)
                        return err;
                imux->items[imux->num_items].label = labels[i];
@@ -2364,6 +3583,7 @@ static int vt1708B_parse_auto_config(struct hda_codec *codec)
        if (spec->hp_mux)
                spec->mixers[spec->num_mixers++] = via_hp_mixer;
 
+       spec->mixers[spec->num_mixers++] = via_smart51_mixer;
        return 1;
 }
 
@@ -2376,12 +3596,14 @@ static struct hda_amp_list vt1708B_loopbacks[] = {
        { } /* end */
 };
 #endif
-
+static int patch_vt1708S(struct hda_codec *codec);
 static int patch_vt1708B_8ch(struct hda_codec *codec)
 {
        struct via_spec *spec;
        int err;
 
+       if (get_codec_type(codec) == VT1708BCE)
+               return patch_vt1708S(codec);
        /* create a codec specific record */
        spec = kzalloc(sizeof(*spec), GFP_KERNEL);
        if (spec == NULL)
@@ -2483,29 +3705,15 @@ static int patch_vt1708B_4ch(struct hda_codec *codec)
 
 /* Patch for VT1708S */
 
-/* VT1708S software backdoor based override for buggy hardware micboost
- * setting */
-#define MIC_BOOST_VOLUME(xname, nid) {                         \
-       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,            \
-       .name = xname,                                  \
-       .index = 0,                                     \
-       .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |     \
-       SNDRV_CTL_ELEM_ACCESS_TLV_READ |                \
-       SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK,             \
-       .info = mic_boost_volume_info,                  \
-       .get = snd_hda_mixer_amp_volume_get,            \
-       .put = snd_hda_mixer_amp_volume_put,            \
-       .tlv = { .c = mic_boost_tlv },                  \
-       .private_value = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT) }
-
 /* capture mixer elements */
 static struct snd_kcontrol_new vt1708S_capture_mixer[] = {
        HDA_CODEC_VOLUME("Capture Volume", 0x13, 0x0, HDA_INPUT),
        HDA_CODEC_MUTE("Capture Switch", 0x13, 0x0, HDA_INPUT),
        HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x14, 0x0, HDA_INPUT),
        HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x14, 0x0, HDA_INPUT),
-       MIC_BOOST_VOLUME("Mic Boost Capture Volume", 0x1A),
-       MIC_BOOST_VOLUME("Front Mic Boost Capture Volume", 0x1E),
+       HDA_CODEC_VOLUME("Mic Boost Capture Volume", 0x1A, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Front Mic Boost Capture Volume", 0x1E, 0x0,
+                        HDA_INPUT),
        {
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
                /* The multiple "Capture Source" controls confuse alsamixer
@@ -2542,11 +3750,21 @@ static struct hda_verb vt1708S_volume_init_verbs[] = {
        {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
        /* Enable Mic Boost Volume backdoor */
        {0x1, 0xf98, 0x1},
+       /* don't bybass mixer */
+       {0x1, 0xf88, 0xc0},
        { }
 };
 
 static struct hda_verb vt1708S_uniwill_init_verbs[] = {
-       {0x1D, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_HP_EVENT},
+       {0x1d, AC_VERB_SET_UNSOLICITED_ENABLE,
+        AC_USRSP_EN | VIA_HP_EVENT | VIA_JACK_EVENT},
+       {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
+       {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
+       {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
+       {0x1c, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
+       {0x1e, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
+       {0x22, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
+       {0x23, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
        { }
 };
 
@@ -2557,8 +3775,9 @@ static struct hda_pcm_stream vt1708S_pcm_analog_playback = {
        .nid = 0x10, /* NID to query formats and rates */
        .ops = {
                .open = via_playback_pcm_open,
-               .prepare = via_playback_pcm_prepare,
-               .cleanup = via_playback_pcm_cleanup
+               .prepare = via_playback_multi_pcm_prepare,
+               .cleanup = via_playback_multi_pcm_cleanup,
+               .close = via_pcm_open_close
        },
 };
 
@@ -2568,8 +3787,10 @@ static struct hda_pcm_stream vt1708S_pcm_analog_capture = {
        .channels_max = 2,
        .nid = 0x13, /* NID to query formats and rates */
        .ops = {
+               .open = via_pcm_open_close,
                .prepare = via_capture_pcm_prepare,
-               .cleanup = via_capture_pcm_cleanup
+               .cleanup = via_capture_pcm_cleanup,
+               .close = via_pcm_open_close
        },
 };
 
@@ -2718,34 +3939,1698 @@ static int vt1708S_auto_create_multi_out_ctls(struct via_spec *spec,
        return 0;
 }
 
-static int vt1708S_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
+static int vt1708S_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
+{
+       int err;
+
+       if (!pin)
+               return 0;
+
+       spec->multiout.hp_nid = VT1708S_HP_NID; /* AOW3 */
+       spec->hp_independent_mode_index = 1;
+
+       err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
+                             "Headphone Playback Volume",
+                             HDA_COMPOSE_AMP_VAL(0x25, 3, 0, HDA_OUTPUT));
+       if (err < 0)
+               return err;
+
+       err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
+                             "Headphone Playback Switch",
+                             HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
+       if (err < 0)
+               return err;
+
+       create_hp_imux(spec);
+
+       return 0;
+}
+
+/* create playback/capture controls for input pins */
+static int vt1708S_auto_create_analog_input_ctls(struct via_spec *spec,
+                                               const struct auto_pin_cfg *cfg)
+{
+       static char *labels[] = {
+               "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
+       };
+       struct hda_input_mux *imux = &spec->private_imux[0];
+       int i, err, idx = 0;
+
+       /* for internal loopback recording select */
+       imux->items[imux->num_items].label = "Stereo Mixer";
+       imux->items[imux->num_items].index = 5;
+       imux->num_items++;
+
+       for (i = 0; i < AUTO_PIN_LAST; i++) {
+               if (!cfg->input_pins[i])
+                       continue;
+
+               switch (cfg->input_pins[i]) {
+               case 0x1a: /* Mic */
+                       idx = 2;
+                       break;
+
+               case 0x1b: /* Line In */
+                       idx = 3;
+                       break;
+
+               case 0x1e: /* Front Mic */
+                       idx = 4;
+                       break;
+
+               case 0x1f: /* CD */
+                       idx = 1;
+                       break;
+               }
+               err = via_new_analog_input(spec, labels[i], idx, 0x16);
+               if (err < 0)
+                       return err;
+               imux->items[imux->num_items].label = labels[i];
+               imux->items[imux->num_items].index = idx-1;
+               imux->num_items++;
+       }
+       return 0;
+}
+
+/* fill out digital output widgets; one for master and one for slave outputs */
+static void fill_dig_outs(struct hda_codec *codec)
+{
+       struct via_spec *spec = codec->spec;
+       int i;
+
+       for (i = 0; i < spec->autocfg.dig_outs; i++) {
+               hda_nid_t nid;
+               int conn;
+
+               nid = spec->autocfg.dig_out_pins[i];
+               if (!nid)
+                       continue;
+               conn = snd_hda_get_connections(codec, nid, &nid, 1);
+               if (conn < 1)
+                       continue;
+               if (!spec->multiout.dig_out_nid)
+                       spec->multiout.dig_out_nid = nid;
+               else {
+                       spec->slave_dig_outs[0] = nid;
+                       break; /* at most two dig outs */
+               }
+       }
+}
+
+static int vt1708S_parse_auto_config(struct hda_codec *codec)
+{
+       struct via_spec *spec = codec->spec;
+       int err;
+
+       err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);
+       if (err < 0)
+               return err;
+       err = vt1708S_auto_fill_dac_nids(spec, &spec->autocfg);
+       if (err < 0)
+               return err;
+       if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0])
+               return 0; /* can't find valid BIOS pin config */
+
+       err = vt1708S_auto_create_multi_out_ctls(spec, &spec->autocfg);
+       if (err < 0)
+               return err;
+       err = vt1708S_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
+       if (err < 0)
+               return err;
+       err = vt1708S_auto_create_analog_input_ctls(spec, &spec->autocfg);
+       if (err < 0)
+               return err;
+
+       spec->multiout.max_channels = spec->multiout.num_dacs * 2;
+
+       fill_dig_outs(codec);
+
+       if (spec->kctls.list)
+               spec->mixers[spec->num_mixers++] = spec->kctls.list;
+
+       spec->input_mux = &spec->private_imux[0];
+
+       if (spec->hp_mux)
+               spec->mixers[spec->num_mixers++] = via_hp_mixer;
+
+       spec->mixers[spec->num_mixers++] = via_smart51_mixer;
+       return 1;
+}
+
+#ifdef CONFIG_SND_HDA_POWER_SAVE
+static struct hda_amp_list vt1708S_loopbacks[] = {
+       { 0x16, HDA_INPUT, 1 },
+       { 0x16, HDA_INPUT, 2 },
+       { 0x16, HDA_INPUT, 3 },
+       { 0x16, HDA_INPUT, 4 },
+       { } /* end */
+};
+#endif
+
+static void override_mic_boost(struct hda_codec *codec, hda_nid_t pin,
+                              int offset, int num_steps, int step_size)
+{
+       snd_hda_override_amp_caps(codec, pin, HDA_INPUT,
+                                 (offset << AC_AMPCAP_OFFSET_SHIFT) |
+                                 (num_steps << AC_AMPCAP_NUM_STEPS_SHIFT) |
+                                 (step_size << AC_AMPCAP_STEP_SIZE_SHIFT) |
+                                 (0 << AC_AMPCAP_MUTE_SHIFT));
+}
+
+static int patch_vt1708S(struct hda_codec *codec)
+{
+       struct via_spec *spec;
+       int err;
+
+       /* create a codec specific record */
+       spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+       if (spec == NULL)
+               return -ENOMEM;
+
+       codec->spec = spec;
+
+       /* automatic parse from the BIOS config */
+       err = vt1708S_parse_auto_config(codec);
+       if (err < 0) {
+               via_free(codec);
+               return err;
+       } else if (!err) {
+               printk(KERN_INFO "hda_codec: Cannot set up configuration "
+                      "from BIOS.  Using genenic mode...\n");
+       }
+
+       spec->init_verbs[spec->num_iverbs++] = vt1708S_volume_init_verbs;
+       spec->init_verbs[spec->num_iverbs++] = vt1708S_uniwill_init_verbs;
+
+       if (codec->vendor_id == 0x11060440)
+               spec->stream_name_analog = "VT1818S Analog";
+       else
+               spec->stream_name_analog = "VT1708S Analog";
+       spec->stream_analog_playback = &vt1708S_pcm_analog_playback;
+       spec->stream_analog_capture = &vt1708S_pcm_analog_capture;
+
+       if (codec->vendor_id == 0x11060440)
+               spec->stream_name_digital = "VT1818S Digital";
+       else
+               spec->stream_name_digital = "VT1708S Digital";
+       spec->stream_digital_playback = &vt1708S_pcm_digital_playback;
+
+       if (!spec->adc_nids && spec->input_mux) {
+               spec->adc_nids = vt1708S_adc_nids;
+               spec->num_adc_nids = ARRAY_SIZE(vt1708S_adc_nids);
+               get_mux_nids(codec);
+               override_mic_boost(codec, 0x1a, 0, 3, 40);
+               override_mic_boost(codec, 0x1e, 0, 3, 40);
+               spec->mixers[spec->num_mixers] = vt1708S_capture_mixer;
+               spec->num_mixers++;
+       }
+
+       codec->patch_ops = via_patch_ops;
+
+       codec->patch_ops.init = via_auto_init;
+       codec->patch_ops.unsol_event = via_unsol_event;
+#ifdef CONFIG_SND_HDA_POWER_SAVE
+       spec->loopback.amplist = vt1708S_loopbacks;
+#endif
+
+       /* correct names for VT1708BCE */
+       if (get_codec_type(codec) == VT1708BCE) {
+               kfree(codec->chip_name);
+               codec->chip_name = kstrdup("VT1708BCE", GFP_KERNEL);
+               snprintf(codec->bus->card->mixername,
+                        sizeof(codec->bus->card->mixername),
+                        "%s %s", codec->vendor_name, codec->chip_name);
+               spec->stream_name_analog = "VT1708BCE Analog";
+               spec->stream_name_digital = "VT1708BCE Digital";
+       }
+       return 0;
+}
+
+/* Patch for VT1702 */
+
+/* capture mixer elements */
+static struct snd_kcontrol_new vt1702_capture_mixer[] = {
+       HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("Capture Switch", 0x12, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x20, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x20, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Digital Mic Capture Volume", 0x1F, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("Digital Mic Capture Switch", 0x1F, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Digital Mic Boost Capture Volume", 0x1E, 0x0,
+                        HDA_INPUT),
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               /* The multiple "Capture Source" controls confuse alsamixer
+                * So call somewhat different..
+                */
+               /* .name = "Capture Source", */
+               .name = "Input Source",
+               .count = 1,
+               .info = via_mux_enum_info,
+               .get = via_mux_enum_get,
+               .put = via_mux_enum_put,
+       },
+       { } /* end */
+};
+
+static struct hda_verb vt1702_volume_init_verbs[] = {
+       /*
+        * Unmute ADC0-1 and set the default input to mic-in
+        */
+       {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x1F, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+
+
+       /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
+        * mixer widget
+        */
+       /* Amp Indices: Mic1 = 1, Line = 1, Mic2 = 3 */
+       {0x1A, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x1A, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       {0x1A, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
+       {0x1A, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
+       {0x1A, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
+
+       /* Setup default input of PW4 to MW0 */
+       {0x17, AC_VERB_SET_CONNECT_SEL, 0x1},
+       /* PW6 PW7 Output enable */
+       {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
+       {0x1C, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
+       /* mixer enable */
+       {0x1, 0xF88, 0x3},
+       /* GPIO 0~2 */
+       {0x1, 0xF82, 0x3F},
+       { }
+};
+
+static struct hda_verb vt1702_uniwill_init_verbs[] = {
+       {0x17, AC_VERB_SET_UNSOLICITED_ENABLE,
+        AC_USRSP_EN | VIA_HP_EVENT | VIA_JACK_EVENT},
+       {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
+       {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
+       {0x16, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
+       {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
+       { }
+};
+
+static struct hda_pcm_stream vt1702_pcm_analog_playback = {
+       .substreams = 2,
+       .channels_min = 2,
+       .channels_max = 2,
+       .nid = 0x10, /* NID to query formats and rates */
+       .ops = {
+               .open = via_playback_pcm_open,
+               .prepare = via_playback_multi_pcm_prepare,
+               .cleanup = via_playback_multi_pcm_cleanup,
+               .close = via_pcm_open_close
+       },
+};
+
+static struct hda_pcm_stream vt1702_pcm_analog_capture = {
+       .substreams = 3,
+       .channels_min = 2,
+       .channels_max = 2,
+       .nid = 0x12, /* NID to query formats and rates */
+       .ops = {
+               .open = via_pcm_open_close,
+               .prepare = via_capture_pcm_prepare,
+               .cleanup = via_capture_pcm_cleanup,
+               .close = via_pcm_open_close
+       },
+};
+
+static struct hda_pcm_stream vt1702_pcm_digital_playback = {
+       .substreams = 2,
+       .channels_min = 2,
+       .channels_max = 2,
+       /* NID is set in via_build_pcms */
+       .ops = {
+               .open = via_dig_playback_pcm_open,
+               .close = via_dig_playback_pcm_close,
+               .prepare = via_dig_playback_pcm_prepare,
+               .cleanup = via_dig_playback_pcm_cleanup
+       },
+};
+
+/* fill in the dac_nids table from the parsed pin configuration */
+static int vt1702_auto_fill_dac_nids(struct via_spec *spec,
+                                    const struct auto_pin_cfg *cfg)
+{
+       spec->multiout.num_dacs = 1;
+       spec->multiout.dac_nids = spec->private_dac_nids;
+
+       if (cfg->line_out_pins[0]) {
+               /* config dac list */
+               spec->multiout.dac_nids[0] = 0x10;
+       }
+
+       return 0;
+}
+
+/* add playback controls from the parsed DAC table */
+static int vt1702_auto_create_line_out_ctls(struct via_spec *spec,
+                                            const struct auto_pin_cfg *cfg)
+{
+       int err;
+
+       if (!cfg->line_out_pins[0])
+               return -1;
+
+       /* add control to mixer index 0 */
+       err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
+                             "Master Front Playback Volume",
+                             HDA_COMPOSE_AMP_VAL(0x1A, 3, 0, HDA_INPUT));
+       if (err < 0)
+               return err;
+       err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
+                             "Master Front Playback Switch",
+                             HDA_COMPOSE_AMP_VAL(0x1A, 3, 0, HDA_INPUT));
+       if (err < 0)
+               return err;
+
+       /* Front */
+       err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
+                             "Front Playback Volume",
+                             HDA_COMPOSE_AMP_VAL(0x10, 3, 0, HDA_OUTPUT));
+       if (err < 0)
+               return err;
+       err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
+                             "Front Playback Switch",
+                             HDA_COMPOSE_AMP_VAL(0x16, 3, 0, HDA_OUTPUT));
+       if (err < 0)
+               return err;
+
+       return 0;
+}
+
+static int vt1702_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
+{
+       int err, i;
+       struct hda_input_mux *imux;
+       static const char *texts[] = { "ON", "OFF", NULL};
+       if (!pin)
+               return 0;
+       spec->multiout.hp_nid = 0x1D;
+       spec->hp_independent_mode_index = 0;
+
+       err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
+                             "Headphone Playback Volume",
+                             HDA_COMPOSE_AMP_VAL(0x1D, 3, 0, HDA_OUTPUT));
+       if (err < 0)
+               return err;
+
+       err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
+                             "Headphone Playback Switch",
+                             HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
+       if (err < 0)
+               return err;
+
+       imux = &spec->private_imux[1];
+
+       /* for hp mode select */
+       i = 0;
+       while (texts[i] != NULL)        {
+               imux->items[imux->num_items].label =  texts[i];
+               imux->items[imux->num_items].index = i;
+               imux->num_items++;
+               i++;
+       }
+
+       spec->hp_mux = &spec->private_imux[1];
+       return 0;
+}
+
+/* create playback/capture controls for input pins */
+static int vt1702_auto_create_analog_input_ctls(struct via_spec *spec,
+                                               const struct auto_pin_cfg *cfg)
+{
+       static char *labels[] = {
+               "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
+       };
+       struct hda_input_mux *imux = &spec->private_imux[0];
+       int i, err, idx = 0;
+
+       /* for internal loopback recording select */
+       imux->items[imux->num_items].label = "Stereo Mixer";
+       imux->items[imux->num_items].index = 3;
+       imux->num_items++;
+
+       for (i = 0; i < AUTO_PIN_LAST; i++) {
+               if (!cfg->input_pins[i])
+                       continue;
+
+               switch (cfg->input_pins[i]) {
+               case 0x14: /* Mic */
+                       idx = 1;
+                       break;
+
+               case 0x15: /* Line In */
+                       idx = 2;
+                       break;
+
+               case 0x18: /* Front Mic */
+                       idx = 3;
+                       break;
+               }
+               err = via_new_analog_input(spec, labels[i], idx, 0x1A);
+               if (err < 0)
+                       return err;
+               imux->items[imux->num_items].label = labels[i];
+               imux->items[imux->num_items].index = idx-1;
+               imux->num_items++;
+       }
+       return 0;
+}
+
+static int vt1702_parse_auto_config(struct hda_codec *codec)
+{
+       struct via_spec *spec = codec->spec;
+       int err;
+
+       err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);
+       if (err < 0)
+               return err;
+       err = vt1702_auto_fill_dac_nids(spec, &spec->autocfg);
+       if (err < 0)
+               return err;
+       if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0])
+               return 0; /* can't find valid BIOS pin config */
+
+       err = vt1702_auto_create_line_out_ctls(spec, &spec->autocfg);
+       if (err < 0)
+               return err;
+       err = vt1702_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
+       if (err < 0)
+               return err;
+       /* limit AA path volume to 0 dB */
+       snd_hda_override_amp_caps(codec, 0x1A, HDA_INPUT,
+                                 (0x17 << AC_AMPCAP_OFFSET_SHIFT) |
+                                 (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) |
+                                 (0x5 << AC_AMPCAP_STEP_SIZE_SHIFT) |
+                                 (1 << AC_AMPCAP_MUTE_SHIFT));
+       err = vt1702_auto_create_analog_input_ctls(spec, &spec->autocfg);
+       if (err < 0)
+               return err;
+
+       spec->multiout.max_channels = spec->multiout.num_dacs * 2;
+
+       fill_dig_outs(codec);
+
+       if (spec->kctls.list)
+               spec->mixers[spec->num_mixers++] = spec->kctls.list;
+
+       spec->input_mux = &spec->private_imux[0];
+
+       if (spec->hp_mux)
+               spec->mixers[spec->num_mixers++] = via_hp_mixer;
+
+       return 1;
+}
+
+#ifdef CONFIG_SND_HDA_POWER_SAVE
+static struct hda_amp_list vt1702_loopbacks[] = {
+       { 0x1A, HDA_INPUT, 1 },
+       { 0x1A, HDA_INPUT, 2 },
+       { 0x1A, HDA_INPUT, 3 },
+       { 0x1A, HDA_INPUT, 4 },
+       { } /* end */
+};
+#endif
+
+static int patch_vt1702(struct hda_codec *codec)
+{
+       struct via_spec *spec;
+       int err;
+
+       /* create a codec specific record */
+       spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+       if (spec == NULL)
+               return -ENOMEM;
+
+       codec->spec = spec;
+
+       /* automatic parse from the BIOS config */
+       err = vt1702_parse_auto_config(codec);
+       if (err < 0) {
+               via_free(codec);
+               return err;
+       } else if (!err) {
+               printk(KERN_INFO "hda_codec: Cannot set up configuration "
+                      "from BIOS.  Using genenic mode...\n");
+       }
+
+       spec->init_verbs[spec->num_iverbs++] = vt1702_volume_init_verbs;
+       spec->init_verbs[spec->num_iverbs++] = vt1702_uniwill_init_verbs;
+
+       spec->stream_name_analog = "VT1702 Analog";
+       spec->stream_analog_playback = &vt1702_pcm_analog_playback;
+       spec->stream_analog_capture = &vt1702_pcm_analog_capture;
+
+       spec->stream_name_digital = "VT1702 Digital";
+       spec->stream_digital_playback = &vt1702_pcm_digital_playback;
+
+       if (!spec->adc_nids && spec->input_mux) {
+               spec->adc_nids = vt1702_adc_nids;
+               spec->num_adc_nids = ARRAY_SIZE(vt1702_adc_nids);
+               get_mux_nids(codec);
+               spec->mixers[spec->num_mixers] = vt1702_capture_mixer;
+               spec->num_mixers++;
+       }
+
+       codec->patch_ops = via_patch_ops;
+
+       codec->patch_ops.init = via_auto_init;
+       codec->patch_ops.unsol_event = via_unsol_event;
+#ifdef CONFIG_SND_HDA_POWER_SAVE
+       spec->loopback.amplist = vt1702_loopbacks;
+#endif
+
+       return 0;
+}
+
+/* Patch for VT1718S */
+
+/* capture mixer elements */
+static struct snd_kcontrol_new vt1718S_capture_mixer[] = {
+       HDA_CODEC_VOLUME("Capture Volume", 0x10, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("Capture Switch", 0x10, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x11, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x11, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost Capture Volume", 0x2b, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Front Mic Boost Capture Volume", 0x29, 0x0,
+                        HDA_INPUT),
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               /* The multiple "Capture Source" controls confuse alsamixer
+                * So call somewhat different..
+                */
+               .name = "Input Source",
+               .count = 2,
+               .info = via_mux_enum_info,
+               .get = via_mux_enum_get,
+               .put = via_mux_enum_put,
+       },
+       { } /* end */
+};
+
+static struct hda_verb vt1718S_volume_init_verbs[] = {
+       /*
+        * Unmute ADC0-1 and set the default input to mic-in
+        */
+       {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+
+
+       /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
+        * mixer widget
+        */
+       /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
+       {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+       {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
+       {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
+       {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
+
+       /* Setup default input of Front HP to MW9 */
+       {0x28, AC_VERB_SET_CONNECT_SEL, 0x1},
+       /* PW9 PW10 Output enable */
+       {0x2d, AC_VERB_SET_PIN_WIDGET_CONTROL, AC_PINCTL_OUT_EN},
+       {0x2e, AC_VERB_SET_PIN_WIDGET_CONTROL, AC_PINCTL_OUT_EN},
+       /* PW11 Input enable */
+       {0x2f, AC_VERB_SET_PIN_WIDGET_CONTROL, AC_PINCTL_IN_EN},
+       /* Enable Boost Volume backdoor */
+       {0x1, 0xf88, 0x8},
+       /* MW0/1/2/3/4: un-mute index 0 (AOWx), mute index 1 (MW9) */
+       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+       {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+       {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+       /* set MUX1 = 2 (AOW4), MUX2 = 1 (AOW3) */
+       {0x34, AC_VERB_SET_CONNECT_SEL, 0x2},
+       {0x35, AC_VERB_SET_CONNECT_SEL, 0x1},
+       /* Unmute MW4's index 0 */
+       {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       { }
+};
+
+
+static struct hda_verb vt1718S_uniwill_init_verbs[] = {
+       {0x28, AC_VERB_SET_UNSOLICITED_ENABLE,
+        AC_USRSP_EN | VIA_HP_EVENT | VIA_JACK_EVENT},
+       {0x24, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
+       {0x25, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
+       {0x26, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
+       {0x27, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
+       {0x29, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
+       {0x2a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
+       {0x2b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
+       { }
+};
+
+static struct hda_pcm_stream vt1718S_pcm_analog_playback = {
+       .substreams = 2,
+       .channels_min = 2,
+       .channels_max = 10,
+       .nid = 0x8, /* NID to query formats and rates */
+       .ops = {
+               .open = via_playback_pcm_open,
+               .prepare = via_playback_multi_pcm_prepare,
+               .cleanup = via_playback_multi_pcm_cleanup,
+               .close = via_pcm_open_close,
+       },
+};
+
+static struct hda_pcm_stream vt1718S_pcm_analog_capture = {
+       .substreams = 2,
+       .channels_min = 2,
+       .channels_max = 2,
+       .nid = 0x10, /* NID to query formats and rates */
+       .ops = {
+               .open = via_pcm_open_close,
+               .prepare = via_capture_pcm_prepare,
+               .cleanup = via_capture_pcm_cleanup,
+               .close = via_pcm_open_close,
+       },
+};
+
+static struct hda_pcm_stream vt1718S_pcm_digital_playback = {
+       .substreams = 2,
+       .channels_min = 2,
+       .channels_max = 2,
+       /* NID is set in via_build_pcms */
+       .ops = {
+               .open = via_dig_playback_pcm_open,
+               .close = via_dig_playback_pcm_close,
+               .prepare = via_dig_playback_pcm_prepare,
+               .cleanup = via_dig_playback_pcm_cleanup
+       },
+};
+
+static struct hda_pcm_stream vt1718S_pcm_digital_capture = {
+       .substreams = 1,
+       .channels_min = 2,
+       .channels_max = 2,
+};
+
+/* fill in the dac_nids table from the parsed pin configuration */
+static int vt1718S_auto_fill_dac_nids(struct via_spec *spec,
+                                    const struct auto_pin_cfg *cfg)
+{
+       int i;
+       hda_nid_t nid;
+
+       spec->multiout.num_dacs = cfg->line_outs;
+
+       spec->multiout.dac_nids = spec->private_dac_nids;
+
+       for (i = 0; i < 4; i++) {
+               nid = cfg->line_out_pins[i];
+               if (nid) {
+                       /* config dac list */
+                       switch (i) {
+                       case AUTO_SEQ_FRONT:
+                               spec->multiout.dac_nids[i] = 0x8;
+                               break;
+                       case AUTO_SEQ_CENLFE:
+                               spec->multiout.dac_nids[i] = 0xa;
+                               break;
+                       case AUTO_SEQ_SURROUND:
+                               spec->multiout.dac_nids[i] = 0x9;
+                               break;
+                       case AUTO_SEQ_SIDE:
+                               spec->multiout.dac_nids[i] = 0xb;
+                               break;
+                       }
+               }
+       }
+
+       return 0;
+}
+
+/* add playback controls from the parsed DAC table */
+static int vt1718S_auto_create_multi_out_ctls(struct via_spec *spec,
+                                            const struct auto_pin_cfg *cfg)
+{
+       char name[32];
+       static const char *chname[4] = { "Front", "Surround", "C/LFE", "Side" };
+       hda_nid_t nid_vols[] = {0x8, 0x9, 0xa, 0xb};
+       hda_nid_t nid_mutes[] = {0x24, 0x25, 0x26, 0x27};
+       hda_nid_t nid, nid_vol, nid_mute = 0;
+       int i, err;
+
+       for (i = 0; i <= AUTO_SEQ_SIDE; i++) {
+               nid = cfg->line_out_pins[i];
+
+               if (!nid)
+                       continue;
+               nid_vol = nid_vols[i];
+               nid_mute = nid_mutes[i];
+
+               if (i == AUTO_SEQ_CENLFE) {
+                       /* Center/LFE */
+                       err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
+                                             "Center Playback Volume",
+                                             HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0,
+                                                                 HDA_OUTPUT));
+                       if (err < 0)
+                               return err;
+                       err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
+                                             "LFE Playback Volume",
+                                             HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0,
+                                                                 HDA_OUTPUT));
+                       if (err < 0)
+                               return err;
+                       err = via_add_control(
+                               spec, VIA_CTL_WIDGET_MUTE,
+                               "Center Playback Switch",
+                               HDA_COMPOSE_AMP_VAL(nid_mute, 1, 0,
+                                                   HDA_OUTPUT));
+                       if (err < 0)
+                               return err;
+                       err = via_add_control(
+                               spec, VIA_CTL_WIDGET_MUTE,
+                               "LFE Playback Switch",
+                               HDA_COMPOSE_AMP_VAL(nid_mute, 2, 0,
+                                                   HDA_OUTPUT));
+                       if (err < 0)
+                               return err;
+               } else if (i == AUTO_SEQ_FRONT) {
+                       /* Front */
+                       sprintf(name, "%s Playback Volume", chname[i]);
+                       err = via_add_control(
+                               spec, VIA_CTL_WIDGET_VOL, name,
+                               HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT));
+                       if (err < 0)
+                               return err;
+                       sprintf(name, "%s Playback Switch", chname[i]);
+                       err = via_add_control(
+                               spec, VIA_CTL_WIDGET_MUTE, name,
+                               HDA_COMPOSE_AMP_VAL(nid_mute, 3, 0,
+                                                   HDA_OUTPUT));
+                       if (err < 0)
+                               return err;
+               } else {
+                       sprintf(name, "%s Playback Volume", chname[i]);
+                       err = via_add_control(
+                               spec, VIA_CTL_WIDGET_VOL, name,
+                               HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT));
+                       if (err < 0)
+                               return err;
+                       sprintf(name, "%s Playback Switch", chname[i]);
+                       err = via_add_control(
+                               spec, VIA_CTL_WIDGET_MUTE, name,
+                               HDA_COMPOSE_AMP_VAL(nid_mute, 3, 0,
+                                                   HDA_OUTPUT));
+                       if (err < 0)
+                               return err;
+               }
+       }
+       return 0;
+}
+
+static int vt1718S_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
+{
+       int err;
+
+       if (!pin)
+               return 0;
+
+       spec->multiout.hp_nid = 0xc; /* AOW4 */
+       spec->hp_independent_mode_index = 1;
+
+       err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
+                             "Headphone Playback Volume",
+                             HDA_COMPOSE_AMP_VAL(0xc, 3, 0, HDA_OUTPUT));
+       if (err < 0)
+               return err;
+
+       err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
+                             "Headphone Playback Switch",
+                             HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
+       if (err < 0)
+               return err;
+
+       create_hp_imux(spec);
+       return 0;
+}
+
+/* create playback/capture controls for input pins */
+static int vt1718S_auto_create_analog_input_ctls(struct via_spec *spec,
+                                               const struct auto_pin_cfg *cfg)
+{
+       static char *labels[] = {
+               "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
+       };
+       struct hda_input_mux *imux = &spec->private_imux[0];
+       int i, err, idx = 0;
+
+       /* for internal loopback recording select */
+       imux->items[imux->num_items].label = "Stereo Mixer";
+       imux->items[imux->num_items].index = 5;
+       imux->num_items++;
+
+       for (i = 0; i < AUTO_PIN_LAST; i++) {
+               if (!cfg->input_pins[i])
+                       continue;
+
+               switch (cfg->input_pins[i]) {
+               case 0x2b: /* Mic */
+                       idx = 1;
+                       break;
+
+               case 0x2a: /* Line In */
+                       idx = 2;
+                       break;
+
+               case 0x29: /* Front Mic */
+                       idx = 3;
+                       break;
+
+               case 0x2c: /* CD */
+                       idx = 0;
+                       break;
+               }
+               err = via_new_analog_input(spec, labels[i], idx, 0x21);
+               if (err < 0)
+                       return err;
+               imux->items[imux->num_items].label = labels[i];
+               imux->items[imux->num_items].index = idx;
+               imux->num_items++;
+       }
+       return 0;
+}
+
+static int vt1718S_parse_auto_config(struct hda_codec *codec)
+{
+       struct via_spec *spec = codec->spec;
+       int err;
+
+       err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);
+
+       if (err < 0)
+               return err;
+       err = vt1718S_auto_fill_dac_nids(spec, &spec->autocfg);
+       if (err < 0)
+               return err;
+       if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0])
+               return 0; /* can't find valid BIOS pin config */
+
+       err = vt1718S_auto_create_multi_out_ctls(spec, &spec->autocfg);
+       if (err < 0)
+               return err;
+       err = vt1718S_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
+       if (err < 0)
+               return err;
+       err = vt1718S_auto_create_analog_input_ctls(spec, &spec->autocfg);
+       if (err < 0)
+               return err;
+
+       spec->multiout.max_channels = spec->multiout.num_dacs * 2;
+
+       fill_dig_outs(codec);
+
+       if (spec->autocfg.dig_in_pin && codec->vendor_id == 0x11060428)
+               spec->dig_in_nid = 0x13;
+
+       if (spec->kctls.list)
+               spec->mixers[spec->num_mixers++] = spec->kctls.list;
+
+       spec->input_mux = &spec->private_imux[0];
+
+       if (spec->hp_mux)
+               spec->mixers[spec->num_mixers++] = via_hp_mixer;
+
+       spec->mixers[spec->num_mixers++] = via_smart51_mixer;
+
+       return 1;
+}
+
+#ifdef CONFIG_SND_HDA_POWER_SAVE
+static struct hda_amp_list vt1718S_loopbacks[] = {
+       { 0x21, HDA_INPUT, 1 },
+       { 0x21, HDA_INPUT, 2 },
+       { 0x21, HDA_INPUT, 3 },
+       { 0x21, HDA_INPUT, 4 },
+       { } /* end */
+};
+#endif
+
+static int patch_vt1718S(struct hda_codec *codec)
+{
+       struct via_spec *spec;
+       int err;
+
+       /* create a codec specific record */
+       spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+       if (spec == NULL)
+               return -ENOMEM;
+
+       codec->spec = spec;
+
+       /* automatic parse from the BIOS config */
+       err = vt1718S_parse_auto_config(codec);
+       if (err < 0) {
+               via_free(codec);
+               return err;
+       } else if (!err) {
+               printk(KERN_INFO "hda_codec: Cannot set up configuration "
+                      "from BIOS.  Using genenic mode...\n");
+       }
+
+       spec->init_verbs[spec->num_iverbs++] = vt1718S_volume_init_verbs;
+       spec->init_verbs[spec->num_iverbs++] = vt1718S_uniwill_init_verbs;
+
+       if (codec->vendor_id == 0x11060441)
+               spec->stream_name_analog = "VT2020 Analog";
+       else if (codec->vendor_id == 0x11064441)
+               spec->stream_name_analog = "VT1828S Analog";
+       else
+               spec->stream_name_analog = "VT1718S Analog";
+       spec->stream_analog_playback = &vt1718S_pcm_analog_playback;
+       spec->stream_analog_capture = &vt1718S_pcm_analog_capture;
+
+       if (codec->vendor_id == 0x11060441)
+               spec->stream_name_digital = "VT2020 Digital";
+       else if (codec->vendor_id == 0x11064441)
+               spec->stream_name_digital = "VT1828S Digital";
+       else
+               spec->stream_name_digital = "VT1718S Digital";
+       spec->stream_digital_playback = &vt1718S_pcm_digital_playback;
+       if (codec->vendor_id == 0x11060428 || codec->vendor_id == 0x11060441)
+               spec->stream_digital_capture = &vt1718S_pcm_digital_capture;
+
+       if (!spec->adc_nids && spec->input_mux) {
+               spec->adc_nids = vt1718S_adc_nids;
+               spec->num_adc_nids = ARRAY_SIZE(vt1718S_adc_nids);
+               get_mux_nids(codec);
+               override_mic_boost(codec, 0x2b, 0, 3, 40);
+               override_mic_boost(codec, 0x29, 0, 3, 40);
+               spec->mixers[spec->num_mixers] = vt1718S_capture_mixer;
+               spec->num_mixers++;
+       }
+
+       codec->patch_ops = via_patch_ops;
+
+       codec->patch_ops.init = via_auto_init;
+       codec->patch_ops.unsol_event = via_unsol_event;
+
+#ifdef CONFIG_SND_HDA_POWER_SAVE
+       spec->loopback.amplist = vt1718S_loopbacks;
+#endif
+
+       return 0;
+}
+
+/* Patch for VT1716S */
+
+static int vt1716s_dmic_info(struct snd_kcontrol *kcontrol,
+                           struct snd_ctl_elem_info *uinfo)
+{
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+       uinfo->count = 1;
+       uinfo->value.integer.min = 0;
+       uinfo->value.integer.max = 1;
+       return 0;
+}
+
+static int vt1716s_dmic_get(struct snd_kcontrol *kcontrol,
+                          struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       int index = 0;
+
+       index = snd_hda_codec_read(codec, 0x26, 0,
+                                              AC_VERB_GET_CONNECT_SEL, 0);
+       if (index != -1)
+               *ucontrol->value.integer.value = index;
+
+       return 0;
+}
+
+static int vt1716s_dmic_put(struct snd_kcontrol *kcontrol,
+                          struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct via_spec *spec = codec->spec;
+       int index = *ucontrol->value.integer.value;
+
+       snd_hda_codec_write(codec, 0x26, 0,
+                                              AC_VERB_SET_CONNECT_SEL, index);
+       spec->dmic_enabled = index;
+       set_jack_power_state(codec);
+
+       return 1;
+}
+
+/* capture mixer elements */
+static struct snd_kcontrol_new vt1716S_capture_mixer[] = {
+       HDA_CODEC_VOLUME("Capture Volume", 0x13, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("Capture Switch", 0x13, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x14, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x14, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost Capture Volume", 0x1A, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Front Mic Boost Capture Volume", 0x1E, 0x0,
+                        HDA_INPUT),
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "Input Source",
+               .count = 1,
+               .info = via_mux_enum_info,
+               .get = via_mux_enum_get,
+               .put = via_mux_enum_put,
+       },
+       { } /* end */
+};
+
+static struct snd_kcontrol_new vt1716s_dmic_mixer[] = {
+       HDA_CODEC_VOLUME("Digital Mic Capture Volume", 0x22, 0x0, HDA_INPUT),
+       {
+        .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+        .name = "Digital Mic Capture Switch",
+        .count = 1,
+        .info = vt1716s_dmic_info,
+        .get = vt1716s_dmic_get,
+        .put = vt1716s_dmic_put,
+        },
+       {}                      /* end */
+};
+
+
+/* mono-out mixer elements */
+static struct snd_kcontrol_new vt1716S_mono_out_mixer[] = {
+       HDA_CODEC_MUTE("Mono Playback Switch", 0x2a, 0x0, HDA_OUTPUT),
+       { } /* end */
+};
+
+static struct hda_verb vt1716S_volume_init_verbs[] = {
+       /*
+        * Unmute ADC0-1 and set the default input to mic-in
+        */
+       {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+
+
+       /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
+        * mixer widget
+        */
+       /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
+       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
+       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
+       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
+
+       /* MUX Indices: Stereo Mixer = 5 */
+       {0x17, AC_VERB_SET_CONNECT_SEL, 0x5},
+
+       /* Setup default input of PW4 to MW0 */
+       {0x1d, AC_VERB_SET_CONNECT_SEL, 0x0},
+
+       /* Setup default input of SW1 as MW0 */
+       {0x18, AC_VERB_SET_CONNECT_SEL, 0x1},
+
+       /* Setup default input of SW4 as AOW0 */
+       {0x28, AC_VERB_SET_CONNECT_SEL, 0x1},
+
+       /* PW9 PW10 Output enable */
+       {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
+       {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
+
+       /* Unmute SW1, PW12 */
+       {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x2a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       /* PW12 Output enable */
+       {0x2a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
+       /* Enable Boost Volume backdoor */
+       {0x1, 0xf8a, 0x80},
+       /* don't bybass mixer */
+       {0x1, 0xf88, 0xc0},
+       /* Enable mono output */
+       {0x1, 0xf90, 0x08},
+       { }
+};
+
+
+static struct hda_verb vt1716S_uniwill_init_verbs[] = {
+       {0x1d, AC_VERB_SET_UNSOLICITED_ENABLE,
+        AC_USRSP_EN | VIA_HP_EVENT | VIA_JACK_EVENT},
+       {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
+       {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
+       {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
+       {0x1c, AC_VERB_SET_UNSOLICITED_ENABLE,
+        AC_USRSP_EN | VIA_MONO_EVENT | VIA_JACK_EVENT},
+       {0x1e, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
+       {0x23, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
+       { }
+};
+
+static struct hda_pcm_stream vt1716S_pcm_analog_playback = {
+       .substreams = 2,
+       .channels_min = 2,
+       .channels_max = 6,
+       .nid = 0x10, /* NID to query formats and rates */
+       .ops = {
+               .open = via_playback_pcm_open,
+               .prepare = via_playback_multi_pcm_prepare,
+               .cleanup = via_playback_multi_pcm_cleanup,
+               .close = via_pcm_open_close,
+       },
+};
+
+static struct hda_pcm_stream vt1716S_pcm_analog_capture = {
+       .substreams = 2,
+       .channels_min = 2,
+       .channels_max = 2,
+       .nid = 0x13, /* NID to query formats and rates */
+       .ops = {
+               .open = via_pcm_open_close,
+               .prepare = via_capture_pcm_prepare,
+               .cleanup = via_capture_pcm_cleanup,
+               .close = via_pcm_open_close,
+       },
+};
+
+static struct hda_pcm_stream vt1716S_pcm_digital_playback = {
+       .substreams = 2,
+       .channels_min = 2,
+       .channels_max = 2,
+       /* NID is set in via_build_pcms */
+       .ops = {
+               .open = via_dig_playback_pcm_open,
+               .close = via_dig_playback_pcm_close,
+               .prepare = via_dig_playback_pcm_prepare,
+               .cleanup = via_dig_playback_pcm_cleanup
+       },
+};
+
+/* fill in the dac_nids table from the parsed pin configuration */
+static int vt1716S_auto_fill_dac_nids(struct via_spec *spec,
+                                     const struct auto_pin_cfg *cfg)
+{      int i;
+       hda_nid_t nid;
+
+       spec->multiout.num_dacs = cfg->line_outs;
+
+       spec->multiout.dac_nids = spec->private_dac_nids;
+
+       for (i = 0; i < 3; i++) {
+               nid = cfg->line_out_pins[i];
+               if (nid) {
+                       /* config dac list */
+                       switch (i) {
+                       case AUTO_SEQ_FRONT:
+                               spec->multiout.dac_nids[i] = 0x10;
+                               break;
+                       case AUTO_SEQ_CENLFE:
+                               spec->multiout.dac_nids[i] = 0x25;
+                               break;
+                       case AUTO_SEQ_SURROUND:
+                               spec->multiout.dac_nids[i] = 0x11;
+                               break;
+                       }
+               }
+       }
+
+       return 0;
+}
+
+/* add playback controls from the parsed DAC table */
+static int vt1716S_auto_create_multi_out_ctls(struct via_spec *spec,
+                                             const struct auto_pin_cfg *cfg)
+{
+       char name[32];
+       static const char *chname[3] = { "Front", "Surround", "C/LFE" };
+       hda_nid_t nid_vols[] = {0x10, 0x11, 0x25};
+       hda_nid_t nid_mutes[] = {0x1C, 0x18, 0x27};
+       hda_nid_t nid, nid_vol, nid_mute;
+       int i, err;
+
+       for (i = 0; i <= AUTO_SEQ_CENLFE; i++) {
+               nid = cfg->line_out_pins[i];
+
+               if (!nid)
+                       continue;
+
+               nid_vol = nid_vols[i];
+               nid_mute = nid_mutes[i];
+
+               if (i == AUTO_SEQ_CENLFE) {
+                       err = via_add_control(
+                               spec, VIA_CTL_WIDGET_VOL,
+                               "Center Playback Volume",
+                               HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0, HDA_OUTPUT));
+                       if (err < 0)
+                               return err;
+                       err = via_add_control(
+                               spec, VIA_CTL_WIDGET_VOL,
+                               "LFE Playback Volume",
+                               HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0, HDA_OUTPUT));
+                       if (err < 0)
+                               return err;
+                       err = via_add_control(
+                               spec, VIA_CTL_WIDGET_MUTE,
+                               "Center Playback Switch",
+                               HDA_COMPOSE_AMP_VAL(nid_mute, 1, 0,
+                                                   HDA_OUTPUT));
+                       if (err < 0)
+                               return err;
+                       err = via_add_control(
+                               spec, VIA_CTL_WIDGET_MUTE,
+                               "LFE Playback Switch",
+                               HDA_COMPOSE_AMP_VAL(nid_mute, 2, 0,
+                                                   HDA_OUTPUT));
+                       if (err < 0)
+                               return err;
+               } else if (i == AUTO_SEQ_FRONT) {
+
+                       err = via_add_control(
+                               spec, VIA_CTL_WIDGET_VOL,
+                               "Master Front Playback Volume",
+                               HDA_COMPOSE_AMP_VAL(0x16, 3, 0, HDA_INPUT));
+                       if (err < 0)
+                               return err;
+                       err = via_add_control(
+                               spec, VIA_CTL_WIDGET_MUTE,
+                               "Master Front Playback Switch",
+                               HDA_COMPOSE_AMP_VAL(0x16, 3, 0, HDA_INPUT));
+                       if (err < 0)
+                               return err;
+
+                       sprintf(name, "%s Playback Volume", chname[i]);
+                       err = via_add_control(
+                               spec, VIA_CTL_WIDGET_VOL, name,
+                               HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT));
+                       if (err < 0)
+                               return err;
+                       sprintf(name, "%s Playback Switch", chname[i]);
+                       err = via_add_control(
+                               spec, VIA_CTL_WIDGET_MUTE, name,
+                               HDA_COMPOSE_AMP_VAL(nid_mute, 3, 0,
+                                                   HDA_OUTPUT));
+                       if (err < 0)
+                               return err;
+               } else {
+                       sprintf(name, "%s Playback Volume", chname[i]);
+                       err = via_add_control(
+                               spec, VIA_CTL_WIDGET_VOL, name,
+                               HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT));
+                       if (err < 0)
+                               return err;
+                       sprintf(name, "%s Playback Switch", chname[i]);
+                       err = via_add_control(
+                               spec, VIA_CTL_WIDGET_MUTE, name,
+                               HDA_COMPOSE_AMP_VAL(nid_mute, 3, 0,
+                                                   HDA_OUTPUT));
+                       if (err < 0)
+                               return err;
+               }
+       }
+       return 0;
+}
+
+static int vt1716S_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
+{
+       int err;
+
+       if (!pin)
+               return 0;
+
+       spec->multiout.hp_nid = 0x25; /* AOW3 */
+       spec->hp_independent_mode_index = 1;
+
+       err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
+                             "Headphone Playback Volume",
+                             HDA_COMPOSE_AMP_VAL(0x25, 3, 0, HDA_OUTPUT));
+       if (err < 0)
+               return err;
+
+       err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
+                             "Headphone Playback Switch",
+                             HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
+       if (err < 0)
+               return err;
+
+       create_hp_imux(spec);
+       return 0;
+}
+
+/* create playback/capture controls for input pins */
+static int vt1716S_auto_create_analog_input_ctls(struct via_spec *spec,
+                                               const struct auto_pin_cfg *cfg)
+{
+       static char *labels[] = {
+               "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
+       };
+       struct hda_input_mux *imux = &spec->private_imux[0];
+       int i, err, idx = 0;
+
+       /* for internal loopback recording select */
+       imux->items[imux->num_items].label = "Stereo Mixer";
+       imux->items[imux->num_items].index = 5;
+       imux->num_items++;
+
+       for (i = 0; i < AUTO_PIN_LAST; i++) {
+               if (!cfg->input_pins[i])
+                       continue;
+
+               switch (cfg->input_pins[i]) {
+               case 0x1a: /* Mic */
+                       idx = 2;
+                       break;
+
+               case 0x1b: /* Line In */
+                       idx = 3;
+                       break;
+
+               case 0x1e: /* Front Mic */
+                       idx = 4;
+                       break;
+
+               case 0x1f: /* CD */
+                       idx = 1;
+                       break;
+               }
+               err = via_new_analog_input(spec, labels[i], idx, 0x16);
+               if (err < 0)
+                       return err;
+               imux->items[imux->num_items].label = labels[i];
+               imux->items[imux->num_items].index = idx-1;
+               imux->num_items++;
+       }
+       return 0;
+}
+
+static int vt1716S_parse_auto_config(struct hda_codec *codec)
+{
+       struct via_spec *spec = codec->spec;
+       int err;
+
+       err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);
+       if (err < 0)
+               return err;
+       err = vt1716S_auto_fill_dac_nids(spec, &spec->autocfg);
+       if (err < 0)
+               return err;
+       if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0])
+               return 0; /* can't find valid BIOS pin config */
+
+       err = vt1716S_auto_create_multi_out_ctls(spec, &spec->autocfg);
+       if (err < 0)
+               return err;
+       err = vt1716S_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
+       if (err < 0)
+               return err;
+       err = vt1716S_auto_create_analog_input_ctls(spec, &spec->autocfg);
+       if (err < 0)
+               return err;
+
+       spec->multiout.max_channels = spec->multiout.num_dacs * 2;
+
+       fill_dig_outs(codec);
+
+       if (spec->kctls.list)
+               spec->mixers[spec->num_mixers++] = spec->kctls.list;
+
+       spec->input_mux = &spec->private_imux[0];
+
+       if (spec->hp_mux)
+               spec->mixers[spec->num_mixers++] = via_hp_mixer;
+
+       spec->mixers[spec->num_mixers++] = via_smart51_mixer;
+
+       return 1;
+}
+
+#ifdef CONFIG_SND_HDA_POWER_SAVE
+static struct hda_amp_list vt1716S_loopbacks[] = {
+       { 0x16, HDA_INPUT, 1 },
+       { 0x16, HDA_INPUT, 2 },
+       { 0x16, HDA_INPUT, 3 },
+       { 0x16, HDA_INPUT, 4 },
+       { } /* end */
+};
+#endif
+
+static int patch_vt1716S(struct hda_codec *codec)
+{
+       struct via_spec *spec;
+       int err;
+
+       /* create a codec specific record */
+       spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+       if (spec == NULL)
+               return -ENOMEM;
+
+       codec->spec = spec;
+
+       /* automatic parse from the BIOS config */
+       err = vt1716S_parse_auto_config(codec);
+       if (err < 0) {
+               via_free(codec);
+               return err;
+       } else if (!err) {
+               printk(KERN_INFO "hda_codec: Cannot set up configuration "
+                      "from BIOS.  Using genenic mode...\n");
+       }
+
+       spec->init_verbs[spec->num_iverbs++]  = vt1716S_volume_init_verbs;
+       spec->init_verbs[spec->num_iverbs++] = vt1716S_uniwill_init_verbs;
+
+       spec->stream_name_analog = "VT1716S Analog";
+       spec->stream_analog_playback = &vt1716S_pcm_analog_playback;
+       spec->stream_analog_capture = &vt1716S_pcm_analog_capture;
+
+       spec->stream_name_digital = "VT1716S Digital";
+       spec->stream_digital_playback = &vt1716S_pcm_digital_playback;
+
+       if (!spec->adc_nids && spec->input_mux) {
+               spec->adc_nids = vt1716S_adc_nids;
+               spec->num_adc_nids = ARRAY_SIZE(vt1716S_adc_nids);
+               get_mux_nids(codec);
+               override_mic_boost(codec, 0x1a, 0, 3, 40);
+               override_mic_boost(codec, 0x1e, 0, 3, 40);
+               spec->mixers[spec->num_mixers] = vt1716S_capture_mixer;
+               spec->num_mixers++;
+       }
+
+       spec->mixers[spec->num_mixers] = vt1716s_dmic_mixer;
+       spec->num_mixers++;
+
+       spec->mixers[spec->num_mixers++] = vt1716S_mono_out_mixer;
+
+       codec->patch_ops = via_patch_ops;
+
+       codec->patch_ops.init = via_auto_init;
+       codec->patch_ops.unsol_event = via_unsol_event;
+
+#ifdef CONFIG_SND_HDA_POWER_SAVE
+       spec->loopback.amplist = vt1716S_loopbacks;
+#endif
+
+       return 0;
+}
+
+/* for vt2002P */
+
+/* capture mixer elements */
+static struct snd_kcontrol_new vt2002P_capture_mixer[] = {
+       HDA_CODEC_VOLUME("Capture Volume", 0x10, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("Capture Switch", 0x10, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x11, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x11, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost Capture Volume", 0x2b, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Front Mic Boost Capture Volume", 0x29, 0x0,
+                        HDA_INPUT),
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               /* The multiple "Capture Source" controls confuse alsamixer
+                * So call somewhat different..
+                */
+               /* .name = "Capture Source", */
+               .name = "Input Source",
+               .count = 2,
+               .info = via_mux_enum_info,
+               .get = via_mux_enum_get,
+               .put = via_mux_enum_put,
+       },
+       { } /* end */
+};
+
+static struct hda_verb vt2002P_volume_init_verbs[] = {
+       /*
+        * Unmute ADC0-1 and set the default input to mic-in
+        */
+       {0x8, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x9, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+
+
+       /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
+        * mixer widget
+        */
+       /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
+       {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+       {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
+       {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
+       {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
+
+       /* MUX Indices: Mic = 0 */
+       {0x1e, AC_VERB_SET_CONNECT_SEL, 0},
+       {0x1f, AC_VERB_SET_CONNECT_SEL, 0},
+
+       /* PW9 Output enable */
+       {0x2d, AC_VERB_SET_PIN_WIDGET_CONTROL, AC_PINCTL_OUT_EN},
+
+       /* Enable Boost Volume backdoor */
+       {0x1, 0xfb9, 0x24},
+
+       /* MW0/1/4/8: un-mute index 0 (MUXx), un-mute index 1 (MW9) */
+       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+
+       /* set MUX0/1/4/8 = 0 (AOW0) */
+       {0x34, AC_VERB_SET_CONNECT_SEL, 0},
+       {0x35, AC_VERB_SET_CONNECT_SEL, 0},
+       {0x37, AC_VERB_SET_CONNECT_SEL, 0},
+       {0x3b, AC_VERB_SET_CONNECT_SEL, 0},
+
+       /* set PW0 index=0 (MW0) */
+       {0x24, AC_VERB_SET_CONNECT_SEL, 0},
+
+       /* Enable AOW0 to MW9 */
+       {0x1, 0xfb8, 0x88},
+       { }
+};
+
+
+static struct hda_verb vt2002P_uniwill_init_verbs[] = {
+       {0x25, AC_VERB_SET_UNSOLICITED_ENABLE,
+        AC_USRSP_EN | VIA_JACK_EVENT | VIA_BIND_HP_EVENT},
+       {0x26, AC_VERB_SET_UNSOLICITED_ENABLE,
+        AC_USRSP_EN | VIA_JACK_EVENT | VIA_BIND_HP_EVENT},
+       {0x29, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
+       {0x2a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
+       {0x2b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
+       { }
+};
+
+static struct hda_pcm_stream vt2002P_pcm_analog_playback = {
+       .substreams = 2,
+       .channels_min = 2,
+       .channels_max = 2,
+       .nid = 0x8, /* NID to query formats and rates */
+       .ops = {
+               .open = via_playback_pcm_open,
+               .prepare = via_playback_multi_pcm_prepare,
+               .cleanup = via_playback_multi_pcm_cleanup,
+               .close = via_pcm_open_close,
+       },
+};
+
+static struct hda_pcm_stream vt2002P_pcm_analog_capture = {
+       .substreams = 2,
+       .channels_min = 2,
+       .channels_max = 2,
+       .nid = 0x10, /* NID to query formats and rates */
+       .ops = {
+               .open = via_pcm_open_close,
+               .prepare = via_capture_pcm_prepare,
+               .cleanup = via_capture_pcm_cleanup,
+               .close = via_pcm_open_close,
+       },
+};
+
+static struct hda_pcm_stream vt2002P_pcm_digital_playback = {
+       .substreams = 1,
+       .channels_min = 2,
+       .channels_max = 2,
+       /* NID is set in via_build_pcms */
+       .ops = {
+               .open = via_dig_playback_pcm_open,
+               .close = via_dig_playback_pcm_close,
+               .prepare = via_dig_playback_pcm_prepare,
+               .cleanup = via_dig_playback_pcm_cleanup
+       },
+};
+
+/* fill in the dac_nids table from the parsed pin configuration */
+static int vt2002P_auto_fill_dac_nids(struct via_spec *spec,
+                                     const struct auto_pin_cfg *cfg)
+{
+       spec->multiout.num_dacs = 1;
+       spec->multiout.dac_nids = spec->private_dac_nids;
+       if (cfg->line_out_pins[0])
+               spec->multiout.dac_nids[0] = 0x8;
+       return 0;
+}
+
+/* add playback controls from the parsed DAC table */
+static int vt2002P_auto_create_multi_out_ctls(struct via_spec *spec,
+                                            const struct auto_pin_cfg *cfg)
+{
+       int err;
+
+       if (!cfg->line_out_pins[0])
+               return -1;
+
+
+       /* Line-Out: PortE */
+       err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
+                             "Master Front Playback Volume",
+                             HDA_COMPOSE_AMP_VAL(0x8, 3, 0, HDA_OUTPUT));
+       if (err < 0)
+               return err;
+       err = via_add_control(spec, VIA_CTL_WIDGET_BIND_PIN_MUTE,
+                             "Master Front Playback Switch",
+                             HDA_COMPOSE_AMP_VAL(0x26, 3, 0, HDA_OUTPUT));
+       if (err < 0)
+               return err;
+
+       return 0;
+}
+
+static int vt2002P_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
 {
        int err;
 
        if (!pin)
                return 0;
 
-       spec->multiout.hp_nid = VT1708S_HP_NID; /* AOW3 */
+       spec->multiout.hp_nid = 0x9;
+       spec->hp_independent_mode_index = 1;
 
        err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
                              "Headphone Playback Volume",
-                             HDA_COMPOSE_AMP_VAL(0x25, 3, 0, HDA_OUTPUT));
+                             HDA_COMPOSE_AMP_VAL(
+                                     spec->multiout.hp_nid, 3, 0, HDA_OUTPUT));
        if (err < 0)
                return err;
 
        err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
                              "Headphone Playback Switch",
-                             HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
+                             HDA_COMPOSE_AMP_VAL(0x25, 3, 0, HDA_OUTPUT));
        if (err < 0)
                return err;
 
        create_hp_imux(spec);
-
        return 0;
 }
 
 /* create playback/capture controls for input pins */
-static int vt1708S_auto_create_analog_input_ctls(struct via_spec *spec,
+static int vt2002P_auto_create_analog_input_ctls(struct via_spec *spec,
                                                const struct auto_pin_cfg *cfg)
 {
        static char *labels[] = {
@@ -2754,89 +5639,73 @@ static int vt1708S_auto_create_analog_input_ctls(struct via_spec *spec,
        struct hda_input_mux *imux = &spec->private_imux[0];
        int i, err, idx = 0;
 
-       /* for internal loopback recording select */
-       imux->items[imux->num_items].label = "Stereo Mixer";
-       imux->items[imux->num_items].index = 5;
-       imux->num_items++;
-
        for (i = 0; i < AUTO_PIN_LAST; i++) {
                if (!cfg->input_pins[i])
                        continue;
 
                switch (cfg->input_pins[i]) {
-               case 0x1a: /* Mic */
-                       idx = 2;
-                       break;
-
-               case 0x1b: /* Line In */
-                       idx = 3;
+               case 0x2b: /* Mic */
+                       idx = 0;
                        break;
 
-               case 0x1e: /* Front Mic */
-                       idx = 4;
+               case 0x2a: /* Line In */
+                       idx = 1;
                        break;
 
-               case 0x1f: /* CD */
-                       idx = 1;
+               case 0x29: /* Front Mic */
+                       idx = 2;
                        break;
                }
-               err = via_new_analog_input(spec, cfg->input_pins[i], labels[i],
-                                          idx, 0x16);
+               err = via_new_analog_input(spec, labels[i], idx, 0x21);
                if (err < 0)
                        return err;
                imux->items[imux->num_items].label = labels[i];
-               imux->items[imux->num_items].index = idx-1;
+               imux->items[imux->num_items].index = idx;
                imux->num_items++;
        }
-       return 0;
-}
 
-/* fill out digital output widgets; one for master and one for slave outputs */
-static void fill_dig_outs(struct hda_codec *codec)
-{
-       struct via_spec *spec = codec->spec;
-       int i;
+       /* build volume/mute control of loopback */
+       err = via_new_analog_input(spec, "Stereo Mixer", 3, 0x21);
+       if (err < 0)
+               return err;
 
-       for (i = 0; i < spec->autocfg.dig_outs; i++) {
-               hda_nid_t nid;
-               int conn;
+       /* for internal loopback recording select */
+       imux->items[imux->num_items].label = "Stereo Mixer";
+       imux->items[imux->num_items].index = 3;
+       imux->num_items++;
 
-               nid = spec->autocfg.dig_out_pins[i];
-               if (!nid)
-                       continue;
-               conn = snd_hda_get_connections(codec, nid, &nid, 1);
-               if (conn < 1)
-                       continue;
-               if (!spec->multiout.dig_out_nid)
-                       spec->multiout.dig_out_nid = nid;
-               else {
-                       spec->slave_dig_outs[0] = nid;
-                       break; /* at most two dig outs */
-               }
-       }
+       /* for digital mic select */
+       imux->items[imux->num_items].label = "Digital Mic";
+       imux->items[imux->num_items].index = 4;
+       imux->num_items++;
+
+       return 0;
 }
 
-static int vt1708S_parse_auto_config(struct hda_codec *codec)
+static int vt2002P_parse_auto_config(struct hda_codec *codec)
 {
        struct via_spec *spec = codec->spec;
        int err;
 
+
        err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);
        if (err < 0)
                return err;
-       err = vt1708S_auto_fill_dac_nids(spec, &spec->autocfg);
+
+       err = vt2002P_auto_fill_dac_nids(spec, &spec->autocfg);
        if (err < 0)
                return err;
+
        if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0])
                return 0; /* can't find valid BIOS pin config */
 
-       err = vt1708S_auto_create_multi_out_ctls(spec, &spec->autocfg);
+       err = vt2002P_auto_create_multi_out_ctls(spec, &spec->autocfg);
        if (err < 0)
                return err;
-       err = vt1708S_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
+       err = vt2002P_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
        if (err < 0)
                return err;
-       err = vt1708S_auto_create_analog_input_ctls(spec, &spec->autocfg);
+       err = vt2002P_auto_create_analog_input_ctls(spec, &spec->autocfg);
        if (err < 0)
                return err;
 
@@ -2856,16 +5725,17 @@ static int vt1708S_parse_auto_config(struct hda_codec *codec)
 }
 
 #ifdef CONFIG_SND_HDA_POWER_SAVE
-static struct hda_amp_list vt1708S_loopbacks[] = {
-       { 0x16, HDA_INPUT, 1 },
-       { 0x16, HDA_INPUT, 2 },
-       { 0x16, HDA_INPUT, 3 },
-       { 0x16, HDA_INPUT, 4 },
+static struct hda_amp_list vt2002P_loopbacks[] = {
+       { 0x21, HDA_INPUT, 0 },
+       { 0x21, HDA_INPUT, 1 },
+       { 0x21, HDA_INPUT, 2 },
        { } /* end */
 };
 #endif
 
-static int patch_vt1708S(struct hda_codec *codec)
+
+/* patch for vt2002P */
+static int patch_vt2002P(struct hda_codec *codec)
 {
        struct via_spec *spec;
        int err;
@@ -2878,7 +5748,7 @@ static int patch_vt1708S(struct hda_codec *codec)
        codec->spec = spec;
 
        /* automatic parse from the BIOS config */
-       err = vt1708S_parse_auto_config(codec);
+       err = vt2002P_parse_auto_config(codec);
        if (err < 0) {
                via_free(codec);
                return err;
@@ -2887,21 +5757,23 @@ static int patch_vt1708S(struct hda_codec *codec)
                       "from BIOS.  Using genenic mode...\n");
        }
 
-       spec->init_verbs[spec->num_iverbs++] = vt1708S_volume_init_verbs;
-       spec->init_verbs[spec->num_iverbs++] = vt1708S_uniwill_init_verbs;
+       spec->init_verbs[spec->num_iverbs++]  = vt2002P_volume_init_verbs;
+       spec->init_verbs[spec->num_iverbs++] = vt2002P_uniwill_init_verbs;
 
-       spec->stream_name_analog = "VT1708S Analog";
-       spec->stream_analog_playback = &vt1708S_pcm_analog_playback;
-       spec->stream_analog_capture = &vt1708S_pcm_analog_capture;
+       spec->stream_name_analog = "VT2002P Analog";
+       spec->stream_analog_playback = &vt2002P_pcm_analog_playback;
+       spec->stream_analog_capture = &vt2002P_pcm_analog_capture;
 
-       spec->stream_name_digital = "VT1708S Digital";
-       spec->stream_digital_playback = &vt1708S_pcm_digital_playback;
+       spec->stream_name_digital = "VT2002P Digital";
+       spec->stream_digital_playback = &vt2002P_pcm_digital_playback;
 
        if (!spec->adc_nids && spec->input_mux) {
-               spec->adc_nids = vt1708S_adc_nids;
-               spec->num_adc_nids = ARRAY_SIZE(vt1708S_adc_nids);
+               spec->adc_nids = vt2002P_adc_nids;
+               spec->num_adc_nids = ARRAY_SIZE(vt2002P_adc_nids);
                get_mux_nids(codec);
-               spec->mixers[spec->num_mixers] = vt1708S_capture_mixer;
+               override_mic_boost(codec, 0x2b, 0, 3, 40);
+               override_mic_boost(codec, 0x29, 0, 3, 40);
+               spec->mixers[spec->num_mixers] = vt2002P_capture_mixer;
                spec->num_mixers++;
        }
 
@@ -2909,33 +5781,32 @@ static int patch_vt1708S(struct hda_codec *codec)
 
        codec->patch_ops.init = via_auto_init;
        codec->patch_ops.unsol_event = via_unsol_event;
+
 #ifdef CONFIG_SND_HDA_POWER_SAVE
-       spec->loopback.amplist = vt1708S_loopbacks;
+       spec->loopback.amplist = vt2002P_loopbacks;
 #endif
 
        return 0;
 }
 
-/* Patch for VT1702 */
+/* for vt1812 */
 
 /* capture mixer elements */
-static struct snd_kcontrol_new vt1702_capture_mixer[] = {
-       HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE("Capture Switch", 0x12, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x20, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x20, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Digital Mic Capture Volume", 0x1F, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE("Digital Mic Capture Switch", 0x1F, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Digital Mic Boost Capture Volume", 0x1E, 0x0,
-                        HDA_INPUT),
+static struct snd_kcontrol_new vt1812_capture_mixer[] = {
+       HDA_CODEC_VOLUME("Capture Volume", 0x10, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("Capture Switch", 0x10, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x11, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x11, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Boost Capture Volume", 0x2b, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("Front Mic Boost Capture Volume", 0x29, 0x0,
+                      HDA_INPUT),
        {
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
                /* The multiple "Capture Source" controls confuse alsamixer
                 * So call somewhat different..
                 */
-               /* .name = "Capture Source", */
                .name = "Input Source",
-               .count = 1,
+               .count = 2,
                .info = via_mux_enum_info,
                .get = via_mux_enum_get,
                .put = via_mux_enum_put,
@@ -2943,64 +5814,99 @@ static struct snd_kcontrol_new vt1702_capture_mixer[] = {
        { } /* end */
 };
 
-static struct hda_verb vt1702_volume_init_verbs[] = {
+static struct hda_verb vt1812_volume_init_verbs[] = {
        /*
         * Unmute ADC0-1 and set the default input to mic-in
         */
-       {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x1F, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x8, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x9, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
 
 
-       /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
+       /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
         * mixer widget
         */
-       /* Amp Indices: Mic1 = 1, Line = 1, Mic2 = 3 */
-       {0x1A, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x1A, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       {0x1A, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
-       {0x1A, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
-       {0x1A, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
+       /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
+       {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+       {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
+       {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
+       {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
 
-       /* Setup default input of PW4 to MW0 */
-       {0x17, AC_VERB_SET_CONNECT_SEL, 0x1},
-       /* PW6 PW7 Output enable */
-       {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
-       {0x1C, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
+       /* MUX Indices: Mic = 0 */
+       {0x1e, AC_VERB_SET_CONNECT_SEL, 0},
+       {0x1f, AC_VERB_SET_CONNECT_SEL, 0},
+
+       /* PW9 Output enable */
+       {0x2d, AC_VERB_SET_PIN_WIDGET_CONTROL, AC_PINCTL_OUT_EN},
+
+       /* Enable Boost Volume backdoor */
+       {0x1, 0xfb9, 0x24},
+
+       /* MW0/1/4/13/15: un-mute index 0 (MUXx), un-mute index 1 (MW9) */
+       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+
+       /* set MUX0/1/4/13/15 = 0 (AOW0) */
+       {0x34, AC_VERB_SET_CONNECT_SEL, 0},
+       {0x35, AC_VERB_SET_CONNECT_SEL, 0},
+       {0x38, AC_VERB_SET_CONNECT_SEL, 0},
+       {0x3c, AC_VERB_SET_CONNECT_SEL, 0},
+       {0x3d, AC_VERB_SET_CONNECT_SEL, 0},
+
+       /* Enable AOW0 to MW9 */
+       {0x1, 0xfb8, 0xa8},
        { }
 };
 
-static struct hda_verb vt1702_uniwill_init_verbs[] = {
-       {0x01, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_GPIO_EVENT},
-       {0x17, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_HP_EVENT},
+
+static struct hda_verb vt1812_uniwill_init_verbs[] = {
+       {0x33, AC_VERB_SET_UNSOLICITED_ENABLE,
+        AC_USRSP_EN | VIA_JACK_EVENT | VIA_BIND_HP_EVENT},
+       {0x25, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT },
+       {0x28, AC_VERB_SET_UNSOLICITED_ENABLE,
+        AC_USRSP_EN | VIA_JACK_EVENT | VIA_BIND_HP_EVENT},
+       {0x29, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
+       {0x2a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
+       {0x2b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
        { }
 };
 
-static struct hda_pcm_stream vt1702_pcm_analog_playback = {
+static struct hda_pcm_stream vt1812_pcm_analog_playback = {
        .substreams = 2,
        .channels_min = 2,
        .channels_max = 2,
-       .nid = 0x10, /* NID to query formats and rates */
+       .nid = 0x8, /* NID to query formats and rates */
        .ops = {
                .open = via_playback_pcm_open,
                .prepare = via_playback_multi_pcm_prepare,
-               .cleanup = via_playback_multi_pcm_cleanup
+               .cleanup = via_playback_multi_pcm_cleanup,
+               .close = via_pcm_open_close,
        },
 };
 
-static struct hda_pcm_stream vt1702_pcm_analog_capture = {
-       .substreams = 3,
+static struct hda_pcm_stream vt1812_pcm_analog_capture = {
+       .substreams = 2,
        .channels_min = 2,
        .channels_max = 2,
-       .nid = 0x12, /* NID to query formats and rates */
+       .nid = 0x10, /* NID to query formats and rates */
        .ops = {
+               .open = via_pcm_open_close,
                .prepare = via_capture_pcm_prepare,
-               .cleanup = via_capture_pcm_cleanup
+               .cleanup = via_capture_pcm_cleanup,
+               .close = via_pcm_open_close,
        },
 };
 
-static struct hda_pcm_stream vt1702_pcm_digital_playback = {
-       .substreams = 2,
+static struct hda_pcm_stream vt1812_pcm_digital_playback = {
+       .substreams = 1,
        .channels_min = 2,
        .channels_max = 2,
        /* NID is set in via_build_pcms */
@@ -3011,24 +5917,20 @@ static struct hda_pcm_stream vt1702_pcm_digital_playback = {
                .cleanup = via_dig_playback_pcm_cleanup
        },
 };
-
 /* fill in the dac_nids table from the parsed pin configuration */
-static int vt1702_auto_fill_dac_nids(struct via_spec *spec,
+static int vt1812_auto_fill_dac_nids(struct via_spec *spec,
                                     const struct auto_pin_cfg *cfg)
 {
        spec->multiout.num_dacs = 1;
        spec->multiout.dac_nids = spec->private_dac_nids;
-
-       if (cfg->line_out_pins[0]) {
-               /* config dac list */
-               spec->multiout.dac_nids[0] = 0x10;
-       }
-
+       if (cfg->line_out_pins[0])
+               spec->multiout.dac_nids[0] = 0x8;
        return 0;
 }
 
+
 /* add playback controls from the parsed DAC table */
-static int vt1702_auto_create_line_out_ctls(struct via_spec *spec,
+static int vt1812_auto_create_multi_out_ctls(struct via_spec *spec,
                                             const struct auto_pin_cfg *cfg)
 {
        int err;
@@ -3036,45 +5938,36 @@ static int vt1702_auto_create_line_out_ctls(struct via_spec *spec,
        if (!cfg->line_out_pins[0])
                return -1;
 
-       /* add control to mixer index 0 */
+       /* Line-Out: PortE */
        err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
                              "Master Front Playback Volume",
-                             HDA_COMPOSE_AMP_VAL(0x1A, 3, 0, HDA_INPUT));
+                             HDA_COMPOSE_AMP_VAL(0x8, 3, 0, HDA_OUTPUT));
        if (err < 0)
                return err;
-       err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
+       err = via_add_control(spec, VIA_CTL_WIDGET_BIND_PIN_MUTE,
                              "Master Front Playback Switch",
-                             HDA_COMPOSE_AMP_VAL(0x1A, 3, 0, HDA_INPUT));
-       if (err < 0)
-               return err;
-
-       /* Front */
-       err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
-                             "Front Playback Volume",
-                             HDA_COMPOSE_AMP_VAL(0x10, 3, 0, HDA_OUTPUT));
-       if (err < 0)
-               return err;
-       err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
-                             "Front Playback Switch",
-                             HDA_COMPOSE_AMP_VAL(0x16, 3, 0, HDA_OUTPUT));
+                             HDA_COMPOSE_AMP_VAL(0x28, 3, 0, HDA_OUTPUT));
        if (err < 0)
                return err;
 
        return 0;
 }
 
-static int vt1702_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
+static int vt1812_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
 {
        int err;
 
        if (!pin)
                return 0;
 
-       spec->multiout.hp_nid = 0x1D;
+       spec->multiout.hp_nid = 0x9;
+       spec->hp_independent_mode_index = 1;
+
 
        err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
                              "Headphone Playback Volume",
-                             HDA_COMPOSE_AMP_VAL(0x1D, 3, 0, HDA_OUTPUT));
+                             HDA_COMPOSE_AMP_VAL(
+                                     spec->multiout.hp_nid, 3, 0, HDA_OUTPUT));
        if (err < 0)
                return err;
 
@@ -3085,12 +5978,11 @@ static int vt1702_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
                return err;
 
        create_hp_imux(spec);
-
        return 0;
 }
 
 /* create playback/capture controls for input pins */
-static int vt1702_auto_create_analog_input_ctls(struct via_spec *spec,
+static int vt1812_auto_create_analog_input_ctls(struct via_spec *spec,
                                                const struct auto_pin_cfg *cfg)
 {
        static char *labels[] = {
@@ -3099,60 +5991,72 @@ static int vt1702_auto_create_analog_input_ctls(struct via_spec *spec,
        struct hda_input_mux *imux = &spec->private_imux[0];
        int i, err, idx = 0;
 
-       /* for internal loopback recording select */
-       imux->items[imux->num_items].label = "Stereo Mixer";
-       imux->items[imux->num_items].index = 3;
-       imux->num_items++;
-
        for (i = 0; i < AUTO_PIN_LAST; i++) {
                if (!cfg->input_pins[i])
                        continue;
 
                switch (cfg->input_pins[i]) {
-               case 0x14: /* Mic */
-                       idx = 1;
+               case 0x2b: /* Mic */
+                       idx = 0;
                        break;
 
-               case 0x15: /* Line In */
-                       idx = 2;
+               case 0x2a: /* Line In */
+                       idx = 1;
                        break;
 
-               case 0x18: /* Front Mic */
-                       idx = 3;
+               case 0x29: /* Front Mic */
+                       idx = 2;
                        break;
                }
-               err = via_new_analog_input(spec, cfg->input_pins[i],
-                                          labels[i], idx, 0x1A);
+               err = via_new_analog_input(spec, labels[i], idx, 0x21);
                if (err < 0)
                        return err;
                imux->items[imux->num_items].label = labels[i];
-               imux->items[imux->num_items].index = idx-1;
+               imux->items[imux->num_items].index = idx;
                imux->num_items++;
        }
+       /* build volume/mute control of loopback */
+       err = via_new_analog_input(spec, "Stereo Mixer", 5, 0x21);
+       if (err < 0)
+               return err;
+
+       /* for internal loopback recording select */
+       imux->items[imux->num_items].label = "Stereo Mixer";
+       imux->items[imux->num_items].index = 5;
+       imux->num_items++;
+
+       /* for digital mic select */
+       imux->items[imux->num_items].label = "Digital Mic";
+       imux->items[imux->num_items].index = 6;
+       imux->num_items++;
+
        return 0;
 }
 
-static int vt1702_parse_auto_config(struct hda_codec *codec)
+static int vt1812_parse_auto_config(struct hda_codec *codec)
 {
        struct via_spec *spec = codec->spec;
        int err;
 
+
        err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);
        if (err < 0)
                return err;
-       err = vt1702_auto_fill_dac_nids(spec, &spec->autocfg);
+       fill_dig_outs(codec);
+       err = vt1812_auto_fill_dac_nids(spec, &spec->autocfg);
        if (err < 0)
                return err;
-       if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0])
+
+       if (!spec->autocfg.line_outs && !spec->autocfg.hp_outs)
                return 0; /* can't find valid BIOS pin config */
 
-       err = vt1702_auto_create_line_out_ctls(spec, &spec->autocfg);
+       err = vt1812_auto_create_multi_out_ctls(spec, &spec->autocfg);
        if (err < 0)
                return err;
-       err = vt1702_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
+       err = vt1812_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
        if (err < 0)
                return err;
-       err = vt1702_auto_create_analog_input_ctls(spec, &spec->autocfg);
+       err = vt1812_auto_create_analog_input_ctls(spec, &spec->autocfg);
        if (err < 0)
                return err;
 
@@ -3172,21 +6076,20 @@ static int vt1702_parse_auto_config(struct hda_codec *codec)
 }
 
 #ifdef CONFIG_SND_HDA_POWER_SAVE
-static struct hda_amp_list vt1702_loopbacks[] = {
-       { 0x1A, HDA_INPUT, 1 },
-       { 0x1A, HDA_INPUT, 2 },
-       { 0x1A, HDA_INPUT, 3 },
-       { 0x1A, HDA_INPUT, 4 },
+static struct hda_amp_list vt1812_loopbacks[] = {
+       { 0x21, HDA_INPUT, 0 },
+       { 0x21, HDA_INPUT, 1 },
+       { 0x21, HDA_INPUT, 2 },
        { } /* end */
 };
 #endif
 
-static int patch_vt1702(struct hda_codec *codec)
+
+/* patch for vt1812 */
+static int patch_vt1812(struct hda_codec *codec)
 {
        struct via_spec *spec;
        int err;
-       unsigned int response;
-       unsigned char control;
 
        /* create a codec specific record */
        spec = kzalloc(sizeof(*spec), GFP_KERNEL);
@@ -3196,7 +6099,7 @@ static int patch_vt1702(struct hda_codec *codec)
        codec->spec = spec;
 
        /* automatic parse from the BIOS config */
-       err = vt1702_parse_auto_config(codec);
+       err = vt1812_parse_auto_config(codec);
        if (err < 0) {
                via_free(codec);
                return err;
@@ -3205,21 +6108,25 @@ static int patch_vt1702(struct hda_codec *codec)
                       "from BIOS.  Using genenic mode...\n");
        }
 
-       spec->init_verbs[spec->num_iverbs++] = vt1702_volume_init_verbs;
-       spec->init_verbs[spec->num_iverbs++] = vt1702_uniwill_init_verbs;
 
-       spec->stream_name_analog = "VT1702 Analog";
-       spec->stream_analog_playback = &vt1702_pcm_analog_playback;
-       spec->stream_analog_capture = &vt1702_pcm_analog_capture;
+       spec->init_verbs[spec->num_iverbs++]  = vt1812_volume_init_verbs;
+       spec->init_verbs[spec->num_iverbs++] = vt1812_uniwill_init_verbs;
+
+       spec->stream_name_analog = "VT1812 Analog";
+       spec->stream_analog_playback = &vt1812_pcm_analog_playback;
+       spec->stream_analog_capture = &vt1812_pcm_analog_capture;
+
+       spec->stream_name_digital = "VT1812 Digital";
+       spec->stream_digital_playback = &vt1812_pcm_digital_playback;
 
-       spec->stream_name_digital = "VT1702 Digital";
-       spec->stream_digital_playback = &vt1702_pcm_digital_playback;
 
        if (!spec->adc_nids && spec->input_mux) {
-               spec->adc_nids = vt1702_adc_nids;
-               spec->num_adc_nids = ARRAY_SIZE(vt1702_adc_nids);
+               spec->adc_nids = vt1812_adc_nids;
+               spec->num_adc_nids = ARRAY_SIZE(vt1812_adc_nids);
                get_mux_nids(codec);
-               spec->mixers[spec->num_mixers] = vt1702_capture_mixer;
+               override_mic_boost(codec, 0x2b, 0, 3, 40);
+               override_mic_boost(codec, 0x29, 0, 3, 40);
+               spec->mixers[spec->num_mixers] = vt1812_capture_mixer;
                spec->num_mixers++;
        }
 
@@ -3227,22 +6134,11 @@ static int patch_vt1702(struct hda_codec *codec)
 
        codec->patch_ops.init = via_auto_init;
        codec->patch_ops.unsol_event = via_unsol_event;
+
 #ifdef CONFIG_SND_HDA_POWER_SAVE
-       spec->loopback.amplist = vt1702_loopbacks;
+       spec->loopback.amplist = vt1812_loopbacks;
 #endif
 
-       /* Open backdoor */
-       response = snd_hda_codec_read(codec, codec->afg, 0, 0xF8C, 0);
-       control = (unsigned char)(response & 0xff);
-       control |= 0x3;
-       snd_hda_codec_write(codec,  codec->afg, 0, 0xF88, control);
-
-       /* Enable GPIO 0&1 for volume&mute control */
-       /* Enable GPIO 2 for DMIC-DATA */
-       response = snd_hda_codec_read(codec, codec->afg, 0, 0xF84, 0);
-       control = (unsigned char)((response >> 16) & 0x3f);
-       snd_hda_codec_write(codec,  codec->afg, 0, 0xF82, control);
-
        return 0;
 }
 
@@ -3318,6 +6214,23 @@ static struct hda_codec_preset snd_hda_preset_via[] = {
          .patch = patch_vt1702},
        { .id = 0x11067398, .name = "VT1702",
          .patch = patch_vt1702},
+       { .id = 0x11060428, .name = "VT1718S",
+         .patch = patch_vt1718S},
+       { .id = 0x11064428, .name = "VT1718S",
+         .patch = patch_vt1718S},
+       { .id = 0x11060441, .name = "VT2020",
+         .patch = patch_vt1718S},
+       { .id = 0x11064441, .name = "VT1828S",
+         .patch = patch_vt1718S},
+       { .id = 0x11060433, .name = "VT1716S",
+         .patch = patch_vt1716S},
+       { .id = 0x1106a721, .name = "VT1716S",
+         .patch = patch_vt1716S},
+       { .id = 0x11060438, .name = "VT2002P", .patch = patch_vt2002P},
+       { .id = 0x11064438, .name = "VT2002P", .patch = patch_vt2002P},
+       { .id = 0x11060448, .name = "VT1812", .patch = patch_vt1812},
+       { .id = 0x11060440, .name = "VT1818S",
+         .patch = patch_vt1708S},
        {} /* terminator */
 };
 
index 536eae2..f7ce33f 100644 (file)
@@ -5,7 +5,7 @@
 
 snd-ice17xx-ak4xxx-objs := ak4xxx.o
 snd-ice1712-objs := ice1712.o delta.o hoontech.o ews.o
-snd-ice1724-objs := ice1724.o amp.o revo.o aureon.o vt1720_mobo.o pontis.o prodigy192.o prodigy_hifi.o juli.o phase.o wtm.o se.o maya44.o
+snd-ice1724-objs := ice1724.o amp.o revo.o aureon.o vt1720_mobo.o pontis.o prodigy192.o prodigy_hifi.o juli.o phase.o wtm.o se.o maya44.o quartet.o
 
 # Toplevel Module Dependency
 obj-$(CONFIG_SND_ICE1712) += snd-ice1712.o snd-ice17xx-ak4xxx.o
index d74033a..c7cff6f 100644 (file)
@@ -298,6 +298,16 @@ static void snd_ice1712_set_gpio_dir(struct snd_ice1712 *ice, unsigned int data)
        inb(ICEREG(ice, DATA)); /* dummy read for pci-posting */
 }
 
+static unsigned int snd_ice1712_get_gpio_dir(struct snd_ice1712 *ice)
+{
+       return snd_ice1712_read(ice, ICE1712_IREG_GPIO_DIRECTION);
+}
+
+static unsigned int snd_ice1712_get_gpio_mask(struct snd_ice1712 *ice)
+{
+       return snd_ice1712_read(ice, ICE1712_IREG_GPIO_WRITE_MASK);
+}
+
 static void snd_ice1712_set_gpio_mask(struct snd_ice1712 *ice, unsigned int data)
 {
        snd_ice1712_write(ice, ICE1712_IREG_GPIO_WRITE_MASK, data);
@@ -2557,7 +2567,9 @@ static int __devinit snd_ice1712_create(struct snd_card *card,
        mutex_init(&ice->i2c_mutex);
        mutex_init(&ice->open_mutex);
        ice->gpio.set_mask = snd_ice1712_set_gpio_mask;
+       ice->gpio.get_mask = snd_ice1712_get_gpio_mask;
        ice->gpio.set_dir = snd_ice1712_set_gpio_dir;
+       ice->gpio.get_dir = snd_ice1712_get_gpio_dir;
        ice->gpio.set_data = snd_ice1712_set_gpio_data;
        ice->gpio.get_data = snd_ice1712_get_gpio_data;
 
index d063149..0da778a 100644 (file)
@@ -359,7 +359,9 @@ struct snd_ice1712 {
                unsigned int saved[2];          /* for ewx_i2c */
                /* operators */
                void (*set_mask)(struct snd_ice1712 *ice, unsigned int data);
+               unsigned int (*get_mask)(struct snd_ice1712 *ice);
                void (*set_dir)(struct snd_ice1712 *ice, unsigned int data);
+               unsigned int (*get_dir)(struct snd_ice1712 *ice);
                void (*set_data)(struct snd_ice1712 *ice, unsigned int data);
                unsigned int (*get_data)(struct snd_ice1712 *ice);
                /* misc operators - move to another place? */
@@ -377,8 +379,11 @@ struct snd_ice1712 {
        unsigned int (*get_rate)(struct snd_ice1712 *ice);
        void (*set_rate)(struct snd_ice1712 *ice, unsigned int rate);
        unsigned char (*set_mclk)(struct snd_ice1712 *ice, unsigned int rate);
-       void (*set_spdif_clock)(struct snd_ice1712 *ice);
-
+       int (*set_spdif_clock)(struct snd_ice1712 *ice, int type);
+       int (*get_spdif_master_type)(struct snd_ice1712 *ice);
+       char **ext_clock_names;
+       int ext_clock_count;
+       void (*pro_open)(struct snd_ice1712 *, struct snd_pcm_substream *);
 #ifdef CONFIG_PM
        int (*pm_suspend)(struct snd_ice1712 *);
        int (*pm_resume)(struct snd_ice1712 *);
@@ -399,6 +404,11 @@ static inline void snd_ice1712_gpio_set_dir(struct snd_ice1712 *ice, unsigned in
        ice->gpio.set_dir(ice, bits);
 }
 
+static inline unsigned int snd_ice1712_gpio_get_dir(struct snd_ice1712 *ice)
+{
+       return ice->gpio.get_dir(ice);
+}
+
 static inline void snd_ice1712_gpio_set_mask(struct snd_ice1712 *ice, unsigned int bits)
 {
        ice->gpio.set_mask(ice, bits);
index 10fc92c..ae29073 100644 (file)
@@ -53,6 +53,7 @@
 #include "phase.h"
 #include "wtm.h"
 #include "se.h"
+#include "quartet.h"
 
 MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
 MODULE_DESCRIPTION("VIA ICEnsemble ICE1724/1720 (Envy24HT/PT)");
@@ -70,6 +71,7 @@ MODULE_SUPPORTED_DEVICE("{"
               PHASE_DEVICE_DESC
               WTM_DEVICE_DESC
               SE_DEVICE_DESC
+              QTET_DEVICE_DESC
                "{VIA,VT1720},"
                "{VIA,VT1724},"
                "{ICEnsemble,Generic ICE1724},"
@@ -104,6 +106,8 @@ static int PRO_RATE_LOCKED;
 static int PRO_RATE_RESET = 1;
 static unsigned int PRO_RATE_DEFAULT = 44100;
 
+static char *ext_clock_names[1] = { "IEC958 In" };
+
 /*
  *  Basic I/O
  */
@@ -118,9 +122,12 @@ static inline int stdclock_is_spdif_master(struct snd_ice1712 *ice)
        return (inb(ICEMT1724(ice, RATE)) & VT1724_SPDIF_MASTER) ? 1 : 0;
 }
 
+/*
+ * locking rate makes sense only for internal clock mode
+ */
 static inline int is_pro_rate_locked(struct snd_ice1712 *ice)
 {
-       return ice->is_spdif_master(ice) || PRO_RATE_LOCKED;
+       return (!ice->is_spdif_master(ice)) && PRO_RATE_LOCKED;
 }
 
 /*
@@ -196,6 +203,12 @@ static void snd_vt1724_set_gpio_dir(struct snd_ice1712 *ice, unsigned int data)
        inw(ICEREG1724(ice, GPIO_DIRECTION)); /* dummy read for pci-posting */
 }
 
+/* get gpio direction 0 = read, 1 = write */
+static unsigned int snd_vt1724_get_gpio_dir(struct snd_ice1712 *ice)
+{
+       return inl(ICEREG1724(ice, GPIO_DIRECTION));
+}
+
 /* set the gpio mask (0 = writable) */
 static void snd_vt1724_set_gpio_mask(struct snd_ice1712 *ice, unsigned int data)
 {
@@ -205,6 +218,17 @@ static void snd_vt1724_set_gpio_mask(struct snd_ice1712 *ice, unsigned int data)
        inw(ICEREG1724(ice, GPIO_WRITE_MASK)); /* dummy read for pci-posting */
 }
 
+static unsigned int snd_vt1724_get_gpio_mask(struct snd_ice1712 *ice)
+{
+       unsigned int mask;
+       if (!ice->vt1720)
+               mask = (unsigned int)inb(ICEREG1724(ice, GPIO_WRITE_MASK_22));
+       else
+               mask = 0;
+       mask = (mask << 16) | inw(ICEREG1724(ice, GPIO_WRITE_MASK));
+       return mask;
+}
+
 static void snd_vt1724_set_gpio_data(struct snd_ice1712 *ice, unsigned int data)
 {
        outw(data, ICEREG1724(ice, GPIO_DATA));
@@ -651,16 +675,22 @@ static int snd_vt1724_set_pro_rate(struct snd_ice1712 *ice, unsigned int rate,
                return ((rate == ice->cur_rate) && !force) ? 0 : -EBUSY;
        }
        if (!force && is_pro_rate_locked(ice)) {
+               /* comparing required and current rate - makes sense for
+                * internal clock only */
                spin_unlock_irqrestore(&ice->reg_lock, flags);
                return (rate == ice->cur_rate) ? 0 : -EBUSY;
        }
 
-       old_rate = ice->get_rate(ice);
-       if (force || (old_rate != rate))
-               ice->set_rate(ice, rate);
-       else if (rate == ice->cur_rate) {
-               spin_unlock_irqrestore(&ice->reg_lock, flags);
-               return 0;
+       if (force || !ice->is_spdif_master(ice)) {
+               /* force means the rate was switched by ucontrol, otherwise
+                * setting clock rate for internal clock mode */
+               old_rate = ice->get_rate(ice);
+               if (force || (old_rate != rate))
+                       ice->set_rate(ice, rate);
+               else if (rate == ice->cur_rate) {
+                       spin_unlock_irqrestore(&ice->reg_lock, flags);
+                       return 0;
+               }
        }
 
        ice->cur_rate = rate;
@@ -1016,6 +1046,8 @@ static int snd_vt1724_playback_pro_open(struct snd_pcm_substream *substream)
                                   VT1724_BUFFER_ALIGN);
        snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
                                   VT1724_BUFFER_ALIGN);
+       if (ice->pro_open)
+               ice->pro_open(ice, substream);
        return 0;
 }
 
@@ -1034,6 +1066,8 @@ static int snd_vt1724_capture_pro_open(struct snd_pcm_substream *substream)
                                   VT1724_BUFFER_ALIGN);
        snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
                                   VT1724_BUFFER_ALIGN);
+       if (ice->pro_open)
+               ice->pro_open(ice, substream);
        return 0;
 }
 
@@ -1787,15 +1821,21 @@ static int snd_vt1724_pro_internal_clock_info(struct snd_kcontrol *kcontrol,
                                              struct snd_ctl_elem_info *uinfo)
 {
        struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
-
+       int hw_rates_count = ice->hw_rates->count;
        uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
        uinfo->count = 1;
-       uinfo->value.enumerated.items = ice->hw_rates->count + 1;
+
+       uinfo->value.enumerated.items = hw_rates_count + ice->ext_clock_count;
+       /* upper limit - keep at top */
        if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
                uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
-       if (uinfo->value.enumerated.item == uinfo->value.enumerated.items - 1)
-               strcpy(uinfo->value.enumerated.name, "IEC958 Input");
+       if (uinfo->value.enumerated.item >= hw_rates_count)
+               /* ext_clock items */
+               strcpy(uinfo->value.enumerated.name,
+                               ice->ext_clock_names[
+                               uinfo->value.enumerated.item - hw_rates_count]);
        else
+               /* int clock items */
                sprintf(uinfo->value.enumerated.name, "%d",
                        ice->hw_rates->list[uinfo->value.enumerated.item]);
        return 0;
@@ -1809,7 +1849,8 @@ static int snd_vt1724_pro_internal_clock_get(struct snd_kcontrol *kcontrol,
 
        spin_lock_irq(&ice->reg_lock);
        if (ice->is_spdif_master(ice)) {
-               ucontrol->value.enumerated.item[0] = ice->hw_rates->count;
+               ucontrol->value.enumerated.item[0] = ice->hw_rates->count +
+                       ice->get_spdif_master_type(ice);
        } else {
                rate = ice->get_rate(ice);
                ucontrol->value.enumerated.item[0] = 0;
@@ -1824,8 +1865,14 @@ static int snd_vt1724_pro_internal_clock_get(struct snd_kcontrol *kcontrol,
        return 0;
 }
 
+static int stdclock_get_spdif_master_type(struct snd_ice1712 *ice)
+{
+       /* standard external clock - only single type - SPDIF IN */
+       return 0;
+}
+
 /* setting clock to external - SPDIF */
-static void stdclock_set_spdif_clock(struct snd_ice1712 *ice)
+static int stdclock_set_spdif_clock(struct snd_ice1712 *ice, int type)
 {
        unsigned char oval;
        unsigned char i2s_oval;
@@ -1834,27 +1881,30 @@ static void stdclock_set_spdif_clock(struct snd_ice1712 *ice)
        /* setting 256fs */
        i2s_oval = inb(ICEMT1724(ice, I2S_FORMAT));
        outb(i2s_oval & ~VT1724_MT_I2S_MCLK_128X, ICEMT1724(ice, I2S_FORMAT));
+       return 0;
 }
 
+
 static int snd_vt1724_pro_internal_clock_put(struct snd_kcontrol *kcontrol,
                                             struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
        unsigned int old_rate, new_rate;
        unsigned int item = ucontrol->value.enumerated.item[0];
-       unsigned int spdif = ice->hw_rates->count;
+       unsigned int first_ext_clock = ice->hw_rates->count;
 
-       if (item > spdif)
+       if (item >  first_ext_clock + ice->ext_clock_count - 1)
                return -EINVAL;
 
+       /* if rate = 0 => external clock */
        spin_lock_irq(&ice->reg_lock);
        if (ice->is_spdif_master(ice))
                old_rate = 0;
        else
                old_rate = ice->get_rate(ice);
-       if (item == spdif) {
-               /* switching to external clock via SPDIF */
-               ice->set_spdif_clock(ice);
+       if (item >= first_ext_clock) {
+               /* switching to external clock */
+               ice->set_spdif_clock(ice, item - first_ext_clock);
                new_rate = 0;
        } else {
                /* internal on-card clock */
@@ -1866,7 +1916,7 @@ static int snd_vt1724_pro_internal_clock_put(struct snd_kcontrol *kcontrol,
        }
        spin_unlock_irq(&ice->reg_lock);
 
-       /* the first reset to the SPDIF master mode? */
+       /* the first switch to the ext. clock mode? */
        if (old_rate != new_rate && !new_rate) {
                /* notify akm chips as well */
                unsigned int i;
@@ -2136,6 +2186,7 @@ static struct snd_ice1712_card_info *card_tables[] __devinitdata = {
        snd_vt1724_phase_cards,
        snd_vt1724_wtm_cards,
        snd_vt1724_se_cards,
+       snd_vt1724_qtet_cards,
        NULL,
 };
 
@@ -2434,7 +2485,9 @@ static int __devinit snd_vt1724_create(struct snd_card *card,
        mutex_init(&ice->open_mutex);
        mutex_init(&ice->i2c_mutex);
        ice->gpio.set_mask = snd_vt1724_set_gpio_mask;
+       ice->gpio.get_mask = snd_vt1724_get_gpio_mask;
        ice->gpio.set_dir = snd_vt1724_set_gpio_dir;
+       ice->gpio.get_dir = snd_vt1724_get_gpio_dir;
        ice->gpio.set_data = snd_vt1724_set_gpio_data;
        ice->gpio.get_data = snd_vt1724_get_gpio_data;
        ice->card = card;
@@ -2522,6 +2575,9 @@ static int __devinit snd_vt1724_probe(struct pci_dev *pci,
                return err;
        }
 
+       /* field init before calling chip_init */
+       ice->ext_clock_count = 0;
+
        for (tbl = card_tables; *tbl; tbl++) {
                for (c = *tbl; c->subvendor; c++) {
                        if (c->subvendor == ice->eeprom.subvendor) {
@@ -2560,6 +2616,13 @@ __found:
                ice->set_mclk = stdclock_set_mclk;
        if (!ice->set_spdif_clock)
                ice->set_spdif_clock = stdclock_set_spdif_clock;
+       if (!ice->get_spdif_master_type)
+               ice->get_spdif_master_type = stdclock_get_spdif_master_type;
+       if (!ice->ext_clock_names)
+               ice->ext_clock_names = ext_clock_names;
+       if (!ice->ext_clock_count)
+               ice->ext_clock_count = ARRAY_SIZE(ext_clock_names);
+
        if (!ice->hw_rates)
                set_std_hw_rates(ice);
 
@@ -2719,7 +2782,7 @@ static int snd_vt1724_resume(struct pci_dev *pci)
 
        if (ice->pm_saved_is_spdif_master) {
                /* switching to external clock via SPDIF */
-               ice->set_spdif_clock(ice);
+               ice->set_spdif_clock(ice, 0);
        } else {
                /* internal on-card clock */
                snd_vt1724_set_pro_rate(ice, ice->pro_rate_default, 1);
index fd948bf..0c9413d 100644 (file)
@@ -412,25 +412,6 @@ static struct snd_kcontrol_new juli_mute_controls[] __devinitdata = {
        },
 };
 
-
-static void ak4358_proc_regs_read(struct snd_info_entry *entry,
-               struct snd_info_buffer *buffer)
-{
-       struct snd_ice1712 *ice = (struct snd_ice1712 *)entry->private_data;
-       int reg, val;
-       for (reg = 0; reg <= 0xf; reg++) {
-               val =  snd_akm4xxx_get(ice->akm, 0, reg);
-               snd_iprintf(buffer, "0x%02x = 0x%02x\n", reg, val);
-       }
-}
-
-static void ak4358_proc_init(struct snd_ice1712 *ice)
-{
-       struct snd_info_entry *entry;
-       if (!snd_card_proc_new(ice->card, "ak4358_codec", &entry))
-               snd_info_set_text_ops(entry, ice, ak4358_proc_regs_read);
-}
-
 static char *slave_vols[] __devinitdata = {
        PCM_VOLUME,
        MONITOR_AN_IN_VOLUME,
@@ -496,14 +477,37 @@ static int __devinit juli_add_controls(struct snd_ice1712 *ice)
        /* only capture SPDIF over AK4114 */
        err = snd_ak4114_build(spec->ak4114, NULL,
                        ice->pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream);
-
-       ak4358_proc_init(ice);
        if (err < 0)
                return err;
        return 0;
 }
 
 /*
+ * suspend/resume
+ * */
+
+#ifdef CONFIG_PM
+static int juli_resume(struct snd_ice1712 *ice)
+{
+       struct snd_akm4xxx *ak = ice->akm;
+       struct juli_spec *spec = ice->spec;
+       /* akm4358 un-reset, un-mute */
+       snd_akm4xxx_reset(ak, 0);
+       /* reinit ak4114 */
+       snd_ak4114_reinit(spec->ak4114);
+       return 0;
+}
+
+static int juli_suspend(struct snd_ice1712 *ice)
+{
+       struct snd_akm4xxx *ak = ice->akm;
+       /* akm4358 reset and soft-mute */
+       snd_akm4xxx_reset(ak, 1);
+       return 0;
+}
+#endif
+
+/*
  * initialize the chip
  */
 
@@ -550,13 +554,14 @@ static inline unsigned char juli_set_mclk(struct snd_ice1712 *ice,
 }
 
 /* setting clock to external - SPDIF */
-static void juli_set_spdif_clock(struct snd_ice1712 *ice)
+static int juli_set_spdif_clock(struct snd_ice1712 *ice, int type)
 {
        unsigned int old;
        old = ice->gpio.get_data(ice);
        /* external clock (= 0), multiply 1x, 48kHz */
        ice->gpio.set_data(ice, (old & ~GPIO_RATE_MASK) | GPIO_MULTI_1X |
                        GPIO_FREQ_48KHZ);
+       return 0;
 }
 
 /* Called when ak4114 detects change in the input SPDIF stream */
@@ -646,6 +651,13 @@ static int __devinit juli_init(struct snd_ice1712 *ice)
        ice->set_spdif_clock = juli_set_spdif_clock;
 
        ice->spdif.ops.open = juli_spdif_in_open;
+
+#ifdef CONFIG_PM
+       ice->pm_resume = juli_resume;
+       ice->pm_suspend = juli_suspend;
+       ice->pm_suspend_enabled = 1;
+#endif
+
        return 0;
 }
 
diff --git a/sound/pci/ice1712/quartet.c b/sound/pci/ice1712/quartet.c
new file mode 100644 (file)
index 0000000..1948632
--- /dev/null
@@ -0,0 +1,1130 @@
+/*
+ *   ALSA driver for ICEnsemble VT1724 (Envy24HT)
+ *
+ *   Lowlevel functions for Infrasonic Quartet
+ *
+ *     Copyright (c) 2009 Pavel Hofman <pavel.hofman@ivitera.com>
+ *
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ *
+ */
+
+#include <asm/io.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/tlv.h>
+#include <sound/info.h>
+
+#include "ice1712.h"
+#include "envy24ht.h"
+#include <sound/ak4113.h>
+#include "quartet.h"
+
+struct qtet_spec {
+       struct ak4113 *ak4113;
+       unsigned int scr;       /* system control register */
+       unsigned int mcr;       /* monitoring control register */
+       unsigned int cpld;      /* cpld register */
+};
+
+struct qtet_kcontrol_private {
+       unsigned int bit;
+       void (*set_register)(struct snd_ice1712 *ice, unsigned int val);
+       unsigned int (*get_register)(struct snd_ice1712 *ice);
+       unsigned char *texts[2];
+};
+
+enum {
+       IN12_SEL = 0,
+       IN34_SEL,
+       AIN34_SEL,
+       COAX_OUT,
+       IN12_MON12,
+       IN12_MON34,
+       IN34_MON12,
+       IN34_MON34,
+       OUT12_MON34,
+       OUT34_MON12,
+};
+
+static char *ext_clock_names[3] = {"IEC958 In", "Word Clock 1xFS",
+       "Word Clock 256xFS"};
+
+/* chip address on I2C bus */
+#define AK4113_ADDR            0x26    /* S/PDIF receiver */
+
+/* chip address on SPI bus */
+#define AK4620_ADDR            0x02    /* ADC/DAC */
+
+
+/*
+ * GPIO pins
+ */
+
+/* GPIO0 - O - DATA0, def. 0 */
+#define GPIO_D0                        (1<<0)
+/* GPIO1 - I/O - DATA1, Jack Detect Input0 (0:present, 1:missing), def. 1 */
+#define GPIO_D1_JACKDTC0       (1<<1)
+/* GPIO2 - I/O - DATA2, Jack Detect Input1 (0:present, 1:missing), def. 1 */
+#define GPIO_D2_JACKDTC1       (1<<2)
+/* GPIO3 - I/O - DATA3, def. 1 */
+#define GPIO_D3                        (1<<3)
+/* GPIO4 - I/O - DATA4, SPI CDTO, def. 1 */
+#define GPIO_D4_SPI_CDTO       (1<<4)
+/* GPIO5 - I/O - DATA5, SPI CCLK, def. 1 */
+#define GPIO_D5_SPI_CCLK       (1<<5)
+/* GPIO6 - I/O - DATA6, Cable Detect Input (0:detected, 1:not detected */
+#define GPIO_D6_CD             (1<<6)
+/* GPIO7 - I/O - DATA7, Device Detect Input (0:detected, 1:not detected */
+#define GPIO_D7_DD             (1<<7)
+/* GPIO8 - O - CPLD Chip Select, def. 1 */
+#define GPIO_CPLD_CSN          (1<<8)
+/* GPIO9 - O - CPLD register read/write (0:write, 1:read), def. 0 */
+#define GPIO_CPLD_RW           (1<<9)
+/* GPIO10 - O - SPI Chip Select for CODEC#0, def. 1 */
+#define GPIO_SPI_CSN0          (1<<10)
+/* GPIO11 - O - SPI Chip Select for CODEC#1, def. 1 */
+#define GPIO_SPI_CSN1          (1<<11)
+/* GPIO12 - O - Ex. Register Output Enable (0:enable, 1:disable), def. 1,
+ * init 0 */
+#define GPIO_EX_GPIOE          (1<<12)
+/* GPIO13 - O - Ex. Register0 Chip Select for System Control Register,
+ * def. 1 */
+#define GPIO_SCR               (1<<13)
+/* GPIO14 - O - Ex. Register1 Chip Select for Monitor Control Register,
+ * def. 1 */
+#define GPIO_MCR               (1<<14)
+
+#define GPIO_SPI_ALL           (GPIO_D4_SPI_CDTO | GPIO_D5_SPI_CCLK |\
+               GPIO_SPI_CSN0 | GPIO_SPI_CSN1)
+
+#define GPIO_DATA_MASK         (GPIO_D0 | GPIO_D1_JACKDTC0 | \
+               GPIO_D2_JACKDTC1 | GPIO_D3 | \
+               GPIO_D4_SPI_CDTO | GPIO_D5_SPI_CCLK | \
+               GPIO_D6_CD | GPIO_D7_DD)
+
+/* System Control Register GPIO_SCR data bits */
+/* Mic/Line select relay (0:line, 1:mic) */
+#define SCR_RELAY              GPIO_D0
+/* Phantom power drive control (0:5V, 1:48V) */
+#define SCR_PHP_V              GPIO_D1_JACKDTC0
+/* H/W mute control (0:Normal, 1:Mute) */
+#define SCR_MUTE               GPIO_D2_JACKDTC1
+/* Phantom power control (0:Phantom on, 1:off) */
+#define SCR_PHP                        GPIO_D3
+/* Analog input 1/2 Source Select */
+#define SCR_AIN12_SEL0         GPIO_D4_SPI_CDTO
+#define SCR_AIN12_SEL1         GPIO_D5_SPI_CCLK
+/* Analog input 3/4 Source Select (0:line, 1:hi-z) */
+#define SCR_AIN34_SEL          GPIO_D6_CD
+/* Codec Power Down (0:power down, 1:normal) */
+#define SCR_CODEC_PDN          GPIO_D7_DD
+
+#define SCR_AIN12_LINE         (0)
+#define SCR_AIN12_MIC          (SCR_AIN12_SEL0)
+#define SCR_AIN12_LOWCUT       (SCR_AIN12_SEL1 | SCR_AIN12_SEL0)
+
+/* Monitor Control Register GPIO_MCR data bits */
+/* Input 1/2 to Monitor 1/2 (0:off, 1:on) */
+#define MCR_IN12_MON12         GPIO_D0
+/* Input 1/2 to Monitor 3/4 (0:off, 1:on) */
+#define MCR_IN12_MON34         GPIO_D1_JACKDTC0
+/* Input 3/4 to Monitor 1/2 (0:off, 1:on) */
+#define MCR_IN34_MON12         GPIO_D2_JACKDTC1
+/* Input 3/4 to Monitor 3/4 (0:off, 1:on) */
+#define MCR_IN34_MON34         GPIO_D3
+/* Output to Monitor 1/2 (0:off, 1:on) */
+#define MCR_OUT34_MON12                GPIO_D4_SPI_CDTO
+/* Output to Monitor 3/4 (0:off, 1:on) */
+#define MCR_OUT12_MON34                GPIO_D5_SPI_CCLK
+
+/* CPLD Register DATA bits */
+/* Clock Rate Select */
+#define CPLD_CKS0              GPIO_D0
+#define CPLD_CKS1              GPIO_D1_JACKDTC0
+#define CPLD_CKS2              GPIO_D2_JACKDTC1
+/* Sync Source Select (0:Internal, 1:External) */
+#define CPLD_SYNC_SEL          GPIO_D3
+/* Word Clock FS Select (0:FS, 1:256FS) */
+#define CPLD_WORD_SEL          GPIO_D4_SPI_CDTO
+/* Coaxial Output Source (IS-Link) (0:SPDIF, 1:I2S) */
+#define CPLD_COAX_OUT          GPIO_D5_SPI_CCLK
+/* Input 1/2 Source Select (0:Analog12, 1:An34) */
+#define CPLD_IN12_SEL          GPIO_D6_CD
+/* Input 3/4 Source Select (0:Analog34, 1:Digital In) */
+#define CPLD_IN34_SEL          GPIO_D7_DD
+
+/* internal clock (CPLD_SYNC_SEL = 0) options */
+#define CPLD_CKS_44100HZ       (0)
+#define CPLD_CKS_48000HZ       (CPLD_CKS0)
+#define CPLD_CKS_88200HZ       (CPLD_CKS1)
+#define CPLD_CKS_96000HZ       (CPLD_CKS1 | CPLD_CKS0)
+#define CPLD_CKS_176400HZ      (CPLD_CKS2)
+#define CPLD_CKS_192000HZ      (CPLD_CKS2 | CPLD_CKS0)
+
+#define CPLD_CKS_MASK          (CPLD_CKS0 | CPLD_CKS1 | CPLD_CKS2)
+
+/* external clock (CPLD_SYNC_SEL = 1) options */
+/* external clock - SPDIF */
+#define CPLD_EXT_SPDIF (0 | CPLD_SYNC_SEL)
+/* external clock - WordClock 1xfs */
+#define CPLD_EXT_WORDCLOCK_1FS (CPLD_CKS1 | CPLD_SYNC_SEL)
+/* external clock - WordClock 256xfs */
+#define CPLD_EXT_WORDCLOCK_256FS       (CPLD_CKS1 | CPLD_WORD_SEL |\
+               CPLD_SYNC_SEL)
+
+#define EXT_SPDIF_TYPE                 0
+#define EXT_WORDCLOCK_1FS_TYPE         1
+#define EXT_WORDCLOCK_256FS_TYPE       2
+
+#define AK4620_DFS0            (1<<0)
+#define AK4620_DFS1            (1<<1)
+#define AK4620_CKS0            (1<<2)
+#define AK4620_CKS1            (1<<3)
+/* Clock and Format Control register */
+#define AK4620_DFS_REG         0x02
+
+/* Deem and Volume Control register */
+#define AK4620_DEEMVOL_REG     0x03
+#define AK4620_SMUTE           (1<<7)
+
+/*
+ * Conversion from int value to its binary form. Used for debugging.
+ * The output buffer must be allocated prior to calling the function.
+ */
+static char *get_binary(char *buffer, int value)
+{
+       int i, j, pos;
+       pos = 0;
+       for (i = 0; i < 4; ++i) {
+               for (j = 0; j < 8; ++j) {
+                       if (value & (1 << (31-(i*8 + j))))
+                               buffer[pos] = '1';
+                       else
+                               buffer[pos] = '0';
+                       pos++;
+               }
+               if (i < 3) {
+                       buffer[pos] = ' ';
+                       pos++;
+               }
+       }
+       buffer[pos] = '\0';
+       return buffer;
+}
+
+/*
+ * Initial setup of the conversion array GPIO <-> rate
+ */
+static unsigned int qtet_rates[] = {
+       44100, 48000, 88200,
+       96000, 176400, 192000,
+};
+
+static unsigned int cks_vals[] = {
+       CPLD_CKS_44100HZ, CPLD_CKS_48000HZ, CPLD_CKS_88200HZ,
+       CPLD_CKS_96000HZ, CPLD_CKS_176400HZ, CPLD_CKS_192000HZ,
+};
+
+static struct snd_pcm_hw_constraint_list qtet_rates_info = {
+       .count = ARRAY_SIZE(qtet_rates),
+       .list = qtet_rates,
+       .mask = 0,
+};
+
+static void qtet_ak4113_write(void *private_data, unsigned char reg,
+               unsigned char val)
+{
+       snd_vt1724_write_i2c((struct snd_ice1712 *)private_data, AK4113_ADDR,
+                       reg, val);
+}
+
+static unsigned char qtet_ak4113_read(void *private_data, unsigned char reg)
+{
+       return snd_vt1724_read_i2c((struct snd_ice1712 *)private_data,
+                       AK4113_ADDR, reg);
+}
+
+
+/*
+ * AK4620 section
+ */
+
+/*
+ * Write data to addr register of ak4620
+ */
+static void qtet_akm_write(struct snd_akm4xxx *ak, int chip,
+               unsigned char addr, unsigned char data)
+{
+       unsigned int tmp, orig_dir;
+       int idx;
+       unsigned int addrdata;
+       struct snd_ice1712 *ice = ak->private_data[0];
+
+       if (snd_BUG_ON(chip < 0 || chip >= 4))
+               return;
+       /*printk(KERN_DEBUG "Writing to AK4620: chip=%d, addr=0x%x,
+         data=0x%x\n", chip, addr, data);*/
+       orig_dir = ice->gpio.get_dir(ice);
+       ice->gpio.set_dir(ice, orig_dir | GPIO_SPI_ALL);
+       /* set mask - only SPI bits */
+       ice->gpio.set_mask(ice, ~GPIO_SPI_ALL);
+
+       tmp = ice->gpio.get_data(ice);
+       /* high all */
+       tmp |= GPIO_SPI_ALL;
+       ice->gpio.set_data(ice, tmp);
+       udelay(100);
+       /* drop chip select */
+       if (chip)
+               /* CODEC 1 */
+               tmp &= ~GPIO_SPI_CSN1;
+       else
+               tmp &= ~GPIO_SPI_CSN0;
+       ice->gpio.set_data(ice, tmp);
+       udelay(100);
+
+       /* build I2C address + data byte */
+       addrdata = (AK4620_ADDR << 6) | 0x20 | (addr & 0x1f);
+       addrdata = (addrdata << 8) | data;
+       for (idx = 15; idx >= 0; idx--) {
+               /* drop clock */
+               tmp &= ~GPIO_D5_SPI_CCLK;
+               ice->gpio.set_data(ice, tmp);
+               udelay(100);
+               /* set data */
+               if (addrdata & (1 << idx))
+                       tmp |= GPIO_D4_SPI_CDTO;
+               else
+                       tmp &= ~GPIO_D4_SPI_CDTO;
+               ice->gpio.set_data(ice, tmp);
+               udelay(100);
+               /* raise clock */
+               tmp |= GPIO_D5_SPI_CCLK;
+               ice->gpio.set_data(ice, tmp);
+               udelay(100);
+       }
+       /* all back to 1 */
+       tmp |= GPIO_SPI_ALL;
+       ice->gpio.set_data(ice, tmp);
+       udelay(100);
+
+       /* return all gpios to non-writable */
+       ice->gpio.set_mask(ice, 0xffffff);
+       /* restore GPIOs direction */
+       ice->gpio.set_dir(ice, orig_dir);
+}
+
+static void qtet_akm_set_regs(struct snd_akm4xxx *ak, unsigned char addr,
+               unsigned char mask, unsigned char value)
+{
+       unsigned char tmp;
+       int chip;
+       for (chip = 0; chip < ak->num_chips; chip++) {
+               tmp = snd_akm4xxx_get(ak, chip, addr);
+               /* clear the bits */
+               tmp &= ~mask;
+               /* set the new bits */
+               tmp |= value;
+               snd_akm4xxx_write(ak, chip, addr, tmp);
+       }
+}
+
+/*
+ * change the rate of AK4620
+ */
+static void qtet_akm_set_rate_val(struct snd_akm4xxx *ak, unsigned int rate)
+{
+       unsigned char ak4620_dfs;
+
+       if (rate == 0)  /* no hint - S/PDIF input is master or the new spdif
+                          input rate undetected, simply return */
+               return;
+
+       /* adjust DFS on codecs - see datasheet */
+       if (rate > 108000)
+               ak4620_dfs = AK4620_DFS1 | AK4620_CKS1;
+       else if (rate > 54000)
+               ak4620_dfs = AK4620_DFS0 | AK4620_CKS0;
+       else
+               ak4620_dfs = 0;
+
+       /* set new value */
+       qtet_akm_set_regs(ak, AK4620_DFS_REG, AK4620_DFS0 | AK4620_DFS1 |
+                       AK4620_CKS0 | AK4620_CKS1, ak4620_dfs);
+}
+
+#define AK_CONTROL(xname, xch) { .name = xname, .num_channels = xch }
+
+#define PCM_12_PLAYBACK_VOLUME "PCM 1/2 Playback Volume"
+#define PCM_34_PLAYBACK_VOLUME "PCM 3/4 Playback Volume"
+#define PCM_12_CAPTURE_VOLUME  "PCM 1/2 Capture Volume"
+#define PCM_34_CAPTURE_VOLUME  "PCM 3/4 Capture Volume"
+
+static const struct snd_akm4xxx_dac_channel qtet_dac[] = {
+       AK_CONTROL(PCM_12_PLAYBACK_VOLUME, 2),
+       AK_CONTROL(PCM_34_PLAYBACK_VOLUME, 2),
+};
+
+static const struct snd_akm4xxx_adc_channel qtet_adc[] = {
+       AK_CONTROL(PCM_12_CAPTURE_VOLUME, 2),
+       AK_CONTROL(PCM_34_CAPTURE_VOLUME, 2),
+};
+
+static struct snd_akm4xxx akm_qtet_dac __devinitdata = {
+       .type = SND_AK4620,
+       .num_dacs = 4,  /* DAC1 - Output 12
+       */
+       .num_adcs = 4,  /* ADC1 - Input 12
+       */
+       .ops = {
+               .write = qtet_akm_write,
+               .set_rate_val = qtet_akm_set_rate_val,
+       },
+       .dac_info = qtet_dac,
+       .adc_info = qtet_adc,
+};
+
+/* Communication routines with the CPLD */
+
+
+/* Writes data to external register reg, both reg and data are
+ * GPIO representations */
+static void reg_write(struct snd_ice1712 *ice, unsigned int reg,
+               unsigned int data)
+{
+       unsigned int tmp;
+
+       mutex_lock(&ice->gpio_mutex);
+       /* set direction of used GPIOs*/
+       /* all outputs */
+       tmp = 0x00ffff;
+       ice->gpio.set_dir(ice, tmp);
+       /* mask - writable bits */
+       ice->gpio.set_mask(ice, ~(tmp));
+       /* write the data */
+       tmp = ice->gpio.get_data(ice);
+       tmp &= ~GPIO_DATA_MASK;
+       tmp |= data;
+       ice->gpio.set_data(ice, tmp);
+       udelay(100);
+       /* drop output enable */
+       tmp &=  ~GPIO_EX_GPIOE;
+       ice->gpio.set_data(ice, tmp);
+       udelay(100);
+       /* drop the register gpio */
+       tmp &= ~reg;
+       ice->gpio.set_data(ice, tmp);
+       udelay(100);
+       /* raise the register GPIO */
+       tmp |= reg;
+       ice->gpio.set_data(ice, tmp);
+       udelay(100);
+
+       /* raise all data gpios */
+       tmp |= GPIO_DATA_MASK;
+       ice->gpio.set_data(ice, tmp);
+       /* mask - immutable bits */
+       ice->gpio.set_mask(ice, 0xffffff);
+       /* outputs only 8-15 */
+       ice->gpio.set_dir(ice, 0x00ff00);
+       mutex_unlock(&ice->gpio_mutex);
+}
+
+static unsigned int get_scr(struct snd_ice1712 *ice)
+{
+       struct qtet_spec *spec = ice->spec;
+       return spec->scr;
+}
+
+static unsigned int get_mcr(struct snd_ice1712 *ice)
+{
+       struct qtet_spec *spec = ice->spec;
+       return spec->mcr;
+}
+
+static unsigned int get_cpld(struct snd_ice1712 *ice)
+{
+       struct qtet_spec *spec = ice->spec;
+       return spec->cpld;
+}
+
+static void set_scr(struct snd_ice1712 *ice, unsigned int val)
+{
+       struct qtet_spec *spec = ice->spec;
+       reg_write(ice, GPIO_SCR, val);
+       spec->scr = val;
+}
+
+static void set_mcr(struct snd_ice1712 *ice, unsigned int val)
+{
+       struct qtet_spec *spec = ice->spec;
+       reg_write(ice, GPIO_MCR, val);
+       spec->mcr = val;
+}
+
+static void set_cpld(struct snd_ice1712 *ice, unsigned int val)
+{
+       struct qtet_spec *spec = ice->spec;
+       reg_write(ice, GPIO_CPLD_CSN, val);
+       spec->cpld = val;
+}
+#ifdef CONFIG_PROC_FS
+static void proc_regs_read(struct snd_info_entry *entry,
+               struct snd_info_buffer *buffer)
+{
+       struct snd_ice1712 *ice = entry->private_data;
+       char bin_buffer[36];
+
+       snd_iprintf(buffer, "SCR:       %s\n", get_binary(bin_buffer,
+                               get_scr(ice)));
+       snd_iprintf(buffer, "MCR:       %s\n", get_binary(bin_buffer,
+                               get_mcr(ice)));
+       snd_iprintf(buffer, "CPLD:      %s\n", get_binary(bin_buffer,
+                               get_cpld(ice)));
+}
+
+static void proc_init(struct snd_ice1712 *ice)
+{
+       struct snd_info_entry *entry;
+       if (!snd_card_proc_new(ice->card, "quartet", &entry))
+               snd_info_set_text_ops(entry, ice, proc_regs_read);
+}
+#else /* !CONFIG_PROC_FS */
+static void proc_init(struct snd_ice1712 *ice) {}
+#endif
+
+static int qtet_mute_get(struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
+       unsigned int val;
+       val = get_scr(ice) & SCR_MUTE;
+       ucontrol->value.integer.value[0] = (val) ? 0 : 1;
+       return 0;
+}
+
+static int qtet_mute_put(struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
+       unsigned int old, new, smute;
+       old = get_scr(ice) & SCR_MUTE;
+       if (ucontrol->value.integer.value[0]) {
+               /* unmute */
+               new = 0;
+               /* un-smuting DAC */
+               smute = 0;
+       } else {
+               /* mute */
+               new = SCR_MUTE;
+               /* smuting DAC */
+               smute = AK4620_SMUTE;
+       }
+       if (old != new) {
+               struct snd_akm4xxx *ak = ice->akm;
+               set_scr(ice, (get_scr(ice) & ~SCR_MUTE) | new);
+               /* set smute */
+               qtet_akm_set_regs(ak, AK4620_DEEMVOL_REG, AK4620_SMUTE, smute);
+               return 1;
+       }
+       /* no change */
+       return 0;
+}
+
+static int qtet_ain12_enum_info(struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_info *uinfo)
+{
+       static char *texts[3] = {"Line In 1/2", "Mic", "Mic + Low-cut"};
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+       uinfo->count = 1;
+       uinfo->value.enumerated.items = ARRAY_SIZE(texts);
+
+       if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
+               uinfo->value.enumerated.item =
+                       uinfo->value.enumerated.items - 1;
+       strcpy(uinfo->value.enumerated.name,
+                       texts[uinfo->value.enumerated.item]);
+
+       return 0;
+}
+
+static int qtet_ain12_sw_get(struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
+       unsigned int val, result;
+       val = get_scr(ice) & (SCR_AIN12_SEL1 | SCR_AIN12_SEL0);
+       switch (val) {
+       case SCR_AIN12_LINE:
+               result = 0;
+               break;
+       case SCR_AIN12_MIC:
+               result = 1;
+               break;
+       case SCR_AIN12_LOWCUT:
+               result = 2;
+               break;
+       default:
+               /* BUG - no other combinations allowed */
+               snd_BUG();
+               result = 0;
+       }
+       ucontrol->value.integer.value[0] = result;
+       return 0;
+}
+
+static int qtet_ain12_sw_put(struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
+       unsigned int old, new, tmp, masked_old;
+       old = new = get_scr(ice);
+       masked_old = old & (SCR_AIN12_SEL1 | SCR_AIN12_SEL0);
+       tmp = ucontrol->value.integer.value[0];
+       if (tmp == 2)
+               tmp = 3;        /* binary 10 is not supported */
+       tmp <<= 4;      /* shifting to SCR_AIN12_SEL0 */
+       if (tmp != masked_old) {
+               /* change requested */
+               switch (tmp) {
+               case SCR_AIN12_LINE:
+                       new = old & ~(SCR_AIN12_SEL1 | SCR_AIN12_SEL0);
+                       set_scr(ice, new);
+                       /* turn off relay */
+                       new &= ~SCR_RELAY;
+                       set_scr(ice, new);
+                       break;
+               case SCR_AIN12_MIC:
+                       /* turn on relay */
+                       new = old | SCR_RELAY;
+                       set_scr(ice, new);
+                       new = (new & ~SCR_AIN12_SEL1) | SCR_AIN12_SEL0;
+                       set_scr(ice, new);
+                       break;
+               case SCR_AIN12_LOWCUT:
+                       /* turn on relay */
+                       new = old | SCR_RELAY;
+                       set_scr(ice, new);
+                       new |= SCR_AIN12_SEL1 | SCR_AIN12_SEL0;
+                       set_scr(ice, new);
+                       break;
+               default:
+                       snd_BUG();
+               }
+               return 1;
+       }
+       /* no change */
+       return 0;
+}
+
+static int qtet_php_get(struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
+       unsigned int val;
+       /* if phantom voltage =48V, phantom on */
+       val = get_scr(ice) & SCR_PHP_V;
+       ucontrol->value.integer.value[0] = val ? 1 : 0;
+       return 0;
+}
+
+static int qtet_php_put(struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
+       unsigned int old, new;
+       old = new = get_scr(ice);
+       if (ucontrol->value.integer.value[0] /* phantom on requested */
+                       && (~old & SCR_PHP_V)) /* 0 = voltage 5V */ {
+               /* is off, turn on */
+               /* turn voltage on first, = 1 */
+               new = old | SCR_PHP_V;
+               set_scr(ice, new);
+               /* turn phantom on, = 0 */
+               new &= ~SCR_PHP;
+               set_scr(ice, new);
+       } else if (!ucontrol->value.integer.value[0] && (old & SCR_PHP_V)) {
+               /* phantom off requested and 1 = voltage 48V */
+               /* is on, turn off */
+               /* turn voltage off first, = 0 */
+               new = old & ~SCR_PHP_V;
+               set_scr(ice, new);
+               /* turn phantom off, = 1 */
+               new |= SCR_PHP;
+               set_scr(ice, new);
+       }
+       if (old != new)
+               return 1;
+       /* no change */
+       return 0;
+}
+
+#define PRIV_SW(xid, xbit, xreg)       [xid] = {.bit = xbit,\
+       .set_register = set_##xreg,\
+       .get_register = get_##xreg, }
+
+
+#define PRIV_ENUM2(xid, xbit, xreg, xtext1, xtext2)    [xid] = {.bit = xbit,\
+       .set_register = set_##xreg,\
+       .get_register = get_##xreg,\
+       .texts = {xtext1, xtext2} }
+
+static struct qtet_kcontrol_private qtet_privates[] = {
+       PRIV_ENUM2(IN12_SEL, CPLD_IN12_SEL, cpld, "An In 1/2", "An In 3/4"),
+       PRIV_ENUM2(IN34_SEL, CPLD_IN34_SEL, cpld, "An In 3/4", "IEC958 In"),
+       PRIV_ENUM2(AIN34_SEL, SCR_AIN34_SEL, scr, "Line In 3/4", "Hi-Z"),
+       PRIV_ENUM2(COAX_OUT, CPLD_COAX_OUT, cpld, "IEC958", "I2S"),
+       PRIV_SW(IN12_MON12, MCR_IN12_MON12, mcr),
+       PRIV_SW(IN12_MON34, MCR_IN12_MON34, mcr),
+       PRIV_SW(IN34_MON12, MCR_IN34_MON12, mcr),
+       PRIV_SW(IN34_MON34, MCR_IN34_MON34, mcr),
+       PRIV_SW(OUT12_MON34, MCR_OUT12_MON34, mcr),
+       PRIV_SW(OUT34_MON12, MCR_OUT34_MON12, mcr),
+};
+
+static int qtet_enum_info(struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_info *uinfo)
+{
+       struct qtet_kcontrol_private private =
+               qtet_privates[kcontrol->private_value];
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+       uinfo->count = 1;
+       uinfo->value.enumerated.items = ARRAY_SIZE(private.texts);
+
+       if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
+               uinfo->value.enumerated.item =
+                       uinfo->value.enumerated.items - 1;
+       strcpy(uinfo->value.enumerated.name,
+                       private.texts[uinfo->value.enumerated.item]);
+
+       return 0;
+}
+
+static int qtet_sw_get(struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_value *ucontrol)
+{
+       struct qtet_kcontrol_private private =
+               qtet_privates[kcontrol->private_value];
+       struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
+       ucontrol->value.integer.value[0] =
+               (private.get_register(ice) & private.bit) ? 1 : 0;
+       return 0;
+}
+
+static int qtet_sw_put(struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_value *ucontrol)
+{
+       struct qtet_kcontrol_private private =
+               qtet_privates[kcontrol->private_value];
+       struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
+       unsigned int old, new;
+       old = private.get_register(ice);
+       if (ucontrol->value.integer.value[0])
+               new = old | private.bit;
+       else
+               new = old & ~private.bit;
+       if (old != new) {
+               private.set_register(ice, new);
+               return 1;
+       }
+       /* no change */
+       return 0;
+}
+
+#define qtet_sw_info   snd_ctl_boolean_mono_info
+
+#define QTET_CONTROL(xname, xtype, xpriv)      \
+       {.iface = SNDRV_CTL_ELEM_IFACE_MIXER,\
+       .name = xname,\
+       .info = qtet_##xtype##_info,\
+       .get = qtet_sw_get,\
+       .put = qtet_sw_put,\
+       .private_value = xpriv }
+
+static struct snd_kcontrol_new qtet_controls[] __devinitdata = {
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "Master Playback Switch",
+               .info = qtet_sw_info,
+               .get = qtet_mute_get,
+               .put = qtet_mute_put,
+               .private_value = 0
+       },
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "Phantom Power",
+               .info = qtet_sw_info,
+               .get = qtet_php_get,
+               .put = qtet_php_put,
+               .private_value = 0
+       },
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "Analog In 1/2 Capture Switch",
+               .info = qtet_ain12_enum_info,
+               .get = qtet_ain12_sw_get,
+               .put = qtet_ain12_sw_put,
+               .private_value = 0
+       },
+       QTET_CONTROL("Analog In 3/4 Capture Switch", enum, AIN34_SEL),
+       QTET_CONTROL("PCM In 1/2 Capture Switch", enum, IN12_SEL),
+       QTET_CONTROL("PCM In 3/4 Capture Switch", enum, IN34_SEL),
+       QTET_CONTROL("Coax Output Source", enum, COAX_OUT),
+       QTET_CONTROL("Analog In 1/2 to Monitor 1/2", sw, IN12_MON12),
+       QTET_CONTROL("Analog In 1/2 to Monitor 3/4", sw, IN12_MON34),
+       QTET_CONTROL("Analog In 3/4 to Monitor 1/2", sw, IN34_MON12),
+       QTET_CONTROL("Analog In 3/4 to Monitor 3/4", sw, IN34_MON34),
+       QTET_CONTROL("Output 1/2 to Monitor 3/4", sw, OUT12_MON34),
+       QTET_CONTROL("Output 3/4 to Monitor 1/2", sw, OUT34_MON12),
+};
+
+static char *slave_vols[] __devinitdata = {
+       PCM_12_PLAYBACK_VOLUME,
+       PCM_34_PLAYBACK_VOLUME,
+       NULL
+};
+
+static __devinitdata
+DECLARE_TLV_DB_SCALE(qtet_master_db_scale, -6350, 50, 1);
+
+static struct snd_kcontrol __devinit *ctl_find(struct snd_card *card,
+               const char *name)
+{
+       struct snd_ctl_elem_id sid;
+       memset(&sid, 0, sizeof(sid));
+       /* FIXME: strcpy is bad. */
+       strcpy(sid.name, name);
+       sid.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+       return snd_ctl_find_id(card, &sid);
+}
+
+static void __devinit add_slaves(struct snd_card *card,
+               struct snd_kcontrol *master, char **list)
+{
+       for (; *list; list++) {
+               struct snd_kcontrol *slave = ctl_find(card, *list);
+               if (slave)
+                       snd_ctl_add_slave(master, slave);
+       }
+}
+
+static int __devinit qtet_add_controls(struct snd_ice1712 *ice)
+{
+       struct qtet_spec *spec = ice->spec;
+       int err, i;
+       struct snd_kcontrol *vmaster;
+       err = snd_ice1712_akm4xxx_build_controls(ice);
+       if (err < 0)
+               return err;
+       for (i = 0; i < ARRAY_SIZE(qtet_controls); i++) {
+               err = snd_ctl_add(ice->card,
+                               snd_ctl_new1(&qtet_controls[i], ice));
+               if (err < 0)
+                       return err;
+       }
+
+       /* Create virtual master control */
+       vmaster = snd_ctl_make_virtual_master("Master Playback Volume",
+                       qtet_master_db_scale);
+       if (!vmaster)
+               return -ENOMEM;
+       add_slaves(ice->card, vmaster, slave_vols);
+       err = snd_ctl_add(ice->card, vmaster);
+       if (err < 0)
+               return err;
+       /* only capture SPDIF over AK4113 */
+       err = snd_ak4113_build(spec->ak4113,
+                       ice->pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream);
+       if (err < 0)
+               return err;
+       return 0;
+}
+
+static inline int qtet_is_spdif_master(struct snd_ice1712 *ice)
+{
+       /* CPLD_SYNC_SEL: 0 = internal, 1 = external (i.e. spdif master) */
+       return (get_cpld(ice) & CPLD_SYNC_SEL) ? 1 : 0;
+}
+
+static unsigned int qtet_get_rate(struct snd_ice1712 *ice)
+{
+       int i;
+       unsigned char result;
+
+       result =  get_cpld(ice) & CPLD_CKS_MASK;
+       for (i = 0; i < ARRAY_SIZE(cks_vals); i++)
+               if (cks_vals[i] == result)
+                       return qtet_rates[i];
+       return 0;
+}
+
+static int get_cks_val(int rate)
+{
+       int i;
+       for (i = 0; i < ARRAY_SIZE(qtet_rates); i++)
+               if (qtet_rates[i] == rate)
+                       return cks_vals[i];
+       return 0;
+}
+
+/* setting new rate */
+static void qtet_set_rate(struct snd_ice1712 *ice, unsigned int rate)
+{
+       unsigned int new;
+       unsigned char val;
+       /* switching ice1724 to external clock - supplied by ext. circuits */
+       val = inb(ICEMT1724(ice, RATE));
+       outb(val | VT1724_SPDIF_MASTER, ICEMT1724(ice, RATE));
+
+       new =  (get_cpld(ice) & ~CPLD_CKS_MASK) | get_cks_val(rate);
+       /* switch to internal clock, drop CPLD_SYNC_SEL */
+       new &= ~CPLD_SYNC_SEL;
+       /* printk(KERN_DEBUG "QT - set_rate: old %x, new %x\n",
+          get_cpld(ice), new); */
+       set_cpld(ice, new);
+}
+
+static inline unsigned char qtet_set_mclk(struct snd_ice1712 *ice,
+               unsigned int rate)
+{
+       /* no change in master clock */
+       return 0;
+}
+
+/* setting clock to external - SPDIF */
+static int qtet_set_spdif_clock(struct snd_ice1712 *ice, int type)
+{
+       unsigned int old, new;
+
+       old = new = get_cpld(ice);
+       new &= ~(CPLD_CKS_MASK | CPLD_WORD_SEL);
+       switch (type) {
+       case EXT_SPDIF_TYPE:
+               new |= CPLD_EXT_SPDIF;
+               break;
+       case EXT_WORDCLOCK_1FS_TYPE:
+               new |= CPLD_EXT_WORDCLOCK_1FS;
+               break;
+       case EXT_WORDCLOCK_256FS_TYPE:
+               new |= CPLD_EXT_WORDCLOCK_256FS;
+               break;
+       default:
+               snd_BUG();
+       }
+       if (old != new) {
+               set_cpld(ice, new);
+               /* changed */
+               return 1;
+       }
+       return 0;
+}
+
+static int qtet_get_spdif_master_type(struct snd_ice1712 *ice)
+{
+       unsigned int val;
+       int result;
+       val = get_cpld(ice);
+       /* checking only rate/clock-related bits */
+       val &= (CPLD_CKS_MASK | CPLD_WORD_SEL | CPLD_SYNC_SEL);
+       if (!(val & CPLD_SYNC_SEL)) {
+               /* switched to internal clock, is not any external type */
+               result = -1;
+       } else {
+               switch (val) {
+               case (CPLD_EXT_SPDIF):
+                       result = EXT_SPDIF_TYPE;
+                       break;
+               case (CPLD_EXT_WORDCLOCK_1FS):
+                       result = EXT_WORDCLOCK_1FS_TYPE;
+                       break;
+               case (CPLD_EXT_WORDCLOCK_256FS):
+                       result = EXT_WORDCLOCK_256FS_TYPE;
+                       break;
+               default:
+                       /* undefined combination of external clock setup */
+                       snd_BUG();
+                       result = 0;
+               }
+       }
+       return result;
+}
+
+/* Called when ak4113 detects change in the input SPDIF stream */
+static void qtet_ak4113_change(struct ak4113 *ak4113, unsigned char c0,
+               unsigned char c1)
+{
+       struct snd_ice1712 *ice = ak4113->change_callback_private;
+       int rate;
+       if ((qtet_get_spdif_master_type(ice) == EXT_SPDIF_TYPE) &&
+                       c1) {
+               /* only for SPDIF master mode, rate was changed */
+               rate = snd_ak4113_external_rate(ak4113);
+               /* printk(KERN_DEBUG "ak4113 - input rate changed to %d\n",
+                  rate); */
+               qtet_akm_set_rate_val(ice->akm, rate);
+       }
+}
+
+/*
+ * If clock slaved to SPDIF-IN, setting runtime rate
+ * to the detected external rate
+ */
+static void qtet_spdif_in_open(struct snd_ice1712 *ice,
+               struct snd_pcm_substream *substream)
+{
+       struct qtet_spec *spec = ice->spec;
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       int rate;
+
+       if (qtet_get_spdif_master_type(ice) != EXT_SPDIF_TYPE)
+               /* not external SPDIF, no rate limitation */
+               return;
+       /* only external SPDIF can detect incoming sample rate */
+       rate = snd_ak4113_external_rate(spec->ak4113);
+       if (rate >= runtime->hw.rate_min && rate <= runtime->hw.rate_max) {
+               runtime->hw.rate_min = rate;
+               runtime->hw.rate_max = rate;
+       }
+}
+
+/*
+ * initialize the chip
+ */
+static int __devinit qtet_init(struct snd_ice1712 *ice)
+{
+       static const unsigned char ak4113_init_vals[] = {
+               /* AK4113_REG_PWRDN */  AK4113_RST | AK4113_PWN |
+                       AK4113_OCKS0 | AK4113_OCKS1,
+               /* AK4113_REQ_FORMAT */ AK4113_DIF_I24I2S | AK4113_VTX |
+                       AK4113_DEM_OFF | AK4113_DEAU,
+               /* AK4113_REG_IO0 */    AK4113_OPS2 | AK4113_TXE |
+                       AK4113_XTL_24_576M,
+               /* AK4113_REG_IO1 */    AK4113_EFH_1024LRCLK | AK4113_IPS(0),
+               /* AK4113_REG_INT0_MASK */      0,
+               /* AK4113_REG_INT1_MASK */      0,
+               /* AK4113_REG_DATDTS */         0,
+       };
+       int err;
+       struct qtet_spec *spec;
+       struct snd_akm4xxx *ak;
+       unsigned char val;
+
+       /* switching ice1724 to external clock - supplied by ext. circuits */
+       val = inb(ICEMT1724(ice, RATE));
+       outb(val | VT1724_SPDIF_MASTER, ICEMT1724(ice, RATE));
+
+       spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+       if (!spec)
+               return -ENOMEM;
+       /* qtet is clocked by Xilinx array */
+       ice->hw_rates = &qtet_rates_info;
+       ice->is_spdif_master = qtet_is_spdif_master;
+       ice->get_rate = qtet_get_rate;
+       ice->set_rate = qtet_set_rate;
+       ice->set_mclk = qtet_set_mclk;
+       ice->set_spdif_clock = qtet_set_spdif_clock;
+       ice->get_spdif_master_type = qtet_get_spdif_master_type;
+       ice->ext_clock_names = ext_clock_names;
+       ice->ext_clock_count = ARRAY_SIZE(ext_clock_names);
+       /* since Qtet can detect correct SPDIF-in rate, all streams can be
+        * limited to this specific rate */
+       ice->spdif.ops.open = ice->pro_open = qtet_spdif_in_open;
+       ice->spec = spec;
+
+       /* Mute Off */
+       /* SCR Initialize*/
+       /* keep codec power down first */
+       set_scr(ice, SCR_PHP);
+       udelay(1);
+       /* codec power up */
+       set_scr(ice, SCR_PHP | SCR_CODEC_PDN);
+
+       /* MCR Initialize */
+       set_mcr(ice, 0);
+
+       /* CPLD Initialize */
+       set_cpld(ice, 0);
+
+
+       ice->num_total_dacs = 2;
+       ice->num_total_adcs = 2;
+
+       ice->akm = kcalloc(2, sizeof(struct snd_akm4xxx), GFP_KERNEL);
+       ak = ice->akm;
+       if (!ak)
+               return -ENOMEM;
+       /* only one codec with two chips */
+       ice->akm_codecs = 1;
+       err = snd_ice1712_akm4xxx_init(ak, &akm_qtet_dac, NULL, ice);
+       if (err < 0)
+               return err;
+       err = snd_ak4113_create(ice->card,
+                       qtet_ak4113_read,
+                       qtet_ak4113_write,
+                       ak4113_init_vals,
+                       ice, &spec->ak4113);
+       if (err < 0)
+               return err;
+       /* callback for codecs rate setting */
+       spec->ak4113->change_callback = qtet_ak4113_change;
+       spec->ak4113->change_callback_private = ice;
+       /* AK41143 in Quartet can detect external rate correctly
+        * (i.e. check_flags = 0) */
+       spec->ak4113->check_flags = 0;
+
+       proc_init(ice);
+
+       qtet_set_rate(ice, 44100);
+       return 0;
+}
+
+static unsigned char qtet_eeprom[] __devinitdata = {
+       [ICE_EEP2_SYSCONF]     = 0x28,  /* clock 256(24MHz), mpu401, 1xADC,
+                                          1xDACs, SPDIF in */
+       [ICE_EEP2_ACLINK]      = 0x80,  /* I2S */
+       [ICE_EEP2_I2S]         = 0x78,  /* 96k, 24bit, 192k */
+       [ICE_EEP2_SPDIF]       = 0xc3,  /* out-en, out-int, in, out-ext */
+       [ICE_EEP2_GPIO_DIR]    = 0x00,  /* 0-7 inputs, switched to output
+                                          only during output operations */
+       [ICE_EEP2_GPIO_DIR1]   = 0xff,  /* 8-15 outputs */
+       [ICE_EEP2_GPIO_DIR2]   = 0x00,
+       [ICE_EEP2_GPIO_MASK]   = 0xff,  /* changed only for OUT operations */
+       [ICE_EEP2_GPIO_MASK1]  = 0x00,
+       [ICE_EEP2_GPIO_MASK2]  = 0xff,
+
+       [ICE_EEP2_GPIO_STATE]  = 0x00, /* inputs */
+       [ICE_EEP2_GPIO_STATE1] = 0x7d, /* all 1, but GPIO_CPLD_RW
+                                         and GPIO15 always zero */
+       [ICE_EEP2_GPIO_STATE2] = 0x00, /* inputs */
+};
+
+/* entry point */
+struct snd_ice1712_card_info snd_vt1724_qtet_cards[] __devinitdata = {
+       {
+               .subvendor = VT1724_SUBDEVICE_QTET,
+               .name = "Infrasonic Quartet",
+               .model = "quartet",
+               .chip_init = qtet_init,
+               .build_controls = qtet_add_controls,
+               .eeprom_size = sizeof(qtet_eeprom),
+               .eeprom_data = qtet_eeprom,
+       },
+       { } /* terminator */
+};
diff --git a/sound/pci/ice1712/quartet.h b/sound/pci/ice1712/quartet.h
new file mode 100644 (file)
index 0000000..80809b7
--- /dev/null
@@ -0,0 +1,10 @@
+#ifndef __SOUND_QTET_H
+#define __SOUND_QTET_H
+
+#define QTET_DEVICE_DESC               "{Infrasonic,Quartet},"
+
+#define VT1724_SUBDEVICE_QTET          0x30305349      /* Infrasonic Quartet */
+
+extern struct snd_ice1712_card_info  snd_vt1724_qtet_cards[];
+
+#endif /* __SOUND_QTET_H */
index aac20fb..b990143 100644 (file)
@@ -2063,6 +2063,12 @@ static struct ac97_quirk ac97_quirks[] __devinitdata = {
                .type = AC97_TUNE_HP_ONLY
        },
        {
+               .subvendor = 0x161f,
+               .subdevice = 0x203a,
+               .name = "Gateway 4525GZ",               /* AD1981B */
+               .type = AC97_TUNE_INV_EAPD
+       },
+       {
                .subvendor = 0x1734,
                .subdevice = 0x0088,
                .name = "Fujitsu-Siemens D1522",        /* AD1981 */
index 4ba07d4..389941c 100644 (file)
@@ -1,7 +1,8 @@
 snd-oxygen-lib-objs := oxygen_io.o oxygen_lib.o oxygen_mixer.o oxygen_pcm.o
 snd-hifier-objs := hifier.o
 snd-oxygen-objs := oxygen.o
-snd-virtuoso-objs := virtuoso.o
+snd-virtuoso-objs := virtuoso.o xonar_lib.o \
+       xonar_pcm179x.o xonar_cs43xx.o xonar_hdmi.o
 
 obj-$(CONFIG_SND_OXYGEN_LIB) += snd-oxygen-lib.o
 obj-$(CONFIG_SND_HIFIER) += snd-hifier.o
diff --git a/sound/pci/oxygen/cs2000.h b/sound/pci/oxygen/cs2000.h
new file mode 100644 (file)
index 0000000..c3501bd
--- /dev/null
@@ -0,0 +1,83 @@
+#ifndef CS2000_H_INCLUDED
+#define CS2000_H_INCLUDED
+
+#define CS2000_DEV_ID          0x01
+#define CS2000_DEV_CTRL                0x02
+#define CS2000_DEV_CFG_1       0x03
+#define CS2000_DEV_CFG_2       0x04
+#define CS2000_GLOBAL_CFG      0x05
+#define CS2000_RATIO_0         0x06 /* 32 bits, big endian */
+#define CS2000_RATIO_1         0x0a
+#define CS2000_RATIO_2         0x0e
+#define CS2000_RATIO_3         0x12
+#define CS2000_FUN_CFG_1       0x16
+#define CS2000_FUN_CFG_2       0x17
+#define CS2000_FUN_CFG_3       0x1e
+
+/* DEV_ID */
+#define CS2000_DEVICE_MASK             0xf8
+#define CS2000_REVISION_MASK           0x07
+
+/* DEV_CTRL */
+#define CS2000_UNLOCK                  0x80
+#define CS2000_AUX_OUT_DIS             0x02
+#define CS2000_CLK_OUT_DIS             0x01
+
+/* DEV_CFG_1 */
+#define CS2000_R_MOD_SEL_MASK          0xe0
+#define CS2000_R_MOD_SEL_1             0x00
+#define CS2000_R_MOD_SEL_2             0x20
+#define CS2000_R_MOD_SEL_4             0x40
+#define CS2000_R_MOD_SEL_8             0x60
+#define CS2000_R_MOD_SEL_1_2           0x80
+#define CS2000_R_MOD_SEL_1_4           0xa0
+#define CS2000_R_MOD_SEL_1_8           0xc0
+#define CS2000_R_MOD_SEL_1_16          0xe0
+#define CS2000_R_SEL_MASK              0x18
+#define CS2000_R_SEL_SHIFT             3
+#define CS2000_AUX_OUT_SRC_MASK                0x06
+#define CS2000_AUX_OUT_SRC_REF_CLK     0x00
+#define CS2000_AUX_OUT_SRC_CLK_IN      0x02
+#define CS2000_AUX_OUT_SRC_CLK_OUT     0x04
+#define CS2000_AUX_OUT_SRC_PLL_LOCK    0x06
+#define CS2000_EN_DEV_CFG_1            0x01
+
+/* DEV_CFG_2 */
+#define CS2000_LOCK_CLK_MASK           0x06
+#define CS2000_LOCK_CLK_SHIFT          1
+#define CS2000_FRAC_N_SRC_MASK         0x01
+#define CS2000_FRAC_N_SRC_STATIC       0x00
+#define CS2000_FRAC_N_SRC_DYNAMIC      0x01
+
+/* GLOBAL_CFG */
+#define CS2000_FREEZE                  0x08
+#define CS2000_EN_DEV_CFG_2            0x01
+
+/* FUN_CFG_1 */
+#define CS2000_CLK_SKIP_EN             0x80
+#define CS2000_AUX_LOCK_CFG_MASK       0x40
+#define CS2000_AUX_LOCK_CFG_PP_HIGH    0x00
+#define CS2000_AUX_LOCK_CFG_OD_LOW     0x40
+#define CS2000_REF_CLK_DIV_MASK                0x18
+#define CS2000_REF_CLK_DIV_4           0x00
+#define CS2000_REF_CLK_DIV_2           0x08
+#define CS2000_REF_CLK_DIV_1           0x10
+
+/* FUN_CFG_2 */
+#define CS2000_CLK_OUT_UNL             0x10
+#define CS2000_L_F_RATIO_CFG_MASK      0x08
+#define CS2000_L_F_RATIO_CFG_20_12     0x00
+#define CS2000_L_F_RATIO_CFG_12_20     0x08
+
+/* FUN_CFG_3 */
+#define CS2000_CLK_IN_BW_MASK          0x70
+#define CS2000_CLK_IN_BW_1             0x00
+#define CS2000_CLK_IN_BW_2             0x10
+#define CS2000_CLK_IN_BW_4             0x20
+#define CS2000_CLK_IN_BW_8             0x30
+#define CS2000_CLK_IN_BW_16            0x40
+#define CS2000_CLK_IN_BW_32            0x50
+#define CS2000_CLK_IN_BW_64            0x60
+#define CS2000_CLK_IN_BW_128           0x70
+
+#endif
index 84ef131..e3c229b 100644 (file)
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  */
 
+/*
+ * CMI8788:
+ *
+ * SPI 0 -> AK4396
+ */
+
 #include <linux/delay.h>
 #include <linux/pci.h>
 #include <sound/control.h>
@@ -51,23 +57,28 @@ static struct pci_device_id hifier_ids[] __devinitdata = {
 MODULE_DEVICE_TABLE(pci, hifier_ids);
 
 struct hifier_data {
-       u8 ak4396_ctl2;
+       u8 ak4396_regs[5];
 };
 
 static void ak4396_write(struct oxygen *chip, u8 reg, u8 value)
 {
+       struct hifier_data *data = chip->model_data;
+
        oxygen_write_spi(chip, OXYGEN_SPI_TRIGGER  |
                         OXYGEN_SPI_DATA_LENGTH_2 |
                         OXYGEN_SPI_CLOCK_160 |
                         (0 << OXYGEN_SPI_CODEC_SHIFT) |
                         OXYGEN_SPI_CEN_LATCH_CLOCK_HI,
                         AK4396_WRITE | (reg << 8) | value);
+       data->ak4396_regs[reg] = value;
 }
 
-static void update_ak4396_volume(struct oxygen *chip)
+static void ak4396_write_cached(struct oxygen *chip, u8 reg, u8 value)
 {
-       ak4396_write(chip, AK4396_LCH_ATT, chip->dac_volume[0]);
-       ak4396_write(chip, AK4396_RCH_ATT, chip->dac_volume[1]);
+       struct hifier_data *data = chip->model_data;
+
+       if (value != data->ak4396_regs[reg])
+               ak4396_write(chip, reg, value);
 }
 
 static void hifier_registers_init(struct oxygen *chip)
@@ -75,16 +86,19 @@ static void hifier_registers_init(struct oxygen *chip)
        struct hifier_data *data = chip->model_data;
 
        ak4396_write(chip, AK4396_CONTROL_1, AK4396_DIF_24_MSB | AK4396_RSTN);
-       ak4396_write(chip, AK4396_CONTROL_2, data->ak4396_ctl2);
+       ak4396_write(chip, AK4396_CONTROL_2,
+                    data->ak4396_regs[AK4396_CONTROL_2]);
        ak4396_write(chip, AK4396_CONTROL_3, AK4396_PCM);
-       update_ak4396_volume(chip);
+       ak4396_write(chip, AK4396_LCH_ATT, chip->dac_volume[0]);
+       ak4396_write(chip, AK4396_RCH_ATT, chip->dac_volume[1]);
 }
 
 static void hifier_init(struct oxygen *chip)
 {
        struct hifier_data *data = chip->model_data;
 
-       data->ak4396_ctl2 = AK4396_SMUTE | AK4396_DEM_OFF | AK4396_DFS_NORMAL;
+       data->ak4396_regs[AK4396_CONTROL_2] =
+               AK4396_SMUTE | AK4396_DEM_OFF | AK4396_DFS_NORMAL;
        hifier_registers_init(chip);
 
        snd_component_add(chip->card, "AK4396");
@@ -106,20 +120,29 @@ static void set_ak4396_params(struct oxygen *chip,
        struct hifier_data *data = chip->model_data;
        u8 value;
 
-       value = data->ak4396_ctl2 & ~AK4396_DFS_MASK;
+       value = data->ak4396_regs[AK4396_CONTROL_2] & ~AK4396_DFS_MASK;
        if (params_rate(params) <= 54000)
                value |= AK4396_DFS_NORMAL;
        else if (params_rate(params) <= 108000)
                value |= AK4396_DFS_DOUBLE;
        else
                value |= AK4396_DFS_QUAD;
-       data->ak4396_ctl2 = value;
 
        msleep(1); /* wait for the new MCLK to become stable */
 
-       ak4396_write(chip, AK4396_CONTROL_1, AK4396_DIF_24_MSB);
-       ak4396_write(chip, AK4396_CONTROL_2, value);
-       ak4396_write(chip, AK4396_CONTROL_1, AK4396_DIF_24_MSB | AK4396_RSTN);
+       if (value != data->ak4396_regs[AK4396_CONTROL_2]) {
+               ak4396_write(chip, AK4396_CONTROL_1,
+                            AK4396_DIF_24_MSB);
+               ak4396_write(chip, AK4396_CONTROL_2, value);
+               ak4396_write(chip, AK4396_CONTROL_1,
+                            AK4396_DIF_24_MSB | AK4396_RSTN);
+       }
+}
+
+static void update_ak4396_volume(struct oxygen *chip)
+{
+       ak4396_write_cached(chip, AK4396_LCH_ATT, chip->dac_volume[0]);
+       ak4396_write_cached(chip, AK4396_RCH_ATT, chip->dac_volume[1]);
 }
 
 static void update_ak4396_mute(struct oxygen *chip)
@@ -127,11 +150,10 @@ static void update_ak4396_mute(struct oxygen *chip)
        struct hifier_data *data = chip->model_data;
        u8 value;
 
-       value = data->ak4396_ctl2 & ~AK4396_SMUTE;
+       value = data->ak4396_regs[AK4396_CONTROL_2] & ~AK4396_SMUTE;
        if (chip->dac_mute)
                value |= AK4396_SMUTE;
-       data->ak4396_ctl2 = value;
-       ak4396_write(chip, AK4396_CONTROL_2, value);
+       ak4396_write_cached(chip, AK4396_CONTROL_2, value);
 }
 
 static void set_cs5340_params(struct oxygen *chip,
@@ -141,21 +163,14 @@ static void set_cs5340_params(struct oxygen *chip,
 
 static const DECLARE_TLV_DB_LINEAR(ak4396_db_scale, TLV_DB_GAIN_MUTE, 0);
 
-static int hifier_control_filter(struct snd_kcontrol_new *template)
-{
-       if (!strcmp(template->name, "Stereo Upmixing"))
-               return 1; /* stereo only - we don't need upmixing */
-       return 0;
-}
-
 static const struct oxygen_model model_hifier = {
        .shortname = "C-Media CMI8787",
        .longname = "C-Media Oxygen HD Audio",
        .chip = "CMI8788",
        .init = hifier_init,
-       .control_filter = hifier_control_filter,
        .cleanup = hifier_cleanup,
        .resume = hifier_resume,
+       .get_i2s_mclk = oxygen_default_i2s_mclk,
        .set_dac_params = set_ak4396_params,
        .set_adc_params = set_cs5340_params,
        .update_dac_volume = update_ak4396_volume,
index 72db4c3..acbedeb 100644 (file)
@@ -18,6 +18,8 @@
  */
 
 /*
+ * CMI8788:
+ *
  * SPI 0 -> 1st AK4396 (front)
  * SPI 1 -> 2nd AK4396 (surround)
  * SPI 2 -> 3rd AK4396 (center/LFE)
  * GPIO 0 -> DFS0 of AK5385
  * GPIO 1 -> DFS1 of AK5385
  * GPIO 8 -> enable headphone amplifier on HT-Omega models
+ *
+ * CM9780:
+ *
+ * GPO 0 -> route line-in (0) or AC97 output (1) to ADC input
  */
 
 #include <linux/delay.h>
@@ -91,8 +97,8 @@ MODULE_DEVICE_TABLE(pci, oxygen_ids);
 #define GPIO_CLARO_HP          0x0100
 
 struct generic_data {
-       u8 ak4396_ctl2;
-       u16 saved_wm8785_registers[2];
+       u8 ak4396_regs[4][5];
+       u16 wm8785_regs[3];
 };
 
 static void ak4396_write(struct oxygen *chip, unsigned int codec,
@@ -102,12 +108,24 @@ static void ak4396_write(struct oxygen *chip, unsigned int codec,
        static const u8 codec_spi_map[4] = {
                0, 1, 2, 4
        };
+       struct generic_data *data = chip->model_data;
+
        oxygen_write_spi(chip, OXYGEN_SPI_TRIGGER |
                         OXYGEN_SPI_DATA_LENGTH_2 |
                         OXYGEN_SPI_CLOCK_160 |
                         (codec_spi_map[codec] << OXYGEN_SPI_CODEC_SHIFT) |
                         OXYGEN_SPI_CEN_LATCH_CLOCK_HI,
                         AK4396_WRITE | (reg << 8) | value);
+       data->ak4396_regs[codec][reg] = value;
+}
+
+static void ak4396_write_cached(struct oxygen *chip, unsigned int codec,
+                               u8 reg, u8 value)
+{
+       struct generic_data *data = chip->model_data;
+
+       if (value != data->ak4396_regs[codec][reg])
+               ak4396_write(chip, codec, reg, value);
 }
 
 static void wm8785_write(struct oxygen *chip, u8 reg, unsigned int value)
@@ -120,20 +138,8 @@ static void wm8785_write(struct oxygen *chip, u8 reg, unsigned int value)
                         (3 << OXYGEN_SPI_CODEC_SHIFT) |
                         OXYGEN_SPI_CEN_LATCH_CLOCK_LO,
                         (reg << 9) | value);
-       if (reg < ARRAY_SIZE(data->saved_wm8785_registers))
-               data->saved_wm8785_registers[reg] = value;
-}
-
-static void update_ak4396_volume(struct oxygen *chip)
-{
-       unsigned int i;
-
-       for (i = 0; i < 4; ++i) {
-               ak4396_write(chip, i,
-                            AK4396_LCH_ATT, chip->dac_volume[i * 2]);
-               ak4396_write(chip, i,
-                            AK4396_RCH_ATT, chip->dac_volume[i * 2 + 1]);
-       }
+       if (reg < ARRAY_SIZE(data->wm8785_regs))
+               data->wm8785_regs[reg] = value;
 }
 
 static void ak4396_registers_init(struct oxygen *chip)
@@ -142,21 +148,25 @@ static void ak4396_registers_init(struct oxygen *chip)
        unsigned int i;
 
        for (i = 0; i < 4; ++i) {
-               ak4396_write(chip, i,
-                            AK4396_CONTROL_1, AK4396_DIF_24_MSB | AK4396_RSTN);
-               ak4396_write(chip, i,
-                            AK4396_CONTROL_2, data->ak4396_ctl2);
-               ak4396_write(chip, i,
-                            AK4396_CONTROL_3, AK4396_PCM);
+               ak4396_write(chip, i, AK4396_CONTROL_1,
+                            AK4396_DIF_24_MSB | AK4396_RSTN);
+               ak4396_write(chip, i, AK4396_CONTROL_2,
+                            data->ak4396_regs[0][AK4396_CONTROL_2]);
+               ak4396_write(chip, i, AK4396_CONTROL_3,
+                            AK4396_PCM);
+               ak4396_write(chip, i, AK4396_LCH_ATT,
+                            chip->dac_volume[i * 2]);
+               ak4396_write(chip, i, AK4396_RCH_ATT,
+                            chip->dac_volume[i * 2 + 1]);
        }
-       update_ak4396_volume(chip);
 }
 
 static void ak4396_init(struct oxygen *chip)
 {
        struct generic_data *data = chip->model_data;
 
-       data->ak4396_ctl2 = AK4396_SMUTE | AK4396_DEM_OFF | AK4396_DFS_NORMAL;
+       data->ak4396_regs[0][AK4396_CONTROL_2] =
+               AK4396_SMUTE | AK4396_DEM_OFF | AK4396_DFS_NORMAL;
        ak4396_registers_init(chip);
        snd_component_add(chip->card, "AK4396");
 }
@@ -173,17 +183,17 @@ static void wm8785_registers_init(struct oxygen *chip)
        struct generic_data *data = chip->model_data;
 
        wm8785_write(chip, WM8785_R7, 0);
-       wm8785_write(chip, WM8785_R0, data->saved_wm8785_registers[0]);
-       wm8785_write(chip, WM8785_R1, data->saved_wm8785_registers[1]);
+       wm8785_write(chip, WM8785_R0, data->wm8785_regs[0]);
+       wm8785_write(chip, WM8785_R2, data->wm8785_regs[2]);
 }
 
 static void wm8785_init(struct oxygen *chip)
 {
        struct generic_data *data = chip->model_data;
 
-       data->saved_wm8785_registers[0] = WM8785_MCR_SLAVE |
-               WM8785_OSR_SINGLE | WM8785_FORMAT_LJUST;
-       data->saved_wm8785_registers[1] = WM8785_WL_24;
+       data->wm8785_regs[0] =
+               WM8785_MCR_SLAVE | WM8785_OSR_SINGLE | WM8785_FORMAT_LJUST;
+       data->wm8785_regs[2] = WM8785_HPFR | WM8785_HPFL;
        wm8785_registers_init(chip);
        snd_component_add(chip->card, "WM8785");
 }
@@ -264,24 +274,36 @@ static void set_ak4396_params(struct oxygen *chip,
        unsigned int i;
        u8 value;
 
-       value = data->ak4396_ctl2 & ~AK4396_DFS_MASK;
+       value = data->ak4396_regs[0][AK4396_CONTROL_2] & ~AK4396_DFS_MASK;
        if (params_rate(params) <= 54000)
                value |= AK4396_DFS_NORMAL;
        else if (params_rate(params) <= 108000)
                value |= AK4396_DFS_DOUBLE;
        else
                value |= AK4396_DFS_QUAD;
-       data->ak4396_ctl2 = value;
 
        msleep(1); /* wait for the new MCLK to become stable */
 
+       if (value != data->ak4396_regs[0][AK4396_CONTROL_2]) {
+               for (i = 0; i < 4; ++i) {
+                       ak4396_write(chip, i, AK4396_CONTROL_1,
+                                    AK4396_DIF_24_MSB);
+                       ak4396_write(chip, i, AK4396_CONTROL_2, value);
+                       ak4396_write(chip, i, AK4396_CONTROL_1,
+                                    AK4396_DIF_24_MSB | AK4396_RSTN);
+               }
+       }
+}
+
+static void update_ak4396_volume(struct oxygen *chip)
+{
+       unsigned int i;
+
        for (i = 0; i < 4; ++i) {
-               ak4396_write(chip, i,
-                            AK4396_CONTROL_1, AK4396_DIF_24_MSB);
-               ak4396_write(chip, i,
-                            AK4396_CONTROL_2, value);
-               ak4396_write(chip, i,
-                            AK4396_CONTROL_1, AK4396_DIF_24_MSB | AK4396_RSTN);
+               ak4396_write_cached(chip, i, AK4396_LCH_ATT,
+                                   chip->dac_volume[i * 2]);
+               ak4396_write_cached(chip, i, AK4396_RCH_ATT,
+                                   chip->dac_volume[i * 2 + 1]);
        }
 }
 
@@ -291,21 +313,19 @@ static void update_ak4396_mute(struct oxygen *chip)
        unsigned int i;
        u8 value;
 
-       value = data->ak4396_ctl2 & ~AK4396_SMUTE;
+       value = data->ak4396_regs[0][AK4396_CONTROL_2] & ~AK4396_SMUTE;
        if (chip->dac_mute)
                value |= AK4396_SMUTE;
-       data->ak4396_ctl2 = value;
        for (i = 0; i < 4; ++i)
-               ak4396_write(chip, i, AK4396_CONTROL_2, value);
+               ak4396_write_cached(chip, i, AK4396_CONTROL_2, value);
 }
 
 static void set_wm8785_params(struct oxygen *chip,
                              struct snd_pcm_hw_params *params)
 {
+       struct generic_data *data = chip->model_data;
        unsigned int value;
 
-       wm8785_write(chip, WM8785_R7, 0);
-
        value = WM8785_MCR_SLAVE | WM8785_FORMAT_LJUST;
        if (params_rate(params) <= 48000)
                value |= WM8785_OSR_SINGLE;
@@ -313,13 +333,11 @@ static void set_wm8785_params(struct oxygen *chip,
                value |= WM8785_OSR_DOUBLE;
        else
                value |= WM8785_OSR_QUAD;
-       wm8785_write(chip, WM8785_R0, value);
-
-       if (snd_pcm_format_width(params_format(params)) <= 16)
-               value = WM8785_WL_16;
-       else
-               value = WM8785_WL_24;
-       wm8785_write(chip, WM8785_R1, value);
+       if (value != data->wm8785_regs[0]) {
+               wm8785_write(chip, WM8785_R7, 0);
+               wm8785_write(chip, WM8785_R0, value);
+               wm8785_write(chip, WM8785_R2, data->wm8785_regs[2]);
+       }
 }
 
 static void set_ak5385_params(struct oxygen *chip,
@@ -337,6 +355,134 @@ static void set_ak5385_params(struct oxygen *chip,
                              value, GPIO_AK5385_DFS_MASK);
 }
 
+static int rolloff_info(struct snd_kcontrol *ctl,
+                       struct snd_ctl_elem_info *info)
+{
+       static const char *const names[2] = {
+               "Sharp Roll-off", "Slow Roll-off"
+       };
+
+       info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+       info->count = 1;
+       info->value.enumerated.items = 2;
+       if (info->value.enumerated.item >= 2)
+               info->value.enumerated.item = 1;
+       strcpy(info->value.enumerated.name, names[info->value.enumerated.item]);
+       return 0;
+}
+
+static int rolloff_get(struct snd_kcontrol *ctl,
+                      struct snd_ctl_elem_value *value)
+{
+       struct oxygen *chip = ctl->private_data;
+       struct generic_data *data = chip->model_data;
+
+       value->value.enumerated.item[0] =
+               (data->ak4396_regs[0][AK4396_CONTROL_2] & AK4396_SLOW) != 0;
+       return 0;
+}
+
+static int rolloff_put(struct snd_kcontrol *ctl,
+                      struct snd_ctl_elem_value *value)
+{
+       struct oxygen *chip = ctl->private_data;
+       struct generic_data *data = chip->model_data;
+       unsigned int i;
+       int changed;
+       u8 reg;
+
+       mutex_lock(&chip->mutex);
+       reg = data->ak4396_regs[0][AK4396_CONTROL_2];
+       if (value->value.enumerated.item[0])
+               reg |= AK4396_SLOW;
+       else
+               reg &= ~AK4396_SLOW;
+       changed = reg != data->ak4396_regs[0][AK4396_CONTROL_2];
+       if (changed) {
+               for (i = 0; i < 4; ++i)
+                       ak4396_write(chip, i, AK4396_CONTROL_2, reg);
+       }
+       mutex_unlock(&chip->mutex);
+       return changed;
+}
+
+static const struct snd_kcontrol_new rolloff_control = {
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       .name = "DAC Filter Playback Enum",
+       .info = rolloff_info,
+       .get = rolloff_get,
+       .put = rolloff_put,
+};
+
+static int hpf_info(struct snd_kcontrol *ctl, struct snd_ctl_elem_info *info)
+{
+       static const char *const names[2] = {
+               "None", "High-pass Filter"
+       };
+
+       info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+       info->count = 1;
+       info->value.enumerated.items = 2;
+       if (info->value.enumerated.item >= 2)
+               info->value.enumerated.item = 1;
+       strcpy(info->value.enumerated.name, names[info->value.enumerated.item]);
+       return 0;
+}
+
+static int hpf_get(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value)
+{
+       struct oxygen *chip = ctl->private_data;
+       struct generic_data *data = chip->model_data;
+
+       value->value.enumerated.item[0] =
+               (data->wm8785_regs[WM8785_R2] & WM8785_HPFR) != 0;
+       return 0;
+}
+
+static int hpf_put(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value)
+{
+       struct oxygen *chip = ctl->private_data;
+       struct generic_data *data = chip->model_data;
+       unsigned int reg;
+       int changed;
+
+       mutex_lock(&chip->mutex);
+       reg = data->wm8785_regs[WM8785_R2] & ~(WM8785_HPFR | WM8785_HPFL);
+       if (value->value.enumerated.item[0])
+               reg |= WM8785_HPFR | WM8785_HPFL;
+       changed = reg != data->wm8785_regs[WM8785_R2];
+       if (changed)
+               wm8785_write(chip, WM8785_R2, reg);
+       mutex_unlock(&chip->mutex);
+       return changed;
+}
+
+static const struct snd_kcontrol_new hpf_control = {
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       .name = "ADC Filter Capture Enum",
+       .info = hpf_info,
+       .get = hpf_get,
+       .put = hpf_put,
+};
+
+static int generic_mixer_init(struct oxygen *chip)
+{
+       return snd_ctl_add(chip->card, snd_ctl_new1(&rolloff_control, chip));
+}
+
+static int generic_wm8785_mixer_init(struct oxygen *chip)
+{
+       int err;
+
+       err = generic_mixer_init(chip);
+       if (err < 0)
+               return err;
+       err = snd_ctl_add(chip->card, snd_ctl_new1(&hpf_control, chip));
+       if (err < 0)
+               return err;
+       return 0;
+}
+
 static const DECLARE_TLV_DB_LINEAR(ak4396_db_scale, TLV_DB_GAIN_MUTE, 0);
 
 static const struct oxygen_model model_generic = {
@@ -344,8 +490,10 @@ static const struct oxygen_model model_generic = {
        .longname = "C-Media Oxygen HD Audio",
        .chip = "CMI8788",
        .init = generic_init,
+       .mixer_init = generic_wm8785_mixer_init,
        .cleanup = generic_cleanup,
        .resume = generic_resume,
+       .get_i2s_mclk = oxygen_default_i2s_mclk,
        .set_dac_params = set_ak4396_params,
        .set_adc_params = set_wm8785_params,
        .update_dac_volume = update_ak4396_volume,
@@ -374,6 +522,7 @@ static int __devinit get_oxygen_model(struct oxygen *chip,
        switch (id->driver_data) {
        case MODEL_MERIDIAN:
                chip->model.init = meridian_init;
+               chip->model.mixer_init = generic_mixer_init;
                chip->model.resume = meridian_resume;
                chip->model.set_adc_params = set_ak5385_params;
                chip->model.device_config = PLAYBACK_0_TO_I2S |
@@ -389,6 +538,7 @@ static int __devinit get_oxygen_model(struct oxygen *chip,
                break;
        case MODEL_CLARO_HALO:
                chip->model.init = claro_halo_init;
+               chip->model.mixer_init = generic_mixer_init;
                chip->model.cleanup = claro_cleanup;
                chip->model.suspend = claro_suspend;
                chip->model.resume = claro_resume;
index bd615db..6147216 100644 (file)
@@ -78,12 +78,15 @@ struct oxygen_model {
        void (*resume)(struct oxygen *chip);
        void (*pcm_hardware_filter)(unsigned int channel,
                                    struct snd_pcm_hardware *hardware);
+       unsigned int (*get_i2s_mclk)(struct oxygen *chip, unsigned int channel,
+                                    struct snd_pcm_hw_params *hw_params);
        void (*set_dac_params)(struct oxygen *chip,
                               struct snd_pcm_hw_params *params);
        void (*set_adc_params)(struct oxygen *chip,
                               struct snd_pcm_hw_params *params);
        void (*update_dac_volume)(struct oxygen *chip);
        void (*update_dac_mute)(struct oxygen *chip);
+       void (*update_center_lfe_mix)(struct oxygen *chip, bool mixed);
        void (*gpio_changed)(struct oxygen *chip);
        void (*uart_input)(struct oxygen *chip);
        void (*ac97_switch)(struct oxygen *chip,
@@ -162,6 +165,8 @@ void oxygen_update_spdif_source(struct oxygen *chip);
 /* oxygen_pcm.c */
 
 int oxygen_pcm_init(struct oxygen *chip);
+unsigned int oxygen_default_i2s_mclk(struct oxygen *chip, unsigned int channel,
+                                    struct snd_pcm_hw_params *hw_params);
 
 /* oxygen_io.c */
 
index 9a8936e..9c5e645 100644 (file)
@@ -278,7 +278,11 @@ oxygen_search_pci_id(struct oxygen *chip, const struct pci_device_id ids[])
 static void oxygen_restore_eeprom(struct oxygen *chip,
                                  const struct pci_device_id *id)
 {
-       if (oxygen_read_eeprom(chip, 0) != OXYGEN_EEPROM_ID) {
+       u16 eeprom_id;
+
+       eeprom_id = oxygen_read_eeprom(chip, 0);
+       if (eeprom_id != OXYGEN_EEPROM_ID &&
+           (eeprom_id != 0xffff || id->subdevice != 0x8788)) {
                /*
                 * This function gets called only when a known card model has
                 * been detected, i.e., we know there is a valid subsystem
@@ -303,6 +307,28 @@ static void oxygen_restore_eeprom(struct oxygen *chip,
        }
 }
 
+static void pci_bridge_magic(void)
+{
+       struct pci_dev *pci = NULL;
+       u32 tmp;
+
+       for (;;) {
+               /* If there is any Pericom PI7C9X110 PCI-E/PCI bridge ... */
+               pci = pci_get_device(0x12d8, 0xe110, pci);
+               if (!pci)
+                       break;
+               /*
+                * ... configure its secondary internal arbiter to park to
+                * the secondary port, instead of to the last master.
+                */
+               if (!pci_read_config_dword(pci, 0x40, &tmp)) {
+                       tmp |= 1;
+                       pci_write_config_dword(pci, 0x40, tmp);
+               }
+               /* Why?  Try asking C-Media. */
+       }
+}
+
 static void oxygen_init(struct oxygen *chip)
 {
        unsigned int i;
@@ -581,6 +607,7 @@ int oxygen_pci_probe(struct pci_dev *pci, int index, char *id,
        snd_card_set_dev(card, &pci->dev);
        card->private_free = oxygen_card_free;
 
+       pci_bridge_magic();
        oxygen_init(chip);
        chip->model.init(chip);
 
index 5401c54..f375b8a 100644 (file)
@@ -99,11 +99,15 @@ static int dac_mute_put(struct snd_kcontrol *ctl,
 
 static int upmix_info(struct snd_kcontrol *ctl, struct snd_ctl_elem_info *info)
 {
-       static const char *const names[3] = {
-               "Front", "Front+Surround", "Front+Surround+Back"
+       static const char *const names[5] = {
+               "Front",
+               "Front+Surround",
+               "Front+Surround+Back",
+               "Front+Surround+Center/LFE",
+               "Front+Surround+Center/LFE+Back",
        };
        struct oxygen *chip = ctl->private_data;
-       unsigned int count = 2 + (chip->model.dac_channels == 8);
+       unsigned int count = chip->model.update_center_lfe_mix ? 5 : 3;
 
        info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
        info->count = 1;
@@ -127,7 +131,7 @@ static int upmix_get(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value)
 void oxygen_update_dac_routing(struct oxygen *chip)
 {
        /* DAC 0: front, DAC 1: surround, DAC 2: center/LFE, DAC 3: back */
-       static const unsigned int reg_values[3] = {
+       static const unsigned int reg_values[5] = {
                /* stereo -> front */
                (0 << OXYGEN_PLAY_DAC0_SOURCE_SHIFT) |
                (1 << OXYGEN_PLAY_DAC1_SOURCE_SHIFT) |
@@ -143,6 +147,16 @@ void oxygen_update_dac_routing(struct oxygen *chip)
                (0 << OXYGEN_PLAY_DAC1_SOURCE_SHIFT) |
                (2 << OXYGEN_PLAY_DAC2_SOURCE_SHIFT) |
                (0 << OXYGEN_PLAY_DAC3_SOURCE_SHIFT),
+               /* stereo -> front+surround+center/LFE */
+               (0 << OXYGEN_PLAY_DAC0_SOURCE_SHIFT) |
+               (0 << OXYGEN_PLAY_DAC1_SOURCE_SHIFT) |
+               (0 << OXYGEN_PLAY_DAC2_SOURCE_SHIFT) |
+               (3 << OXYGEN_PLAY_DAC3_SOURCE_SHIFT),
+               /* stereo -> front+surround+center/LFE+back */
+               (0 << OXYGEN_PLAY_DAC0_SOURCE_SHIFT) |
+               (0 << OXYGEN_PLAY_DAC1_SOURCE_SHIFT) |
+               (0 << OXYGEN_PLAY_DAC2_SOURCE_SHIFT) |
+               (0 << OXYGEN_PLAY_DAC3_SOURCE_SHIFT),
        };
        u8 channels;
        unsigned int reg_value;
@@ -167,22 +181,23 @@ void oxygen_update_dac_routing(struct oxygen *chip)
                              OXYGEN_PLAY_DAC1_SOURCE_MASK |
                              OXYGEN_PLAY_DAC2_SOURCE_MASK |
                              OXYGEN_PLAY_DAC3_SOURCE_MASK);
+       if (chip->model.update_center_lfe_mix)
+               chip->model.update_center_lfe_mix(chip, chip->dac_routing > 2);
 }
 
 static int upmix_put(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value)
 {
        struct oxygen *chip = ctl->private_data;
-       unsigned int count = 2 + (chip->model.dac_channels == 8);
+       unsigned int count = chip->model.update_center_lfe_mix ? 5 : 3;
        int changed;
 
+       if (value->value.enumerated.item[0] >= count)
+               return -EINVAL;
        mutex_lock(&chip->mutex);
        changed = value->value.enumerated.item[0] != chip->dac_routing;
        if (changed) {
-               chip->dac_routing = min(value->value.enumerated.item[0],
-                                       count - 1);
-               spin_lock_irq(&chip->reg_lock);
+               chip->dac_routing = value->value.enumerated.item[0];
                oxygen_update_dac_routing(chip);
-               spin_unlock_irq(&chip->reg_lock);
        }
        mutex_unlock(&chip->mutex);
        return changed;
@@ -790,7 +805,7 @@ static const struct {
                .controls = {
                        {
                                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-                               .name = "Analog Input Monitor Switch",
+                               .name = "Analog Input Monitor Playback Switch",
                                .info = snd_ctl_boolean_mono_info,
                                .get = monitor_get,
                                .put = monitor_put,
@@ -798,7 +813,7 @@ static const struct {
                        },
                        {
                                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-                               .name = "Analog Input Monitor Volume",
+                               .name = "Analog Input Monitor Playback Volume",
                                .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
                                          SNDRV_CTL_ELEM_ACCESS_TLV_READ,
                                .info = monitor_volume_info,
@@ -815,7 +830,7 @@ static const struct {
                .controls = {
                        {
                                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-                               .name = "Analog Input Monitor Switch",
+                               .name = "Analog Input Monitor Playback Switch",
                                .info = snd_ctl_boolean_mono_info,
                                .get = monitor_get,
                                .put = monitor_put,
@@ -823,7 +838,7 @@ static const struct {
                        },
                        {
                                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-                               .name = "Analog Input Monitor Volume",
+                               .name = "Analog Input Monitor Playback Volume",
                                .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
                                          SNDRV_CTL_ELEM_ACCESS_TLV_READ,
                                .info = monitor_volume_info,
@@ -840,7 +855,7 @@ static const struct {
                .controls = {
                        {
                                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-                               .name = "Analog Input Monitor Switch",
+                               .name = "Analog Input Monitor Playback Switch",
                                .index = 1,
                                .info = snd_ctl_boolean_mono_info,
                                .get = monitor_get,
@@ -849,7 +864,7 @@ static const struct {
                        },
                        {
                                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-                               .name = "Analog Input Monitor Volume",
+                               .name = "Analog Input Monitor Playback Volume",
                                .index = 1,
                                .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
                                          SNDRV_CTL_ELEM_ACCESS_TLV_READ,
@@ -867,7 +882,7 @@ static const struct {
                .controls = {
                        {
                                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-                               .name = "Digital Input Monitor Switch",
+                               .name = "Digital Input Monitor Playback Switch",
                                .info = snd_ctl_boolean_mono_info,
                                .get = monitor_get,
                                .put = monitor_put,
@@ -875,7 +890,7 @@ static const struct {
                        },
                        {
                                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-                               .name = "Digital Input Monitor Volume",
+                               .name = "Digital Input Monitor Playback Volume",
                                .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
                                          SNDRV_CTL_ELEM_ACCESS_TLV_READ,
                                .info = monitor_volume_info,
@@ -954,6 +969,9 @@ static int add_controls(struct oxygen *chip,
                        if (err == 1)
                                continue;
                }
+               if (!strcmp(template.name, "Stereo Upmixing") &&
+                   chip->model.dac_channels == 2)
+                       continue;
                if (!strcmp(template.name, "Master Playback Volume") &&
                    chip->model.dac_tlv) {
                        template.tlv.p = chip->model.dac_tlv;
index ef2345d..9dff695 100644 (file)
@@ -271,13 +271,16 @@ static unsigned int oxygen_rate(struct snd_pcm_hw_params *hw_params)
        }
 }
 
-static unsigned int oxygen_i2s_mclk(struct snd_pcm_hw_params *hw_params)
+unsigned int oxygen_default_i2s_mclk(struct oxygen *chip,
+                                    unsigned int channel,
+                                    struct snd_pcm_hw_params *hw_params)
 {
        if (params_rate(hw_params) <= 96000)
                return OXYGEN_I2S_MCLK_256;
        else
                return OXYGEN_I2S_MCLK_128;
 }
+EXPORT_SYMBOL(oxygen_default_i2s_mclk);
 
 static unsigned int oxygen_i2s_bits(struct snd_pcm_hw_params *hw_params)
 {
@@ -354,7 +357,7 @@ static int oxygen_rec_a_hw_params(struct snd_pcm_substream *substream,
                             OXYGEN_REC_FORMAT_A_MASK);
        oxygen_write16_masked(chip, OXYGEN_I2S_A_FORMAT,
                              oxygen_rate(hw_params) |
-                             oxygen_i2s_mclk(hw_params) |
+                             chip->model.get_i2s_mclk(chip, PCM_A, hw_params) |
                              chip->model.adc_i2s_format |
                              oxygen_i2s_bits(hw_params),
                              OXYGEN_I2S_RATE_MASK |
@@ -390,7 +393,8 @@ static int oxygen_rec_b_hw_params(struct snd_pcm_substream *substream,
        if (!is_ac97)
                oxygen_write16_masked(chip, OXYGEN_I2S_B_FORMAT,
                                      oxygen_rate(hw_params) |
-                                     oxygen_i2s_mclk(hw_params) |
+                                     chip->model.get_i2s_mclk(chip, PCM_B,
+                                                              hw_params) |
                                      chip->model.adc_i2s_format |
                                      oxygen_i2s_bits(hw_params),
                                      OXYGEN_I2S_RATE_MASK |
@@ -435,6 +439,7 @@ static int oxygen_spdif_hw_params(struct snd_pcm_substream *substream,
        if (err < 0)
                return err;
 
+       mutex_lock(&chip->mutex);
        spin_lock_irq(&chip->reg_lock);
        oxygen_clear_bits32(chip, OXYGEN_SPDIF_CONTROL,
                            OXYGEN_SPDIF_OUT_ENABLE);
@@ -446,6 +451,7 @@ static int oxygen_spdif_hw_params(struct snd_pcm_substream *substream,
                              OXYGEN_SPDIF_OUT_RATE_MASK);
        oxygen_update_spdif_source(chip);
        spin_unlock_irq(&chip->reg_lock);
+       mutex_unlock(&chip->mutex);
        return 0;
 }
 
@@ -459,6 +465,7 @@ static int oxygen_multich_hw_params(struct snd_pcm_substream *substream,
        if (err < 0)
                return err;
 
+       mutex_lock(&chip->mutex);
        spin_lock_irq(&chip->reg_lock);
        oxygen_write8_masked(chip, OXYGEN_PLAY_CHANNELS,
                             oxygen_play_channels(hw_params),
@@ -469,18 +476,18 @@ static int oxygen_multich_hw_params(struct snd_pcm_substream *substream,
        oxygen_write16_masked(chip, OXYGEN_I2S_MULTICH_FORMAT,
                              oxygen_rate(hw_params) |
                              chip->model.dac_i2s_format |
-                             oxygen_i2s_mclk(hw_params) |
+                             chip->model.get_i2s_mclk(chip, PCM_MULTICH,
+                                                      hw_params) |
                              oxygen_i2s_bits(hw_params),
                              OXYGEN_I2S_RATE_MASK |
                              OXYGEN_I2S_FORMAT_MASK |
                              OXYGEN_I2S_MCLK_MASK |
                              OXYGEN_I2S_BITS_MASK);
-       oxygen_update_dac_routing(chip);
        oxygen_update_spdif_source(chip);
        spin_unlock_irq(&chip->reg_lock);
 
-       mutex_lock(&chip->mutex);
        chip->model.set_dac_params(chip, hw_params);
+       oxygen_update_dac_routing(chip);
        mutex_unlock(&chip->mutex);
        return 0;
 }
index 6ebcb6b..6accaf9 100644 (file)
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  */
 
-/*
- * Xonar D2/D2X
- * ------------
- *
- * CMI8788:
- *
- * SPI 0 -> 1st PCM1796 (front)
- * SPI 1 -> 2nd PCM1796 (surround)
- * SPI 2 -> 3rd PCM1796 (center/LFE)
- * SPI 4 -> 4th PCM1796 (back)
- *
- * GPIO 2 -> M0 of CS5381
- * GPIO 3 -> M1 of CS5381
- * GPIO 5 <- external power present (D2X only)
- * GPIO 7 -> ALT
- * GPIO 8 -> enable output to speakers
- */
-
-/*
- * Xonar D1/DX
- * -----------
- *
- * CMI8788:
- *
- * I²C <-> CS4398 (front)
- *     <-> CS4362A (surround, center/LFE, back)
- *
- * GPI 0 <- external power present (DX only)
- *
- * GPIO 0 -> enable output to speakers
- * GPIO 1 -> enable front panel I/O
- * GPIO 2 -> M0 of CS5361
- * GPIO 3 -> M1 of CS5361
- * GPIO 8 -> route input jack to line-in (0) or mic-in (1)
- *
- * CS4398:
- *
- * AD0 <- 1
- * AD1 <- 1
- *
- * CS4362A:
- *
- * AD0 <- 0
- */
-
-/*
- * Xonar HDAV1.3 (Deluxe)
- * ----------------------
- *
- * CMI8788:
- *
- * I²C <-> PCM1796 (front)
- *
- * GPI 0 <- external power present
- *
- * GPIO 0 -> enable output to speakers
- * GPIO 2 -> M0 of CS5381
- * GPIO 3 -> M1 of CS5381
- * GPIO 8 -> route input jack to line-in (0) or mic-in (1)
- *
- * TXD -> HDMI controller
- * RXD <- HDMI controller
- *
- * PCM1796 front: AD1,0 <- 0,0
- *
- * no daughterboard
- * ----------------
- *
- * GPIO 4 <- 1
- *
- * H6 daughterboard
- * ----------------
- *
- * GPIO 4 <- 0
- * GPIO 5 <- 0
- *
- * I²C <-> PCM1796 (surround)
- *     <-> PCM1796 (center/LFE)
- *     <-> PCM1796 (back)
- *
- * PCM1796 surround:   AD1,0 <- 0,1
- * PCM1796 center/LFE: AD1,0 <- 1,0
- * PCM1796 back:       AD1,0 <- 1,1
- *
- * unknown daughterboard
- * ---------------------
- *
- * GPIO 4 <- 0
- * GPIO 5 <- 1
- *
- * I²C <-> CS4362A (surround, center/LFE, back)
- *
- * CS4362A: AD0 <- 0
- */
-
-/*
- * Xonar Essence ST (Deluxe)/STX
- * -----------------------------
- *
- * CMI8788:
- *
- * I²C <-> PCM1792A
- *
- * GPI 0 <- external power present
- *
- * GPIO 0 -> enable output to speakers
- * GPIO 1 -> route HP to front panel (0) or rear jack (1)
- * GPIO 2 -> M0 of CS5381
- * GPIO 3 -> M1 of CS5381
- * GPIO 7 -> route output to speaker jacks (0) or HP (1)
- * GPIO 8 -> route input jack to line-in (0) or mic-in (1)
- *
- * PCM1792A:
- *
- * AD0 <- 0
- *
- * H6 daughterboard
- * ----------------
- *
- * GPIO 4 <- 0
- * GPIO 5 <- 0
- */
-
 #include <linux/pci.h>
 #include <linux/delay.h>
-#include <linux/mutex.h>
-#include <sound/ac97_codec.h>
-#include <sound/asoundef.h>
-#include <sound/control.h>
 #include <sound/core.h>
 #include <sound/initval.h>
 #include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/tlv.h>
-#include "oxygen.h"
-#include "cm9780.h"
-#include "pcm1796.h"
-#include "cs4398.h"
-#include "cs4362a.h"
+#include "xonar.h"
 
 MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>");
 MODULE_DESCRIPTION("Asus AVx00 driver");
@@ -173,972 +40,28 @@ MODULE_PARM_DESC(id, "ID string");
 module_param_array(enable, bool, NULL, 0444);
 MODULE_PARM_DESC(enable, "enable card");
 
-enum {
-       MODEL_D2,
-       MODEL_D2X,
-       MODEL_D1,
-       MODEL_DX,
-       MODEL_HDAV,     /* without daughterboard */
-       MODEL_HDAV_H6,  /* with H6 daughterboard */
-       MODEL_ST,
-       MODEL_ST_H6,
-       MODEL_STX,
-};
-
 static struct pci_device_id xonar_ids[] __devinitdata = {
-       { OXYGEN_PCI_SUBID(0x1043, 0x8269), .driver_data = MODEL_D2 },
-       { OXYGEN_PCI_SUBID(0x1043, 0x8275), .driver_data = MODEL_DX },
-       { OXYGEN_PCI_SUBID(0x1043, 0x82b7), .driver_data = MODEL_D2X },
-       { OXYGEN_PCI_SUBID(0x1043, 0x8314), .driver_data = MODEL_HDAV },
-       { OXYGEN_PCI_SUBID(0x1043, 0x8327), .driver_data = MODEL_DX },
-       { OXYGEN_PCI_SUBID(0x1043, 0x834f), .driver_data = MODEL_D1 },
-       { OXYGEN_PCI_SUBID(0x1043, 0x835c), .driver_data = MODEL_STX },
-       { OXYGEN_PCI_SUBID(0x1043, 0x835d), .driver_data = MODEL_ST },
+       { OXYGEN_PCI_SUBID(0x1043, 0x8269) },
+       { OXYGEN_PCI_SUBID(0x1043, 0x8275) },
+       { OXYGEN_PCI_SUBID(0x1043, 0x82b7) },
+       { OXYGEN_PCI_SUBID(0x1043, 0x8314) },
+       { OXYGEN_PCI_SUBID(0x1043, 0x8327) },
+       { OXYGEN_PCI_SUBID(0x1043, 0x834f) },
+       { OXYGEN_PCI_SUBID(0x1043, 0x835c) },
+       { OXYGEN_PCI_SUBID(0x1043, 0x835d) },
        { OXYGEN_PCI_SUBID_BROKEN_EEPROM },
        { }
 };
 MODULE_DEVICE_TABLE(pci, xonar_ids);
 
-
-#define GPIO_CS53x1_M_MASK     0x000c
-#define GPIO_CS53x1_M_SINGLE   0x0000
-#define GPIO_CS53x1_M_DOUBLE   0x0004
-#define GPIO_CS53x1_M_QUAD     0x0008
-
-#define GPIO_D2X_EXT_POWER     0x0020
-#define GPIO_D2_ALT            0x0080
-#define GPIO_D2_OUTPUT_ENABLE  0x0100
-
-#define GPI_DX_EXT_POWER       0x01
-#define GPIO_DX_OUTPUT_ENABLE  0x0001
-#define GPIO_DX_FRONT_PANEL    0x0002
-#define GPIO_DX_INPUT_ROUTE    0x0100
-
-#define GPIO_DB_MASK           0x0030
-#define GPIO_DB_H6             0x0000
-#define GPIO_DB_XX             0x0020
-
-#define GPIO_ST_HP_REAR                0x0002
-#define GPIO_ST_HP             0x0080
-
-#define I2C_DEVICE_PCM1796(i)  (0x98 + ((i) << 1))     /* 10011, ADx=i, /W=0 */
-#define I2C_DEVICE_CS4398      0x9e    /* 10011, AD1=1, AD0=1, /W=0 */
-#define I2C_DEVICE_CS4362A     0x30    /* 001100, AD0=0, /W=0 */
-
-struct xonar_data {
-       unsigned int anti_pop_delay;
-       unsigned int dacs;
-       u16 output_enable_bit;
-       u8 ext_power_reg;
-       u8 ext_power_int_reg;
-       u8 ext_power_bit;
-       u8 has_power;
-       u8 pcm1796_oversampling;
-       u8 cs4398_fm;
-       u8 cs4362a_fm;
-       u8 hdmi_params[5];
-};
-
-static void xonar_gpio_changed(struct oxygen *chip);
-
-static inline void pcm1796_write_spi(struct oxygen *chip, unsigned int codec,
-                                    u8 reg, u8 value)
-{
-       /* maps ALSA channel pair number to SPI output */
-       static const u8 codec_map[4] = {
-               0, 1, 2, 4
-       };
-       oxygen_write_spi(chip, OXYGEN_SPI_TRIGGER  |
-                        OXYGEN_SPI_DATA_LENGTH_2 |
-                        OXYGEN_SPI_CLOCK_160 |
-                        (codec_map[codec] << OXYGEN_SPI_CODEC_SHIFT) |
-                        OXYGEN_SPI_CEN_LATCH_CLOCK_HI,
-                        (reg << 8) | value);
-}
-
-static inline void pcm1796_write_i2c(struct oxygen *chip, unsigned int codec,
-                                    u8 reg, u8 value)
-{
-       oxygen_write_i2c(chip, I2C_DEVICE_PCM1796(codec), reg, value);
-}
-
-static void pcm1796_write(struct oxygen *chip, unsigned int codec,
-                         u8 reg, u8 value)
-{
-       if ((chip->model.function_flags & OXYGEN_FUNCTION_2WIRE_SPI_MASK) ==
-           OXYGEN_FUNCTION_SPI)
-               pcm1796_write_spi(chip, codec, reg, value);
-       else
-               pcm1796_write_i2c(chip, codec, reg, value);
-}
-
-static void cs4398_write(struct oxygen *chip, u8 reg, u8 value)
-{
-       oxygen_write_i2c(chip, I2C_DEVICE_CS4398, reg, value);
-}
-
-static void cs4362a_write(struct oxygen *chip, u8 reg, u8 value)
-{
-       oxygen_write_i2c(chip, I2C_DEVICE_CS4362A, reg, value);
-}
-
-static void hdmi_write_command(struct oxygen *chip, u8 command,
-                              unsigned int count, const u8 *params)
-{
-       unsigned int i;
-       u8 checksum;
-
-       oxygen_write_uart(chip, 0xfb);
-       oxygen_write_uart(chip, 0xef);
-       oxygen_write_uart(chip, command);
-       oxygen_write_uart(chip, count);
-       for (i = 0; i < count; ++i)
-               oxygen_write_uart(chip, params[i]);
-       checksum = 0xfb + 0xef + command + count;
-       for (i = 0; i < count; ++i)
-               checksum += params[i];
-       oxygen_write_uart(chip, checksum);
-}
-
-static void xonar_enable_output(struct oxygen *chip)
-{
-       struct xonar_data *data = chip->model_data;
-
-       msleep(data->anti_pop_delay);
-       oxygen_set_bits16(chip, OXYGEN_GPIO_DATA, data->output_enable_bit);
-}
-
-static void xonar_common_init(struct oxygen *chip)
-{
-       struct xonar_data *data = chip->model_data;
-
-       if (data->ext_power_reg) {
-               oxygen_set_bits8(chip, data->ext_power_int_reg,
-                                data->ext_power_bit);
-               chip->interrupt_mask |= OXYGEN_INT_GPIO;
-               chip->model.gpio_changed = xonar_gpio_changed;
-               data->has_power = !!(oxygen_read8(chip, data->ext_power_reg)
-                                    & data->ext_power_bit);
-       }
-       oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL,
-                         GPIO_CS53x1_M_MASK | data->output_enable_bit);
-       oxygen_write16_masked(chip, OXYGEN_GPIO_DATA,
-                             GPIO_CS53x1_M_SINGLE, GPIO_CS53x1_M_MASK);
-       oxygen_ac97_set_bits(chip, 0, CM9780_JACK, CM9780_FMIC2MIC);
-       xonar_enable_output(chip);
-}
-
-static void update_pcm1796_volume(struct oxygen *chip)
-{
-       struct xonar_data *data = chip->model_data;
-       unsigned int i;
-
-       for (i = 0; i < data->dacs; ++i) {
-               pcm1796_write(chip, i, 16, chip->dac_volume[i * 2]);
-               pcm1796_write(chip, i, 17, chip->dac_volume[i * 2 + 1]);
-       }
-}
-
-static void update_pcm1796_mute(struct oxygen *chip)
-{
-       struct xonar_data *data = chip->model_data;
-       unsigned int i;
-       u8 value;
-
-       value = PCM1796_DMF_DISABLED | PCM1796_FMT_24_LJUST | PCM1796_ATLD;
-       if (chip->dac_mute)
-               value |= PCM1796_MUTE;
-       for (i = 0; i < data->dacs; ++i)
-               pcm1796_write(chip, i, 18, value);
-}
-
-static void pcm1796_init(struct oxygen *chip)
-{
-       struct xonar_data *data = chip->model_data;
-       unsigned int i;
-
-       for (i = 0; i < data->dacs; ++i) {
-               pcm1796_write(chip, i, 19, PCM1796_FLT_SHARP | PCM1796_ATS_1);
-               pcm1796_write(chip, i, 20, data->pcm1796_oversampling);
-               pcm1796_write(chip, i, 21, 0);
-       }
-       update_pcm1796_mute(chip); /* set ATLD before ATL/ATR */
-       update_pcm1796_volume(chip);
-}
-
-static void xonar_d2_init(struct oxygen *chip)
-{
-       struct xonar_data *data = chip->model_data;
-
-       data->anti_pop_delay = 300;
-       data->dacs = 4;
-       data->output_enable_bit = GPIO_D2_OUTPUT_ENABLE;
-       data->pcm1796_oversampling = PCM1796_OS_64;
-
-       pcm1796_init(chip);
-
-       oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_D2_ALT);
-       oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, GPIO_D2_ALT);
-
-       xonar_common_init(chip);
-
-       snd_component_add(chip->card, "PCM1796");
-       snd_component_add(chip->card, "CS5381");
-}
-
-static void xonar_d2x_init(struct oxygen *chip)
-{
-       struct xonar_data *data = chip->model_data;
-
-       data->ext_power_reg = OXYGEN_GPIO_DATA;
-       data->ext_power_int_reg = OXYGEN_GPIO_INTERRUPT_MASK;
-       data->ext_power_bit = GPIO_D2X_EXT_POWER;
-       oxygen_clear_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_D2X_EXT_POWER);
-
-       xonar_d2_init(chip);
-}
-
-static void update_cs4362a_volumes(struct oxygen *chip)
-{
-       u8 mute;
-
-       mute = chip->dac_mute ? CS4362A_MUTE : 0;
-       cs4362a_write(chip, 7, (127 - chip->dac_volume[2]) | mute);
-       cs4362a_write(chip, 8, (127 - chip->dac_volume[3]) | mute);
-       cs4362a_write(chip, 10, (127 - chip->dac_volume[4]) | mute);
-       cs4362a_write(chip, 11, (127 - chip->dac_volume[5]) | mute);
-       cs4362a_write(chip, 13, (127 - chip->dac_volume[6]) | mute);
-       cs4362a_write(chip, 14, (127 - chip->dac_volume[7]) | mute);
-}
-
-static void update_cs43xx_volume(struct oxygen *chip)
-{
-       cs4398_write(chip, 5, (127 - chip->dac_volume[0]) * 2);
-       cs4398_write(chip, 6, (127 - chip->dac_volume[1]) * 2);
-       update_cs4362a_volumes(chip);
-}
-
-static void update_cs43xx_mute(struct oxygen *chip)
-{
-       u8 reg;
-
-       reg = CS4398_MUTEP_LOW | CS4398_PAMUTE;
-       if (chip->dac_mute)
-               reg |= CS4398_MUTE_B | CS4398_MUTE_A;
-       cs4398_write(chip, 4, reg);
-       update_cs4362a_volumes(chip);
-}
-
-static void cs43xx_init(struct oxygen *chip)
-{
-       struct xonar_data *data = chip->model_data;
-
-       /* set CPEN (control port mode) and power down */
-       cs4398_write(chip, 8, CS4398_CPEN | CS4398_PDN);
-       cs4362a_write(chip, 0x01, CS4362A_PDN | CS4362A_CPEN);
-       /* configure */
-       cs4398_write(chip, 2, data->cs4398_fm);
-       cs4398_write(chip, 3, CS4398_ATAPI_B_R | CS4398_ATAPI_A_L);
-       cs4398_write(chip, 7, CS4398_RMP_DN | CS4398_RMP_UP |
-                    CS4398_ZERO_CROSS | CS4398_SOFT_RAMP);
-       cs4362a_write(chip, 0x02, CS4362A_DIF_LJUST);
-       cs4362a_write(chip, 0x03, CS4362A_MUTEC_6 | CS4362A_AMUTE |
-                     CS4362A_RMP_UP | CS4362A_ZERO_CROSS | CS4362A_SOFT_RAMP);
-       cs4362a_write(chip, 0x04, CS4362A_RMP_DN | CS4362A_DEM_NONE);
-       cs4362a_write(chip, 0x05, 0);
-       cs4362a_write(chip, 0x06, data->cs4362a_fm);
-       cs4362a_write(chip, 0x09, data->cs4362a_fm);
-       cs4362a_write(chip, 0x0c, data->cs4362a_fm);
-       update_cs43xx_volume(chip);
-       update_cs43xx_mute(chip);
-       /* clear power down */
-       cs4398_write(chip, 8, CS4398_CPEN);
-       cs4362a_write(chip, 0x01, CS4362A_CPEN);
-}
-
-static void xonar_d1_init(struct oxygen *chip)
-{
-       struct xonar_data *data = chip->model_data;
-
-       data->anti_pop_delay = 800;
-       data->output_enable_bit = GPIO_DX_OUTPUT_ENABLE;
-       data->cs4398_fm = CS4398_FM_SINGLE | CS4398_DEM_NONE | CS4398_DIF_LJUST;
-       data->cs4362a_fm = CS4362A_FM_SINGLE |
-               CS4362A_ATAPI_B_R | CS4362A_ATAPI_A_L;
-
-       oxygen_write16(chip, OXYGEN_2WIRE_BUS_STATUS,
-                      OXYGEN_2WIRE_LENGTH_8 |
-                      OXYGEN_2WIRE_INTERRUPT_MASK |
-                      OXYGEN_2WIRE_SPEED_FAST);
-
-       cs43xx_init(chip);
-
-       oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL,
-                         GPIO_DX_FRONT_PANEL | GPIO_DX_INPUT_ROUTE);
-       oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA,
-                           GPIO_DX_FRONT_PANEL | GPIO_DX_INPUT_ROUTE);
-
-       xonar_common_init(chip);
-
-       snd_component_add(chip->card, "CS4398");
-       snd_component_add(chip->card, "CS4362A");
-       snd_component_add(chip->card, "CS5361");
-}
-
-static void xonar_dx_init(struct oxygen *chip)
-{
-       struct xonar_data *data = chip->model_data;
-
-       data->ext_power_reg = OXYGEN_GPI_DATA;
-       data->ext_power_int_reg = OXYGEN_GPI_INTERRUPT_MASK;
-       data->ext_power_bit = GPI_DX_EXT_POWER;
-
-       xonar_d1_init(chip);
-}
-
-static void xonar_hdav_init(struct oxygen *chip)
-{
-       struct xonar_data *data = chip->model_data;
-       u8 param;
-
-       oxygen_write16(chip, OXYGEN_2WIRE_BUS_STATUS,
-                      OXYGEN_2WIRE_LENGTH_8 |
-                      OXYGEN_2WIRE_INTERRUPT_MASK |
-                      OXYGEN_2WIRE_SPEED_FAST);
-
-       data->anti_pop_delay = 100;
-       data->dacs = chip->model.private_data == MODEL_HDAV_H6 ? 4 : 1;
-       data->output_enable_bit = GPIO_DX_OUTPUT_ENABLE;
-       data->ext_power_reg = OXYGEN_GPI_DATA;
-       data->ext_power_int_reg = OXYGEN_GPI_INTERRUPT_MASK;
-       data->ext_power_bit = GPI_DX_EXT_POWER;
-       data->pcm1796_oversampling = PCM1796_OS_64;
-
-       pcm1796_init(chip);
-
-       oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_DX_INPUT_ROUTE);
-       oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, GPIO_DX_INPUT_ROUTE);
-
-       oxygen_reset_uart(chip);
-       param = 0;
-       hdmi_write_command(chip, 0x61, 1, &param);
-       param = 1;
-       hdmi_write_command(chip, 0x74, 1, &param);
-       data->hdmi_params[1] = IEC958_AES3_CON_FS_48000;
-       data->hdmi_params[4] = 1;
-       hdmi_write_command(chip, 0x54, 5, data->hdmi_params);
-
-       xonar_common_init(chip);
-
-       snd_component_add(chip->card, "PCM1796");
-       snd_component_add(chip->card, "CS5381");
-}
-
-static void xonar_st_init(struct oxygen *chip)
-{
-       struct xonar_data *data = chip->model_data;
-
-       oxygen_write16(chip, OXYGEN_2WIRE_BUS_STATUS,
-                      OXYGEN_2WIRE_LENGTH_8 |
-                      OXYGEN_2WIRE_INTERRUPT_MASK |
-                      OXYGEN_2WIRE_SPEED_FAST);
-
-       if (chip->model.private_data == MODEL_ST_H6)
-               chip->model.dac_channels = 8;
-       data->anti_pop_delay = 100;
-       data->dacs = chip->model.private_data == MODEL_ST_H6 ? 4 : 1;
-       data->output_enable_bit = GPIO_DX_OUTPUT_ENABLE;
-       data->pcm1796_oversampling = PCM1796_OS_64;
-
-       pcm1796_init(chip);
-
-       oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL,
-                         GPIO_DX_INPUT_ROUTE | GPIO_ST_HP_REAR | GPIO_ST_HP);
-       oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA,
-                           GPIO_DX_INPUT_ROUTE | GPIO_ST_HP_REAR | GPIO_ST_HP);
-
-       xonar_common_init(chip);
-
-       snd_component_add(chip->card, "PCM1792A");
-       snd_component_add(chip->card, "CS5381");
-}
-
-static void xonar_stx_init(struct oxygen *chip)
-{
-       struct xonar_data *data = chip->model_data;
-
-       data->ext_power_reg = OXYGEN_GPI_DATA;
-       data->ext_power_int_reg = OXYGEN_GPI_INTERRUPT_MASK;
-       data->ext_power_bit = GPI_DX_EXT_POWER;
-
-       xonar_st_init(chip);
-}
-
-static void xonar_disable_output(struct oxygen *chip)
-{
-       struct xonar_data *data = chip->model_data;
-
-       oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, data->output_enable_bit);
-}
-
-static void xonar_d2_cleanup(struct oxygen *chip)
-{
-       xonar_disable_output(chip);
-}
-
-static void xonar_d1_cleanup(struct oxygen *chip)
-{
-       xonar_disable_output(chip);
-       cs4362a_write(chip, 0x01, CS4362A_PDN | CS4362A_CPEN);
-       oxygen_clear_bits8(chip, OXYGEN_FUNCTION, OXYGEN_FUNCTION_RESET_CODEC);
-}
-
-static void xonar_hdav_cleanup(struct oxygen *chip)
-{
-       u8 param = 0;
-
-       hdmi_write_command(chip, 0x74, 1, &param);
-       xonar_disable_output(chip);
-}
-
-static void xonar_st_cleanup(struct oxygen *chip)
-{
-       xonar_disable_output(chip);
-}
-
-static void xonar_d2_suspend(struct oxygen *chip)
-{
-       xonar_d2_cleanup(chip);
-}
-
-static void xonar_d1_suspend(struct oxygen *chip)
-{
-       xonar_d1_cleanup(chip);
-}
-
-static void xonar_hdav_suspend(struct oxygen *chip)
-{
-       xonar_hdav_cleanup(chip);
-       msleep(2);
-}
-
-static void xonar_st_suspend(struct oxygen *chip)
-{
-       xonar_st_cleanup(chip);
-}
-
-static void xonar_d2_resume(struct oxygen *chip)
-{
-       pcm1796_init(chip);
-       xonar_enable_output(chip);
-}
-
-static void xonar_d1_resume(struct oxygen *chip)
-{
-       oxygen_set_bits8(chip, OXYGEN_FUNCTION, OXYGEN_FUNCTION_RESET_CODEC);
-       msleep(1);
-       cs43xx_init(chip);
-       xonar_enable_output(chip);
-}
-
-static void xonar_hdav_resume(struct oxygen *chip)
-{
-       struct xonar_data *data = chip->model_data;
-       u8 param;
-
-       oxygen_reset_uart(chip);
-       param = 0;
-       hdmi_write_command(chip, 0x61, 1, &param);
-       param = 1;
-       hdmi_write_command(chip, 0x74, 1, &param);
-       hdmi_write_command(chip, 0x54, 5, data->hdmi_params);
-       pcm1796_init(chip);
-       xonar_enable_output(chip);
-}
-
-static void xonar_st_resume(struct oxygen *chip)
-{
-       pcm1796_init(chip);
-       xonar_enable_output(chip);
-}
-
-static void xonar_hdav_pcm_hardware_filter(unsigned int channel,
-                                          struct snd_pcm_hardware *hardware)
-{
-       if (channel == PCM_MULTICH) {
-               hardware->rates = SNDRV_PCM_RATE_44100 |
-                                 SNDRV_PCM_RATE_48000 |
-                                 SNDRV_PCM_RATE_96000 |
-                                 SNDRV_PCM_RATE_192000;
-               hardware->rate_min = 44100;
-       }
-}
-
-static void set_pcm1796_params(struct oxygen *chip,
-                              struct snd_pcm_hw_params *params)
-{
-       struct xonar_data *data = chip->model_data;
-       unsigned int i;
-
-       data->pcm1796_oversampling =
-               params_rate(params) >= 96000 ? PCM1796_OS_32 : PCM1796_OS_64;
-       for (i = 0; i < data->dacs; ++i)
-               pcm1796_write(chip, i, 20, data->pcm1796_oversampling);
-}
-
-static void set_cs53x1_params(struct oxygen *chip,
-                             struct snd_pcm_hw_params *params)
-{
-       unsigned int value;
-
-       if (params_rate(params) <= 54000)
-               value = GPIO_CS53x1_M_SINGLE;
-       else if (params_rate(params) <= 108000)
-               value = GPIO_CS53x1_M_DOUBLE;
-       else
-               value = GPIO_CS53x1_M_QUAD;
-       oxygen_write16_masked(chip, OXYGEN_GPIO_DATA,
-                             value, GPIO_CS53x1_M_MASK);
-}
-
-static void set_cs43xx_params(struct oxygen *chip,
-                             struct snd_pcm_hw_params *params)
-{
-       struct xonar_data *data = chip->model_data;
-
-       data->cs4398_fm = CS4398_DEM_NONE | CS4398_DIF_LJUST;
-       data->cs4362a_fm = CS4362A_ATAPI_B_R | CS4362A_ATAPI_A_L;
-       if (params_rate(params) <= 50000) {
-               data->cs4398_fm |= CS4398_FM_SINGLE;
-               data->cs4362a_fm |= CS4362A_FM_SINGLE;
-       } else if (params_rate(params) <= 100000) {
-               data->cs4398_fm |= CS4398_FM_DOUBLE;
-               data->cs4362a_fm |= CS4362A_FM_DOUBLE;
-       } else {
-               data->cs4398_fm |= CS4398_FM_QUAD;
-               data->cs4362a_fm |= CS4362A_FM_QUAD;
-       }
-       cs4398_write(chip, 2, data->cs4398_fm);
-       cs4362a_write(chip, 0x06, data->cs4362a_fm);
-       cs4362a_write(chip, 0x09, data->cs4362a_fm);
-       cs4362a_write(chip, 0x0c, data->cs4362a_fm);
-}
-
-static void set_hdmi_params(struct oxygen *chip,
-                           struct snd_pcm_hw_params *params)
-{
-       struct xonar_data *data = chip->model_data;
-
-       data->hdmi_params[0] = 0; /* 1 = non-audio */
-       switch (params_rate(params)) {
-       case 44100:
-               data->hdmi_params[1] = IEC958_AES3_CON_FS_44100;
-               break;
-       case 48000:
-               data->hdmi_params[1] = IEC958_AES3_CON_FS_48000;
-               break;
-       default: /* 96000 */
-               data->hdmi_params[1] = IEC958_AES3_CON_FS_96000;
-               break;
-       case 192000:
-               data->hdmi_params[1] = IEC958_AES3_CON_FS_192000;
-               break;
-       }
-       data->hdmi_params[2] = params_channels(params) / 2 - 1;
-       if (params_format(params) == SNDRV_PCM_FORMAT_S16_LE)
-               data->hdmi_params[3] = 0;
-       else
-               data->hdmi_params[3] = 0xc0;
-       data->hdmi_params[4] = 1; /* ? */
-       hdmi_write_command(chip, 0x54, 5, data->hdmi_params);
-}
-
-static void set_hdav_params(struct oxygen *chip,
-                           struct snd_pcm_hw_params *params)
-{
-       set_pcm1796_params(chip, params);
-       set_hdmi_params(chip, params);
-}
-
-static void xonar_gpio_changed(struct oxygen *chip)
-{
-       struct xonar_data *data = chip->model_data;
-       u8 has_power;
-
-       has_power = !!(oxygen_read8(chip, data->ext_power_reg)
-                      & data->ext_power_bit);
-       if (has_power != data->has_power) {
-               data->has_power = has_power;
-               if (has_power) {
-                       snd_printk(KERN_NOTICE "power restored\n");
-               } else {
-                       snd_printk(KERN_CRIT
-                                  "Hey! Don't unplug the power cable!\n");
-                       /* TODO: stop PCMs */
-               }
-       }
-}
-
-static void xonar_hdav_uart_input(struct oxygen *chip)
-{
-       if (chip->uart_input_count >= 2 &&
-           chip->uart_input[chip->uart_input_count - 2] == 'O' &&
-           chip->uart_input[chip->uart_input_count - 1] == 'K') {
-               printk(KERN_DEBUG "message from Xonar HDAV HDMI chip received:\n");
-               print_hex_dump_bytes("", DUMP_PREFIX_OFFSET,
-                                    chip->uart_input, chip->uart_input_count);
-               chip->uart_input_count = 0;
-       }
-}
-
-static int gpio_bit_switch_get(struct snd_kcontrol *ctl,
-                              struct snd_ctl_elem_value *value)
-{
-       struct oxygen *chip = ctl->private_data;
-       u16 bit = ctl->private_value;
-
-       value->value.integer.value[0] =
-               !!(oxygen_read16(chip, OXYGEN_GPIO_DATA) & bit);
-       return 0;
-}
-
-static int gpio_bit_switch_put(struct snd_kcontrol *ctl,
-                              struct snd_ctl_elem_value *value)
-{
-       struct oxygen *chip = ctl->private_data;
-       u16 bit = ctl->private_value;
-       u16 old_bits, new_bits;
-       int changed;
-
-       spin_lock_irq(&chip->reg_lock);
-       old_bits = oxygen_read16(chip, OXYGEN_GPIO_DATA);
-       if (value->value.integer.value[0])
-               new_bits = old_bits | bit;
-       else
-               new_bits = old_bits & ~bit;
-       changed = new_bits != old_bits;
-       if (changed)
-               oxygen_write16(chip, OXYGEN_GPIO_DATA, new_bits);
-       spin_unlock_irq(&chip->reg_lock);
-       return changed;
-}
-
-static const struct snd_kcontrol_new alt_switch = {
-       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-       .name = "Analog Loopback Switch",
-       .info = snd_ctl_boolean_mono_info,
-       .get = gpio_bit_switch_get,
-       .put = gpio_bit_switch_put,
-       .private_value = GPIO_D2_ALT,
-};
-
-static const struct snd_kcontrol_new front_panel_switch = {
-       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-       .name = "Front Panel Switch",
-       .info = snd_ctl_boolean_mono_info,
-       .get = gpio_bit_switch_get,
-       .put = gpio_bit_switch_put,
-       .private_value = GPIO_DX_FRONT_PANEL,
-};
-
-static int st_output_switch_info(struct snd_kcontrol *ctl,
-                                struct snd_ctl_elem_info *info)
-{
-       static const char *const names[3] = {
-               "Speakers", "Headphones", "FP Headphones"
-       };
-
-       info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
-       info->count = 1;
-       info->value.enumerated.items = 3;
-       if (info->value.enumerated.item >= 3)
-               info->value.enumerated.item = 2;
-       strcpy(info->value.enumerated.name, names[info->value.enumerated.item]);
-       return 0;
-}
-
-static int st_output_switch_get(struct snd_kcontrol *ctl,
-                               struct snd_ctl_elem_value *value)
-{
-       struct oxygen *chip = ctl->private_data;
-       u16 gpio;
-
-       gpio = oxygen_read16(chip, OXYGEN_GPIO_DATA);
-       if (!(gpio & GPIO_ST_HP))
-               value->value.enumerated.item[0] = 0;
-       else if (gpio & GPIO_ST_HP_REAR)
-               value->value.enumerated.item[0] = 1;
-       else
-               value->value.enumerated.item[0] = 2;
-       return 0;
-}
-
-
-static int st_output_switch_put(struct snd_kcontrol *ctl,
-                               struct snd_ctl_elem_value *value)
-{
-       struct oxygen *chip = ctl->private_data;
-       u16 gpio_old, gpio;
-
-       mutex_lock(&chip->mutex);
-       gpio_old = oxygen_read16(chip, OXYGEN_GPIO_DATA);
-       gpio = gpio_old;
-       switch (value->value.enumerated.item[0]) {
-       case 0:
-               gpio &= ~(GPIO_ST_HP | GPIO_ST_HP_REAR);
-               break;
-       case 1:
-               gpio |= GPIO_ST_HP | GPIO_ST_HP_REAR;
-               break;
-       case 2:
-               gpio = (gpio | GPIO_ST_HP) & ~GPIO_ST_HP_REAR;
-               break;
-       }
-       oxygen_write16(chip, OXYGEN_GPIO_DATA, gpio);
-       mutex_unlock(&chip->mutex);
-       return gpio != gpio_old;
-}
-
-static const struct snd_kcontrol_new st_output_switch = {
-       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-       .name = "Analog Output",
-       .info = st_output_switch_info,
-       .get = st_output_switch_get,
-       .put = st_output_switch_put,
-};
-
-static void xonar_line_mic_ac97_switch(struct oxygen *chip,
-                                      unsigned int reg, unsigned int mute)
-{
-       if (reg == AC97_LINE) {
-               spin_lock_irq(&chip->reg_lock);
-               oxygen_write16_masked(chip, OXYGEN_GPIO_DATA,
-                                     mute ? GPIO_DX_INPUT_ROUTE : 0,
-                                     GPIO_DX_INPUT_ROUTE);
-               spin_unlock_irq(&chip->reg_lock);
-       }
-}
-
-static const DECLARE_TLV_DB_SCALE(pcm1796_db_scale, -6000, 50, 0);
-static const DECLARE_TLV_DB_SCALE(cs4362a_db_scale, -6000, 100, 0);
-
-static int xonar_d2_control_filter(struct snd_kcontrol_new *template)
-{
-       if (!strncmp(template->name, "CD Capture ", 11))
-               /* CD in is actually connected to the video in pin */
-               template->private_value ^= AC97_CD ^ AC97_VIDEO;
-       return 0;
-}
-
-static int xonar_d1_control_filter(struct snd_kcontrol_new *template)
-{
-       if (!strncmp(template->name, "CD Capture ", 11))
-               return 1; /* no CD input */
-       return 0;
-}
-
-static int xonar_st_control_filter(struct snd_kcontrol_new *template)
-{
-       if (!strncmp(template->name, "CD Capture ", 11))
-               return 1; /* no CD input */
-       if (!strcmp(template->name, "Stereo Upmixing"))
-               return 1; /* stereo only - we don't need upmixing */
-       return 0;
-}
-
-static int xonar_d2_mixer_init(struct oxygen *chip)
-{
-       return snd_ctl_add(chip->card, snd_ctl_new1(&alt_switch, chip));
-}
-
-static int xonar_d1_mixer_init(struct oxygen *chip)
-{
-       return snd_ctl_add(chip->card, snd_ctl_new1(&front_panel_switch, chip));
-}
-
-static int xonar_st_mixer_init(struct oxygen *chip)
-{
-       return snd_ctl_add(chip->card, snd_ctl_new1(&st_output_switch, chip));
-}
-
-static const struct oxygen_model model_xonar_d2 = {
-       .longname = "Asus Virtuoso 200",
-       .chip = "AV200",
-       .init = xonar_d2_init,
-       .control_filter = xonar_d2_control_filter,
-       .mixer_init = xonar_d2_mixer_init,
-       .cleanup = xonar_d2_cleanup,
-       .suspend = xonar_d2_suspend,
-       .resume = xonar_d2_resume,
-       .set_dac_params = set_pcm1796_params,
-       .set_adc_params = set_cs53x1_params,
-       .update_dac_volume = update_pcm1796_volume,
-       .update_dac_mute = update_pcm1796_mute,
-       .dac_tlv = pcm1796_db_scale,
-       .model_data_size = sizeof(struct xonar_data),
-       .device_config = PLAYBACK_0_TO_I2S |
-                        PLAYBACK_1_TO_SPDIF |
-                        CAPTURE_0_FROM_I2S_2 |
-                        CAPTURE_1_FROM_SPDIF |
-                        MIDI_OUTPUT |
-                        MIDI_INPUT,
-       .dac_channels = 8,
-       .dac_volume_min = 255 - 2*60,
-       .dac_volume_max = 255,
-       .misc_flags = OXYGEN_MISC_MIDI,
-       .function_flags = OXYGEN_FUNCTION_SPI |
-                         OXYGEN_FUNCTION_ENABLE_SPI_4_5,
-       .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
-       .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
-};
-
-static const struct oxygen_model model_xonar_d1 = {
-       .longname = "Asus Virtuoso 100",
-       .chip = "AV200",
-       .init = xonar_d1_init,
-       .control_filter = xonar_d1_control_filter,
-       .mixer_init = xonar_d1_mixer_init,
-       .cleanup = xonar_d1_cleanup,
-       .suspend = xonar_d1_suspend,
-       .resume = xonar_d1_resume,
-       .set_dac_params = set_cs43xx_params,
-       .set_adc_params = set_cs53x1_params,
-       .update_dac_volume = update_cs43xx_volume,
-       .update_dac_mute = update_cs43xx_mute,
-       .ac97_switch = xonar_line_mic_ac97_switch,
-       .dac_tlv = cs4362a_db_scale,
-       .model_data_size = sizeof(struct xonar_data),
-       .device_config = PLAYBACK_0_TO_I2S |
-                        PLAYBACK_1_TO_SPDIF |
-                        CAPTURE_0_FROM_I2S_2,
-       .dac_channels = 8,
-       .dac_volume_min = 127 - 60,
-       .dac_volume_max = 127,
-       .function_flags = OXYGEN_FUNCTION_2WIRE,
-       .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
-       .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
-};
-
-static const struct oxygen_model model_xonar_hdav = {
-       .longname = "Asus Virtuoso 200",
-       .chip = "AV200",
-       .init = xonar_hdav_init,
-       .cleanup = xonar_hdav_cleanup,
-       .suspend = xonar_hdav_suspend,
-       .resume = xonar_hdav_resume,
-       .pcm_hardware_filter = xonar_hdav_pcm_hardware_filter,
-       .set_dac_params = set_hdav_params,
-       .set_adc_params = set_cs53x1_params,
-       .update_dac_volume = update_pcm1796_volume,
-       .update_dac_mute = update_pcm1796_mute,
-       .uart_input = xonar_hdav_uart_input,
-       .ac97_switch = xonar_line_mic_ac97_switch,
-       .dac_tlv = pcm1796_db_scale,
-       .model_data_size = sizeof(struct xonar_data),
-       .device_config = PLAYBACK_0_TO_I2S |
-                        PLAYBACK_1_TO_SPDIF |
-                        CAPTURE_0_FROM_I2S_2 |
-                        CAPTURE_1_FROM_SPDIF,
-       .dac_channels = 8,
-       .dac_volume_min = 255 - 2*60,
-       .dac_volume_max = 255,
-       .misc_flags = OXYGEN_MISC_MIDI,
-       .function_flags = OXYGEN_FUNCTION_2WIRE,
-       .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
-       .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
-};
-
-static const struct oxygen_model model_xonar_st = {
-       .longname = "Asus Virtuoso 100",
-       .chip = "AV200",
-       .init = xonar_st_init,
-       .control_filter = xonar_st_control_filter,
-       .mixer_init = xonar_st_mixer_init,
-       .cleanup = xonar_st_cleanup,
-       .suspend = xonar_st_suspend,
-       .resume = xonar_st_resume,
-       .set_dac_params = set_pcm1796_params,
-       .set_adc_params = set_cs53x1_params,
-       .update_dac_volume = update_pcm1796_volume,
-       .update_dac_mute = update_pcm1796_mute,
-       .ac97_switch = xonar_line_mic_ac97_switch,
-       .dac_tlv = pcm1796_db_scale,
-       .model_data_size = sizeof(struct xonar_data),
-       .device_config = PLAYBACK_0_TO_I2S |
-                        PLAYBACK_1_TO_SPDIF |
-                        CAPTURE_0_FROM_I2S_2,
-       .dac_channels = 2,
-       .dac_volume_min = 255 - 2*60,
-       .dac_volume_max = 255,
-       .function_flags = OXYGEN_FUNCTION_2WIRE,
-       .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
-       .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
-};
-
 static int __devinit get_xonar_model(struct oxygen *chip,
                                     const struct pci_device_id *id)
 {
-       static const struct oxygen_model *const models[] = {
-               [MODEL_D1]      = &model_xonar_d1,
-               [MODEL_DX]      = &model_xonar_d1,
-               [MODEL_D2]      = &model_xonar_d2,
-               [MODEL_D2X]     = &model_xonar_d2,
-               [MODEL_HDAV]    = &model_xonar_hdav,
-               [MODEL_ST]      = &model_xonar_st,
-               [MODEL_STX]     = &model_xonar_st,
-       };
-       static const char *const names[] = {
-               [MODEL_D1]      = "Xonar D1",
-               [MODEL_DX]      = "Xonar DX",
-               [MODEL_D2]      = "Xonar D2",
-               [MODEL_D2X]     = "Xonar D2X",
-               [MODEL_HDAV]    = "Xonar HDAV1.3",
-               [MODEL_HDAV_H6] = "Xonar HDAV1.3+H6",
-               [MODEL_ST]      = "Xonar Essence ST",
-               [MODEL_ST_H6]   = "Xonar Essence ST+H6",
-               [MODEL_STX]     = "Xonar Essence STX",
-       };
-       unsigned int model = id->driver_data;
-
-       if (model >= ARRAY_SIZE(models) || !models[model])
-               return -EINVAL;
-       chip->model = *models[model];
-
-       switch (model) {
-       case MODEL_D2X:
-               chip->model.init = xonar_d2x_init;
-               break;
-       case MODEL_DX:
-               chip->model.init = xonar_dx_init;
-               break;
-       case MODEL_HDAV:
-               oxygen_clear_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_DB_MASK);
-               switch (oxygen_read16(chip, OXYGEN_GPIO_DATA) & GPIO_DB_MASK) {
-               case GPIO_DB_H6:
-                       model = MODEL_HDAV_H6;
-                       break;
-               case GPIO_DB_XX:
-                       snd_printk(KERN_ERR "unknown daughterboard\n");
-                       return -ENODEV;
-               }
-               break;
-       case MODEL_ST:
-               oxygen_clear_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_DB_MASK);
-               switch (oxygen_read16(chip, OXYGEN_GPIO_DATA) & GPIO_DB_MASK) {
-               case GPIO_DB_H6:
-                       model = MODEL_ST_H6;
-                       break;
-               }
-               break;
-       case MODEL_STX:
-               chip->model.init = xonar_stx_init;
-               oxygen_clear_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_DB_MASK);
-               break;
-       }
-
-       chip->model.shortname = names[model];
-       chip->model.private_data = model;
-       return 0;
+       if (get_xonar_pcm179x_model(chip, id) >= 0)
+               return 0;
+       if (get_xonar_cs43xx_model(chip, id) >= 0)
+               return 0;
+       return -EINVAL;
 }
 
 static int __devinit xonar_probe(struct pci_dev *pci,
diff --git a/sound/pci/oxygen/xonar.h b/sound/pci/oxygen/xonar.h
new file mode 100644 (file)
index 0000000..89b3ed8
--- /dev/null
@@ -0,0 +1,50 @@
+#ifndef XONAR_H_INCLUDED
+#define XONAR_H_INCLUDED
+
+#include "oxygen.h"
+
+struct xonar_generic {
+       unsigned int anti_pop_delay;
+       u16 output_enable_bit;
+       u8 ext_power_reg;
+       u8 ext_power_int_reg;
+       u8 ext_power_bit;
+       u8 has_power;
+};
+
+struct xonar_hdmi {
+       u8 params[5];
+};
+
+/* generic helper functions */
+
+void xonar_enable_output(struct oxygen *chip);
+void xonar_disable_output(struct oxygen *chip);
+void xonar_init_ext_power(struct oxygen *chip);
+void xonar_init_cs53x1(struct oxygen *chip);
+void xonar_set_cs53x1_params(struct oxygen *chip,
+                            struct snd_pcm_hw_params *params);
+int xonar_gpio_bit_switch_get(struct snd_kcontrol *ctl,
+                             struct snd_ctl_elem_value *value);
+int xonar_gpio_bit_switch_put(struct snd_kcontrol *ctl,
+                             struct snd_ctl_elem_value *value);
+
+/* model-specific card drivers */
+
+int get_xonar_pcm179x_model(struct oxygen *chip,
+                           const struct pci_device_id *id);
+int get_xonar_cs43xx_model(struct oxygen *chip,
+                          const struct pci_device_id *id);
+
+/* HDMI helper functions */
+
+void xonar_hdmi_init(struct oxygen *chip, struct xonar_hdmi *data);
+void xonar_hdmi_cleanup(struct oxygen *chip);
+void xonar_hdmi_resume(struct oxygen *chip, struct xonar_hdmi *hdmi);
+void xonar_hdmi_pcm_hardware_filter(unsigned int channel,
+                                   struct snd_pcm_hardware *hardware);
+void xonar_set_hdmi_params(struct oxygen *chip, struct xonar_hdmi *hdmi,
+                          struct snd_pcm_hw_params *params);
+void xonar_hdmi_uart_input(struct oxygen *chip);
+
+#endif
diff --git a/sound/pci/oxygen/xonar_cs43xx.c b/sound/pci/oxygen/xonar_cs43xx.c
new file mode 100644 (file)
index 0000000..16c226b
--- /dev/null
@@ -0,0 +1,434 @@
+/*
+ * card driver for models with CS4398/CS4362A DACs (Xonar D1/DX)
+ *
+ * Copyright (c) Clemens Ladisch <clemens@ladisch.de>
+ *
+ *
+ *  This driver is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License, version 2.
+ *
+ *  This driver 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 driver; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * Xonar D1/DX
+ * -----------
+ *
+ * CMI8788:
+ *
+ * I²C <-> CS4398 (front)
+ *     <-> CS4362A (surround, center/LFE, back)
+ *
+ * GPI 0 <- external power present (DX only)
+ *
+ * GPIO 0 -> enable output to speakers
+ * GPIO 1 -> enable front panel I/O
+ * GPIO 2 -> M0 of CS5361
+ * GPIO 3 -> M1 of CS5361
+ * GPIO 8 -> route input jack to line-in (0) or mic-in (1)
+ *
+ * CS4398:
+ *
+ * AD0 <- 1
+ * AD1 <- 1
+ *
+ * CS4362A:
+ *
+ * AD0 <- 0
+ *
+ * CM9780:
+ *
+ * GPO 0 -> route line-in (0) or AC97 output (1) to CS5361 input
+ */
+
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <sound/ac97_codec.h>
+#include <sound/control.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/tlv.h>
+#include "xonar.h"
+#include "cs4398.h"
+#include "cs4362a.h"
+
+#define GPI_EXT_POWER          0x01
+#define GPIO_D1_OUTPUT_ENABLE  0x0001
+#define GPIO_D1_FRONT_PANEL    0x0002
+#define GPIO_D1_INPUT_ROUTE    0x0100
+
+#define I2C_DEVICE_CS4398      0x9e    /* 10011, AD1=1, AD0=1, /W=0 */
+#define I2C_DEVICE_CS4362A     0x30    /* 001100, AD0=0, /W=0 */
+
+struct xonar_cs43xx {
+       struct xonar_generic generic;
+       u8 cs4398_regs[8];
+       u8 cs4362a_regs[15];
+};
+
+static void cs4398_write(struct oxygen *chip, u8 reg, u8 value)
+{
+       struct xonar_cs43xx *data = chip->model_data;
+
+       oxygen_write_i2c(chip, I2C_DEVICE_CS4398, reg, value);
+       if (reg < ARRAY_SIZE(data->cs4398_regs))
+               data->cs4398_regs[reg] = value;
+}
+
+static void cs4398_write_cached(struct oxygen *chip, u8 reg, u8 value)
+{
+       struct xonar_cs43xx *data = chip->model_data;
+
+       if (value != data->cs4398_regs[reg])
+               cs4398_write(chip, reg, value);
+}
+
+static void cs4362a_write(struct oxygen *chip, u8 reg, u8 value)
+{
+       struct xonar_cs43xx *data = chip->model_data;
+
+       oxygen_write_i2c(chip, I2C_DEVICE_CS4362A, reg, value);
+       if (reg < ARRAY_SIZE(data->cs4362a_regs))
+               data->cs4362a_regs[reg] = value;
+}
+
+static void cs4362a_write_cached(struct oxygen *chip, u8 reg, u8 value)
+{
+       struct xonar_cs43xx *data = chip->model_data;
+
+       if (value != data->cs4362a_regs[reg])
+               cs4362a_write(chip, reg, value);
+}
+
+static void cs43xx_registers_init(struct oxygen *chip)
+{
+       struct xonar_cs43xx *data = chip->model_data;
+       unsigned int i;
+
+       /* set CPEN (control port mode) and power down */
+       cs4398_write(chip, 8, CS4398_CPEN | CS4398_PDN);
+       cs4362a_write(chip, 0x01, CS4362A_PDN | CS4362A_CPEN);
+       /* configure */
+       cs4398_write(chip, 2, data->cs4398_regs[2]);
+       cs4398_write(chip, 3, CS4398_ATAPI_B_R | CS4398_ATAPI_A_L);
+       cs4398_write(chip, 4, data->cs4398_regs[4]);
+       cs4398_write(chip, 5, data->cs4398_regs[5]);
+       cs4398_write(chip, 6, data->cs4398_regs[6]);
+       cs4398_write(chip, 7, data->cs4398_regs[7]);
+       cs4362a_write(chip, 0x02, CS4362A_DIF_LJUST);
+       cs4362a_write(chip, 0x03, CS4362A_MUTEC_6 | CS4362A_AMUTE |
+                     CS4362A_RMP_UP | CS4362A_ZERO_CROSS | CS4362A_SOFT_RAMP);
+       cs4362a_write(chip, 0x04, data->cs4362a_regs[0x04]);
+       cs4362a_write(chip, 0x05, 0);
+       for (i = 6; i <= 14; ++i)
+               cs4362a_write(chip, i, data->cs4362a_regs[i]);
+       /* clear power down */
+       cs4398_write(chip, 8, CS4398_CPEN);
+       cs4362a_write(chip, 0x01, CS4362A_CPEN);
+}
+
+static void xonar_d1_init(struct oxygen *chip)
+{
+       struct xonar_cs43xx *data = chip->model_data;
+
+       data->generic.anti_pop_delay = 800;
+       data->generic.output_enable_bit = GPIO_D1_OUTPUT_ENABLE;
+       data->cs4398_regs[2] =
+               CS4398_FM_SINGLE | CS4398_DEM_NONE | CS4398_DIF_LJUST;
+       data->cs4398_regs[4] = CS4398_MUTEP_LOW |
+               CS4398_MUTE_B | CS4398_MUTE_A | CS4398_PAMUTE;
+       data->cs4398_regs[5] = 60 * 2;
+       data->cs4398_regs[6] = 60 * 2;
+       data->cs4398_regs[7] = CS4398_RMP_DN | CS4398_RMP_UP |
+               CS4398_ZERO_CROSS | CS4398_SOFT_RAMP;
+       data->cs4362a_regs[4] = CS4362A_RMP_DN | CS4362A_DEM_NONE;
+       data->cs4362a_regs[6] = CS4362A_FM_SINGLE |
+               CS4362A_ATAPI_B_R | CS4362A_ATAPI_A_L;
+       data->cs4362a_regs[7] = 60 | CS4362A_MUTE;
+       data->cs4362a_regs[8] = 60 | CS4362A_MUTE;
+       data->cs4362a_regs[9] = data->cs4362a_regs[6];
+       data->cs4362a_regs[10] = 60 | CS4362A_MUTE;
+       data->cs4362a_regs[11] = 60 | CS4362A_MUTE;
+       data->cs4362a_regs[12] = data->cs4362a_regs[6];
+       data->cs4362a_regs[13] = 60 | CS4362A_MUTE;
+       data->cs4362a_regs[14] = 60 | CS4362A_MUTE;
+
+       oxygen_write16(chip, OXYGEN_2WIRE_BUS_STATUS,
+                      OXYGEN_2WIRE_LENGTH_8 |
+                      OXYGEN_2WIRE_INTERRUPT_MASK |
+                      OXYGEN_2WIRE_SPEED_FAST);
+
+       cs43xx_registers_init(chip);
+
+       oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL,
+                         GPIO_D1_FRONT_PANEL | GPIO_D1_INPUT_ROUTE);
+       oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA,
+                           GPIO_D1_FRONT_PANEL | GPIO_D1_INPUT_ROUTE);
+
+       xonar_init_cs53x1(chip);
+       xonar_enable_output(chip);
+
+       snd_component_add(chip->card, "CS4398");
+       snd_component_add(chip->card, "CS4362A");
+       snd_component_add(chip->card, "CS5361");
+}
+
+static void xonar_dx_init(struct oxygen *chip)
+{
+       struct xonar_cs43xx *data = chip->model_data;
+
+       data->generic.ext_power_reg = OXYGEN_GPI_DATA;
+       data->generic.ext_power_int_reg = OXYGEN_GPI_INTERRUPT_MASK;
+       data->generic.ext_power_bit = GPI_EXT_POWER;
+       xonar_init_ext_power(chip);
+       xonar_d1_init(chip);
+}
+
+static void xonar_d1_cleanup(struct oxygen *chip)
+{
+       xonar_disable_output(chip);
+       cs4362a_write(chip, 0x01, CS4362A_PDN | CS4362A_CPEN);
+       oxygen_clear_bits8(chip, OXYGEN_FUNCTION, OXYGEN_FUNCTION_RESET_CODEC);
+}
+
+static void xonar_d1_suspend(struct oxygen *chip)
+{
+       xonar_d1_cleanup(chip);
+}
+
+static void xonar_d1_resume(struct oxygen *chip)
+{
+       oxygen_set_bits8(chip, OXYGEN_FUNCTION, OXYGEN_FUNCTION_RESET_CODEC);
+       msleep(1);
+       cs43xx_registers_init(chip);
+       xonar_enable_output(chip);
+}
+
+static void set_cs43xx_params(struct oxygen *chip,
+                             struct snd_pcm_hw_params *params)
+{
+       struct xonar_cs43xx *data = chip->model_data;
+       u8 cs4398_fm, cs4362a_fm;
+
+       if (params_rate(params) <= 50000) {
+               cs4398_fm = CS4398_FM_SINGLE;
+               cs4362a_fm = CS4362A_FM_SINGLE;
+       } else if (params_rate(params) <= 100000) {
+               cs4398_fm = CS4398_FM_DOUBLE;
+               cs4362a_fm = CS4362A_FM_DOUBLE;
+       } else {
+               cs4398_fm = CS4398_FM_QUAD;
+               cs4362a_fm = CS4362A_FM_QUAD;
+       }
+       cs4398_fm |= CS4398_DEM_NONE | CS4398_DIF_LJUST;
+       cs4398_write_cached(chip, 2, cs4398_fm);
+       cs4362a_fm |= data->cs4362a_regs[6] & ~CS4362A_FM_MASK;
+       cs4362a_write_cached(chip, 6, cs4362a_fm);
+       cs4362a_write_cached(chip, 12, cs4362a_fm);
+       cs4362a_fm &= CS4362A_FM_MASK;
+       cs4362a_fm |= data->cs4362a_regs[9] & ~CS4362A_FM_MASK;
+       cs4362a_write_cached(chip, 9, cs4362a_fm);
+}
+
+static void update_cs4362a_volumes(struct oxygen *chip)
+{
+       unsigned int i;
+       u8 mute;
+
+       mute = chip->dac_mute ? CS4362A_MUTE : 0;
+       for (i = 0; i < 6; ++i)
+               cs4362a_write_cached(chip, 7 + i + i / 2,
+                                    (127 - chip->dac_volume[2 + i]) | mute);
+}
+
+static void update_cs43xx_volume(struct oxygen *chip)
+{
+       cs4398_write_cached(chip, 5, (127 - chip->dac_volume[0]) * 2);
+       cs4398_write_cached(chip, 6, (127 - chip->dac_volume[1]) * 2);
+       update_cs4362a_volumes(chip);
+}
+
+static void update_cs43xx_mute(struct oxygen *chip)
+{
+       u8 reg;
+
+       reg = CS4398_MUTEP_LOW | CS4398_PAMUTE;
+       if (chip->dac_mute)
+               reg |= CS4398_MUTE_B | CS4398_MUTE_A;
+       cs4398_write_cached(chip, 4, reg);
+       update_cs4362a_volumes(chip);
+}
+
+static void update_cs43xx_center_lfe_mix(struct oxygen *chip, bool mixed)
+{
+       struct xonar_cs43xx *data = chip->model_data;
+       u8 reg;
+
+       reg = data->cs4362a_regs[9] & ~CS4362A_ATAPI_MASK;
+       if (mixed)
+               reg |= CS4362A_ATAPI_B_LR | CS4362A_ATAPI_A_LR;
+       else
+               reg |= CS4362A_ATAPI_B_R | CS4362A_ATAPI_A_L;
+       cs4362a_write_cached(chip, 9, reg);
+}
+
+static const struct snd_kcontrol_new front_panel_switch = {
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       .name = "Front Panel Switch",
+       .info = snd_ctl_boolean_mono_info,
+       .get = xonar_gpio_bit_switch_get,
+       .put = xonar_gpio_bit_switch_put,
+       .private_value = GPIO_D1_FRONT_PANEL,
+};
+
+static int rolloff_info(struct snd_kcontrol *ctl,
+                       struct snd_ctl_elem_info *info)
+{
+       static const char *const names[2] = {
+               "Fast Roll-off", "Slow Roll-off"
+       };
+
+       info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+       info->count = 1;
+       info->value.enumerated.items = 2;
+       if (info->value.enumerated.item >= 2)
+               info->value.enumerated.item = 1;
+       strcpy(info->value.enumerated.name, names[info->value.enumerated.item]);
+       return 0;
+}
+
+static int rolloff_get(struct snd_kcontrol *ctl,
+                      struct snd_ctl_elem_value *value)
+{
+       struct oxygen *chip = ctl->private_data;
+       struct xonar_cs43xx *data = chip->model_data;
+
+       value->value.enumerated.item[0] =
+               (data->cs4398_regs[7] & CS4398_FILT_SEL) != 0;
+       return 0;
+}
+
+static int rolloff_put(struct snd_kcontrol *ctl,
+                      struct snd_ctl_elem_value *value)
+{
+       struct oxygen *chip = ctl->private_data;
+       struct xonar_cs43xx *data = chip->model_data;
+       int changed;
+       u8 reg;
+
+       mutex_lock(&chip->mutex);
+       reg = data->cs4398_regs[7];
+       if (value->value.enumerated.item[0])
+               reg |= CS4398_FILT_SEL;
+       else
+               reg &= ~CS4398_FILT_SEL;
+       changed = reg != data->cs4398_regs[7];
+       if (changed) {
+               cs4398_write(chip, 7, reg);
+               if (reg & CS4398_FILT_SEL)
+                       reg = data->cs4362a_regs[0x04] | CS4362A_FILT_SEL;
+               else
+                       reg = data->cs4362a_regs[0x04] & ~CS4362A_FILT_SEL;
+               cs4362a_write(chip, 0x04, reg);
+       }
+       mutex_unlock(&chip->mutex);
+       return changed;
+}
+
+static const struct snd_kcontrol_new rolloff_control = {
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       .name = "DAC Filter Playback Enum",
+       .info = rolloff_info,
+       .get = rolloff_get,
+       .put = rolloff_put,
+};
+
+static void xonar_d1_line_mic_ac97_switch(struct oxygen *chip,
+                                         unsigned int reg, unsigned int mute)
+{
+       if (reg == AC97_LINE) {
+               spin_lock_irq(&chip->reg_lock);
+               oxygen_write16_masked(chip, OXYGEN_GPIO_DATA,
+                                     mute ? GPIO_D1_INPUT_ROUTE : 0,
+                                     GPIO_D1_INPUT_ROUTE);
+               spin_unlock_irq(&chip->reg_lock);
+       }
+}
+
+static const DECLARE_TLV_DB_SCALE(cs4362a_db_scale, -6000, 100, 0);
+
+static int xonar_d1_control_filter(struct snd_kcontrol_new *template)
+{
+       if (!strncmp(template->name, "CD Capture ", 11))
+               return 1; /* no CD input */
+       return 0;
+}
+
+static int xonar_d1_mixer_init(struct oxygen *chip)
+{
+       int err;
+
+       err = snd_ctl_add(chip->card, snd_ctl_new1(&front_panel_switch, chip));
+       if (err < 0)
+               return err;
+       err = snd_ctl_add(chip->card, snd_ctl_new1(&rolloff_control, chip));
+       if (err < 0)
+               return err;
+       return 0;
+}
+
+static const struct oxygen_model model_xonar_d1 = {
+       .longname = "Asus Virtuoso 100",
+       .chip = "AV200",
+       .init = xonar_d1_init,
+       .control_filter = xonar_d1_control_filter,
+       .mixer_init = xonar_d1_mixer_init,
+       .cleanup = xonar_d1_cleanup,
+       .suspend = xonar_d1_suspend,
+       .resume = xonar_d1_resume,
+       .get_i2s_mclk = oxygen_default_i2s_mclk,
+       .set_dac_params = set_cs43xx_params,
+       .set_adc_params = xonar_set_cs53x1_params,
+       .update_dac_volume = update_cs43xx_volume,
+       .update_dac_mute = update_cs43xx_mute,
+       .update_center_lfe_mix = update_cs43xx_center_lfe_mix,
+       .ac97_switch = xonar_d1_line_mic_ac97_switch,
+       .dac_tlv = cs4362a_db_scale,
+       .model_data_size = sizeof(struct xonar_cs43xx),
+       .device_config = PLAYBACK_0_TO_I2S |
+                        PLAYBACK_1_TO_SPDIF |
+                        CAPTURE_0_FROM_I2S_2,
+       .dac_channels = 8,
+       .dac_volume_min = 127 - 60,
+       .dac_volume_max = 127,
+       .function_flags = OXYGEN_FUNCTION_2WIRE,
+       .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
+       .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
+};
+
+int __devinit get_xonar_cs43xx_model(struct oxygen *chip,
+                                    const struct pci_device_id *id)
+{
+       switch (id->subdevice) {
+       case 0x834f:
+               chip->model = model_xonar_d1;
+               chip->model.shortname = "Xonar D1";
+               break;
+       case 0x8275:
+       case 0x8327:
+               chip->model = model_xonar_d1;
+               chip->model.shortname = "Xonar DX";
+               chip->model.init = xonar_dx_init;
+               break;
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
diff --git a/sound/pci/oxygen/xonar_hdmi.c b/sound/pci/oxygen/xonar_hdmi.c
new file mode 100644 (file)
index 0000000..b12db1f
--- /dev/null
@@ -0,0 +1,128 @@
+/*
+ * helper functions for HDMI models (Xonar HDAV1.3)
+ *
+ * Copyright (c) Clemens Ladisch <clemens@ladisch.de>
+ *
+ *
+ *  This driver is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License, version 2.
+ *
+ *  This driver 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 driver; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <sound/asoundef.h>
+#include <sound/control.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/tlv.h>
+#include "xonar.h"
+
+static void hdmi_write_command(struct oxygen *chip, u8 command,
+                              unsigned int count, const u8 *params)
+{
+       unsigned int i;
+       u8 checksum;
+
+       oxygen_write_uart(chip, 0xfb);
+       oxygen_write_uart(chip, 0xef);
+       oxygen_write_uart(chip, command);
+       oxygen_write_uart(chip, count);
+       for (i = 0; i < count; ++i)
+               oxygen_write_uart(chip, params[i]);
+       checksum = 0xfb + 0xef + command + count;
+       for (i = 0; i < count; ++i)
+               checksum += params[i];
+       oxygen_write_uart(chip, checksum);
+}
+
+static void xonar_hdmi_init_commands(struct oxygen *chip,
+                                    struct xonar_hdmi *hdmi)
+{
+       u8 param;
+
+       oxygen_reset_uart(chip);
+       param = 0;
+       hdmi_write_command(chip, 0x61, 1, &param);
+       param = 1;
+       hdmi_write_command(chip, 0x74, 1, &param);
+       hdmi_write_command(chip, 0x54, 5, hdmi->params);
+}
+
+void xonar_hdmi_init(struct oxygen *chip, struct xonar_hdmi *hdmi)
+{
+       hdmi->params[1] = IEC958_AES3_CON_FS_48000;
+       hdmi->params[4] = 1;
+       xonar_hdmi_init_commands(chip, hdmi);
+}
+
+void xonar_hdmi_cleanup(struct oxygen *chip)
+{
+       u8 param = 0;
+
+       hdmi_write_command(chip, 0x74, 1, &param);
+}
+
+void xonar_hdmi_resume(struct oxygen *chip, struct xonar_hdmi *hdmi)
+{
+       xonar_hdmi_init_commands(chip, hdmi);
+}
+
+void xonar_hdmi_pcm_hardware_filter(unsigned int channel,
+                                   struct snd_pcm_hardware *hardware)
+{
+       if (channel == PCM_MULTICH) {
+               hardware->rates = SNDRV_PCM_RATE_44100 |
+                                 SNDRV_PCM_RATE_48000 |
+                                 SNDRV_PCM_RATE_96000 |
+                                 SNDRV_PCM_RATE_192000;
+               hardware->rate_min = 44100;
+       }
+}
+
+void xonar_set_hdmi_params(struct oxygen *chip, struct xonar_hdmi *hdmi,
+                          struct snd_pcm_hw_params *params)
+{
+       hdmi->params[0] = 0; /* 1 = non-audio */
+       switch (params_rate(params)) {
+       case 44100:
+               hdmi->params[1] = IEC958_AES3_CON_FS_44100;
+               break;
+       case 48000:
+               hdmi->params[1] = IEC958_AES3_CON_FS_48000;
+               break;
+       default: /* 96000 */
+               hdmi->params[1] = IEC958_AES3_CON_FS_96000;
+               break;
+       case 192000:
+               hdmi->params[1] = IEC958_AES3_CON_FS_192000;
+               break;
+       }
+       hdmi->params[2] = params_channels(params) / 2 - 1;
+       if (params_format(params) == SNDRV_PCM_FORMAT_S16_LE)
+               hdmi->params[3] = 0;
+       else
+               hdmi->params[3] = 0xc0;
+       hdmi->params[4] = 1; /* ? */
+       hdmi_write_command(chip, 0x54, 5, hdmi->params);
+}
+
+void xonar_hdmi_uart_input(struct oxygen *chip)
+{
+       if (chip->uart_input_count >= 2 &&
+           chip->uart_input[chip->uart_input_count - 2] == 'O' &&
+           chip->uart_input[chip->uart_input_count - 1] == 'K') {
+               printk(KERN_DEBUG "message from HDMI chip received:\n");
+               print_hex_dump_bytes("", DUMP_PREFIX_OFFSET,
+                                    chip->uart_input, chip->uart_input_count);
+               chip->uart_input_count = 0;
+       }
+}
diff --git a/sound/pci/oxygen/xonar_lib.c b/sound/pci/oxygen/xonar_lib.c
new file mode 100644 (file)
index 0000000..b3ff713
--- /dev/null
@@ -0,0 +1,132 @@
+/*
+ * helper functions for Asus Xonar cards
+ *
+ * Copyright (c) Clemens Ladisch <clemens@ladisch.de>
+ *
+ *
+ *  This driver is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License, version 2.
+ *
+ *  This driver 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 driver; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/delay.h>
+#include <sound/core.h>
+#include <sound/control.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include "xonar.h"
+
+
+#define GPIO_CS53x1_M_MASK     0x000c
+#define GPIO_CS53x1_M_SINGLE   0x0000
+#define GPIO_CS53x1_M_DOUBLE   0x0004
+#define GPIO_CS53x1_M_QUAD     0x0008
+
+
+void xonar_enable_output(struct oxygen *chip)
+{
+       struct xonar_generic *data = chip->model_data;
+
+       oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, data->output_enable_bit);
+       msleep(data->anti_pop_delay);
+       oxygen_set_bits16(chip, OXYGEN_GPIO_DATA, data->output_enable_bit);
+}
+
+void xonar_disable_output(struct oxygen *chip)
+{
+       struct xonar_generic *data = chip->model_data;
+
+       oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, data->output_enable_bit);
+}
+
+static void xonar_ext_power_gpio_changed(struct oxygen *chip)
+{
+       struct xonar_generic *data = chip->model_data;
+       u8 has_power;
+
+       has_power = !!(oxygen_read8(chip, data->ext_power_reg)
+                      & data->ext_power_bit);
+       if (has_power != data->has_power) {
+               data->has_power = has_power;
+               if (has_power) {
+                       snd_printk(KERN_NOTICE "power restored\n");
+               } else {
+                       snd_printk(KERN_CRIT
+                                  "Hey! Don't unplug the power cable!\n");
+                       /* TODO: stop PCMs */
+               }
+       }
+}
+
+void xonar_init_ext_power(struct oxygen *chip)
+{
+       struct xonar_generic *data = chip->model_data;
+
+       oxygen_set_bits8(chip, data->ext_power_int_reg,
+                        data->ext_power_bit);
+       chip->interrupt_mask |= OXYGEN_INT_GPIO;
+       chip->model.gpio_changed = xonar_ext_power_gpio_changed;
+       data->has_power = !!(oxygen_read8(chip, data->ext_power_reg)
+                            & data->ext_power_bit);
+}
+
+void xonar_init_cs53x1(struct oxygen *chip)
+{
+       oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_CS53x1_M_MASK);
+       oxygen_write16_masked(chip, OXYGEN_GPIO_DATA,
+                             GPIO_CS53x1_M_SINGLE, GPIO_CS53x1_M_MASK);
+}
+
+void xonar_set_cs53x1_params(struct oxygen *chip,
+                            struct snd_pcm_hw_params *params)
+{
+       unsigned int value;
+
+       if (params_rate(params) <= 54000)
+               value = GPIO_CS53x1_M_SINGLE;
+       else if (params_rate(params) <= 108000)
+               value = GPIO_CS53x1_M_DOUBLE;
+       else
+               value = GPIO_CS53x1_M_QUAD;
+       oxygen_write16_masked(chip, OXYGEN_GPIO_DATA,
+                             value, GPIO_CS53x1_M_MASK);
+}
+
+int xonar_gpio_bit_switch_get(struct snd_kcontrol *ctl,
+                             struct snd_ctl_elem_value *value)
+{
+       struct oxygen *chip = ctl->private_data;
+       u16 bit = ctl->private_value;
+
+       value->value.integer.value[0] =
+               !!(oxygen_read16(chip, OXYGEN_GPIO_DATA) & bit);
+       return 0;
+}
+
+int xonar_gpio_bit_switch_put(struct snd_kcontrol *ctl,
+                             struct snd_ctl_elem_value *value)
+{
+       struct oxygen *chip = ctl->private_data;
+       u16 bit = ctl->private_value;
+       u16 old_bits, new_bits;
+       int changed;
+
+       spin_lock_irq(&chip->reg_lock);
+       old_bits = oxygen_read16(chip, OXYGEN_GPIO_DATA);
+       if (value->value.integer.value[0])
+               new_bits = old_bits | bit;
+       else
+               new_bits = old_bits & ~bit;
+       changed = new_bits != old_bits;
+       if (changed)
+               oxygen_write16(chip, OXYGEN_GPIO_DATA, new_bits);
+       spin_unlock_irq(&chip->reg_lock);
+       return changed;
+}
diff --git a/sound/pci/oxygen/xonar_pcm179x.c b/sound/pci/oxygen/xonar_pcm179x.c
new file mode 100644 (file)
index 0000000..ba18fb5
--- /dev/null
@@ -0,0 +1,1115 @@
+/*
+ * card driver for models with PCM1796 DACs (Xonar D2/D2X/HDAV1.3/ST/STX)
+ *
+ * Copyright (c) Clemens Ladisch <clemens@ladisch.de>
+ *
+ *
+ *  This driver is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License, version 2.
+ *
+ *  This driver 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 driver; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * Xonar D2/D2X
+ * ------------
+ *
+ * CMI8788:
+ *
+ * SPI 0 -> 1st PCM1796 (front)
+ * SPI 1 -> 2nd PCM1796 (surround)
+ * SPI 2 -> 3rd PCM1796 (center/LFE)
+ * SPI 4 -> 4th PCM1796 (back)
+ *
+ * GPIO 2 -> M0 of CS5381
+ * GPIO 3 -> M1 of CS5381
+ * GPIO 5 <- external power present (D2X only)
+ * GPIO 7 -> ALT
+ * GPIO 8 -> enable output to speakers
+ *
+ * CM9780:
+ *
+ * GPO 0 -> route line-in (0) or AC97 output (1) to CS5381 input
+ */
+
+/*
+ * Xonar HDAV1.3 (Deluxe)
+ * ----------------------
+ *
+ * CMI8788:
+ *
+ * I²C <-> PCM1796 (front)
+ *
+ * GPI 0 <- external power present
+ *
+ * GPIO 0 -> enable output to speakers
+ * GPIO 2 -> M0 of CS5381
+ * GPIO 3 -> M1 of CS5381
+ * GPIO 8 -> route input jack to line-in (0) or mic-in (1)
+ *
+ * TXD -> HDMI controller
+ * RXD <- HDMI controller
+ *
+ * PCM1796 front: AD1,0 <- 0,0
+ *
+ * CM9780:
+ *
+ * GPO 0 -> route line-in (0) or AC97 output (1) to CS5381 input
+ *
+ * no daughterboard
+ * ----------------
+ *
+ * GPIO 4 <- 1
+ *
+ * H6 daughterboard
+ * ----------------
+ *
+ * GPIO 4 <- 0
+ * GPIO 5 <- 0
+ *
+ * I²C <-> PCM1796 (surround)
+ *     <-> PCM1796 (center/LFE)
+ *     <-> PCM1796 (back)
+ *
+ * PCM1796 surround:   AD1,0 <- 0,1
+ * PCM1796 center/LFE: AD1,0 <- 1,0
+ * PCM1796 back:       AD1,0 <- 1,1
+ *
+ * unknown daughterboard
+ * ---------------------
+ *
+ * GPIO 4 <- 0
+ * GPIO 5 <- 1
+ *
+ * I²C <-> CS4362A (surround, center/LFE, back)
+ *
+ * CS4362A: AD0 <- 0
+ */
+
+/*
+ * Xonar Essence ST (Deluxe)/STX
+ * -----------------------------
+ *
+ * CMI8788:
+ *
+ * I²C <-> PCM1792A
+ *     <-> CS2000 (ST only)
+ *
+ * ADC1 MCLK -> REF_CLK of CS2000 (ST only)
+ *
+ * GPI 0 <- external power present (STX only)
+ *
+ * GPIO 0 -> enable output to speakers
+ * GPIO 1 -> route HP to front panel (0) or rear jack (1)
+ * GPIO 2 -> M0 of CS5381
+ * GPIO 3 -> M1 of CS5381
+ * GPIO 7 -> route output to speaker jacks (0) or HP (1)
+ * GPIO 8 -> route input jack to line-in (0) or mic-in (1)
+ *
+ * PCM1792A:
+ *
+ * AD1,0 <- 0,0
+ * SCK <- CLK_OUT of CS2000 (ST only)
+ *
+ * CS2000:
+ *
+ * AD0 <- 0
+ *
+ * CM9780:
+ *
+ * GPO 0 -> route line-in (0) or AC97 output (1) to CS5381 input
+ *
+ * H6 daughterboard
+ * ----------------
+ *
+ * GPIO 4 <- 0
+ * GPIO 5 <- 0
+ */
+
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/mutex.h>
+#include <sound/ac97_codec.h>
+#include <sound/control.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/tlv.h>
+#include "xonar.h"
+#include "cm9780.h"
+#include "pcm1796.h"
+#include "cs2000.h"
+
+
+#define GPIO_D2X_EXT_POWER     0x0020
+#define GPIO_D2_ALT            0x0080
+#define GPIO_D2_OUTPUT_ENABLE  0x0100
+
+#define GPI_EXT_POWER          0x01
+#define GPIO_INPUT_ROUTE       0x0100
+
+#define GPIO_HDAV_OUTPUT_ENABLE        0x0001
+
+#define GPIO_DB_MASK           0x0030
+#define GPIO_DB_H6             0x0000
+
+#define GPIO_ST_OUTPUT_ENABLE  0x0001
+#define GPIO_ST_HP_REAR                0x0002
+#define GPIO_ST_HP             0x0080
+
+#define I2C_DEVICE_PCM1796(i)  (0x98 + ((i) << 1))     /* 10011, ii, /W=0 */
+#define I2C_DEVICE_CS2000      0x9c                    /* 100111, 0, /W=0 */
+
+#define PCM1796_REG_BASE       16
+
+
+struct xonar_pcm179x {
+       struct xonar_generic generic;
+       unsigned int dacs;
+       u8 pcm1796_regs[4][5];
+       unsigned int current_rate;
+       bool os_128;
+       bool hp_active;
+       s8 hp_gain_offset;
+       bool has_cs2000;
+       u8 cs2000_fun_cfg_1;
+};
+
+struct xonar_hdav {
+       struct xonar_pcm179x pcm179x;
+       struct xonar_hdmi hdmi;
+};
+
+
+static inline void pcm1796_write_spi(struct oxygen *chip, unsigned int codec,
+                                    u8 reg, u8 value)
+{
+       /* maps ALSA channel pair number to SPI output */
+       static const u8 codec_map[4] = {
+               0, 1, 2, 4
+       };
+       oxygen_write_spi(chip, OXYGEN_SPI_TRIGGER  |
+                        OXYGEN_SPI_DATA_LENGTH_2 |
+                        OXYGEN_SPI_CLOCK_160 |
+                        (codec_map[codec] << OXYGEN_SPI_CODEC_SHIFT) |
+                        OXYGEN_SPI_CEN_LATCH_CLOCK_HI,
+                        (reg << 8) | value);
+}
+
+static inline void pcm1796_write_i2c(struct oxygen *chip, unsigned int codec,
+                                    u8 reg, u8 value)
+{
+       oxygen_write_i2c(chip, I2C_DEVICE_PCM1796(codec), reg, value);
+}
+
+static void pcm1796_write(struct oxygen *chip, unsigned int codec,
+                         u8 reg, u8 value)
+{
+       struct xonar_pcm179x *data = chip->model_data;
+
+       if ((chip->model.function_flags & OXYGEN_FUNCTION_2WIRE_SPI_MASK) ==
+           OXYGEN_FUNCTION_SPI)
+               pcm1796_write_spi(chip, codec, reg, value);
+       else
+               pcm1796_write_i2c(chip, codec, reg, value);
+       if ((unsigned int)(reg - PCM1796_REG_BASE)
+           < ARRAY_SIZE(data->pcm1796_regs[codec]))
+               data->pcm1796_regs[codec][reg - PCM1796_REG_BASE] = value;
+}
+
+static void pcm1796_write_cached(struct oxygen *chip, unsigned int codec,
+                                u8 reg, u8 value)
+{
+       struct xonar_pcm179x *data = chip->model_data;
+
+       if (value != data->pcm1796_regs[codec][reg - PCM1796_REG_BASE])
+               pcm1796_write(chip, codec, reg, value);
+}
+
+static void cs2000_write(struct oxygen *chip, u8 reg, u8 value)
+{
+       struct xonar_pcm179x *data = chip->model_data;
+
+       oxygen_write_i2c(chip, I2C_DEVICE_CS2000, reg, value);
+       if (reg == CS2000_FUN_CFG_1)
+               data->cs2000_fun_cfg_1 = value;
+}
+
+static void cs2000_write_cached(struct oxygen *chip, u8 reg, u8 value)
+{
+       struct xonar_pcm179x *data = chip->model_data;
+
+       if (reg != CS2000_FUN_CFG_1 ||
+           value != data->cs2000_fun_cfg_1)
+               cs2000_write(chip, reg, value);
+}
+
+static void pcm1796_registers_init(struct oxygen *chip)
+{
+       struct xonar_pcm179x *data = chip->model_data;
+       unsigned int i;
+       s8 gain_offset;
+
+       gain_offset = data->hp_active ? data->hp_gain_offset : 0;
+       for (i = 0; i < data->dacs; ++i) {
+               /* set ATLD before ATL/ATR */
+               pcm1796_write(chip, i, 18,
+                             data->pcm1796_regs[0][18 - PCM1796_REG_BASE]);
+               pcm1796_write(chip, i, 16, chip->dac_volume[i * 2]
+                             + gain_offset);
+               pcm1796_write(chip, i, 17, chip->dac_volume[i * 2 + 1]
+                             + gain_offset);
+               pcm1796_write(chip, i, 19,
+                             data->pcm1796_regs[0][19 - PCM1796_REG_BASE]);
+               pcm1796_write(chip, i, 20,
+                             data->pcm1796_regs[0][20 - PCM1796_REG_BASE]);
+               pcm1796_write(chip, i, 21, 0);
+       }
+}
+
+static void pcm1796_init(struct oxygen *chip)
+{
+       struct xonar_pcm179x *data = chip->model_data;
+
+       data->pcm1796_regs[0][18 - PCM1796_REG_BASE] = PCM1796_MUTE |
+               PCM1796_DMF_DISABLED | PCM1796_FMT_24_LJUST | PCM1796_ATLD;
+       data->pcm1796_regs[0][19 - PCM1796_REG_BASE] =
+               PCM1796_FLT_SHARP | PCM1796_ATS_1;
+       data->pcm1796_regs[0][20 - PCM1796_REG_BASE] = PCM1796_OS_64;
+       pcm1796_registers_init(chip);
+       data->current_rate = 48000;
+}
+
+static void xonar_d2_init(struct oxygen *chip)
+{
+       struct xonar_pcm179x *data = chip->model_data;
+
+       data->generic.anti_pop_delay = 300;
+       data->generic.output_enable_bit = GPIO_D2_OUTPUT_ENABLE;
+       data->dacs = 4;
+
+       pcm1796_init(chip);
+
+       oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_D2_ALT);
+       oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, GPIO_D2_ALT);
+
+       oxygen_ac97_set_bits(chip, 0, CM9780_JACK, CM9780_FMIC2MIC);
+
+       xonar_init_cs53x1(chip);
+       xonar_enable_output(chip);
+
+       snd_component_add(chip->card, "PCM1796");
+       snd_component_add(chip->card, "CS5381");
+}
+
+static void xonar_d2x_init(struct oxygen *chip)
+{
+       struct xonar_pcm179x *data = chip->model_data;
+
+       data->generic.ext_power_reg = OXYGEN_GPIO_DATA;
+       data->generic.ext_power_int_reg = OXYGEN_GPIO_INTERRUPT_MASK;
+       data->generic.ext_power_bit = GPIO_D2X_EXT_POWER;
+       oxygen_clear_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_D2X_EXT_POWER);
+       xonar_init_ext_power(chip);
+       xonar_d2_init(chip);
+}
+
+static void xonar_hdav_init(struct oxygen *chip)
+{
+       struct xonar_hdav *data = chip->model_data;
+
+       oxygen_write16(chip, OXYGEN_2WIRE_BUS_STATUS,
+                      OXYGEN_2WIRE_LENGTH_8 |
+                      OXYGEN_2WIRE_INTERRUPT_MASK |
+                      OXYGEN_2WIRE_SPEED_FAST);
+
+       data->pcm179x.generic.anti_pop_delay = 100;
+       data->pcm179x.generic.output_enable_bit = GPIO_HDAV_OUTPUT_ENABLE;
+       data->pcm179x.generic.ext_power_reg = OXYGEN_GPI_DATA;
+       data->pcm179x.generic.ext_power_int_reg = OXYGEN_GPI_INTERRUPT_MASK;
+       data->pcm179x.generic.ext_power_bit = GPI_EXT_POWER;
+       data->pcm179x.dacs = chip->model.private_data ? 4 : 1;
+
+       pcm1796_init(chip);
+
+       oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_INPUT_ROUTE);
+       oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, GPIO_INPUT_ROUTE);
+
+       xonar_init_cs53x1(chip);
+       xonar_init_ext_power(chip);
+       xonar_hdmi_init(chip, &data->hdmi);
+       xonar_enable_output(chip);
+
+       snd_component_add(chip->card, "PCM1796");
+       snd_component_add(chip->card, "CS5381");
+}
+
+static void xonar_st_init_i2c(struct oxygen *chip)
+{
+       oxygen_write16(chip, OXYGEN_2WIRE_BUS_STATUS,
+                      OXYGEN_2WIRE_LENGTH_8 |
+                      OXYGEN_2WIRE_INTERRUPT_MASK |
+                      OXYGEN_2WIRE_SPEED_FAST);
+}
+
+static void xonar_st_init_common(struct oxygen *chip)
+{
+       struct xonar_pcm179x *data = chip->model_data;
+
+       data->generic.anti_pop_delay = 100;
+       data->generic.output_enable_bit = GPIO_ST_OUTPUT_ENABLE;
+       data->dacs = chip->model.private_data ? 4 : 1;
+       data->hp_gain_offset = 2*-18;
+
+       pcm1796_init(chip);
+
+       oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL,
+                         GPIO_INPUT_ROUTE | GPIO_ST_HP_REAR | GPIO_ST_HP);
+       oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA,
+                           GPIO_INPUT_ROUTE | GPIO_ST_HP_REAR | GPIO_ST_HP);
+
+       xonar_init_cs53x1(chip);
+       xonar_enable_output(chip);
+
+       snd_component_add(chip->card, "PCM1792A");
+       snd_component_add(chip->card, "CS5381");
+}
+
+static void cs2000_registers_init(struct oxygen *chip)
+{
+       struct xonar_pcm179x *data = chip->model_data;
+
+       cs2000_write(chip, CS2000_GLOBAL_CFG, CS2000_FREEZE);
+       cs2000_write(chip, CS2000_DEV_CTRL, 0);
+       cs2000_write(chip, CS2000_DEV_CFG_1,
+                    CS2000_R_MOD_SEL_1 |
+                    (0 << CS2000_R_SEL_SHIFT) |
+                    CS2000_AUX_OUT_SRC_REF_CLK |
+                    CS2000_EN_DEV_CFG_1);
+       cs2000_write(chip, CS2000_DEV_CFG_2,
+                    (0 << CS2000_LOCK_CLK_SHIFT) |
+                    CS2000_FRAC_N_SRC_STATIC);
+       cs2000_write(chip, CS2000_RATIO_0 + 0, 0x00); /* 1.0 */
+       cs2000_write(chip, CS2000_RATIO_0 + 1, 0x10);
+       cs2000_write(chip, CS2000_RATIO_0 + 2, 0x00);
+       cs2000_write(chip, CS2000_RATIO_0 + 3, 0x00);
+       cs2000_write(chip, CS2000_FUN_CFG_1, data->cs2000_fun_cfg_1);
+       cs2000_write(chip, CS2000_FUN_CFG_2, 0);
+       cs2000_write(chip, CS2000_GLOBAL_CFG, CS2000_EN_DEV_CFG_2);
+}
+
+static void xonar_st_init(struct oxygen *chip)
+{
+       struct xonar_pcm179x *data = chip->model_data;
+
+       data->has_cs2000 = 1;
+       data->cs2000_fun_cfg_1 = CS2000_REF_CLK_DIV_1;
+
+       oxygen_write16(chip, OXYGEN_I2S_A_FORMAT,
+                      OXYGEN_RATE_48000 | OXYGEN_I2S_FORMAT_I2S |
+                      OXYGEN_I2S_MCLK_128 | OXYGEN_I2S_BITS_16 |
+                      OXYGEN_I2S_MASTER | OXYGEN_I2S_BCLK_64);
+
+       xonar_st_init_i2c(chip);
+       cs2000_registers_init(chip);
+       xonar_st_init_common(chip);
+
+       snd_component_add(chip->card, "CS2000");
+}
+
+static void xonar_stx_init(struct oxygen *chip)
+{
+       struct xonar_pcm179x *data = chip->model_data;
+
+       xonar_st_init_i2c(chip);
+       data->generic.ext_power_reg = OXYGEN_GPI_DATA;
+       data->generic.ext_power_int_reg = OXYGEN_GPI_INTERRUPT_MASK;
+       data->generic.ext_power_bit = GPI_EXT_POWER;
+       xonar_init_ext_power(chip);
+       xonar_st_init_common(chip);
+}
+
+static void xonar_d2_cleanup(struct oxygen *chip)
+{
+       xonar_disable_output(chip);
+}
+
+static void xonar_hdav_cleanup(struct oxygen *chip)
+{
+       xonar_hdmi_cleanup(chip);
+       xonar_disable_output(chip);
+       msleep(2);
+}
+
+static void xonar_st_cleanup(struct oxygen *chip)
+{
+       xonar_disable_output(chip);
+}
+
+static void xonar_d2_suspend(struct oxygen *chip)
+{
+       xonar_d2_cleanup(chip);
+}
+
+static void xonar_hdav_suspend(struct oxygen *chip)
+{
+       xonar_hdav_cleanup(chip);
+}
+
+static void xonar_st_suspend(struct oxygen *chip)
+{
+       xonar_st_cleanup(chip);
+}
+
+static void xonar_d2_resume(struct oxygen *chip)
+{
+       pcm1796_registers_init(chip);
+       xonar_enable_output(chip);
+}
+
+static void xonar_hdav_resume(struct oxygen *chip)
+{
+       struct xonar_hdav *data = chip->model_data;
+
+       pcm1796_registers_init(chip);
+       xonar_hdmi_resume(chip, &data->hdmi);
+       xonar_enable_output(chip);
+}
+
+static void xonar_stx_resume(struct oxygen *chip)
+{
+       pcm1796_registers_init(chip);
+       xonar_enable_output(chip);
+}
+
+static void xonar_st_resume(struct oxygen *chip)
+{
+       cs2000_registers_init(chip);
+       xonar_stx_resume(chip);
+}
+
+static unsigned int mclk_from_rate(struct oxygen *chip, unsigned int rate)
+{
+       struct xonar_pcm179x *data = chip->model_data;
+
+       if (rate <= 32000)
+               return OXYGEN_I2S_MCLK_512;
+       else if (rate <= 48000 && data->os_128)
+               return OXYGEN_I2S_MCLK_512;
+       else if (rate <= 96000)
+               return OXYGEN_I2S_MCLK_256;
+       else
+               return OXYGEN_I2S_MCLK_128;
+}
+
+static unsigned int get_pcm1796_i2s_mclk(struct oxygen *chip,
+                                        unsigned int channel,
+                                        struct snd_pcm_hw_params *params)
+{
+       if (channel == PCM_MULTICH)
+               return mclk_from_rate(chip, params_rate(params));
+       else
+               return oxygen_default_i2s_mclk(chip, channel, params);
+}
+
+static void update_pcm1796_oversampling(struct oxygen *chip)
+{
+       struct xonar_pcm179x *data = chip->model_data;
+       unsigned int i;
+       u8 reg;
+
+       if (data->current_rate <= 32000)
+               reg = PCM1796_OS_128;
+       else if (data->current_rate <= 48000 && data->os_128)
+               reg = PCM1796_OS_128;
+       else if (data->current_rate <= 96000 || data->os_128)
+               reg = PCM1796_OS_64;
+       else
+               reg = PCM1796_OS_32;
+       for (i = 0; i < data->dacs; ++i)
+               pcm1796_write_cached(chip, i, 20, reg);
+}
+
+static void set_pcm1796_params(struct oxygen *chip,
+                              struct snd_pcm_hw_params *params)
+{
+       struct xonar_pcm179x *data = chip->model_data;
+
+       data->current_rate = params_rate(params);
+       update_pcm1796_oversampling(chip);
+}
+
+static void update_pcm1796_volume(struct oxygen *chip)
+{
+       struct xonar_pcm179x *data = chip->model_data;
+       unsigned int i;
+       s8 gain_offset;
+
+       gain_offset = data->hp_active ? data->hp_gain_offset : 0;
+       for (i = 0; i < data->dacs; ++i) {
+               pcm1796_write_cached(chip, i, 16, chip->dac_volume[i * 2]
+                                    + gain_offset);
+               pcm1796_write_cached(chip, i, 17, chip->dac_volume[i * 2 + 1]
+                                    + gain_offset);
+       }
+}
+
+static void update_pcm1796_mute(struct oxygen *chip)
+{
+       struct xonar_pcm179x *data = chip->model_data;
+       unsigned int i;
+       u8 value;
+
+       value = PCM1796_DMF_DISABLED | PCM1796_FMT_24_LJUST | PCM1796_ATLD;
+       if (chip->dac_mute)
+               value |= PCM1796_MUTE;
+       for (i = 0; i < data->dacs; ++i)
+               pcm1796_write_cached(chip, i, 18, value);
+}
+
+static void update_cs2000_rate(struct oxygen *chip, unsigned int rate)
+{
+       struct xonar_pcm179x *data = chip->model_data;
+       u8 rate_mclk, reg;
+
+       switch (rate) {
+               /* XXX Why is the I2S A MCLK half the actual I2S MCLK? */
+       case 32000:
+               rate_mclk = OXYGEN_RATE_32000 | OXYGEN_I2S_MCLK_256;
+               break;
+       case 44100:
+               if (data->os_128)
+                       rate_mclk = OXYGEN_RATE_44100 | OXYGEN_I2S_MCLK_256;
+               else
+                       rate_mclk = OXYGEN_RATE_44100 | OXYGEN_I2S_MCLK_128;
+               break;
+       default: /* 48000 */
+               if (data->os_128)
+                       rate_mclk = OXYGEN_RATE_48000 | OXYGEN_I2S_MCLK_256;
+               else
+                       rate_mclk = OXYGEN_RATE_48000 | OXYGEN_I2S_MCLK_128;
+               break;
+       case 64000:
+               rate_mclk = OXYGEN_RATE_32000 | OXYGEN_I2S_MCLK_256;
+               break;
+       case 88200:
+               rate_mclk = OXYGEN_RATE_44100 | OXYGEN_I2S_MCLK_256;
+               break;
+       case 96000:
+               rate_mclk = OXYGEN_RATE_48000 | OXYGEN_I2S_MCLK_256;
+               break;
+       case 176400:
+               rate_mclk = OXYGEN_RATE_44100 | OXYGEN_I2S_MCLK_256;
+               break;
+       case 192000:
+               rate_mclk = OXYGEN_RATE_48000 | OXYGEN_I2S_MCLK_256;
+               break;
+       }
+       oxygen_write16_masked(chip, OXYGEN_I2S_A_FORMAT, rate_mclk,
+                             OXYGEN_I2S_RATE_MASK | OXYGEN_I2S_MCLK_MASK);
+       if ((rate_mclk & OXYGEN_I2S_MCLK_MASK) <= OXYGEN_I2S_MCLK_128)
+               reg = CS2000_REF_CLK_DIV_1;
+       else
+               reg = CS2000_REF_CLK_DIV_2;
+       cs2000_write_cached(chip, CS2000_FUN_CFG_1, reg);
+}
+
+static void set_st_params(struct oxygen *chip,
+                         struct snd_pcm_hw_params *params)
+{
+       update_cs2000_rate(chip, params_rate(params));
+       set_pcm1796_params(chip, params);
+}
+
+static void set_hdav_params(struct oxygen *chip,
+                           struct snd_pcm_hw_params *params)
+{
+       struct xonar_hdav *data = chip->model_data;
+
+       set_pcm1796_params(chip, params);
+       xonar_set_hdmi_params(chip, &data->hdmi, params);
+}
+
+static const struct snd_kcontrol_new alt_switch = {
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       .name = "Analog Loopback Switch",
+       .info = snd_ctl_boolean_mono_info,
+       .get = xonar_gpio_bit_switch_get,
+       .put = xonar_gpio_bit_switch_put,
+       .private_value = GPIO_D2_ALT,
+};
+
+static int rolloff_info(struct snd_kcontrol *ctl,
+                       struct snd_ctl_elem_info *info)
+{
+       static const char *const names[2] = {
+               "Sharp Roll-off", "Slow Roll-off"
+       };
+
+       info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+       info->count = 1;
+       info->value.enumerated.items = 2;
+       if (info->value.enumerated.item >= 2)
+               info->value.enumerated.item = 1;
+       strcpy(info->value.enumerated.name, names[info->value.enumerated.item]);
+       return 0;
+}
+
+static int rolloff_get(struct snd_kcontrol *ctl,
+                      struct snd_ctl_elem_value *value)
+{
+       struct oxygen *chip = ctl->private_data;
+       struct xonar_pcm179x *data = chip->model_data;
+
+       value->value.enumerated.item[0] =
+               (data->pcm1796_regs[0][19 - PCM1796_REG_BASE] &
+                PCM1796_FLT_MASK) != PCM1796_FLT_SHARP;
+       return 0;
+}
+
+static int rolloff_put(struct snd_kcontrol *ctl,
+                      struct snd_ctl_elem_value *value)
+{
+       struct oxygen *chip = ctl->private_data;
+       struct xonar_pcm179x *data = chip->model_data;
+       unsigned int i;
+       int changed;
+       u8 reg;
+
+       mutex_lock(&chip->mutex);
+       reg = data->pcm1796_regs[0][19 - PCM1796_REG_BASE];
+       reg &= ~PCM1796_FLT_MASK;
+       if (!value->value.enumerated.item[0])
+               reg |= PCM1796_FLT_SHARP;
+       else
+               reg |= PCM1796_FLT_SLOW;
+       changed = reg != data->pcm1796_regs[0][19 - PCM1796_REG_BASE];
+       if (changed) {
+               for (i = 0; i < data->dacs; ++i)
+                       pcm1796_write(chip, i, 19, reg);
+       }
+       mutex_unlock(&chip->mutex);
+       return changed;
+}
+
+static const struct snd_kcontrol_new rolloff_control = {
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       .name = "DAC Filter Playback Enum",
+       .info = rolloff_info,
+       .get = rolloff_get,
+       .put = rolloff_put,
+};
+
+static int os_128_info(struct snd_kcontrol *ctl, struct snd_ctl_elem_info *info)
+{
+       static const char *const names[2] = { "64x", "128x" };
+
+       info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+       info->count = 1;
+       info->value.enumerated.items = 2;
+       if (info->value.enumerated.item >= 2)
+               info->value.enumerated.item = 1;
+       strcpy(info->value.enumerated.name, names[info->value.enumerated.item]);
+       return 0;
+}
+
+static int os_128_get(struct snd_kcontrol *ctl,
+                     struct snd_ctl_elem_value *value)
+{
+       struct oxygen *chip = ctl->private_data;
+       struct xonar_pcm179x *data = chip->model_data;
+
+       value->value.enumerated.item[0] = data->os_128;
+       return 0;
+}
+
+static int os_128_put(struct snd_kcontrol *ctl,
+                     struct snd_ctl_elem_value *value)
+{
+       struct oxygen *chip = ctl->private_data;
+       struct xonar_pcm179x *data = chip->model_data;
+       int changed;
+
+       mutex_lock(&chip->mutex);
+       changed = value->value.enumerated.item[0] != data->os_128;
+       if (changed) {
+               data->os_128 = value->value.enumerated.item[0];
+               if (data->has_cs2000)
+                       update_cs2000_rate(chip, data->current_rate);
+               oxygen_write16_masked(chip, OXYGEN_I2S_MULTICH_FORMAT,
+                                     mclk_from_rate(chip, data->current_rate),
+                                     OXYGEN_I2S_MCLK_MASK);
+               update_pcm1796_oversampling(chip);
+       }
+       mutex_unlock(&chip->mutex);
+       return changed;
+}
+
+static const struct snd_kcontrol_new os_128_control = {
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       .name = "DAC Oversampling Playback Enum",
+       .info = os_128_info,
+       .get = os_128_get,
+       .put = os_128_put,
+};
+
+static int st_output_switch_info(struct snd_kcontrol *ctl,
+                                struct snd_ctl_elem_info *info)
+{
+       static const char *const names[3] = {
+               "Speakers", "Headphones", "FP Headphones"
+       };
+
+       info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+       info->count = 1;
+       info->value.enumerated.items = 3;
+       if (info->value.enumerated.item >= 3)
+               info->value.enumerated.item = 2;
+       strcpy(info->value.enumerated.name, names[info->value.enumerated.item]);
+       return 0;
+}
+
+static int st_output_switch_get(struct snd_kcontrol *ctl,
+                               struct snd_ctl_elem_value *value)
+{
+       struct oxygen *chip = ctl->private_data;
+       u16 gpio;
+
+       gpio = oxygen_read16(chip, OXYGEN_GPIO_DATA);
+       if (!(gpio & GPIO_ST_HP))
+               value->value.enumerated.item[0] = 0;
+       else if (gpio & GPIO_ST_HP_REAR)
+               value->value.enumerated.item[0] = 1;
+       else
+               value->value.enumerated.item[0] = 2;
+       return 0;
+}
+
+
+static int st_output_switch_put(struct snd_kcontrol *ctl,
+                               struct snd_ctl_elem_value *value)
+{
+       struct oxygen *chip = ctl->private_data;
+       struct xonar_pcm179x *data = chip->model_data;
+       u16 gpio_old, gpio;
+
+       mutex_lock(&chip->mutex);
+       gpio_old = oxygen_read16(chip, OXYGEN_GPIO_DATA);
+       gpio = gpio_old;
+       switch (value->value.enumerated.item[0]) {
+       case 0:
+               gpio &= ~(GPIO_ST_HP | GPIO_ST_HP_REAR);
+               break;
+       case 1:
+               gpio |= GPIO_ST_HP | GPIO_ST_HP_REAR;
+               break;
+       case 2:
+               gpio = (gpio | GPIO_ST_HP) & ~GPIO_ST_HP_REAR;
+               break;
+       }
+       oxygen_write16(chip, OXYGEN_GPIO_DATA, gpio);
+       data->hp_active = gpio & GPIO_ST_HP;
+       update_pcm1796_volume(chip);
+       mutex_unlock(&chip->mutex);
+       return gpio != gpio_old;
+}
+
+static int st_hp_volume_offset_info(struct snd_kcontrol *ctl,
+                                   struct snd_ctl_elem_info *info)
+{
+       static const char *const names[3] = {
+               "< 64 ohms", "64-300 ohms", "300-600 ohms"
+       };
+
+       info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+       info->count = 1;
+       info->value.enumerated.items = 3;
+       if (info->value.enumerated.item > 2)
+               info->value.enumerated.item = 2;
+       strcpy(info->value.enumerated.name, names[info->value.enumerated.item]);
+       return 0;
+}
+
+static int st_hp_volume_offset_get(struct snd_kcontrol *ctl,
+                                  struct snd_ctl_elem_value *value)
+{
+       struct oxygen *chip = ctl->private_data;
+       struct xonar_pcm179x *data = chip->model_data;
+
+       mutex_lock(&chip->mutex);
+       if (data->hp_gain_offset < 2*-6)
+               value->value.enumerated.item[0] = 0;
+       else if (data->hp_gain_offset < 0)
+               value->value.enumerated.item[0] = 1;
+       else
+               value->value.enumerated.item[0] = 2;
+       mutex_unlock(&chip->mutex);
+       return 0;
+}
+
+
+static int st_hp_volume_offset_put(struct snd_kcontrol *ctl,
+                                  struct snd_ctl_elem_value *value)
+{
+       static const s8 offsets[] = { 2*-18, 2*-6, 0 };
+       struct oxygen *chip = ctl->private_data;
+       struct xonar_pcm179x *data = chip->model_data;
+       s8 offset;
+       int changed;
+
+       if (value->value.enumerated.item[0] > 2)
+               return -EINVAL;
+       offset = offsets[value->value.enumerated.item[0]];
+       mutex_lock(&chip->mutex);
+       changed = offset != data->hp_gain_offset;
+       if (changed) {
+               data->hp_gain_offset = offset;
+               update_pcm1796_volume(chip);
+       }
+       mutex_unlock(&chip->mutex);
+       return changed;
+}
+
+static const struct snd_kcontrol_new st_controls[] = {
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "Analog Output",
+               .info = st_output_switch_info,
+               .get = st_output_switch_get,
+               .put = st_output_switch_put,
+       },
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "Headphones Impedance Playback Enum",
+               .info = st_hp_volume_offset_info,
+               .get = st_hp_volume_offset_get,
+               .put = st_hp_volume_offset_put,
+       },
+};
+
+static void xonar_line_mic_ac97_switch(struct oxygen *chip,
+                                      unsigned int reg, unsigned int mute)
+{
+       if (reg == AC97_LINE) {
+               spin_lock_irq(&chip->reg_lock);
+               oxygen_write16_masked(chip, OXYGEN_GPIO_DATA,
+                                     mute ? GPIO_INPUT_ROUTE : 0,
+                                     GPIO_INPUT_ROUTE);
+               spin_unlock_irq(&chip->reg_lock);
+       }
+}
+
+static const DECLARE_TLV_DB_SCALE(pcm1796_db_scale, -6000, 50, 0);
+
+static int xonar_d2_control_filter(struct snd_kcontrol_new *template)
+{
+       if (!strncmp(template->name, "CD Capture ", 11))
+               /* CD in is actually connected to the video in pin */
+               template->private_value ^= AC97_CD ^ AC97_VIDEO;
+       return 0;
+}
+
+static int xonar_st_control_filter(struct snd_kcontrol_new *template)
+{
+       if (!strncmp(template->name, "CD Capture ", 11))
+               return 1; /* no CD input */
+       return 0;
+}
+
+static int add_pcm1796_controls(struct oxygen *chip)
+{
+       int err;
+
+       err = snd_ctl_add(chip->card, snd_ctl_new1(&rolloff_control, chip));
+       if (err < 0)
+               return err;
+       err = snd_ctl_add(chip->card, snd_ctl_new1(&os_128_control, chip));
+       if (err < 0)
+               return err;
+       return 0;
+}
+
+static int xonar_d2_mixer_init(struct oxygen *chip)
+{
+       int err;
+
+       err = snd_ctl_add(chip->card, snd_ctl_new1(&alt_switch, chip));
+       if (err < 0)
+               return err;
+       err = add_pcm1796_controls(chip);
+       if (err < 0)
+               return err;
+       return 0;
+}
+
+static int xonar_hdav_mixer_init(struct oxygen *chip)
+{
+       return add_pcm1796_controls(chip);
+}
+
+static int xonar_st_mixer_init(struct oxygen *chip)
+{
+       unsigned int i;
+       int err;
+
+       for (i = 0; i < ARRAY_SIZE(st_controls); ++i) {
+               err = snd_ctl_add(chip->card,
+                                 snd_ctl_new1(&st_controls[i], chip));
+               if (err < 0)
+                       return err;
+       }
+       err = add_pcm1796_controls(chip);
+       if (err < 0)
+               return err;
+       return 0;
+}
+
+static const struct oxygen_model model_xonar_d2 = {
+       .longname = "Asus Virtuoso 200",
+       .chip = "AV200",
+       .init = xonar_d2_init,
+       .control_filter = xonar_d2_control_filter,
+       .mixer_init = xonar_d2_mixer_init,
+       .cleanup = xonar_d2_cleanup,
+       .suspend = xonar_d2_suspend,
+       .resume = xonar_d2_resume,
+       .get_i2s_mclk = get_pcm1796_i2s_mclk,
+       .set_dac_params = set_pcm1796_params,
+       .set_adc_params = xonar_set_cs53x1_params,
+       .update_dac_volume = update_pcm1796_volume,
+       .update_dac_mute = update_pcm1796_mute,
+       .dac_tlv = pcm1796_db_scale,
+       .model_data_size = sizeof(struct xonar_pcm179x),
+       .device_config = PLAYBACK_0_TO_I2S |
+                        PLAYBACK_1_TO_SPDIF |
+                        CAPTURE_0_FROM_I2S_2 |
+                        CAPTURE_1_FROM_SPDIF |
+                        MIDI_OUTPUT |
+                        MIDI_INPUT,
+       .dac_channels = 8,
+       .dac_volume_min = 255 - 2*60,
+       .dac_volume_max = 255,
+       .misc_flags = OXYGEN_MISC_MIDI,
+       .function_flags = OXYGEN_FUNCTION_SPI |
+                         OXYGEN_FUNCTION_ENABLE_SPI_4_5,
+       .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
+       .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
+};
+
+static const struct oxygen_model model_xonar_hdav = {
+       .longname = "Asus Virtuoso 200",
+       .chip = "AV200",
+       .init = xonar_hdav_init,
+       .mixer_init = xonar_hdav_mixer_init,
+       .cleanup = xonar_hdav_cleanup,
+       .suspend = xonar_hdav_suspend,
+       .resume = xonar_hdav_resume,
+       .pcm_hardware_filter = xonar_hdmi_pcm_hardware_filter,
+       .get_i2s_mclk = get_pcm1796_i2s_mclk,
+       .set_dac_params = set_hdav_params,
+       .set_adc_params = xonar_set_cs53x1_params,
+       .update_dac_volume = update_pcm1796_volume,
+       .update_dac_mute = update_pcm1796_mute,
+       .uart_input = xonar_hdmi_uart_input,
+       .ac97_switch = xonar_line_mic_ac97_switch,
+       .dac_tlv = pcm1796_db_scale,
+       .model_data_size = sizeof(struct xonar_hdav),
+       .device_config = PLAYBACK_0_TO_I2S |
+                        PLAYBACK_1_TO_SPDIF |
+                        CAPTURE_0_FROM_I2S_2 |
+                        CAPTURE_1_FROM_SPDIF,
+       .dac_channels = 8,
+       .dac_volume_min = 255 - 2*60,
+       .dac_volume_max = 255,
+       .misc_flags = OXYGEN_MISC_MIDI,
+       .function_flags = OXYGEN_FUNCTION_2WIRE,
+       .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
+       .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
+};
+
+static const struct oxygen_model model_xonar_st = {
+       .longname = "Asus Virtuoso 100",
+       .chip = "AV200",
+       .init = xonar_st_init,
+       .control_filter = xonar_st_control_filter,
+       .mixer_init = xonar_st_mixer_init,
+       .cleanup = xonar_st_cleanup,
+       .suspend = xonar_st_suspend,
+       .resume = xonar_st_resume,
+       .get_i2s_mclk = get_pcm1796_i2s_mclk,
+       .set_dac_params = set_st_params,
+       .set_adc_params = xonar_set_cs53x1_params,
+       .update_dac_volume = update_pcm1796_volume,
+       .update_dac_mute = update_pcm1796_mute,
+       .ac97_switch = xonar_line_mic_ac97_switch,
+       .dac_tlv = pcm1796_db_scale,
+       .model_data_size = sizeof(struct xonar_pcm179x),
+       .device_config = PLAYBACK_0_TO_I2S |
+                        PLAYBACK_1_TO_SPDIF |
+                        CAPTURE_0_FROM_I2S_2,
+       .dac_channels = 2,
+       .dac_volume_min = 255 - 2*60,
+       .dac_volume_max = 255,
+       .function_flags = OXYGEN_FUNCTION_2WIRE,
+       .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
+       .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
+};
+
+int __devinit get_xonar_pcm179x_model(struct oxygen *chip,
+                                     const struct pci_device_id *id)
+{
+       switch (id->subdevice) {
+       case 0x8269:
+               chip->model = model_xonar_d2;
+               chip->model.shortname = "Xonar D2";
+               break;
+       case 0x82b7:
+               chip->model = model_xonar_d2;
+               chip->model.shortname = "Xonar D2X";
+               chip->model.init = xonar_d2x_init;
+               break;
+       case 0x8314:
+               chip->model = model_xonar_hdav;
+               oxygen_clear_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_DB_MASK);
+               switch (oxygen_read16(chip, OXYGEN_GPIO_DATA) & GPIO_DB_MASK) {
+               default:
+                       chip->model.shortname = "Xonar HDAV1.3";
+                       break;
+               case GPIO_DB_H6:
+                       chip->model.shortname = "Xonar HDAV1.3+H6";
+                       chip->model.private_data = 1;
+                       break;
+               }
+               break;
+       case 0x835d:
+               chip->model = model_xonar_st;
+               oxygen_clear_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_DB_MASK);
+               switch (oxygen_read16(chip, OXYGEN_GPIO_DATA) & GPIO_DB_MASK) {
+               default:
+                       chip->model.shortname = "Xonar ST";
+                       break;
+               case GPIO_DB_H6:
+                       chip->model.shortname = "Xonar ST+H6";
+                       chip->model.dac_channels = 8;
+                       chip->model.private_data = 1;
+                       break;
+               }
+               break;
+       case 0x835c:
+               chip->model = model_xonar_st;
+               chip->model.shortname = "Xonar STX";
+               chip->model.init = xonar_stx_init;
+               chip->model.resume = xonar_stx_resume;
+               chip->model.set_dac_params = set_pcm1796_params;
+               break;
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
index 2cc0eda..2e15646 100644 (file)
@@ -479,7 +479,7 @@ static int snd_pmac_awacs_put_master_amp(struct snd_kcontrol *kcontrol,
 
 static struct snd_kcontrol_new snd_pmac_awacs_amp_vol[] __devinitdata = {
        { .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-         .name = "PC Speaker Playback Volume",
+         .name = "Speaker Playback Volume",
          .info = snd_pmac_awacs_info_volume_amp,
          .get = snd_pmac_awacs_get_volume_amp,
          .put = snd_pmac_awacs_put_volume_amp,
@@ -525,7 +525,7 @@ static struct snd_kcontrol_new snd_pmac_awacs_amp_hp_sw __devinitdata = {
 
 static struct snd_kcontrol_new snd_pmac_awacs_amp_spk_sw __devinitdata = {
        .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-       .name = "PC Speaker Playback Switch",
+       .name = "Speaker Playback Switch",
        .info = snd_pmac_boolean_stereo_info,
        .get = snd_pmac_awacs_get_switch_amp,
        .put = snd_pmac_awacs_put_switch_amp,
@@ -696,17 +696,17 @@ static struct snd_kcontrol_new snd_pmac_screamer_mic_boost_imac[] __devinitdata
 };
 
 static struct snd_kcontrol_new snd_pmac_awacs_speaker_vol[] __devinitdata = {
-       AWACS_VOLUME("PC Speaker Playback Volume", 4, 6, 1),
+       AWACS_VOLUME("Speaker Playback Volume", 4, 6, 1),
 };
 
 static struct snd_kcontrol_new snd_pmac_awacs_speaker_sw __devinitdata =
-AWACS_SWITCH("PC Speaker Playback Switch", 1, SHIFT_SPKMUTE, 1);
+AWACS_SWITCH("Speaker Playback Switch", 1, SHIFT_SPKMUTE, 1);
 
 static struct snd_kcontrol_new snd_pmac_awacs_speaker_sw_imac1 __devinitdata =
-AWACS_SWITCH("PC Speaker Playback Switch", 1, SHIFT_PAROUT1, 1);
+AWACS_SWITCH("Speaker Playback Switch", 1, SHIFT_PAROUT1, 1);
 
 static struct snd_kcontrol_new snd_pmac_awacs_speaker_sw_imac2 __devinitdata =
-AWACS_SWITCH("PC Speaker Playback Switch", 1, SHIFT_PAROUT1, 0);
+AWACS_SWITCH("Speaker Playback Switch", 1, SHIFT_PAROUT1, 0);
 
 
 /*
index 16ed240..0accfe4 100644 (file)
@@ -505,7 +505,7 @@ static struct snd_kcontrol_new snd_pmac_burgundy_mixers_imac[] __devinitdata = {
                        MASK_ADDR_BURGUNDY_GAINLINE, 1, 0),
        BURGUNDY_VOLUME_B("Mic Gain Capture Volume", 0,
                        MASK_ADDR_BURGUNDY_GAINMIC, 1, 0),
-       BURGUNDY_VOLUME_B("PC Speaker Playback Volume", 0,
+       BURGUNDY_VOLUME_B("Speaker Playback Volume", 0,
                        MASK_ADDR_BURGUNDY_ATTENSPEAKER, 1, 1),
        BURGUNDY_VOLUME_B("Line out Playback Volume", 0,
                        MASK_ADDR_BURGUNDY_ATTENLINEOUT, 1, 1),
@@ -527,7 +527,7 @@ static struct snd_kcontrol_new snd_pmac_burgundy_mixers_pmac[] __devinitdata = {
                        MASK_ADDR_BURGUNDY_VOLMIC, 16),
        BURGUNDY_VOLUME_B("Line in Gain Capture Volume", 0,
                        MASK_ADDR_BURGUNDY_GAINMIC, 1, 0),
-       BURGUNDY_VOLUME_B("PC Speaker Playback Volume", 0,
+       BURGUNDY_VOLUME_B("Speaker Playback Volume", 0,
                        MASK_ADDR_BURGUNDY_ATTENMONO, 0, 1),
        BURGUNDY_VOLUME_B("Line out Playback Volume", 0,
                        MASK_ADDR_BURGUNDY_ATTENSPEAKER, 1, 1),
@@ -549,11 +549,11 @@ BURGUNDY_SWITCH_B("Master Playback Switch", 0,
        BURGUNDY_OUTPUT_INTERN
        | BURGUNDY_OUTPUT_LEFT, BURGUNDY_OUTPUT_RIGHT, 1);
 static struct snd_kcontrol_new snd_pmac_burgundy_speaker_sw_imac __devinitdata =
-BURGUNDY_SWITCH_B("PC Speaker Playback Switch", 0,
+BURGUNDY_SWITCH_B("Speaker Playback Switch", 0,
        MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES,
        BURGUNDY_OUTPUT_LEFT, BURGUNDY_OUTPUT_RIGHT, 1);
 static struct snd_kcontrol_new snd_pmac_burgundy_speaker_sw_pmac __devinitdata =
-BURGUNDY_SWITCH_B("PC Speaker Playback Switch", 0,
+BURGUNDY_SWITCH_B("Speaker Playback Switch", 0,
        MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES,
        BURGUNDY_OUTPUT_INTERN, 0, 0);
 static struct snd_kcontrol_new snd_pmac_burgundy_line_sw_imac __devinitdata =
index 08e584d..789f44f 100644 (file)
@@ -905,7 +905,7 @@ static struct snd_kcontrol_new tumbler_hp_sw __devinitdata = {
 };
 static struct snd_kcontrol_new tumbler_speaker_sw __devinitdata = {
        .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-       .name = "PC Speaker Playback Switch",
+       .name = "Speaker Playback Switch",
        .info = snd_pmac_boolean_mono_info,
        .get = tumbler_get_mute_switch,
        .put = tumbler_put_mute_switch,
index aed0f90..61139f3 100644 (file)
@@ -19,5 +19,13 @@ config SND_AICA
        help
          ALSA Sound driver for the SEGA Dreamcast console.
 
+config SND_SH_DAC_AUDIO
+       tristate "SuperH DAC audio support"
+       depends on SND
+       depends on CPU_SH3 && HIGH_RES_TIMERS
+       select SND_PCM
+       help
+         Say Y here to include support for the on-chip DAC.
+
 endif  # SND_SUPERH
 
index 8fdcb6e..7d09b51 100644 (file)
@@ -3,6 +3,8 @@
 #
 
 snd-aica-objs := aica.o
+snd-sh_dac_audio-objs := sh_dac_audio.o
 
 # Toplevel Module Dependency
 obj-$(CONFIG_SND_AICA) += snd-aica.o
+obj-$(CONFIG_SND_SH_DAC_AUDIO) += snd-sh_dac_audio.o
diff --git a/sound/sh/sh_dac_audio.c b/sound/sh/sh_dac_audio.c
new file mode 100644 (file)
index 0000000..76d9ad2
--- /dev/null
@@ -0,0 +1,453 @@
+/*
+ * sh_dac_audio.c - SuperH DAC audio driver for ALSA
+ *
+ * Copyright (c) 2009 by Rafael Ignacio Zurita <rizurita@yahoo.com>
+ *
+ *
+ * Based on sh_dac_audio.c (Copyright (C) 2004, 2005 by Andriy Skulysh)
+ *
+ *   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/hrtimer.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/initval.h>
+#include <sound/pcm.h>
+#include <sound/sh_dac_audio.h>
+#include <asm/clock.h>
+#include <asm/hd64461.h>
+#include <mach/hp6xx.h>
+#include <cpu/dac.h>
+
+MODULE_AUTHOR("Rafael Ignacio Zurita <rizurita@yahoo.com>");
+MODULE_DESCRIPTION("SuperH DAC audio driver");
+MODULE_LICENSE("GPL");
+MODULE_SUPPORTED_DEVICE("{{SuperH DAC audio support}}");
+
+/* Module Parameters */
+static int index = SNDRV_DEFAULT_IDX1;
+static char *id = SNDRV_DEFAULT_STR1;
+module_param(index, int, 0444);
+MODULE_PARM_DESC(index, "Index value for SuperH DAC audio.");
+module_param(id, charp, 0444);
+MODULE_PARM_DESC(id, "ID string for SuperH DAC audio.");
+
+/* main struct */
+struct snd_sh_dac {
+       struct snd_card *card;
+       struct snd_pcm_substream *substream;
+       struct hrtimer hrtimer;
+       ktime_t wakeups_per_second;
+
+       int rate;
+       int empty;
+       char *data_buffer, *buffer_begin, *buffer_end;
+       int processed; /* bytes proccesed, to compare with period_size */
+       int buffer_size;
+       struct dac_audio_pdata *pdata;
+};
+
+
+static void dac_audio_start_timer(struct snd_sh_dac *chip)
+{
+       hrtimer_start(&chip->hrtimer, chip->wakeups_per_second,
+                     HRTIMER_MODE_REL);
+}
+
+static void dac_audio_stop_timer(struct snd_sh_dac *chip)
+{
+       hrtimer_cancel(&chip->hrtimer);
+}
+
+static void dac_audio_reset(struct snd_sh_dac *chip)
+{
+       dac_audio_stop_timer(chip);
+       chip->buffer_begin = chip->buffer_end = chip->data_buffer;
+       chip->processed = 0;
+       chip->empty = 1;
+}
+
+static void dac_audio_set_rate(struct snd_sh_dac *chip)
+{
+       chip->wakeups_per_second = ktime_set(0, 1000000000 / chip->rate);
+}
+
+
+/* PCM INTERFACE */
+
+static struct snd_pcm_hardware snd_sh_dac_pcm_hw = {
+       .info                   = (SNDRV_PCM_INFO_MMAP |
+                                       SNDRV_PCM_INFO_MMAP_VALID |
+                                       SNDRV_PCM_INFO_INTERLEAVED |
+                                       SNDRV_PCM_INFO_HALF_DUPLEX),
+       .formats                = SNDRV_PCM_FMTBIT_U8,
+       .rates                  = SNDRV_PCM_RATE_8000,
+       .rate_min               = 8000,
+       .rate_max               = 8000,
+       .channels_min           = 1,
+       .channels_max           = 1,
+       .buffer_bytes_max       = (48*1024),
+       .period_bytes_min       = 1,
+       .period_bytes_max       = (48*1024),
+       .periods_min            = 1,
+       .periods_max            = 1024,
+};
+
+static int snd_sh_dac_pcm_open(struct snd_pcm_substream *substream)
+{
+       struct snd_sh_dac *chip = snd_pcm_substream_chip(substream);
+       struct snd_pcm_runtime *runtime = substream->runtime;
+
+       runtime->hw = snd_sh_dac_pcm_hw;
+
+       chip->substream = substream;
+       chip->buffer_begin = chip->buffer_end = chip->data_buffer;
+       chip->processed = 0;
+       chip->empty = 1;
+
+       chip->pdata->start(chip->pdata);
+
+       return 0;
+}
+
+static int snd_sh_dac_pcm_close(struct snd_pcm_substream *substream)
+{
+       struct snd_sh_dac *chip = snd_pcm_substream_chip(substream);
+
+       chip->substream = NULL;
+
+       dac_audio_stop_timer(chip);
+       chip->pdata->stop(chip->pdata);
+
+       return 0;
+}
+
+static int snd_sh_dac_pcm_hw_params(struct snd_pcm_substream *substream,
+                               struct snd_pcm_hw_params *hw_params)
+{
+       return snd_pcm_lib_malloc_pages(substream,
+                       params_buffer_bytes(hw_params));
+}
+
+static int snd_sh_dac_pcm_hw_free(struct snd_pcm_substream *substream)
+{
+       return snd_pcm_lib_free_pages(substream);
+}
+
+static int snd_sh_dac_pcm_prepare(struct snd_pcm_substream *substream)
+{
+       struct snd_sh_dac *chip = snd_pcm_substream_chip(substream);
+       struct snd_pcm_runtime *runtime = chip->substream->runtime;
+
+       chip->buffer_size = runtime->buffer_size;
+       memset(chip->data_buffer, 0, chip->pdata->buffer_size);
+
+       return 0;
+}
+
+static int snd_sh_dac_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+       struct snd_sh_dac *chip = snd_pcm_substream_chip(substream);
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+               dac_audio_start_timer(chip);
+               break;
+       case SNDRV_PCM_TRIGGER_STOP:
+               chip->buffer_begin = chip->buffer_end = chip->data_buffer;
+               chip->processed = 0;
+               chip->empty = 1;
+               dac_audio_stop_timer(chip);
+               break;
+       default:
+                return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int snd_sh_dac_pcm_copy(struct snd_pcm_substream *substream, int channel,
+       snd_pcm_uframes_t pos, void __user *src, snd_pcm_uframes_t count)
+{
+       /* channel is not used (interleaved data) */
+       struct snd_sh_dac *chip = snd_pcm_substream_chip(substream);
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       ssize_t b_count = frames_to_bytes(runtime , count);
+       ssize_t b_pos = frames_to_bytes(runtime , pos);
+
+       if (count < 0)
+               return -EINVAL;
+
+       if (!count)
+               return 0;
+
+       memcpy_toio(chip->data_buffer + b_pos, src, b_count);
+       chip->buffer_end = chip->data_buffer + b_pos + b_count;
+
+       if (chip->empty) {
+               chip->empty = 0;
+               dac_audio_start_timer(chip);
+       }
+
+       return 0;
+}
+
+static int snd_sh_dac_pcm_silence(struct snd_pcm_substream *substream,
+                                 int channel, snd_pcm_uframes_t pos,
+                                 snd_pcm_uframes_t count)
+{
+       /* channel is not used (interleaved data) */
+       struct snd_sh_dac *chip = snd_pcm_substream_chip(substream);
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       ssize_t b_count = frames_to_bytes(runtime , count);
+       ssize_t b_pos = frames_to_bytes(runtime , pos);
+
+       if (count < 0)
+               return -EINVAL;
+
+       if (!count)
+               return 0;
+
+       memset_io(chip->data_buffer + b_pos, 0, b_count);
+       chip->buffer_end = chip->data_buffer + b_pos + b_count;
+
+       if (chip->empty) {
+               chip->empty = 0;
+               dac_audio_start_timer(chip);
+       }
+
+       return 0;
+}
+
+static
+snd_pcm_uframes_t snd_sh_dac_pcm_pointer(struct snd_pcm_substream *substream)
+{
+       struct snd_sh_dac *chip = snd_pcm_substream_chip(substream);
+       int pointer = chip->buffer_begin - chip->data_buffer;
+
+       return pointer;
+}
+
+/* pcm ops */
+static struct snd_pcm_ops snd_sh_dac_pcm_ops = {
+       .open           = snd_sh_dac_pcm_open,
+       .close          = snd_sh_dac_pcm_close,
+       .ioctl          = snd_pcm_lib_ioctl,
+       .hw_params      = snd_sh_dac_pcm_hw_params,
+       .hw_free        = snd_sh_dac_pcm_hw_free,
+       .prepare        = snd_sh_dac_pcm_prepare,
+       .trigger        = snd_sh_dac_pcm_trigger,
+       .pointer        = snd_sh_dac_pcm_pointer,
+       .copy           = snd_sh_dac_pcm_copy,
+       .silence        = snd_sh_dac_pcm_silence,
+       .mmap           = snd_pcm_lib_mmap_iomem,
+};
+
+static int __devinit snd_sh_dac_pcm(struct snd_sh_dac *chip, int device)
+{
+       int err;
+       struct snd_pcm *pcm;
+
+       /* device should be always 0 for us */
+       err = snd_pcm_new(chip->card, "SH_DAC PCM", device, 1, 0, &pcm);
+       if (err < 0)
+               return err;
+
+       pcm->private_data = chip;
+       strcpy(pcm->name, "SH_DAC PCM");
+       snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_sh_dac_pcm_ops);
+
+       /* buffer size=48K */
+       snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS,
+                                         snd_dma_continuous_data(GFP_KERNEL),
+                                                       48 * 1024,
+                                                       48 * 1024);
+
+       return 0;
+}
+/* END OF PCM INTERFACE */
+
+
+/* driver .remove  --  destructor */
+static int snd_sh_dac_remove(struct platform_device *devptr)
+{
+       snd_card_free(platform_get_drvdata(devptr));
+       platform_set_drvdata(devptr, NULL);
+
+       return 0;
+}
+
+/* free -- it has been defined by create */
+static int snd_sh_dac_free(struct snd_sh_dac *chip)
+{
+       /* release the data */
+       kfree(chip->data_buffer);
+       kfree(chip);
+
+       return 0;
+}
+
+static int snd_sh_dac_dev_free(struct snd_device *device)
+{
+       struct snd_sh_dac *chip = device->device_data;
+
+       return snd_sh_dac_free(chip);
+}
+
+static enum hrtimer_restart sh_dac_audio_timer(struct hrtimer *handle)
+{
+       struct snd_sh_dac *chip = container_of(handle, struct snd_sh_dac,
+                                              hrtimer);
+       struct snd_pcm_runtime *runtime = chip->substream->runtime;
+       ssize_t b_ps = frames_to_bytes(runtime, runtime->period_size);
+
+       if (!chip->empty) {
+               sh_dac_output(*chip->buffer_begin, chip->pdata->channel);
+               chip->buffer_begin++;
+
+               chip->processed++;
+               if (chip->processed >= b_ps) {
+                       chip->processed -= b_ps;
+                       snd_pcm_period_elapsed(chip->substream);
+               }
+
+               if (chip->buffer_begin == (chip->data_buffer +
+                                          chip->buffer_size - 1))
+                       chip->buffer_begin = chip->data_buffer;
+
+               if (chip->buffer_begin == chip->buffer_end)
+                       chip->empty = 1;
+
+       }
+
+       if (!chip->empty)
+               hrtimer_start(&chip->hrtimer, chip->wakeups_per_second,
+                             HRTIMER_MODE_REL);
+
+       return HRTIMER_NORESTART;
+}
+
+/* create  --  chip-specific constructor for the cards components */
+static int __devinit snd_sh_dac_create(struct snd_card *card,
+                                      struct platform_device *devptr,
+                                      struct snd_sh_dac **rchip)
+{
+       struct snd_sh_dac *chip;
+       int err;
+
+       static struct snd_device_ops ops = {
+                  .dev_free = snd_sh_dac_dev_free,
+       };
+
+       *rchip = NULL;
+
+       chip = kzalloc(sizeof(*chip), GFP_KERNEL);
+       if (chip == NULL)
+               return -ENOMEM;
+
+       chip->card = card;
+
+       hrtimer_init(&chip->hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+       chip->hrtimer.function = sh_dac_audio_timer;
+
+       dac_audio_reset(chip);
+       chip->rate = 8000;
+       dac_audio_set_rate(chip);
+
+       chip->pdata = devptr->dev.platform_data;
+
+       chip->data_buffer = kmalloc(chip->pdata->buffer_size, GFP_KERNEL);
+       if (chip->data_buffer == NULL) {
+               kfree(chip);
+               return -ENOMEM;
+       }
+
+       err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops);
+       if (err < 0) {
+               snd_sh_dac_free(chip);
+               return err;
+       }
+
+       *rchip = chip;
+
+       return 0;
+}
+
+/* driver .probe  --  constructor */
+static int __devinit snd_sh_dac_probe(struct platform_device *devptr)
+{
+       struct snd_sh_dac *chip;
+       struct snd_card *card;
+       int err;
+
+       err = snd_card_create(index, id, THIS_MODULE, 0, &card);
+       if (err < 0) {
+                       snd_printk(KERN_ERR "cannot allocate the card\n");
+                       return err;
+       }
+
+       err = snd_sh_dac_create(card, devptr, &chip);
+       if (err < 0)
+               goto probe_error;
+
+       err = snd_sh_dac_pcm(chip, 0);
+       if (err < 0)
+               goto probe_error;
+
+       strcpy(card->driver, "snd_sh_dac");
+       strcpy(card->shortname, "SuperH DAC audio driver");
+       printk(KERN_INFO "%s %s", card->longname, card->shortname);
+
+       err = snd_card_register(card);
+       if (err < 0)
+               goto probe_error;
+
+       snd_printk("ALSA driver for SuperH DAC audio");
+
+       platform_set_drvdata(devptr, card);
+       return 0;
+
+probe_error:
+       snd_card_free(card);
+       return err;
+}
+
+/*
+ * "driver" definition
+ */
+static struct platform_driver driver = {
+       .probe  = snd_sh_dac_probe,
+       .remove = snd_sh_dac_remove,
+       .driver = {
+               .name = "dac_audio",
+       },
+};
+
+static int __init sh_dac_init(void)
+{
+       return platform_driver_register(&driver);
+}
+
+static void __exit sh_dac_exit(void)
+{
+       platform_driver_unregister(&driver);
+}
+
+module_init(sh_dac_init);
+module_exit(sh_dac_exit);
index 0c5eac0..1470141 100644 (file)
@@ -1,4 +1,4 @@
-snd-soc-core-objs := soc-core.o soc-dapm.o soc-jack.o soc-cache.o
+snd-soc-core-objs := soc-core.o soc-dapm.o soc-jack.o soc-cache.o soc-utils.o
 
 obj-$(CONFIG_SND_SOC)  += snd-soc-core.o
 obj-$(CONFIG_SND_SOC)  += codecs/
index 9eb610c..9df4c68 100644 (file)
@@ -268,7 +268,7 @@ static int playpaq_wm8510_hw_params(struct snd_pcm_substream *substream,
 #endif /* CONFIG_SND_AT32_SOC_PLAYPAQ_SLAVE */
 
 
-       ret = snd_soc_dai_set_pll(codec_dai, 0,
+       ret = snd_soc_dai_set_pll(codec_dai, 0, 0,
                                         clk_get_rate(CODEC_CLK), pll_out);
        if (ret < 0) {
                pr_warning("playpaq_wm8510: Failed to set CODEC DAI PLL (%d)\n",
index 885ba01..e028744 100644 (file)
@@ -207,7 +207,7 @@ static int __init at91sam9g20ek_init(void)
        struct clk *pllb;
        int ret;
 
-       if (!machine_is_at91sam9g20ek())
+       if (!(machine_is_at91sam9g20ek() || machine_is_at91sam9g20ek_2mmc()))
                return -ENODEV;
 
        /*
index 594c6c5..19e4d37 100644 (file)
@@ -2,7 +2,7 @@
  * Au12x0/Au1550 PSC ALSA ASoC audio support.
  *
  * (c) 2007-2008 MSC Vertriebsges.m.b.H.,
- *     Manuel Lauss <mano@roarinelk.homelinux.net>
+ *     Manuel Lauss <manuel.lauss@gmail.com>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -333,6 +333,30 @@ static int au1xpsc_pcm_new(struct snd_card *card,
 
 static int au1xpsc_pcm_probe(struct platform_device *pdev)
 {
+       if (!au1xpsc_audio_pcmdma[PCM_TX] || !au1xpsc_audio_pcmdma[PCM_RX])
+               return -ENODEV;
+
+       return 0;
+}
+
+static int au1xpsc_pcm_remove(struct platform_device *pdev)
+{
+       return 0;
+}
+
+/* au1xpsc audio platform */
+struct snd_soc_platform au1xpsc_soc_platform = {
+       .name           = "au1xpsc-pcm-dbdma",
+       .probe          = au1xpsc_pcm_probe,
+       .remove         = au1xpsc_pcm_remove,
+       .pcm_ops        = &au1xpsc_pcm_ops,
+       .pcm_new        = au1xpsc_pcm_new,
+       .pcm_free       = au1xpsc_pcm_free_dma_buffers,
+};
+EXPORT_SYMBOL_GPL(au1xpsc_soc_platform);
+
+static int __devinit au1xpsc_pcm_drvprobe(struct platform_device *pdev)
+{
        struct resource *r;
        int ret;
 
@@ -365,7 +389,9 @@ static int au1xpsc_pcm_probe(struct platform_device *pdev)
        }
        (au1xpsc_audio_pcmdma[PCM_RX])->ddma_id = r->start;
 
-       return 0;
+       ret = snd_soc_register_platform(&au1xpsc_soc_platform);
+       if (!ret)
+               return ret;
 
 out2:
        kfree(au1xpsc_audio_pcmdma[PCM_RX]);
@@ -376,10 +402,12 @@ out1:
        return ret;
 }
 
-static int au1xpsc_pcm_remove(struct platform_device *pdev)
+static int __devexit au1xpsc_pcm_drvremove(struct platform_device *pdev)
 {
        int i;
 
+       snd_soc_unregister_platform(&au1xpsc_soc_platform);
+
        for (i = 0; i < 2; i++) {
                if (au1xpsc_audio_pcmdma[i]) {
                        au1x_pcm_dbdma_free(au1xpsc_audio_pcmdma[i]);
@@ -391,32 +419,81 @@ static int au1xpsc_pcm_remove(struct platform_device *pdev)
        return 0;
 }
 
-/* au1xpsc audio platform */
-struct snd_soc_platform au1xpsc_soc_platform = {
-       .name           = "au1xpsc-pcm-dbdma",
-       .probe          = au1xpsc_pcm_probe,
-       .remove         = au1xpsc_pcm_remove,
-       .pcm_ops        = &au1xpsc_pcm_ops,
-       .pcm_new        = au1xpsc_pcm_new,
-       .pcm_free       = au1xpsc_pcm_free_dma_buffers,
+static struct platform_driver au1xpsc_pcm_driver = {
+       .driver = {
+               .name   = "au1xpsc-pcm",
+               .owner  = THIS_MODULE,
+       },
+       .probe          = au1xpsc_pcm_drvprobe,
+       .remove         = __devexit_p(au1xpsc_pcm_drvremove),
 };
-EXPORT_SYMBOL_GPL(au1xpsc_soc_platform);
 
-static int __init au1xpsc_audio_dbdma_init(void)
+static int __init au1xpsc_audio_dbdma_load(void)
 {
        au1xpsc_audio_pcmdma[PCM_TX] = NULL;
        au1xpsc_audio_pcmdma[PCM_RX] = NULL;
-       return snd_soc_register_platform(&au1xpsc_soc_platform);
+       return platform_driver_register(&au1xpsc_pcm_driver);
 }
 
-static void __exit au1xpsc_audio_dbdma_exit(void)
+static void __exit au1xpsc_audio_dbdma_unload(void)
 {
-       snd_soc_unregister_platform(&au1xpsc_soc_platform);
+       platform_driver_unregister(&au1xpsc_pcm_driver);
 }
 
-module_init(au1xpsc_audio_dbdma_init);
-module_exit(au1xpsc_audio_dbdma_exit);
+module_init(au1xpsc_audio_dbdma_load);
+module_exit(au1xpsc_audio_dbdma_unload);
+
+
+struct platform_device *au1xpsc_pcm_add(struct platform_device *pdev)
+{
+       struct resource *res, *r;
+       struct platform_device *pd;
+       int id[2];
+       int ret;
+
+       r = platform_get_resource(pdev, IORESOURCE_DMA, 0);
+       if (!r)
+               return NULL;
+       id[0] = r->start;
+
+       r = platform_get_resource(pdev, IORESOURCE_DMA, 1);
+       if (!r)
+               return NULL;
+       id[1] = r->start;
+
+       res = kzalloc(sizeof(struct resource) * 2, GFP_KERNEL);
+       if (!res)
+               return NULL;
+
+       res[0].start = res[0].end = id[0];
+       res[1].start = res[1].end = id[1];
+       res[0].flags = res[1].flags = IORESOURCE_DMA;
+
+       pd = platform_device_alloc("au1xpsc-pcm", -1);
+       if (!pd)
+               goto out;
+
+       pd->resource = res;
+       pd->num_resources = 2;
+
+       ret = platform_device_add(pd);
+       if (!ret)
+               return pd;
+
+       platform_device_put(pd);
+out:
+       kfree(res);
+       return NULL;
+}
+EXPORT_SYMBOL_GPL(au1xpsc_pcm_add);
+
+void au1xpsc_pcm_destroy(struct platform_device *dmapd)
+{
+       if (dmapd)
+               platform_device_unregister(dmapd);
+}
+EXPORT_SYMBOL_GPL(au1xpsc_pcm_destroy);
 
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("Au12x0/Au1550 PSC Audio DMA driver");
-MODULE_AUTHOR("Manuel Lauss <mano@roarinelk.homelinux.net>");
+MODULE_AUTHOR("Manuel Lauss");
index a521aa9..340311d 100644 (file)
@@ -61,7 +61,8 @@ static unsigned short au1xpsc_ac97_read(struct snd_ac97 *ac97,
 {
        /* FIXME */
        struct au1xpsc_audio_data *pscdata = au1xpsc_ac97_workdata;
-       unsigned short data, retry, tmo;
+       unsigned short retry, tmo;
+       unsigned long data;
 
        au_writel(PSC_AC97EVNT_CD, AC97_EVNT(pscdata));
        au_sync();
@@ -74,20 +75,26 @@ static unsigned short au1xpsc_ac97_read(struct snd_ac97 *ac97,
                          AC97_CDC(pscdata));
                au_sync();
 
-               tmo = 2000;
-               while ((!(au_readl(AC97_EVNT(pscdata)) & PSC_AC97EVNT_CD))
-                       && --tmo)
-                       udelay(2);
+               tmo = 20;
+               do {
+                       udelay(21);
+                       if (au_readl(AC97_EVNT(pscdata)) & PSC_AC97EVNT_CD)
+                               break;
+               } while (--tmo);
 
-               data = au_readl(AC97_CDC(pscdata)) & 0xffff;
+               data = au_readl(AC97_CDC(pscdata));
 
                au_writel(PSC_AC97EVNT_CD, AC97_EVNT(pscdata));
                au_sync();
 
                mutex_unlock(&pscdata->lock);
+
+               if (reg != ((data >> 16) & 0x7f))
+                       tmo = 1;        /* wrong register, try again */
+
        } while (--retry && !tmo);
 
-       return retry ? data : 0xffff;
+       return retry ? data & 0xffff : 0xffff;
 }
 
 /* AC97 controller writes to codec register */
@@ -109,10 +116,12 @@ static void au1xpsc_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
                          AC97_CDC(pscdata));
                au_sync();
 
-               tmo = 2000;
-               while ((!(au_readl(AC97_EVNT(pscdata)) & PSC_AC97EVNT_CD))
-                      && --tmo)
-                       udelay(2);
+               tmo = 20;
+               do {
+                       udelay(21);
+                       if (au_readl(AC97_EVNT(pscdata)) & PSC_AC97EVNT_CD)
+                               break;
+               } while (--tmo);
 
                au_writel(PSC_AC97EVNT_CD, AC97_EVNT(pscdata));
                au_sync();
@@ -195,7 +204,7 @@ static int au1xpsc_ac97_hw_params(struct snd_pcm_substream *substream,
        /* FIXME */
        struct au1xpsc_audio_data *pscdata = au1xpsc_ac97_workdata;
        unsigned long r, ro, stat;
-       int chans, stype = SUBSTREAM_TYPE(substream);
+       int chans, t, stype = SUBSTREAM_TYPE(substream);
 
        chans = params_channels(params);
 
@@ -237,8 +246,12 @@ static int au1xpsc_ac97_hw_params(struct snd_pcm_substream *substream,
                au_sync();
 
                /* ...wait for it... */
-               while (au_readl(AC97_STAT(pscdata)) & PSC_AC97STAT_DR)
-                       asm volatile ("nop");
+               t = 100;
+               while ((au_readl(AC97_STAT(pscdata)) & PSC_AC97STAT_DR) && --t)
+                       msleep(1);
+
+               if (!t)
+                       printk(KERN_ERR "PSC-AC97: can't disable!\n");
 
                /* ...write config... */
                au_writel(r, AC97_CFG(pscdata));
@@ -249,8 +262,12 @@ static int au1xpsc_ac97_hw_params(struct snd_pcm_substream *substream,
                au_sync();
 
                /* ...and wait for ready bit */
-               while (!(au_readl(AC97_STAT(pscdata)) & PSC_AC97STAT_DR))
-                       asm volatile ("nop");
+               t = 100;
+               while ((!(au_readl(AC97_STAT(pscdata)) & PSC_AC97STAT_DR)) && --t)
+                       msleep(1);
+
+               if (!t)
+                       printk(KERN_ERR "PSC-AC97: can't enable!\n");
 
                mutex_unlock(&pscdata->lock);
 
@@ -300,19 +317,55 @@ static int au1xpsc_ac97_trigger(struct snd_pcm_substream *substream,
 static int au1xpsc_ac97_probe(struct platform_device *pdev,
                              struct snd_soc_dai *dai)
 {
+       return au1xpsc_ac97_workdata ? 0 : -ENODEV;
+}
+
+static void au1xpsc_ac97_remove(struct platform_device *pdev,
+                               struct snd_soc_dai *dai)
+{
+}
+
+static struct snd_soc_dai_ops au1xpsc_ac97_dai_ops = {
+       .trigger        = au1xpsc_ac97_trigger,
+       .hw_params      = au1xpsc_ac97_hw_params,
+};
+
+struct snd_soc_dai au1xpsc_ac97_dai = {
+       .name                   = "au1xpsc_ac97",
+       .ac97_control           = 1,
+       .probe                  = au1xpsc_ac97_probe,
+       .remove                 = au1xpsc_ac97_remove,
+       .playback = {
+               .rates          = AC97_RATES,
+               .formats        = AC97_FMTS,
+               .channels_min   = 2,
+               .channels_max   = 2,
+       },
+       .capture = {
+               .rates          = AC97_RATES,
+               .formats        = AC97_FMTS,
+               .channels_min   = 2,
+               .channels_max   = 2,
+       },
+       .ops = &au1xpsc_ac97_dai_ops,
+};
+EXPORT_SYMBOL_GPL(au1xpsc_ac97_dai);
+
+static int __devinit au1xpsc_ac97_drvprobe(struct platform_device *pdev)
+{
        int ret;
        struct resource *r;
        unsigned long sel;
+       struct au1xpsc_audio_data *wd;
 
        if (au1xpsc_ac97_workdata)
                return -EBUSY;
 
-       au1xpsc_ac97_workdata =
-               kzalloc(sizeof(struct au1xpsc_audio_data), GFP_KERNEL);
-       if (!au1xpsc_ac97_workdata)
+       wd = kzalloc(sizeof(struct au1xpsc_audio_data), GFP_KERNEL);
+       if (!wd)
                return -ENOMEM;
 
-       mutex_init(&au1xpsc_ac97_workdata->lock);
+       mutex_init(&wd->lock);
 
        r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (!r) {
@@ -321,81 +374,95 @@ static int au1xpsc_ac97_probe(struct platform_device *pdev,
        }
 
        ret = -EBUSY;
-       au1xpsc_ac97_workdata->ioarea =
-               request_mem_region(r->start, r->end - r->start + 1,
+       wd->ioarea = request_mem_region(r->start, r->end - r->start + 1,
                                        "au1xpsc_ac97");
-       if (!au1xpsc_ac97_workdata->ioarea)
+       if (!wd->ioarea)
                goto out0;
 
-       au1xpsc_ac97_workdata->mmio = ioremap(r->start, 0xffff);
-       if (!au1xpsc_ac97_workdata->mmio)
+       wd->mmio = ioremap(r->start, 0xffff);
+       if (!wd->mmio)
                goto out1;
 
        /* configuration: max dma trigger threshold, enable ac97 */
-       au1xpsc_ac97_workdata->cfg = PSC_AC97CFG_RT_FIFO8 |
-                                    PSC_AC97CFG_TT_FIFO8 |
-                                    PSC_AC97CFG_DE_ENABLE;
+       wd->cfg = PSC_AC97CFG_RT_FIFO8 | PSC_AC97CFG_TT_FIFO8 |
+                 PSC_AC97CFG_DE_ENABLE;
 
-       /* preserve PSC clock source set up by platform (dev.platform_data
-        * is already occupied by soc layer)
-        */
-       sel = au_readl(PSC_SEL(au1xpsc_ac97_workdata)) & PSC_SEL_CLK_MASK;
-       au_writel(PSC_CTRL_DISABLE, PSC_CTRL(au1xpsc_ac97_workdata));
+       /* preserve PSC clock source set up by platform  */
+       sel = au_readl(PSC_SEL(wd)) & PSC_SEL_CLK_MASK;
+       au_writel(PSC_CTRL_DISABLE, PSC_CTRL(wd));
        au_sync();
-       au_writel(0, PSC_SEL(au1xpsc_ac97_workdata));
+       au_writel(0, PSC_SEL(wd));
        au_sync();
-       au_writel(PSC_SEL_PS_AC97MODE | sel, PSC_SEL(au1xpsc_ac97_workdata));
+       au_writel(PSC_SEL_PS_AC97MODE | sel, PSC_SEL(wd));
        au_sync();
-       /* next up: cold reset.  Dont check for PSC-ready now since
-        * there may not be any codec clock yet.
-        */
 
-       return 0;
+       ret = snd_soc_register_dai(&au1xpsc_ac97_dai);
+       if (ret)
+               goto out1;
 
+       wd->dmapd = au1xpsc_pcm_add(pdev);
+       if (wd->dmapd) {
+               platform_set_drvdata(pdev, wd);
+               au1xpsc_ac97_workdata = wd;     /* MDEV */
+               return 0;
+       }
+
+       snd_soc_unregister_dai(&au1xpsc_ac97_dai);
 out1:
-       release_resource(au1xpsc_ac97_workdata->ioarea);
-       kfree(au1xpsc_ac97_workdata->ioarea);
+       release_resource(wd->ioarea);
+       kfree(wd->ioarea);
 out0:
-       kfree(au1xpsc_ac97_workdata);
-       au1xpsc_ac97_workdata = NULL;
+       kfree(wd);
        return ret;
 }
 
-static void au1xpsc_ac97_remove(struct platform_device *pdev,
-                               struct snd_soc_dai *dai)
+static int __devexit au1xpsc_ac97_drvremove(struct platform_device *pdev)
 {
+       struct au1xpsc_audio_data *wd = platform_get_drvdata(pdev);
+
+       if (wd->dmapd)
+               au1xpsc_pcm_destroy(wd->dmapd);
+
+       snd_soc_unregister_dai(&au1xpsc_ac97_dai);
+
        /* disable PSC completely */
-       au_writel(0, AC97_CFG(au1xpsc_ac97_workdata));
+       au_writel(0, AC97_CFG(wd));
        au_sync();
-       au_writel(PSC_CTRL_DISABLE, PSC_CTRL(au1xpsc_ac97_workdata));
+       au_writel(PSC_CTRL_DISABLE, PSC_CTRL(wd));
        au_sync();
 
-       iounmap(au1xpsc_ac97_workdata->mmio);
-       release_resource(au1xpsc_ac97_workdata->ioarea);
-       kfree(au1xpsc_ac97_workdata->ioarea);
-       kfree(au1xpsc_ac97_workdata);
-       au1xpsc_ac97_workdata = NULL;
+       iounmap(wd->mmio);
+       release_resource(wd->ioarea);
+       kfree(wd->ioarea);
+       kfree(wd);
+
+       au1xpsc_ac97_workdata = NULL;   /* MDEV */
+
+       return 0;
 }
 
-static int au1xpsc_ac97_suspend(struct snd_soc_dai *dai)
+#ifdef CONFIG_PM
+static int au1xpsc_ac97_drvsuspend(struct device *dev)
 {
+       struct au1xpsc_audio_data *wd = dev_get_drvdata(dev);
+
        /* save interesting registers and disable PSC */
-       au1xpsc_ac97_workdata->pm[0] =
-                       au_readl(PSC_SEL(au1xpsc_ac97_workdata));
+       wd->pm[0] = au_readl(PSC_SEL(wd));
 
-       au_writel(0, AC97_CFG(au1xpsc_ac97_workdata));
+       au_writel(0, AC97_CFG(wd));
        au_sync();
-       au_writel(PSC_CTRL_DISABLE, PSC_CTRL(au1xpsc_ac97_workdata));
+       au_writel(PSC_CTRL_DISABLE, PSC_CTRL(wd));
        au_sync();
 
        return 0;
 }
 
-static int au1xpsc_ac97_resume(struct snd_soc_dai *dai)
+static int au1xpsc_ac97_drvresume(struct device *dev)
 {
+       struct au1xpsc_audio_data *wd = dev_get_drvdata(dev);
+
        /* restore PSC clock config */
-       au_writel(au1xpsc_ac97_workdata->pm[0] | PSC_SEL_PS_AC97MODE,
-                       PSC_SEL(au1xpsc_ac97_workdata));
+       au_writel(wd->pm[0] | PSC_SEL_PS_AC97MODE, PSC_SEL(wd));
        au_sync();
 
        /* after this point the ac97 core will cold-reset the codec.
@@ -405,48 +472,44 @@ static int au1xpsc_ac97_resume(struct snd_soc_dai *dai)
        return 0;
 }
 
-static struct snd_soc_dai_ops au1xpsc_ac97_dai_ops = {
-       .trigger        = au1xpsc_ac97_trigger,
-       .hw_params      = au1xpsc_ac97_hw_params,
+static struct dev_pm_ops au1xpscac97_pmops = {
+       .suspend        = au1xpsc_ac97_drvsuspend,
+       .resume         = au1xpsc_ac97_drvresume,
 };
 
-struct snd_soc_dai au1xpsc_ac97_dai = {
-       .name                   = "au1xpsc_ac97",
-       .ac97_control           = 1,
-       .probe                  = au1xpsc_ac97_probe,
-       .remove                 = au1xpsc_ac97_remove,
-       .suspend                = au1xpsc_ac97_suspend,
-       .resume                 = au1xpsc_ac97_resume,
-       .playback = {
-               .rates          = AC97_RATES,
-               .formats        = AC97_FMTS,
-               .channels_min   = 2,
-               .channels_max   = 2,
-       },
-       .capture = {
-               .rates          = AC97_RATES,
-               .formats        = AC97_FMTS,
-               .channels_min   = 2,
-               .channels_max   = 2,
+#define AU1XPSCAC97_PMOPS &au1xpscac97_pmops
+
+#else
+
+#define AU1XPSCAC97_PMOPS NULL
+
+#endif
+
+static struct platform_driver au1xpsc_ac97_driver = {
+       .driver = {
+               .name   = "au1xpsc_ac97",
+               .owner  = THIS_MODULE,
+               .pm     = AU1XPSCAC97_PMOPS,
        },
-       .ops = &au1xpsc_ac97_dai_ops,
+       .probe          = au1xpsc_ac97_drvprobe,
+       .remove         = __devexit_p(au1xpsc_ac97_drvremove),
 };
-EXPORT_SYMBOL_GPL(au1xpsc_ac97_dai);
 
-static int __init au1xpsc_ac97_init(void)
+static int __init au1xpsc_ac97_load(void)
 {
        au1xpsc_ac97_workdata = NULL;
-       return snd_soc_register_dai(&au1xpsc_ac97_dai);
+       return platform_driver_register(&au1xpsc_ac97_driver);
 }
 
-static void __exit au1xpsc_ac97_exit(void)
+static void __exit au1xpsc_ac97_unload(void)
 {
-       snd_soc_unregister_dai(&au1xpsc_ac97_dai);
+       platform_driver_unregister(&au1xpsc_ac97_driver);
 }
 
-module_init(au1xpsc_ac97_init);
-module_exit(au1xpsc_ac97_exit);
+module_init(au1xpsc_ac97_load);
+module_exit(au1xpsc_ac97_unload);
 
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("Au12x0/Au1550 PSC AC97 ALSA ASoC audio driver");
-MODULE_AUTHOR("Manuel Lauss <manuel.lauss@gmail.com>");
+MODULE_AUTHOR("Manuel Lauss");
+
index bb58932..0cf2ca6 100644 (file)
@@ -2,7 +2,7 @@
  * Au12x0/Au1550 PSC ALSA ASoC audio support.
  *
  * (c) 2007-2008 MSC Vertriebsges.m.b.H.,
- *     Manuel Lauss <mano@roarinelk.homelinux.net>
+ *     Manuel Lauss <manuel.lauss@gmail.com>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -265,16 +265,52 @@ static int au1xpsc_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
 static int au1xpsc_i2s_probe(struct platform_device *pdev,
                             struct snd_soc_dai *dai)
 {
+       return  au1xpsc_i2s_workdata ? 0 : -ENODEV;
+}
+
+static void au1xpsc_i2s_remove(struct platform_device *pdev,
+                              struct snd_soc_dai *dai)
+{
+}
+
+static struct snd_soc_dai_ops au1xpsc_i2s_dai_ops = {
+       .trigger        = au1xpsc_i2s_trigger,
+       .hw_params      = au1xpsc_i2s_hw_params,
+       .set_fmt        = au1xpsc_i2s_set_fmt,
+};
+
+struct snd_soc_dai au1xpsc_i2s_dai = {
+       .name                   = "au1xpsc_i2s",
+       .probe                  = au1xpsc_i2s_probe,
+       .remove                 = au1xpsc_i2s_remove,
+       .playback = {
+               .rates          = AU1XPSC_I2S_RATES,
+               .formats        = AU1XPSC_I2S_FMTS,
+               .channels_min   = 2,
+               .channels_max   = 8,    /* 2 without external help */
+       },
+       .capture = {
+               .rates          = AU1XPSC_I2S_RATES,
+               .formats        = AU1XPSC_I2S_FMTS,
+               .channels_min   = 2,
+               .channels_max   = 8,    /* 2 without external help */
+       },
+       .ops = &au1xpsc_i2s_dai_ops,
+};
+EXPORT_SYMBOL(au1xpsc_i2s_dai);
+
+static int __init au1xpsc_i2s_drvprobe(struct platform_device *pdev)
+{
        struct resource *r;
        unsigned long sel;
        int ret;
+       struct au1xpsc_audio_data *wd;
 
        if (au1xpsc_i2s_workdata)
                return -EBUSY;
 
-       au1xpsc_i2s_workdata =
-               kzalloc(sizeof(struct au1xpsc_audio_data), GFP_KERNEL);
-       if (!au1xpsc_i2s_workdata)
+       wd = kzalloc(sizeof(struct au1xpsc_audio_data), GFP_KERNEL);
+       if (!wd)
                return -ENOMEM;
 
        r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -284,131 +320,146 @@ static int au1xpsc_i2s_probe(struct platform_device *pdev,
        }
 
        ret = -EBUSY;
-       au1xpsc_i2s_workdata->ioarea =
-               request_mem_region(r->start, r->end - r->start + 1,
+       wd->ioarea = request_mem_region(r->start, r->end - r->start + 1,
                                        "au1xpsc_i2s");
-       if (!au1xpsc_i2s_workdata->ioarea)
+       if (!wd->ioarea)
                goto out0;
 
-       au1xpsc_i2s_workdata->mmio = ioremap(r->start, 0xffff);
-       if (!au1xpsc_i2s_workdata->mmio)
+       wd->mmio = ioremap(r->start, 0xffff);
+       if (!wd->mmio)
                goto out1;
 
        /* preserve PSC clock source set up by platform (dev.platform_data
         * is already occupied by soc layer)
         */
-       sel = au_readl(PSC_SEL(au1xpsc_i2s_workdata)) & PSC_SEL_CLK_MASK;
-       au_writel(PSC_CTRL_DISABLE, PSC_CTRL(au1xpsc_i2s_workdata));
+       sel = au_readl(PSC_SEL(wd)) & PSC_SEL_CLK_MASK;
+       au_writel(PSC_CTRL_DISABLE, PSC_CTRL(wd));
        au_sync();
-       au_writel(PSC_SEL_PS_I2SMODE | sel, PSC_SEL(au1xpsc_i2s_workdata));
-       au_writel(0, I2S_CFG(au1xpsc_i2s_workdata));
+       au_writel(PSC_SEL_PS_I2SMODE | sel, PSC_SEL(wd));
+       au_writel(0, I2S_CFG(wd));
        au_sync();
 
        /* preconfigure: set max rx/tx fifo depths */
-       au1xpsc_i2s_workdata->cfg |=
-                       PSC_I2SCFG_RT_FIFO8 | PSC_I2SCFG_TT_FIFO8;
+       wd->cfg |= PSC_I2SCFG_RT_FIFO8 | PSC_I2SCFG_TT_FIFO8;
 
        /* don't wait for I2S core to become ready now; clocks may not
         * be running yet; depending on clock input for PSC a wait might
         * time out.
         */
 
-       return 0;
+       ret = snd_soc_register_dai(&au1xpsc_i2s_dai);
+       if (ret)
+               goto out1;
 
+       /* finally add the DMA device for this PSC */
+       wd->dmapd = au1xpsc_pcm_add(pdev);
+       if (wd->dmapd) {
+               platform_set_drvdata(pdev, wd);
+               au1xpsc_i2s_workdata = wd;
+               return 0;
+       }
+
+       snd_soc_unregister_dai(&au1xpsc_i2s_dai);
 out1:
-       release_resource(au1xpsc_i2s_workdata->ioarea);
-       kfree(au1xpsc_i2s_workdata->ioarea);
+       release_resource(wd->ioarea);
+       kfree(wd->ioarea);
 out0:
-       kfree(au1xpsc_i2s_workdata);
-       au1xpsc_i2s_workdata = NULL;
+       kfree(wd);
        return ret;
 }
 
-static void au1xpsc_i2s_remove(struct platform_device *pdev,
-                              struct snd_soc_dai *dai)
+static int __devexit au1xpsc_i2s_drvremove(struct platform_device *pdev)
 {
-       au_writel(0, I2S_CFG(au1xpsc_i2s_workdata));
+       struct au1xpsc_audio_data *wd = platform_get_drvdata(pdev);
+
+       if (wd->dmapd)
+               au1xpsc_pcm_destroy(wd->dmapd);
+
+       snd_soc_unregister_dai(&au1xpsc_i2s_dai);
+
+       au_writel(0, I2S_CFG(wd));
        au_sync();
-       au_writel(PSC_CTRL_DISABLE, PSC_CTRL(au1xpsc_i2s_workdata));
+       au_writel(PSC_CTRL_DISABLE, PSC_CTRL(wd));
        au_sync();
 
-       iounmap(au1xpsc_i2s_workdata->mmio);
-       release_resource(au1xpsc_i2s_workdata->ioarea);
-       kfree(au1xpsc_i2s_workdata->ioarea);
-       kfree(au1xpsc_i2s_workdata);
-       au1xpsc_i2s_workdata = NULL;
+       iounmap(wd->mmio);
+       release_resource(wd->ioarea);
+       kfree(wd->ioarea);
+       kfree(wd);
+
+       au1xpsc_i2s_workdata = NULL;    /* MDEV */
+
+       return 0;
 }
 
-static int au1xpsc_i2s_suspend(struct snd_soc_dai *cpu_dai)
+#ifdef CONFIG_PM
+static int au1xpsc_i2s_drvsuspend(struct device *dev)
 {
+       struct au1xpsc_audio_data *wd = dev_get_drvdata(dev);
+
        /* save interesting register and disable PSC */
-       au1xpsc_i2s_workdata->pm[0] =
-               au_readl(PSC_SEL(au1xpsc_i2s_workdata));
+       wd->pm[0] = au_readl(PSC_SEL(wd));
 
-       au_writel(0, I2S_CFG(au1xpsc_i2s_workdata));
+       au_writel(0, I2S_CFG(wd));
        au_sync();
-       au_writel(PSC_CTRL_DISABLE, PSC_CTRL(au1xpsc_i2s_workdata));
+       au_writel(PSC_CTRL_DISABLE, PSC_CTRL(wd));
        au_sync();
 
        return 0;
 }
 
-static int au1xpsc_i2s_resume(struct snd_soc_dai *cpu_dai)
+static int au1xpsc_i2s_drvresume(struct device *dev)
 {
+       struct au1xpsc_audio_data *wd = dev_get_drvdata(dev);
+
        /* select I2S mode and PSC clock */
-       au_writel(PSC_CTRL_DISABLE, PSC_CTRL(au1xpsc_i2s_workdata));
+       au_writel(PSC_CTRL_DISABLE, PSC_CTRL(wd));
        au_sync();
-       au_writel(0, PSC_SEL(au1xpsc_i2s_workdata));
+       au_writel(0, PSC_SEL(wd));
        au_sync();
-       au_writel(au1xpsc_i2s_workdata->pm[0],
-                       PSC_SEL(au1xpsc_i2s_workdata));
+       au_writel(wd->pm[0], PSC_SEL(wd));
        au_sync();
 
        return 0;
 }
 
-static struct snd_soc_dai_ops au1xpsc_i2s_dai_ops = {
-       .trigger        = au1xpsc_i2s_trigger,
-       .hw_params      = au1xpsc_i2s_hw_params,
-       .set_fmt        = au1xpsc_i2s_set_fmt,
+static struct dev_pm_ops au1xpsci2s_pmops = {
+       .suspend        = au1xpsc_i2s_drvsuspend,
+       .resume         = au1xpsc_i2s_drvresume,
 };
 
-struct snd_soc_dai au1xpsc_i2s_dai = {
-       .name                   = "au1xpsc_i2s",
-       .probe                  = au1xpsc_i2s_probe,
-       .remove                 = au1xpsc_i2s_remove,
-       .suspend                = au1xpsc_i2s_suspend,
-       .resume                 = au1xpsc_i2s_resume,
-       .playback = {
-               .rates          = AU1XPSC_I2S_RATES,
-               .formats        = AU1XPSC_I2S_FMTS,
-               .channels_min   = 2,
-               .channels_max   = 8,    /* 2 without external help */
-       },
-       .capture = {
-               .rates          = AU1XPSC_I2S_RATES,
-               .formats        = AU1XPSC_I2S_FMTS,
-               .channels_min   = 2,
-               .channels_max   = 8,    /* 2 without external help */
+#define AU1XPSCI2S_PMOPS &au1xpsci2s_pmops
+
+#else
+
+#define AU1XPSCI2S_PMOPS NULL
+
+#endif
+
+static struct platform_driver au1xpsc_i2s_driver = {
+       .driver         = {
+               .name   = "au1xpsc_i2s",
+               .owner  = THIS_MODULE,
+               .pm     = AU1XPSCI2S_PMOPS,
        },
-       .ops = &au1xpsc_i2s_dai_ops,
+       .probe          = au1xpsc_i2s_drvprobe,
+       .remove         = __devexit_p(au1xpsc_i2s_drvremove),
 };
-EXPORT_SYMBOL(au1xpsc_i2s_dai);
 
-static int __init au1xpsc_i2s_init(void)
+static int __init au1xpsc_i2s_load(void)
 {
        au1xpsc_i2s_workdata = NULL;
-       return snd_soc_register_dai(&au1xpsc_i2s_dai);
+       return platform_driver_register(&au1xpsc_i2s_driver);
 }
 
-static void __exit au1xpsc_i2s_exit(void)
+static void __exit au1xpsc_i2s_unload(void)
 {
-       snd_soc_unregister_dai(&au1xpsc_i2s_dai);
+       platform_driver_unregister(&au1xpsc_i2s_driver);
 }
 
-module_init(au1xpsc_i2s_init);
-module_exit(au1xpsc_i2s_exit);
+module_init(au1xpsc_i2s_load);
+module_exit(au1xpsc_i2s_unload);
 
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("Au12x0/Au1550 PSC I2S ALSA ASoC audio driver");
-MODULE_AUTHOR("Manuel Lauss <mano@roarinelk.homelinux.net>");
+MODULE_AUTHOR("Manuel Lauss");
index 3f474e8..32d3807 100644 (file)
@@ -2,7 +2,7 @@
  * Au12x0/Au1550 PSC ALSA ASoC audio support.
  *
  * (c) 2007-2008 MSC Vertriebsges.m.b.H.,
- *     Manuel Lauss <mano@roarinelk.homelinux.net>
+ *     Manuel Lauss <manuel.lauss@gmail.com>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -21,6 +21,10 @@ extern struct snd_soc_dai au1xpsc_i2s_dai;
 extern struct snd_soc_platform au1xpsc_soc_platform;
 extern struct snd_ac97_bus_ops soc_ac97_ops;
 
+/* DBDMA helpers */
+extern struct platform_device *au1xpsc_pcm_add(struct platform_device *pdev);
+extern void au1xpsc_pcm_destroy(struct platform_device *dmapd);
+
 struct au1xpsc_audio_data {
        void __iomem *mmio;
 
@@ -30,6 +34,7 @@ struct au1xpsc_audio_data {
        unsigned long pm[2];
        struct resource *ioarea;
        struct mutex lock;
+       struct platform_device *dmapd;
 };
 
 #define PCM_TX 0
index cd361e3..0f45a3f 100644 (file)
@@ -52,6 +52,7 @@ static int bf5xx_ad1836_hw_params(struct snd_pcm_substream *substream,
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
        struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
+       unsigned int channel_map[] = {0, 4, 1, 5, 2, 6, 3, 7};
        int ret = 0;
        /* set cpu DAI configuration */
        ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_DSP_A |
@@ -65,6 +66,12 @@ static int bf5xx_ad1836_hw_params(struct snd_pcm_substream *substream,
        if (ret < 0)
                return ret;
 
+       /* set cpu DAI channel mapping */
+       ret = snd_soc_dai_set_channel_map(cpu_dai, ARRAY_SIZE(channel_map),
+               channel_map, ARRAY_SIZE(channel_map), channel_map);
+       if (ret < 0)
+               return ret;
+
        return 0;
 }
 
index 08269e9..2ef1e50 100644 (file)
@@ -61,6 +61,7 @@ static int bf5xx_ad1938_hw_params(struct snd_pcm_substream *substream,
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
        struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
+       unsigned int channel_map[] = {0, 1, 2, 3, 4, 5, 6, 7};
        int ret = 0;
        /* set cpu DAI configuration */
        ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_DSP_A |
@@ -75,7 +76,13 @@ static int bf5xx_ad1938_hw_params(struct snd_pcm_substream *substream,
                return ret;
 
        /* set codec DAI slots, 8 channels, all channels are enabled */
-       ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xFF, 8);
+       ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xFF, 0xFF, 8, 32);
+       if (ret < 0)
+               return ret;
+
+       /* set cpu DAI channel mapping */
+       ret = snd_soc_dai_set_channel_map(cpu_dai, ARRAY_SIZE(channel_map),
+               channel_map, ARRAY_SIZE(channel_map), channel_map);
        if (ret < 0)
                return ret;
 
index 084b688..3e6ada0 100644 (file)
@@ -49,7 +49,6 @@ struct bf5xx_i2s_port {
        u16 rcr1;
        u16 tcr2;
        u16 rcr2;
-       int counter;
        int configured;
 };
 
@@ -133,16 +132,6 @@ static int bf5xx_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai,
        return ret;
 }
 
-static int bf5xx_i2s_startup(struct snd_pcm_substream *substream,
-                            struct snd_soc_dai *dai)
-{
-       pr_debug("%s enter\n", __func__);
-
-       /*this counter is used for counting how many pcm streams are opened*/
-       bf5xx_i2s.counter++;
-       return 0;
-}
-
 static int bf5xx_i2s_hw_params(struct snd_pcm_substream *substream,
                                struct snd_pcm_hw_params *params,
                                struct snd_soc_dai *dai)
@@ -201,9 +190,8 @@ static void bf5xx_i2s_shutdown(struct snd_pcm_substream *substream,
                               struct snd_soc_dai *dai)
 {
        pr_debug("%s enter\n", __func__);
-       bf5xx_i2s.counter--;
        /* No active stream, SPORT is allowed to be configured again. */
-       if (!bf5xx_i2s.counter)
+       if (!dai->active)
                bf5xx_i2s.configured = 0;
 }
 
@@ -284,7 +272,6 @@ static int bf5xx_i2s_resume(struct snd_soc_dai *dai)
        SNDRV_PCM_FMTBIT_S32_LE)
 
 static struct snd_soc_dai_ops bf5xx_i2s_dai_ops = {
-       .startup        = bf5xx_i2s_startup,
        .shutdown       = bf5xx_i2s_shutdown,
        .hw_params      = bf5xx_i2s_hw_params,
        .set_fmt        = bf5xx_i2s_set_dai_fmt,
index ccb5e82..a8c73cb 100644 (file)
@@ -43,7 +43,7 @@
 #include "bf5xx-tdm.h"
 #include "bf5xx-sport.h"
 
-#define PCM_BUFFER_MAX  0x10000
+#define PCM_BUFFER_MAX  0x8000
 #define FRAGMENT_SIZE_MIN  (4*1024)
 #define FRAGMENTS_MIN  2
 #define FRAGMENTS_MAX  32
@@ -177,6 +177,9 @@ out:
 static int bf5xx_pcm_copy(struct snd_pcm_substream *substream, int channel,
        snd_pcm_uframes_t pos, void *buf, snd_pcm_uframes_t count)
 {
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct sport_device *sport = runtime->private_data;
+       struct bf5xx_tdm_port *tdm_port = sport->private_data;
        unsigned int *src;
        unsigned int *dst;
        int i;
@@ -188,7 +191,7 @@ static int bf5xx_pcm_copy(struct snd_pcm_substream *substream, int channel,
                dst += pos * 8;
                while (count--) {
                        for (i = 0; i < substream->runtime->channels; i++)
-                               *(dst + i) = *src++;
+                               *(dst + tdm_port->tx_map[i]) = *src++;
                        dst += 8;
                }
        } else {
@@ -198,7 +201,7 @@ static int bf5xx_pcm_copy(struct snd_pcm_substream *substream, int channel,
                src += pos * 8;
                while (count--) {
                        for (i = 0; i < substream->runtime->channels; i++)
-                               *dst++ = *(src+i);
+                               *dst++ = *(src + tdm_port->rx_map[i]);
                        src += 8;
                }
        }
index ff546e9..4b36012 100644 (file)
 #include "bf5xx-sport.h"
 #include "bf5xx-tdm.h"
 
-struct bf5xx_tdm_port {
-       u16 tcr1;
-       u16 rcr1;
-       u16 tcr2;
-       u16 rcr2;
-       int configured;
-};
-
 static struct bf5xx_tdm_port bf5xx_tdm;
 static int sport_num = CONFIG_SND_BF5XX_SPORT_NUM;
 
@@ -181,6 +173,40 @@ static void bf5xx_tdm_shutdown(struct snd_pcm_substream *substream,
                bf5xx_tdm.configured = 0;
 }
 
+static int bf5xx_tdm_set_channel_map(struct snd_soc_dai *dai,
+               unsigned int tx_num, unsigned int *tx_slot,
+               unsigned int rx_num, unsigned int *rx_slot)
+{
+       int i;
+       unsigned int slot;
+       unsigned int tx_mapped = 0, rx_mapped = 0;
+
+       if ((tx_num > BFIN_TDM_DAI_MAX_SLOTS) ||
+                       (rx_num > BFIN_TDM_DAI_MAX_SLOTS))
+               return -EINVAL;
+
+       for (i = 0; i < tx_num; i++) {
+               slot = tx_slot[i];
+               if ((slot < BFIN_TDM_DAI_MAX_SLOTS) &&
+                               (!(tx_mapped & (1 << slot)))) {
+                       bf5xx_tdm.tx_map[i] = slot;
+                       tx_mapped |= 1 << slot;
+               } else
+                       return -EINVAL;
+       }
+       for (i = 0; i < rx_num; i++) {
+               slot = rx_slot[i];
+               if ((slot < BFIN_TDM_DAI_MAX_SLOTS) &&
+                               (!(rx_mapped & (1 << slot)))) {
+                       bf5xx_tdm.rx_map[i] = slot;
+                       rx_mapped |= 1 << slot;
+               } else
+                       return -EINVAL;
+       }
+
+       return 0;
+}
+
 #ifdef CONFIG_PM
 static int bf5xx_tdm_suspend(struct snd_soc_dai *dai)
 {
@@ -235,6 +261,7 @@ static struct snd_soc_dai_ops bf5xx_tdm_dai_ops = {
        .hw_params      = bf5xx_tdm_hw_params,
        .set_fmt        = bf5xx_tdm_set_dai_fmt,
        .shutdown       = bf5xx_tdm_shutdown,
+       .set_channel_map   = bf5xx_tdm_set_channel_map,
 };
 
 struct snd_soc_dai bf5xx_tdm_dai = {
@@ -300,6 +327,8 @@ static int __devinit bfin_tdm_probe(struct platform_device *pdev)
                pr_err("Failed to register DAI: %d\n", ret);
                goto sport_config_err;
        }
+
+       sport_handle->private_data = &bf5xx_tdm;
        return 0;
 
 sport_config_err:
index 618ec3d..04189a1 100644 (file)
@@ -9,6 +9,17 @@
 #ifndef _BF5XX_TDM_H
 #define _BF5XX_TDM_H
 
+#define BFIN_TDM_DAI_MAX_SLOTS 8
+struct bf5xx_tdm_port {
+       u16 tcr1;
+       u16 rcr1;
+       u16 tcr2;
+       u16 rcr2;
+       unsigned int tx_map[BFIN_TDM_DAI_MAX_SLOTS];
+       unsigned int rx_map[BFIN_TDM_DAI_MAX_SLOTS];
+       int configured;
+};
+
 extern struct snd_soc_dai bf5xx_tdm_dai;
 
 #endif
index 0edca93..52b005f 100644 (file)
@@ -15,10 +15,12 @@ config SND_SOC_ALL_CODECS
        select SND_SOC_AD1836 if SPI_MASTER
        select SND_SOC_AD1938 if SPI_MASTER
        select SND_SOC_AD1980 if SND_SOC_AC97_BUS
+       select SND_SOC_ADS117X
        select SND_SOC_AD73311 if I2C
        select SND_SOC_AK4104 if SPI_MASTER
        select SND_SOC_AK4535 if I2C
        select SND_SOC_AK4642 if I2C
+       select SND_SOC_AK4671 if I2C
        select SND_SOC_CS4270 if I2C
        select SND_SOC_MAX9877 if I2C
        select SND_SOC_PCM3008
@@ -28,6 +30,8 @@ config SND_SOC_ALL_CODECS
        select SND_SOC_TLV320AIC23 if I2C
        select SND_SOC_TLV320AIC26 if SPI_MASTER
        select SND_SOC_TLV320AIC3X if I2C
+       select SND_SOC_TPA6130A2 if I2C
+       select SND_SOC_TLV320DAC33 if I2C
        select SND_SOC_TWL4030 if TWL4030_CORE
        select SND_SOC_UDA134X
        select SND_SOC_UDA1380 if I2C
@@ -36,6 +40,8 @@ config SND_SOC_ALL_CODECS
        select SND_SOC_WM8510 if SND_SOC_I2C_AND_SPI
        select SND_SOC_WM8523 if I2C
        select SND_SOC_WM8580 if I2C
+       select SND_SOC_WM8711 if SND_SOC_I2C_AND_SPI
+       select SND_SOC_WM8727
        select SND_SOC_WM8728 if SND_SOC_I2C_AND_SPI
        select SND_SOC_WM8731 if SND_SOC_I2C_AND_SPI
        select SND_SOC_WM8750 if SND_SOC_I2C_AND_SPI
@@ -86,6 +92,9 @@ config SND_SOC_AD1980
 
 config SND_SOC_AD73311
        tristate
+       
+config SND_SOC_ADS117X
+       tristate
 
 config SND_SOC_AK4104
        tristate
@@ -96,6 +105,9 @@ config SND_SOC_AK4535
 config SND_SOC_AK4642
        tristate
 
+config SND_SOC_AK4671
+       tristate
+
 # Cirrus Logic CS4270 Codec
 config SND_SOC_CS4270
        tristate
@@ -136,7 +148,11 @@ config SND_SOC_TLV320AIC26
 config SND_SOC_TLV320AIC3X
        tristate
 
+config SND_SOC_TLV320DAC33
+       tristate
+
 config SND_SOC_TWL4030
+       select TWL4030_CODEC
        tristate
 
 config SND_SOC_UDA134X
@@ -160,6 +176,12 @@ config SND_SOC_WM8523
 config SND_SOC_WM8580
        tristate
 
+config SND_SOC_WM8711
+       tristate
+
+config SND_SOC_WM8727
+       tristate
+
 config SND_SOC_WM8728
        tristate
 
@@ -220,3 +242,6 @@ config SND_SOC_WM9713
 # Amp
 config SND_SOC_MAX9877
        tristate
+
+config SND_SOC_TPA6130A2
+       tristate
index fb4af28..dbaecb1 100644 (file)
@@ -3,9 +3,11 @@ snd-soc-ad1836-objs := ad1836.o
 snd-soc-ad1938-objs := ad1938.o
 snd-soc-ad1980-objs := ad1980.o
 snd-soc-ad73311-objs := ad73311.o
+snd-soc-ads117x-objs := ads117x.o
 snd-soc-ak4104-objs := ak4104.o
 snd-soc-ak4535-objs := ak4535.o
 snd-soc-ak4642-objs := ak4642.o
+snd-soc-ak4671-objs := ak4671.o
 snd-soc-cs4270-objs := cs4270.o
 snd-soc-cx20442-objs := cx20442.o
 snd-soc-l3-objs := l3.o
@@ -16,6 +18,7 @@ snd-soc-stac9766-objs := stac9766.o
 snd-soc-tlv320aic23-objs := tlv320aic23.o
 snd-soc-tlv320aic26-objs := tlv320aic26.o
 snd-soc-tlv320aic3x-objs := tlv320aic3x.o
+snd-soc-tlv320dac33-objs := tlv320dac33.o
 snd-soc-twl4030-objs := twl4030.o
 snd-soc-uda134x-objs := uda134x.o
 snd-soc-uda1380-objs := uda1380.o
@@ -24,6 +27,8 @@ snd-soc-wm8400-objs := wm8400.o
 snd-soc-wm8510-objs := wm8510.o
 snd-soc-wm8523-objs := wm8523.o
 snd-soc-wm8580-objs := wm8580.o
+snd-soc-wm8711-objs := wm8711.o
+snd-soc-wm8727-objs := wm8727.o
 snd-soc-wm8728-objs := wm8728.o
 snd-soc-wm8731-objs := wm8731.o
 snd-soc-wm8750-objs := wm8750.o
@@ -47,15 +52,18 @@ snd-soc-wm-hubs-objs := wm_hubs.o
 
 # Amp
 snd-soc-max9877-objs := max9877.o
+snd-soc-tpa6130a2-objs := tpa6130a2.o
 
 obj-$(CONFIG_SND_SOC_AC97_CODEC)       += snd-soc-ac97.o
 obj-$(CONFIG_SND_SOC_AD1836)   += snd-soc-ad1836.o
 obj-$(CONFIG_SND_SOC_AD1938)   += snd-soc-ad1938.o
 obj-$(CONFIG_SND_SOC_AD1980)   += snd-soc-ad1980.o
 obj-$(CONFIG_SND_SOC_AD73311) += snd-soc-ad73311.o
+obj-$(CONFIG_SND_SOC_ADS117X)  += snd-soc-ads117x.o
 obj-$(CONFIG_SND_SOC_AK4104)   += snd-soc-ak4104.o
 obj-$(CONFIG_SND_SOC_AK4535)   += snd-soc-ak4535.o
 obj-$(CONFIG_SND_SOC_AK4642)   += snd-soc-ak4642.o
+obj-$(CONFIG_SND_SOC_AK4671)   += snd-soc-ak4671.o
 obj-$(CONFIG_SND_SOC_CS4270)   += snd-soc-cs4270.o
 obj-$(CONFIG_SND_SOC_CX20442)  += snd-soc-cx20442.o
 obj-$(CONFIG_SND_SOC_L3)       += snd-soc-l3.o
@@ -66,6 +74,7 @@ obj-$(CONFIG_SND_SOC_STAC9766)        += snd-soc-stac9766.o
 obj-$(CONFIG_SND_SOC_TLV320AIC23)      += snd-soc-tlv320aic23.o
 obj-$(CONFIG_SND_SOC_TLV320AIC26)      += snd-soc-tlv320aic26.o
 obj-$(CONFIG_SND_SOC_TLV320AIC3X)      += snd-soc-tlv320aic3x.o
+obj-$(CONFIG_SND_SOC_TLV320DAC33)      += snd-soc-tlv320dac33.o
 obj-$(CONFIG_SND_SOC_TWL4030)  += snd-soc-twl4030.o
 obj-$(CONFIG_SND_SOC_UDA134X)  += snd-soc-uda134x.o
 obj-$(CONFIG_SND_SOC_UDA1380)  += snd-soc-uda1380.o
@@ -74,6 +83,8 @@ obj-$(CONFIG_SND_SOC_WM8400)  += snd-soc-wm8400.o
 obj-$(CONFIG_SND_SOC_WM8510)   += snd-soc-wm8510.o
 obj-$(CONFIG_SND_SOC_WM8523)   += snd-soc-wm8523.o
 obj-$(CONFIG_SND_SOC_WM8580)   += snd-soc-wm8580.o
+obj-$(CONFIG_SND_SOC_WM8711)   += snd-soc-wm8711.o
+obj-$(CONFIG_SND_SOC_WM8727)   += snd-soc-wm8727.o
 obj-$(CONFIG_SND_SOC_WM8728)   += snd-soc-wm8728.o
 obj-$(CONFIG_SND_SOC_WM8731)   += snd-soc-wm8731.o
 obj-$(CONFIG_SND_SOC_WM8750)   += snd-soc-wm8750.o
@@ -97,3 +108,4 @@ obj-$(CONFIG_SND_SOC_WM_HUBS)        += snd-soc-wm-hubs.o
 
 # Amp
 obj-$(CONFIG_SND_SOC_MAX9877)  += snd-soc-max9877.o
+obj-$(CONFIG_SND_SOC_TPA6130A2)        += snd-soc-tpa6130a2.o
index 932299b..69bd0ac 100644 (file)
@@ -117,9 +117,6 @@ static int ac97_soc_probe(struct platform_device *pdev)
        if (ret < 0)
                goto bus_err;
 
-       ret = snd_soc_init_card(socdev);
-       if (ret < 0)
-               goto bus_err;
        return 0;
 
 bus_err:
index c48485f..2c18e3d 100644 (file)
@@ -385,19 +385,7 @@ static int ad1836_probe(struct platform_device *pdev)
        snd_soc_dapm_new_controls(codec, ad1836_dapm_widgets,
                                  ARRAY_SIZE(ad1836_dapm_widgets));
        snd_soc_dapm_add_routes(codec, audio_paths, ARRAY_SIZE(audio_paths));
-       snd_soc_dapm_new_widgets(codec);
 
-       ret = snd_soc_init_card(socdev);
-       if (ret < 0) {
-               dev_err(codec->dev, "failed to register card: %d\n", ret);
-               goto card_err;
-       }
-
-       return ret;
-
-card_err:
-       snd_soc_free_pcms(socdev);
-       snd_soc_dapm_free(socdev);
 pcm_err:
        return ret;
 }
index 34b30ef..5d48918 100644 (file)
@@ -592,21 +592,9 @@ static int ad1938_probe(struct platform_device *pdev)
        snd_soc_dapm_new_controls(codec, ad1938_dapm_widgets,
                                  ARRAY_SIZE(ad1938_dapm_widgets));
        snd_soc_dapm_add_routes(codec, audio_paths, ARRAY_SIZE(audio_paths));
-       snd_soc_dapm_new_widgets(codec);
 
        ad1938_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
-       ret = snd_soc_init_card(socdev);
-       if (ret < 0) {
-               dev_err(codec->dev, "failed to register card: %d\n", ret);
-               goto card_err;
-       }
-
-       return ret;
-
-card_err:
-       snd_soc_free_pcms(socdev);
-       snd_soc_dapm_free(socdev);
 pcm_err:
        return ret;
 }
index d7440a9..39c0f75 100644 (file)
@@ -257,11 +257,6 @@ static int ad1980_soc_probe(struct platform_device *pdev)
 
        snd_soc_add_controls(codec, ad1980_snd_ac97_controls,
                                ARRAY_SIZE(ad1980_snd_ac97_controls));
-       ret = snd_soc_init_card(socdev);
-       if (ret < 0) {
-               printk(KERN_ERR "ad1980: failed to register card\n");
-               goto reset_err;
-       }
 
        return 0;
 
index e61dac5..d2fcc60 100644 (file)
@@ -64,16 +64,8 @@ static int ad73311_soc_probe(struct platform_device *pdev)
                goto pcm_err;
        }
 
-       ret = snd_soc_init_card(socdev);
-       if (ret < 0) {
-               printk(KERN_ERR "ad73311: failed to register card\n");
-               goto register_err;
-       }
-
        return ret;
 
-register_err:
-       snd_soc_free_pcms(socdev);
 pcm_err:
        kfree(socdev->card->codec);
        socdev->card->codec = NULL;
diff --git a/sound/soc/codecs/ads117x.c b/sound/soc/codecs/ads117x.c
new file mode 100644 (file)
index 0000000..cc96411
--- /dev/null
@@ -0,0 +1,123 @@
+/*
+ * ads117x.c  --  Driver for ads1174/8 ADC chips
+ *
+ * Copyright 2009 ShotSpotter Inc.
+ * Author: Graeme Gregory <gg@slimlogic.co.uk>
+ *
+ *  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/kernel.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+
+#include "ads117x.h"
+
+#define ADS117X_RATES (SNDRV_PCM_RATE_8000_48000)
+
+#define ADS117X_FORMATS (SNDRV_PCM_FMTBIT_S16_LE)
+
+struct snd_soc_dai ads117x_dai = {
+/* ADC */
+       .name = "ADS117X ADC",
+       .id = 1,
+       .capture = {
+               .stream_name = "Capture",
+               .channels_min = 1,
+               .channels_max = 32,
+               .rates = ADS117X_RATES,
+               .formats = ADS117X_FORMATS,},
+};
+EXPORT_SYMBOL_GPL(ads117x_dai);
+
+static int ads117x_probe(struct platform_device *pdev)
+{
+       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+       struct snd_soc_codec *codec;
+       int ret;
+
+       codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
+       if (codec == NULL)
+               return -ENOMEM;
+
+       socdev->card->codec = codec;
+       mutex_init(&codec->mutex);
+       INIT_LIST_HEAD(&codec->dapm_widgets);
+       INIT_LIST_HEAD(&codec->dapm_paths);
+       codec->name = "ADS117X";
+       codec->owner = THIS_MODULE;
+       codec->dai = &ads117x_dai;
+       codec->num_dai = 1;
+
+       /* register pcms */
+       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
+       if (ret < 0) {
+               printk(KERN_ERR "ads117x: failed to create pcms\n");
+               kfree(codec);
+               return ret;
+       }
+
+       return 0;
+}
+
+static int ads117x_remove(struct platform_device *pdev)
+{
+       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+       struct snd_soc_codec *codec = socdev->card->codec;
+
+       snd_soc_free_pcms(socdev);
+       kfree(codec);
+
+       return 0;
+}
+
+struct snd_soc_codec_device soc_codec_dev_ads117x = {
+       .probe =        ads117x_probe,
+       .remove =       ads117x_remove,
+};
+EXPORT_SYMBOL_GPL(soc_codec_dev_ads117x);
+
+static __devinit int ads117x_platform_probe(struct platform_device *pdev)
+{
+       ads117x_dai.dev = &pdev->dev;
+       return snd_soc_register_dai(&ads117x_dai);
+}
+
+static int __devexit ads117x_platform_remove(struct platform_device *pdev)
+{
+       snd_soc_unregister_dai(&ads117x_dai);
+       return 0;
+}
+
+static struct platform_driver ads117x_codec_driver = {
+       .driver = {
+                       .name = "ads117x",
+                       .owner = THIS_MODULE,
+       },
+
+       .probe = ads117x_platform_probe,
+       .remove = __devexit_p(ads117x_platform_remove),
+};
+
+static int __init ads117x_init(void)
+{
+       return platform_driver_register(&ads117x_codec_driver);
+}
+module_init(ads117x_init);
+
+static void __exit ads117x_exit(void)
+{
+       platform_driver_unregister(&ads117x_codec_driver);
+}
+module_exit(ads117x_exit);
+
+MODULE_DESCRIPTION("ASoC ads117x driver");
+MODULE_AUTHOR("Graeme Gregory");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/ads117x.h b/sound/soc/codecs/ads117x.h
new file mode 100644 (file)
index 0000000..dbcf50e
--- /dev/null
@@ -0,0 +1,13 @@
+/*
+ * ads117x.h  --  Driver for ads1174/8 ADC chips
+ *
+ * Copyright 2009 ShotSpotter Inc.
+ * Author: Graeme Gregory <gg@slimlogic.co.uk>
+ *
+ *  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.
+ */
+extern struct snd_soc_dai ads117x_dai;
+extern struct snd_soc_codec_device soc_codec_dev_ads117x;
index 4d47bc4..3a14c6f 100644 (file)
@@ -313,14 +313,6 @@ static int ak4104_probe(struct platform_device *pdev)
                return ret;
        }
 
-       /* Register the socdev */
-       ret = snd_soc_init_card(socdev);
-       if (ret < 0) {
-               dev_err(codec->dev, "failed to register card\n");
-               snd_soc_free_pcms(socdev);
-               return ret;
-       }
-
        return 0;
 }
 
index 0abec0d..ff96656 100644 (file)
@@ -294,7 +294,6 @@ static int ak4535_add_widgets(struct snd_soc_codec *codec)
 
        snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
 
-       snd_soc_dapm_new_widgets(codec);
        return 0;
 }
 
@@ -485,17 +484,9 @@ static int ak4535_init(struct snd_soc_device *socdev)
        snd_soc_add_controls(codec, ak4535_snd_controls,
                                ARRAY_SIZE(ak4535_snd_controls));
        ak4535_add_widgets(codec);
-       ret = snd_soc_init_card(socdev);
-       if (ret < 0) {
-               printk(KERN_ERR "ak4535: failed to register card\n");
-               goto card_err;
-       }
 
        return ret;
 
-card_err:
-       snd_soc_free_pcms(socdev);
-       snd_soc_dapm_free(socdev);
 pcm_err:
        kfree(codec->reg_cache);
 
index e057c7b..b69861d 100644 (file)
@@ -442,18 +442,9 @@ static int ak4642_probe(struct platform_device *pdev)
                goto pcm_err;
        }
 
-       ret = snd_soc_init_card(socdev);
-       if (ret < 0) {
-               printk(KERN_ERR "ak4642: failed to register card\n");
-               goto card_err;
-       }
-
        dev_info(&pdev->dev, "AK4642 Audio Codec %s", AK4642_VERSION);
        return ret;
 
-card_err:
-       snd_soc_free_pcms(socdev);
-       snd_soc_dapm_free(socdev);
 pcm_err:
        return ret;
 
diff --git a/sound/soc/codecs/ak4671.c b/sound/soc/codecs/ak4671.c
new file mode 100644 (file)
index 0000000..82fca28
--- /dev/null
@@ -0,0 +1,815 @@
+/*
+ * ak4671.c  --  audio driver for AK4671
+ *
+ * Copyright (C) 2009 Samsung Electronics Co.Ltd
+ * Author: Joonyoung Shim <jy0922.shim@samsung.com>
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/delay.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+
+#include "ak4671.h"
+
+static struct snd_soc_codec *ak4671_codec;
+
+/* codec private data */
+struct ak4671_priv {
+       struct snd_soc_codec codec;
+       u8 reg_cache[AK4671_CACHEREGNUM];
+};
+
+/* ak4671 register cache & default register settings */
+static const u8 ak4671_reg[AK4671_CACHEREGNUM] = {
+       0x00,   /* AK4671_AD_DA_POWER_MANAGEMENT        (0x00)  */
+       0xf6,   /* AK4671_PLL_MODE_SELECT0              (0x01)  */
+       0x00,   /* AK4671_PLL_MODE_SELECT1              (0x02)  */
+       0x02,   /* AK4671_FORMAT_SELECT                 (0x03)  */
+       0x00,   /* AK4671_MIC_SIGNAL_SELECT             (0x04)  */
+       0x55,   /* AK4671_MIC_AMP_GAIN                  (0x05)  */
+       0x00,   /* AK4671_MIXING_POWER_MANAGEMENT0      (0x06)  */
+       0x00,   /* AK4671_MIXING_POWER_MANAGEMENT1      (0x07)  */
+       0xb5,   /* AK4671_OUTPUT_VOLUME_CONTROL         (0x08)  */
+       0x00,   /* AK4671_LOUT1_SIGNAL_SELECT           (0x09)  */
+       0x00,   /* AK4671_ROUT1_SIGNAL_SELECT           (0x0a)  */
+       0x00,   /* AK4671_LOUT2_SIGNAL_SELECT           (0x0b)  */
+       0x00,   /* AK4671_ROUT2_SIGNAL_SELECT           (0x0c)  */
+       0x00,   /* AK4671_LOUT3_SIGNAL_SELECT           (0x0d)  */
+       0x00,   /* AK4671_ROUT3_SIGNAL_SELECT           (0x0e)  */
+       0x00,   /* AK4671_LOUT1_POWER_MANAGERMENT       (0x0f)  */
+       0x00,   /* AK4671_LOUT2_POWER_MANAGERMENT       (0x10)  */
+       0x80,   /* AK4671_LOUT3_POWER_MANAGERMENT       (0x11)  */
+       0x91,   /* AK4671_LCH_INPUT_VOLUME_CONTROL      (0x12)  */
+       0x91,   /* AK4671_RCH_INPUT_VOLUME_CONTROL      (0x13)  */
+       0xe1,   /* AK4671_ALC_REFERENCE_SELECT          (0x14)  */
+       0x00,   /* AK4671_DIGITAL_MIXING_CONTROL        (0x15)  */
+       0x00,   /* AK4671_ALC_TIMER_SELECT              (0x16)  */
+       0x00,   /* AK4671_ALC_MODE_CONTROL              (0x17)  */
+       0x02,   /* AK4671_MODE_CONTROL1                 (0x18)  */
+       0x01,   /* AK4671_MODE_CONTROL2                 (0x19)  */
+       0x18,   /* AK4671_LCH_OUTPUT_VOLUME_CONTROL     (0x1a)  */
+       0x18,   /* AK4671_RCH_OUTPUT_VOLUME_CONTROL     (0x1b)  */
+       0x00,   /* AK4671_SIDETONE_A_CONTROL            (0x1c)  */
+       0x02,   /* AK4671_DIGITAL_FILTER_SELECT         (0x1d)  */
+       0x00,   /* AK4671_FIL3_COEFFICIENT0             (0x1e)  */
+       0x00,   /* AK4671_FIL3_COEFFICIENT1             (0x1f)  */
+       0x00,   /* AK4671_FIL3_COEFFICIENT2             (0x20)  */
+       0x00,   /* AK4671_FIL3_COEFFICIENT3             (0x21)  */
+       0x00,   /* AK4671_EQ_COEFFICIENT0               (0x22)  */
+       0x00,   /* AK4671_EQ_COEFFICIENT1               (0x23)  */
+       0x00,   /* AK4671_EQ_COEFFICIENT2               (0x24)  */
+       0x00,   /* AK4671_EQ_COEFFICIENT3               (0x25)  */
+       0x00,   /* AK4671_EQ_COEFFICIENT4               (0x26)  */
+       0x00,   /* AK4671_EQ_COEFFICIENT5               (0x27)  */
+       0xa9,   /* AK4671_FIL1_COEFFICIENT0             (0x28)  */
+       0x1f,   /* AK4671_FIL1_COEFFICIENT1             (0x29)  */
+       0xad,   /* AK4671_FIL1_COEFFICIENT2             (0x2a)  */
+       0x20,   /* AK4671_FIL1_COEFFICIENT3             (0x2b)  */
+       0x00,   /* AK4671_FIL2_COEFFICIENT0             (0x2c)  */
+       0x00,   /* AK4671_FIL2_COEFFICIENT1             (0x2d)  */
+       0x00,   /* AK4671_FIL2_COEFFICIENT2             (0x2e)  */
+       0x00,   /* AK4671_FIL2_COEFFICIENT3             (0x2f)  */
+       0x00,   /* AK4671_DIGITAL_FILTER_SELECT2        (0x30)  */
+       0x00,   /* this register not used                       */
+       0x00,   /* AK4671_E1_COEFFICIENT0               (0x32)  */
+       0x00,   /* AK4671_E1_COEFFICIENT1               (0x33)  */
+       0x00,   /* AK4671_E1_COEFFICIENT2               (0x34)  */
+       0x00,   /* AK4671_E1_COEFFICIENT3               (0x35)  */
+       0x00,   /* AK4671_E1_COEFFICIENT4               (0x36)  */
+       0x00,   /* AK4671_E1_COEFFICIENT5               (0x37)  */
+       0x00,   /* AK4671_E2_COEFFICIENT0               (0x38)  */
+       0x00,   /* AK4671_E2_COEFFICIENT1               (0x39)  */
+       0x00,   /* AK4671_E2_COEFFICIENT2               (0x3a)  */
+       0x00,   /* AK4671_E2_COEFFICIENT3               (0x3b)  */
+       0x00,   /* AK4671_E2_COEFFICIENT4               (0x3c)  */
+       0x00,   /* AK4671_E2_COEFFICIENT5               (0x3d)  */
+       0x00,   /* AK4671_E3_COEFFICIENT0               (0x3e)  */
+       0x00,   /* AK4671_E3_COEFFICIENT1               (0x3f)  */
+       0x00,   /* AK4671_E3_COEFFICIENT2               (0x40)  */
+       0x00,   /* AK4671_E3_COEFFICIENT3               (0x41)  */
+       0x00,   /* AK4671_E3_COEFFICIENT4               (0x42)  */
+       0x00,   /* AK4671_E3_COEFFICIENT5               (0x43)  */
+       0x00,   /* AK4671_E4_COEFFICIENT0               (0x44)  */
+       0x00,   /* AK4671_E4_COEFFICIENT1               (0x45)  */
+       0x00,   /* AK4671_E4_COEFFICIENT2               (0x46)  */
+       0x00,   /* AK4671_E4_COEFFICIENT3               (0x47)  */
+       0x00,   /* AK4671_E4_COEFFICIENT4               (0x48)  */
+       0x00,   /* AK4671_E4_COEFFICIENT5               (0x49)  */
+       0x00,   /* AK4671_E5_COEFFICIENT0               (0x4a)  */
+       0x00,   /* AK4671_E5_COEFFICIENT1               (0x4b)  */
+       0x00,   /* AK4671_E5_COEFFICIENT2               (0x4c)  */
+       0x00,   /* AK4671_E5_COEFFICIENT3               (0x4d)  */
+       0x00,   /* AK4671_E5_COEFFICIENT4               (0x4e)  */
+       0x00,   /* AK4671_E5_COEFFICIENT5               (0x4f)  */
+       0x88,   /* AK4671_EQ_CONTROL_250HZ_100HZ        (0x50)  */
+       0x88,   /* AK4671_EQ_CONTROL_3500HZ_1KHZ        (0x51)  */
+       0x08,   /* AK4671_EQ_CONTRO_10KHZ               (0x52)  */
+       0x00,   /* AK4671_PCM_IF_CONTROL0               (0x53)  */
+       0x00,   /* AK4671_PCM_IF_CONTROL1               (0x54)  */
+       0x00,   /* AK4671_PCM_IF_CONTROL2               (0x55)  */
+       0x18,   /* AK4671_DIGITAL_VOLUME_B_CONTROL      (0x56)  */
+       0x18,   /* AK4671_DIGITAL_VOLUME_C_CONTROL      (0x57)  */
+       0x00,   /* AK4671_SIDETONE_VOLUME_CONTROL       (0x58)  */
+       0x00,   /* AK4671_DIGITAL_MIXING_CONTROL2       (0x59)  */
+       0x00,   /* AK4671_SAR_ADC_CONTROL               (0x5a)  */
+};
+
+/*
+ * LOUT1/ROUT1 output volume control:
+ * from -24 to 6 dB in 6 dB steps (mute instead of -30 dB)
+ */
+static DECLARE_TLV_DB_SCALE(out1_tlv, -3000, 600, 1);
+
+/*
+ * LOUT2/ROUT2 output volume control:
+ * from -33 to 6 dB in 3 dB steps (mute instead of -33 dB)
+ */
+static DECLARE_TLV_DB_SCALE(out2_tlv, -3300, 300, 1);
+
+/*
+ * LOUT3/ROUT3 output volume control:
+ * from -6 to 3 dB in 3 dB steps
+ */
+static DECLARE_TLV_DB_SCALE(out3_tlv, -600, 300, 0);
+
+/*
+ * Mic amp gain control:
+ * from -15 to 30 dB in 3 dB steps
+ * REVISIT: The actual min value(0x01) is -12 dB and the reg value 0x00 is not
+ * available
+ */
+static DECLARE_TLV_DB_SCALE(mic_amp_tlv, -1500, 300, 0);
+
+static const struct snd_kcontrol_new ak4671_snd_controls[] = {
+       /* Common playback gain controls */
+       SOC_SINGLE_TLV("Line Output1 Playback Volume",
+                       AK4671_OUTPUT_VOLUME_CONTROL, 0, 0x6, 0, out1_tlv),
+       SOC_SINGLE_TLV("Headphone Output2 Playback Volume",
+                       AK4671_OUTPUT_VOLUME_CONTROL, 4, 0xd, 0, out2_tlv),
+       SOC_SINGLE_TLV("Line Output3 Playback Volume",
+                       AK4671_LOUT3_POWER_MANAGERMENT, 6, 0x3, 0, out3_tlv),
+
+       /* Common capture gain controls */
+       SOC_DOUBLE_TLV("Mic Amp Capture Volume",
+                       AK4671_MIC_AMP_GAIN, 0, 4, 0xf, 0, mic_amp_tlv),
+};
+
+/* event handlers */
+static int ak4671_out2_event(struct snd_soc_dapm_widget *w,
+               struct snd_kcontrol *kcontrol, int event)
+{
+       struct snd_soc_codec *codec = w->codec;
+       u8 reg;
+
+       switch (event) {
+       case SND_SOC_DAPM_POST_PMU:
+               reg = snd_soc_read(codec, AK4671_LOUT2_POWER_MANAGERMENT);
+               reg |= AK4671_MUTEN;
+               snd_soc_write(codec, AK4671_LOUT2_POWER_MANAGERMENT, reg);
+               break;
+       case SND_SOC_DAPM_PRE_PMD:
+               reg = snd_soc_read(codec, AK4671_LOUT2_POWER_MANAGERMENT);
+               reg &= ~AK4671_MUTEN;
+               snd_soc_write(codec, AK4671_LOUT2_POWER_MANAGERMENT, reg);
+               break;
+       }
+
+       return 0;
+}
+
+/* Output Mixers */
+static const struct snd_kcontrol_new ak4671_lout1_mixer_controls[] = {
+       SOC_DAPM_SINGLE("DACL", AK4671_LOUT1_SIGNAL_SELECT, 0, 1, 0),
+       SOC_DAPM_SINGLE("LINL1", AK4671_LOUT1_SIGNAL_SELECT, 1, 1, 0),
+       SOC_DAPM_SINGLE("LINL2", AK4671_LOUT1_SIGNAL_SELECT, 2, 1, 0),
+       SOC_DAPM_SINGLE("LINL3", AK4671_LOUT1_SIGNAL_SELECT, 3, 1, 0),
+       SOC_DAPM_SINGLE("LINL4", AK4671_LOUT1_SIGNAL_SELECT, 4, 1, 0),
+       SOC_DAPM_SINGLE("LOOPL", AK4671_LOUT1_SIGNAL_SELECT, 5, 1, 0),
+};
+
+static const struct snd_kcontrol_new ak4671_rout1_mixer_controls[] = {
+       SOC_DAPM_SINGLE("DACR", AK4671_ROUT1_SIGNAL_SELECT, 0, 1, 0),
+       SOC_DAPM_SINGLE("RINR1", AK4671_ROUT1_SIGNAL_SELECT, 1, 1, 0),
+       SOC_DAPM_SINGLE("RINR2", AK4671_ROUT1_SIGNAL_SELECT, 2, 1, 0),
+       SOC_DAPM_SINGLE("RINR3", AK4671_ROUT1_SIGNAL_SELECT, 3, 1, 0),
+       SOC_DAPM_SINGLE("RINR4", AK4671_ROUT1_SIGNAL_SELECT, 4, 1, 0),
+       SOC_DAPM_SINGLE("LOOPR", AK4671_ROUT1_SIGNAL_SELECT, 5, 1, 0),
+};
+
+static const struct snd_kcontrol_new ak4671_lout2_mixer_controls[] = {
+       SOC_DAPM_SINGLE("DACHL", AK4671_LOUT2_SIGNAL_SELECT, 0, 1, 0),
+       SOC_DAPM_SINGLE("LINH1", AK4671_LOUT2_SIGNAL_SELECT, 1, 1, 0),
+       SOC_DAPM_SINGLE("LINH2", AK4671_LOUT2_SIGNAL_SELECT, 2, 1, 0),
+       SOC_DAPM_SINGLE("LINH3", AK4671_LOUT2_SIGNAL_SELECT, 3, 1, 0),
+       SOC_DAPM_SINGLE("LINH4", AK4671_LOUT2_SIGNAL_SELECT, 4, 1, 0),
+       SOC_DAPM_SINGLE("LOOPHL", AK4671_LOUT2_SIGNAL_SELECT, 5, 1, 0),
+};
+
+static const struct snd_kcontrol_new ak4671_rout2_mixer_controls[] = {
+       SOC_DAPM_SINGLE("DACHR", AK4671_ROUT2_SIGNAL_SELECT, 0, 1, 0),
+       SOC_DAPM_SINGLE("RINH1", AK4671_ROUT2_SIGNAL_SELECT, 1, 1, 0),
+       SOC_DAPM_SINGLE("RINH2", AK4671_ROUT2_SIGNAL_SELECT, 2, 1, 0),
+       SOC_DAPM_SINGLE("RINH3", AK4671_ROUT2_SIGNAL_SELECT, 3, 1, 0),
+       SOC_DAPM_SINGLE("RINH4", AK4671_ROUT2_SIGNAL_SELECT, 4, 1, 0),
+       SOC_DAPM_SINGLE("LOOPHR", AK4671_ROUT2_SIGNAL_SELECT, 5, 1, 0),
+};
+
+static const struct snd_kcontrol_new ak4671_lout3_mixer_controls[] = {
+       SOC_DAPM_SINGLE("DACSL", AK4671_LOUT3_SIGNAL_SELECT, 0, 1, 0),
+       SOC_DAPM_SINGLE("LINS1", AK4671_LOUT3_SIGNAL_SELECT, 1, 1, 0),
+       SOC_DAPM_SINGLE("LINS2", AK4671_LOUT3_SIGNAL_SELECT, 2, 1, 0),
+       SOC_DAPM_SINGLE("LINS3", AK4671_LOUT3_SIGNAL_SELECT, 3, 1, 0),
+       SOC_DAPM_SINGLE("LINS4", AK4671_LOUT3_SIGNAL_SELECT, 4, 1, 0),
+       SOC_DAPM_SINGLE("LOOPSL", AK4671_LOUT3_SIGNAL_SELECT, 5, 1, 0),
+};
+
+static const struct snd_kcontrol_new ak4671_rout3_mixer_controls[] = {
+       SOC_DAPM_SINGLE("DACSR", AK4671_ROUT3_SIGNAL_SELECT, 0, 1, 0),
+       SOC_DAPM_SINGLE("RINS1", AK4671_ROUT3_SIGNAL_SELECT, 1, 1, 0),
+       SOC_DAPM_SINGLE("RINS2", AK4671_ROUT3_SIGNAL_SELECT, 2, 1, 0),
+       SOC_DAPM_SINGLE("RINS3", AK4671_ROUT3_SIGNAL_SELECT, 3, 1, 0),
+       SOC_DAPM_SINGLE("RINS4", AK4671_ROUT3_SIGNAL_SELECT, 4, 1, 0),
+       SOC_DAPM_SINGLE("LOOPSR", AK4671_ROUT3_SIGNAL_SELECT, 5, 1, 0),
+};
+
+/* Input MUXs */
+static const char *ak4671_lin_mux_texts[] =
+               {"LIN1", "LIN2", "LIN3", "LIN4"};
+static const struct soc_enum ak4671_lin_mux_enum =
+       SOC_ENUM_SINGLE(AK4671_MIC_SIGNAL_SELECT, 0,
+                       ARRAY_SIZE(ak4671_lin_mux_texts),
+                       ak4671_lin_mux_texts);
+static const struct snd_kcontrol_new ak4671_lin_mux_control =
+       SOC_DAPM_ENUM("Route", ak4671_lin_mux_enum);
+
+static const char *ak4671_rin_mux_texts[] =
+               {"RIN1", "RIN2", "RIN3", "RIN4"};
+static const struct soc_enum ak4671_rin_mux_enum =
+       SOC_ENUM_SINGLE(AK4671_MIC_SIGNAL_SELECT, 2,
+                       ARRAY_SIZE(ak4671_rin_mux_texts),
+                       ak4671_rin_mux_texts);
+static const struct snd_kcontrol_new ak4671_rin_mux_control =
+       SOC_DAPM_ENUM("Route", ak4671_rin_mux_enum);
+
+static const struct snd_soc_dapm_widget ak4671_dapm_widgets[] = {
+       /* Inputs */
+       SND_SOC_DAPM_INPUT("LIN1"),
+       SND_SOC_DAPM_INPUT("RIN1"),
+       SND_SOC_DAPM_INPUT("LIN2"),
+       SND_SOC_DAPM_INPUT("RIN2"),
+       SND_SOC_DAPM_INPUT("LIN3"),
+       SND_SOC_DAPM_INPUT("RIN3"),
+       SND_SOC_DAPM_INPUT("LIN4"),
+       SND_SOC_DAPM_INPUT("RIN4"),
+
+       /* Outputs */
+       SND_SOC_DAPM_OUTPUT("LOUT1"),
+       SND_SOC_DAPM_OUTPUT("ROUT1"),
+       SND_SOC_DAPM_OUTPUT("LOUT2"),
+       SND_SOC_DAPM_OUTPUT("ROUT2"),
+       SND_SOC_DAPM_OUTPUT("LOUT3"),
+       SND_SOC_DAPM_OUTPUT("ROUT3"),
+
+       /* DAC */
+       SND_SOC_DAPM_DAC("DAC Left", "Left HiFi Playback",
+                       AK4671_AD_DA_POWER_MANAGEMENT, 6, 0),
+       SND_SOC_DAPM_DAC("DAC Right", "Right HiFi Playback",
+                       AK4671_AD_DA_POWER_MANAGEMENT, 7, 0),
+
+       /* ADC */
+       SND_SOC_DAPM_ADC("ADC Left", "Left HiFi Capture",
+                       AK4671_AD_DA_POWER_MANAGEMENT, 4, 0),
+       SND_SOC_DAPM_ADC("ADC Right", "Right HiFi Capture",
+                       AK4671_AD_DA_POWER_MANAGEMENT, 5, 0),
+
+       /* PGA */
+       SND_SOC_DAPM_PGA("LOUT2 Mix Amp",
+                       AK4671_LOUT2_POWER_MANAGERMENT, 5, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("ROUT2 Mix Amp",
+                       AK4671_LOUT2_POWER_MANAGERMENT, 6, 0, NULL, 0),
+
+       SND_SOC_DAPM_PGA("LIN1 Mixing Circuit",
+                       AK4671_MIXING_POWER_MANAGEMENT1, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("RIN1 Mixing Circuit",
+                       AK4671_MIXING_POWER_MANAGEMENT1, 1, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("LIN2 Mixing Circuit",
+                       AK4671_MIXING_POWER_MANAGEMENT1, 2, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("RIN2 Mixing Circuit",
+                       AK4671_MIXING_POWER_MANAGEMENT1, 3, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("LIN3 Mixing Circuit",
+                       AK4671_MIXING_POWER_MANAGEMENT1, 4, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("RIN3 Mixing Circuit",
+                       AK4671_MIXING_POWER_MANAGEMENT1, 5, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("LIN4 Mixing Circuit",
+                       AK4671_MIXING_POWER_MANAGEMENT1, 6, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("RIN4 Mixing Circuit",
+                       AK4671_MIXING_POWER_MANAGEMENT1, 7, 0, NULL, 0),
+
+       /* Output Mixers */
+       SND_SOC_DAPM_MIXER("LOUT1 Mixer", AK4671_LOUT1_POWER_MANAGERMENT, 0, 0,
+                       &ak4671_lout1_mixer_controls[0],
+                       ARRAY_SIZE(ak4671_lout1_mixer_controls)),
+       SND_SOC_DAPM_MIXER("ROUT1 Mixer", AK4671_LOUT1_POWER_MANAGERMENT, 1, 0,
+                       &ak4671_rout1_mixer_controls[0],
+                       ARRAY_SIZE(ak4671_rout1_mixer_controls)),
+       SND_SOC_DAPM_MIXER_E("LOUT2 Mixer", AK4671_LOUT2_POWER_MANAGERMENT,
+                       0, 0, &ak4671_lout2_mixer_controls[0],
+                       ARRAY_SIZE(ak4671_lout2_mixer_controls),
+                       ak4671_out2_event,
+                       SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_PRE_PMD),
+       SND_SOC_DAPM_MIXER_E("ROUT2 Mixer", AK4671_LOUT2_POWER_MANAGERMENT,
+                       1, 0, &ak4671_rout2_mixer_controls[0],
+                       ARRAY_SIZE(ak4671_rout2_mixer_controls),
+                       ak4671_out2_event,
+                       SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_PRE_PMD),
+       SND_SOC_DAPM_MIXER("LOUT3 Mixer", AK4671_LOUT3_POWER_MANAGERMENT, 0, 0,
+                       &ak4671_lout3_mixer_controls[0],
+                       ARRAY_SIZE(ak4671_lout3_mixer_controls)),
+       SND_SOC_DAPM_MIXER("ROUT3 Mixer", AK4671_LOUT3_POWER_MANAGERMENT, 1, 0,
+                       &ak4671_rout3_mixer_controls[0],
+                       ARRAY_SIZE(ak4671_rout3_mixer_controls)),
+
+       /* Input MUXs */
+       SND_SOC_DAPM_MUX("LIN MUX", AK4671_AD_DA_POWER_MANAGEMENT, 2, 0,
+                       &ak4671_lin_mux_control),
+       SND_SOC_DAPM_MUX("RIN MUX", AK4671_AD_DA_POWER_MANAGEMENT, 3, 0,
+                       &ak4671_rin_mux_control),
+
+       /* Mic Power */
+       SND_SOC_DAPM_MICBIAS("Mic Bias", AK4671_AD_DA_POWER_MANAGEMENT, 1, 0),
+
+       /* Supply */
+       SND_SOC_DAPM_SUPPLY("PMPLL", AK4671_PLL_MODE_SELECT1, 0, 0, NULL, 0),
+};
+
+static const struct snd_soc_dapm_route intercon[] = {
+       {"DAC Left", "NULL", "PMPLL"},
+       {"DAC Right", "NULL", "PMPLL"},
+       {"ADC Left", "NULL", "PMPLL"},
+       {"ADC Right", "NULL", "PMPLL"},
+
+       /* Outputs */
+       {"LOUT1", "NULL", "LOUT1 Mixer"},
+       {"ROUT1", "NULL", "ROUT1 Mixer"},
+       {"LOUT2", "NULL", "LOUT2 Mix Amp"},
+       {"ROUT2", "NULL", "ROUT2 Mix Amp"},
+       {"LOUT3", "NULL", "LOUT3 Mixer"},
+       {"ROUT3", "NULL", "ROUT3 Mixer"},
+
+       {"LOUT1 Mixer", "DACL", "DAC Left"},
+       {"ROUT1 Mixer", "DACR", "DAC Right"},
+       {"LOUT2 Mixer", "DACHL", "DAC Left"},
+       {"ROUT2 Mixer", "DACHR", "DAC Right"},
+       {"LOUT2 Mix Amp", "NULL", "LOUT2 Mixer"},
+       {"ROUT2 Mix Amp", "NULL", "ROUT2 Mixer"},
+       {"LOUT3 Mixer", "DACSL", "DAC Left"},
+       {"ROUT3 Mixer", "DACSR", "DAC Right"},
+
+       /* Inputs */
+       {"LIN MUX", "LIN1", "LIN1"},
+       {"LIN MUX", "LIN2", "LIN2"},
+       {"LIN MUX", "LIN3", "LIN3"},
+       {"LIN MUX", "LIN4", "LIN4"},
+
+       {"RIN MUX", "RIN1", "RIN1"},
+       {"RIN MUX", "RIN2", "RIN2"},
+       {"RIN MUX", "RIN3", "RIN3"},
+       {"RIN MUX", "RIN4", "RIN4"},
+
+       {"LIN1", NULL, "Mic Bias"},
+       {"RIN1", NULL, "Mic Bias"},
+       {"LIN2", NULL, "Mic Bias"},
+       {"RIN2", NULL, "Mic Bias"},
+
+       {"ADC Left", "NULL", "LIN MUX"},
+       {"ADC Right", "NULL", "RIN MUX"},
+
+       /* Analog Loops */
+       {"LIN1 Mixing Circuit", "NULL", "LIN1"},
+       {"RIN1 Mixing Circuit", "NULL", "RIN1"},
+       {"LIN2 Mixing Circuit", "NULL", "LIN2"},
+       {"RIN2 Mixing Circuit", "NULL", "RIN2"},
+       {"LIN3 Mixing Circuit", "NULL", "LIN3"},
+       {"RIN3 Mixing Circuit", "NULL", "RIN3"},
+       {"LIN4 Mixing Circuit", "NULL", "LIN4"},
+       {"RIN4 Mixing Circuit", "NULL", "RIN4"},
+
+       {"LOUT1 Mixer", "LINL1", "LIN1 Mixing Circuit"},
+       {"ROUT1 Mixer", "RINR1", "RIN1 Mixing Circuit"},
+       {"LOUT2 Mixer", "LINH1", "LIN1 Mixing Circuit"},
+       {"ROUT2 Mixer", "RINH1", "RIN1 Mixing Circuit"},
+       {"LOUT3 Mixer", "LINS1", "LIN1 Mixing Circuit"},
+       {"ROUT3 Mixer", "RINS1", "RIN1 Mixing Circuit"},
+
+       {"LOUT1 Mixer", "LINL2", "LIN2 Mixing Circuit"},
+       {"ROUT1 Mixer", "RINR2", "RIN2 Mixing Circuit"},
+       {"LOUT2 Mixer", "LINH2", "LIN2 Mixing Circuit"},
+       {"ROUT2 Mixer", "RINH2", "RIN2 Mixing Circuit"},
+       {"LOUT3 Mixer", "LINS2", "LIN2 Mixing Circuit"},
+       {"ROUT3 Mixer", "RINS2", "RIN2 Mixing Circuit"},
+
+       {"LOUT1 Mixer", "LINL3", "LIN3 Mixing Circuit"},
+       {"ROUT1 Mixer", "RINR3", "RIN3 Mixing Circuit"},
+       {"LOUT2 Mixer", "LINH3", "LIN3 Mixing Circuit"},
+       {"ROUT2 Mixer", "RINH3", "RIN3 Mixing Circuit"},
+       {"LOUT3 Mixer", "LINS3", "LIN3 Mixing Circuit"},
+       {"ROUT3 Mixer", "RINS3", "RIN3 Mixing Circuit"},
+
+       {"LOUT1 Mixer", "LINL4", "LIN4 Mixing Circuit"},
+       {"ROUT1 Mixer", "RINR4", "RIN4 Mixing Circuit"},
+       {"LOUT2 Mixer", "LINH4", "LIN4 Mixing Circuit"},
+       {"ROUT2 Mixer", "RINH4", "RIN4 Mixing Circuit"},
+       {"LOUT3 Mixer", "LINS4", "LIN4 Mixing Circuit"},
+       {"ROUT3 Mixer", "RINS4", "RIN4 Mixing Circuit"},
+};
+
+static int ak4671_add_widgets(struct snd_soc_codec *codec)
+{
+       snd_soc_dapm_new_controls(codec, ak4671_dapm_widgets,
+                                 ARRAY_SIZE(ak4671_dapm_widgets));
+
+       snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon));
+
+       return 0;
+}
+
+static int ak4671_hw_params(struct snd_pcm_substream *substream,
+               struct snd_pcm_hw_params *params,
+               struct snd_soc_dai *dai)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       u8 fs;
+
+       fs = snd_soc_read(codec, AK4671_PLL_MODE_SELECT0);
+       fs &= ~AK4671_FS;
+
+       switch (params_rate(params)) {
+       case 8000:
+               fs |= AK4671_FS_8KHZ;
+               break;
+       case 12000:
+               fs |= AK4671_FS_12KHZ;
+               break;
+       case 16000:
+               fs |= AK4671_FS_16KHZ;
+               break;
+       case 24000:
+               fs |= AK4671_FS_24KHZ;
+               break;
+       case 11025:
+               fs |= AK4671_FS_11_025KHZ;
+               break;
+       case 22050:
+               fs |= AK4671_FS_22_05KHZ;
+               break;
+       case 32000:
+               fs |= AK4671_FS_32KHZ;
+               break;
+       case 44100:
+               fs |= AK4671_FS_44_1KHZ;
+               break;
+       case 48000:
+               fs |= AK4671_FS_48KHZ;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       snd_soc_write(codec, AK4671_PLL_MODE_SELECT0, fs);
+
+       return 0;
+}
+
+static int ak4671_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id,
+               unsigned int freq, int dir)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       u8 pll;
+
+       pll = snd_soc_read(codec, AK4671_PLL_MODE_SELECT0);
+       pll &= ~AK4671_PLL;
+
+       switch (freq) {
+       case 11289600:
+               pll |= AK4671_PLL_11_2896MHZ;
+               break;
+       case 12000000:
+               pll |= AK4671_PLL_12MHZ;
+               break;
+       case 12288000:
+               pll |= AK4671_PLL_12_288MHZ;
+               break;
+       case 13000000:
+               pll |= AK4671_PLL_13MHZ;
+               break;
+       case 13500000:
+               pll |= AK4671_PLL_13_5MHZ;
+               break;
+       case 19200000:
+               pll |= AK4671_PLL_19_2MHZ;
+               break;
+       case 24000000:
+               pll |= AK4671_PLL_24MHZ;
+               break;
+       case 26000000:
+               pll |= AK4671_PLL_26MHZ;
+               break;
+       case 27000000:
+               pll |= AK4671_PLL_27MHZ;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       snd_soc_write(codec, AK4671_PLL_MODE_SELECT0, pll);
+
+       return 0;
+}
+
+static int ak4671_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       u8 mode;
+       u8 format;
+
+       /* set master/slave audio interface */
+       mode = snd_soc_read(codec, AK4671_PLL_MODE_SELECT1);
+
+       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_CBM_CFM:
+               mode |= AK4671_M_S;
+               break;
+       case SND_SOC_DAIFMT_CBM_CFS:
+               mode &= ~(AK4671_M_S);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       /* interface format */
+       format = snd_soc_read(codec, AK4671_FORMAT_SELECT);
+       format &= ~AK4671_DIF;
+
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_I2S:
+               format |= AK4671_DIF_I2S_MODE;
+               break;
+       case SND_SOC_DAIFMT_LEFT_J:
+               format |= AK4671_DIF_MSB_MODE;
+               break;
+       case SND_SOC_DAIFMT_DSP_A:
+               format |= AK4671_DIF_DSP_MODE;
+               format |= AK4671_BCKP;
+               format |= AK4671_MSBS;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       /* set mode and format */
+       snd_soc_write(codec, AK4671_PLL_MODE_SELECT1, mode);
+       snd_soc_write(codec, AK4671_FORMAT_SELECT, format);
+
+       return 0;
+}
+
+static int ak4671_set_bias_level(struct snd_soc_codec *codec,
+               enum snd_soc_bias_level level)
+{
+       u8 reg;
+
+       switch (level) {
+       case SND_SOC_BIAS_ON:
+       case SND_SOC_BIAS_PREPARE:
+       case SND_SOC_BIAS_STANDBY:
+               reg = snd_soc_read(codec, AK4671_AD_DA_POWER_MANAGEMENT);
+               snd_soc_write(codec, AK4671_AD_DA_POWER_MANAGEMENT,
+                               reg | AK4671_PMVCM);
+               break;
+       case SND_SOC_BIAS_OFF:
+               snd_soc_write(codec, AK4671_AD_DA_POWER_MANAGEMENT, 0x00);
+               break;
+       }
+       codec->bias_level = level;
+       return 0;
+}
+
+#define AK4671_RATES           (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
+                               SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |\
+                               SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |\
+                               SNDRV_PCM_RATE_48000)
+
+#define AK4671_FORMATS         SNDRV_PCM_FMTBIT_S16_LE
+
+static struct snd_soc_dai_ops ak4671_dai_ops = {
+       .hw_params      = ak4671_hw_params,
+       .set_sysclk     = ak4671_set_dai_sysclk,
+       .set_fmt        = ak4671_set_dai_fmt,
+};
+
+struct snd_soc_dai ak4671_dai = {
+       .name = "AK4671",
+       .playback = {
+               .stream_name = "Playback",
+               .channels_min = 1,
+               .channels_max = 2,
+               .rates = AK4671_RATES,
+               .formats = AK4671_FORMATS,},
+       .capture = {
+               .stream_name = "Capture",
+               .channels_min = 1,
+               .channels_max = 2,
+               .rates = AK4671_RATES,
+               .formats = AK4671_FORMATS,},
+       .ops = &ak4671_dai_ops,
+};
+EXPORT_SYMBOL_GPL(ak4671_dai);
+
+static int ak4671_probe(struct platform_device *pdev)
+{
+       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+       struct snd_soc_codec *codec;
+       int ret = 0;
+
+       if (ak4671_codec == NULL) {
+               dev_err(&pdev->dev, "Codec device not registered\n");
+               return -ENODEV;
+       }
+
+       socdev->card->codec = ak4671_codec;
+       codec = ak4671_codec;
+
+       /* register pcms */
+       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
+       if (ret < 0) {
+               dev_err(codec->dev, "failed to create pcms: %d\n", ret);
+               goto pcm_err;
+       }
+
+       snd_soc_add_controls(codec, ak4671_snd_controls,
+                            ARRAY_SIZE(ak4671_snd_controls));
+       ak4671_add_widgets(codec);
+
+       ak4671_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+       return ret;
+
+pcm_err:
+       return ret;
+}
+
+static int ak4671_remove(struct platform_device *pdev)
+{
+       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+
+       snd_soc_free_pcms(socdev);
+       snd_soc_dapm_free(socdev);
+
+       return 0;
+}
+
+struct snd_soc_codec_device soc_codec_dev_ak4671 = {
+       .probe = ak4671_probe,
+       .remove = ak4671_remove,
+};
+EXPORT_SYMBOL_GPL(soc_codec_dev_ak4671);
+
+static int ak4671_register(struct ak4671_priv *ak4671,
+               enum snd_soc_control_type control)
+{
+       int ret;
+       struct snd_soc_codec *codec = &ak4671->codec;
+
+       if (ak4671_codec) {
+               dev_err(codec->dev, "Another AK4671 is registered\n");
+               ret = -EINVAL;
+               goto err;
+       }
+
+       mutex_init(&codec->mutex);
+       INIT_LIST_HEAD(&codec->dapm_widgets);
+       INIT_LIST_HEAD(&codec->dapm_paths);
+
+       codec->private_data = ak4671;
+       codec->name = "AK4671";
+       codec->owner = THIS_MODULE;
+       codec->bias_level = SND_SOC_BIAS_OFF;
+       codec->set_bias_level = ak4671_set_bias_level;
+       codec->dai = &ak4671_dai;
+       codec->num_dai = 1;
+       codec->reg_cache_size = AK4671_CACHEREGNUM;
+       codec->reg_cache = &ak4671->reg_cache;
+
+       memcpy(codec->reg_cache, ak4671_reg, sizeof(ak4671_reg));
+
+       ret = snd_soc_codec_set_cache_io(codec, 8, 8, control);
+       if (ret < 0) {
+               dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
+               goto err;
+       }
+
+       ak4671_dai.dev = codec->dev;
+       ak4671_codec = codec;
+
+       ret = snd_soc_register_codec(codec);
+       if (ret != 0) {
+               dev_err(codec->dev, "Failed to register codec: %d\n", ret);
+               goto err;
+       }
+
+       ret = snd_soc_register_dai(&ak4671_dai);
+       if (ret != 0) {
+               dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
+               goto err_codec;
+       }
+
+       return 0;
+
+err_codec:
+       snd_soc_unregister_codec(codec);
+err:
+       kfree(ak4671);
+       return ret;
+}
+
+static void ak4671_unregister(struct ak4671_priv *ak4671)
+{
+       ak4671_set_bias_level(&ak4671->codec, SND_SOC_BIAS_OFF);
+       snd_soc_unregister_dai(&ak4671_dai);
+       snd_soc_unregister_codec(&ak4671->codec);
+       kfree(ak4671);
+       ak4671_codec = NULL;
+}
+
+static int __devinit ak4671_i2c_probe(struct i2c_client *client,
+               const struct i2c_device_id *id)
+{
+       struct ak4671_priv *ak4671;
+       struct snd_soc_codec *codec;
+
+       ak4671 = kzalloc(sizeof(struct ak4671_priv), GFP_KERNEL);
+       if (ak4671 == NULL)
+               return -ENOMEM;
+
+       codec = &ak4671->codec;
+       codec->hw_write = (hw_write_t)i2c_master_send;
+
+       i2c_set_clientdata(client, ak4671);
+       codec->control_data = client;
+
+       codec->dev = &client->dev;
+
+       return ak4671_register(ak4671, SND_SOC_I2C);
+}
+
+static __devexit int ak4671_i2c_remove(struct i2c_client *client)
+{
+       struct ak4671_priv *ak4671 = i2c_get_clientdata(client);
+
+       ak4671_unregister(ak4671);
+
+       return 0;
+}
+
+static const struct i2c_device_id ak4671_i2c_id[] = {
+       { "ak4671", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, ak4671_i2c_id);
+
+static struct i2c_driver ak4671_i2c_driver = {
+       .driver = {
+               .name = "ak4671",
+               .owner = THIS_MODULE,
+       },
+       .probe = ak4671_i2c_probe,
+       .remove = __devexit_p(ak4671_i2c_remove),
+       .id_table = ak4671_i2c_id,
+};
+
+static int __init ak4671_modinit(void)
+{
+       return i2c_add_driver(&ak4671_i2c_driver);
+}
+module_init(ak4671_modinit);
+
+static void __exit ak4671_exit(void)
+{
+       i2c_del_driver(&ak4671_i2c_driver);
+}
+module_exit(ak4671_exit);
+
+MODULE_DESCRIPTION("ASoC AK4671 codec driver");
+MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/ak4671.h b/sound/soc/codecs/ak4671.h
new file mode 100644 (file)
index 0000000..e2fad96
--- /dev/null
@@ -0,0 +1,156 @@
+/*
+ * ak4671.h  --  audio driver for AK4671
+ *
+ * Copyright (C) 2009 Samsung Electronics Co.Ltd
+ * Author: Joonyoung Shim <jy0922.shim@samsung.com>
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ */
+
+#ifndef _AK4671_H
+#define _AK4671_H
+
+#define AK4671_AD_DA_POWER_MANAGEMENT          0x00
+#define AK4671_PLL_MODE_SELECT0                        0x01
+#define AK4671_PLL_MODE_SELECT1                        0x02
+#define AK4671_FORMAT_SELECT                   0x03
+#define AK4671_MIC_SIGNAL_SELECT               0x04
+#define AK4671_MIC_AMP_GAIN                    0x05
+#define AK4671_MIXING_POWER_MANAGEMENT0                0x06
+#define AK4671_MIXING_POWER_MANAGEMENT1                0x07
+#define AK4671_OUTPUT_VOLUME_CONTROL           0x08
+#define AK4671_LOUT1_SIGNAL_SELECT             0x09
+#define AK4671_ROUT1_SIGNAL_SELECT             0x0a
+#define AK4671_LOUT2_SIGNAL_SELECT             0x0b
+#define AK4671_ROUT2_SIGNAL_SELECT             0x0c
+#define AK4671_LOUT3_SIGNAL_SELECT             0x0d
+#define AK4671_ROUT3_SIGNAL_SELECT             0x0e
+#define AK4671_LOUT1_POWER_MANAGERMENT         0x0f
+#define AK4671_LOUT2_POWER_MANAGERMENT         0x10
+#define AK4671_LOUT3_POWER_MANAGERMENT         0x11
+#define AK4671_LCH_INPUT_VOLUME_CONTROL                0x12
+#define AK4671_RCH_INPUT_VOLUME_CONTROL                0x13
+#define AK4671_ALC_REFERENCE_SELECT            0x14
+#define AK4671_DIGITAL_MIXING_CONTROL          0x15
+#define AK4671_ALC_TIMER_SELECT                        0x16
+#define AK4671_ALC_MODE_CONTROL                        0x17
+#define AK4671_MODE_CONTROL1                   0x18
+#define AK4671_MODE_CONTROL2                   0x19
+#define AK4671_LCH_OUTPUT_VOLUME_CONTROL       0x1a
+#define AK4671_RCH_OUTPUT_VOLUME_CONTROL       0x1b
+#define AK4671_SIDETONE_A_CONTROL              0x1c
+#define AK4671_DIGITAL_FILTER_SELECT           0x1d
+#define AK4671_FIL3_COEFFICIENT0               0x1e
+#define AK4671_FIL3_COEFFICIENT1               0x1f
+#define AK4671_FIL3_COEFFICIENT2               0x20
+#define AK4671_FIL3_COEFFICIENT3               0x21
+#define AK4671_EQ_COEFFICIENT0                 0x22
+#define AK4671_EQ_COEFFICIENT1                 0x23
+#define AK4671_EQ_COEFFICIENT2                 0x24
+#define AK4671_EQ_COEFFICIENT3                 0x25
+#define AK4671_EQ_COEFFICIENT4                 0x26
+#define AK4671_EQ_COEFFICIENT5                 0x27
+#define AK4671_FIL1_COEFFICIENT0               0x28
+#define AK4671_FIL1_COEFFICIENT1               0x29
+#define AK4671_FIL1_COEFFICIENT2               0x2a
+#define AK4671_FIL1_COEFFICIENT3               0x2b
+#define AK4671_FIL2_COEFFICIENT0               0x2c
+#define AK4671_FIL2_COEFFICIENT1               0x2d
+#define AK4671_FIL2_COEFFICIENT2               0x2e
+#define AK4671_FIL2_COEFFICIENT3               0x2f
+#define AK4671_DIGITAL_FILTER_SELECT2          0x30
+#define AK4671_E1_COEFFICIENT0                 0x32
+#define AK4671_E1_COEFFICIENT1                 0x33
+#define AK4671_E1_COEFFICIENT2                 0x34
+#define AK4671_E1_COEFFICIENT3                 0x35
+#define AK4671_E1_COEFFICIENT4                 0x36
+#define AK4671_E1_COEFFICIENT5                 0x37
+#define AK4671_E2_COEFFICIENT0                 0x38
+#define AK4671_E2_COEFFICIENT1                 0x39
+#define AK4671_E2_COEFFICIENT2                 0x3a
+#define AK4671_E2_COEFFICIENT3                 0x3b
+#define AK4671_E2_COEFFICIENT4                 0x3c
+#define AK4671_E2_COEFFICIENT5                 0x3d
+#define AK4671_E3_COEFFICIENT0                 0x3e
+#define AK4671_E3_COEFFICIENT1                 0x3f
+#define AK4671_E3_COEFFICIENT2                 0x40
+#define AK4671_E3_COEFFICIENT3                 0x41
+#define AK4671_E3_COEFFICIENT4                 0x42
+#define AK4671_E3_COEFFICIENT5                 0x43
+#define AK4671_E4_COEFFICIENT0                 0x44
+#define AK4671_E4_COEFFICIENT1                 0x45
+#define AK4671_E4_COEFFICIENT2                 0x46
+#define AK4671_E4_COEFFICIENT3                 0x47
+#define AK4671_E4_COEFFICIENT4                 0x48
+#define AK4671_E4_COEFFICIENT5                 0x49
+#define AK4671_E5_COEFFICIENT0                 0x4a
+#define AK4671_E5_COEFFICIENT1                 0x4b
+#define AK4671_E5_COEFFICIENT2                 0x4c
+#define AK4671_E5_COEFFICIENT3                 0x4d
+#define AK4671_E5_COEFFICIENT4                 0x4e
+#define AK4671_E5_COEFFICIENT5                 0x4f
+#define AK4671_EQ_CONTROL_250HZ_100HZ          0x50
+#define AK4671_EQ_CONTROL_3500HZ_1KHZ          0x51
+#define AK4671_EQ_CONTRO_10KHZ                 0x52
+#define AK4671_PCM_IF_CONTROL0                 0x53
+#define AK4671_PCM_IF_CONTROL1                 0x54
+#define AK4671_PCM_IF_CONTROL2                 0x55
+#define AK4671_DIGITAL_VOLUME_B_CONTROL                0x56
+#define AK4671_DIGITAL_VOLUME_C_CONTROL                0x57
+#define AK4671_SIDETONE_VOLUME_CONTROL         0x58
+#define AK4671_DIGITAL_MIXING_CONTROL2         0x59
+#define AK4671_SAR_ADC_CONTROL                 0x5a
+
+#define AK4671_CACHEREGNUM                     (AK4671_SAR_ADC_CONTROL + 1)
+
+/* Bitfield Definitions */
+
+/* AK4671_AD_DA_POWER_MANAGEMENT (0x00) Fields */
+#define AK4671_PMVCM                           0x01
+
+/* AK4671_PLL_MODE_SELECT0 (0x01) Fields */
+#define AK4671_PLL                             0x0f
+#define AK4671_PLL_11_2896MHZ                  (4 << 0)
+#define AK4671_PLL_12_288MHZ                   (5 << 0)
+#define AK4671_PLL_12MHZ                       (6 << 0)
+#define AK4671_PLL_24MHZ                       (7 << 0)
+#define AK4671_PLL_19_2MHZ                     (8 << 0)
+#define AK4671_PLL_13_5MHZ                     (12 << 0)
+#define AK4671_PLL_27MHZ                       (13 << 0)
+#define AK4671_PLL_13MHZ                       (14 << 0)
+#define AK4671_PLL_26MHZ                       (15 << 0)
+#define AK4671_FS                              0xf0
+#define AK4671_FS_8KHZ                         (0 << 4)
+#define AK4671_FS_12KHZ                                (1 << 4)
+#define AK4671_FS_16KHZ                                (2 << 4)
+#define AK4671_FS_24KHZ                                (3 << 4)
+#define AK4671_FS_11_025KHZ                    (5 << 4)
+#define AK4671_FS_22_05KHZ                     (7 << 4)
+#define AK4671_FS_32KHZ                                (10 << 4)
+#define AK4671_FS_48KHZ                                (11 << 4)
+#define AK4671_FS_44_1KHZ                      (15 << 4)
+
+/* AK4671_PLL_MODE_SELECT1 (0x02) Fields */
+#define AK4671_PMPLL                           0x01
+#define AK4671_M_S                             0x02
+
+/* AK4671_FORMAT_SELECT (0x03) Fields */
+#define AK4671_DIF                             0x03
+#define AK4671_DIF_DSP_MODE                    (0 << 0)
+#define AK4671_DIF_MSB_MODE                    (2 << 0)
+#define AK4671_DIF_I2S_MODE                    (3 << 0)
+#define AK4671_BCKP                            0x04
+#define AK4671_MSBS                            0x08
+#define AK4671_SDOD                            0x10
+
+/* AK4671_LOUT2_POWER_MANAGEMENT (0x10) Fields */
+#define AK4671_MUTEN                           0x04
+
+extern struct snd_soc_dai ak4671_dai;
+extern struct snd_soc_codec_device soc_codec_dev_ak4671;
+
+#endif
index ca1e24a..ffe122d 100644 (file)
@@ -520,6 +520,7 @@ static const struct snd_kcontrol_new cs4270_snd_controls[] = {
        SOC_SINGLE("Digital Sidetone Switch", CS4270_FORMAT, 5, 1, 0),
        SOC_SINGLE("Soft Ramp Switch", CS4270_TRANS, 6, 1, 0),
        SOC_SINGLE("Zero Cross Switch", CS4270_TRANS, 5, 1, 0),
+       SOC_SINGLE("De-emphasis filter", CS4270_TRANS, 0, 1, 0),
        SOC_SINGLE("Popguard Switch", CS4270_MODE, 0, 1, 1),
        SOC_SINGLE("Auto-Mute Switch", CS4270_MUTE, 5, 1, 0),
        SOC_DOUBLE("Master Capture Switch", CS4270_MUTE, 3, 4, 1, 1),
@@ -598,13 +599,6 @@ static int cs4270_probe(struct platform_device *pdev)
                goto error_free_pcms;
        }
 
-       /* And finally, register the socdev */
-       ret = snd_soc_init_card(socdev);
-       if (ret < 0) {
-               dev_err(codec->dev, "failed to register card\n");
-               goto error_free_pcms;
-       }
-
        return 0;
 
 error_free_pcms:
@@ -802,22 +796,6 @@ MODULE_DEVICE_TABLE(i2c, cs4270_id);
  * and all registers are written back to the hardware when resuming.
  */
 
-static int cs4270_i2c_suspend(struct i2c_client *client, pm_message_t mesg)
-{
-       struct cs4270_private *cs4270 = i2c_get_clientdata(client);
-       struct snd_soc_codec *codec = &cs4270->codec;
-
-       return snd_soc_suspend_device(codec->dev);
-}
-
-static int cs4270_i2c_resume(struct i2c_client *client)
-{
-       struct cs4270_private *cs4270 = i2c_get_clientdata(client);
-       struct snd_soc_codec *codec = &cs4270->codec;
-
-       return snd_soc_resume_device(codec->dev);
-}
-
 static int cs4270_soc_suspend(struct platform_device *pdev, pm_message_t mesg)
 {
        struct snd_soc_codec *codec = cs4270_codec;
@@ -853,8 +831,6 @@ static int cs4270_soc_resume(struct platform_device *pdev)
        return snd_soc_write(codec, CS4270_PWRCTL, reg);
 }
 #else
-#define cs4270_i2c_suspend     NULL
-#define cs4270_i2c_resume      NULL
 #define cs4270_soc_suspend     NULL
 #define cs4270_soc_resume      NULL
 #endif /* CONFIG_PM */
@@ -873,8 +849,6 @@ static struct i2c_driver cs4270_i2c_driver = {
        .id_table = cs4270_id,
        .probe = cs4270_i2c_probe,
        .remove = cs4270_i2c_remove,
-       .suspend = cs4270_i2c_suspend,
-       .resume = cs4270_i2c_resume,
 };
 
 /*
index 38eac9c..e000cdf 100644 (file)
@@ -93,7 +93,6 @@ static int cx20442_add_widgets(struct snd_soc_codec *codec)
        snd_soc_dapm_add_routes(codec, cx20442_audio_map,
                                ARRAY_SIZE(cx20442_audio_map));
 
-       snd_soc_dapm_new_widgets(codec);
        return 0;
 }
 
@@ -355,17 +354,6 @@ static int cx20442_codec_probe(struct platform_device *pdev)
 
        cx20442_add_widgets(codec);
 
-       ret = snd_soc_init_card(socdev);
-       if (ret < 0) {
-               dev_err(&pdev->dev, "failed to register card\n");
-               goto card_err;
-       }
-
-       return ret;
-
-card_err:
-       snd_soc_free_pcms(socdev);
-       snd_soc_dapm_free(socdev);
 pcm_err:
        return ret;
 }
index 5cda9e6..2afcd0a 100644 (file)
@@ -90,13 +90,6 @@ static int pcm3008_soc_probe(struct platform_device *pdev)
                goto pcm_err;
        }
 
-       /* Register Card. */
-       ret = snd_soc_init_card(socdev);
-       if (ret < 0) {
-               printk(KERN_ERR "pcm3008: failed to register card\n");
-               goto card_err;
-       }
-
        /* DEM1  DEM0  DE-EMPHASIS_MODE
         * Low   Low   De-emphasis 44.1 kHz ON
         * Low   High  De-emphasis OFF
@@ -136,8 +129,6 @@ static int pcm3008_soc_probe(struct platform_device *pdev)
 
 gpio_err:
        pcm3008_gpio_free(setup);
-card_err:
-       snd_soc_free_pcms(socdev);
 pcm_err:
        kfree(socdev->card->codec);
 
index c550750..d2ff1cd 100644 (file)
@@ -210,7 +210,6 @@ static int ssm2602_add_widgets(struct snd_soc_codec *codec)
 
        snd_soc_dapm_add_routes(codec, audio_conn, ARRAY_SIZE(audio_conn));
 
-       snd_soc_dapm_new_widgets(codec);
        return 0;
 }
 
@@ -613,17 +612,9 @@ static int ssm2602_init(struct snd_soc_device *socdev)
        snd_soc_add_controls(codec, ssm2602_snd_controls,
                                ARRAY_SIZE(ssm2602_snd_controls));
        ssm2602_add_widgets(codec);
-       ret = snd_soc_init_card(socdev);
-       if (ret < 0) {
-               pr_err("ssm2602: failed to register card\n");
-               goto card_err;
-       }
 
        return ret;
 
-card_err:
-       snd_soc_free_pcms(socdev);
-       snd_soc_dapm_free(socdev);
 pcm_err:
        kfree(codec->reg_cache);
        return ret;
index befc648..bbc72c2 100644 (file)
@@ -418,9 +418,6 @@ static int stac9766_codec_probe(struct platform_device *pdev)
        snd_soc_add_controls(codec, stac9766_snd_ac97_controls,
                             ARRAY_SIZE(stac9766_snd_ac97_controls));
 
-       ret = snd_soc_init_card(socdev);
-       if (ret < 0)
-               goto reset_err;
        return 0;
 
 reset_err:
index 90a0264..a9dc5fb 100644 (file)
@@ -85,7 +85,7 @@ static int tlv320aic23_write(struct snd_soc_codec *codec, unsigned int reg,
         * of data into val
         */
 
-       if ((reg < 0 || reg > 9) && (reg != 15)) {
+       if (reg > 9 && reg != 15) {
                printk(KERN_WARNING "%s Invalid register R%u\n", __func__, reg);
                return -1;
        }
@@ -395,7 +395,6 @@ static int tlv320aic23_add_widgets(struct snd_soc_codec *codec)
        /* set up audio path interconnects */
        snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon));
 
-       snd_soc_dapm_new_widgets(codec);
        return 0;
 }
 
@@ -706,17 +705,9 @@ static int tlv320aic23_init(struct snd_soc_device *socdev)
        snd_soc_add_controls(codec, tlv320aic23_snd_controls,
                                ARRAY_SIZE(tlv320aic23_snd_controls));
        tlv320aic23_add_widgets(codec);
-       ret = snd_soc_init_card(socdev);
-       if (ret < 0) {
-               printk(KERN_ERR "tlv320aic23: failed to register card\n");
-               goto card_err;
-       }
 
        return ret;
 
-card_err:
-       snd_soc_free_pcms(socdev);
-       snd_soc_dapm_free(socdev);
 pcm_err:
        kfree(codec->reg_cache);
        return ret;
index 3387d9e..357b609 100644 (file)
@@ -356,18 +356,7 @@ static int aic26_probe(struct platform_device *pdev)
                        ARRAY_SIZE(aic26_snd_controls));
        WARN_ON(err < 0);
 
-       /* CODEC is setup, we can register the card now */
-       dev_dbg(&pdev->dev, "Registering card\n");
-       ret = snd_soc_init_card(socdev);
-       if (ret < 0) {
-               dev_err(&pdev->dev, "aic26: failed to register card\n");
-               goto card_err;
-       }
        return 0;
-
- card_err:
-       snd_soc_free_pcms(socdev);
-       return ret;
 }
 
 static int aic26_remove(struct platform_device *pdev)
index 3395cf9..2b4dc2b 100644 (file)
@@ -753,7 +753,6 @@ static int aic3x_add_widgets(struct snd_soc_codec *codec)
        /* set up audio path interconnects */
        snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon));
 
-       snd_soc_dapm_new_widgets(codec);
        return 0;
 }
 
@@ -1405,18 +1404,8 @@ static int aic3x_probe(struct platform_device *pdev)
 
        aic3x_add_widgets(codec);
 
-       ret = snd_soc_init_card(socdev);
-       if (ret < 0) {
-               printk(KERN_ERR "aic3x: failed to register card\n");
-               goto card_err;
-       }
-
        return ret;
 
-card_err:
-       snd_soc_free_pcms(socdev);
-       snd_soc_dapm_free(socdev);
-
 pcm_err:
        kfree(codec->reg_cache);
        return ret;
diff --git a/sound/soc/codecs/tlv320dac33.c b/sound/soc/codecs/tlv320dac33.c
new file mode 100644 (file)
index 0000000..9c8903d
--- /dev/null
@@ -0,0 +1,1229 @@
+/*
+ * ALSA SoC Texas Instruments TLV320DAC33 codec driver
+ *
+ * Author:     Peter Ujfalusi <peter.ujfalusi@nokia.com>
+ *
+ * Copyright:   (C) 2009 Nokia Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/gpio.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+
+#include <sound/tlv320dac33-plat.h>
+#include "tlv320dac33.h"
+
+#define DAC33_BUFFER_SIZE_BYTES                24576   /* bytes, 12288 16 bit words,
+                                                * 6144 stereo */
+#define DAC33_BUFFER_SIZE_SAMPLES      6144
+
+#define NSAMPLE_MAX            5700
+
+#define LATENCY_TIME_MS                20
+
+static struct snd_soc_codec *tlv320dac33_codec;
+
+enum dac33_state {
+       DAC33_IDLE = 0,
+       DAC33_PREFILL,
+       DAC33_PLAYBACK,
+       DAC33_FLUSH,
+};
+
+struct tlv320dac33_priv {
+       struct mutex mutex;
+       struct workqueue_struct *dac33_wq;
+       struct work_struct work;
+       struct snd_soc_codec codec;
+       int power_gpio;
+       int chip_power;
+       int irq;
+       unsigned int refclk;
+
+       unsigned int alarm_threshold;   /* set to be half of LATENCY_TIME_MS */
+       unsigned int nsample_min;       /* nsample should not be lower than
+                                        * this */
+       unsigned int nsample_max;       /* nsample should not be higher than
+                                        * this */
+       unsigned int nsample_switch;    /* Use FIFO or bypass FIFO switch */
+       unsigned int nsample;           /* burst read amount from host */
+
+       enum dac33_state state;
+};
+
+static const u8 dac33_reg[DAC33_CACHEREGNUM] = {
+0x00, 0x00, 0x00, 0x00, /* 0x00 - 0x03 */
+0x00, 0x00, 0x00, 0x00, /* 0x04 - 0x07 */
+0x00, 0x00, 0x00, 0x00, /* 0x08 - 0x0b */
+0x00, 0x00, 0x00, 0x00, /* 0x0c - 0x0f */
+0x00, 0x00, 0x00, 0x00, /* 0x10 - 0x13 */
+0x00, 0x00, 0x00, 0x00, /* 0x14 - 0x17 */
+0x00, 0x00, 0x00, 0x00, /* 0x18 - 0x1b */
+0x00, 0x00, 0x00, 0x00, /* 0x1c - 0x1f */
+0x00, 0x00, 0x00, 0x00, /* 0x20 - 0x23 */
+0x00, 0x00, 0x00, 0x00, /* 0x24 - 0x27 */
+0x00, 0x00, 0x00, 0x00, /* 0x28 - 0x2b */
+0x00, 0x00, 0x00, 0x80, /* 0x2c - 0x2f */
+0x80, 0x00, 0x00, 0x00, /* 0x30 - 0x33 */
+0x00, 0x00, 0x00, 0x00, /* 0x34 - 0x37 */
+0x00, 0x00,             /* 0x38 - 0x39 */
+/* Registers 0x3a - 0x3f are reserved  */
+            0x00, 0x00, /* 0x3a - 0x3b */
+0x00, 0x00, 0x00, 0x00, /* 0x3c - 0x3f */
+
+0x00, 0x00, 0x00, 0x00, /* 0x40 - 0x43 */
+0x00, 0x80,             /* 0x44 - 0x45 */
+/* Registers 0x46 - 0x47 are reserved  */
+            0x80, 0x80, /* 0x46 - 0x47 */
+
+0x80, 0x00, 0x00,       /* 0x48 - 0x4a */
+/* Registers 0x4b - 0x7c are reserved  */
+                  0x00, /* 0x4b        */
+0x00, 0x00, 0x00, 0x00, /* 0x4c - 0x4f */
+0x00, 0x00, 0x00, 0x00, /* 0x50 - 0x53 */
+0x00, 0x00, 0x00, 0x00, /* 0x54 - 0x57 */
+0x00, 0x00, 0x00, 0x00, /* 0x58 - 0x5b */
+0x00, 0x00, 0x00, 0x00, /* 0x5c - 0x5f */
+0x00, 0x00, 0x00, 0x00, /* 0x60 - 0x63 */
+0x00, 0x00, 0x00, 0x00, /* 0x64 - 0x67 */
+0x00, 0x00, 0x00, 0x00, /* 0x68 - 0x6b */
+0x00, 0x00, 0x00, 0x00, /* 0x6c - 0x6f */
+0x00, 0x00, 0x00, 0x00, /* 0x70 - 0x73 */
+0x00, 0x00, 0x00, 0x00, /* 0x74 - 0x77 */
+0x00, 0x00, 0x00, 0x00, /* 0x78 - 0x7b */
+0x00,                   /* 0x7c        */
+
+      0xda, 0x33, 0x03, /* 0x7d - 0x7f */
+};
+
+/* Register read and write */
+static inline unsigned int dac33_read_reg_cache(struct snd_soc_codec *codec,
+                                               unsigned reg)
+{
+       u8 *cache = codec->reg_cache;
+       if (reg >= DAC33_CACHEREGNUM)
+               return 0;
+
+       return cache[reg];
+}
+
+static inline void dac33_write_reg_cache(struct snd_soc_codec *codec,
+                                        u8 reg, u8 value)
+{
+       u8 *cache = codec->reg_cache;
+       if (reg >= DAC33_CACHEREGNUM)
+               return;
+
+       cache[reg] = value;
+}
+
+static int dac33_read(struct snd_soc_codec *codec, unsigned int reg,
+                     u8 *value)
+{
+       struct tlv320dac33_priv *dac33 = codec->private_data;
+       int val;
+
+       *value = reg & 0xff;
+
+       /* If powered off, return the cached value */
+       if (dac33->chip_power) {
+               val = i2c_smbus_read_byte_data(codec->control_data, value[0]);
+               if (val < 0) {
+                       dev_err(codec->dev, "Read failed (%d)\n", val);
+                       value[0] = dac33_read_reg_cache(codec, reg);
+               } else {
+                       value[0] = val;
+                       dac33_write_reg_cache(codec, reg, val);
+               }
+       } else {
+               value[0] = dac33_read_reg_cache(codec, reg);
+       }
+
+       return 0;
+}
+
+static int dac33_write(struct snd_soc_codec *codec, unsigned int reg,
+                      unsigned int value)
+{
+       struct tlv320dac33_priv *dac33 = codec->private_data;
+       u8 data[2];
+       int ret = 0;
+
+       /*
+        * data is
+        *   D15..D8 dac33 register offset
+        *   D7...D0 register data
+        */
+       data[0] = reg & 0xff;
+       data[1] = value & 0xff;
+
+       dac33_write_reg_cache(codec, data[0], data[1]);
+       if (dac33->chip_power) {
+               ret = codec->hw_write(codec->control_data, data, 2);
+               if (ret != 2)
+                       dev_err(codec->dev, "Write failed (%d)\n", ret);
+               else
+                       ret = 0;
+       }
+
+       return ret;
+}
+
+static int dac33_write_locked(struct snd_soc_codec *codec, unsigned int reg,
+                      unsigned int value)
+{
+       struct tlv320dac33_priv *dac33 = codec->private_data;
+       int ret;
+
+       mutex_lock(&dac33->mutex);
+       ret = dac33_write(codec, reg, value);
+       mutex_unlock(&dac33->mutex);
+
+       return ret;
+}
+
+#define DAC33_I2C_ADDR_AUTOINC 0x80
+static int dac33_write16(struct snd_soc_codec *codec, unsigned int reg,
+                      unsigned int value)
+{
+       struct tlv320dac33_priv *dac33 = codec->private_data;
+       u8 data[3];
+       int ret = 0;
+
+       /*
+        * data is
+        *   D23..D16 dac33 register offset
+        *   D15..D8  register data MSB
+        *   D7...D0  register data LSB
+        */
+       data[0] = reg & 0xff;
+       data[1] = (value >> 8) & 0xff;
+       data[2] = value & 0xff;
+
+       dac33_write_reg_cache(codec, data[0], data[1]);
+       dac33_write_reg_cache(codec, data[0] + 1, data[2]);
+
+       if (dac33->chip_power) {
+               /* We need to set autoincrement mode for 16 bit writes */
+               data[0] |= DAC33_I2C_ADDR_AUTOINC;
+               ret = codec->hw_write(codec->control_data, data, 3);
+               if (ret != 3)
+                       dev_err(codec->dev, "Write failed (%d)\n", ret);
+               else
+                       ret = 0;
+       }
+
+       return ret;
+}
+
+static void dac33_restore_regs(struct snd_soc_codec *codec)
+{
+       struct tlv320dac33_priv *dac33 = codec->private_data;
+       u8 *cache = codec->reg_cache;
+       u8 data[2];
+       int i, ret;
+
+       if (!dac33->chip_power)
+               return;
+
+       for (i = DAC33_PWR_CTRL; i <= DAC33_INTP_CTRL_B; i++) {
+               data[0] = i;
+               data[1] = cache[i];
+               /* Skip the read only registers */
+               if ((i >= DAC33_INT_OSC_STATUS &&
+                               i <= DAC33_INT_OSC_FREQ_RAT_READ_B) ||
+                   (i >= DAC33_FIFO_WPTR_MSB && i <= DAC33_FIFO_IRQ_FLAG) ||
+                   i == DAC33_DAC_STATUS_FLAGS ||
+                   i == DAC33_SRC_EST_REF_CLK_RATIO_A ||
+                   i == DAC33_SRC_EST_REF_CLK_RATIO_B)
+                       continue;
+               ret = codec->hw_write(codec->control_data, data, 2);
+               if (ret != 2)
+                       dev_err(codec->dev, "Write failed (%d)\n", ret);
+       }
+       for (i = DAC33_LDAC_PWR_CTRL; i <= DAC33_LINEL_TO_LLO_VOL; i++) {
+               data[0] = i;
+               data[1] = cache[i];
+               ret = codec->hw_write(codec->control_data, data, 2);
+               if (ret != 2)
+                       dev_err(codec->dev, "Write failed (%d)\n", ret);
+       }
+       for (i = DAC33_LINER_TO_RLO_VOL; i <= DAC33_OSC_TRIM; i++) {
+               data[0] = i;
+               data[1] = cache[i];
+               ret = codec->hw_write(codec->control_data, data, 2);
+               if (ret != 2)
+                       dev_err(codec->dev, "Write failed (%d)\n", ret);
+       }
+}
+
+static inline void dac33_soft_power(struct snd_soc_codec *codec, int power)
+{
+       u8 reg;
+
+       reg = dac33_read_reg_cache(codec, DAC33_PWR_CTRL);
+       if (power)
+               reg |= DAC33_PDNALLB;
+       else
+               reg &= ~DAC33_PDNALLB;
+       dac33_write(codec, DAC33_PWR_CTRL, reg);
+}
+
+static void dac33_hard_power(struct snd_soc_codec *codec, int power)
+{
+       struct tlv320dac33_priv *dac33 = codec->private_data;
+
+       mutex_lock(&dac33->mutex);
+       if (power) {
+               if (dac33->power_gpio >= 0) {
+                       gpio_set_value(dac33->power_gpio, 1);
+                       dac33->chip_power = 1;
+                       /* Restore registers */
+                       dac33_restore_regs(codec);
+               }
+               dac33_soft_power(codec, 1);
+       } else {
+               dac33_soft_power(codec, 0);
+               if (dac33->power_gpio >= 0) {
+                       gpio_set_value(dac33->power_gpio, 0);
+                       dac33->chip_power = 0;
+               }
+       }
+       mutex_unlock(&dac33->mutex);
+
+}
+
+static int dac33_get_nsample(struct snd_kcontrol *kcontrol,
+                        struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct tlv320dac33_priv *dac33 = codec->private_data;
+
+       ucontrol->value.integer.value[0] = dac33->nsample;
+
+       return 0;
+}
+
+static int dac33_set_nsample(struct snd_kcontrol *kcontrol,
+                        struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct tlv320dac33_priv *dac33 = codec->private_data;
+       int ret = 0;
+
+       if (dac33->nsample == ucontrol->value.integer.value[0])
+               return 0;
+
+       if (ucontrol->value.integer.value[0] < dac33->nsample_min ||
+           ucontrol->value.integer.value[0] > dac33->nsample_max)
+               ret = -EINVAL;
+       else
+               dac33->nsample = ucontrol->value.integer.value[0];
+
+       return ret;
+}
+
+static int dac33_get_nsample_switch(struct snd_kcontrol *kcontrol,
+                        struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct tlv320dac33_priv *dac33 = codec->private_data;
+
+       ucontrol->value.integer.value[0] = dac33->nsample_switch;
+
+       return 0;
+}
+
+static int dac33_set_nsample_switch(struct snd_kcontrol *kcontrol,
+                        struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct tlv320dac33_priv *dac33 = codec->private_data;
+       int ret = 0;
+
+       if (dac33->nsample_switch == ucontrol->value.integer.value[0])
+               return 0;
+       /* Do not allow changes while stream is running*/
+       if (codec->active)
+               return -EPERM;
+
+       if (ucontrol->value.integer.value[0] < 0 ||
+           ucontrol->value.integer.value[0] > 1)
+               ret = -EINVAL;
+       else
+               dac33->nsample_switch = ucontrol->value.integer.value[0];
+
+       return ret;
+}
+
+/*
+ * DACL/R digital volume control:
+ * from 0 dB to -63.5 in 0.5 dB steps
+ * Need to be inverted later on:
+ * 0x00 == 0 dB
+ * 0x7f == -63.5 dB
+ */
+static DECLARE_TLV_DB_SCALE(dac_digivol_tlv, -6350, 50, 0);
+
+static const struct snd_kcontrol_new dac33_snd_controls[] = {
+       SOC_DOUBLE_R_TLV("DAC Digital Playback Volume",
+               DAC33_LDAC_DIG_VOL_CTRL, DAC33_RDAC_DIG_VOL_CTRL,
+               0, 0x7f, 1, dac_digivol_tlv),
+       SOC_DOUBLE_R("DAC Digital Playback Switch",
+                DAC33_LDAC_DIG_VOL_CTRL, DAC33_RDAC_DIG_VOL_CTRL, 7, 1, 1),
+       SOC_DOUBLE_R("Line to Line Out Volume",
+                DAC33_LINEL_TO_LLO_VOL, DAC33_LINER_TO_RLO_VOL, 0, 127, 1),
+};
+
+static const struct snd_kcontrol_new dac33_nsample_snd_controls[] = {
+       SOC_SINGLE_EXT("nSample", 0, 0, 5900, 0,
+                dac33_get_nsample, dac33_set_nsample),
+       SOC_SINGLE_EXT("nSample Switch", 0, 0, 1, 0,
+                dac33_get_nsample_switch, dac33_set_nsample_switch),
+};
+
+/* Analog bypass */
+static const struct snd_kcontrol_new dac33_dapm_abypassl_control =
+       SOC_DAPM_SINGLE("Switch", DAC33_LINEL_TO_LLO_VOL, 7, 1, 1);
+
+static const struct snd_kcontrol_new dac33_dapm_abypassr_control =
+       SOC_DAPM_SINGLE("Switch", DAC33_LINER_TO_RLO_VOL, 7, 1, 1);
+
+static const struct snd_soc_dapm_widget dac33_dapm_widgets[] = {
+       SND_SOC_DAPM_OUTPUT("LEFT_LO"),
+       SND_SOC_DAPM_OUTPUT("RIGHT_LO"),
+
+       SND_SOC_DAPM_INPUT("LINEL"),
+       SND_SOC_DAPM_INPUT("LINER"),
+
+       SND_SOC_DAPM_DAC("DACL", "Left Playback", DAC33_LDAC_PWR_CTRL, 2, 0),
+       SND_SOC_DAPM_DAC("DACR", "Right Playback", DAC33_RDAC_PWR_CTRL, 2, 0),
+
+       /* Analog bypass */
+       SND_SOC_DAPM_SWITCH("Analog Left Bypass", SND_SOC_NOPM, 0, 0,
+                               &dac33_dapm_abypassl_control),
+       SND_SOC_DAPM_SWITCH("Analog Right Bypass", SND_SOC_NOPM, 0, 0,
+                               &dac33_dapm_abypassr_control),
+
+       SND_SOC_DAPM_REG(snd_soc_dapm_mixer, "Output Left Amp Power",
+                        DAC33_OUT_AMP_PWR_CTRL, 6, 3, 3, 0),
+       SND_SOC_DAPM_REG(snd_soc_dapm_mixer, "Output Right Amp Power",
+                        DAC33_OUT_AMP_PWR_CTRL, 4, 3, 3, 0),
+};
+
+static const struct snd_soc_dapm_route audio_map[] = {
+       /* Analog bypass */
+       {"Analog Left Bypass", "Switch", "LINEL"},
+       {"Analog Right Bypass", "Switch", "LINER"},
+
+       {"Output Left Amp Power", NULL, "DACL"},
+       {"Output Right Amp Power", NULL, "DACR"},
+
+       {"Output Left Amp Power", NULL, "Analog Left Bypass"},
+       {"Output Right Amp Power", NULL, "Analog Right Bypass"},
+
+       /* output */
+       {"LEFT_LO", NULL, "Output Left Amp Power"},
+       {"RIGHT_LO", NULL, "Output Right Amp Power"},
+};
+
+static int dac33_add_widgets(struct snd_soc_codec *codec)
+{
+       snd_soc_dapm_new_controls(codec, dac33_dapm_widgets,
+                                 ARRAY_SIZE(dac33_dapm_widgets));
+
+       /* set up audio path interconnects */
+       snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
+
+       return 0;
+}
+
+static int dac33_set_bias_level(struct snd_soc_codec *codec,
+                               enum snd_soc_bias_level level)
+{
+       switch (level) {
+       case SND_SOC_BIAS_ON:
+               dac33_soft_power(codec, 1);
+               break;
+       case SND_SOC_BIAS_PREPARE:
+               break;
+       case SND_SOC_BIAS_STANDBY:
+               if (codec->bias_level == SND_SOC_BIAS_OFF)
+                       dac33_hard_power(codec, 1);
+               dac33_soft_power(codec, 0);
+               break;
+       case SND_SOC_BIAS_OFF:
+               dac33_hard_power(codec, 0);
+               break;
+       }
+       codec->bias_level = level;
+
+       return 0;
+}
+
+static void dac33_work(struct work_struct *work)
+{
+       struct snd_soc_codec *codec;
+       struct tlv320dac33_priv *dac33;
+       u8 reg;
+
+       dac33 = container_of(work, struct tlv320dac33_priv, work);
+       codec = &dac33->codec;
+
+       mutex_lock(&dac33->mutex);
+       switch (dac33->state) {
+       case DAC33_PREFILL:
+               dac33->state = DAC33_PLAYBACK;
+               dac33_write16(codec, DAC33_NSAMPLE_MSB,
+                               DAC33_THRREG(dac33->nsample));
+               dac33_write16(codec, DAC33_PREFILL_MSB,
+                               DAC33_THRREG(dac33->alarm_threshold));
+               break;
+       case DAC33_PLAYBACK:
+               dac33_write16(codec, DAC33_NSAMPLE_MSB,
+                               DAC33_THRREG(dac33->nsample));
+               break;
+       case DAC33_IDLE:
+               break;
+       case DAC33_FLUSH:
+               dac33->state = DAC33_IDLE;
+               /* Mask all interrupts from dac33 */
+               dac33_write(codec, DAC33_FIFO_IRQ_MASK, 0);
+
+               /* flush fifo */
+               reg = dac33_read_reg_cache(codec, DAC33_FIFO_CTRL_A);
+               reg |= DAC33_FIFOFLUSH;
+               dac33_write(codec, DAC33_FIFO_CTRL_A, reg);
+               break;
+       }
+       mutex_unlock(&dac33->mutex);
+}
+
+static irqreturn_t dac33_interrupt_handler(int irq, void *dev)
+{
+       struct snd_soc_codec *codec = dev;
+       struct tlv320dac33_priv *dac33 = codec->private_data;
+
+       queue_work(dac33->dac33_wq, &dac33->work);
+
+       return IRQ_HANDLED;
+}
+
+static void dac33_shutdown(struct snd_pcm_substream *substream,
+                            struct snd_soc_dai *dai)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_device *socdev = rtd->socdev;
+       struct snd_soc_codec *codec = socdev->card->codec;
+       struct tlv320dac33_priv *dac33 = codec->private_data;
+       unsigned int pwr_ctrl;
+
+       /* Stop pending workqueue */
+       if (dac33->nsample_switch)
+               cancel_work_sync(&dac33->work);
+
+       mutex_lock(&dac33->mutex);
+       pwr_ctrl = dac33_read_reg_cache(codec, DAC33_PWR_CTRL);
+       pwr_ctrl &= ~(DAC33_OSCPDNB | DAC33_DACRPDNB | DAC33_DACLPDNB);
+       dac33_write(codec, DAC33_PWR_CTRL, pwr_ctrl);
+       mutex_unlock(&dac33->mutex);
+}
+
+static void dac33_oscwait(struct snd_soc_codec *codec)
+{
+       int timeout = 20;
+       u8 reg;
+
+       do {
+               msleep(1);
+               dac33_read(codec, DAC33_INT_OSC_STATUS, &reg);
+       } while (((reg & 0x03) != DAC33_OSCSTATUS_NORMAL) && timeout--);
+       if ((reg & 0x03) != DAC33_OSCSTATUS_NORMAL)
+               dev_err(codec->dev,
+                       "internal oscillator calibration failed\n");
+}
+
+static int dac33_hw_params(struct snd_pcm_substream *substream,
+                          struct snd_pcm_hw_params *params,
+                          struct snd_soc_dai *dai)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_device *socdev = rtd->socdev;
+       struct snd_soc_codec *codec = socdev->card->codec;
+
+       /* Check parameters for validity */
+       switch (params_rate(params)) {
+       case 44100:
+       case 48000:
+               break;
+       default:
+               dev_err(codec->dev, "unsupported rate %d\n",
+                       params_rate(params));
+               return -EINVAL;
+       }
+
+       switch (params_format(params)) {
+       case SNDRV_PCM_FORMAT_S16_LE:
+               break;
+       default:
+               dev_err(codec->dev, "unsupported format %d\n",
+                       params_format(params));
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+#define CALC_OSCSET(rate, refclk) ( \
+       ((((rate * 10000) / refclk) * 4096) + 5000) / 10000)
+#define CALC_RATIOSET(rate, refclk) ( \
+       ((((refclk  * 100000) / rate) * 16384) + 50000) / 100000)
+
+/*
+ * tlv320dac33 is strict on the sequence of the register writes, if the register
+ * writes happens in different order, than dac33 might end up in unknown state.
+ * Use the known, working sequence of register writes to initialize the dac33.
+ */
+static int dac33_prepare_chip(struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_device *socdev = rtd->socdev;
+       struct snd_soc_codec *codec = socdev->card->codec;
+       struct tlv320dac33_priv *dac33 = codec->private_data;
+       unsigned int oscset, ratioset, pwr_ctrl, reg_tmp;
+       u8 aictrl_a, fifoctrl_a;
+
+       switch (substream->runtime->rate) {
+       case 44100:
+       case 48000:
+               oscset = CALC_OSCSET(substream->runtime->rate, dac33->refclk);
+               ratioset = CALC_RATIOSET(substream->runtime->rate,
+                                        dac33->refclk);
+               break;
+       default:
+               dev_err(codec->dev, "unsupported rate %d\n",
+                       substream->runtime->rate);
+               return -EINVAL;
+       }
+
+
+       aictrl_a = dac33_read_reg_cache(codec, DAC33_SER_AUDIOIF_CTRL_A);
+       aictrl_a &= ~(DAC33_NCYCL_MASK | DAC33_WLEN_MASK);
+       fifoctrl_a = dac33_read_reg_cache(codec, DAC33_FIFO_CTRL_A);
+       fifoctrl_a &= ~DAC33_WIDTH;
+       switch (substream->runtime->format) {
+       case SNDRV_PCM_FORMAT_S16_LE:
+               aictrl_a |= (DAC33_NCYCL_16 | DAC33_WLEN_16);
+               fifoctrl_a |= DAC33_WIDTH;
+               break;
+       default:
+               dev_err(codec->dev, "unsupported format %d\n",
+                       substream->runtime->format);
+               return -EINVAL;
+       }
+
+       mutex_lock(&dac33->mutex);
+       dac33_soft_power(codec, 1);
+
+       reg_tmp = dac33_read_reg_cache(codec, DAC33_INT_OSC_CTRL);
+       dac33_write(codec, DAC33_INT_OSC_CTRL, reg_tmp);
+
+       /* Write registers 0x08 and 0x09 (MSB, LSB) */
+       dac33_write16(codec, DAC33_INT_OSC_FREQ_RAT_A, oscset);
+
+       /* calib time: 128 is a nice number ;) */
+       dac33_write(codec, DAC33_CALIB_TIME, 128);
+
+       /* adjustment treshold & step */
+       dac33_write(codec, DAC33_INT_OSC_CTRL_B, DAC33_ADJTHRSHLD(2) |
+                                                DAC33_ADJSTEP(1));
+
+       /* div=4 / gain=1 / div */
+       dac33_write(codec, DAC33_INT_OSC_CTRL_C, DAC33_REFDIV(4));
+
+       pwr_ctrl = dac33_read_reg_cache(codec, DAC33_PWR_CTRL);
+       pwr_ctrl |= DAC33_OSCPDNB | DAC33_DACRPDNB | DAC33_DACLPDNB;
+       dac33_write(codec, DAC33_PWR_CTRL, pwr_ctrl);
+
+       dac33_oscwait(codec);
+
+       if (dac33->nsample_switch) {
+               /* 50-51 : ASRC Control registers */
+               dac33_write(codec, DAC33_ASRC_CTRL_A, (1 << 4)); /* div=2 */
+               dac33_write(codec, DAC33_ASRC_CTRL_B, 1); /* ??? */
+
+               /* Write registers 0x34 and 0x35 (MSB, LSB) */
+               dac33_write16(codec, DAC33_SRC_REF_CLK_RATIO_A, ratioset);
+
+               /* Set interrupts to high active */
+               dac33_write(codec, DAC33_INTP_CTRL_A, DAC33_INTPM_AHIGH);
+
+               dac33_write(codec, DAC33_FIFO_IRQ_MODE_B,
+                           DAC33_ATM(DAC33_FIFO_IRQ_MODE_LEVEL));
+               dac33_write(codec, DAC33_FIFO_IRQ_MASK, DAC33_MAT);
+       } else {
+               /* 50-51 : ASRC Control registers */
+               dac33_write(codec, DAC33_ASRC_CTRL_A, DAC33_SRCBYP);
+               dac33_write(codec, DAC33_ASRC_CTRL_B, 0); /* ??? */
+       }
+
+       if (dac33->nsample_switch)
+               fifoctrl_a &= ~DAC33_FBYPAS;
+       else
+               fifoctrl_a |= DAC33_FBYPAS;
+       dac33_write(codec, DAC33_FIFO_CTRL_A, fifoctrl_a);
+
+       dac33_write(codec, DAC33_SER_AUDIOIF_CTRL_A, aictrl_a);
+       reg_tmp = dac33_read_reg_cache(codec, DAC33_SER_AUDIOIF_CTRL_B);
+       if (dac33->nsample_switch)
+               reg_tmp &= ~DAC33_BCLKON;
+       else
+               reg_tmp |= DAC33_BCLKON;
+       dac33_write(codec, DAC33_SER_AUDIOIF_CTRL_B, reg_tmp);
+
+       if (dac33->nsample_switch) {
+               /* 20: BCLK divide ratio */
+               dac33_write(codec, DAC33_SER_AUDIOIF_CTRL_C, 3);
+
+               dac33_write16(codec, DAC33_ATHR_MSB,
+                             DAC33_THRREG(dac33->alarm_threshold));
+       } else {
+               dac33_write(codec, DAC33_SER_AUDIOIF_CTRL_C, 32);
+       }
+
+       mutex_unlock(&dac33->mutex);
+
+       return 0;
+}
+
+static void dac33_calculate_times(struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_device *socdev = rtd->socdev;
+       struct snd_soc_codec *codec = socdev->card->codec;
+       struct tlv320dac33_priv *dac33 = codec->private_data;
+       unsigned int nsample_limit;
+
+       /* Number of samples (16bit, stereo) in one period */
+       dac33->nsample_min = snd_pcm_lib_period_bytes(substream) / 4;
+
+       /* Number of samples (16bit, stereo) in ALSA buffer */
+       dac33->nsample_max = snd_pcm_lib_buffer_bytes(substream) / 4;
+       /* Subtract one period from the total */
+       dac33->nsample_max -= dac33->nsample_min;
+
+       /* Number of samples for LATENCY_TIME_MS / 2 */
+       dac33->alarm_threshold = substream->runtime->rate /
+                                (1000 / (LATENCY_TIME_MS / 2));
+
+       /* Find and fix up the lowest nsmaple limit */
+       nsample_limit = substream->runtime->rate / (1000 / LATENCY_TIME_MS);
+
+       if (dac33->nsample_min < nsample_limit)
+               dac33->nsample_min = nsample_limit;
+
+       if (dac33->nsample < dac33->nsample_min)
+               dac33->nsample = dac33->nsample_min;
+
+       /*
+        * Find and fix up the highest nsmaple limit
+        * In order to not overflow the DAC33 buffer substract the
+        * alarm_threshold value from the size of the DAC33 buffer
+        */
+       nsample_limit = DAC33_BUFFER_SIZE_SAMPLES - dac33->alarm_threshold;
+
+       if (dac33->nsample_max > nsample_limit)
+               dac33->nsample_max = nsample_limit;
+
+       if (dac33->nsample > dac33->nsample_max)
+               dac33->nsample = dac33->nsample_max;
+}
+
+static int dac33_pcm_prepare(struct snd_pcm_substream *substream,
+                            struct snd_soc_dai *dai)
+{
+       dac33_calculate_times(substream);
+       dac33_prepare_chip(substream);
+
+       return 0;
+}
+
+static int dac33_pcm_trigger(struct snd_pcm_substream *substream, int cmd,
+                            struct snd_soc_dai *dai)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_device *socdev = rtd->socdev;
+       struct snd_soc_codec *codec = socdev->card->codec;
+       struct tlv320dac33_priv *dac33 = codec->private_data;
+       int ret = 0;
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+       case SNDRV_PCM_TRIGGER_RESUME:
+       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+               if (dac33->nsample_switch) {
+                       dac33->state = DAC33_PREFILL;
+                       queue_work(dac33->dac33_wq, &dac33->work);
+               }
+               break;
+       case SNDRV_PCM_TRIGGER_STOP:
+       case SNDRV_PCM_TRIGGER_SUSPEND:
+       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+               if (dac33->nsample_switch) {
+                       dac33->state = DAC33_FLUSH;
+                       queue_work(dac33->dac33_wq, &dac33->work);
+               }
+               break;
+       default:
+               ret = -EINVAL;
+       }
+
+       return ret;
+}
+
+static int dac33_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+               int clk_id, unsigned int freq, int dir)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+       struct tlv320dac33_priv *dac33 = codec->private_data;
+       u8 ioc_reg, asrcb_reg;
+
+       ioc_reg = dac33_read_reg_cache(codec, DAC33_INT_OSC_CTRL);
+       asrcb_reg = dac33_read_reg_cache(codec, DAC33_ASRC_CTRL_B);
+       switch (clk_id) {
+       case TLV320DAC33_MCLK:
+               ioc_reg |= DAC33_REFSEL;
+               asrcb_reg |= DAC33_SRCREFSEL;
+               break;
+       case TLV320DAC33_SLEEPCLK:
+               ioc_reg &= ~DAC33_REFSEL;
+               asrcb_reg &= ~DAC33_SRCREFSEL;
+               break;
+       default:
+               dev_err(codec->dev, "Invalid clock ID (%d)\n", clk_id);
+               break;
+       }
+       dac33->refclk = freq;
+
+       dac33_write_reg_cache(codec, DAC33_INT_OSC_CTRL, ioc_reg);
+       dac33_write_reg_cache(codec, DAC33_ASRC_CTRL_B, asrcb_reg);
+
+       return 0;
+}
+
+static int dac33_set_dai_fmt(struct snd_soc_dai *codec_dai,
+                            unsigned int fmt)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+       u8 aictrl_a, aictrl_b;
+
+       aictrl_a = dac33_read_reg_cache(codec, DAC33_SER_AUDIOIF_CTRL_A);
+       aictrl_b = dac33_read_reg_cache(codec, DAC33_SER_AUDIOIF_CTRL_B);
+       /* set master/slave audio interface */
+       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_CBM_CFM:
+               /* Codec Master */
+               aictrl_a |= (DAC33_MSBCLK | DAC33_MSWCLK);
+               break;
+       case SND_SOC_DAIFMT_CBS_CFS:
+               /* Codec Slave */
+               aictrl_a &= ~(DAC33_MSBCLK | DAC33_MSWCLK);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       aictrl_a &= ~DAC33_AFMT_MASK;
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_I2S:
+               aictrl_a |= DAC33_AFMT_I2S;
+               break;
+       case SND_SOC_DAIFMT_DSP_A:
+               aictrl_a |= DAC33_AFMT_DSP;
+               aictrl_b &= ~DAC33_DATA_DELAY_MASK;
+               aictrl_b |= DAC33_DATA_DELAY(1); /* 1 bit delay */
+               break;
+       case SND_SOC_DAIFMT_DSP_B:
+               aictrl_a |= DAC33_AFMT_DSP;
+               aictrl_b &= ~DAC33_DATA_DELAY_MASK; /* No delay */
+               break;
+       case SND_SOC_DAIFMT_RIGHT_J:
+               aictrl_a |= DAC33_AFMT_RIGHT_J;
+               break;
+       case SND_SOC_DAIFMT_LEFT_J:
+               aictrl_a |= DAC33_AFMT_LEFT_J;
+               break;
+       default:
+               dev_err(codec->dev, "Unsupported format (%u)\n",
+                       fmt & SND_SOC_DAIFMT_FORMAT_MASK);
+               return -EINVAL;
+       }
+
+       dac33_write_reg_cache(codec, DAC33_SER_AUDIOIF_CTRL_A, aictrl_a);
+       dac33_write_reg_cache(codec, DAC33_SER_AUDIOIF_CTRL_B, aictrl_b);
+
+       return 0;
+}
+
+static void dac33_init_chip(struct snd_soc_codec *codec)
+{
+       /* 44-46: DAC Control Registers */
+       /* A : DAC sample rate Fsref/1.5 */
+       dac33_write(codec, DAC33_DAC_CTRL_A, DAC33_DACRATE(1));
+       /* B : DAC src=normal, not muted */
+       dac33_write(codec, DAC33_DAC_CTRL_B, DAC33_DACSRCR_RIGHT |
+                                            DAC33_DACSRCL_LEFT);
+       /* C : (defaults) */
+       dac33_write(codec, DAC33_DAC_CTRL_C, 0x00);
+
+       /* 64-65 : L&R DAC power control
+        Line In -> OUT 1V/V Gain, DAC -> OUT 4V/V Gain*/
+       dac33_write(codec, DAC33_LDAC_PWR_CTRL, DAC33_LROUT_GAIN(2));
+       dac33_write(codec, DAC33_RDAC_PWR_CTRL, DAC33_LROUT_GAIN(2));
+
+       /* 73 : volume soft stepping control,
+        clock source = internal osc (?) */
+       dac33_write(codec, DAC33_ANA_VOL_SOFT_STEP_CTRL, DAC33_VOLCLKEN);
+
+       /* 66 : LOP/LOM Modes */
+       dac33_write(codec, DAC33_OUT_AMP_CM_CTRL, 0xff);
+
+       /* 68 : LOM inverted from LOP */
+       dac33_write(codec, DAC33_OUT_AMP_CTRL, (3<<2));
+
+       dac33_write(codec, DAC33_PWR_CTRL, DAC33_PDNALLB);
+}
+
+static int dac33_soc_probe(struct platform_device *pdev)
+{
+       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+       struct snd_soc_codec *codec;
+       struct tlv320dac33_priv *dac33;
+       int ret = 0;
+
+       BUG_ON(!tlv320dac33_codec);
+
+       codec = tlv320dac33_codec;
+       socdev->card->codec = codec;
+       dac33 = codec->private_data;
+
+       /* Power up the codec */
+       dac33_hard_power(codec, 1);
+       /* Set default configuration */
+       dac33_init_chip(codec);
+
+       /* register pcms */
+       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
+       if (ret < 0) {
+               dev_err(codec->dev, "failed to create pcms\n");
+               goto pcm_err;
+       }
+
+       snd_soc_add_controls(codec, dac33_snd_controls,
+                            ARRAY_SIZE(dac33_snd_controls));
+       /* Only add the nSample controls, if we have valid IRQ number */
+       if (dac33->irq >= 0)
+               snd_soc_add_controls(codec, dac33_nsample_snd_controls,
+                                    ARRAY_SIZE(dac33_nsample_snd_controls));
+
+       dac33_add_widgets(codec);
+
+       /* power on device */
+       dac33_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+       return 0;
+
+pcm_err:
+       dac33_hard_power(codec, 0);
+       return ret;
+}
+
+static int dac33_soc_remove(struct platform_device *pdev)
+{
+       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+       struct snd_soc_codec *codec = socdev->card->codec;
+
+       dac33_set_bias_level(codec, SND_SOC_BIAS_OFF);
+
+       snd_soc_free_pcms(socdev);
+       snd_soc_dapm_free(socdev);
+
+       return 0;
+}
+
+static int dac33_soc_suspend(struct platform_device *pdev, pm_message_t state)
+{
+       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+       struct snd_soc_codec *codec = socdev->card->codec;
+
+       dac33_set_bias_level(codec, SND_SOC_BIAS_OFF);
+
+       return 0;
+}
+
+static int dac33_soc_resume(struct platform_device *pdev)
+{
+       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+       struct snd_soc_codec *codec = socdev->card->codec;
+
+       dac33_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+       dac33_set_bias_level(codec, codec->suspend_bias_level);
+
+       return 0;
+}
+
+struct snd_soc_codec_device soc_codec_dev_tlv320dac33 = {
+       .probe = dac33_soc_probe,
+       .remove = dac33_soc_remove,
+       .suspend = dac33_soc_suspend,
+       .resume = dac33_soc_resume,
+};
+EXPORT_SYMBOL_GPL(soc_codec_dev_tlv320dac33);
+
+#define DAC33_RATES    (SNDRV_PCM_RATE_44100 | \
+                        SNDRV_PCM_RATE_48000)
+#define DAC33_FORMATS  SNDRV_PCM_FMTBIT_S16_LE
+
+static struct snd_soc_dai_ops dac33_dai_ops = {
+       .shutdown       = dac33_shutdown,
+       .hw_params      = dac33_hw_params,
+       .prepare        = dac33_pcm_prepare,
+       .trigger        = dac33_pcm_trigger,
+       .set_sysclk     = dac33_set_dai_sysclk,
+       .set_fmt        = dac33_set_dai_fmt,
+};
+
+struct snd_soc_dai dac33_dai = {
+       .name = "tlv320dac33",
+       .playback = {
+               .stream_name = "Playback",
+               .channels_min = 2,
+               .channels_max = 2,
+               .rates = DAC33_RATES,
+               .formats = DAC33_FORMATS,},
+       .ops = &dac33_dai_ops,
+};
+EXPORT_SYMBOL_GPL(dac33_dai);
+
+static int dac33_i2c_probe(struct i2c_client *client,
+                          const struct i2c_device_id *id)
+{
+       struct tlv320dac33_platform_data *pdata;
+       struct tlv320dac33_priv *dac33;
+       struct snd_soc_codec *codec;
+       int ret = 0;
+
+       if (client->dev.platform_data == NULL) {
+               dev_err(&client->dev, "Platform data not set\n");
+               return -ENODEV;
+       }
+       pdata = client->dev.platform_data;
+
+       dac33 = kzalloc(sizeof(struct tlv320dac33_priv), GFP_KERNEL);
+       if (dac33 == NULL)
+               return -ENOMEM;
+
+       codec = &dac33->codec;
+       codec->private_data = dac33;
+       codec->control_data = client;
+
+       mutex_init(&codec->mutex);
+       mutex_init(&dac33->mutex);
+       INIT_LIST_HEAD(&codec->dapm_widgets);
+       INIT_LIST_HEAD(&codec->dapm_paths);
+
+       codec->name = "tlv320dac33";
+       codec->owner = THIS_MODULE;
+       codec->read = dac33_read_reg_cache;
+       codec->write = dac33_write_locked;
+       codec->hw_write = (hw_write_t) i2c_master_send;
+       codec->bias_level = SND_SOC_BIAS_OFF;
+       codec->set_bias_level = dac33_set_bias_level;
+       codec->dai = &dac33_dai;
+       codec->num_dai = 1;
+       codec->reg_cache_size = ARRAY_SIZE(dac33_reg);
+       codec->reg_cache = kmemdup(dac33_reg, ARRAY_SIZE(dac33_reg),
+                                  GFP_KERNEL);
+       if (codec->reg_cache == NULL) {
+               ret = -ENOMEM;
+               goto error_reg;
+       }
+
+       i2c_set_clientdata(client, dac33);
+
+       dac33->power_gpio = pdata->power_gpio;
+       dac33->irq = client->irq;
+       dac33->nsample = NSAMPLE_MAX;
+       /* Disable FIFO use by default */
+       dac33->nsample_switch = 0;
+
+       tlv320dac33_codec = codec;
+
+       codec->dev = &client->dev;
+       dac33_dai.dev = codec->dev;
+
+       /* Check if the reset GPIO number is valid and request it */
+       if (dac33->power_gpio >= 0) {
+               ret = gpio_request(dac33->power_gpio, "tlv320dac33 reset");
+               if (ret < 0) {
+                       dev_err(codec->dev,
+                               "Failed to request reset GPIO (%d)\n",
+                               dac33->power_gpio);
+                       snd_soc_unregister_dai(&dac33_dai);
+                       snd_soc_unregister_codec(codec);
+                       goto error_gpio;
+               }
+               gpio_direction_output(dac33->power_gpio, 0);
+       } else {
+               dac33->chip_power = 1;
+       }
+
+       /* Check if the IRQ number is valid and request it */
+       if (dac33->irq >= 0) {
+               ret = request_irq(dac33->irq, dac33_interrupt_handler,
+                                 IRQF_TRIGGER_RISING | IRQF_DISABLED,
+                                 codec->name, codec);
+               if (ret < 0) {
+                       dev_err(codec->dev, "Could not request IRQ%d (%d)\n",
+                                               dac33->irq, ret);
+                       dac33->irq = -1;
+               }
+               if (dac33->irq != -1) {
+                       /* Setup work queue */
+                       dac33->dac33_wq =
+                               create_singlethread_workqueue("tlv320dac33");
+                       if (dac33->dac33_wq == NULL) {
+                               free_irq(dac33->irq, &dac33->codec);
+                               ret = -ENOMEM;
+                               goto error_wq;
+                       }
+
+                       INIT_WORK(&dac33->work, dac33_work);
+               }
+       }
+
+       ret = snd_soc_register_codec(codec);
+       if (ret != 0) {
+               dev_err(codec->dev, "Failed to register codec: %d\n", ret);
+               goto error_codec;
+       }
+
+       ret = snd_soc_register_dai(&dac33_dai);
+       if (ret != 0) {
+               dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
+               snd_soc_unregister_codec(codec);
+               goto error_codec;
+       }
+
+       /* Shut down the codec for now */
+       dac33_hard_power(codec, 0);
+
+       return ret;
+
+error_codec:
+       if (dac33->irq >= 0) {
+               free_irq(dac33->irq, &dac33->codec);
+               destroy_workqueue(dac33->dac33_wq);
+       }
+error_wq:
+       if (dac33->power_gpio >= 0)
+               gpio_free(dac33->power_gpio);
+error_gpio:
+       kfree(codec->reg_cache);
+error_reg:
+       tlv320dac33_codec = NULL;
+       kfree(dac33);
+
+       return ret;
+}
+
+static int dac33_i2c_remove(struct i2c_client *client)
+{
+       struct tlv320dac33_priv *dac33;
+
+       dac33 = i2c_get_clientdata(client);
+       dac33_hard_power(&dac33->codec, 0);
+
+       if (dac33->power_gpio >= 0)
+               gpio_free(dac33->power_gpio);
+       if (dac33->irq >= 0)
+               free_irq(dac33->irq, &dac33->codec);
+
+       destroy_workqueue(dac33->dac33_wq);
+       snd_soc_unregister_dai(&dac33_dai);
+       snd_soc_unregister_codec(&dac33->codec);
+       kfree(dac33->codec.reg_cache);
+       kfree(dac33);
+       tlv320dac33_codec = NULL;
+
+       return 0;
+}
+
+static const struct i2c_device_id tlv320dac33_i2c_id[] = {
+       {
+               .name = "tlv320dac33",
+               .driver_data = 0,
+       },
+       { },
+};
+
+static struct i2c_driver tlv320dac33_i2c_driver = {
+       .driver = {
+               .name = "tlv320dac33",
+               .owner = THIS_MODULE,
+       },
+       .probe          = dac33_i2c_probe,
+       .remove         = __devexit_p(dac33_i2c_remove),
+       .id_table       = tlv320dac33_i2c_id,
+};
+
+static int __init dac33_module_init(void)
+{
+       int r;
+       r = i2c_add_driver(&tlv320dac33_i2c_driver);
+       if (r < 0) {
+               printk(KERN_ERR "DAC33: driver registration failed\n");
+               return r;
+       }
+       return 0;
+}
+module_init(dac33_module_init);
+
+static void __exit dac33_module_exit(void)
+{
+       i2c_del_driver(&tlv320dac33_i2c_driver);
+}
+module_exit(dac33_module_exit);
+
+
+MODULE_DESCRIPTION("ASoC TLV320DAC33 codec driver");
+MODULE_AUTHOR("Peter Ujfalusi <peter.ujfalusi@nokia.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/tlv320dac33.h b/sound/soc/codecs/tlv320dac33.h
new file mode 100644 (file)
index 0000000..eb8ae07
--- /dev/null
@@ -0,0 +1,267 @@
+/*
+ * ALSA SoC Texas Instruments TLV320DAC33 codec driver
+ *
+ * Author:     Peter Ujfalusi <peter.ujfalusi@nokia.com>
+ *
+ * Copyright:   (C) 2009 Nokia Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __TLV320DAC33_H
+#define __TLV320DAC33_H
+
+#define DAC33_PAGE_SELECT              0x00
+#define DAC33_PWR_CTRL                 0x01
+#define DAC33_PLL_CTRL_A               0x02
+#define DAC33_PLL_CTRL_B               0x03
+#define DAC33_PLL_CTRL_C               0x04
+#define DAC33_PLL_CTRL_D               0x05
+#define DAC33_PLL_CTRL_E               0x06
+#define DAC33_INT_OSC_CTRL             0x07
+#define DAC33_INT_OSC_FREQ_RAT_A       0x08
+#define DAC33_INT_OSC_FREQ_RAT_B       0x09
+#define DAC33_INT_OSC_DAC_RATIO_SET    0x0A
+#define DAC33_CALIB_TIME               0x0B
+#define DAC33_INT_OSC_CTRL_B           0x0C
+#define DAC33_INT_OSC_CTRL_C           0x0D
+#define DAC33_INT_OSC_STATUS           0x0E
+#define DAC33_INT_OSC_DAC_RATIO_READ   0x0F
+#define DAC33_INT_OSC_FREQ_RAT_READ_A  0x10
+#define DAC33_INT_OSC_FREQ_RAT_READ_B  0x11
+#define DAC33_SER_AUDIOIF_CTRL_A       0x12
+#define DAC33_SER_AUDIOIF_CTRL_B       0x13
+#define DAC33_SER_AUDIOIF_CTRL_C       0x14
+#define DAC33_FIFO_CTRL_A              0x15
+#define DAC33_UTHR_MSB                 0x16
+#define DAC33_UTHR_LSB                 0x17
+#define DAC33_ATHR_MSB                 0x18
+#define DAC33_ATHR_LSB                 0x19
+#define DAC33_LTHR_MSB                 0x1A
+#define DAC33_LTHR_LSB                 0x1B
+#define DAC33_PREFILL_MSB              0x1C
+#define DAC33_PREFILL_LSB              0x1D
+#define DAC33_NSAMPLE_MSB              0x1E
+#define DAC33_NSAMPLE_LSB              0x1F
+#define DAC33_FIFO_WPTR_MSB            0x20
+#define DAC33_FIFO_WPTR_LSB            0x21
+#define DAC33_FIFO_RPTR_MSB            0x22
+#define DAC33_FIFO_RPTR_LSB            0x23
+#define DAC33_FIFO_DEPTH_MSB           0x24
+#define DAC33_FIFO_DEPTH_LSB           0x25
+#define DAC33_SAMPLES_REMAINING_MSB    0x26
+#define DAC33_SAMPLES_REMAINING_LSB    0x27
+#define DAC33_FIFO_IRQ_FLAG            0x28
+#define DAC33_FIFO_IRQ_MASK            0x29
+#define DAC33_FIFO_IRQ_MODE_A          0x2A
+#define DAC33_FIFO_IRQ_MODE_B          0x2B
+#define DAC33_DAC_CTRL_A               0x2C
+#define DAC33_DAC_CTRL_B               0x2D
+#define DAC33_DAC_CTRL_C               0x2E
+#define DAC33_LDAC_DIG_VOL_CTRL                0x2F
+#define DAC33_RDAC_DIG_VOL_CTRL                0x30
+#define DAC33_DAC_STATUS_FLAGS         0x31
+#define DAC33_ASRC_CTRL_A              0x32
+#define DAC33_ASRC_CTRL_B              0x33
+#define DAC33_SRC_REF_CLK_RATIO_A      0x34
+#define DAC33_SRC_REF_CLK_RATIO_B      0x35
+#define DAC33_SRC_EST_REF_CLK_RATIO_A  0x36
+#define DAC33_SRC_EST_REF_CLK_RATIO_B  0x37
+#define DAC33_INTP_CTRL_A              0x38
+#define DAC33_INTP_CTRL_B              0x39
+/* Registers 0x3A - 0x3F Reserved */
+#define DAC33_LDAC_PWR_CTRL            0x40
+#define DAC33_RDAC_PWR_CTRL            0x41
+#define DAC33_OUT_AMP_CM_CTRL          0x42
+#define DAC33_OUT_AMP_PWR_CTRL         0x43
+#define DAC33_OUT_AMP_CTRL             0x44
+#define DAC33_LINEL_TO_LLO_VOL         0x45
+/* Registers 0x45 - 0x47 Reserved */
+#define DAC33_LINER_TO_RLO_VOL         0x48
+#define DAC33_ANA_VOL_SOFT_STEP_CTRL   0x49
+#define DAC33_OSC_TRIM                 0x4A
+/* Registers 0x4B - 0x7C Reserved */
+#define DAC33_DEVICE_ID_MSB            0x7D
+#define DAC33_DEVICE_ID_LSB            0x7E
+#define DAC33_DEVICE_REV_ID            0x7F
+
+#define DAC33_CACHEREGNUM               128
+
+/* Bit definitions */
+
+/* DAC33_PWR_CTRL (0x01) */
+#define DAC33_DACRPDNB                 (0x01 << 0)
+#define DAC33_DACLPDNB                 (0x01 << 1)
+#define DAC33_OSCPDNB                  (0x01 << 2)
+#define DAC33_PLLPDNB                  (0x01 << 3)
+#define DAC33_PDNALLB                  (0x01 << 4)
+#define DAC33_SOFT_RESET               (0x01 << 7)
+
+/* DAC33_INT_OSC_CTRL (0x07) */
+#define DAC33_REFSEL                   (0x01 << 1)
+
+/* DAC33_INT_OSC_CTRL_B (0x0C) */
+#define DAC33_ADJSTEP(x)               (x << 0)
+#define DAC33_ADJTHRSHLD(x)            (x << 4)
+
+/* DAC33_INT_OSC_CTRL_C (0x0D) */
+#define DAC33_REFDIV(x)                        (x << 4)
+
+/* DAC33_INT_OSC_STATUS (0x0E) */
+#define DAC33_OSCSTATUS_IDLE_CALIB     (0x00)
+#define DAC33_OSCSTATUS_NORMAL         (0x01)
+#define DAC33_OSCSTATUS_ADJUSTMENT     (0x03)
+#define DAC33_OSCSTATUS_NOT_USED       (0x02)
+
+/* DAC33_SER_AUDIOIF_CTRL_A (0x12) */
+#define DAC33_MSWCLK                   (0x01 << 0)
+#define DAC33_MSBCLK                   (0x01 << 1)
+#define DAC33_AFMT_MASK                        (0x03 << 2)
+#define DAC33_AFMT_I2S                 (0x00 << 2)
+#define DAC33_AFMT_DSP                 (0x01 << 2)
+#define DAC33_AFMT_RIGHT_J             (0x02 << 2)
+#define DAC33_AFMT_LEFT_J              (0x03 << 2)
+#define DAC33_WLEN_MASK                        (0x03 << 4)
+#define DAC33_WLEN_16                  (0x00 << 4)
+#define DAC33_WLEN_20                  (0x01 << 4)
+#define DAC33_WLEN_24                  (0x02 << 4)
+#define DAC33_WLEN_32                  (0x03 << 4)
+#define DAC33_NCYCL_MASK               (0x03 << 6)
+#define DAC33_NCYCL_16                 (0x00 << 6)
+#define DAC33_NCYCL_20                 (0x01 << 6)
+#define DAC33_NCYCL_24                 (0x02 << 6)
+#define DAC33_NCYCL_32                 (0x03 << 6)
+
+/* DAC33_SER_AUDIOIF_CTRL_B (0x13) */
+#define DAC33_DATA_DELAY_MASK          (0x03 << 2)
+#define DAC33_DATA_DELAY(x)            (x << 2)
+#define DAC33_BCLKON                   (0x01 << 5)
+
+/* DAC33_FIFO_CTRL_A (0x15) */
+#define DAC33_WIDTH                            (0x01 << 0)
+#define DAC33_FBYPAS                           (0x01 << 1)
+#define DAC33_FAUTO                            (0x01 << 2)
+#define DAC33_FIFOFLUSH                        (0x01 << 3)
+
+/*
+ * UTHR, ATHR, LTHR, PREFILL, NSAMPLE (0x16 - 0x1F)
+ * 13-bit values
+*/
+#define DAC33_THRREG(x)                        (((x) & 0x1FFF) << 3)
+
+/* DAC33_FIFO_IRQ_MASK (0x29) */
+#define DAC33_MNS                      (0x01 << 0)
+#define DAC33_MPS                      (0x01 << 1)
+#define DAC33_MAT                      (0x01 << 2)
+#define DAC33_MLT                      (0x01 << 3)
+#define DAC33_MUT                      (0x01 << 4)
+#define DAC33_MUF                      (0x01 << 5)
+#define DAC33_MOF                      (0x01 << 6)
+
+#define DAC33_FIFO_IRQ_MODE_MASK       (0x03)
+#define DAC33_FIFO_IRQ_MODE_RISING     (0x00)
+#define DAC33_FIFO_IRQ_MODE_FALLING    (0x01)
+#define DAC33_FIFO_IRQ_MODE_LEVEL      (0x02)
+#define DAC33_FIFO_IRQ_MODE_EDGE       (0x03)
+
+/* DAC33_FIFO_IRQ_MODE_A (0x2A) */
+#define DAC33_UTM(x)                   (x << 0)
+#define DAC33_UFM(x)                   (x << 2)
+#define DAC33_OFM(x)                   (x << 4)
+
+/* DAC33_FIFO_IRQ_MODE_B (0x2B) */
+#define DAC33_NSM(x)                   (x << 0)
+#define DAC33_PSM(x)                   (x << 2)
+#define DAC33_ATM(x)                   (x << 4)
+#define DAC33_LTM(x)                   (x << 6)
+
+/* DAC33_DAC_CTRL_A (0x2C) */
+#define DAC33_DACRATE(x)               (x << 0)
+#define DAC33_DACDUAL                  (0x01 << 4)
+#define DAC33_DACLKSEL_MASK            (0x03 << 5)
+#define DAC33_DACLKSEL_INTSOC          (0x00 << 5)
+#define DAC33_DACLKSEL_PLL             (0x01 << 5)
+#define DAC33_DACLKSEL_MCLK            (0x02 << 5)
+#define DAC33_DACLKSEL_BCLK            (0x03 << 5)
+
+/* DAC33_DAC_CTRL_B (0x2D) */
+#define DAC33_DACSRCR_MASK             (0x03 << 0)
+#define DAC33_DACSRCR_MUTE             (0x00 << 0)
+#define DAC33_DACSRCR_RIGHT            (0x01 << 0)
+#define DAC33_DACSRCR_LEFT             (0x02 << 0)
+#define DAC33_DACSRCR_MONOMIX          (0x03 << 0)
+#define DAC33_DACSRCL_MASK             (0x03 << 2)
+#define DAC33_DACSRCL_MUTE             (0x00 << 2)
+#define DAC33_DACSRCL_LEFT             (0x01 << 2)
+#define DAC33_DACSRCL_RIGHT            (0x02 << 2)
+#define DAC33_DACSRCL_MONOMIX          (0x03 << 2)
+#define DAC33_DVOLSTEP_MASK            (0x03 << 4)
+#define DAC33_DVOLSTEP_SS_PERFS                (0x00 << 4)
+#define DAC33_DVOLSTEP_SS_PER2FS       (0x01 << 4)
+#define DAC33_DVOLSTEP_SS_DISABLED     (0x02 << 4)
+#define DAC33_DVOLCTRL_MASK            (0x03 << 6)
+#define DAC33_DVOLCTRL_LR_INDEPENDENT1 (0x00 << 6)
+#define DAC33_DVOLCTRL_LR_RIGHT_CONTROL        (0x01 << 6)
+#define DAC33_DVOLCTRL_LR_LEFT_CONTROL (0x02 << 6)
+#define DAC33_DVOLCTRL_LR_INDEPENDENT2 (0x03 << 6)
+
+/* DAC33_DAC_CTRL_C (0x2E) */
+#define DAC33_DEEMENR                  (0x01 << 0)
+#define DAC33_EFFENR                   (0x01 << 1)
+#define DAC33_DEEMENL                  (0x01 << 2)
+#define DAC33_EFFENL                   (0x01 << 3)
+#define DAC33_EN3D                     (0x01 << 4)
+#define DAC33_RESYNMUTE                        (0x01 << 5)
+#define DAC33_RESYNEN                  (0x01 << 6)
+
+/* DAC33_ASRC_CTRL_A (0x32) */
+#define DAC33_SRCBYP                   (0x01 << 0)
+#define DAC33_SRCLKSEL_MASK            (0x03 << 1)
+#define DAC33_SRCLKSEL_INTSOC          (0x00 << 1)
+#define DAC33_SRCLKSEL_PLL             (0x01 << 1)
+#define DAC33_SRCLKSEL_MCLK            (0x02 << 1)
+#define DAC33_SRCLKSEL_BCLK            (0x03 << 1)
+#define DAC33_SRCLKDIV(x)              (x << 3)
+
+/* DAC33_ASRC_CTRL_B (0x33) */
+#define DAC33_SRCSETUP(x)              (x << 0)
+#define DAC33_SRCREFSEL                        (0x01 << 4)
+#define DAC33_SRCREFDIV(x)             (x << 5)
+
+/* DAC33_INTP_CTRL_A (0x38) */
+#define DAC33_INTPSEL                  (0x01 << 0)
+#define DAC33_INTPM_MASK               (0x03 << 1)
+#define DAC33_INTPM_ALOW_OPENDRAIN     (0x00 << 1)
+#define DAC33_INTPM_ALOW               (0x01 << 1)
+#define DAC33_INTPM_AHIGH              (0x02 << 1)
+
+/* DAC33_LDAC_PWR_CTRL (0x40) */
+/* DAC33_RDAC_PWR_CTRL (0x41) */
+#define DAC33_DACLRNUM                 (0x01 << 2)
+#define DAC33_LROUT_GAIN(x)            (x << 0)
+
+/* DAC33_ANA_VOL_SOFT_STEP_CTRL (0x49) */
+#define DAC33_VOLCLKSEL                        (0x01 << 0)
+#define DAC33_VOLCLKEN                 (0x01 << 1)
+#define DAC33_VOLBYPASS                        (0x01 << 2)
+
+#define TLV320DAC33_MCLK               0
+#define TLV320DAC33_SLEEPCLK           1
+
+extern struct snd_soc_dai dac33_dai;
+extern struct snd_soc_codec_device soc_codec_dev_tlv320dac33;
+
+#endif /* __TLV320DAC33_H */
diff --git a/sound/soc/codecs/tpa6130a2.c b/sound/soc/codecs/tpa6130a2.c
new file mode 100644 (file)
index 0000000..6b650c1
--- /dev/null
@@ -0,0 +1,463 @@
+/*
+ * ALSA SoC Texas Instruments TPA6130A2 headset stereo amplifier driver
+ *
+ * Copyright (C) Nokia Corporation
+ *
+ * Author: Peter Ujfalusi <peter.ujfalusi@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/device.h>
+#include <linux/i2c.h>
+#include <linux/gpio.h>
+#include <sound/tpa6130a2-plat.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/tlv.h>
+
+#include "tpa6130a2.h"
+
+static struct i2c_client *tpa6130a2_client;
+
+/* This struct is used to save the context */
+struct tpa6130a2_data {
+       struct mutex mutex;
+       unsigned char regs[TPA6130A2_CACHEREGNUM];
+       int power_gpio;
+       unsigned char power_state;
+};
+
+static int tpa6130a2_i2c_read(int reg)
+{
+       struct tpa6130a2_data *data;
+       int val;
+
+       BUG_ON(tpa6130a2_client == NULL);
+       data = i2c_get_clientdata(tpa6130a2_client);
+
+       /* If powered off, return the cached value */
+       if (data->power_state) {
+               val = i2c_smbus_read_byte_data(tpa6130a2_client, reg);
+               if (val < 0)
+                       dev_err(&tpa6130a2_client->dev, "Read failed\n");
+               else
+                       data->regs[reg] = val;
+       } else {
+               val = data->regs[reg];
+       }
+
+       return val;
+}
+
+static int tpa6130a2_i2c_write(int reg, u8 value)
+{
+       struct tpa6130a2_data *data;
+       int val = 0;
+
+       BUG_ON(tpa6130a2_client == NULL);
+       data = i2c_get_clientdata(tpa6130a2_client);
+
+       if (data->power_state) {
+               val = i2c_smbus_write_byte_data(tpa6130a2_client, reg, value);
+               if (val < 0)
+                       dev_err(&tpa6130a2_client->dev, "Write failed\n");
+       }
+
+       /* Either powered on or off, we save the context */
+       data->regs[reg] = value;
+
+       return val;
+}
+
+static u8 tpa6130a2_read(int reg)
+{
+       struct tpa6130a2_data *data;
+
+       BUG_ON(tpa6130a2_client == NULL);
+       data = i2c_get_clientdata(tpa6130a2_client);
+
+       return data->regs[reg];
+}
+
+static void tpa6130a2_initialize(void)
+{
+       struct tpa6130a2_data *data;
+       int i;
+
+       BUG_ON(tpa6130a2_client == NULL);
+       data = i2c_get_clientdata(tpa6130a2_client);
+
+       for (i = 1; i < TPA6130A2_REG_VERSION; i++)
+               tpa6130a2_i2c_write(i, data->regs[i]);
+}
+
+static void tpa6130a2_power(int power)
+{
+       struct  tpa6130a2_data *data;
+       u8      val;
+
+       BUG_ON(tpa6130a2_client == NULL);
+       data = i2c_get_clientdata(tpa6130a2_client);
+
+       mutex_lock(&data->mutex);
+       if (power) {
+               /* Power on */
+               if (data->power_gpio >= 0) {
+                       gpio_set_value(data->power_gpio, 1);
+                       data->power_state = 1;
+                       tpa6130a2_initialize();
+               }
+               /* Clear SWS */
+               val = tpa6130a2_read(TPA6130A2_REG_CONTROL);
+               val &= ~TPA6130A2_SWS;
+               tpa6130a2_i2c_write(TPA6130A2_REG_CONTROL, val);
+       } else {
+               /* set SWS */
+               val = tpa6130a2_read(TPA6130A2_REG_CONTROL);
+               val |= TPA6130A2_SWS;
+               tpa6130a2_i2c_write(TPA6130A2_REG_CONTROL, val);
+               /* Power off */
+               if (data->power_gpio >= 0) {
+                       gpio_set_value(data->power_gpio, 0);
+                       data->power_state = 0;
+               }
+       }
+       mutex_unlock(&data->mutex);
+}
+
+static int tpa6130a2_get_reg(struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_value *ucontrol)
+{
+       struct soc_mixer_control *mc =
+               (struct soc_mixer_control *)kcontrol->private_value;
+       struct tpa6130a2_data *data;
+       unsigned int reg = mc->reg;
+       unsigned int shift = mc->shift;
+       unsigned int mask = mc->max;
+       unsigned int invert = mc->invert;
+
+       BUG_ON(tpa6130a2_client == NULL);
+       data = i2c_get_clientdata(tpa6130a2_client);
+
+       mutex_lock(&data->mutex);
+
+       ucontrol->value.integer.value[0] =
+               (tpa6130a2_read(reg) >> shift) & mask;
+
+       if (invert)
+               ucontrol->value.integer.value[0] =
+                       mask - ucontrol->value.integer.value[0];
+
+       mutex_unlock(&data->mutex);
+       return 0;
+}
+
+static int tpa6130a2_set_reg(struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_value *ucontrol)
+{
+       struct soc_mixer_control *mc =
+               (struct soc_mixer_control *)kcontrol->private_value;
+       struct tpa6130a2_data *data;
+       unsigned int reg = mc->reg;
+       unsigned int shift = mc->shift;
+       unsigned int mask = mc->max;
+       unsigned int invert = mc->invert;
+       unsigned int val = (ucontrol->value.integer.value[0] & mask);
+       unsigned int val_reg;
+
+       BUG_ON(tpa6130a2_client == NULL);
+       data = i2c_get_clientdata(tpa6130a2_client);
+
+       if (invert)
+               val = mask - val;
+
+       mutex_lock(&data->mutex);
+
+       val_reg = tpa6130a2_read(reg);
+       if (((val_reg >> shift) & mask) == val) {
+               mutex_unlock(&data->mutex);
+               return 0;
+       }
+
+       val_reg &= ~(mask << shift);
+       val_reg |= val << shift;
+       tpa6130a2_i2c_write(reg, val_reg);
+
+       mutex_unlock(&data->mutex);
+
+       return 1;
+}
+
+/*
+ * TPA6130 volume. From -59.5 to 4 dB with increasing step size when going
+ * down in gain.
+ */
+static const unsigned int tpa6130_tlv[] = {
+       TLV_DB_RANGE_HEAD(10),
+       0, 1, TLV_DB_SCALE_ITEM(-5950, 600, 0),
+       2, 3, TLV_DB_SCALE_ITEM(-5000, 250, 0),
+       4, 5, TLV_DB_SCALE_ITEM(-4550, 160, 0),
+       6, 7, TLV_DB_SCALE_ITEM(-4140, 190, 0),
+       8, 9, TLV_DB_SCALE_ITEM(-3650, 120, 0),
+       10, 11, TLV_DB_SCALE_ITEM(-3330, 160, 0),
+       12, 13, TLV_DB_SCALE_ITEM(-3040, 180, 0),
+       14, 20, TLV_DB_SCALE_ITEM(-2710, 110, 0),
+       21, 37, TLV_DB_SCALE_ITEM(-1960, 74, 0),
+       38, 63, TLV_DB_SCALE_ITEM(-720, 45, 0),
+};
+
+static const struct snd_kcontrol_new tpa6130a2_controls[] = {
+       SOC_SINGLE_EXT_TLV("TPA6130A2 Headphone Playback Volume",
+                      TPA6130A2_REG_VOL_MUTE, 0, 0x3f, 0,
+                      tpa6130a2_get_reg, tpa6130a2_set_reg,
+                      tpa6130_tlv),
+};
+
+/*
+ * Enable or disable channel (left or right)
+ * The bit number for mute and amplifier are the same per channel:
+ * bit 6: Right channel
+ * bit 7: Left channel
+ * in both registers.
+ */
+static void tpa6130a2_channel_enable(u8 channel, int enable)
+{
+       struct  tpa6130a2_data *data;
+       u8      val;
+
+       BUG_ON(tpa6130a2_client == NULL);
+       data = i2c_get_clientdata(tpa6130a2_client);
+
+       if (enable) {
+               /* Enable channel */
+               /* Enable amplifier */
+               val = tpa6130a2_read(TPA6130A2_REG_CONTROL);
+               val |= channel;
+               tpa6130a2_i2c_write(TPA6130A2_REG_CONTROL, val);
+
+               /* Unmute channel */
+               val = tpa6130a2_read(TPA6130A2_REG_VOL_MUTE);
+               val &= ~channel;
+               tpa6130a2_i2c_write(TPA6130A2_REG_VOL_MUTE, val);
+       } else {
+               /* Disable channel */
+               /* Mute channel */
+               val = tpa6130a2_read(TPA6130A2_REG_VOL_MUTE);
+               val |= channel;
+               tpa6130a2_i2c_write(TPA6130A2_REG_VOL_MUTE, val);
+
+               /* Disable amplifier */
+               val = tpa6130a2_read(TPA6130A2_REG_CONTROL);
+               val &= ~channel;
+               tpa6130a2_i2c_write(TPA6130A2_REG_CONTROL, val);
+       }
+}
+
+static int tpa6130a2_left_event(struct snd_soc_dapm_widget *w,
+               struct snd_kcontrol *kcontrol, int event)
+{
+       switch (event) {
+       case SND_SOC_DAPM_POST_PMU:
+               tpa6130a2_channel_enable(TPA6130A2_HP_EN_L, 1);
+               break;
+       case SND_SOC_DAPM_POST_PMD:
+               tpa6130a2_channel_enable(TPA6130A2_HP_EN_L, 0);
+               break;
+       }
+       return 0;
+}
+
+static int tpa6130a2_right_event(struct snd_soc_dapm_widget *w,
+               struct snd_kcontrol *kcontrol, int event)
+{
+       switch (event) {
+       case SND_SOC_DAPM_POST_PMU:
+               tpa6130a2_channel_enable(TPA6130A2_HP_EN_R, 1);
+               break;
+       case SND_SOC_DAPM_POST_PMD:
+               tpa6130a2_channel_enable(TPA6130A2_HP_EN_R, 0);
+               break;
+       }
+       return 0;
+}
+
+static int tpa6130a2_supply_event(struct snd_soc_dapm_widget *w,
+               struct snd_kcontrol *kcontrol, int event)
+{
+       switch (event) {
+       case SND_SOC_DAPM_POST_PMU:
+               tpa6130a2_power(1);
+               break;
+       case SND_SOC_DAPM_POST_PMD:
+               tpa6130a2_power(0);
+               break;
+       }
+       return 0;
+}
+
+static const struct snd_soc_dapm_widget tpa6130a2_dapm_widgets[] = {
+       SND_SOC_DAPM_PGA_E("TPA6130A2 Left", SND_SOC_NOPM,
+                       0, 0, NULL, 0, tpa6130a2_left_event,
+                       SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_POST_PMD),
+       SND_SOC_DAPM_PGA_E("TPA6130A2 Right", SND_SOC_NOPM,
+                       0, 0, NULL, 0, tpa6130a2_right_event,
+                       SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_POST_PMD),
+       SND_SOC_DAPM_SUPPLY("TPA6130A2 Enable", SND_SOC_NOPM,
+                       0, 0, tpa6130a2_supply_event,
+                       SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_POST_PMD),
+       /* Outputs */
+       SND_SOC_DAPM_HP("TPA6130A2 Headphone Left", NULL),
+       SND_SOC_DAPM_HP("TPA6130A2 Headphone Right", NULL),
+};
+
+static const struct snd_soc_dapm_route audio_map[] = {
+       {"TPA6130A2 Headphone Left", NULL, "TPA6130A2 Left"},
+       {"TPA6130A2 Headphone Right", NULL, "TPA6130A2 Right"},
+
+       {"TPA6130A2 Headphone Left", NULL, "TPA6130A2 Enable"},
+       {"TPA6130A2 Headphone Right", NULL, "TPA6130A2 Enable"},
+};
+
+int tpa6130a2_add_controls(struct snd_soc_codec *codec)
+{
+       snd_soc_dapm_new_controls(codec, tpa6130a2_dapm_widgets,
+                               ARRAY_SIZE(tpa6130a2_dapm_widgets));
+
+       snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
+
+       return snd_soc_add_controls(codec, tpa6130a2_controls,
+                               ARRAY_SIZE(tpa6130a2_controls));
+
+}
+EXPORT_SYMBOL_GPL(tpa6130a2_add_controls);
+
+static int tpa6130a2_probe(struct i2c_client *client,
+                          const struct i2c_device_id *id)
+{
+       struct device *dev;
+       struct tpa6130a2_data *data;
+       struct tpa6130a2_platform_data *pdata;
+       int ret;
+
+       dev = &client->dev;
+
+       if (client->dev.platform_data == NULL) {
+               dev_err(dev, "Platform data not set\n");
+               dump_stack();
+               return -ENODEV;
+       }
+
+       data = kzalloc(sizeof(*data), GFP_KERNEL);
+       if (data == NULL) {
+               dev_err(dev, "Can not allocate memory\n");
+               return -ENOMEM;
+       }
+
+       tpa6130a2_client = client;
+
+       i2c_set_clientdata(tpa6130a2_client, data);
+
+       pdata = client->dev.platform_data;
+       data->power_gpio = pdata->power_gpio;
+
+       mutex_init(&data->mutex);
+
+       /* Set default register values */
+       data->regs[TPA6130A2_REG_CONTROL] =     TPA6130A2_SWS;
+       data->regs[TPA6130A2_REG_VOL_MUTE] =    TPA6130A2_MUTE_R |
+                                               TPA6130A2_MUTE_L;
+
+       if (data->power_gpio >= 0) {
+               ret = gpio_request(data->power_gpio, "tpa6130a2 enable");
+               if (ret < 0) {
+                       dev_err(dev, "Failed to request power GPIO (%d)\n",
+                               data->power_gpio);
+                       goto fail;
+               }
+               gpio_direction_output(data->power_gpio, 0);
+       } else {
+               data->power_state = 1;
+               tpa6130a2_initialize();
+       }
+
+       tpa6130a2_power(1);
+
+       /* Read version */
+       ret = tpa6130a2_i2c_read(TPA6130A2_REG_VERSION) &
+                                TPA6130A2_VERSION_MASK;
+       if ((ret != 1) && (ret != 2))
+               dev_warn(dev, "UNTESTED version detected (%d)\n", ret);
+
+       /* Disable the chip */
+       tpa6130a2_power(0);
+
+       return 0;
+fail:
+       kfree(data);
+       i2c_set_clientdata(tpa6130a2_client, NULL);
+       tpa6130a2_client = NULL;
+
+       return ret;
+}
+
+static int tpa6130a2_remove(struct i2c_client *client)
+{
+       struct tpa6130a2_data *data = i2c_get_clientdata(client);
+
+       tpa6130a2_power(0);
+
+       if (data->power_gpio >= 0)
+               gpio_free(data->power_gpio);
+       kfree(data);
+       tpa6130a2_client = NULL;
+
+       return 0;
+}
+
+static const struct i2c_device_id tpa6130a2_id[] = {
+       { "tpa6130a2", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, tpa6130a2_id);
+
+static struct i2c_driver tpa6130a2_i2c_driver = {
+       .driver = {
+               .name = "tpa6130a2",
+               .owner = THIS_MODULE,
+       },
+       .probe = tpa6130a2_probe,
+       .remove = __devexit_p(tpa6130a2_remove),
+       .id_table = tpa6130a2_id,
+};
+
+static int __init tpa6130a2_init(void)
+{
+       return i2c_add_driver(&tpa6130a2_i2c_driver);
+}
+
+static void __exit tpa6130a2_exit(void)
+{
+       i2c_del_driver(&tpa6130a2_i2c_driver);
+}
+
+MODULE_AUTHOR("Peter Ujfalusi");
+MODULE_DESCRIPTION("TPA6130A2 Headphone amplifier driver");
+MODULE_LICENSE("GPL");
+
+module_init(tpa6130a2_init);
+module_exit(tpa6130a2_exit);
diff --git a/sound/soc/codecs/tpa6130a2.h b/sound/soc/codecs/tpa6130a2.h
new file mode 100644 (file)
index 0000000..57e867f
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * ALSA SoC TPA6130A2 amplifier driver
+ *
+ * Copyright (C) Nokia Corporation
+ *
+ * Author: Peter Ujfalusi <peter.ujfalusi@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __TPA6130A2_H__
+#define __TPA6130A2_H__
+
+/* Register addresses */
+#define TPA6130A2_REG_CONTROL          0x01
+#define TPA6130A2_REG_VOL_MUTE         0x02
+#define TPA6130A2_REG_OUT_IMPEDANCE    0x03
+#define TPA6130A2_REG_VERSION          0x04
+
+#define TPA6130A2_CACHEREGNUM  (TPA6130A2_REG_VERSION + 1)
+
+/* Register bits */
+/* TPA6130A2_REG_CONTROL (0x01) */
+#define TPA6130A2_SWS                  (0x01 << 0)
+#define TPA6130A2_TERMAL               (0x01 << 1)
+#define TPA6130A2_MODE(x)              (x << 4)
+#define TPA6130A2_MODE_STEREO          (0x00)
+#define TPA6130A2_MODE_DUAL_MONO       (0x01)
+#define TPA6130A2_MODE_BRIDGE          (0x02)
+#define TPA6130A2_MODE_MASK            (0x03)
+#define TPA6130A2_HP_EN_R              (0x01 << 6)
+#define TPA6130A2_HP_EN_L              (0x01 << 7)
+
+/* TPA6130A2_REG_VOL_MUTE (0x02) */
+#define TPA6130A2_VOLUME(x)            ((x & 0x3f) << 0)
+#define TPA6130A2_MUTE_R               (0x01 << 6)
+#define TPA6130A2_MUTE_L               (0x01 << 7)
+
+/* TPA6130A2_REG_OUT_IMPEDANCE (0x03) */
+#define TPA6130A2_HIZ_R                        (0x01 << 0)
+#define TPA6130A2_HIZ_L                        (0x01 << 1)
+
+/* TPA6130A2_REG_VERSION (0x04) */
+#define TPA6130A2_VERSION_MASK         (0x0f)
+
+extern int tpa6130a2_add_controls(struct snd_soc_codec *codec);
+
+#endif /* __TPA6130A2_H__ */
index 4df7c6c..5f1681f 100644 (file)
@@ -120,9 +120,10 @@ static const u8 twl4030_reg[TWL4030_CACHEREGNUM] = {
 
 /* codec private data */
 struct twl4030_priv {
-       unsigned int bypass_state;
+       struct snd_soc_codec codec;
+
        unsigned int codec_powered;
-       unsigned int codec_muted;
+       unsigned int apll_enabled;
 
        struct snd_pcm_substream *master_substream;
        struct snd_pcm_substream *slave_substream;
@@ -183,19 +184,20 @@ static int twl4030_write(struct snd_soc_codec *codec,
 static void twl4030_codec_enable(struct snd_soc_codec *codec, int enable)
 {
        struct twl4030_priv *twl4030 = codec->private_data;
-       u8 mode;
+       int mode;
 
        if (enable == twl4030->codec_powered)
                return;
 
-       mode = twl4030_read_reg_cache(codec, TWL4030_REG_CODEC_MODE);
        if (enable)
-               mode |= TWL4030_CODECPDZ;
+               mode = twl4030_codec_enable_resource(TWL4030_CODEC_RES_POWER);
        else
-               mode &= ~TWL4030_CODECPDZ;
+               mode = twl4030_codec_disable_resource(TWL4030_CODEC_RES_POWER);
 
-       twl4030_write(codec, TWL4030_REG_CODEC_MODE, mode);
-       twl4030->codec_powered = enable;
+       if (mode >= 0) {
+               twl4030_write_reg_cache(codec, TWL4030_REG_CODEC_MODE, mode);
+               twl4030->codec_powered = enable;
+       }
 
        /* REVISIT: this delay is present in TI sample drivers */
        /* but there seems to be no TRM requirement for it     */
@@ -212,31 +214,30 @@ static void twl4030_init_chip(struct snd_soc_codec *codec)
 
        /* set all audio section registers to reasonable defaults */
        for (i = TWL4030_REG_OPTION; i <= TWL4030_REG_MISC_SET_2; i++)
-               twl4030_write(codec, i, cache[i]);
+               if (i != TWL4030_REG_APLL_CTL)
+                       twl4030_write(codec, i, cache[i]);
 
 }
 
-static void twl4030_codec_mute(struct snd_soc_codec *codec, int mute)
+static void twl4030_apll_enable(struct snd_soc_codec *codec, int enable)
 {
        struct twl4030_priv *twl4030 = codec->private_data;
-       u8 reg_val;
+       int status;
 
-       if (mute == twl4030->codec_muted)
+       if (enable == twl4030->apll_enabled)
                return;
 
-       if (mute) {
-               /* Disable PLL */
-               reg_val = twl4030_read_reg_cache(codec, TWL4030_REG_APLL_CTL);
-               reg_val &= ~TWL4030_APLL_EN;
-               twl4030_write(codec, TWL4030_REG_APLL_CTL, reg_val);
-       } else {
+       if (enable)
                /* Enable PLL */
-               reg_val = twl4030_read_reg_cache(codec, TWL4030_REG_APLL_CTL);
-               reg_val |= TWL4030_APLL_EN;
-               twl4030_write(codec, TWL4030_REG_APLL_CTL, reg_val);
-       }
+               status = twl4030_codec_enable_resource(TWL4030_CODEC_RES_APLL);
+       else
+               /* Disable PLL */
+               status = twl4030_codec_disable_resource(TWL4030_CODEC_RES_APLL);
+
+       if (status >= 0)
+               twl4030_write_reg_cache(codec, TWL4030_REG_APLL_CTL, status);
 
-       twl4030->codec_muted = mute;
+       twl4030->apll_enabled = enable;
 }
 
 static void twl4030_power_up(struct snd_soc_codec *codec)
@@ -613,6 +614,27 @@ static int handsfreerpga_event(struct snd_soc_dapm_widget *w,
        return 0;
 }
 
+static int vibramux_event(struct snd_soc_dapm_widget *w,
+               struct snd_kcontrol *kcontrol, int event)
+{
+       twl4030_write(w->codec, TWL4030_REG_VIBRA_SET, 0xff);
+       return 0;
+}
+
+static int apll_event(struct snd_soc_dapm_widget *w,
+               struct snd_kcontrol *kcontrol, int event)
+{
+       switch (event) {
+       case SND_SOC_DAPM_PRE_PMU:
+               twl4030_apll_enable(w->codec, 1);
+               break;
+       case SND_SOC_DAPM_POST_PMD:
+               twl4030_apll_enable(w->codec, 0);
+               break;
+       }
+       return 0;
+}
+
 static void headset_ramp(struct snd_soc_codec *codec, int ramp)
 {
        struct snd_soc_device *socdev = codec->socdev;
@@ -724,67 +746,6 @@ static int headsetrpga_event(struct snd_soc_dapm_widget *w,
        return 0;
 }
 
-static int bypass_event(struct snd_soc_dapm_widget *w,
-               struct snd_kcontrol *kcontrol, int event)
-{
-       struct soc_mixer_control *m =
-               (struct soc_mixer_control *)w->kcontrols->private_value;
-       struct twl4030_priv *twl4030 = w->codec->private_data;
-       unsigned char reg, misc;
-
-       reg = twl4030_read_reg_cache(w->codec, m->reg);
-
-       /*
-        * bypass_state[0:3] - analog HiFi bypass
-        * bypass_state[4]   - analog voice bypass
-        * bypass_state[5]   - digital voice bypass
-        * bypass_state[6:7] - digital HiFi bypass
-        */
-       if (m->reg == TWL4030_REG_VSTPGA) {
-               /* Voice digital bypass */
-               if (reg)
-                       twl4030->bypass_state |= (1 << 5);
-               else
-                       twl4030->bypass_state &= ~(1 << 5);
-       } else if (m->reg <= TWL4030_REG_ARXR2_APGA_CTL) {
-               /* Analog bypass */
-               if (reg & (1 << m->shift))
-                       twl4030->bypass_state |=
-                               (1 << (m->reg - TWL4030_REG_ARXL1_APGA_CTL));
-               else
-                       twl4030->bypass_state &=
-                               ~(1 << (m->reg - TWL4030_REG_ARXL1_APGA_CTL));
-       } else if (m->reg == TWL4030_REG_VDL_APGA_CTL) {
-               /* Analog voice bypass */
-               if (reg & (1 << m->shift))
-                       twl4030->bypass_state |= (1 << 4);
-               else
-                       twl4030->bypass_state &= ~(1 << 4);
-       } else {
-               /* Digital bypass */
-               if (reg & (0x7 << m->shift))
-                       twl4030->bypass_state |= (1 << (m->shift ? 7 : 6));
-               else
-                       twl4030->bypass_state &= ~(1 << (m->shift ? 7 : 6));
-       }
-
-       /* Enable master analog loopback mode if any analog switch is enabled*/
-       misc = twl4030_read_reg_cache(w->codec, TWL4030_REG_MISC_SET_1);
-       if (twl4030->bypass_state & 0x1F)
-               misc |= TWL4030_FMLOOP_EN;
-       else
-               misc &= ~TWL4030_FMLOOP_EN;
-       twl4030_write(w->codec, TWL4030_REG_MISC_SET_1, misc);
-
-       if (w->codec->bias_level == SND_SOC_BIAS_STANDBY) {
-               if (twl4030->bypass_state)
-                       twl4030_codec_mute(w->codec, 0);
-               else
-                       twl4030_codec_mute(w->codec, 1);
-       }
-       return 0;
-}
-
 /*
  * Some of the gain controls in TWL (mostly those which are associated with
  * the outputs) are implemented in an interesting way:
@@ -1192,32 +1153,28 @@ static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = {
                        SND_SOC_NOPM, 0, 0),
 
        /* Analog bypasses */
-       SND_SOC_DAPM_SWITCH_E("Right1 Analog Loopback", SND_SOC_NOPM, 0, 0,
-                       &twl4030_dapm_abypassr1_control, bypass_event,
-                       SND_SOC_DAPM_POST_REG),
-       SND_SOC_DAPM_SWITCH_E("Left1 Analog Loopback", SND_SOC_NOPM, 0, 0,
-                       &twl4030_dapm_abypassl1_control,
-                       bypass_event, SND_SOC_DAPM_POST_REG),
-       SND_SOC_DAPM_SWITCH_E("Right2 Analog Loopback", SND_SOC_NOPM, 0, 0,
-                       &twl4030_dapm_abypassr2_control,
-                       bypass_event, SND_SOC_DAPM_POST_REG),
-       SND_SOC_DAPM_SWITCH_E("Left2 Analog Loopback", SND_SOC_NOPM, 0, 0,
-                       &twl4030_dapm_abypassl2_control,
-                       bypass_event, SND_SOC_DAPM_POST_REG),
-       SND_SOC_DAPM_SWITCH_E("Voice Analog Loopback", SND_SOC_NOPM, 0, 0,
-                       &twl4030_dapm_abypassv_control,
-                       bypass_event, SND_SOC_DAPM_POST_REG),
+       SND_SOC_DAPM_SWITCH("Right1 Analog Loopback", SND_SOC_NOPM, 0, 0,
+                       &twl4030_dapm_abypassr1_control),
+       SND_SOC_DAPM_SWITCH("Left1 Analog Loopback", SND_SOC_NOPM, 0, 0,
+                       &twl4030_dapm_abypassl1_control),
+       SND_SOC_DAPM_SWITCH("Right2 Analog Loopback", SND_SOC_NOPM, 0, 0,
+                       &twl4030_dapm_abypassr2_control),
+       SND_SOC_DAPM_SWITCH("Left2 Analog Loopback", SND_SOC_NOPM, 0, 0,
+                       &twl4030_dapm_abypassl2_control),
+       SND_SOC_DAPM_SWITCH("Voice Analog Loopback", SND_SOC_NOPM, 0, 0,
+                       &twl4030_dapm_abypassv_control),
+
+       /* Master analog loopback switch */
+       SND_SOC_DAPM_SUPPLY("FM Loop Enable", TWL4030_REG_MISC_SET_1, 5, 0,
+                           NULL, 0),
 
        /* Digital bypasses */
-       SND_SOC_DAPM_SWITCH_E("Left Digital Loopback", SND_SOC_NOPM, 0, 0,
-                       &twl4030_dapm_dbypassl_control, bypass_event,
-                       SND_SOC_DAPM_POST_REG),
-       SND_SOC_DAPM_SWITCH_E("Right Digital Loopback", SND_SOC_NOPM, 0, 0,
-                       &twl4030_dapm_dbypassr_control, bypass_event,
-                       SND_SOC_DAPM_POST_REG),
-       SND_SOC_DAPM_SWITCH_E("Voice Digital Loopback", SND_SOC_NOPM, 0, 0,
-                       &twl4030_dapm_dbypassv_control, bypass_event,
-                       SND_SOC_DAPM_POST_REG),
+       SND_SOC_DAPM_SWITCH("Left Digital Loopback", SND_SOC_NOPM, 0, 0,
+                       &twl4030_dapm_dbypassl_control),
+       SND_SOC_DAPM_SWITCH("Right Digital Loopback", SND_SOC_NOPM, 0, 0,
+                       &twl4030_dapm_dbypassr_control),
+       SND_SOC_DAPM_SWITCH("Voice Digital Loopback", SND_SOC_NOPM, 0, 0,
+                       &twl4030_dapm_dbypassv_control),
 
        /* Digital mixers, power control for the physical DACs */
        SND_SOC_DAPM_MIXER("Digital R1 Playback Mixer",
@@ -1243,6 +1200,9 @@ static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = {
        SND_SOC_DAPM_MIXER("Analog Voice Playback Mixer",
                        TWL4030_REG_VDL_APGA_CTL, 0, 0, NULL, 0),
 
+       SND_SOC_DAPM_SUPPLY("APLL Enable", SND_SOC_NOPM, 0, 0, apll_event,
+                           SND_SOC_DAPM_PRE_PMU|SND_SOC_DAPM_POST_PMD),
+
        /* Output MIXER controls */
        /* Earpiece */
        SND_SOC_DAPM_MIXER("Earpiece Mixer", SND_SOC_NOPM, 0, 0,
@@ -1308,8 +1268,9 @@ static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = {
                        0, 0, NULL, 0, handsfreerpga_event,
                        SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_POST_PMD),
        /* Vibra */
-       SND_SOC_DAPM_MUX("Vibra Mux", TWL4030_REG_VIBRA_CTL, 0, 0,
-               &twl4030_dapm_vibra_control),
+       SND_SOC_DAPM_MUX_E("Vibra Mux", TWL4030_REG_VIBRA_CTL, 0, 0,
+                          &twl4030_dapm_vibra_control, vibramux_event,
+                          SND_SOC_DAPM_PRE_PMU),
        SND_SOC_DAPM_MUX("Vibra Route", SND_SOC_NOPM, 0, 0,
                &twl4030_dapm_vibrapath_control),
 
@@ -1369,6 +1330,13 @@ static const struct snd_soc_dapm_route intercon[] = {
        {"Digital R2 Playback Mixer", NULL, "DAC Right2"},
        {"Digital Voice Playback Mixer", NULL, "DAC Voice"},
 
+       /* Supply for the digital part (APLL) */
+       {"Digital R1 Playback Mixer", NULL, "APLL Enable"},
+       {"Digital L1 Playback Mixer", NULL, "APLL Enable"},
+       {"Digital R2 Playback Mixer", NULL, "APLL Enable"},
+       {"Digital L2 Playback Mixer", NULL, "APLL Enable"},
+       {"Digital Voice Playback Mixer", NULL, "APLL Enable"},
+
        {"Analog L1 Playback Mixer", NULL, "Digital L1 Playback Mixer"},
        {"Analog R1 Playback Mixer", NULL, "Digital R1 Playback Mixer"},
        {"Analog L2 Playback Mixer", NULL, "Digital L2 Playback Mixer"},
@@ -1482,6 +1450,11 @@ static const struct snd_soc_dapm_route intercon[] = {
        {"ADC Virtual Left2", NULL, "TX2 Capture Route"},
        {"ADC Virtual Right2", NULL, "TX2 Capture Route"},
 
+       {"ADC Virtual Left1", NULL, "APLL Enable"},
+       {"ADC Virtual Right1", NULL, "APLL Enable"},
+       {"ADC Virtual Left2", NULL, "APLL Enable"},
+       {"ADC Virtual Right2", NULL, "APLL Enable"},
+
        /* Analog bypass routes */
        {"Right1 Analog Loopback", "Switch", "Analog Right"},
        {"Left1 Analog Loopback", "Switch", "Analog Left"},
@@ -1489,6 +1462,13 @@ static const struct snd_soc_dapm_route intercon[] = {
        {"Left2 Analog Loopback", "Switch", "Analog Left"},
        {"Voice Analog Loopback", "Switch", "Analog Left"},
 
+       /* Supply for the Analog loopbacks */
+       {"Right1 Analog Loopback", NULL, "FM Loop Enable"},
+       {"Left1 Analog Loopback", NULL, "FM Loop Enable"},
+       {"Right2 Analog Loopback", NULL, "FM Loop Enable"},
+       {"Left2 Analog Loopback", NULL, "FM Loop Enable"},
+       {"Voice Analog Loopback", NULL, "FM Loop Enable"},
+
        {"Analog R1 Playback Mixer", NULL, "Right1 Analog Loopback"},
        {"Analog L1 Playback Mixer", NULL, "Left1 Analog Loopback"},
        {"Analog R2 Playback Mixer", NULL, "Right2 Analog Loopback"},
@@ -1513,32 +1493,20 @@ static int twl4030_add_widgets(struct snd_soc_codec *codec)
 
        snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon));
 
-       snd_soc_dapm_new_widgets(codec);
        return 0;
 }
 
 static int twl4030_set_bias_level(struct snd_soc_codec *codec,
                                  enum snd_soc_bias_level level)
 {
-       struct twl4030_priv *twl4030 = codec->private_data;
-
        switch (level) {
        case SND_SOC_BIAS_ON:
-               twl4030_codec_mute(codec, 0);
                break;
        case SND_SOC_BIAS_PREPARE:
-               twl4030_power_up(codec);
-               if (twl4030->bypass_state)
-                       twl4030_codec_mute(codec, 0);
-               else
-                       twl4030_codec_mute(codec, 1);
                break;
        case SND_SOC_BIAS_STANDBY:
-               twl4030_power_up(codec);
-               if (twl4030->bypass_state)
-                       twl4030_codec_mute(codec, 0);
-               else
-                       twl4030_codec_mute(codec, 1);
+               if (codec->bias_level == SND_SOC_BIAS_OFF)
+                       twl4030_power_up(codec);
                break;
        case SND_SOC_BIAS_OFF:
                twl4030_power_down(codec);
@@ -1785,29 +1753,23 @@ static int twl4030_set_dai_sysclk(struct snd_soc_dai *codec_dai,
 {
        struct snd_soc_codec *codec = codec_dai->codec;
        struct twl4030_priv *twl4030 = codec->private_data;
-       u8 infreq;
 
        switch (freq) {
        case 19200000:
-               infreq = TWL4030_APLL_INFREQ_19200KHZ;
-               twl4030->sysclk = 19200;
-               break;
        case 26000000:
-               infreq = TWL4030_APLL_INFREQ_26000KHZ;
-               twl4030->sysclk = 26000;
-               break;
        case 38400000:
-               infreq = TWL4030_APLL_INFREQ_38400KHZ;
-               twl4030->sysclk = 38400;
                break;
        default:
-               printk(KERN_ERR "TWL4030 set sysclk: unknown rate %d\n",
-                       freq);
+               dev_err(codec->dev, "Unsupported APLL mclk: %u\n", freq);
                return -EINVAL;
        }
 
-       infreq |= TWL4030_APLL_EN;
-       twl4030_write(codec, TWL4030_REG_APLL_CTL, infreq);
+       if ((freq / 1000) != twl4030->sysclk) {
+               dev_err(codec->dev,
+                       "Mismatch in APLL mclk: %u (configured: %u)\n",
+                       freq, twl4030->sysclk * 1000);
+               return -EINVAL;
+       }
 
        return 0;
 }
@@ -1905,18 +1867,16 @@ static int twl4030_voice_startup(struct snd_pcm_substream *substream,
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct snd_soc_device *socdev = rtd->socdev;
        struct snd_soc_codec *codec = socdev->card->codec;
-       u8 infreq;
+       struct twl4030_priv *twl4030 = codec->private_data;
        u8 mode;
 
        /* If the system master clock is not 26MHz, the voice PCM interface is
         * not avilable.
         */
-       infreq = twl4030_read_reg_cache(codec, TWL4030_REG_APLL_CTL)
-               & TWL4030_APLL_INFREQ;
-
-       if (infreq != TWL4030_APLL_INFREQ_26000KHZ) {
-               printk(KERN_ERR "TWL4030 voice startup: "
-                       "MCLK is not 26MHz, call set_sysclk() on init\n");
+       if (twl4030->sysclk != 26000) {
+               dev_err(codec->dev, "The board is configured for %u Hz, while"
+                       "the Voice interface needs 26MHz APLL mclk\n",
+                       twl4030->sysclk * 1000);
                return -EINVAL;
        }
 
@@ -1989,21 +1949,19 @@ static int twl4030_voice_set_dai_sysclk(struct snd_soc_dai *codec_dai,
                int clk_id, unsigned int freq, int dir)
 {
        struct snd_soc_codec *codec = codec_dai->codec;
-       u8 infreq;
+       struct twl4030_priv *twl4030 = codec->private_data;
 
-       switch (freq) {
-       case 26000000:
-               infreq = TWL4030_APLL_INFREQ_26000KHZ;
-               break;
-       default:
-               printk(KERN_ERR "TWL4030 voice set sysclk: unknown rate %d\n",
-                       freq);
+       if (freq != 26000000) {
+               dev_err(codec->dev, "Unsupported APLL mclk: %u, the Voice"
+                       "interface needs 26MHz APLL mclk\n", freq);
+               return -EINVAL;
+       }
+       if ((freq / 1000) != twl4030->sysclk) {
+               dev_err(codec->dev,
+                       "Mismatch in APLL mclk: %u (configured: %u)\n",
+                       freq, twl4030->sysclk * 1000);
                return -EINVAL;
        }
-
-       infreq |= TWL4030_APLL_EN;
-       twl4030_write(codec, TWL4030_REG_APLL_CTL, infreq);
-
        return 0;
 }
 
@@ -2121,7 +2079,7 @@ struct snd_soc_dai twl4030_dai[] = {
 };
 EXPORT_SYMBOL_GPL(twl4030_dai);
 
-static int twl4030_suspend(struct platform_device *pdev, pm_message_t state)
+static int twl4030_soc_suspend(struct platform_device *pdev, pm_message_t state)
 {
        struct snd_soc_device *socdev = platform_get_drvdata(pdev);
        struct snd_soc_codec *codec = socdev->card->codec;
@@ -2131,7 +2089,7 @@ static int twl4030_suspend(struct platform_device *pdev, pm_message_t state)
        return 0;
 }
 
-static int twl4030_resume(struct platform_device *pdev)
+static int twl4030_soc_resume(struct platform_device *pdev)
 {
        struct snd_soc_device *socdev = platform_get_drvdata(pdev);
        struct snd_soc_codec *codec = socdev->card->codec;
@@ -2141,147 +2099,181 @@ static int twl4030_resume(struct platform_device *pdev)
        return 0;
 }
 
-/*
- * initialize the driver
- * register the mixer and dsp interfaces with the kernel
- */
+static struct snd_soc_codec *twl4030_codec;
 
-static int twl4030_init(struct snd_soc_device *socdev)
+static int twl4030_soc_probe(struct platform_device *pdev)
 {
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
        struct twl4030_setup_data *setup = socdev->codec_data;
-       struct twl4030_priv *twl4030 = codec->private_data;
-       int ret = 0;
+       struct snd_soc_codec *codec;
+       struct twl4030_priv *twl4030;
+       int ret;
 
-       printk(KERN_INFO "TWL4030 Audio Codec init \n");
+       BUG_ON(!twl4030_codec);
 
-       codec->name = "twl4030";
-       codec->owner = THIS_MODULE;
-       codec->read = twl4030_read_reg_cache;
-       codec->write = twl4030_write;
-       codec->set_bias_level = twl4030_set_bias_level;
-       codec->dai = twl4030_dai;
-       codec->num_dai = ARRAY_SIZE(twl4030_dai),
-       codec->reg_cache_size = sizeof(twl4030_reg);
-       codec->reg_cache = kmemdup(twl4030_reg, sizeof(twl4030_reg),
-                                       GFP_KERNEL);
-       if (codec->reg_cache == NULL)
-               return -ENOMEM;
+       codec = twl4030_codec;
+       twl4030 = codec->private_data;
+       socdev->card->codec = codec;
 
        /* Configuration for headset ramp delay from setup data */
        if (setup) {
                unsigned char hs_pop;
 
-               if (setup->sysclk)
-                       twl4030->sysclk = setup->sysclk;
-               else
-                       twl4030->sysclk = 26000;
+               if (setup->sysclk != twl4030->sysclk)
+                       dev_warn(&pdev->dev,
+                                "Mismatch in APLL mclk: %u (configured: %u)\n",
+                                setup->sysclk, twl4030->sysclk);
 
                hs_pop = twl4030_read_reg_cache(codec, TWL4030_REG_HS_POPN_SET);
                hs_pop &= ~TWL4030_RAMP_DELAY;
                hs_pop |= (setup->ramp_delay_value << 2);
                twl4030_write_reg_cache(codec, TWL4030_REG_HS_POPN_SET, hs_pop);
-       } else {
-               twl4030->sysclk = 26000;
        }
 
        /* register pcms */
        ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
        if (ret < 0) {
-               printk(KERN_ERR "twl4030: failed to create pcms\n");
-               goto pcm_err;
+               dev_err(&pdev->dev, "failed to create pcms\n");
+               return ret;
        }
 
-       twl4030_init_chip(codec);
-
-       /* power on device */
-       twl4030_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
        snd_soc_add_controls(codec, twl4030_snd_controls,
                                ARRAY_SIZE(twl4030_snd_controls));
        twl4030_add_widgets(codec);
 
-       ret = snd_soc_init_card(socdev);
-       if (ret < 0) {
-               printk(KERN_ERR "twl4030: failed to register card\n");
-               goto card_err;
-       }
+       return 0;
+}
 
-       return ret;
+static int twl4030_soc_remove(struct platform_device *pdev)
+{
+       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+       struct snd_soc_codec *codec = socdev->card->codec;
 
-card_err:
+       twl4030_set_bias_level(codec, SND_SOC_BIAS_OFF);
        snd_soc_free_pcms(socdev);
        snd_soc_dapm_free(socdev);
-pcm_err:
-       kfree(codec->reg_cache);
-       return ret;
-}
+       kfree(codec->private_data);
+       kfree(codec);
 
-static struct snd_soc_device *twl4030_socdev;
+       return 0;
+}
 
-static int twl4030_probe(struct platform_device *pdev)
+static int __devinit twl4030_codec_probe(struct platform_device *pdev)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+       struct twl4030_codec_audio_data *pdata = pdev->dev.platform_data;
        struct snd_soc_codec *codec;
        struct twl4030_priv *twl4030;
+       int ret;
 
-       codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
-       if (codec == NULL)
-               return -ENOMEM;
+       if (!pdata) {
+               dev_err(&pdev->dev, "platform_data is missing\n");
+               return -EINVAL;
+       }
 
        twl4030 = kzalloc(sizeof(struct twl4030_priv), GFP_KERNEL);
        if (twl4030 == NULL) {
-               kfree(codec);
+               dev_err(&pdev->dev, "Can not allocate memroy\n");
                return -ENOMEM;
        }
 
+       codec = &twl4030->codec;
        codec->private_data = twl4030;
-       socdev->card->codec = codec;
+       codec->dev = &pdev->dev;
+       twl4030_dai[0].dev = &pdev->dev;
+       twl4030_dai[1].dev = &pdev->dev;
+
        mutex_init(&codec->mutex);
        INIT_LIST_HEAD(&codec->dapm_widgets);
        INIT_LIST_HEAD(&codec->dapm_paths);
 
-       twl4030_socdev = socdev;
-       twl4030_init(socdev);
+       codec->name = "twl4030";
+       codec->owner = THIS_MODULE;
+       codec->read = twl4030_read_reg_cache;
+       codec->write = twl4030_write;
+       codec->set_bias_level = twl4030_set_bias_level;
+       codec->dai = twl4030_dai;
+       codec->num_dai = ARRAY_SIZE(twl4030_dai),
+       codec->reg_cache_size = sizeof(twl4030_reg);
+       codec->reg_cache = kmemdup(twl4030_reg, sizeof(twl4030_reg),
+                                       GFP_KERNEL);
+       if (codec->reg_cache == NULL) {
+               ret = -ENOMEM;
+               goto error_cache;
+       }
+
+       platform_set_drvdata(pdev, twl4030);
+       twl4030_codec = codec;
+
+       /* Set the defaults, and power up the codec */
+       twl4030->sysclk = twl4030_codec_get_mclk() / 1000;
+       twl4030_init_chip(codec);
+       codec->bias_level = SND_SOC_BIAS_OFF;
+       twl4030_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+       ret = snd_soc_register_codec(codec);
+       if (ret != 0) {
+               dev_err(codec->dev, "Failed to register codec: %d\n", ret);
+               goto error_codec;
+       }
+
+       ret = snd_soc_register_dais(&twl4030_dai[0], ARRAY_SIZE(twl4030_dai));
+       if (ret != 0) {
+               dev_err(codec->dev, "Failed to register DAIs: %d\n", ret);
+               snd_soc_unregister_codec(codec);
+               goto error_codec;
+       }
 
        return 0;
+
+error_codec:
+       twl4030_power_down(codec);
+       kfree(codec->reg_cache);
+error_cache:
+       kfree(twl4030);
+       return ret;
 }
 
-static int twl4030_remove(struct platform_device *pdev)
+static int __devexit twl4030_codec_remove(struct platform_device *pdev)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct twl4030_priv *twl4030 = platform_get_drvdata(pdev);
 
-       printk(KERN_INFO "TWL4030 Audio Codec remove\n");
-       twl4030_set_bias_level(codec, SND_SOC_BIAS_OFF);
-       snd_soc_free_pcms(socdev);
-       snd_soc_dapm_free(socdev);
-       kfree(codec->private_data);
-       kfree(codec);
+       kfree(twl4030);
 
+       twl4030_codec = NULL;
        return 0;
 }
 
-struct snd_soc_codec_device soc_codec_dev_twl4030 = {
-       .probe = twl4030_probe,
-       .remove = twl4030_remove,
-       .suspend = twl4030_suspend,
-       .resume = twl4030_resume,
+MODULE_ALIAS("platform:twl4030_codec_audio");
+
+static struct platform_driver twl4030_codec_driver = {
+       .probe          = twl4030_codec_probe,
+       .remove         = __devexit_p(twl4030_codec_remove),
+       .driver         = {
+               .name   = "twl4030_codec_audio",
+               .owner  = THIS_MODULE,
+       },
 };
-EXPORT_SYMBOL_GPL(soc_codec_dev_twl4030);
 
 static int __init twl4030_modinit(void)
 {
-       return snd_soc_register_dais(&twl4030_dai[0], ARRAY_SIZE(twl4030_dai));
+       return platform_driver_register(&twl4030_codec_driver);
 }
 module_init(twl4030_modinit);
 
 static void __exit twl4030_exit(void)
 {
-       snd_soc_unregister_dais(&twl4030_dai[0], ARRAY_SIZE(twl4030_dai));
+       platform_driver_unregister(&twl4030_codec_driver);
 }
 module_exit(twl4030_exit);
 
+struct snd_soc_codec_device soc_codec_dev_twl4030 = {
+       .probe = twl4030_soc_probe,
+       .remove = twl4030_soc_remove,
+       .suspend = twl4030_soc_suspend,
+       .resume = twl4030_soc_resume,
+};
+EXPORT_SYMBOL_GPL(soc_codec_dev_twl4030);
+
 MODULE_DESCRIPTION("ASoC TWL4030 codec driver");
 MODULE_AUTHOR("Steve Sakoman");
 MODULE_LICENSE("GPL");
index 2b4bfa2..dd6396e 100644 (file)
 #ifndef __TWL4030_AUDIO_H__
 #define __TWL4030_AUDIO_H__
 
-#define TWL4030_REG_CODEC_MODE         0x1
-#define TWL4030_REG_OPTION             0x2
-#define TWL4030_REG_UNKNOWN            0x3
-#define TWL4030_REG_MICBIAS_CTL                0x4
-#define TWL4030_REG_ANAMICL            0x5
-#define TWL4030_REG_ANAMICR            0x6
-#define TWL4030_REG_AVADC_CTL          0x7
-#define TWL4030_REG_ADCMICSEL          0x8
-#define TWL4030_REG_DIGMIXING          0x9
-#define TWL4030_REG_ATXL1PGA           0xA
-#define TWL4030_REG_ATXR1PGA           0xB
-#define TWL4030_REG_AVTXL2PGA          0xC
-#define TWL4030_REG_AVTXR2PGA          0xD
-#define TWL4030_REG_AUDIO_IF           0xE
-#define TWL4030_REG_VOICE_IF           0xF
-#define TWL4030_REG_ARXR1PGA           0x10
-#define TWL4030_REG_ARXL1PGA           0x11
-#define TWL4030_REG_ARXR2PGA           0x12
-#define TWL4030_REG_ARXL2PGA           0x13
-#define TWL4030_REG_VRXPGA             0x14
-#define TWL4030_REG_VSTPGA             0x15
-#define TWL4030_REG_VRX2ARXPGA         0x16
-#define TWL4030_REG_AVDAC_CTL          0x17
-#define TWL4030_REG_ARX2VTXPGA         0x18
-#define TWL4030_REG_ARXL1_APGA_CTL     0x19
-#define TWL4030_REG_ARXR1_APGA_CTL     0x1A
-#define TWL4030_REG_ARXL2_APGA_CTL     0x1B
-#define TWL4030_REG_ARXR2_APGA_CTL     0x1C
-#define TWL4030_REG_ATX2ARXPGA         0x1D
-#define TWL4030_REG_BT_IF              0x1E
-#define TWL4030_REG_BTPGA              0x1F
-#define TWL4030_REG_BTSTPGA            0x20
-#define TWL4030_REG_EAR_CTL            0x21
-#define TWL4030_REG_HS_SEL             0x22
-#define TWL4030_REG_HS_GAIN_SET                0x23
-#define TWL4030_REG_HS_POPN_SET                0x24
-#define TWL4030_REG_PREDL_CTL          0x25
-#define TWL4030_REG_PREDR_CTL          0x26
-#define TWL4030_REG_PRECKL_CTL         0x27
-#define TWL4030_REG_PRECKR_CTL         0x28
-#define TWL4030_REG_HFL_CTL            0x29
-#define TWL4030_REG_HFR_CTL            0x2A
-#define TWL4030_REG_ALC_CTL            0x2B
-#define TWL4030_REG_ALC_SET1           0x2C
-#define TWL4030_REG_ALC_SET2           0x2D
-#define TWL4030_REG_BOOST_CTL          0x2E
-#define TWL4030_REG_SOFTVOL_CTL                0x2F
-#define TWL4030_REG_DTMF_FREQSEL       0x30
-#define TWL4030_REG_DTMF_TONEXT1H      0x31
-#define TWL4030_REG_DTMF_TONEXT1L      0x32
-#define TWL4030_REG_DTMF_TONEXT2H      0x33
-#define TWL4030_REG_DTMF_TONEXT2L      0x34
-#define TWL4030_REG_DTMF_TONOFF                0x35
-#define TWL4030_REG_DTMF_WANONOFF      0x36
-#define TWL4030_REG_I2S_RX_SCRAMBLE_H  0x37
-#define TWL4030_REG_I2S_RX_SCRAMBLE_M  0x38
-#define TWL4030_REG_I2S_RX_SCRAMBLE_L  0x39
-#define TWL4030_REG_APLL_CTL           0x3A
-#define TWL4030_REG_DTMF_CTL           0x3B
-#define TWL4030_REG_DTMF_PGA_CTL2      0x3C
-#define TWL4030_REG_DTMF_PGA_CTL1      0x3D
-#define TWL4030_REG_MISC_SET_1         0x3E
-#define TWL4030_REG_PCMBTMUX           0x3F
-#define TWL4030_REG_RX_PATH_SEL                0x43
-#define TWL4030_REG_VDL_APGA_CTL       0x44
-#define TWL4030_REG_VIBRA_CTL          0x45
-#define TWL4030_REG_VIBRA_SET          0x46
-#define TWL4030_REG_VIBRA_PWM_SET      0x47
-#define TWL4030_REG_ANAMIC_GAIN                0x48
-#define TWL4030_REG_MISC_SET_2         0x49
-#define TWL4030_REG_SW_SHADOW          0x4A
+/* Register descriptions are here */
+#include <linux/mfd/twl4030-codec.h>
 
+/* Sgadow register used by the audio driver */
+#define TWL4030_REG_SW_SHADOW          0x4A
 #define TWL4030_CACHEREGNUM    (TWL4030_REG_SW_SHADOW + 1)
 
-/* Bitfield Definitions */
-
-/* TWL4030_CODEC_MODE (0x01) Fields */
-
-#define TWL4030_APLL_RATE              0xF0
-#define TWL4030_APLL_RATE_8000         0x00
-#define TWL4030_APLL_RATE_11025                0x10
-#define TWL4030_APLL_RATE_12000                0x20
-#define TWL4030_APLL_RATE_16000                0x40
-#define TWL4030_APLL_RATE_22050                0x50
-#define TWL4030_APLL_RATE_24000                0x60
-#define TWL4030_APLL_RATE_32000                0x80
-#define TWL4030_APLL_RATE_44100                0x90
-#define TWL4030_APLL_RATE_48000                0xA0
-#define TWL4030_APLL_RATE_96000                0xE0
-#define TWL4030_SEL_16K                        0x08
-#define TWL4030_CODECPDZ               0x02
-#define TWL4030_OPT_MODE               0x01
-#define TWL4030_OPTION_1               (1 << 0)
-#define TWL4030_OPTION_2               (0 << 0)
-
-/* TWL4030_OPTION (0x02) Fields */
-
-#define TWL4030_ATXL1_EN               (1 << 0)
-#define TWL4030_ATXR1_EN               (1 << 1)
-#define TWL4030_ATXL2_VTXL_EN          (1 << 2)
-#define TWL4030_ATXR2_VTXR_EN          (1 << 3)
-#define TWL4030_ARXL1_VRX_EN           (1 << 4)
-#define TWL4030_ARXR1_EN               (1 << 5)
-#define TWL4030_ARXL2_EN               (1 << 6)
-#define TWL4030_ARXR2_EN               (1 << 7)
-
-/* TWL4030_REG_MICBIAS_CTL (0x04) Fields */
-
-#define TWL4030_MICBIAS2_CTL           0x40
-#define TWL4030_MICBIAS1_CTL           0x20
-#define TWL4030_HSMICBIAS_EN           0x04
-#define TWL4030_MICBIAS2_EN            0x02
-#define TWL4030_MICBIAS1_EN            0x01
-
-/* ANAMICL (0x05) Fields */
-
-#define TWL4030_CNCL_OFFSET_START      0x80
-#define TWL4030_OFFSET_CNCL_SEL                0x60
-#define TWL4030_OFFSET_CNCL_SEL_ARX1   0x00
-#define TWL4030_OFFSET_CNCL_SEL_ARX2   0x20
-#define TWL4030_OFFSET_CNCL_SEL_VRX    0x40
-#define TWL4030_OFFSET_CNCL_SEL_ALL    0x60
-#define TWL4030_MICAMPL_EN             0x10
-#define TWL4030_CKMIC_EN               0x08
-#define TWL4030_AUXL_EN                        0x04
-#define TWL4030_HSMIC_EN               0x02
-#define TWL4030_MAINMIC_EN             0x01
-
-/* ANAMICR (0x06) Fields */
-
-#define TWL4030_MICAMPR_EN             0x10
-#define TWL4030_AUXR_EN                        0x04
-#define TWL4030_SUBMIC_EN              0x01
-
-/* AVADC_CTL (0x07) Fields */
-
-#define TWL4030_ADCL_EN                        0x08
-#define TWL4030_AVADC_CLK_PRIORITY     0x04
-#define TWL4030_ADCR_EN                        0x02
-
-/* TWL4030_REG_ADCMICSEL (0x08) Fields */
-
-#define TWL4030_DIGMIC1_EN             0x08
-#define TWL4030_TX2IN_SEL              0x04
-#define TWL4030_DIGMIC0_EN             0x02
-#define TWL4030_TX1IN_SEL              0x01
-
-/* AUDIO_IF (0x0E) Fields */
-
-#define TWL4030_AIF_SLAVE_EN           0x80
-#define TWL4030_DATA_WIDTH             0x60
-#define TWL4030_DATA_WIDTH_16S_16W     0x00
-#define TWL4030_DATA_WIDTH_32S_16W     0x40
-#define TWL4030_DATA_WIDTH_32S_24W     0x60
-#define TWL4030_AIF_FORMAT             0x18
-#define TWL4030_AIF_FORMAT_CODEC       0x00
-#define TWL4030_AIF_FORMAT_LEFT                0x08
-#define TWL4030_AIF_FORMAT_RIGHT       0x10
-#define TWL4030_AIF_FORMAT_TDM         0x18
-#define TWL4030_AIF_TRI_EN             0x04
-#define TWL4030_CLK256FS_EN            0x02
-#define TWL4030_AIF_EN                 0x01
-
-/* VOICE_IF (0x0F) Fields */
-
-#define TWL4030_VIF_SLAVE_EN           0x80
-#define TWL4030_VIF_DIN_EN             0x40
-#define TWL4030_VIF_DOUT_EN            0x20
-#define TWL4030_VIF_SWAP               0x10
-#define TWL4030_VIF_FORMAT             0x08
-#define TWL4030_VIF_TRI_EN             0x04
-#define TWL4030_VIF_SUB_EN             0x02
-#define TWL4030_VIF_EN                 0x01
-
-/* EAR_CTL (0x21) */
-#define TWL4030_EAR_GAIN               0x30
-
-/* HS_GAIN_SET (0x23) Fields */
-
-#define TWL4030_HSR_GAIN               0x0C
-#define TWL4030_HSR_GAIN_PWR_DOWN      0x00
-#define TWL4030_HSR_GAIN_PLUS_6DB      0x04
-#define TWL4030_HSR_GAIN_0DB           0x08
-#define TWL4030_HSR_GAIN_MINUS_6DB     0x0C
-#define TWL4030_HSL_GAIN               0x03
-#define TWL4030_HSL_GAIN_PWR_DOWN      0x00
-#define TWL4030_HSL_GAIN_PLUS_6DB      0x01
-#define TWL4030_HSL_GAIN_0DB           0x02
-#define TWL4030_HSL_GAIN_MINUS_6DB     0x03
-
-/* HS_POPN_SET (0x24) Fields */
-
-#define TWL4030_VMID_EN                        0x40
-#define        TWL4030_EXTMUTE                 0x20
-#define TWL4030_RAMP_DELAY             0x1C
-#define TWL4030_RAMP_DELAY_20MS                0x00
-#define TWL4030_RAMP_DELAY_40MS                0x04
-#define TWL4030_RAMP_DELAY_81MS                0x08
-#define TWL4030_RAMP_DELAY_161MS       0x0C
-#define TWL4030_RAMP_DELAY_323MS       0x10
-#define TWL4030_RAMP_DELAY_645MS       0x14
-#define TWL4030_RAMP_DELAY_1291MS      0x18
-#define TWL4030_RAMP_DELAY_2581MS      0x1C
-#define TWL4030_RAMP_EN                        0x02
-
-/* PREDL_CTL (0x25) */
-#define TWL4030_PREDL_GAIN             0x30
-
-/* PREDR_CTL (0x26) */
-#define TWL4030_PREDR_GAIN             0x30
-
-/* PRECKL_CTL (0x27) */
-#define TWL4030_PRECKL_GAIN            0x30
-
-/* PRECKR_CTL (0x28) */
-#define TWL4030_PRECKR_GAIN            0x30
-
-/* HFL_CTL (0x29, 0x2A) Fields */
-#define TWL4030_HF_CTL_HB_EN           0x04
-#define TWL4030_HF_CTL_LOOP_EN         0x08
-#define TWL4030_HF_CTL_RAMP_EN         0x10
-#define TWL4030_HF_CTL_REF_EN          0x20
-
-/* APLL_CTL (0x3A) Fields */
-
-#define TWL4030_APLL_EN                        0x10
-#define TWL4030_APLL_INFREQ            0x0F
-#define TWL4030_APLL_INFREQ_19200KHZ   0x05
-#define TWL4030_APLL_INFREQ_26000KHZ   0x06
-#define TWL4030_APLL_INFREQ_38400KHZ   0x0F
-
-/* REG_MISC_SET_1 (0x3E) Fields */
-
-#define TWL4030_CLK64_EN               0x80
-#define TWL4030_SCRAMBLE_EN            0x40
-#define TWL4030_FMLOOP_EN              0x20
-#define TWL4030_SMOOTH_ANAVOL_EN       0x02
-#define TWL4030_DIGMIC_LR_SWAP_EN      0x01
-
 /* TWL4030_REG_SW_SHADOW (0x4A) Fields */
 #define TWL4030_HFL_EN                 0x01
 #define TWL4030_HFR_EN                 0x02
@@ -279,3 +47,5 @@ struct twl4030_setup_data {
 };
 
 #endif /* End of __TWL4030_AUDIO_H__ */
+
+
index c33b92e..aa40d98 100644 (file)
@@ -562,17 +562,8 @@ static int uda134x_soc_probe(struct platform_device *pdev)
                goto pcm_err;
        }
 
-       ret = snd_soc_init_card(socdev);
-       if (ret < 0) {
-               printk(KERN_ERR "UDA134X: failed to register card\n");
-               goto card_err;
-       }
-
        return 0;
 
-card_err:
-       snd_soc_free_pcms(socdev);
-       snd_soc_dapm_free(socdev);
 pcm_err:
        kfree(codec->reg_cache);
 reg_err:
index 92ec034..a2763c2 100644 (file)
@@ -378,7 +378,6 @@ static int uda1380_add_widgets(struct snd_soc_codec *codec)
 
        snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
 
-       snd_soc_dapm_new_widgets(codec);
        return 0;
 }
 
@@ -713,17 +712,9 @@ static int uda1380_probe(struct platform_device *pdev)
        snd_soc_add_controls(codec, uda1380_snd_controls,
                                ARRAY_SIZE(uda1380_snd_controls));
        uda1380_add_widgets(codec);
-       ret = snd_soc_init_card(socdev);
-       if (ret < 0) {
-               dev_err(codec->dev, "failed to register card: %d\n", ret);
-               goto card_err;
-       }
 
        return ret;
 
-card_err:
-       snd_soc_free_pcms(socdev);
-       snd_soc_dapm_free(socdev);
 pcm_err:
        return ret;
 }
index 593d5b9..f82125d 100644 (file)
@@ -800,7 +800,7 @@ static int wm8350_add_widgets(struct snd_soc_codec *codec)
                return ret;
        }
 
-       return snd_soc_dapm_new_widgets(codec);
+       return 0;
 }
 
 static int wm8350_set_dai_sysclk(struct snd_soc_dai *codec_dai,
@@ -1101,7 +1101,7 @@ static inline int fll_factors(struct _fll_div *fll_div, unsigned int input,
 }
 
 static int wm8350_set_fll(struct snd_soc_dai *codec_dai,
-                         int pll_id, unsigned int freq_in,
+                         int pll_id, int source, unsigned int freq_in,
                          unsigned int freq_out)
 {
        struct snd_soc_codec *codec = codec_dai->codec;
@@ -1501,18 +1501,7 @@ static int wm8350_probe(struct platform_device *pdev)
 
        wm8350_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
-       ret = snd_soc_init_card(socdev);
-       if (ret < 0) {
-               dev_err(&pdev->dev, "failed to register card\n");
-               goto card_err;
-       }
-
        return 0;
-
-card_err:
-       snd_soc_free_pcms(socdev);
-       snd_soc_dapm_free(socdev);
-       return ret;
 }
 
 static int wm8350_remove(struct platform_device *pdev)
@@ -1680,21 +1669,6 @@ static int __devexit wm8350_codec_remove(struct platform_device *pdev)
        return 0;
 }
 
-#ifdef CONFIG_PM
-static int wm8350_codec_suspend(struct platform_device *pdev, pm_message_t m)
-{
-       return snd_soc_suspend_device(&pdev->dev);
-}
-
-static int wm8350_codec_resume(struct platform_device *pdev)
-{
-       return snd_soc_resume_device(&pdev->dev);
-}
-#else
-#define wm8350_codec_suspend NULL
-#define wm8350_codec_resume NULL
-#endif
-
 static struct platform_driver wm8350_codec_driver = {
        .driver = {
                   .name = "wm8350-codec",
@@ -1702,8 +1676,6 @@ static struct platform_driver wm8350_codec_driver = {
                   },
        .probe = wm8350_codec_probe,
        .remove = __devexit_p(wm8350_codec_remove),
-       .suspend = wm8350_codec_suspend,
-       .resume = wm8350_codec_resume,
 };
 
 static __init int wm8350_init(void)
index b9ef4d9..b432f4d 100644 (file)
@@ -915,7 +915,6 @@ static int wm8400_add_widgets(struct snd_soc_codec *codec)
 
        snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
 
-       snd_soc_dapm_new_widgets(codec);
        return 0;
 }
 
@@ -1011,7 +1010,8 @@ static int fll_factors(struct wm8400_priv *wm8400, struct fll_factors *factors,
 }
 
 static int wm8400_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
-                             unsigned int freq_in, unsigned int freq_out)
+                             int source, unsigned int freq_in,
+                             unsigned int freq_out)
 {
        struct snd_soc_codec *codec = codec_dai->codec;
        struct wm8400_priv *wm8400 = codec->private_data;
@@ -1399,17 +1399,6 @@ static int wm8400_probe(struct platform_device *pdev)
        wm8400_add_controls(codec);
        wm8400_add_widgets(codec);
 
-       ret = snd_soc_init_card(socdev);
-       if (ret < 0) {
-               dev_err(&pdev->dev, "failed to register card\n");
-               goto card_err;
-       }
-
-       return ret;
-
-card_err:
-       snd_soc_free_pcms(socdev);
-       snd_soc_dapm_free(socdev);
 pcm_err:
        return ret;
 }
@@ -1558,21 +1547,6 @@ static int __exit wm8400_codec_remove(struct platform_device *dev)
        return 0;
 }
 
-#ifdef CONFIG_PM
-static int wm8400_pdev_suspend(struct platform_device *pdev, pm_message_t msg)
-{
-       return snd_soc_suspend_device(&pdev->dev);
-}
-
-static int wm8400_pdev_resume(struct platform_device *pdev)
-{
-       return snd_soc_resume_device(&pdev->dev);
-}
-#else
-#define wm8400_pdev_suspend NULL
-#define wm8400_pdev_resume NULL
-#endif
-
 static struct platform_driver wm8400_codec_driver = {
        .driver = {
                .name = "wm8400-codec",
@@ -1580,8 +1554,6 @@ static struct platform_driver wm8400_codec_driver = {
        },
        .probe = wm8400_codec_probe,
        .remove = __exit_p(wm8400_codec_remove),
-       .suspend = wm8400_pdev_suspend,
-       .resume = wm8400_pdev_resume,
 };
 
 static int __init wm8400_codec_init(void)
index 060d5d0..265e68c 100644 (file)
@@ -219,7 +219,6 @@ static int wm8510_add_widgets(struct snd_soc_codec *codec)
 
        snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
 
-       snd_soc_dapm_new_widgets(codec);
        return 0;
 }
 
@@ -271,8 +270,8 @@ static void pll_factors(unsigned int target, unsigned int source)
        pll_div.k = K;
 }
 
-static int wm8510_set_dai_pll(struct snd_soc_dai *codec_dai,
-               int pll_id, unsigned int freq_in, unsigned int freq_out)
+static int wm8510_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
+               int source, unsigned int freq_in, unsigned int freq_out)
 {
        struct snd_soc_codec *codec = codec_dai->codec;
        u16 reg;
@@ -604,16 +603,9 @@ static int wm8510_init(struct snd_soc_device *socdev,
        snd_soc_add_controls(codec, wm8510_snd_controls,
                                ARRAY_SIZE(wm8510_snd_controls));
        wm8510_add_widgets(codec);
-       ret = snd_soc_init_card(socdev);
-       if (ret < 0) {
-               printk(KERN_ERR "wm8510: failed to register card\n");
-               goto card_err;
-       }
+
        return ret;
 
-card_err:
-       snd_soc_free_pcms(socdev);
-       snd_soc_dapm_free(socdev);
 err:
        kfree(codec->reg_cache);
        return ret;
index 25870a4..d3a61d7 100644 (file)
@@ -117,7 +117,6 @@ static int wm8523_add_widgets(struct snd_soc_codec *codec)
 
        snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon));
 
-       snd_soc_dapm_new_widgets(codec);
        return 0;
 }
 
@@ -448,17 +447,9 @@ static int wm8523_probe(struct platform_device *pdev)
        snd_soc_add_controls(codec, wm8523_snd_controls,
                             ARRAY_SIZE(wm8523_snd_controls));
        wm8523_add_widgets(codec);
-       ret = snd_soc_init_card(socdev);
-       if (ret < 0) {
-               dev_err(codec->dev, "failed to register card: %d\n", ret);
-               goto card_err;
-       }
 
        return ret;
 
-card_err:
-       snd_soc_free_pcms(socdev);
-       snd_soc_dapm_free(socdev);
 pcm_err:
        return ret;
 }
@@ -638,21 +629,6 @@ static __devexit int wm8523_i2c_remove(struct i2c_client *client)
        return 0;
 }
 
-#ifdef CONFIG_PM
-static int wm8523_i2c_suspend(struct i2c_client *i2c, pm_message_t msg)
-{
-       return snd_soc_suspend_device(&i2c->dev);
-}
-
-static int wm8523_i2c_resume(struct i2c_client *i2c)
-{
-       return snd_soc_resume_device(&i2c->dev);
-}
-#else
-#define wm8523_i2c_suspend NULL
-#define wm8523_i2c_resume NULL
-#endif
-
 static const struct i2c_device_id wm8523_i2c_id[] = {
        { "wm8523", 0 },
        { }
@@ -666,8 +642,6 @@ static struct i2c_driver wm8523_i2c_driver = {
        },
        .probe =    wm8523_i2c_probe,
        .remove =   __devexit_p(wm8523_i2c_remove),
-       .suspend =  wm8523_i2c_suspend,
-       .resume =   wm8523_i2c_resume,
        .id_table = wm8523_i2c_id,
 };
 #endif
index 6bded8c..d077df6 100644 (file)
@@ -315,7 +315,6 @@ static int wm8580_add_widgets(struct snd_soc_codec *codec)
 
        snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
 
-       snd_soc_dapm_new_widgets(codec);
        return 0;
 }
 
@@ -407,8 +406,8 @@ static int pll_factors(struct _pll_div *pll_div, unsigned int target,
        return 0;
 }
 
-static int wm8580_set_dai_pll(struct snd_soc_dai *codec_dai,
-               int pll_id, unsigned int freq_in, unsigned int freq_out)
+static int wm8580_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
+               int source, unsigned int freq_in, unsigned int freq_out)
 {
        int offset;
        struct snd_soc_codec *codec = codec_dai->codec;
@@ -800,17 +799,9 @@ static int wm8580_probe(struct platform_device *pdev)
        snd_soc_add_controls(codec, wm8580_snd_controls,
                             ARRAY_SIZE(wm8580_snd_controls));
        wm8580_add_widgets(codec);
-       ret = snd_soc_init_card(socdev);
-       if (ret < 0) {
-               dev_err(codec->dev, "failed to register card: %d\n", ret);
-               goto card_err;
-       }
 
        return ret;
 
-card_err:
-       snd_soc_free_pcms(socdev);
-       snd_soc_dapm_free(socdev);
 pcm_err:
        return ret;
 }
@@ -961,21 +952,6 @@ static int wm8580_i2c_remove(struct i2c_client *client)
        return 0;
 }
 
-#ifdef CONFIG_PM
-static int wm8580_i2c_suspend(struct i2c_client *client, pm_message_t msg)
-{
-       return snd_soc_suspend_device(&client->dev);
-}
-
-static int wm8580_i2c_resume(struct i2c_client *client)
-{
-       return snd_soc_resume_device(&client->dev);
-}
-#else
-#define wm8580_i2c_suspend NULL
-#define wm8580_i2c_resume NULL
-#endif
-
 static const struct i2c_device_id wm8580_i2c_id[] = {
        { "wm8580", 0 },
        { }
@@ -989,8 +965,6 @@ static struct i2c_driver wm8580_i2c_driver = {
        },
        .probe =    wm8580_i2c_probe,
        .remove =   wm8580_i2c_remove,
-       .suspend =  wm8580_i2c_suspend,
-       .resume =   wm8580_i2c_resume,
        .id_table = wm8580_i2c_id,
 };
 #endif
diff --git a/sound/soc/codecs/wm8711.c b/sound/soc/codecs/wm8711.c
new file mode 100644 (file)
index 0000000..24a3560
--- /dev/null
@@ -0,0 +1,633 @@
+/*
+ * wm8711.c  --  WM8711 ALSA SoC Audio driver
+ *
+ * Copyright 2006 Wolfson Microelectronics
+ *
+ * Author: Mike Arthur <linux@wolfsonmicro.com>
+ *
+ * Based on wm8731.c by Richard Purdie
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <linux/spi/spi.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/tlv.h>
+#include <sound/initval.h>
+
+#include "wm8711.h"
+
+static struct snd_soc_codec *wm8711_codec;
+
+/* codec private data */
+struct wm8711_priv {
+       struct snd_soc_codec codec;
+       u16 reg_cache[WM8711_CACHEREGNUM];
+       unsigned int sysclk;
+};
+
+/*
+ * wm8711 register cache
+ * We can't read the WM8711 register space when we are
+ * using 2 wire for device control, so we cache them instead.
+ * There is no point in caching the reset register
+ */
+static const u16 wm8711_reg[WM8711_CACHEREGNUM] = {
+       0x0079, 0x0079, 0x000a, 0x0008,
+       0x009f, 0x000a, 0x0000, 0x0000
+};
+
+#define wm8711_reset(c)        snd_soc_write(c, WM8711_RESET, 0)
+
+static const DECLARE_TLV_DB_SCALE(out_tlv, -12100, 100, 1);
+
+static const struct snd_kcontrol_new wm8711_snd_controls[] = {
+
+SOC_DOUBLE_R_TLV("Master Playback Volume", WM8711_LOUT1V, WM8711_ROUT1V,
+                0, 127, 0, out_tlv),
+SOC_DOUBLE_R("Master Playback ZC Switch", WM8711_LOUT1V, WM8711_ROUT1V,
+       7, 1, 0),
+
+};
+
+/* Output Mixer */
+static const struct snd_kcontrol_new wm8711_output_mixer_controls[] = {
+SOC_DAPM_SINGLE("Line Bypass Switch", WM8711_APANA, 3, 1, 0),
+SOC_DAPM_SINGLE("HiFi Playback Switch", WM8711_APANA, 4, 1, 0),
+};
+
+static const struct snd_soc_dapm_widget wm8711_dapm_widgets[] = {
+SND_SOC_DAPM_MIXER("Output Mixer", WM8711_PWR, 4, 1,
+       &wm8711_output_mixer_controls[0],
+       ARRAY_SIZE(wm8711_output_mixer_controls)),
+SND_SOC_DAPM_DAC("DAC", "HiFi Playback", WM8711_PWR, 3, 1),
+SND_SOC_DAPM_OUTPUT("LOUT"),
+SND_SOC_DAPM_OUTPUT("LHPOUT"),
+SND_SOC_DAPM_OUTPUT("ROUT"),
+SND_SOC_DAPM_OUTPUT("RHPOUT"),
+};
+
+static const struct snd_soc_dapm_route intercon[] = {
+       /* output mixer */
+       {"Output Mixer", "Line Bypass Switch", "Line Input"},
+       {"Output Mixer", "HiFi Playback Switch", "DAC"},
+
+       /* outputs */
+       {"RHPOUT", NULL, "Output Mixer"},
+       {"ROUT", NULL, "Output Mixer"},
+       {"LHPOUT", NULL, "Output Mixer"},
+       {"LOUT", NULL, "Output Mixer"},
+};
+
+static int wm8711_add_widgets(struct snd_soc_codec *codec)
+{
+       snd_soc_dapm_new_controls(codec, wm8711_dapm_widgets,
+                                 ARRAY_SIZE(wm8711_dapm_widgets));
+
+       snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon));
+
+       return 0;
+}
+
+struct _coeff_div {
+       u32 mclk;
+       u32 rate;
+       u16 fs;
+       u8 sr:4;
+       u8 bosr:1;
+       u8 usb:1;
+};
+
+/* codec mclk clock divider coefficients */
+static const struct _coeff_div coeff_div[] = {
+       /* 48k */
+       {12288000, 48000, 256, 0x0, 0x0, 0x0},
+       {18432000, 48000, 384, 0x0, 0x1, 0x0},
+       {12000000, 48000, 250, 0x0, 0x0, 0x1},
+
+       /* 32k */
+       {12288000, 32000, 384, 0x6, 0x0, 0x0},
+       {18432000, 32000, 576, 0x6, 0x1, 0x0},
+       {12000000, 32000, 375, 0x6, 0x0, 0x1},
+
+       /* 8k */
+       {12288000, 8000, 1536, 0x3, 0x0, 0x0},
+       {18432000, 8000, 2304, 0x3, 0x1, 0x0},
+       {11289600, 8000, 1408, 0xb, 0x0, 0x0},
+       {16934400, 8000, 2112, 0xb, 0x1, 0x0},
+       {12000000, 8000, 1500, 0x3, 0x0, 0x1},
+
+       /* 96k */
+       {12288000, 96000, 128, 0x7, 0x0, 0x0},
+       {18432000, 96000, 192, 0x7, 0x1, 0x0},
+       {12000000, 96000, 125, 0x7, 0x0, 0x1},
+
+       /* 44.1k */
+       {11289600, 44100, 256, 0x8, 0x0, 0x0},
+       {16934400, 44100, 384, 0x8, 0x1, 0x0},
+       {12000000, 44100, 272, 0x8, 0x1, 0x1},
+
+       /* 88.2k */
+       {11289600, 88200, 128, 0xf, 0x0, 0x0},
+       {16934400, 88200, 192, 0xf, 0x1, 0x0},
+       {12000000, 88200, 136, 0xf, 0x1, 0x1},
+};
+
+static inline int get_coeff(int mclk, int rate)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(coeff_div); i++) {
+               if (coeff_div[i].rate == rate && coeff_div[i].mclk == mclk)
+                       return i;
+       }
+       return 0;
+}
+
+static int wm8711_hw_params(struct snd_pcm_substream *substream,
+       struct snd_pcm_hw_params *params,
+       struct snd_soc_dai *dai)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       struct wm8711_priv *wm8711 = codec->private_data;
+       u16 iface = snd_soc_read(codec, WM8711_IFACE) & 0xfffc;
+       int i = get_coeff(wm8711->sysclk, params_rate(params));
+       u16 srate = (coeff_div[i].sr << 2) |
+               (coeff_div[i].bosr << 1) | coeff_div[i].usb;
+
+       snd_soc_write(codec, WM8711_SRATE, srate);
+
+       /* bit size */
+       switch (params_format(params)) {
+       case SNDRV_PCM_FORMAT_S16_LE:
+               break;
+       case SNDRV_PCM_FORMAT_S20_3LE:
+               iface |= 0x0004;
+               break;
+       case SNDRV_PCM_FORMAT_S24_LE:
+               iface |= 0x0008;
+               break;
+       }
+
+       snd_soc_write(codec, WM8711_IFACE, iface);
+       return 0;
+}
+
+static int wm8711_pcm_prepare(struct snd_pcm_substream *substream,
+                             struct snd_soc_dai *dai)
+{
+       struct snd_soc_codec *codec = dai->codec;
+
+       /* set active */
+       snd_soc_write(codec, WM8711_ACTIVE, 0x0001);
+
+       return 0;
+}
+
+static void wm8711_shutdown(struct snd_pcm_substream *substream,
+                           struct snd_soc_dai *dai)
+{
+       struct snd_soc_codec *codec = dai->codec;
+
+       /* deactivate */
+       if (!codec->active) {
+               udelay(50);
+               snd_soc_write(codec, WM8711_ACTIVE, 0x0);
+       }
+}
+
+static int wm8711_mute(struct snd_soc_dai *dai, int mute)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       u16 mute_reg = snd_soc_read(codec, WM8711_APDIGI) & 0xfff7;
+
+       if (mute)
+               snd_soc_write(codec, WM8711_APDIGI, mute_reg | 0x8);
+       else
+               snd_soc_write(codec, WM8711_APDIGI, mute_reg);
+
+       return 0;
+}
+
+static int wm8711_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+               int clk_id, unsigned int freq, int dir)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+       struct wm8711_priv *wm8711 = codec->private_data;
+
+       switch (freq) {
+       case 11289600:
+       case 12000000:
+       case 12288000:
+       case 16934400:
+       case 18432000:
+               wm8711->sysclk = freq;
+               return 0;
+       }
+       return -EINVAL;
+}
+
+static int wm8711_set_dai_fmt(struct snd_soc_dai *codec_dai,
+               unsigned int fmt)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+       u16 iface = 0;
+
+       /* set master/slave audio interface */
+       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_CBM_CFM:
+               iface |= 0x0040;
+               break;
+       case SND_SOC_DAIFMT_CBS_CFS:
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       /* interface format */
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_I2S:
+               iface |= 0x0002;
+               break;
+       case SND_SOC_DAIFMT_RIGHT_J:
+               break;
+       case SND_SOC_DAIFMT_LEFT_J:
+               iface |= 0x0001;
+               break;
+       case SND_SOC_DAIFMT_DSP_A:
+               iface |= 0x0003;
+               break;
+       case SND_SOC_DAIFMT_DSP_B:
+               iface |= 0x0013;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       /* clock inversion */
+       switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+       case SND_SOC_DAIFMT_NB_NF:
+               break;
+       case SND_SOC_DAIFMT_IB_IF:
+               iface |= 0x0090;
+               break;
+       case SND_SOC_DAIFMT_IB_NF:
+               iface |= 0x0080;
+               break;
+       case SND_SOC_DAIFMT_NB_IF:
+               iface |= 0x0010;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       /* set iface */
+       snd_soc_write(codec, WM8711_IFACE, iface);
+       return 0;
+}
+
+
+static int wm8711_set_bias_level(struct snd_soc_codec *codec,
+       enum snd_soc_bias_level level)
+{
+       u16 reg = snd_soc_read(codec, WM8711_PWR) & 0xff7f;
+
+       switch (level) {
+       case SND_SOC_BIAS_ON:
+               snd_soc_write(codec, WM8711_PWR, reg);
+               break;
+       case SND_SOC_BIAS_PREPARE:
+               break;
+       case SND_SOC_BIAS_STANDBY:
+               snd_soc_write(codec, WM8711_PWR, reg | 0x0040);
+               break;
+       case SND_SOC_BIAS_OFF:
+               snd_soc_write(codec, WM8711_ACTIVE, 0x0);
+               snd_soc_write(codec, WM8711_PWR, 0xffff);
+               break;
+       }
+       codec->bias_level = level;
+       return 0;
+}
+
+#define WM8711_RATES SNDRV_PCM_RATE_8000_96000
+
+#define WM8711_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
+       SNDRV_PCM_FMTBIT_S24_LE)
+
+static struct snd_soc_dai_ops wm8711_ops = {
+       .prepare = wm8711_pcm_prepare,
+       .hw_params = wm8711_hw_params,
+       .shutdown = wm8711_shutdown,
+       .digital_mute = wm8711_mute,
+       .set_sysclk = wm8711_set_dai_sysclk,
+       .set_fmt = wm8711_set_dai_fmt,
+};
+
+struct snd_soc_dai wm8711_dai = {
+       .name = "WM8711",
+       .playback = {
+               .stream_name = "Playback",
+               .channels_min = 1,
+               .channels_max = 2,
+               .rates = WM8711_RATES,
+               .formats = WM8711_FORMATS,
+       },
+       .ops = &wm8711_ops,
+};
+EXPORT_SYMBOL_GPL(wm8711_dai);
+
+static int wm8711_suspend(struct platform_device *pdev, pm_message_t state)
+{
+       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+       struct snd_soc_codec *codec = socdev->card->codec;
+
+       snd_soc_write(codec, WM8711_ACTIVE, 0x0);
+       wm8711_set_bias_level(codec, SND_SOC_BIAS_OFF);
+       return 0;
+}
+
+static int wm8711_resume(struct platform_device *pdev)
+{
+       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+       struct snd_soc_codec *codec = socdev->card->codec;
+       int i;
+       u8 data[2];
+       u16 *cache = codec->reg_cache;
+
+       /* Sync reg_cache with the hardware */
+       for (i = 0; i < ARRAY_SIZE(wm8711_reg); i++) {
+               data[0] = (i << 1) | ((cache[i] >> 8) & 0x0001);
+               data[1] = cache[i] & 0x00ff;
+               codec->hw_write(codec->control_data, data, 2);
+       }
+       wm8711_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+       wm8711_set_bias_level(codec, codec->suspend_bias_level);
+       return 0;
+}
+
+static int wm8711_probe(struct platform_device *pdev)
+{
+       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+       struct snd_soc_codec *codec;
+       int ret = 0;
+
+       if (wm8711_codec == NULL) {
+               dev_err(&pdev->dev, "Codec device not registered\n");
+               return -ENODEV;
+       }
+
+       socdev->card->codec = wm8711_codec;
+       codec = wm8711_codec;
+
+       /* register pcms */
+       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
+       if (ret < 0) {
+               dev_err(codec->dev, "failed to create pcms: %d\n", ret);
+               goto pcm_err;
+       }
+
+       snd_soc_add_controls(codec, wm8711_snd_controls,
+                            ARRAY_SIZE(wm8711_snd_controls));
+       wm8711_add_widgets(codec);
+
+       return ret;
+
+pcm_err:
+       return ret;
+}
+
+/* power down chip */
+static int wm8711_remove(struct platform_device *pdev)
+{
+       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+
+       snd_soc_free_pcms(socdev);
+       snd_soc_dapm_free(socdev);
+
+       return 0;
+}
+
+struct snd_soc_codec_device soc_codec_dev_wm8711 = {
+       .probe =        wm8711_probe,
+       .remove =       wm8711_remove,
+       .suspend =      wm8711_suspend,
+       .resume =       wm8711_resume,
+};
+EXPORT_SYMBOL_GPL(soc_codec_dev_wm8711);
+
+static int wm8711_register(struct wm8711_priv *wm8711,
+                          enum snd_soc_control_type control)
+{
+       int ret;
+       struct snd_soc_codec *codec = &wm8711->codec;
+       u16 reg;
+
+       if (wm8711_codec) {
+               dev_err(codec->dev, "Another WM8711 is registered\n");
+               return -EINVAL;
+       }
+
+       mutex_init(&codec->mutex);
+       INIT_LIST_HEAD(&codec->dapm_widgets);
+       INIT_LIST_HEAD(&codec->dapm_paths);
+
+       codec->private_data = wm8711;
+       codec->name = "WM8711";
+       codec->owner = THIS_MODULE;
+       codec->bias_level = SND_SOC_BIAS_OFF;
+       codec->set_bias_level = wm8711_set_bias_level;
+       codec->dai = &wm8711_dai;
+       codec->num_dai = 1;
+       codec->reg_cache_size = WM8711_CACHEREGNUM;
+       codec->reg_cache = &wm8711->reg_cache;
+
+       memcpy(codec->reg_cache, wm8711_reg, sizeof(wm8711_reg));
+
+       ret = snd_soc_codec_set_cache_io(codec, 7, 9, control);
+       if (ret < 0) {
+               dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
+               goto err;
+       }
+
+       ret = wm8711_reset(codec);
+       if (ret < 0) {
+               dev_err(codec->dev, "Failed to issue reset\n");
+               goto err;
+       }
+
+       wm8711_dai.dev = codec->dev;
+
+       wm8711_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+       /* Latch the update bits */
+       reg = snd_soc_read(codec, WM8711_LOUT1V);
+       snd_soc_write(codec, WM8711_LOUT1V, reg | 0x0100);
+       reg = snd_soc_read(codec, WM8711_ROUT1V);
+       snd_soc_write(codec, WM8711_ROUT1V, reg | 0x0100);
+
+       wm8711_codec = codec;
+
+       ret = snd_soc_register_codec(codec);
+       if (ret != 0) {
+               dev_err(codec->dev, "Failed to register codec: %d\n", ret);
+               goto err;
+       }
+
+       ret = snd_soc_register_dai(&wm8711_dai);
+       if (ret != 0) {
+               dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
+               goto err_codec;
+       }
+
+       return 0;
+
+err_codec:
+       snd_soc_unregister_codec(codec);
+err:
+       kfree(wm8711);
+       return ret;
+}
+
+static void wm8711_unregister(struct wm8711_priv *wm8711)
+{
+       wm8711_set_bias_level(&wm8711->codec, SND_SOC_BIAS_OFF);
+       snd_soc_unregister_dai(&wm8711_dai);
+       snd_soc_unregister_codec(&wm8711->codec);
+       kfree(wm8711);
+       wm8711_codec = NULL;
+}
+
+#if defined(CONFIG_SPI_MASTER)
+static int __devinit wm8711_spi_probe(struct spi_device *spi)
+{
+       struct snd_soc_codec *codec;
+       struct wm8711_priv *wm8711;
+
+       wm8711 = kzalloc(sizeof(struct wm8711_priv), GFP_KERNEL);
+       if (wm8711 == NULL)
+               return -ENOMEM;
+
+       codec = &wm8711->codec;
+       codec->control_data = spi;
+       codec->dev = &spi->dev;
+
+       dev_set_drvdata(&spi->dev, wm8711);
+
+       return wm8711_register(wm8711, SND_SOC_SPI);
+}
+
+static int __devexit wm8711_spi_remove(struct spi_device *spi)
+{
+       struct wm8711_priv *wm8711 = dev_get_drvdata(&spi->dev);
+
+       wm8711_unregister(wm8711);
+
+       return 0;
+}
+
+static struct spi_driver wm8711_spi_driver = {
+       .driver = {
+               .name   = "wm8711",
+               .bus    = &spi_bus_type,
+               .owner  = THIS_MODULE,
+       },
+       .probe          = wm8711_spi_probe,
+       .remove         = __devexit_p(wm8711_spi_remove),
+};
+#endif /* CONFIG_SPI_MASTER */
+
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+static __devinit int wm8711_i2c_probe(struct i2c_client *i2c,
+                                     const struct i2c_device_id *id)
+{
+       struct wm8711_priv *wm8711;
+       struct snd_soc_codec *codec;
+
+       wm8711 = kzalloc(sizeof(struct wm8711_priv), GFP_KERNEL);
+       if (wm8711 == NULL)
+               return -ENOMEM;
+
+       codec = &wm8711->codec;
+       codec->hw_write = (hw_write_t)i2c_master_send;
+
+       i2c_set_clientdata(i2c, wm8711);
+       codec->control_data = i2c;
+
+       codec->dev = &i2c->dev;
+
+       return wm8711_register(wm8711, SND_SOC_I2C);
+}
+
+static __devexit int wm8711_i2c_remove(struct i2c_client *client)
+{
+       struct wm8711_priv *wm8711 = i2c_get_clientdata(client);
+       wm8711_unregister(wm8711);
+       return 0;
+}
+
+static const struct i2c_device_id wm8711_i2c_id[] = {
+       { "wm8711", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, wm8711_i2c_id);
+
+static struct i2c_driver wm8711_i2c_driver = {
+       .driver = {
+               .name = "WM8711 I2C Codec",
+               .owner = THIS_MODULE,
+       },
+       .probe =    wm8711_i2c_probe,
+       .remove =   __devexit_p(wm8711_i2c_remove),
+       .id_table = wm8711_i2c_id,
+};
+#endif
+
+static int __init wm8711_modinit(void)
+{
+       int ret;
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+       ret = i2c_add_driver(&wm8711_i2c_driver);
+       if (ret != 0) {
+               printk(KERN_ERR "Failed to register WM8711 I2C driver: %d\n",
+                      ret);
+       }
+#endif
+#if defined(CONFIG_SPI_MASTER)
+       ret = spi_register_driver(&wm8711_spi_driver);
+       if (ret != 0) {
+               printk(KERN_ERR "Failed to register WM8711 SPI driver: %d\n",
+                      ret);
+       }
+#endif
+       return 0;
+}
+module_init(wm8711_modinit);
+
+static void __exit wm8711_exit(void)
+{
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+       i2c_del_driver(&wm8711_i2c_driver);
+#endif
+#if defined(CONFIG_SPI_MASTER)
+       spi_unregister_driver(&wm8711_spi_driver);
+#endif
+}
+module_exit(wm8711_exit);
+
+MODULE_DESCRIPTION("ASoC WM8711 driver");
+MODULE_AUTHOR("Mike Arthur");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm8711.h b/sound/soc/codecs/wm8711.h
new file mode 100644 (file)
index 0000000..381e84a
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * wm8711.h  --  WM8711 Soc Audio driver
+ *
+ * Copyright 2006 Wolfson Microelectronics
+ *
+ * Author: Mike Arthur <linux@wolfsonmicro.com>
+ *
+ * Based on wm8731.h
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _WM8711_H
+#define _WM8711_H
+
+/* WM8711 register space */
+
+#define WM8711_LOUT1V   0x02
+#define WM8711_ROUT1V   0x03
+#define WM8711_APANA    0x04
+#define WM8711_APDIGI   0x05
+#define WM8711_PWR      0x06
+#define WM8711_IFACE    0x07
+#define WM8711_SRATE    0x08
+#define WM8711_ACTIVE   0x09
+#define WM8711_RESET   0x0f
+
+#define WM8711_CACHEREGNUM     8
+
+#define WM8711_SYSCLK  0
+#define WM8711_DAI             0
+
+struct wm8711_setup_data {
+       unsigned short i2c_address;
+};
+
+extern struct snd_soc_dai wm8711_dai;
+extern struct snd_soc_codec_device soc_codec_dev_wm8711;
+
+#endif
diff --git a/sound/soc/codecs/wm8727.c b/sound/soc/codecs/wm8727.c
new file mode 100644 (file)
index 0000000..d8ffbd6
--- /dev/null
@@ -0,0 +1,135 @@
+/*
+ * wm8727.c
+ *
+ *  Created on: 15-Oct-2009
+ *      Author: neil.jones@imgtec.com
+ *
+ * Copyright (C) 2009 Imagination Technologies Ltd.
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/ac97_codec.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+
+#include "wm8727.h"
+/*
+ * Note this is a simple chip with no configuration interface, sample rate is
+ * determined automatically by examining the Master clock and Bit clock ratios
+ */
+#define WM8727_RATES  (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |\
+                       SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 |\
+                       SNDRV_PCM_RATE_192000)
+
+
+struct snd_soc_dai wm8727_dai = {
+       .name = "WM8727",
+       .playback = {
+               .stream_name = "Playback",
+               .channels_min = 2,
+               .channels_max = 2,
+               .rates = WM8727_RATES,
+               .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE,
+               },
+};
+EXPORT_SYMBOL_GPL(wm8727_dai);
+
+static int wm8727_soc_probe(struct platform_device *pdev)
+{
+       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+       struct snd_soc_codec *codec;
+       int ret = 0;
+
+       codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
+       if (codec == NULL)
+               return -ENOMEM;
+       mutex_init(&codec->mutex);
+       codec->name = "WM8727";
+       codec->owner = THIS_MODULE;
+       codec->dai = &wm8727_dai;
+       codec->num_dai = 1;
+       socdev->card->codec = codec;
+       INIT_LIST_HEAD(&codec->dapm_widgets);
+       INIT_LIST_HEAD(&codec->dapm_paths);
+
+       /* register pcms */
+       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
+       if (ret < 0) {
+               printk(KERN_ERR "wm8727: failed to create pcms\n");
+               goto pcm_err;
+       }
+
+       return ret;
+
+pcm_err:
+       kfree(socdev->card->codec);
+       socdev->card->codec = NULL;
+       return ret;
+}
+
+static int wm8727_soc_remove(struct platform_device *pdev)
+{
+       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+       struct snd_soc_codec *codec = socdev->card->codec;
+
+       if (codec == NULL)
+               return 0;
+       snd_soc_free_pcms(socdev);
+       kfree(codec);
+       return 0;
+}
+
+struct snd_soc_codec_device soc_codec_dev_wm8727 = {
+       .probe =        wm8727_soc_probe,
+       .remove =       wm8727_soc_remove,
+};
+EXPORT_SYMBOL_GPL(soc_codec_dev_wm8727);
+
+
+static __devinit int wm8727_platform_probe(struct platform_device *pdev)
+{
+       wm8727_dai.dev = &pdev->dev;
+       return snd_soc_register_dai(&wm8727_dai);
+}
+
+static int __devexit wm8727_platform_remove(struct platform_device *pdev)
+{
+       snd_soc_unregister_dai(&wm8727_dai);
+       return 0;
+}
+
+static struct platform_driver wm8727_codec_driver = {
+       .driver = {
+                       .name = "wm8727-codec",
+                       .owner = THIS_MODULE,
+       },
+
+       .probe = wm8727_platform_probe,
+       .remove = __devexit_p(wm8727_platform_remove),
+};
+
+static int __init wm8727_init(void)
+{
+       return platform_driver_register(&wm8727_codec_driver);
+}
+module_init(wm8727_init);
+
+static void __exit wm8727_exit(void)
+{
+       platform_driver_unregister(&wm8727_codec_driver);
+}
+module_exit(wm8727_exit);
+
+MODULE_DESCRIPTION("ASoC wm8727 driver");
+MODULE_AUTHOR("Neil Jones");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm8727.h b/sound/soc/codecs/wm8727.h
new file mode 100644 (file)
index 0000000..ee19aa7
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ * wm8727.h
+ *
+ *  Created on: 15-Oct-2009
+ *      Author: neil.jones@imgtec.com
+ *
+ * Copyright (C) 2009 Imagination Technologies Ltd.
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ */
+
+#ifndef WM8727_H_
+#define WM8727_H_
+
+extern struct snd_soc_dai wm8727_dai;
+extern struct snd_soc_codec_device soc_codec_dev_wm8727;
+
+#endif /* WM8727_H_ */
index 16e969a..3fb653b 100644 (file)
@@ -74,8 +74,6 @@ static int wm8728_add_widgets(struct snd_soc_codec *codec)
 
        snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon));
 
-       snd_soc_dapm_new_widgets(codec);
-
        return 0;
 }
 
@@ -287,17 +285,9 @@ static int wm8728_init(struct snd_soc_device *socdev,
        snd_soc_add_controls(codec, wm8728_snd_controls,
                                ARRAY_SIZE(wm8728_snd_controls));
        wm8728_add_widgets(codec);
-       ret = snd_soc_init_card(socdev);
-       if (ret < 0) {
-               printk(KERN_ERR "wm8728: failed to register card\n");
-               goto card_err;
-       }
 
        return ret;
 
-card_err:
-       snd_soc_free_pcms(socdev);
-       snd_soc_dapm_free(socdev);
 err:
        kfree(codec->reg_cache);
        return ret;
index d3fd4f2..3a49781 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/pm.h>
 #include <linux/i2c.h>
 #include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
 #include <linux/spi/spi.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 static struct snd_soc_codec *wm8731_codec;
 struct snd_soc_codec_device soc_codec_dev_wm8731;
 
+#define WM8731_NUM_SUPPLIES 4
+static const char *wm8731_supply_names[WM8731_NUM_SUPPLIES] = {
+       "AVDD",
+       "HPVDD",
+       "DCVDD",
+       "DBVDD",
+};
+
 /* codec private data */
 struct wm8731_priv {
        struct snd_soc_codec codec;
+       struct regulator_bulk_data supplies[WM8731_NUM_SUPPLIES];
        u16 reg_cache[WM8731_CACHEREGNUM];
        unsigned int sysclk;
 };
@@ -149,7 +159,6 @@ static int wm8731_add_widgets(struct snd_soc_codec *codec)
 
        snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon));
 
-       snd_soc_dapm_new_widgets(codec);
        return 0;
 }
 
@@ -422,9 +431,12 @@ static int wm8731_suspend(struct platform_device *pdev, pm_message_t state)
 {
        struct snd_soc_device *socdev = platform_get_drvdata(pdev);
        struct snd_soc_codec *codec = socdev->card->codec;
+       struct wm8731_priv *wm8731 = codec->private_data;
 
        snd_soc_write(codec, WM8731_ACTIVE, 0x0);
        wm8731_set_bias_level(codec, SND_SOC_BIAS_OFF);
+       regulator_bulk_disable(ARRAY_SIZE(wm8731->supplies),
+                              wm8731->supplies);
        return 0;
 }
 
@@ -432,10 +444,16 @@ static int wm8731_resume(struct platform_device *pdev)
 {
        struct snd_soc_device *socdev = platform_get_drvdata(pdev);
        struct snd_soc_codec *codec = socdev->card->codec;
-       int i;
+       struct wm8731_priv *wm8731 = codec->private_data;
+       int i, ret;
        u8 data[2];
        u16 *cache = codec->reg_cache;
 
+       ret = regulator_bulk_enable(ARRAY_SIZE(wm8731->supplies),
+                                   wm8731->supplies);
+       if (ret != 0)
+               return ret;
+
        /* Sync reg_cache with the hardware */
        for (i = 0; i < ARRAY_SIZE(wm8731_reg); i++) {
                data[0] = (i << 1) | ((cache[i] >> 8) & 0x0001);
@@ -444,6 +462,7 @@ static int wm8731_resume(struct platform_device *pdev)
        }
        wm8731_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
        wm8731_set_bias_level(codec, codec->suspend_bias_level);
+
        return 0;
 }
 #else
@@ -475,17 +494,9 @@ static int wm8731_probe(struct platform_device *pdev)
        snd_soc_add_controls(codec, wm8731_snd_controls,
                             ARRAY_SIZE(wm8731_snd_controls));
        wm8731_add_widgets(codec);
-       ret = snd_soc_init_card(socdev);
-       if (ret < 0) {
-               dev_err(codec->dev, "failed to register card: %d\n", ret);
-               goto card_err;
-       }
 
        return ret;
 
-card_err:
-       snd_soc_free_pcms(socdev);
-       snd_soc_dapm_free(socdev);
 pcm_err:
        return ret;
 }
@@ -512,7 +523,7 @@ EXPORT_SYMBOL_GPL(soc_codec_dev_wm8731);
 static int wm8731_register(struct wm8731_priv *wm8731,
                           enum snd_soc_control_type control)
 {
-       int ret;
+       int ret, i;
        struct snd_soc_codec *codec = &wm8731->codec;
 
        if (wm8731_codec) {
@@ -543,10 +554,27 @@ static int wm8731_register(struct wm8731_priv *wm8731,
                goto err;
        }
 
+       for (i = 0; i < ARRAY_SIZE(wm8731->supplies); i++)
+               wm8731->supplies[i].supply = wm8731_supply_names[i];
+
+       ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8731->supplies),
+                                wm8731->supplies);
+       if (ret != 0) {
+               dev_err(codec->dev, "Failed to request supplies: %d\n", ret);
+               goto err;
+       }
+
+       ret = regulator_bulk_enable(ARRAY_SIZE(wm8731->supplies),
+                                   wm8731->supplies);
+       if (ret != 0) {
+               dev_err(codec->dev, "Failed to enable supplies: %d\n", ret);
+               goto err_regulator_get;
+       }
+
        ret = wm8731_reset(codec);
        if (ret < 0) {
                dev_err(codec->dev, "Failed to issue reset: %d\n", ret);
-               goto err;
+               goto err_regulator_enable;
        }
 
        wm8731_dai.dev = codec->dev;
@@ -567,7 +595,7 @@ static int wm8731_register(struct wm8731_priv *wm8731,
        ret = snd_soc_register_codec(codec);
        if (ret != 0) {
                dev_err(codec->dev, "Failed to register codec: %d\n", ret);
-               goto err;
+               goto err_regulator_enable;
        }
 
        ret = snd_soc_register_dai(&wm8731_dai);
@@ -581,6 +609,10 @@ static int wm8731_register(struct wm8731_priv *wm8731,
 
 err_codec:
        snd_soc_unregister_codec(codec);
+err_regulator_enable:
+       regulator_bulk_disable(ARRAY_SIZE(wm8731->supplies), wm8731->supplies);
+err_regulator_get:
+       regulator_bulk_free(ARRAY_SIZE(wm8731->supplies), wm8731->supplies);
 err:
        kfree(wm8731);
        return ret;
@@ -591,6 +623,8 @@ static void wm8731_unregister(struct wm8731_priv *wm8731)
        wm8731_set_bias_level(&wm8731->codec, SND_SOC_BIAS_OFF);
        snd_soc_unregister_dai(&wm8731_dai);
        snd_soc_unregister_codec(&wm8731->codec);
+       regulator_bulk_disable(ARRAY_SIZE(wm8731->supplies), wm8731->supplies);
+       regulator_bulk_free(ARRAY_SIZE(wm8731->supplies), wm8731->supplies);
        kfree(wm8731);
        wm8731_codec = NULL;
 }
@@ -623,21 +657,6 @@ static int __devexit wm8731_spi_remove(struct spi_device *spi)
        return 0;
 }
 
-#ifdef CONFIG_PM
-static int wm8731_spi_suspend(struct spi_device *spi, pm_message_t msg)
-{
-       return snd_soc_suspend_device(&spi->dev);
-}
-
-static int wm8731_spi_resume(struct spi_device *spi)
-{
-       return snd_soc_resume_device(&spi->dev);
-}
-#else
-#define wm8731_spi_suspend NULL
-#define wm8731_spi_resume NULL
-#endif
-
 static struct spi_driver wm8731_spi_driver = {
        .driver = {
                .name   = "wm8731",
@@ -645,8 +664,6 @@ static struct spi_driver wm8731_spi_driver = {
                .owner  = THIS_MODULE,
        },
        .probe          = wm8731_spi_probe,
-       .suspend        = wm8731_spi_suspend,
-       .resume         = wm8731_spi_resume,
        .remove         = __devexit_p(wm8731_spi_remove),
 };
 #endif /* CONFIG_SPI_MASTER */
@@ -679,21 +696,6 @@ static __devexit int wm8731_i2c_remove(struct i2c_client *client)
        return 0;
 }
 
-#ifdef CONFIG_PM
-static int wm8731_i2c_suspend(struct i2c_client *i2c, pm_message_t msg)
-{
-       return snd_soc_suspend_device(&i2c->dev);
-}
-
-static int wm8731_i2c_resume(struct i2c_client *i2c)
-{
-       return snd_soc_resume_device(&i2c->dev);
-}
-#else
-#define wm8731_i2c_suspend NULL
-#define wm8731_i2c_resume NULL
-#endif
-
 static const struct i2c_device_id wm8731_i2c_id[] = {
        { "wm8731", 0 },
        { }
@@ -707,8 +709,6 @@ static struct i2c_driver wm8731_i2c_driver = {
        },
        .probe =    wm8731_i2c_probe,
        .remove =   __devexit_p(wm8731_i2c_remove),
-       .suspend =  wm8731_i2c_suspend,
-       .resume =   wm8731_i2c_resume,
        .id_table = wm8731_i2c_id,
 };
 #endif
index 4ba1e7e..475c67a 100644 (file)
@@ -403,7 +403,6 @@ static int wm8750_add_widgets(struct snd_soc_codec *codec)
 
        snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
 
-       snd_soc_dapm_new_widgets(codec);
        return 0;
 }
 
@@ -772,16 +771,8 @@ static int wm8750_init(struct snd_soc_device *socdev,
        snd_soc_add_controls(codec, wm8750_snd_controls,
                                ARRAY_SIZE(wm8750_snd_controls));
        wm8750_add_widgets(codec);
-       ret = snd_soc_init_card(socdev);
-       if (ret < 0) {
-               printk(KERN_ERR "wm8750: failed to register card\n");
-               goto card_err;
-       }
        return ret;
 
-card_err:
-       snd_soc_free_pcms(socdev);
-       snd_soc_dapm_free(socdev);
 err:
        kfree(codec->reg_cache);
        return ret;
index 5ad677c..d6850da 100644 (file)
@@ -673,7 +673,6 @@ static int wm8753_add_widgets(struct snd_soc_codec *codec)
 
        snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
 
-       snd_soc_dapm_new_widgets(codec);
        return 0;
 }
 
@@ -724,8 +723,8 @@ static void pll_factors(struct _pll_div *pll_div, unsigned int target,
        pll_div->k = K;
 }
 
-static int wm8753_set_dai_pll(struct snd_soc_dai *codec_dai,
-               int pll_id, unsigned int freq_in, unsigned int freq_out)
+static int wm8753_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
+               int source, unsigned int freq_in, unsigned int freq_out)
 {
        u16 reg, enable;
        int offset;
@@ -1583,18 +1582,9 @@ static int wm8753_probe(struct platform_device *pdev)
        snd_soc_add_controls(codec, wm8753_snd_controls,
                             ARRAY_SIZE(wm8753_snd_controls));
        wm8753_add_widgets(codec);
-       ret = snd_soc_init_card(socdev);
-       if (ret < 0) {
-               printk(KERN_ERR "wm8753: failed to register card\n");
-               goto card_err;
-       }
 
        return 0;
 
-card_err:
-       snd_soc_free_pcms(socdev);
-       snd_soc_dapm_free(socdev);
-
 pcm_err:
        return ret;
 }
@@ -1767,21 +1757,6 @@ static int wm8753_i2c_remove(struct i2c_client *client)
         return 0;
 }
 
-#ifdef CONFIG_PM
-static int wm8753_i2c_suspend(struct i2c_client *client, pm_message_t msg)
-{
-       return snd_soc_suspend_device(&client->dev);
-}
-
-static int wm8753_i2c_resume(struct i2c_client *client)
-{
-       return snd_soc_resume_device(&client->dev);
-}
-#else
-#define wm8753_i2c_suspend NULL
-#define wm8753_i2c_resume NULL
-#endif
-
 static const struct i2c_device_id wm8753_i2c_id[] = {
        { "wm8753", 0 },
        { }
@@ -1795,8 +1770,6 @@ static struct i2c_driver wm8753_i2c_driver = {
        },
        .probe =    wm8753_i2c_probe,
        .remove =   wm8753_i2c_remove,
-       .suspend =  wm8753_i2c_suspend,
-       .resume =   wm8753_i2c_resume,
        .id_table = wm8753_i2c_id,
 };
 #endif
@@ -1852,22 +1825,6 @@ static int __devexit wm8753_spi_remove(struct spi_device *spi)
        return 0;
 }
 
-#ifdef CONFIG_PM
-static int wm8753_spi_suspend(struct spi_device *spi, pm_message_t msg)
-{
-       return snd_soc_suspend_device(&spi->dev);
-}
-
-static int wm8753_spi_resume(struct spi_device *spi)
-{
-       return snd_soc_resume_device(&spi->dev);
-}
-
-#else
-#define wm8753_spi_suspend NULL
-#define wm8753_spi_resume NULL
-#endif
-
 static struct spi_driver wm8753_spi_driver = {
        .driver = {
                .name   = "wm8753",
@@ -1876,8 +1833,6 @@ static struct spi_driver wm8753_spi_driver = {
        },
        .probe          = wm8753_spi_probe,
        .remove         = __devexit_p(wm8753_spi_remove),
-       .suspend        = wm8753_spi_suspend,
-       .resume         = wm8753_spi_resume,
 };
 #endif
 
index a9829aa..ab2c0da 100644 (file)
@@ -447,17 +447,8 @@ static int wm8776_probe(struct platform_device *pdev)
                                  ARRAY_SIZE(wm8776_dapm_widgets));
        snd_soc_dapm_add_routes(codec, routes, ARRAY_SIZE(routes));
 
-       ret = snd_soc_init_card(socdev);
-       if (ret < 0) {
-               dev_err(codec->dev, "failed to register card: %d\n", ret);
-               goto card_err;
-       }
-
        return ret;
 
-card_err:
-       snd_soc_free_pcms(socdev);
-       snd_soc_dapm_free(socdev);
 pcm_err:
        return ret;
 }
@@ -616,21 +607,6 @@ static int __devexit wm8776_spi_remove(struct spi_device *spi)
        return 0;
 }
 
-#ifdef CONFIG_PM
-static int wm8776_spi_suspend(struct spi_device *spi, pm_message_t msg)
-{
-       return snd_soc_suspend_device(&spi->dev);
-}
-
-static int wm8776_spi_resume(struct spi_device *spi)
-{
-       return snd_soc_resume_device(&spi->dev);
-}
-#else
-#define wm8776_spi_suspend NULL
-#define wm8776_spi_resume NULL
-#endif
-
 static struct spi_driver wm8776_spi_driver = {
        .driver = {
                .name   = "wm8776",
@@ -638,8 +614,6 @@ static struct spi_driver wm8776_spi_driver = {
                .owner  = THIS_MODULE,
        },
        .probe          = wm8776_spi_probe,
-       .suspend        = wm8776_spi_suspend,
-       .resume         = wm8776_spi_resume,
        .remove         = __devexit_p(wm8776_spi_remove),
 };
 #endif /* CONFIG_SPI_MASTER */
@@ -673,21 +647,6 @@ static __devexit int wm8776_i2c_remove(struct i2c_client *client)
        return 0;
 }
 
-#ifdef CONFIG_PM
-static int wm8776_i2c_suspend(struct i2c_client *i2c, pm_message_t msg)
-{
-       return snd_soc_suspend_device(&i2c->dev);
-}
-
-static int wm8776_i2c_resume(struct i2c_client *i2c)
-{
-       return snd_soc_resume_device(&i2c->dev);
-}
-#else
-#define wm8776_i2c_suspend NULL
-#define wm8776_i2c_resume NULL
-#endif
-
 static const struct i2c_device_id wm8776_i2c_id[] = {
        { "wm8776", 0 },
        { }
@@ -701,8 +660,6 @@ static struct i2c_driver wm8776_i2c_driver = {
        },
        .probe =    wm8776_i2c_probe,
        .remove =   __devexit_p(wm8776_i2c_remove),
-       .suspend =  wm8776_i2c_suspend,
-       .resume =   wm8776_i2c_resume,
        .id_table = wm8776_i2c_id,
 };
 #endif
index 5e9c855..c9438dd 100644 (file)
@@ -618,8 +618,6 @@ static int wm8900_add_widgets(struct snd_soc_codec *codec)
 
        snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
 
-       snd_soc_dapm_new_widgets(codec);
-
        return 0;
 }
 
@@ -814,8 +812,8 @@ reenable:
        return 0;
 }
 
-static int wm8900_set_dai_pll(struct snd_soc_dai *codec_dai,
-               int pll_id, unsigned int freq_in, unsigned int freq_out)
+static int wm8900_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
+               int source, unsigned int freq_in, unsigned int freq_out)
 {
        return wm8900_set_fll(codec_dai->codec, pll_id, freq_in, freq_out);
 }
@@ -1312,21 +1310,6 @@ static __devexit int wm8900_i2c_remove(struct i2c_client *client)
        return 0;
 }
 
-#ifdef CONFIG_PM
-static int wm8900_i2c_suspend(struct i2c_client *client, pm_message_t msg)
-{
-       return snd_soc_suspend_device(&client->dev);
-}
-
-static int wm8900_i2c_resume(struct i2c_client *client)
-{
-       return snd_soc_resume_device(&client->dev);
-}
-#else
-#define wm8900_i2c_suspend NULL
-#define wm8900_i2c_resume NULL
-#endif
-
 static const struct i2c_device_id wm8900_i2c_id[] = {
        { "wm8900", 0 },
        { }
@@ -1340,8 +1323,6 @@ static struct i2c_driver wm8900_i2c_driver = {
        },
        .probe = wm8900_i2c_probe,
        .remove = __devexit_p(wm8900_i2c_remove),
-       .suspend = wm8900_i2c_suspend,
-       .resume = wm8900_i2c_resume,
        .id_table = wm8900_i2c_id,
 };
 
@@ -1370,17 +1351,6 @@ static int wm8900_probe(struct platform_device *pdev)
                                ARRAY_SIZE(wm8900_snd_controls));
        wm8900_add_widgets(codec);
 
-       ret = snd_soc_init_card(socdev);
-       if (ret < 0) {
-               dev_err(&pdev->dev, "Failed to register card\n");
-               goto card_err;
-       }
-
-       return ret;
-
-card_err:
-       snd_soc_free_pcms(socdev);
-       snd_soc_dapm_free(socdev);
 pcm_err:
        return ret;
 }
index fe1307b..b8cae17 100644 (file)
@@ -919,8 +919,6 @@ static int wm8903_add_widgets(struct snd_soc_codec *codec)
 
        snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon));
 
-       snd_soc_dapm_new_widgets(codec);
-
        return 0;
 }
 
@@ -1655,21 +1653,6 @@ static __devexit int wm8903_i2c_remove(struct i2c_client *client)
        return 0;
 }
 
-#ifdef CONFIG_PM
-static int wm8903_i2c_suspend(struct i2c_client *client, pm_message_t msg)
-{
-       return snd_soc_suspend_device(&client->dev);
-}
-
-static int wm8903_i2c_resume(struct i2c_client *client)
-{
-       return snd_soc_resume_device(&client->dev);
-}
-#else
-#define wm8903_i2c_suspend NULL
-#define wm8903_i2c_resume NULL
-#endif
-
 /* i2c codec control layer */
 static const struct i2c_device_id wm8903_i2c_id[] = {
        { "wm8903", 0 },
@@ -1684,8 +1667,6 @@ static struct i2c_driver wm8903_i2c_driver = {
        },
        .probe    = wm8903_i2c_probe,
        .remove   = __devexit_p(wm8903_i2c_remove),
-       .suspend  = wm8903_i2c_suspend,
-       .resume   = wm8903_i2c_resume,
        .id_table = wm8903_i2c_id,
 };
 
@@ -1712,17 +1693,8 @@ static int wm8903_probe(struct platform_device *pdev)
                                ARRAY_SIZE(wm8903_snd_controls));
        wm8903_add_widgets(socdev->card->codec);
 
-       ret = snd_soc_init_card(socdev);
-       if (ret < 0) {
-               dev_err(&pdev->dev, "wm8903: failed to register card\n");
-               goto card_err;
-       }
-
        return ret;
 
-card_err:
-       snd_soc_free_pcms(socdev);
-       snd_soc_dapm_free(socdev);
 err:
        return ret;
 }
index 1ef2454..3d850b9 100644 (file)
@@ -298,7 +298,6 @@ static int wm8940_add_widgets(struct snd_soc_codec *codec)
        ret = snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
        if (ret)
                goto error_ret;
-       ret = snd_soc_dapm_new_widgets(codec);
 
 error_ret:
        return ret;
@@ -536,8 +535,8 @@ static void pll_factors(unsigned int target, unsigned int source)
 }
 
 /* Untested at the moment */
-static int wm8940_set_dai_pll(struct snd_soc_dai *codec_dai,
-               int pll_id, unsigned int freq_in, unsigned int freq_out)
+static int wm8940_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
+               int source, unsigned int freq_in, unsigned int freq_out)
 {
        struct snd_soc_codec *codec = codec_dai->codec;
        u16 reg;
@@ -731,12 +730,6 @@ static int wm8940_probe(struct platform_device *pdev)
        if (ret)
                goto error_free_pcms;
 
-       ret = snd_soc_init_card(socdev);
-       if (ret < 0) {
-               dev_err(codec->dev, "failed to register card: %d\n", ret);
-               goto error_free_pcms;
-       }
-
        return ret;
 
 error_free_pcms:
@@ -877,21 +870,6 @@ static int __devexit wm8940_i2c_remove(struct i2c_client *client)
        return 0;
 }
 
-#ifdef CONFIG_PM
-static int wm8940_i2c_suspend(struct i2c_client *client, pm_message_t msg)
-{
-       return snd_soc_suspend_device(&client->dev);
-}
-
-static int wm8940_i2c_resume(struct i2c_client *client)
-{
-       return snd_soc_resume_device(&client->dev);
-}
-#else
-#define wm8940_i2c_suspend NULL
-#define wm8940_i2c_resume NULL
-#endif
-
 static const struct i2c_device_id wm8940_i2c_id[] = {
        { "wm8940", 0 },
        { }
@@ -905,8 +883,6 @@ static struct i2c_driver wm8940_i2c_driver = {
        },
        .probe = wm8940_i2c_probe,
        .remove = __devexit_p(wm8940_i2c_remove),
-       .suspend = wm8940_i2c_suspend,
-       .resume = wm8940_i2c_resume,
        .id_table = wm8940_i2c_id,
 };
 
index f59703b..d07bcc1 100644 (file)
@@ -307,7 +307,6 @@ static int wm8960_add_widgets(struct snd_soc_codec *codec)
 
        snd_soc_dapm_add_routes(codec, audio_paths, ARRAY_SIZE(audio_paths));
 
-       snd_soc_dapm_new_widgets(codec);
        return 0;
 }
 
@@ -540,8 +539,8 @@ static int pll_factors(unsigned int source, unsigned int target,
        return 0;
 }
 
-static int wm8960_set_dai_pll(struct snd_soc_dai *codec_dai,
-               int pll_id, unsigned int freq_in, unsigned int freq_out)
+static int wm8960_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
+               int source, unsigned int freq_in, unsigned int freq_out)
 {
        struct snd_soc_codec *codec = codec_dai->codec;
        u16 reg;
@@ -713,17 +712,9 @@ static int wm8960_probe(struct platform_device *pdev)
        snd_soc_add_controls(codec, wm8960_snd_controls,
                             ARRAY_SIZE(wm8960_snd_controls));
        wm8960_add_widgets(codec);
-       ret = snd_soc_init_card(socdev);
-       if (ret < 0) {
-               dev_err(codec->dev, "failed to register card: %d\n", ret);
-               goto card_err;
-       }
 
        return ret;
 
-card_err:
-       snd_soc_free_pcms(socdev);
-       snd_soc_dapm_free(socdev);
 pcm_err:
        return ret;
 }
@@ -883,21 +874,6 @@ static __devexit int wm8960_i2c_remove(struct i2c_client *client)
        return 0;
 }
 
-#ifdef CONFIG_PM
-static int wm8960_i2c_suspend(struct i2c_client *client, pm_message_t msg)
-{
-       return snd_soc_suspend_device(&client->dev);
-}
-
-static int wm8960_i2c_resume(struct i2c_client *client)
-{
-       return snd_soc_resume_device(&client->dev);
-}
-#else
-#define wm8960_i2c_suspend NULL
-#define wm8960_i2c_resume NULL
-#endif
-
 static const struct i2c_device_id wm8960_i2c_id[] = {
        { "wm8960", 0 },
        { }
@@ -911,8 +887,6 @@ static struct i2c_driver wm8960_i2c_driver = {
        },
        .probe =    wm8960_i2c_probe,
        .remove =   __devexit_p(wm8960_i2c_remove),
-       .suspend =  wm8960_i2c_suspend,
-       .resume =   wm8960_i2c_resume,
        .id_table = wm8960_i2c_id,
 };
 
index 5030320..a8007d5 100644 (file)
@@ -986,19 +986,9 @@ static int wm8961_probe(struct platform_device *pdev)
        snd_soc_dapm_new_controls(codec, wm8961_dapm_widgets,
                                  ARRAY_SIZE(wm8961_dapm_widgets));
        snd_soc_dapm_add_routes(codec, audio_paths, ARRAY_SIZE(audio_paths));
-       snd_soc_dapm_new_widgets(codec);
-
-       ret = snd_soc_init_card(socdev);
-       if (ret < 0) {
-               dev_err(codec->dev, "failed to register card: %d\n", ret);
-               goto card_err;
-       }
 
        return ret;
 
-card_err:
-       snd_soc_free_pcms(socdev);
-       snd_soc_dapm_free(socdev);
 pcm_err:
        return ret;
 }
@@ -1206,21 +1196,6 @@ static __devexit int wm8961_i2c_remove(struct i2c_client *client)
        return 0;
 }
 
-#ifdef CONFIG_PM
-static int wm8961_i2c_suspend(struct i2c_client *client, pm_message_t state)
-{
-       return snd_soc_suspend_device(&client->dev);
-}
-
-static int wm8961_i2c_resume(struct i2c_client *client)
-{
-       return snd_soc_resume_device(&client->dev);
-}
-#else
-#define wm8961_i2c_suspend NULL
-#define wm8961_i2c_resume NULL
-#endif
-
 static const struct i2c_device_id wm8961_i2c_id[] = {
        { "wm8961", 0 },
        { }
@@ -1234,8 +1209,6 @@ static struct i2c_driver wm8961_i2c_driver = {
        },
        .probe =    wm8961_i2c_probe,
        .remove =   __devexit_p(wm8961_i2c_remove),
-       .suspend =  wm8961_i2c_suspend,
-       .resume =   wm8961_i2c_resume,
        .id_table = wm8961_i2c_id,
 };
 
index d66efb0..d9540d5 100644 (file)
@@ -338,8 +338,6 @@ static int wm8971_add_widgets(struct snd_soc_codec *codec)
 
        snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
 
-       snd_soc_dapm_new_widgets(codec);
-
        return 0;
 }
 
@@ -703,16 +701,9 @@ static int wm8971_init(struct snd_soc_device *socdev,
        snd_soc_add_controls(codec, wm8971_snd_controls,
                                ARRAY_SIZE(wm8971_snd_controls));
        wm8971_add_widgets(codec);
-       ret = snd_soc_init_card(socdev);
-       if (ret < 0) {
-               printk(KERN_ERR "wm8971: failed to register card\n");
-               goto card_err;
-       }
+
        return ret;
 
-card_err:
-       snd_soc_free_pcms(socdev);
-       snd_soc_dapm_free(socdev);
 err:
        kfree(codec->reg_cache);
        return ret;
index 98d663a..81c57b5 100644 (file)
@@ -276,41 +276,42 @@ static int wm8974_add_widgets(struct snd_soc_codec *codec)
 
        snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
 
-       snd_soc_dapm_new_widgets(codec);
        return 0;
 }
 
 struct pll_ {
-       unsigned int pre_div:4; /* prescale - 1 */
+       unsigned int pre_div:1;
        unsigned int n:4;
        unsigned int k;
 };
 
-static struct pll_ pll_div;
-
 /* The size in bits of the pll divide multiplied by 10
  * to allow rounding later */
 #define FIXED_PLL_SIZE ((1 << 24) * 10)
 
-static void pll_factors(unsigned int target, unsigned int source)
+static void pll_factors(struct pll_ *pll_div,
+                       unsigned int target, unsigned int source)
 {
        unsigned long long Kpart;
        unsigned int K, Ndiv, Nmod;
 
+       /* There is a fixed divide by 4 in the output path */
+       target *= 4;
+
        Ndiv = target / source;
        if (Ndiv < 6) {
-               source >>= 1;
-               pll_div.pre_div = 1;
+               source /= 2;
+               pll_div->pre_div = 1;
                Ndiv = target / source;
        } else
-               pll_div.pre_div = 0;
+               pll_div->pre_div = 0;
 
        if ((Ndiv < 6) || (Ndiv > 12))
                printk(KERN_WARNING
                        "WM8974 N value %u outwith recommended range!\n",
                        Ndiv);
 
-       pll_div.n = Ndiv;
+       pll_div->n = Ndiv;
        Nmod = target % source;
        Kpart = FIXED_PLL_SIZE * (long long)Nmod;
 
@@ -325,13 +326,14 @@ static void pll_factors(unsigned int target, unsigned int source)
        /* Move down to proper range now rounding is done */
        K /= 10;
 
-       pll_div.k = K;
+       pll_div->k = K;
 }
 
-static int wm8974_set_dai_pll(struct snd_soc_dai *codec_dai,
-               int pll_id, unsigned int freq_in, unsigned int freq_out)
+static int wm8974_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
+               int source, unsigned int freq_in, unsigned int freq_out)
 {
        struct snd_soc_codec *codec = codec_dai->codec;
+       struct pll_ pll_div;
        u16 reg;
 
        if (freq_in == 0 || freq_out == 0) {
@@ -345,7 +347,7 @@ static int wm8974_set_dai_pll(struct snd_soc_dai *codec_dai,
                return 0;
        }
 
-       pll_factors(freq_out*4, freq_in);
+       pll_factors(&pll_div, freq_out, freq_in);
 
        snd_soc_write(codec, WM8974_PLLN, (pll_div.pre_div << 4) | pll_div.n);
        snd_soc_write(codec, WM8974_PLLK1, pll_div.k >> 18);
@@ -638,17 +640,9 @@ static int wm8974_probe(struct platform_device *pdev)
        snd_soc_add_controls(codec, wm8974_snd_controls,
                             ARRAY_SIZE(wm8974_snd_controls));
        wm8974_add_widgets(codec);
-       ret = snd_soc_init_card(socdev);
-       if (ret < 0) {
-               dev_err(codec->dev, "failed to register card: %d\n", ret);
-               goto card_err;
-       }
 
        return ret;
 
-card_err:
-       snd_soc_free_pcms(socdev);
-       snd_soc_dapm_free(socdev);
 pcm_err:
        return ret;
 }
index 3f530f8..2862e4d 100644 (file)
@@ -790,19 +790,9 @@ static int wm8988_probe(struct platform_device *pdev)
        snd_soc_dapm_new_controls(codec, wm8988_dapm_widgets,
                                  ARRAY_SIZE(wm8988_dapm_widgets));
        snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
-       snd_soc_dapm_new_widgets(codec);
-
-       ret = snd_soc_init_card(socdev);
-       if (ret < 0) {
-               dev_err(codec->dev, "failed to register card: %d\n", ret);
-               goto card_err;
-       }
 
        return ret;
 
-card_err:
-       snd_soc_free_pcms(socdev);
-       snd_soc_dapm_free(socdev);
 pcm_err:
        return ret;
 }
@@ -944,21 +934,6 @@ static int wm8988_i2c_remove(struct i2c_client *client)
        return 0;
 }
 
-#ifdef CONFIG_PM
-static int wm8988_i2c_suspend(struct i2c_client *client, pm_message_t msg)
-{
-       return snd_soc_suspend_device(&client->dev);
-}
-
-static int wm8988_i2c_resume(struct i2c_client *client)
-{
-       return snd_soc_resume_device(&client->dev);
-}
-#else
-#define wm8988_i2c_suspend NULL
-#define wm8988_i2c_resume NULL
-#endif
-
 static const struct i2c_device_id wm8988_i2c_id[] = {
        { "wm8988", 0 },
        { }
@@ -972,8 +947,6 @@ static struct i2c_driver wm8988_i2c_driver = {
        },
        .probe = wm8988_i2c_probe,
        .remove = wm8988_i2c_remove,
-       .suspend = wm8988_i2c_suspend,
-       .resume = wm8988_i2c_resume,
        .id_table = wm8988_i2c_id,
 };
 #endif
@@ -1006,21 +979,6 @@ static int __devexit wm8988_spi_remove(struct spi_device *spi)
        return 0;
 }
 
-#ifdef CONFIG_PM
-static int wm8988_spi_suspend(struct spi_device *spi, pm_message_t msg)
-{
-       return snd_soc_suspend_device(&spi->dev);
-}
-
-static int wm8988_spi_resume(struct spi_device *spi)
-{
-       return snd_soc_resume_device(&spi->dev);
-}
-#else
-#define wm8988_spi_suspend NULL
-#define wm8988_spi_resume NULL
-#endif
-
 static struct spi_driver wm8988_spi_driver = {
        .driver = {
                .name   = "wm8988",
@@ -1029,8 +987,6 @@ static struct spi_driver wm8988_spi_driver = {
        },
        .probe          = wm8988_spi_probe,
        .remove         = __devexit_p(wm8988_spi_remove),
-       .suspend        = wm8988_spi_suspend,
-       .resume         = wm8988_spi_resume,
 };
 #endif
 
index 2d702db..341481e 100644 (file)
@@ -920,7 +920,6 @@ static int wm8990_add_widgets(struct snd_soc_codec *codec)
        /* set up the WM8990 audio map */
        snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
 
-       snd_soc_dapm_new_widgets(codec);
        return 0;
 }
 
@@ -972,8 +971,8 @@ static void pll_factors(struct _pll_div *pll_div, unsigned int target,
        pll_div->k = K;
 }
 
-static int wm8990_set_dai_pll(struct snd_soc_dai *codec_dai,
-               int pll_id, unsigned int freq_in, unsigned int freq_out)
+static int wm8990_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
+               int source, unsigned int freq_in, unsigned int freq_out)
 {
        u16 reg;
        struct snd_soc_codec *codec = codec_dai->codec;
@@ -1409,16 +1408,9 @@ static int wm8990_init(struct snd_soc_device *socdev)
        snd_soc_add_controls(codec, wm8990_snd_controls,
                                ARRAY_SIZE(wm8990_snd_controls));
        wm8990_add_widgets(codec);
-       ret = snd_soc_init_card(socdev);
-       if (ret < 0) {
-               printk(KERN_ERR "wm8990: failed to register card\n");
-               goto card_err;
-       }
+
        return ret;
 
-card_err:
-       snd_soc_free_pcms(socdev);
-       snd_soc_dapm_free(socdev);
 pcm_err:
        kfree(codec->reg_cache);
        return ret;
index d998799..5e32f2e 100644 (file)
@@ -422,7 +422,7 @@ static int fll_factors(struct _fll_div *fll_div, unsigned int Fref,
        return 0;
 }
 
-static int wm8993_set_fll(struct snd_soc_dai *dai, int fll_id,
+static int wm8993_set_fll(struct snd_soc_dai *dai, int fll_id, int source,
                          unsigned int Fref, unsigned int Fout)
 {
        struct snd_soc_codec *codec = dai->codec;
@@ -1464,19 +1464,8 @@ static int wm8993_probe(struct platform_device *pdev)
        wm_hubs_add_analogue_routes(codec, wm8993->pdata.lineout1_diff,
                                    wm8993->pdata.lineout2_diff);
 
-       snd_soc_dapm_new_widgets(codec);
-
-       ret = snd_soc_init_card(socdev);
-       if (ret < 0) {
-               dev_err(codec->dev, "failed to register card\n");
-               goto card_err;
-       }
-
        return ret;
 
-card_err:
-       snd_soc_free_pcms(socdev);
-       snd_soc_dapm_free(socdev);
 err:
        return ret;
 }
@@ -1572,33 +1561,15 @@ static int wm8993_i2c_probe(struct i2c_client *i2c,
        /* Use automatic clock configuration */
        snd_soc_update_bits(codec, WM8993_CLOCKING_4, WM8993_SR_MODE, 0);
 
-       if (!wm8993->pdata.lineout1_diff)
-               snd_soc_update_bits(codec, WM8993_LINE_MIXER1,
-                                   WM8993_LINEOUT1_MODE,
-                                   WM8993_LINEOUT1_MODE);
-       if (!wm8993->pdata.lineout2_diff)
-               snd_soc_update_bits(codec, WM8993_LINE_MIXER2,
-                                   WM8993_LINEOUT2_MODE,
-                                   WM8993_LINEOUT2_MODE);
-
-       if (wm8993->pdata.lineout1fb)
-               snd_soc_update_bits(codec, WM8993_ADDITIONAL_CONTROL,
-                                   WM8993_LINEOUT1_FB, WM8993_LINEOUT1_FB);
-
-       if (wm8993->pdata.lineout2fb)
-               snd_soc_update_bits(codec, WM8993_ADDITIONAL_CONTROL,
-                                   WM8993_LINEOUT2_FB, WM8993_LINEOUT2_FB);
-
-       /* Apply the microphone bias/detection configuration - the
-        * platform data is directly applicable to the register. */
-       snd_soc_update_bits(codec, WM8993_MICBIAS,
-                           WM8993_JD_SCTHR_MASK | WM8993_JD_THR_MASK |
-                           WM8993_MICB1_LVL | WM8993_MICB2_LVL,
-                           wm8993->pdata.jd_scthr << WM8993_JD_SCTHR_SHIFT |
-                           wm8993->pdata.jd_thr << WM8993_JD_THR_SHIFT |
-                           wm8993->pdata.micbias1_lvl |
-                           wm8993->pdata.micbias1_lvl << 1);
-
+       wm_hubs_handle_analogue_pdata(codec, wm8993->pdata.lineout1_diff,
+                                     wm8993->pdata.lineout2_diff,
+                                     wm8993->pdata.lineout1fb,
+                                     wm8993->pdata.lineout2fb,
+                                     wm8993->pdata.jd_scthr,
+                                     wm8993->pdata.jd_thr,
+                                     wm8993->pdata.micbias1_lvl,
+                                     wm8993->pdata.micbias2_lvl);
+                            
        ret = wm8993_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
        if (ret != 0)
                goto err;
index 686e5aa..c468497 100644 (file)
@@ -1262,19 +1262,9 @@ static int wm9081_probe(struct platform_device *pdev)
        snd_soc_dapm_new_controls(codec, wm9081_dapm_widgets,
                                  ARRAY_SIZE(wm9081_dapm_widgets));
        snd_soc_dapm_add_routes(codec, audio_paths, ARRAY_SIZE(audio_paths));
-       snd_soc_dapm_new_widgets(codec);
-
-       ret = snd_soc_init_card(socdev);
-       if (ret < 0) {
-               dev_err(codec->dev, "failed to register card: %d\n", ret);
-               goto card_err;
-       }
 
        return ret;
 
-card_err:
-       snd_soc_free_pcms(socdev);
-       snd_soc_dapm_free(socdev);
 pcm_err:
        return ret;
 }
@@ -1452,21 +1442,6 @@ static __devexit int wm9081_i2c_remove(struct i2c_client *client)
        return 0;
 }
 
-#ifdef CONFIG_PM
-static int wm9081_i2c_suspend(struct i2c_client *client, pm_message_t msg)
-{
-       return snd_soc_suspend_device(&client->dev);
-}
-
-static int wm9081_i2c_resume(struct i2c_client *client)
-{
-       return snd_soc_resume_device(&client->dev);
-}
-#else
-#define wm9081_i2c_suspend NULL
-#define wm9081_i2c_resume NULL
-#endif
-
 static const struct i2c_device_id wm9081_i2c_id[] = {
        { "wm9081", 0 },
        { }
@@ -1480,8 +1455,6 @@ static struct i2c_driver wm9081_i2c_driver = {
        },
        .probe =    wm9081_i2c_probe,
        .remove =   __devexit_p(wm9081_i2c_remove),
-       .suspend =  wm9081_i2c_suspend,
-       .resume =   wm9081_i2c_resume,
        .id_table = wm9081_i2c_id,
 };
 
index e7d2840..ec54c6d 100644 (file)
@@ -205,7 +205,6 @@ static int wm9705_add_widgets(struct snd_soc_codec *codec)
        snd_soc_dapm_new_controls(codec, wm9705_dapm_widgets,
                                        ARRAY_SIZE(wm9705_dapm_widgets));
        snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
-       snd_soc_dapm_new_widgets(codec);
 
        return 0;
 }
@@ -403,12 +402,6 @@ static int wm9705_soc_probe(struct platform_device *pdev)
                                ARRAY_SIZE(wm9705_snd_ac97_controls));
        wm9705_add_widgets(codec);
 
-       ret = snd_soc_init_card(socdev);
-       if (ret < 0) {
-               printk(KERN_ERR "wm9705: failed to register card\n");
-               goto reset_err;
-       }
-
        return 0;
 
 reset_err:
index 1fd4e88..0ac1215 100644 (file)
@@ -436,7 +436,6 @@ static int wm9712_add_widgets(struct snd_soc_codec *codec)
 
        snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
 
-       snd_soc_dapm_new_widgets(codec);
        return 0;
 }
 
@@ -695,17 +694,11 @@ static int wm9712_soc_probe(struct platform_device *pdev)
        snd_soc_add_controls(codec, wm9712_snd_ac97_controls,
                                ARRAY_SIZE(wm9712_snd_ac97_controls));
        wm9712_add_widgets(codec);
-       ret = snd_soc_init_card(socdev);
-       if (ret < 0) {
-               printk(KERN_ERR "wm9712: failed to register card\n");
-               goto reset_err;
-       }
 
        return 0;
 
 reset_err:
        snd_soc_free_pcms(socdev);
-
 pcm_err:
        snd_soc_free_ac97_codec(codec);
 
index abed37a..c58aab3 100644 (file)
@@ -165,9 +165,9 @@ SOC_SINGLE("Mono Playback Switch", AC97_MASTER_TONE, 7, 1, 1),
 SOC_SINGLE("Mono Playback ZC Switch", AC97_MASTER_TONE, 6, 1, 0),
 SOC_SINGLE("Mono Playback Volume", AC97_MASTER_TONE, 0, 31, 1),
 
-SOC_SINGLE("PC Beep Playback Headphone Volume", AC97_AUX, 12, 7, 1),
-SOC_SINGLE("PC Beep Playback Speaker Volume", AC97_AUX, 8, 7, 1),
-SOC_SINGLE("PC Beep Playback Mono Volume", AC97_AUX, 4, 7, 1),
+SOC_SINGLE("Beep Playback Headphone Volume", AC97_AUX, 12, 7, 1),
+SOC_SINGLE("Beep Playback Speaker Volume", AC97_AUX, 8, 7, 1),
+SOC_SINGLE("Beep Playback Mono Volume", AC97_AUX, 4, 7, 1),
 
 SOC_SINGLE("Voice Playback Headphone Volume", AC97_PCM, 12, 7, 1),
 SOC_SINGLE("Voice Playback Master Volume", AC97_PCM, 8, 7, 1),
@@ -266,7 +266,7 @@ static int mixer_event(struct snd_soc_dapm_widget *w,
 
 /* Left Headphone Mixers */
 static const struct snd_kcontrol_new wm9713_hpl_mixer_controls[] = {
-SOC_DAPM_SINGLE("PC Beep Playback Switch", HPL_MIXER, 5, 1, 0),
+SOC_DAPM_SINGLE("Beep Playback Switch", HPL_MIXER, 5, 1, 0),
 SOC_DAPM_SINGLE("Voice Playback Switch", HPL_MIXER, 4, 1, 0),
 SOC_DAPM_SINGLE("Aux Playback Switch", HPL_MIXER, 3, 1, 0),
 SOC_DAPM_SINGLE("PCM Playback Switch", HPL_MIXER, 2, 1, 0),
@@ -276,7 +276,7 @@ SOC_DAPM_SINGLE("Bypass Playback Switch", HPL_MIXER, 0, 1, 0),
 
 /* Right Headphone Mixers */
 static const struct snd_kcontrol_new wm9713_hpr_mixer_controls[] = {
-SOC_DAPM_SINGLE("PC Beep Playback Switch", HPR_MIXER, 5, 1, 0),
+SOC_DAPM_SINGLE("Beep Playback Switch", HPR_MIXER, 5, 1, 0),
 SOC_DAPM_SINGLE("Voice Playback Switch", HPR_MIXER, 4, 1, 0),
 SOC_DAPM_SINGLE("Aux Playback Switch", HPR_MIXER, 3, 1, 0),
 SOC_DAPM_SINGLE("PCM Playback Switch", HPR_MIXER, 2, 1, 0),
@@ -294,7 +294,7 @@ SOC_DAPM_ENUM("Route", wm9713_enum[0]);
 
 /* Speaker Mixer */
 static const struct snd_kcontrol_new wm9713_speaker_mixer_controls[] = {
-SOC_DAPM_SINGLE("PC Beep Playback Switch", AC97_AUX, 11, 1, 1),
+SOC_DAPM_SINGLE("Beep Playback Switch", AC97_AUX, 11, 1, 1),
 SOC_DAPM_SINGLE("Voice Playback Switch", AC97_PCM, 11, 1, 1),
 SOC_DAPM_SINGLE("Aux Playback Switch", AC97_REC_SEL, 11, 1, 1),
 SOC_DAPM_SINGLE("PCM Playback Switch", AC97_PHONE, 14, 1, 1),
@@ -304,7 +304,7 @@ SOC_DAPM_SINGLE("Bypass Playback Switch", AC97_PC_BEEP, 14, 1, 1),
 
 /* Mono Mixer */
 static const struct snd_kcontrol_new wm9713_mono_mixer_controls[] = {
-SOC_DAPM_SINGLE("PC Beep Playback Switch", AC97_AUX, 7, 1, 1),
+SOC_DAPM_SINGLE("Beep Playback Switch", AC97_AUX, 7, 1, 1),
 SOC_DAPM_SINGLE("Voice Playback Switch", AC97_PCM, 7, 1, 1),
 SOC_DAPM_SINGLE("Aux Playback Switch", AC97_REC_SEL, 7, 1, 1),
 SOC_DAPM_SINGLE("PCM Playback Switch", AC97_PHONE, 13, 1, 1),
@@ -463,7 +463,7 @@ SND_SOC_DAPM_VMID("VMID"),
 
 static const struct snd_soc_dapm_route audio_map[] = {
        /* left HP mixer */
-       {"Left HP Mixer", "PC Beep Playback Switch", "PCBEEP"},
+       {"Left HP Mixer", "Beep Playback Switch",    "PCBEEP"},
        {"Left HP Mixer", "Voice Playback Switch",   "Voice DAC"},
        {"Left HP Mixer", "Aux Playback Switch",     "Aux DAC"},
        {"Left HP Mixer", "Bypass Playback Switch",  "Left Line In"},
@@ -472,7 +472,7 @@ static const struct snd_soc_dapm_route audio_map[] = {
        {"Left HP Mixer", NULL,  "Capture Headphone Mux"},
 
        /* right HP mixer */
-       {"Right HP Mixer", "PC Beep Playback Switch", "PCBEEP"},
+       {"Right HP Mixer", "Beep Playback Switch",    "PCBEEP"},
        {"Right HP Mixer", "Voice Playback Switch",   "Voice DAC"},
        {"Right HP Mixer", "Aux Playback Switch",     "Aux DAC"},
        {"Right HP Mixer", "Bypass Playback Switch",  "Right Line In"},
@@ -491,7 +491,7 @@ static const struct snd_soc_dapm_route audio_map[] = {
        {"Capture Mixer", NULL, "Right Capture Source"},
 
        /* speaker mixer */
-       {"Speaker Mixer", "PC Beep Playback Switch", "PCBEEP"},
+       {"Speaker Mixer", "Beep Playback Switch",    "PCBEEP"},
        {"Speaker Mixer", "Voice Playback Switch",   "Voice DAC"},
        {"Speaker Mixer", "Aux Playback Switch",     "Aux DAC"},
        {"Speaker Mixer", "Bypass Playback Switch",  "Line Mixer"},
@@ -499,7 +499,7 @@ static const struct snd_soc_dapm_route audio_map[] = {
        {"Speaker Mixer", "MonoIn Playback Switch",  "Mono In"},
 
        /* mono mixer */
-       {"Mono Mixer", "PC Beep Playback Switch", "PCBEEP"},
+       {"Mono Mixer", "Beep Playback Switch",    "PCBEEP"},
        {"Mono Mixer", "Voice Playback Switch",   "Voice DAC"},
        {"Mono Mixer", "Aux Playback Switch",     "Aux DAC"},
        {"Mono Mixer", "Bypass Playback Switch",  "Line Mixer"},
@@ -625,7 +625,6 @@ static int wm9713_add_widgets(struct snd_soc_codec *codec)
 
        snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
 
-       snd_soc_dapm_new_widgets(codec);
        return 0;
 }
 
@@ -800,8 +799,8 @@ static int wm9713_set_pll(struct snd_soc_codec *codec,
        return 0;
 }
 
-static int wm9713_set_dai_pll(struct snd_soc_dai *codec_dai,
-               int pll_id, unsigned int freq_in, unsigned int freq_out)
+static int wm9713_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
+               int source, unsigned int freq_in, unsigned int freq_out)
 {
        struct snd_soc_codec *codec = codec_dai->codec;
        return wm9713_set_pll(codec, pll_id, freq_in, freq_out);
@@ -1247,14 +1246,11 @@ static int wm9713_soc_probe(struct platform_device *pdev)
        snd_soc_add_controls(codec, wm9713_snd_ac97_controls,
                                ARRAY_SIZE(wm9713_snd_ac97_controls));
        wm9713_add_widgets(codec);
-       ret = snd_soc_init_card(socdev);
-       if (ret < 0)
-               goto reset_err;
+
        return 0;
 
 reset_err:
        snd_soc_free_pcms(socdev);
-
 pcm_err:
        snd_soc_free_ac97_codec(codec);
 
index e542027..d73c305 100644 (file)
@@ -438,11 +438,11 @@ static const struct snd_soc_dapm_widget analogue_dapm_widgets[] = {
 SND_SOC_DAPM_INPUT("IN1LN"),
 SND_SOC_DAPM_INPUT("IN1LP"),
 SND_SOC_DAPM_INPUT("IN2LN"),
-SND_SOC_DAPM_INPUT("IN2LP/VXRN"),
+SND_SOC_DAPM_INPUT("IN2LP:VXRN"),
 SND_SOC_DAPM_INPUT("IN1RN"),
 SND_SOC_DAPM_INPUT("IN1RP"),
 SND_SOC_DAPM_INPUT("IN2RN"),
-SND_SOC_DAPM_INPUT("IN2RP/VXRP"),
+SND_SOC_DAPM_INPUT("IN2RP:VXRP"),
 
 SND_SOC_DAPM_MICBIAS("MICBIAS2", WM8993_POWER_MANAGEMENT_1, 5, 0),
 SND_SOC_DAPM_MICBIAS("MICBIAS1", WM8993_POWER_MANAGEMENT_1, 4, 0),
@@ -537,14 +537,14 @@ static const struct snd_soc_dapm_route analogue_routes[] = {
        { "IN1R PGA", "IN1RP Switch", "IN1RP" },
        { "IN1R PGA", "IN1RN Switch", "IN1RN" },
 
-       { "IN2L PGA", "IN2LP Switch", "IN2LP/VXRN" },
+       { "IN2L PGA", "IN2LP Switch", "IN2LP:VXRN" },
        { "IN2L PGA", "IN2LN Switch", "IN2LN" },
 
-       { "IN2R PGA", "IN2RP Switch", "IN2RP/VXRP" },
+       { "IN2R PGA", "IN2RP Switch", "IN2RP:VXRP" },
        { "IN2R PGA", "IN2RN Switch", "IN2RN" },
 
-       { "Direct Voice", NULL, "IN2LP/VXRN" },
-       { "Direct Voice", NULL, "IN2RP/VXRP" },
+       { "Direct Voice", NULL, "IN2LP:VXRN" },
+       { "Direct Voice", NULL, "IN2RP:VXRP" },
 
        { "MIXINL", "IN1L Switch", "IN1L PGA" },
        { "MIXINL", "IN2L Switch", "IN2L PGA" },
@@ -565,7 +565,7 @@ static const struct snd_soc_dapm_route analogue_routes[] = {
        { "Left Output Mixer", "Right Input Switch", "MIXINR" },
        { "Left Output Mixer", "IN2RN Switch", "IN2RN" },
        { "Left Output Mixer", "IN2LN Switch", "IN2LN" },
-       { "Left Output Mixer", "IN2LP Switch", "IN2LP/VXRN" },
+       { "Left Output Mixer", "IN2LP Switch", "IN2LP:VXRN" },
        { "Left Output Mixer", "IN1L Switch", "IN1L PGA" },
        { "Left Output Mixer", "IN1R Switch", "IN1R PGA" },
 
@@ -573,7 +573,7 @@ static const struct snd_soc_dapm_route analogue_routes[] = {
        { "Right Output Mixer", "Right Input Switch", "MIXINR" },
        { "Right Output Mixer", "IN2LN Switch", "IN2LN" },
        { "Right Output Mixer", "IN2RN Switch", "IN2RN" },
-       { "Right Output Mixer", "IN2RP Switch", "IN2RP/VXRP" },
+       { "Right Output Mixer", "IN2RP Switch", "IN2RP:VXRP" },
        { "Right Output Mixer", "IN1L Switch", "IN1L PGA" },
        { "Right Output Mixer", "IN1R Switch", "IN1R PGA" },
 
@@ -738,6 +738,41 @@ int wm_hubs_add_analogue_routes(struct snd_soc_codec *codec,
 }
 EXPORT_SYMBOL_GPL(wm_hubs_add_analogue_routes);
 
+int wm_hubs_handle_analogue_pdata(struct snd_soc_codec *codec,
+                                 int lineout1_diff, int lineout2_diff,
+                                 int lineout1fb, int lineout2fb,
+                                 int jd_scthr, int jd_thr, int micbias1_lvl,
+                                 int micbias2_lvl)
+{
+       if (!lineout1_diff)
+               snd_soc_update_bits(codec, WM8993_LINE_MIXER1,
+                                   WM8993_LINEOUT1_MODE,
+                                   WM8993_LINEOUT1_MODE);
+       if (!lineout2_diff)
+               snd_soc_update_bits(codec, WM8993_LINE_MIXER2,
+                                   WM8993_LINEOUT2_MODE,
+                                   WM8993_LINEOUT2_MODE);
+
+       if (lineout1fb)
+               snd_soc_update_bits(codec, WM8993_ADDITIONAL_CONTROL,
+                                   WM8993_LINEOUT1_FB, WM8993_LINEOUT1_FB);
+
+       if (lineout2fb)
+               snd_soc_update_bits(codec, WM8993_ADDITIONAL_CONTROL,
+                                   WM8993_LINEOUT2_FB, WM8993_LINEOUT2_FB);
+
+       snd_soc_update_bits(codec, WM8993_MICBIAS,
+                           WM8993_JD_SCTHR_MASK | WM8993_JD_THR_MASK |
+                           WM8993_MICB1_LVL | WM8993_MICB2_LVL,
+                           jd_scthr << WM8993_JD_SCTHR_SHIFT |
+                           jd_thr << WM8993_JD_THR_SHIFT |
+                           micbias1_lvl |
+                           micbias2_lvl << WM8993_MICB2_LVL_SHIFT);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(wm_hubs_handle_analogue_pdata);
+
 MODULE_DESCRIPTION("Shared support for Wolfson hubs products");
 MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
 MODULE_LICENSE("GPL");
index ec09cb6..36d3fba 100644 (file)
@@ -20,5 +20,10 @@ extern const unsigned int wm_hubs_spkmix_tlv[];
 
 extern int wm_hubs_add_analogue_controls(struct snd_soc_codec *);
 extern int wm_hubs_add_analogue_routes(struct snd_soc_codec *, int, int);
+extern int wm_hubs_handle_analogue_pdata(struct snd_soc_codec *,
+                                        int lineout1_diff, int lineout2_diff,
+                                        int lineout1fb, int lineout2fb,
+                                        int jd_scthr, int jd_thr,
+                                        int micbias1_lvl, int micbias2_lvl);
 
 #endif
index 4dfd4ad..047ee39 100644 (file)
@@ -13,9 +13,9 @@ config SND_DAVINCI_SOC_MCASP
        tristate
 
 config SND_DAVINCI_SOC_EVM
-       tristate "SoC Audio support for DaVinci DM6446 or DM355 EVM"
+       tristate "SoC Audio support for DaVinci DM6446, DM355 or DM365 EVM"
        depends on SND_DAVINCI_SOC
-       depends on MACH_DAVINCI_EVM || MACH_DAVINCI_DM355_EVM
+       depends on MACH_DAVINCI_EVM || MACH_DAVINCI_DM355_EVM  || MACH_DAVINCI_DM365_EVM
        select SND_DAVINCI_SOC_I2S
        select SND_SOC_TLV320AIC3X
        help
index 67414f6..7ccbe66 100644 (file)
@@ -45,7 +45,8 @@ static int evm_hw_params(struct snd_pcm_substream *substream,
        unsigned sysclk;
 
        /* ASP1 on DM355 EVM is clocked by an external oscillator */
-       if (machine_is_davinci_dm355_evm() || machine_is_davinci_dm6467_evm())
+       if (machine_is_davinci_dm355_evm() || machine_is_davinci_dm6467_evm() ||
+           machine_is_davinci_dm365_evm())
                sysclk = 27000000;
 
        /* ASP0 in DM6446 EVM is clocked by U55, as configured by
@@ -176,7 +177,7 @@ static struct snd_soc_dai_link da8xx_evm_dai = {
        .ops = &evm_ops,
 };
 
-/* davinci-evm audio machine driver */
+/* davinci dm6446, dm355 or dm365 evm audio machine driver */
 static struct snd_soc_card snd_soc_card_evm = {
        .name = "DaVinci EVM",
        .platform = &davinci_soc_platform,
@@ -243,7 +244,7 @@ static int __init evm_init(void)
        int index;
        int ret;
 
-       if (machine_is_davinci_evm()) {
+       if (machine_is_davinci_evm() || machine_is_davinci_dm365_evm()) {
                evm_snd_dev_data = &evm_snd_devdata;
                index = 0;
        } else if (machine_is_davinci_dm355_evm()) {
index 4ae7070..6362ca0 100644 (file)
@@ -97,12 +97,24 @@ enum {
        DAVINCI_MCBSP_WORD_32,
 };
 
+static const unsigned char data_type[SNDRV_PCM_FORMAT_S32_LE + 1] = {
+       [SNDRV_PCM_FORMAT_S8]           = 1,
+       [SNDRV_PCM_FORMAT_S16_LE]       = 2,
+       [SNDRV_PCM_FORMAT_S32_LE]       = 4,
+};
+
+static const unsigned char asp_word_length[SNDRV_PCM_FORMAT_S32_LE + 1] = {
+       [SNDRV_PCM_FORMAT_S8]           = DAVINCI_MCBSP_WORD_8,
+       [SNDRV_PCM_FORMAT_S16_LE]       = DAVINCI_MCBSP_WORD_16,
+       [SNDRV_PCM_FORMAT_S32_LE]       = DAVINCI_MCBSP_WORD_32,
+};
+
+static const unsigned char double_fmt[SNDRV_PCM_FORMAT_S32_LE + 1] = {
+       [SNDRV_PCM_FORMAT_S8]           = SNDRV_PCM_FORMAT_S16_LE,
+       [SNDRV_PCM_FORMAT_S16_LE]       = SNDRV_PCM_FORMAT_S32_LE,
+};
+
 struct davinci_mcbsp_dev {
-       /*
-        * dma_params must be first because rtd->dai->cpu_dai->private_data
-        * is cast to a pointer of an array of struct davinci_pcm_dma_params in
-        * davinci_pcm_open.
-        */
        struct davinci_pcm_dma_params   dma_params[2];
        void __iomem                    *base;
 #define MOD_DSP_A      0
@@ -110,6 +122,27 @@ struct davinci_mcbsp_dev {
        int                             mode;
        u32                             pcr;
        struct clk                      *clk;
+       /*
+        * Combining both channels into 1 element will at least double the
+        * amount of time between servicing the dma channel, increase
+        * effiency, and reduce the chance of overrun/underrun. But,
+        * it will result in the left & right channels being swapped.
+        *
+        * If relabeling the left and right channels is not possible,
+        * you may want to let the codec know to swap them back.
+        *
+        * It may allow x10 the amount of time to service dma requests,
+        * if the codec is master and is using an unnecessarily fast bit clock
+        * (ie. tlvaic23b), independent of the sample rate. So, having an
+        * entire frame at once means it can be serviced at the sample rate
+        * instead of the bit clock rate.
+        *
+        * In the now unlikely case that an underrun still
+        * occurs, both the left and right samples will be repeated
+        * so that no pops are heard, and the left and right channels
+        * won't end up being swapped because of the underrun.
+        */
+       unsigned enable_channel_combine:1;
 };
 
 static inline void davinci_mcbsp_write_reg(struct davinci_mcbsp_dev *dev,
@@ -349,6 +382,8 @@ static int davinci_i2s_hw_params(struct snd_pcm_substream *substream,
        int mcbsp_word_length;
        unsigned int rcr, xcr, srgr;
        u32 spcr;
+       snd_pcm_format_t fmt;
+       unsigned element_cnt = 1;
 
        /* general line settings */
        spcr = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG);
@@ -378,27 +413,24 @@ static int davinci_i2s_hw_params(struct snd_pcm_substream *substream,
                xcr |= DAVINCI_MCBSP_XCR_XDATDLY(1);
        }
        /* Determine xfer data type */
-       switch (params_format(params)) {
-       case SNDRV_PCM_FORMAT_S8:
-               dma_params->data_type = 1;
-               mcbsp_word_length = DAVINCI_MCBSP_WORD_8;
-               break;
-       case SNDRV_PCM_FORMAT_S16_LE:
-               dma_params->data_type = 2;
-               mcbsp_word_length = DAVINCI_MCBSP_WORD_16;
-               break;
-       case SNDRV_PCM_FORMAT_S32_LE:
-               dma_params->data_type = 4;
-               mcbsp_word_length = DAVINCI_MCBSP_WORD_32;
-               break;
-       default:
+       fmt = params_format(params);
+       if ((fmt > SNDRV_PCM_FORMAT_S32_LE) || !data_type[fmt]) {
                printk(KERN_WARNING "davinci-i2s: unsupported PCM format\n");
                return -EINVAL;
        }
 
-       dma_params->acnt  = dma_params->data_type;
-       rcr |= DAVINCI_MCBSP_RCR_RFRLEN1(1);
-       xcr |= DAVINCI_MCBSP_XCR_XFRLEN1(1);
+       if (params_channels(params) == 2) {
+               element_cnt = 2;
+               if (double_fmt[fmt] && dev->enable_channel_combine) {
+                       element_cnt = 1;
+                       fmt = double_fmt[fmt];
+               }
+       }
+       dma_params->acnt = dma_params->data_type = data_type[fmt];
+       dma_params->fifo_level = 0;
+       mcbsp_word_length = asp_word_length[fmt];
+       rcr |= DAVINCI_MCBSP_RCR_RFRLEN1(element_cnt - 1);
+       xcr |= DAVINCI_MCBSP_XCR_XFRLEN1(element_cnt - 1);
 
        rcr |= DAVINCI_MCBSP_RCR_RWDLEN1(mcbsp_word_length) |
                DAVINCI_MCBSP_RCR_RWDLEN2(mcbsp_word_length);
@@ -513,7 +545,13 @@ static int davinci_i2s_probe(struct platform_device *pdev)
                ret = -ENOMEM;
                goto err_release_region;
        }
-
+       if (pdata) {
+               dev->enable_channel_combine = pdata->enable_channel_combine;
+               dev->dma_params[SNDRV_PCM_STREAM_PLAYBACK].sram_size =
+                       pdata->sram_size_playback;
+               dev->dma_params[SNDRV_PCM_STREAM_CAPTURE].sram_size =
+                       pdata->sram_size_capture;
+       }
        dev->clk = clk_get(&pdev->dev, NULL);
        if (IS_ERR(dev->clk)) {
                ret = -ENODEV;
@@ -547,6 +585,7 @@ static int davinci_i2s_probe(struct platform_device *pdev)
        dev->dma_params[SNDRV_PCM_STREAM_CAPTURE].channel = res->start;
 
        davinci_i2s_dai.private_data = dev;
+       davinci_i2s_dai.dma_data = dev->dma_params;
        ret = snd_soc_register_dai(&davinci_i2s_dai);
        if (ret != 0)
                goto err_free_mem;
index 5d1f98a..0a302e1 100644 (file)
@@ -714,16 +714,13 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream,
        struct davinci_pcm_dma_params *dma_params =
                                        &dev->dma_params[substream->stream];
        int word_length;
-       u8 numevt;
+       u8 fifo_level;
 
        davinci_hw_common_param(dev, substream->stream);
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-               numevt = dev->txnumevt;
+               fifo_level = dev->txnumevt;
        else
-               numevt = dev->rxnumevt;
-
-       if (!numevt)
-               numevt = 1;
+               fifo_level = dev->rxnumevt;
 
        if (dev->op_mode == DAVINCI_MCASP_DIT_MODE)
                davinci_hw_dit_param(dev);
@@ -751,12 +748,12 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream,
                return -EINVAL;
        }
 
-       if (dev->version == MCASP_VERSION_2) {
-               dma_params->data_type *= numevt;
-               dma_params->acnt = 4 * numevt;
-       } else
+       if (dev->version == MCASP_VERSION_2 && !fifo_level)
+               dma_params->acnt = 4;
+       else
                dma_params->acnt = dma_params->data_type;
 
+       dma_params->fifo_level = fifo_level;
        davinci_config_channel_size(dev, word_length);
 
        return 0;
@@ -907,6 +904,7 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
 
        dma_data->channel = res->start;
        davinci_mcasp_dai[pdata->op_mode].private_data = dev;
+       davinci_mcasp_dai[pdata->op_mode].dma_data = dev->dma_params;
        davinci_mcasp_dai[pdata->op_mode].dev = &pdev->dev;
        ret = snd_soc_register_dai(&davinci_mcasp_dai[pdata->op_mode]);
 
index 9d179cc..582c924 100644 (file)
@@ -39,11 +39,6 @@ enum {
 };
 
 struct davinci_audio_dev {
-       /*
-        * dma_params must be first because rtd->dai->cpu_dai->private_data
-        * is cast to a pointer of an array of struct davinci_pcm_dma_params in
-        * davinci_pcm_open.
-        */
        struct davinci_pcm_dma_params dma_params[2];
        void __iomem *base;
        int sample_rate;
index c73a915..ad4d7f4 100644 (file)
@@ -3,6 +3,7 @@
  *
  * Author:      Vladimir Barinov, <vbarinov@embeddedalley.com>
  * Copyright:   (C) 2007 MontaVista Software, Inc., <source@mvista.com>
+ * added SRAM ping/pong (C) 2008 Troy Kisky <troy.kisky@boundarydevices.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
 
 #include <asm/dma.h>
 #include <mach/edma.h>
+#include <mach/sram.h>
 
 #include "davinci-pcm.h"
 
-static struct snd_pcm_hardware davinci_pcm_hardware = {
+#ifdef DEBUG
+static void print_buf_info(int slot, char *name)
+{
+       struct edmacc_param p;
+       if (slot < 0)
+               return;
+       edma_read_slot(slot, &p);
+       printk(KERN_DEBUG "%s: 0x%x, opt=%x, src=%x, a_b_cnt=%x dst=%x\n",
+                       name, slot, p.opt, p.src, p.a_b_cnt, p.dst);
+       printk(KERN_DEBUG "    src_dst_bidx=%x link_bcntrld=%x src_dst_cidx=%x ccnt=%x\n",
+                       p.src_dst_bidx, p.link_bcntrld, p.src_dst_cidx, p.ccnt);
+}
+#else
+static void print_buf_info(int slot, char *name)
+{
+}
+#endif
+
+static struct snd_pcm_hardware pcm_hardware_playback = {
        .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
                 SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
                 SNDRV_PCM_INFO_PAUSE),
@@ -48,102 +68,432 @@ static struct snd_pcm_hardware davinci_pcm_hardware = {
        .fifo_size = 0,
 };
 
+static struct snd_pcm_hardware pcm_hardware_capture = {
+       .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
+                SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
+                SNDRV_PCM_INFO_PAUSE),
+       .formats = (SNDRV_PCM_FMTBIT_S16_LE),
+       .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
+                 SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 |
+                 SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
+                 SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |
+                 SNDRV_PCM_RATE_KNOT),
+       .rate_min = 8000,
+       .rate_max = 96000,
+       .channels_min = 2,
+       .channels_max = 2,
+       .buffer_bytes_max = 128 * 1024,
+       .period_bytes_min = 32,
+       .period_bytes_max = 8 * 1024,
+       .periods_min = 16,
+       .periods_max = 255,
+       .fifo_size = 0,
+};
+
+/*
+ * How ping/pong works....
+ *
+ * Playback:
+ * ram_params - copys 2*ping_size from start of SDRAM to iram,
+ *     links to ram_link2
+ * ram_link2 - copys rest of SDRAM to iram in ping_size units,
+ *     links to ram_link
+ * ram_link - copys entire SDRAM to iram in ping_size uints,
+ *     links to self
+ *
+ * asp_params - same as asp_link[0]
+ * asp_link[0] - copys from lower half of iram to asp port
+ *     links to asp_link[1], triggers iram copy event on completion
+ * asp_link[1] - copys from upper half of iram to asp port
+ *     links to asp_link[0], triggers iram copy event on completion
+ *     triggers interrupt only needed to let upper SOC levels update position
+ *     in stream on completion
+ *
+ * When playback is started:
+ *     ram_params started
+ *     asp_params started
+ *
+ * Capture:
+ * ram_params - same as ram_link,
+ *     links to ram_link
+ * ram_link - same as playback
+ *     links to self
+ *
+ * asp_params - same as playback
+ * asp_link[0] - same as playback
+ * asp_link[1] - same as playback
+ *
+ * When capture is started:
+ *     asp_params started
+ */
 struct davinci_runtime_data {
        spinlock_t lock;
        int period;             /* current DMA period */
-       int master_lch;         /* Master DMA channel */
-       int slave_lch;          /* linked parameter RAM reload slot */
+       int asp_channel;        /* Master DMA channel */
+       int asp_link[2];        /* asp parameter link channel, ping/pong */
        struct davinci_pcm_dma_params *params;  /* DMA params */
+       int ram_channel;
+       int ram_link;
+       int ram_link2;
+       struct edmacc_param asp_params;
+       struct edmacc_param ram_params;
 };
 
+/*
+ * Not used with ping/pong
+ */
 static void davinci_pcm_enqueue_dma(struct snd_pcm_substream *substream)
 {
        struct davinci_runtime_data *prtd = substream->runtime->private_data;
        struct snd_pcm_runtime *runtime = substream->runtime;
-       int lch = prtd->slave_lch;
+       int link = prtd->asp_link[0];
        unsigned int period_size;
        unsigned int dma_offset;
        dma_addr_t dma_pos;
        dma_addr_t src, dst;
        unsigned short src_bidx, dst_bidx;
+       unsigned short src_cidx, dst_cidx;
        unsigned int data_type;
        unsigned short acnt;
        unsigned int count;
+       unsigned int fifo_level;
 
        period_size = snd_pcm_lib_period_bytes(substream);
        dma_offset = prtd->period * period_size;
        dma_pos = runtime->dma_addr + dma_offset;
+       fifo_level = prtd->params->fifo_level;
 
        pr_debug("davinci_pcm: audio_set_dma_params_play channel = %d "
-               "dma_ptr = %x period_size=%x\n", lch, dma_pos, period_size);
+               "dma_ptr = %x period_size=%x\n", link, dma_pos, period_size);
 
        data_type = prtd->params->data_type;
        count = period_size / data_type;
+       if (fifo_level)
+               count /= fifo_level;
 
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
                src = dma_pos;
                dst = prtd->params->dma_addr;
                src_bidx = data_type;
                dst_bidx = 0;
+               src_cidx = data_type * fifo_level;
+               dst_cidx = 0;
        } else {
                src = prtd->params->dma_addr;
                dst = dma_pos;
                src_bidx = 0;
                dst_bidx = data_type;
+               src_cidx = 0;
+               dst_cidx = data_type * fifo_level;
        }
 
        acnt = prtd->params->acnt;
-       edma_set_src(lch, src, INCR, W8BIT);
-       edma_set_dest(lch, dst, INCR, W8BIT);
-       edma_set_src_index(lch, src_bidx, 0);
-       edma_set_dest_index(lch, dst_bidx, 0);
-       edma_set_transfer_params(lch, acnt, count, 1, 0, ASYNC);
+       edma_set_src(link, src, INCR, W8BIT);
+       edma_set_dest(link, dst, INCR, W8BIT);
+
+       edma_set_src_index(link, src_bidx, src_cidx);
+       edma_set_dest_index(link, dst_bidx, dst_cidx);
+
+       if (!fifo_level)
+               edma_set_transfer_params(link, acnt, count, 1, 0, ASYNC);
+       else
+               edma_set_transfer_params(link, acnt, fifo_level, count,
+                                                       fifo_level, ABSYNC);
 
        prtd->period++;
        if (unlikely(prtd->period >= runtime->periods))
                prtd->period = 0;
 }
 
-static void davinci_pcm_dma_irq(unsigned lch, u16 ch_status, void *data)
+static void davinci_pcm_dma_irq(unsigned link, u16 ch_status, void *data)
 {
        struct snd_pcm_substream *substream = data;
        struct davinci_runtime_data *prtd = substream->runtime->private_data;
 
-       pr_debug("davinci_pcm: lch=%d, status=0x%x\n", lch, ch_status);
+       print_buf_info(prtd->ram_channel, "i ram_channel");
+       pr_debug("davinci_pcm: link=%d, status=0x%x\n", link, ch_status);
 
        if (unlikely(ch_status != DMA_COMPLETE))
                return;
 
        if (snd_pcm_running(substream)) {
+               if (prtd->ram_channel < 0) {
+                       /* No ping/pong must fix up link dma data*/
+                       spin_lock(&prtd->lock);
+                       davinci_pcm_enqueue_dma(substream);
+                       spin_unlock(&prtd->lock);
+               }
                snd_pcm_period_elapsed(substream);
+       }
+}
+
+static int allocate_sram(struct snd_pcm_substream *substream, unsigned size,
+               struct snd_pcm_hardware *ppcm)
+{
+       struct snd_dma_buffer *buf = &substream->dma_buffer;
+       struct snd_dma_buffer *iram_dma = NULL;
+       dma_addr_t iram_phys = 0;
+       void *iram_virt = NULL;
+
+       if (buf->private_data || !size)
+               return 0;
+
+       ppcm->period_bytes_max = size;
+       iram_virt = sram_alloc(size, &iram_phys);
+       if (!iram_virt)
+               goto exit1;
+       iram_dma = kzalloc(sizeof(*iram_dma), GFP_KERNEL);
+       if (!iram_dma)
+               goto exit2;
+       iram_dma->area = iram_virt;
+       iram_dma->addr = iram_phys;
+       memset(iram_dma->area, 0, size);
+       iram_dma->bytes = size;
+       buf->private_data = iram_dma;
+       return 0;
+exit2:
+       if (iram_virt)
+               sram_free(iram_virt, size);
+exit1:
+       return -ENOMEM;
+}
+
+/*
+ * Only used with ping/pong.
+ * This is called after runtime->dma_addr, period_bytes and data_type are valid
+ */
+static int ping_pong_dma_setup(struct snd_pcm_substream *substream)
+{
+       unsigned short ram_src_cidx, ram_dst_cidx;
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct davinci_runtime_data *prtd = runtime->private_data;
+       struct snd_dma_buffer *iram_dma =
+               (struct snd_dma_buffer *)substream->dma_buffer.private_data;
+       struct davinci_pcm_dma_params *params = prtd->params;
+       unsigned int data_type = params->data_type;
+       unsigned int acnt = params->acnt;
+       /* divide by 2 for ping/pong */
+       unsigned int ping_size = snd_pcm_lib_period_bytes(substream) >> 1;
+       int link = prtd->asp_link[1];
+       unsigned int fifo_level = prtd->params->fifo_level;
+       unsigned int count;
+       if ((data_type == 0) || (data_type > 4)) {
+               printk(KERN_ERR "%s: data_type=%i\n", __func__, data_type);
+               return -EINVAL;
+       }
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               dma_addr_t asp_src_pong = iram_dma->addr + ping_size;
+               ram_src_cidx = ping_size;
+               ram_dst_cidx = -ping_size;
+               edma_set_src(link, asp_src_pong, INCR, W8BIT);
+
+               link = prtd->asp_link[0];
+               edma_set_src_index(link, data_type, data_type * fifo_level);
+               link = prtd->asp_link[1];
+               edma_set_src_index(link, data_type, data_type * fifo_level);
+
+               link = prtd->ram_link;
+               edma_set_src(link, runtime->dma_addr, INCR, W32BIT);
+       } else {
+               dma_addr_t asp_dst_pong = iram_dma->addr + ping_size;
+               ram_src_cidx = -ping_size;
+               ram_dst_cidx = ping_size;
+               edma_set_dest(link, asp_dst_pong, INCR, W8BIT);
+
+               link = prtd->asp_link[0];
+               edma_set_dest_index(link, data_type, data_type * fifo_level);
+               link = prtd->asp_link[1];
+               edma_set_dest_index(link, data_type, data_type * fifo_level);
+
+               link = prtd->ram_link;
+               edma_set_dest(link, runtime->dma_addr, INCR, W32BIT);
+       }
 
-               spin_lock(&prtd->lock);
-               davinci_pcm_enqueue_dma(substream);
-               spin_unlock(&prtd->lock);
+       if (!fifo_level) {
+               count = ping_size / data_type;
+               edma_set_transfer_params(prtd->asp_link[0], acnt, count,
+                               1, 0, ASYNC);
+               edma_set_transfer_params(prtd->asp_link[1], acnt, count,
+                               1, 0, ASYNC);
+       } else {
+               count = ping_size / (data_type * fifo_level);
+               edma_set_transfer_params(prtd->asp_link[0], acnt, fifo_level,
+                               count, fifo_level, ABSYNC);
+               edma_set_transfer_params(prtd->asp_link[1], acnt, fifo_level,
+                               count, fifo_level, ABSYNC);
        }
+
+       link = prtd->ram_link;
+       edma_set_src_index(link, ping_size, ram_src_cidx);
+       edma_set_dest_index(link, ping_size, ram_dst_cidx);
+       edma_set_transfer_params(link, ping_size, 2,
+                       runtime->periods, 2, ASYNC);
+
+       /* init master params */
+       edma_read_slot(prtd->asp_link[0], &prtd->asp_params);
+       edma_read_slot(prtd->ram_link, &prtd->ram_params);
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               struct edmacc_param p_ram;
+               /* Copy entire iram buffer before playback started */
+               prtd->ram_params.a_b_cnt = (1 << 16) | (ping_size << 1);
+               /* 0 dst_bidx */
+               prtd->ram_params.src_dst_bidx = (ping_size << 1);
+               /* 0 dst_cidx */
+               prtd->ram_params.src_dst_cidx = (ping_size << 1);
+               prtd->ram_params.ccnt = 1;
+
+               /* Skip 1st period */
+               edma_read_slot(prtd->ram_link, &p_ram);
+               p_ram.src += (ping_size << 1);
+               p_ram.ccnt -= 1;
+               edma_write_slot(prtd->ram_link2, &p_ram);
+               /*
+                * When 1st started, ram -> iram dma channel will fill the
+                * entire iram.  Then, whenever a ping/pong asp buffer finishes,
+                * 1/2 iram will be filled.
+                */
+               prtd->ram_params.link_bcntrld =
+                       EDMA_CHAN_SLOT(prtd->ram_link2) << 5;
+       }
+       return 0;
+}
+
+/* 1 asp tx or rx channel using 2 parameter channels
+ * 1 ram to/from iram channel using 1 parameter channel
+ *
+ * Playback
+ * ram copy channel kicks off first,
+ * 1st ram copy of entire iram buffer completion kicks off asp channel
+ * asp tcc always kicks off ram copy of 1/2 iram buffer
+ *
+ * Record
+ * asp channel starts, tcc kicks off ram copy
+ */
+static int request_ping_pong(struct snd_pcm_substream *substream,
+               struct davinci_runtime_data *prtd,
+               struct snd_dma_buffer *iram_dma)
+{
+       dma_addr_t asp_src_ping;
+       dma_addr_t asp_dst_ping;
+       int link;
+       struct davinci_pcm_dma_params *params = prtd->params;
+
+       /* Request ram master channel */
+       link = prtd->ram_channel = edma_alloc_channel(EDMA_CHANNEL_ANY,
+                                 davinci_pcm_dma_irq, substream,
+                                 EVENTQ_1);
+       if (link < 0)
+               goto exit1;
+
+       /* Request ram link channel */
+       link = prtd->ram_link = edma_alloc_slot(
+                       EDMA_CTLR(prtd->ram_channel), EDMA_SLOT_ANY);
+       if (link < 0)
+               goto exit2;
+
+       link = prtd->asp_link[1] = edma_alloc_slot(
+                       EDMA_CTLR(prtd->asp_channel), EDMA_SLOT_ANY);
+       if (link < 0)
+               goto exit3;
+
+       prtd->ram_link2 = -1;
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               link = prtd->ram_link2 = edma_alloc_slot(
+                       EDMA_CTLR(prtd->ram_channel), EDMA_SLOT_ANY);
+               if (link < 0)
+                       goto exit4;
+       }
+       /* circle ping-pong buffers */
+       edma_link(prtd->asp_link[0], prtd->asp_link[1]);
+       edma_link(prtd->asp_link[1], prtd->asp_link[0]);
+       /* circle ram buffers */
+       edma_link(prtd->ram_link, prtd->ram_link);
+
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               asp_src_ping = iram_dma->addr;
+               asp_dst_ping = params->dma_addr;        /* fifo */
+       } else {
+               asp_src_ping = params->dma_addr;        /* fifo */
+               asp_dst_ping = iram_dma->addr;
+       }
+       /* ping */
+       link = prtd->asp_link[0];
+       edma_set_src(link, asp_src_ping, INCR, W16BIT);
+       edma_set_dest(link, asp_dst_ping, INCR, W16BIT);
+       edma_set_src_index(link, 0, 0);
+       edma_set_dest_index(link, 0, 0);
+
+       edma_read_slot(link, &prtd->asp_params);
+       prtd->asp_params.opt &= ~(TCCMODE | EDMA_TCC(0x3f) | TCINTEN);
+       prtd->asp_params.opt |= TCCHEN | EDMA_TCC(prtd->ram_channel & 0x3f);
+       edma_write_slot(link, &prtd->asp_params);
+
+       /* pong */
+       link = prtd->asp_link[1];
+       edma_set_src(link, asp_src_ping, INCR, W16BIT);
+       edma_set_dest(link, asp_dst_ping, INCR, W16BIT);
+       edma_set_src_index(link, 0, 0);
+       edma_set_dest_index(link, 0, 0);
+
+       edma_read_slot(link, &prtd->asp_params);
+       prtd->asp_params.opt &= ~(TCCMODE | EDMA_TCC(0x3f));
+       /* interrupt after every pong completion */
+       prtd->asp_params.opt |= TCINTEN | TCCHEN |
+               EDMA_TCC(EDMA_CHAN_SLOT(prtd->ram_channel));
+       edma_write_slot(link, &prtd->asp_params);
+
+       /* ram */
+       link = prtd->ram_link;
+       edma_set_src(link, iram_dma->addr, INCR, W32BIT);
+       edma_set_dest(link, iram_dma->addr, INCR, W32BIT);
+       pr_debug("%s: audio dma channels/slots in use for ram:%u %u %u,"
+               "for asp:%u %u %u\n", __func__,
+               prtd->ram_channel, prtd->ram_link, prtd->ram_link2,
+               prtd->asp_channel, prtd->asp_link[0],
+               prtd->asp_link[1]);
+       return 0;
+exit4:
+       edma_free_channel(prtd->asp_link[1]);
+       prtd->asp_link[1] = -1;
+exit3:
+       edma_free_channel(prtd->ram_link);
+       prtd->ram_link = -1;
+exit2:
+       edma_free_channel(prtd->ram_channel);
+       prtd->ram_channel = -1;
+exit1:
+       return link;
 }
 
 static int davinci_pcm_dma_request(struct snd_pcm_substream *substream)
 {
+       struct snd_dma_buffer *iram_dma;
        struct davinci_runtime_data *prtd = substream->runtime->private_data;
-       struct edmacc_param p_ram;
-       int ret;
+       struct davinci_pcm_dma_params *params = prtd->params;
+       int link;
 
-       /* Request master DMA channel */
-       ret = edma_alloc_channel(prtd->params->channel,
-                                 davinci_pcm_dma_irq, substream,
-                                 EVENTQ_0);
-       if (ret < 0)
-               return ret;
-       prtd->master_lch = ret;
+       if (!params)
+               return -ENODEV;
 
-       /* Request parameter RAM reload slot */
-       ret = edma_alloc_slot(EDMA_CTLR(prtd->master_lch), EDMA_SLOT_ANY);
-       if (ret < 0) {
-               edma_free_channel(prtd->master_lch);
-               return ret;
+       /* Request asp master DMA channel */
+       link = prtd->asp_channel = edma_alloc_channel(params->channel,
+                       davinci_pcm_dma_irq, substream, EVENTQ_0);
+       if (link < 0)
+               goto exit1;
+
+       /* Request asp link channels */
+       link = prtd->asp_link[0] = edma_alloc_slot(
+                       EDMA_CTLR(prtd->asp_channel), EDMA_SLOT_ANY);
+       if (link < 0)
+               goto exit2;
+
+       iram_dma = (struct snd_dma_buffer *)substream->dma_buffer.private_data;
+       if (iram_dma) {
+               if (request_ping_pong(substream, prtd, iram_dma) == 0)
+                       return 0;
+               printk(KERN_WARNING "%s: dma channel allocation failed,"
+                               "not using sram\n", __func__);
        }
-       prtd->slave_lch = ret;
 
        /* Issue transfer completion IRQ when the channel completes a
         * transfer, then always reload from the same slot (by a kind
@@ -154,12 +504,17 @@ static int davinci_pcm_dma_request(struct snd_pcm_substream *substream)
         * the buffer and its length (ccnt) ... use it as a template
         * so davinci_pcm_enqueue_dma() takes less time in IRQ.
         */
-       edma_read_slot(prtd->slave_lch, &p_ram);
-       p_ram.opt |= TCINTEN | EDMA_TCC(EDMA_CHAN_SLOT(prtd->master_lch));
-       p_ram.link_bcntrld = EDMA_CHAN_SLOT(prtd->slave_lch) << 5;
-       edma_write_slot(prtd->slave_lch, &p_ram);
-
+       edma_read_slot(link, &prtd->asp_params);
+       prtd->asp_params.opt |= TCINTEN |
+               EDMA_TCC(EDMA_CHAN_SLOT(prtd->asp_channel));
+       prtd->asp_params.link_bcntrld = EDMA_CHAN_SLOT(link) << 5;
+       edma_write_slot(link, &prtd->asp_params);
        return 0;
+exit2:
+       edma_free_channel(prtd->asp_channel);
+       prtd->asp_channel = -1;
+exit1:
+       return link;
 }
 
 static int davinci_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
@@ -173,12 +528,12 @@ static int davinci_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
        case SNDRV_PCM_TRIGGER_START:
        case SNDRV_PCM_TRIGGER_RESUME:
        case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-               edma_start(prtd->master_lch);
+               edma_resume(prtd->asp_channel);
                break;
        case SNDRV_PCM_TRIGGER_STOP:
        case SNDRV_PCM_TRIGGER_SUSPEND:
        case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-               edma_stop(prtd->master_lch);
+               edma_pause(prtd->asp_channel);
                break;
        default:
                ret = -EINVAL;
@@ -193,15 +548,37 @@ static int davinci_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
 static int davinci_pcm_prepare(struct snd_pcm_substream *substream)
 {
        struct davinci_runtime_data *prtd = substream->runtime->private_data;
-       struct edmacc_param temp;
 
+       if (prtd->ram_channel >= 0) {
+               int ret = ping_pong_dma_setup(substream);
+               if (ret < 0)
+                       return ret;
+
+               edma_write_slot(prtd->ram_channel, &prtd->ram_params);
+               edma_write_slot(prtd->asp_channel, &prtd->asp_params);
+
+               print_buf_info(prtd->ram_channel, "ram_channel");
+               print_buf_info(prtd->ram_link, "ram_link");
+               print_buf_info(prtd->ram_link2, "ram_link2");
+               print_buf_info(prtd->asp_channel, "asp_channel");
+               print_buf_info(prtd->asp_link[0], "asp_link[0]");
+               print_buf_info(prtd->asp_link[1], "asp_link[1]");
+
+               if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+                       /* copy 1st iram buffer */
+                       edma_start(prtd->ram_channel);
+               }
+               edma_start(prtd->asp_channel);
+               return 0;
+       }
        prtd->period = 0;
        davinci_pcm_enqueue_dma(substream);
 
        /* Copy self-linked parameter RAM entry into master channel */
-       edma_read_slot(prtd->slave_lch, &temp);
-       edma_write_slot(prtd->master_lch, &temp);
+       edma_read_slot(prtd->asp_link[0], &prtd->asp_params);
+       edma_write_slot(prtd->asp_channel, &prtd->asp_params);
        davinci_pcm_enqueue_dma(substream);
+       edma_start(prtd->asp_channel);
 
        return 0;
 }
@@ -212,20 +589,53 @@ davinci_pcm_pointer(struct snd_pcm_substream *substream)
        struct snd_pcm_runtime *runtime = substream->runtime;
        struct davinci_runtime_data *prtd = runtime->private_data;
        unsigned int offset;
-       dma_addr_t count;
-       dma_addr_t src, dst;
+       int asp_count;
+       dma_addr_t asp_src, asp_dst;
 
        spin_lock(&prtd->lock);
-
-       edma_get_position(prtd->master_lch, &src, &dst);
-       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-               count = src - runtime->dma_addr;
-       else
-               count = dst - runtime->dma_addr;
-
+       if (prtd->ram_channel >= 0) {
+               int ram_count;
+               int mod_ram;
+               dma_addr_t ram_src, ram_dst;
+               unsigned int period_size = snd_pcm_lib_period_bytes(substream);
+               if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+                       /* reading ram before asp should be safe
+                        * as long as the asp transfers less than a ping size
+                        * of bytes between the 2 reads
+                        */
+                       edma_get_position(prtd->ram_channel,
+                                       &ram_src, &ram_dst);
+                       edma_get_position(prtd->asp_channel,
+                                       &asp_src, &asp_dst);
+                       asp_count = asp_src - prtd->asp_params.src;
+                       ram_count = ram_src - prtd->ram_params.src;
+                       mod_ram = ram_count % period_size;
+                       mod_ram -= asp_count;
+                       if (mod_ram < 0)
+                               mod_ram += period_size;
+                       else if (mod_ram == 0) {
+                               if (snd_pcm_running(substream))
+                                       mod_ram += period_size;
+                       }
+                       ram_count -= mod_ram;
+                       if (ram_count < 0)
+                               ram_count += period_size * runtime->periods;
+               } else {
+                       edma_get_position(prtd->ram_channel,
+                                       &ram_src, &ram_dst);
+                       ram_count = ram_dst - prtd->ram_params.dst;
+               }
+               asp_count = ram_count;
+       } else {
+               edma_get_position(prtd->asp_channel, &asp_src, &asp_dst);
+               if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+                       asp_count = asp_src - runtime->dma_addr;
+               else
+                       asp_count = asp_dst - runtime->dma_addr;
+       }
        spin_unlock(&prtd->lock);
 
-       offset = bytes_to_frames(runtime, count);
+       offset = bytes_to_frames(runtime, asp_count);
        if (offset >= runtime->buffer_size)
                offset = 0;
 
@@ -236,14 +646,19 @@ static int davinci_pcm_open(struct snd_pcm_substream *substream)
 {
        struct snd_pcm_runtime *runtime = substream->runtime;
        struct davinci_runtime_data *prtd;
+       struct snd_pcm_hardware *ppcm;
        int ret = 0;
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct davinci_pcm_dma_params *pa = rtd->dai->cpu_dai->private_data;
-       struct davinci_pcm_dma_params *params = &pa[substream->stream];
-       if (!params)
+       struct davinci_pcm_dma_params *pa = rtd->dai->cpu_dai->dma_data;
+       struct davinci_pcm_dma_params *params;
+       if (!pa)
                return -ENODEV;
+       params = &pa[substream->stream];
 
-       snd_soc_set_runtime_hwparams(substream, &davinci_pcm_hardware);
+       ppcm = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
+                       &pcm_hardware_playback : &pcm_hardware_capture;
+       allocate_sram(substream, params->sram_size, ppcm);
+       snd_soc_set_runtime_hwparams(substream, ppcm);
        /* ensure that buffer size is a multiple of period size */
        ret = snd_pcm_hw_constraint_integer(runtime,
                                                SNDRV_PCM_HW_PARAM_PERIODS);
@@ -256,6 +671,11 @@ static int davinci_pcm_open(struct snd_pcm_substream *substream)
 
        spin_lock_init(&prtd->lock);
        prtd->params = params;
+       prtd->asp_channel = -1;
+       prtd->asp_link[0] = prtd->asp_link[1] = -1;
+       prtd->ram_channel = -1;
+       prtd->ram_link = -1;
+       prtd->ram_link2 = -1;
 
        runtime->private_data = prtd;
 
@@ -273,10 +693,29 @@ static int davinci_pcm_close(struct snd_pcm_substream *substream)
        struct snd_pcm_runtime *runtime = substream->runtime;
        struct davinci_runtime_data *prtd = runtime->private_data;
 
-       edma_unlink(prtd->slave_lch);
-
-       edma_free_slot(prtd->slave_lch);
-       edma_free_channel(prtd->master_lch);
+       if (prtd->ram_channel >= 0)
+               edma_stop(prtd->ram_channel);
+       if (prtd->asp_channel >= 0)
+               edma_stop(prtd->asp_channel);
+       if (prtd->asp_link[0] >= 0)
+               edma_unlink(prtd->asp_link[0]);
+       if (prtd->asp_link[1] >= 0)
+               edma_unlink(prtd->asp_link[1]);
+       if (prtd->ram_link >= 0)
+               edma_unlink(prtd->ram_link);
+
+       if (prtd->asp_link[0] >= 0)
+               edma_free_slot(prtd->asp_link[0]);
+       if (prtd->asp_link[1] >= 0)
+               edma_free_slot(prtd->asp_link[1]);
+       if (prtd->asp_channel >= 0)
+               edma_free_channel(prtd->asp_channel);
+       if (prtd->ram_link >= 0)
+               edma_free_slot(prtd->ram_link);
+       if (prtd->ram_link2 >= 0)
+               edma_free_slot(prtd->ram_link2);
+       if (prtd->ram_channel >= 0)
+               edma_free_channel(prtd->ram_channel);
 
        kfree(prtd);
 
@@ -318,11 +757,11 @@ static struct snd_pcm_ops davinci_pcm_ops = {
        .mmap =         davinci_pcm_mmap,
 };
 
-static int davinci_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
+static int davinci_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream,
+               size_t size)
 {
        struct snd_pcm_substream *substream = pcm->streams[stream].substream;
        struct snd_dma_buffer *buf = &substream->dma_buffer;
-       size_t size = davinci_pcm_hardware.buffer_bytes_max;
 
        buf->dev.type = SNDRV_DMA_TYPE_DEV;
        buf->dev.dev = pcm->card->dev;
@@ -347,6 +786,7 @@ static void davinci_pcm_free(struct snd_pcm *pcm)
        int stream;
 
        for (stream = 0; stream < 2; stream++) {
+               struct snd_dma_buffer *iram_dma;
                substream = pcm->streams[stream].substream;
                if (!substream)
                        continue;
@@ -358,6 +798,11 @@ static void davinci_pcm_free(struct snd_pcm *pcm)
                dma_free_writecombine(pcm->card->dev, buf->bytes,
                                      buf->area, buf->addr);
                buf->area = NULL;
+               iram_dma = (struct snd_dma_buffer *)buf->private_data;
+               if (iram_dma) {
+                       sram_free(iram_dma->area, iram_dma->bytes);
+                       kfree(iram_dma);
+               }
        }
 }
 
@@ -375,14 +820,16 @@ static int davinci_pcm_new(struct snd_card *card,
 
        if (dai->playback.channels_min) {
                ret = davinci_pcm_preallocate_dma_buffer(pcm,
-                       SNDRV_PCM_STREAM_PLAYBACK);
+                       SNDRV_PCM_STREAM_PLAYBACK,
+                       pcm_hardware_playback.buffer_bytes_max);
                if (ret)
                        return ret;
        }
 
        if (dai->capture.channels_min) {
                ret = davinci_pcm_preallocate_dma_buffer(pcm,
-                       SNDRV_PCM_STREAM_CAPTURE);
+                       SNDRV_PCM_STREAM_CAPTURE,
+                       pcm_hardware_capture.buffer_bytes_max);
                if (ret)
                        return ret;
        }
index 8746606..0764944 100644 (file)
@@ -20,9 +20,11 @@ struct davinci_pcm_dma_params {
        int channel;                    /* sync dma channel ID */
        unsigned short acnt;
        dma_addr_t dma_addr;            /* device physical address for DMA */
+       unsigned sram_size;
        enum dma_event_q eventq_no;     /* event queue number */
        unsigned char data_type;        /* xfer data type */
        unsigned char convert_mono_stereo;
+       unsigned int fifo_level;
 };
 
 
index 6096d22..30ed568 100644 (file)
@@ -58,47 +58,15 @@ static void psc_dma_bcom_enqueue_next_buffer(struct psc_dma_stream *s)
        /* Prepare and enqueue the next buffer descriptor */
        bd = bcom_prepare_next_buffer(s->bcom_task);
        bd->status = s->period_bytes;
-       bd->data[0] = s->period_next_pt;
+       bd->data[0] = s->runtime->dma_addr + (s->period_next * s->period_bytes);
        bcom_submit_next_buffer(s->bcom_task, NULL);
 
        /* Update for next period */
-       s->period_next_pt += s->period_bytes;
-       if (s->period_next_pt >= s->period_end)
-               s->period_next_pt = s->period_start;
-}
-
-static void psc_dma_bcom_enqueue_tx(struct psc_dma_stream *s)
-{
-       if (s->appl_ptr > s->runtime->control->appl_ptr) {
-               /*
-                * In this case s->runtime->control->appl_ptr has wrapped around.
-                * Play the data to the end of the boundary, then wrap our own
-                * appl_ptr back around.
-                */
-               while (s->appl_ptr < s->runtime->boundary) {
-                       if (bcom_queue_full(s->bcom_task))
-                               return;
-
-                       s->appl_ptr += s->period_size;
-
-                       psc_dma_bcom_enqueue_next_buffer(s);
-               }
-               s->appl_ptr -= s->runtime->boundary;
-       }
-
-       while (s->appl_ptr < s->runtime->control->appl_ptr) {
-
-               if (bcom_queue_full(s->bcom_task))
-                       return;
-
-               s->appl_ptr += s->period_size;
-
-               psc_dma_bcom_enqueue_next_buffer(s);
-       }
+       s->period_next = (s->period_next + 1) % s->runtime->periods;
 }
 
 /* Bestcomm DMA irq handler */
-static irqreturn_t psc_dma_bcom_irq_tx(int irq, void *_psc_dma_stream)
+static irqreturn_t psc_dma_bcom_irq(int irq, void *_psc_dma_stream)
 {
        struct psc_dma_stream *s = _psc_dma_stream;
 
@@ -108,34 +76,8 @@ static irqreturn_t psc_dma_bcom_irq_tx(int irq, void *_psc_dma_stream)
        while (bcom_buffer_done(s->bcom_task)) {
                bcom_retrieve_buffer(s->bcom_task, NULL, NULL);
 
-               s->period_current_pt += s->period_bytes;
-               if (s->period_current_pt >= s->period_end)
-                       s->period_current_pt = s->period_start;
-       }
-       psc_dma_bcom_enqueue_tx(s);
-       spin_unlock(&s->psc_dma->lock);
-
-       /* If the stream is active, then also inform the PCM middle layer
-        * of the period finished event. */
-       if (s->active)
-               snd_pcm_period_elapsed(s->stream);
-
-       return IRQ_HANDLED;
-}
-
-static irqreturn_t psc_dma_bcom_irq_rx(int irq, void *_psc_dma_stream)
-{
-       struct psc_dma_stream *s = _psc_dma_stream;
-
-       spin_lock(&s->psc_dma->lock);
-       /* For each finished period, dequeue the completed period buffer
-        * and enqueue a new one in it's place. */
-       while (bcom_buffer_done(s->bcom_task)) {
-               bcom_retrieve_buffer(s->bcom_task, NULL, NULL);
-
-               s->period_current_pt += s->period_bytes;
-               if (s->period_current_pt >= s->period_end)
-                       s->period_current_pt = s->period_start;
+               s->period_current = (s->period_current+1) % s->runtime->periods;
+               s->period_count++;
 
                psc_dma_bcom_enqueue_next_buffer(s);
        }
@@ -166,54 +108,38 @@ static int psc_dma_trigger(struct snd_pcm_substream *substream, int cmd)
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct psc_dma *psc_dma = rtd->dai->cpu_dai->private_data;
        struct snd_pcm_runtime *runtime = substream->runtime;
-       struct psc_dma_stream *s;
+       struct psc_dma_stream *s = to_psc_dma_stream(substream, psc_dma);
        struct mpc52xx_psc __iomem *regs = psc_dma->psc_regs;
        u16 imr;
        unsigned long flags;
        int i;
 
-       if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE)
-               s = &psc_dma->capture;
-       else
-               s = &psc_dma->playback;
-
-       dev_dbg(psc_dma->dev, "psc_dma_trigger(substream=%p, cmd=%i)"
-               " stream_id=%i\n",
-               substream, cmd, substream->pstr->stream);
-
        switch (cmd) {
        case SNDRV_PCM_TRIGGER_START:
+               dev_dbg(psc_dma->dev, "START: stream=%i fbits=%u ps=%u #p=%u\n",
+                       substream->pstr->stream, runtime->frame_bits,
+                       (int)runtime->period_size, runtime->periods);
                s->period_bytes = frames_to_bytes(runtime,
                                                  runtime->period_size);
-               s->period_start = virt_to_phys(runtime->dma_area);
-               s->period_end = s->period_start +
-                               (s->period_bytes * runtime->periods);
-               s->period_next_pt = s->period_start;
-               s->period_current_pt = s->period_start;
-               s->period_size = runtime->period_size;
+               s->period_next = 0;
+               s->period_current = 0;
                s->active = 1;
-
-               /* track appl_ptr so that we have a better chance of detecting
-                * end of stream and not over running it.
-                */
+               s->period_count = 0;
                s->runtime = runtime;
-               s->appl_ptr = s->runtime->control->appl_ptr -
-                               (runtime->period_size * runtime->periods);
 
                /* Fill up the bestcomm bd queue and enable DMA.
                 * This will begin filling the PSC's fifo.
                 */
                spin_lock_irqsave(&psc_dma->lock, flags);
 
-               if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE) {
+               if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE)
                        bcom_gen_bd_rx_reset(s->bcom_task);
-                       for (i = 0; i < runtime->periods; i++)
-                               if (!bcom_queue_full(s->bcom_task))
-                                       psc_dma_bcom_enqueue_next_buffer(s);
-               } else {
+               else
                        bcom_gen_bd_tx_reset(s->bcom_task);
-                       psc_dma_bcom_enqueue_tx(s);
-               }
+
+               for (i = 0; i < runtime->periods; i++)
+                       if (!bcom_queue_full(s->bcom_task))
+                               psc_dma_bcom_enqueue_next_buffer(s);
 
                bcom_enable(s->bcom_task);
                spin_unlock_irqrestore(&psc_dma->lock, flags);
@@ -223,6 +149,8 @@ static int psc_dma_trigger(struct snd_pcm_substream *substream, int cmd)
                break;
 
        case SNDRV_PCM_TRIGGER_STOP:
+               dev_dbg(psc_dma->dev, "STOP: stream=%i periods_count=%i\n",
+                       substream->pstr->stream, s->period_count);
                s->active = 0;
 
                spin_lock_irqsave(&psc_dma->lock, flags);
@@ -236,7 +164,8 @@ static int psc_dma_trigger(struct snd_pcm_substream *substream, int cmd)
                break;
 
        default:
-               dev_dbg(psc_dma->dev, "invalid command\n");
+               dev_dbg(psc_dma->dev, "unhandled trigger: stream=%i cmd=%i\n",
+                       substream->pstr->stream, cmd);
                return -EINVAL;
        }
 
@@ -343,7 +272,7 @@ psc_dma_pointer(struct snd_pcm_substream *substream)
        else
                s = &psc_dma->playback;
 
-       count = s->period_current_pt - s->period_start;
+       count = s->period_current * s->period_bytes;
 
        return bytes_to_frames(substream->runtime, count);
 }
@@ -532,11 +461,9 @@ int mpc5200_audio_dma_create(struct of_device *op)
 
        rc = request_irq(psc_dma->irq, &psc_dma_status_irq, IRQF_SHARED,
                         "psc-dma-status", psc_dma);
-       rc |= request_irq(psc_dma->capture.irq,
-                         &psc_dma_bcom_irq_rx, IRQF_SHARED,
+       rc |= request_irq(psc_dma->capture.irq, &psc_dma_bcom_irq, IRQF_SHARED,
                          "psc-dma-capture", &psc_dma->capture);
-       rc |= request_irq(psc_dma->playback.irq,
-                         &psc_dma_bcom_irq_tx, IRQF_SHARED,
+       rc |= request_irq(psc_dma->playback.irq, &psc_dma_bcom_irq, IRQF_SHARED,
                          "psc-dma-playback", &psc_dma->playback);
        if (rc) {
                ret = -ENODEV;
index 8d396bb..22208b3 100644 (file)
  * @psc_dma:           pointer back to parent psc_dma data structure
  * @bcom_task:         bestcomm task structure
  * @irq:               irq number for bestcomm task
- * @period_start:      physical address of start of DMA region
  * @period_end:                physical address of end of DMA region
  * @period_next_pt:    physical address of next DMA buffer to enqueue
  * @period_bytes:      size of DMA period in bytes
+ * @ac97_slot_bits:    Enable bits for turning on the correct AC97 slot
  */
 struct psc_dma_stream {
        struct snd_pcm_runtime *runtime;
-       snd_pcm_uframes_t appl_ptr;
-
        int active;
        struct psc_dma *psc_dma;
        struct bcom_task *bcom_task;
        int irq;
        struct snd_pcm_substream *stream;
-       dma_addr_t period_start;
-       dma_addr_t period_end;
-       dma_addr_t period_next_pt;
-       dma_addr_t period_current_pt;
+       int period_next;
+       int period_current;
        int period_bytes;
-       int period_size;
+       int period_count;
+
+       /* AC97 state */
+       u32 ac97_slot_bits;
 };
 
 /**
@@ -73,6 +72,15 @@ struct psc_dma {
        } stats;
 };
 
+/* Utility for retrieving psc_dma_stream structure from a substream */
+inline struct psc_dma_stream *
+to_psc_dma_stream(struct snd_pcm_substream *substream, struct psc_dma *psc_dma)
+{
+       if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE)
+               return &psc_dma->capture;
+       return &psc_dma->playback;
+}
+
 int mpc5200_audio_dma_create(struct of_device *op);
 int mpc5200_audio_dma_destroy(struct of_device *op);
 
index c4ae3e0..3dbc7f7 100644 (file)
@@ -130,6 +130,7 @@ static int psc_ac97_hw_analog_params(struct snd_pcm_substream *substream,
                                 struct snd_soc_dai *cpu_dai)
 {
        struct psc_dma *psc_dma = cpu_dai->private_data;
+       struct psc_dma_stream *s = to_psc_dma_stream(substream, psc_dma);
 
        dev_dbg(psc_dma->dev, "%s(substream=%p) p_size=%i p_bytes=%i"
                " periods=%i buffer_size=%i  buffer_bytes=%i channels=%i"
@@ -140,20 +141,10 @@ static int psc_ac97_hw_analog_params(struct snd_pcm_substream *substream,
                params_channels(params), params_rate(params),
                params_format(params));
 
-
-       if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE) {
-               if (params_channels(params) == 1)
-                       psc_dma->slots |= 0x00000100;
-               else
-                       psc_dma->slots |= 0x00000300;
-       } else {
-               if (params_channels(params) == 1)
-                       psc_dma->slots |= 0x01000000;
-               else
-                       psc_dma->slots |= 0x03000000;
-       }
-       out_be32(&psc_dma->psc_regs->ac97_slots, psc_dma->slots);
-
+       /* Determine the set of enable bits to turn on */
+       s->ac97_slot_bits = (params_channels(params) == 1) ? 0x100 : 0x300;
+       if (substream->pstr->stream != SNDRV_PCM_STREAM_CAPTURE)
+               s->ac97_slot_bits <<= 16;
        return 0;
 }
 
@@ -163,6 +154,8 @@ static int psc_ac97_hw_digital_params(struct snd_pcm_substream *substream,
 {
        struct psc_dma *psc_dma = cpu_dai->private_data;
 
+       dev_dbg(psc_dma->dev, "%s(substream=%p)\n", __func__, substream);
+
        if (params_channels(params) == 1)
                out_be32(&psc_dma->psc_regs->ac97_slots, 0x01000000);
        else
@@ -176,14 +169,24 @@ static int psc_ac97_trigger(struct snd_pcm_substream *substream, int cmd,
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct psc_dma *psc_dma = rtd->dai->cpu_dai->private_data;
+       struct psc_dma_stream *s = to_psc_dma_stream(substream, psc_dma);
 
        switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+               dev_dbg(psc_dma->dev, "AC97 START: stream=%i\n",
+                       substream->pstr->stream);
+
+               /* Set the slot enable bits */
+               psc_dma->slots |= s->ac97_slot_bits;
+               out_be32(&psc_dma->psc_regs->ac97_slots, psc_dma->slots);
+               break;
+
        case SNDRV_PCM_TRIGGER_STOP:
-               if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE)
-                       psc_dma->slots &= 0xFFFF0000;
-               else
-                       psc_dma->slots &= 0x0000FFFF;
+               dev_dbg(psc_dma->dev, "AC97 STOP: stream=%i\n",
+                       substream->pstr->stream);
 
+               /* Clear the slot enable bits */
+               psc_dma->slots &= ~(s->ac97_slot_bits);
                out_be32(&psc_dma->psc_regs->ac97_slots, psc_dma->slots);
                break;
        }
index e4dcb53..0267d2d 100644 (file)
@@ -157,7 +157,7 @@ static int mx27vis_hifi_hw_params(struct snd_pcm_substream *substream,
 
 
        /* codec PLL input is 25 MHz */
-       ret = codec_dai->ops->set_pll(codec_dai, IGNORED_ARG,
+       ret = codec_dai->ops->set_pll(codec_dai, IGNORED_ARG, IGNORED_ARG,
                                        25000000, pll_out);
        if (ret < 0) {
                printk(KERN_ERR "Error when setting PLL input\n");
index 653a362..61952aa 100644 (file)
@@ -43,12 +43,13 @@ config SND_OMAP_SOC_OSK5912
          Say Y if you want to add support for SoC audio on osk5912.
 
 config SND_OMAP_SOC_OVERO
-       tristate "SoC Audio support for Gumstix Overo"
-       depends on TWL4030_CORE && SND_OMAP_SOC && MACH_OVERO
+       tristate "SoC Audio support for Gumstix Overo and CompuLab CM-T35"
+       depends on TWL4030_CORE && SND_OMAP_SOC && (MACH_OVERO || MACH_CM_T35)
        select SND_OMAP_SOC_MCBSP
        select SND_SOC_TWL4030
        help
-         Say Y if you want to add support for SoC audio on the Gumstix Overo.
+         Say Y if you want to add support for SoC audio on the
+         Gumstix Overo or CompuLab CM-T35
 
 config SND_OMAP_SOC_OMAP2EVM
        tristate "SoC Audio support for OMAP2EVM board"
@@ -66,6 +67,15 @@ config SND_OMAP_SOC_OMAP3EVM
        help
          Say Y if you want to add support for SoC audio on the omap3evm board.
 
+config SND_OMAP_SOC_AM3517EVM
+       tristate "SoC Audio support for OMAP3517 / AM3517 EVM"
+       depends on SND_OMAP_SOC && MACH_OMAP3517EVM && I2C
+       select SND_OMAP_SOC_MCBSP
+       select SND_SOC_TLV320AIC23
+       help
+         Say Y if you want to add support for SoC audio on the OMAP3517 / AM3517
+         EVM.
+
 config SND_OMAP_SOC_SDP3430
        tristate "SoC Audio support for Texas Instruments SDP3430"
        depends on TWL4030_CORE && SND_OMAP_SOC && MACH_OMAP_3430SDP
@@ -99,3 +109,10 @@ config SND_OMAP_SOC_ZOOM2
        help
          Say Y if you want to add support for Soc audio on Zoom2 board.
 
+config SND_OMAP_SOC_IGEP0020
+       tristate "SoC Audio support for IGEP v2"
+       depends on TWL4030_CORE && SND_OMAP_SOC && MACH_IGEP0020
+       select SND_OMAP_SOC_MCBSP
+       select SND_SOC_TWL4030
+       help
+         Say Y if you want to add support for Soc audio on IGEP v2 board.
index 02d6947..d49458a 100644 (file)
@@ -12,10 +12,12 @@ snd-soc-osk5912-objs := osk5912.o
 snd-soc-overo-objs := overo.o
 snd-soc-omap2evm-objs := omap2evm.o
 snd-soc-omap3evm-objs := omap3evm.o
+snd-soc-am3517evm-objs := am3517evm.o
 snd-soc-sdp3430-objs := sdp3430.o
 snd-soc-omap3pandora-objs := omap3pandora.o
 snd-soc-omap3beagle-objs := omap3beagle.o
 snd-soc-zoom2-objs := zoom2.o
+snd-soc-igep0020-objs := igep0020.o
 
 obj-$(CONFIG_SND_OMAP_SOC_N810) += snd-soc-n810.o
 obj-$(CONFIG_SND_OMAP_SOC_AMS_DELTA) += snd-soc-ams-delta.o
@@ -23,7 +25,9 @@ obj-$(CONFIG_SND_OMAP_SOC_OSK5912) += snd-soc-osk5912.o
 obj-$(CONFIG_SND_OMAP_SOC_OVERO) += snd-soc-overo.o
 obj-$(CONFIG_MACH_OMAP2EVM) += snd-soc-omap2evm.o
 obj-$(CONFIG_MACH_OMAP3EVM) += snd-soc-omap3evm.o
+obj-$(CONFIG_MACH_OMAP3517EVM) += snd-soc-am3517evm.o
 obj-$(CONFIG_SND_OMAP_SOC_SDP3430) += snd-soc-sdp3430.o
 obj-$(CONFIG_SND_OMAP_SOC_OMAP3_PANDORA) += snd-soc-omap3pandora.o
 obj-$(CONFIG_SND_OMAP_SOC_OMAP3_BEAGLE) += snd-soc-omap3beagle.o
 obj-$(CONFIG_SND_OMAP_SOC_ZOOM2) += snd-soc-zoom2.o
+obj-$(CONFIG_SND_OMAP_SOC_IGEP0020) += snd-soc-igep0020.o
diff --git a/sound/soc/omap/am3517evm.c b/sound/soc/omap/am3517evm.c
new file mode 100644 (file)
index 0000000..135901b
--- /dev/null
@@ -0,0 +1,202 @@
+/*
+ * am3517evm.c  -- ALSA SoC support for OMAP3517 / AM3517 EVM
+ *
+ * Author: Anuj Aggarwal <anuj.aggarwal@ti.com>
+ *
+ * Based on sound/soc/omap/beagle.c by Steve Sakoman
+ *
+ * Copyright (C) 2009 Texas Instruments Incorporated
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any kind,
+ * whether express or implied; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+
+#include <asm/mach-types.h>
+#include <mach/hardware.h>
+#include <mach/gpio.h>
+#include <plat/mcbsp.h>
+
+#include "omap-mcbsp.h"
+#include "omap-pcm.h"
+
+#include "../codecs/tlv320aic23.h"
+
+#define CODEC_CLOCK    12000000
+
+static int am3517evm_hw_params(struct snd_pcm_substream *substream,
+       struct snd_pcm_hw_params *params)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
+       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+       int ret;
+
+       /* Set codec DAI configuration */
+       ret = snd_soc_dai_set_fmt(codec_dai,
+                                 SND_SOC_DAIFMT_DSP_B |
+                                 SND_SOC_DAIFMT_NB_NF |
+                                 SND_SOC_DAIFMT_CBM_CFM);
+       if (ret < 0) {
+               printk(KERN_ERR "can't set codec DAI configuration\n");
+               return ret;
+       }
+
+       /* Set cpu DAI configuration */
+       ret = snd_soc_dai_set_fmt(cpu_dai,
+                                 SND_SOC_DAIFMT_DSP_B |
+                                 SND_SOC_DAIFMT_NB_NF |
+                                 SND_SOC_DAIFMT_CBM_CFM);
+       if (ret < 0) {
+               printk(KERN_ERR "can't set cpu DAI configuration\n");
+               return ret;
+       }
+
+       /* Set the codec system clock for DAC and ADC */
+       ret = snd_soc_dai_set_sysclk(codec_dai, 0,
+                       CODEC_CLOCK, SND_SOC_CLOCK_IN);
+       if (ret < 0) {
+               printk(KERN_ERR "can't set codec system clock\n");
+               return ret;
+       }
+
+       ret = snd_soc_dai_set_sysclk(cpu_dai, OMAP_MCBSP_CLKR_SRC_CLKX, 0,
+                               SND_SOC_CLOCK_IN);
+       if (ret < 0) {
+               printk(KERN_ERR "can't set CPU system clock OMAP_MCBSP_CLKR_SRC_CLKX\n");
+               return ret;
+       }
+
+       snd_soc_dai_set_sysclk(cpu_dai, OMAP_MCBSP_FSR_SRC_FSX, 0,
+                               SND_SOC_CLOCK_IN);
+       if (ret < 0) {
+               printk(KERN_ERR "can't set CPU system clock OMAP_MCBSP_FSR_SRC_FSX\n");
+               return ret;
+       }
+
+       return 0;
+}
+
+static struct snd_soc_ops am3517evm_ops = {
+       .hw_params = am3517evm_hw_params,
+};
+
+/* am3517evm machine dapm widgets */
+static const struct snd_soc_dapm_widget tlv320aic23_dapm_widgets[] = {
+       SND_SOC_DAPM_HP("Line Out", NULL),
+       SND_SOC_DAPM_LINE("Line In", NULL),
+       SND_SOC_DAPM_MIC("Mic In", NULL),
+};
+
+static const struct snd_soc_dapm_route audio_map[] = {
+       /* Line Out connected to LLOUT, RLOUT */
+       {"Line Out", NULL, "LOUT"},
+       {"Line Out", NULL, "ROUT"},
+
+       {"LLINEIN", NULL, "Line In"},
+       {"RLINEIN", NULL, "Line In"},
+
+       {"MICIN", NULL, "Mic In"},
+};
+
+static int am3517evm_aic23_init(struct snd_soc_codec *codec)
+{
+       /* Add am3517-evm specific widgets */
+       snd_soc_dapm_new_controls(codec, tlv320aic23_dapm_widgets,
+                                 ARRAY_SIZE(tlv320aic23_dapm_widgets));
+
+       /* Set up davinci-evm specific audio path audio_map */
+       snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
+
+       /* always connected */
+       snd_soc_dapm_enable_pin(codec, "Line Out");
+       snd_soc_dapm_enable_pin(codec, "Line In");
+       snd_soc_dapm_enable_pin(codec, "Mic In");
+
+       snd_soc_dapm_sync(codec);
+
+       return 0;
+}
+
+/* Digital audio interface glue - connects codec <--> CPU */
+static struct snd_soc_dai_link am3517evm_dai = {
+       .name = "TLV320AIC23",
+       .stream_name = "AIC23",
+       .cpu_dai = &omap_mcbsp_dai[0],
+       .codec_dai = &tlv320aic23_dai,
+       .init = am3517evm_aic23_init,
+       .ops = &am3517evm_ops,
+};
+
+/* Audio machine driver */
+static struct snd_soc_card snd_soc_am3517evm = {
+       .name = "am3517evm",
+       .platform = &omap_soc_platform,
+       .dai_link = &am3517evm_dai,
+       .num_links = 1,
+};
+
+/* Audio subsystem */
+static struct snd_soc_device am3517evm_snd_devdata = {
+       .card = &snd_soc_am3517evm,
+       .codec_dev = &soc_codec_dev_tlv320aic23,
+};
+
+static struct platform_device *am3517evm_snd_device;
+
+static int __init am3517evm_soc_init(void)
+{
+       int ret;
+
+       if (!machine_is_omap3517evm()) {
+               pr_err("Not OMAP3517 / AM3517 EVM!\n");
+               return -ENODEV;
+       }
+       pr_info("OMAP3517 / AM3517 EVM SoC init\n");
+
+       am3517evm_snd_device = platform_device_alloc("soc-audio", -1);
+       if (!am3517evm_snd_device) {
+               printk(KERN_ERR "Platform device allocation failed\n");
+               return -ENOMEM;
+       }
+
+       platform_set_drvdata(am3517evm_snd_device, &am3517evm_snd_devdata);
+       am3517evm_snd_devdata.dev = &am3517evm_snd_device->dev;
+       *(unsigned int *)am3517evm_dai.cpu_dai->private_data = 0; /* McBSP1 */
+
+       ret = platform_device_add(am3517evm_snd_device);
+       if (ret)
+               goto err1;
+
+       return 0;
+
+err1:
+       printk(KERN_ERR "Unable to add platform device\n");
+       platform_device_put(am3517evm_snd_device);
+
+       return ret;
+}
+
+static void __exit am3517evm_soc_exit(void)
+{
+       platform_device_unregister(am3517evm_snd_device);
+}
+
+module_init(am3517evm_soc_init);
+module_exit(am3517evm_soc_exit);
+
+MODULE_AUTHOR("Anuj Aggarwal <anuj.aggarwal@ti.com>");
+MODULE_DESCRIPTION("ALSA SoC OMAP3517 / AM3517 EVM");
+MODULE_LICENSE("GPL v2");
index 5a5166a..b0f618e 100644 (file)
@@ -31,8 +31,8 @@
 
 #include <asm/mach-types.h>
 
-#include <mach/board-ams-delta.h>
-#include <mach/mcbsp.h>
+#include <plat/board-ams-delta.h>
+#include <plat/mcbsp.h>
 
 #include "omap-mcbsp.h"
 #include "omap-pcm.h"
@@ -40,7 +40,7 @@
 
 
 /* Board specific DAPM widgets */
- const struct snd_soc_dapm_widget ams_delta_dapm_widgets[] = {
+static const struct snd_soc_dapm_widget ams_delta_dapm_widgets[] = {
        /* Handset */
        SND_SOC_DAPM_MIC("Mouthpiece", NULL),
        SND_SOC_DAPM_HP("Earpiece", NULL),
@@ -81,7 +81,7 @@ static const char *ams_delta_audio_mode[] =
                                                (1 << AMS_DELTA_SPEAKER))
 #define AMS_DELTA_SPEAKERPHONE (AMS_DELTA_HANDSFREE | (1 << AMS_DELTA_AGC))
 
-unsigned short ams_delta_audio_mode_pins[] = {
+static const unsigned short ams_delta_audio_mode_pins[] = {
        AMS_DELTA_MIXED,
        AMS_DELTA_HANDSET,
        AMS_DELTA_HANDSFREE,
diff --git a/sound/soc/omap/igep0020.c b/sound/soc/omap/igep0020.c
new file mode 100644 (file)
index 0000000..3583c42
--- /dev/null
@@ -0,0 +1,148 @@
+/*
+ * igep0020.c  --  SoC audio for IGEP v2
+ *
+ * Based on sound/soc/omap/overo.c by Steve Sakoman
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+
+#include <asm/mach-types.h>
+#include <mach/hardware.h>
+#include <mach/gpio.h>
+#include <plat/mcbsp.h>
+
+#include "omap-mcbsp.h"
+#include "omap-pcm.h"
+#include "../codecs/twl4030.h"
+
+static int igep2_hw_params(struct snd_pcm_substream *substream,
+       struct snd_pcm_hw_params *params)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
+       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+       int ret;
+
+       /* Set codec DAI configuration */
+       ret = snd_soc_dai_set_fmt(codec_dai,
+                                 SND_SOC_DAIFMT_I2S |
+                                 SND_SOC_DAIFMT_NB_NF |
+                                 SND_SOC_DAIFMT_CBM_CFM);
+       if (ret < 0) {
+               printk(KERN_ERR "can't set codec DAI configuration\n");
+               return ret;
+       }
+
+       /* Set cpu DAI configuration */
+       ret = snd_soc_dai_set_fmt(cpu_dai,
+                                 SND_SOC_DAIFMT_I2S |
+                                 SND_SOC_DAIFMT_NB_NF |
+                                 SND_SOC_DAIFMT_CBM_CFM);
+       if (ret < 0) {
+               printk(KERN_ERR "can't set cpu DAI configuration\n");
+               return ret;
+       }
+
+       /* Set the codec system clock for DAC and ADC */
+       ret = snd_soc_dai_set_sysclk(codec_dai, 0, 26000000,
+                                           SND_SOC_CLOCK_IN);
+       if (ret < 0) {
+               printk(KERN_ERR "can't set codec system clock\n");
+               return ret;
+       }
+
+       return 0;
+}
+
+static struct snd_soc_ops igep2_ops = {
+       .hw_params = igep2_hw_params,
+};
+
+/* Digital audio interface glue - connects codec <--> CPU */
+static struct snd_soc_dai_link igep2_dai = {
+       .name = "TWL4030",
+       .stream_name = "TWL4030",
+       .cpu_dai = &omap_mcbsp_dai[0],
+       .codec_dai = &twl4030_dai[TWL4030_DAI_HIFI],
+       .ops = &igep2_ops,
+};
+
+/* Audio machine driver */
+static struct snd_soc_card snd_soc_card_igep2 = {
+       .name = "igep2",
+       .platform = &omap_soc_platform,
+       .dai_link = &igep2_dai,
+       .num_links = 1,
+};
+
+/* Audio subsystem */
+static struct snd_soc_device igep2_snd_devdata = {
+       .card = &snd_soc_card_igep2,
+       .codec_dev = &soc_codec_dev_twl4030,
+};
+
+static struct platform_device *igep2_snd_device;
+
+static int __init igep2_soc_init(void)
+{
+       int ret;
+
+       if (!machine_is_igep0020()) {
+               pr_debug("Not IGEP v2!\n");
+               return -ENODEV;
+       }
+       printk(KERN_INFO "IGEP v2 SoC init\n");
+
+       igep2_snd_device = platform_device_alloc("soc-audio", -1);
+       if (!igep2_snd_device) {
+               printk(KERN_ERR "Platform device allocation failed\n");
+               return -ENOMEM;
+       }
+
+       platform_set_drvdata(igep2_snd_device, &igep2_snd_devdata);
+       igep2_snd_devdata.dev = &igep2_snd_device->dev;
+       *(unsigned int *)igep2_dai.cpu_dai->private_data = 1; /* McBSP2 */
+
+       ret = platform_device_add(igep2_snd_device);
+       if (ret)
+               goto err1;
+
+       return 0;
+
+err1:
+       printk(KERN_ERR "Unable to add platform device\n");
+       platform_device_put(igep2_snd_device);
+
+       return ret;
+}
+module_init(igep2_soc_init);
+
+static void __exit igep2_soc_exit(void)
+{
+       platform_device_unregister(igep2_snd_device);
+}
+module_exit(igep2_soc_exit);
+
+MODULE_AUTHOR("Enric Balletbo i Serra <eballetbo@iseebcn.com>");
+MODULE_DESCRIPTION("ALSA SoC IGEP v2");
+MODULE_LICENSE("GPL");
index 0a50593..08e09d7 100644 (file)
@@ -32,7 +32,7 @@
 #include <asm/mach-types.h>
 #include <mach/hardware.h>
 #include <linux/gpio.h>
-#include <mach/mcbsp.h>
+#include <plat/mcbsp.h>
 
 #include "omap-mcbsp.h"
 #include "omap-pcm.h"
index 3341f49..6bbbd2a 100644 (file)
@@ -31,9 +31,9 @@
 #include <sound/initval.h>
 #include <sound/soc.h>
 
-#include <mach/control.h>
-#include <mach/dma.h>
-#include <mach/mcbsp.h>
+#include <plat/control.h>
+#include <plat/dma.h>
+#include <plat/mcbsp.h>
 #include "omap-mcbsp.h"
 #include "omap-pcm.h"
 
@@ -49,6 +49,8 @@ struct omap_mcbsp_data {
         */
        int                             active;
        int                             configured;
+       unsigned int                    in_freq;
+       int                             clk_div;
 };
 
 #define to_mcbsp(priv) container_of((priv), struct omap_mcbsp_data, bus_id)
@@ -257,7 +259,7 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream,
        int dma, bus_id = mcbsp_data->bus_id, id = cpu_dai->id;
        int wlen, channels, wpf, sync_mode = OMAP_DMA_SYNC_ELEMENT;
        unsigned long port;
-       unsigned int format;
+       unsigned int format, div, framesize, master;
 
        if (cpu_class_is_omap1()) {
                dma = omap1_dma_reqs[bus_id][substream->stream];
@@ -294,28 +296,19 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream,
 
        format = mcbsp_data->fmt & SND_SOC_DAIFMT_FORMAT_MASK;
        wpf = channels = params_channels(params);
-       switch (channels) {
-       case 2:
-               if (format == SND_SOC_DAIFMT_I2S) {
-                       /* Use dual-phase frames */
-                       regs->rcr2      |= RPHASE;
-                       regs->xcr2      |= XPHASE;
-                       /* Set 1 word per (McBSP) frame for phase1 and phase2 */
-                       wpf--;
-                       regs->rcr2      |= RFRLEN2(wpf - 1);
-                       regs->xcr2      |= XFRLEN2(wpf - 1);
-               }
-       case 1:
-       case 4:
-               /* Set word per (McBSP) frame for phase1 */
-               regs->rcr1      |= RFRLEN1(wpf - 1);
-               regs->xcr1      |= XFRLEN1(wpf - 1);
-               break;
-       default:
-               /* Unsupported number of channels */
-               return -EINVAL;
+       if (channels == 2 && format == SND_SOC_DAIFMT_I2S) {
+               /* Use dual-phase frames */
+               regs->rcr2      |= RPHASE;
+               regs->xcr2      |= XPHASE;
+               /* Set 1 word per (McBSP) frame for phase1 and phase2 */
+               wpf--;
+               regs->rcr2      |= RFRLEN2(wpf - 1);
+               regs->xcr2      |= XFRLEN2(wpf - 1);
        }
 
+       regs->rcr1      |= RFRLEN1(wpf - 1);
+       regs->xcr1      |= XFRLEN1(wpf - 1);
+
        switch (params_format(params)) {
        case SNDRV_PCM_FORMAT_S16_LE:
                /* Set word lengths */
@@ -330,15 +323,30 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream,
                return -EINVAL;
        }
 
+       /* In McBSP master modes, FRAME (i.e. sample rate) is generated
+        * by _counting_ BCLKs. Calculate frame size in BCLKs */
+       master = mcbsp_data->fmt & SND_SOC_DAIFMT_MASTER_MASK;
+       if (master ==   SND_SOC_DAIFMT_CBS_CFS) {
+               div = mcbsp_data->clk_div ? mcbsp_data->clk_div : 1;
+               framesize = (mcbsp_data->in_freq / div) / params_rate(params);
+
+               if (framesize < wlen * channels) {
+                       printk(KERN_ERR "%s: not enough bandwidth for desired rate and "
+                                       "channels\n", __func__);
+                       return -EINVAL;
+               }
+       } else
+               framesize = wlen * channels;
+
        /* Set FS period and length in terms of bit clock periods */
        switch (format) {
        case SND_SOC_DAIFMT_I2S:
-               regs->srgr2     |= FPER(wlen * channels - 1);
-               regs->srgr1     |= FWID(wlen - 1);
+               regs->srgr2     |= FPER(framesize - 1);
+               regs->srgr1     |= FWID((framesize >> 1) - 1);
                break;
        case SND_SOC_DAIFMT_DSP_A:
        case SND_SOC_DAIFMT_DSP_B:
-               regs->srgr2     |= FPER(wlen * channels - 1);
+               regs->srgr2     |= FPER(framesize - 1);
                regs->srgr1     |= FWID(0);
                break;
        }
@@ -454,6 +462,7 @@ static int omap_mcbsp_dai_set_clkdiv(struct snd_soc_dai *cpu_dai,
        if (div_id != OMAP_MCBSP_CLKGDV)
                return -ENODEV;
 
+       mcbsp_data->clk_div = div;
        regs->srgr1     |= CLKGDV(div - 1);
 
        return 0;
@@ -554,6 +563,8 @@ static int omap_mcbsp_dai_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
        struct omap_mcbsp_reg_cfg *regs = &mcbsp_data->regs;
        int err = 0;
 
+       mcbsp_data->in_freq = freq;
+
        switch (clk_id) {
        case OMAP_MCBSP_SYSCLK_CLK:
                regs->srgr2     |= CLKSM;
@@ -598,13 +609,13 @@ static struct snd_soc_dai_ops omap_mcbsp_dai_ops = {
        .id = (link_id),                                        \
        .playback = {                                           \
                .channels_min = 1,                              \
-               .channels_max = 4,                              \
+               .channels_max = 16,                             \
                .rates = OMAP_MCBSP_RATES,                      \
                .formats = SNDRV_PCM_FMTBIT_S16_LE,             \
        },                                                      \
        .capture = {                                            \
                .channels_min = 1,                              \
-               .channels_max = 4,                              \
+               .channels_max = 16,                             \
                .rates = OMAP_MCBSP_RATES,                      \
                .formats = SNDRV_PCM_FMTBIT_S16_LE,             \
        },                                                      \
index 6a829ee..9db2770 100644 (file)
@@ -28,7 +28,7 @@
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
 
-#include <mach/dma.h>
+#include <plat/dma.h>
 #include "omap-pcm.h"
 
 static const struct snd_pcm_hardware omap_pcm_hardware = {
index 027e1a4..c7adea3 100644 (file)
@@ -31,7 +31,7 @@
 #include <asm/mach-types.h>
 #include <mach/hardware.h>
 #include <mach/gpio.h>
-#include <mach/mcbsp.h>
+#include <plat/mcbsp.h>
 
 #include "omap-mcbsp.h"
 #include "omap-pcm.h"
index b0cff9f..d88ad5c 100644 (file)
@@ -29,7 +29,7 @@
 #include <asm/mach-types.h>
 #include <mach/hardware.h>
 #include <mach/gpio.h>
-#include <mach/mcbsp.h>
+#include <plat/mcbsp.h>
 
 #include "omap-mcbsp.h"
 #include "omap-pcm.h"
index 13aa380..dfcb344 100644 (file)
@@ -27,7 +27,7 @@
 #include <asm/mach-types.h>
 #include <mach/hardware.h>
 #include <mach/gpio.h>
-#include <mach/mcbsp.h>
+#include <plat/mcbsp.h>
 
 #include "omap-mcbsp.h"
 #include "omap-pcm.h"
@@ -93,10 +93,17 @@ static struct snd_soc_card snd_soc_omap3evm = {
        .num_links = 1,
 };
 
+/* twl4030 setup */
+static struct twl4030_setup_data twl4030_setup = {
+       .ramp_delay_value = 4,
+       .sysclk = 26000,
+};
+
 /* Audio subsystem */
 static struct snd_soc_device omap3evm_snd_devdata = {
        .card = &snd_soc_omap3evm,
        .codec_dev = &soc_codec_dev_twl4030,
+       .codec_data = &twl4030_setup,
 };
 
 static struct platform_device *omap3evm_snd_device;
index 0cd06f5..71b2c16 100644 (file)
 
 #define PREFIX "ASoC omap3pandora: "
 
-static int omap3pandora_cmn_hw_params(struct snd_soc_dai *codec_dai,
-       struct snd_soc_dai *cpu_dai, unsigned int fmt)
+static int omap3pandora_cmn_hw_params(struct snd_pcm_substream *substream,
+       struct snd_pcm_hw_params *params, unsigned int fmt)
 {
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
+       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
        int ret;
 
        /* Set codec DAI configuration */
@@ -68,8 +71,9 @@ static int omap3pandora_cmn_hw_params(struct snd_soc_dai *codec_dai,
        }
 
        /* Set McBSP clock to external */
-       ret = snd_soc_dai_set_sysclk(cpu_dai, OMAP_MCBSP_SYSCLK_CLKS_EXT, 0,
-                                           SND_SOC_CLOCK_IN);
+       ret = snd_soc_dai_set_sysclk(cpu_dai, OMAP_MCBSP_SYSCLK_CLKS_EXT,
+                                    256 * params_rate(params),
+                                    SND_SOC_CLOCK_IN);
        if (ret < 0) {
                pr_err(PREFIX "can't set cpu system clock\n");
                return ret;
@@ -87,11 +91,7 @@ static int omap3pandora_cmn_hw_params(struct snd_soc_dai *codec_dai,
 static int omap3pandora_out_hw_params(struct snd_pcm_substream *substream,
        struct snd_pcm_hw_params *params)
 {
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
-       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
-
-       return omap3pandora_cmn_hw_params(codec_dai, cpu_dai,
+       return omap3pandora_cmn_hw_params(substream, params,
                                          SND_SOC_DAIFMT_I2S |
                                          SND_SOC_DAIFMT_IB_NF |
                                          SND_SOC_DAIFMT_CBS_CFS);
@@ -100,11 +100,7 @@ static int omap3pandora_out_hw_params(struct snd_pcm_substream *substream,
 static int omap3pandora_in_hw_params(struct snd_pcm_substream *substream,
        struct snd_pcm_hw_params *params)
 {
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
-       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
-
-       return omap3pandora_cmn_hw_params(codec_dai, cpu_dai,
+       return omap3pandora_cmn_hw_params(substream, params,
                                          SND_SOC_DAIFMT_I2S |
                                          SND_SOC_DAIFMT_NB_NF |
                                          SND_SOC_DAIFMT_CBS_CFS);
index a4e149b..498ca2e 100644 (file)
@@ -31,7 +31,7 @@
 #include <asm/mach-types.h>
 #include <mach/hardware.h>
 #include <linux/gpio.h>
-#include <mach/mcbsp.h>
+#include <plat/mcbsp.h>
 
 #include "omap-mcbsp.h"
 #include "omap-pcm.h"
index ec4f8fd..c25f527 100644 (file)
@@ -29,7 +29,7 @@
 #include <asm/mach-types.h>
 #include <mach/hardware.h>
 #include <mach/gpio.h>
-#include <mach/mcbsp.h>
+#include <plat/mcbsp.h>
 
 #include "omap-mcbsp.h"
 #include "omap-pcm.h"
@@ -107,8 +107,8 @@ static int __init overo_soc_init(void)
 {
        int ret;
 
-       if (!machine_is_overo()) {
-               pr_debug("Not Overo!\n");
+       if (!(machine_is_overo() || machine_is_cm_t35())) {
+               pr_debug("Incomatible machine!\n");
                return -ENODEV;
        }
        printk(KERN_INFO "overo SoC init\n");
index 4a3f62d..c071f96 100644 (file)
@@ -34,7 +34,7 @@
 #include <asm/mach-types.h>
 #include <mach/hardware.h>
 #include <mach/gpio.h>
-#include <mach/mcbsp.h>
+#include <plat/mcbsp.h>
 
 #include "omap-mcbsp.h"
 #include "omap-pcm.h"
index f90b45f..f90a2ac 100644 (file)
@@ -29,7 +29,7 @@
 #include <asm/mach-types.h>
 #include <mach/hardware.h>
 #include <mach/gpio.h>
-#include <mach/mcbsp.h>
+#include <plat/mcbsp.h>
 
 #include "omap-mcbsp.h"
 #include "omap-pcm.h"
index dcb3181..376e14a 100644 (file)
@@ -90,7 +90,8 @@ config SND_PXA2XX_SOC_E800
 
 config SND_PXA2XX_SOC_EM_X270
        tristate "SoC Audio support for CompuLab EM-x270, eXeda and CM-X300"
-       depends on SND_PXA2XX_SOC && MACH_EM_X270
+       depends on SND_PXA2XX_SOC && (MACH_EM_X270 || MACH_EXEDA || \
+                       MACH_CM_X300)
        select SND_PXA2XX_SOC_AC97
        select SND_SOC_WM9712
        help
@@ -117,6 +118,15 @@ config SND_SOC_ZYLONITE
          Say Y if you want to add support for SoC audio on the
          Marvell Zylonite reference platform.
 
+config SND_SOC_RAUMFELD
+       tristate "SoC Audio support Raumfeld audio adapter"
+       depends on SND_PXA2XX_SOC && (MACH_RAUMFELD_SPEAKER || MACH_RAUMFELD_CONNECTOR)
+       select SND_PXA_SOC_SSP
+       select SND_SOC_CS4270
+       select SND_SOC_AK4104
+       help
+         Say Y if you want to add support for SoC audio on Raumfeld devices
+
 config SND_PXA2XX_SOC_MAGICIAN
        tristate "SoC Audio support for HTC Magician"
        depends on SND_PXA2XX_SOC && MACH_MAGICIAN
index 6e096b4..f3e08fd 100644 (file)
@@ -23,6 +23,7 @@ snd-soc-zylonite-objs := zylonite.o
 snd-soc-magician-objs := magician.o
 snd-soc-mioa701-objs := mioa701_wm9713.o
 snd-soc-imote2-objs := imote2.o
+snd-soc-raumfeld-objs := raumfeld.o
 
 obj-$(CONFIG_SND_PXA2XX_SOC_CORGI) += snd-soc-corgi.o
 obj-$(CONFIG_SND_PXA2XX_SOC_POODLE) += snd-soc-poodle.o
@@ -37,3 +38,4 @@ obj-$(CONFIG_SND_PXA2XX_SOC_MAGICIAN) += snd-soc-magician.o
 obj-$(CONFIG_SND_PXA2XX_SOC_MIOA701) += snd-soc-mioa701.o
 obj-$(CONFIG_SND_SOC_ZYLONITE) += snd-soc-zylonite.o
 obj-$(CONFIG_SND_PXA2XX_SOC_IMOTE2) += snd-soc-imote2.o
+obj-$(CONFIG_SND_SOC_RAUMFELD) += snd-soc-raumfeld.o
index 9f7c61e..4c8d99a 100644 (file)
@@ -213,7 +213,7 @@ static int magician_playback_hw_params(struct snd_pcm_substream *substream,
                return ret;
 
        /* set SSP audio pll clock */
-       ret = snd_soc_dai_set_pll(cpu_dai, 0, 0, acps);
+       ret = snd_soc_dai_set_pll(cpu_dai, 0, 0, 0, acps);
        if (ret < 0)
                return ret;
 
index d11a6d7..3bd7712 100644 (file)
@@ -305,8 +305,8 @@ static int pxa_ssp_set_dai_clkdiv(struct snd_soc_dai *cpu_dai,
 /*
  * Configure the PLL frequency pxa27x and (afaik - pxa320 only)
  */
-static int pxa_ssp_set_dai_pll(struct snd_soc_dai *cpu_dai,
-       int pll_id, unsigned int freq_in, unsigned int freq_out)
+static int pxa_ssp_set_dai_pll(struct snd_soc_dai *cpu_dai, int pll_id,
+       int source, unsigned int freq_in, unsigned int freq_out)
 {
        struct ssp_priv *priv = cpu_dai->private_data;
        struct ssp_device *ssp = priv->dev.ssp;
@@ -760,13 +760,13 @@ struct snd_soc_dai pxa_ssp_dai[] = {
                .resume = pxa_ssp_resume,
                .playback = {
                        .channels_min = 1,
-                       .channels_max = 2,
+                       .channels_max = 8,
                        .rates = PXA_SSP_RATES,
                        .formats = PXA_SSP_FORMATS,
                },
                .capture = {
                         .channels_min = 1,
-                        .channels_max = 2,
+                        .channels_max = 8,
                        .rates = PXA_SSP_RATES,
                        .formats = PXA_SSP_FORMATS,
                 },
@@ -780,13 +780,13 @@ struct snd_soc_dai pxa_ssp_dai[] = {
                .resume = pxa_ssp_resume,
                .playback = {
                        .channels_min = 1,
-                       .channels_max = 2,
+                       .channels_max = 8,
                        .rates = PXA_SSP_RATES,
                        .formats = PXA_SSP_FORMATS,
                },
                .capture = {
                        .channels_min = 1,
-                       .channels_max = 2,
+                       .channels_max = 8,
                        .rates = PXA_SSP_RATES,
                        .formats = PXA_SSP_FORMATS,
                 },
@@ -801,13 +801,13 @@ struct snd_soc_dai pxa_ssp_dai[] = {
                .resume = pxa_ssp_resume,
                .playback = {
                        .channels_min = 1,
-                       .channels_max = 2,
+                       .channels_max = 8,
                        .rates = PXA_SSP_RATES,
                        .formats = PXA_SSP_FORMATS,
                },
                .capture = {
                        .channels_min = 1,
-                       .channels_max = 2,
+                       .channels_max = 8,
                        .rates = PXA_SSP_RATES,
                        .formats = PXA_SSP_FORMATS,
                 },
@@ -822,13 +822,13 @@ struct snd_soc_dai pxa_ssp_dai[] = {
                .resume = pxa_ssp_resume,
                .playback = {
                        .channels_min = 1,
-                       .channels_max = 2,
+                       .channels_max = 8,
                        .rates = PXA_SSP_RATES,
                        .formats = PXA_SSP_FORMATS,
                },
                .capture = {
                        .channels_min = 1,
-                       .channels_max = 2,
+                       .channels_max = 8,
                        .rates = PXA_SSP_RATES,
                        .formats = PXA_SSP_FORMATS,
                 },
diff --git a/sound/soc/pxa/raumfeld.c b/sound/soc/pxa/raumfeld.c
new file mode 100644 (file)
index 0000000..acfce1c
--- /dev/null
@@ -0,0 +1,335 @@
+/*
+ * raumfeld_audio.c  --  SoC audio for Raumfeld audio devices
+ *
+ * Copyright (c) 2009 Daniel Mack <daniel@caiaq.de>
+ *
+ * based on code from:
+ *
+ *    Wolfson Microelectronics PLC.
+ *    Openedhand Ltd.
+ *    Liam Girdwood <lrg@slimlogic.co.uk>
+ *    Richard Purdie <richard@openedhand.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/i2c.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+
+#include <asm/mach-types.h>
+
+#include "../codecs/cs4270.h"
+#include "../codecs/ak4104.h"
+#include "pxa2xx-pcm.h"
+#include "pxa-ssp.h"
+
+#define GPIO_SPDIF_RESET       (38)
+#define GPIO_MCLK_RESET                (111)
+#define GPIO_CODEC_RESET       (120)
+
+static struct i2c_client *max9486_client;
+static struct i2c_board_info max9486_hwmon_info = {
+       I2C_BOARD_INFO("max9485", 0x63),
+};
+
+#define MAX9485_MCLK_FREQ_112896 0x22
+#define        MAX9485_MCLK_FREQ_122880 0x23
+
+static void set_max9485_clk(char clk)
+{
+       i2c_master_send(max9486_client, &clk, 1);
+}
+
+static void raumfeld_enable_audio(bool en)
+{
+       if (en) {
+               gpio_set_value(GPIO_MCLK_RESET, 1);
+
+               /* wait some time to let the clocks become stable */
+               msleep(100);
+
+               gpio_set_value(GPIO_SPDIF_RESET, 1);
+               gpio_set_value(GPIO_CODEC_RESET, 1);
+       } else {
+               gpio_set_value(GPIO_MCLK_RESET, 0);
+               gpio_set_value(GPIO_SPDIF_RESET, 0);
+               gpio_set_value(GPIO_CODEC_RESET, 0);
+       }
+}
+
+/* CS4270 */
+static int raumfeld_cs4270_startup(struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
+
+       set_max9485_clk(MAX9485_MCLK_FREQ_112896);
+
+       return snd_soc_dai_set_sysclk(codec_dai, 0, 11289600, 0);
+}
+
+static int raumfeld_cs4270_hw_params(struct snd_pcm_substream *substream,
+                                    struct snd_pcm_hw_params *params)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
+       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+       unsigned int fmt, clk = 0;
+       int ret = 0;
+
+       switch (params_rate(params)) {
+       case 8000:
+       case 16000:
+       case 48000:
+       case 96000:
+               set_max9485_clk(MAX9485_MCLK_FREQ_122880);
+               clk = 12288000;
+               break;
+       case 11025:
+       case 22050:
+       case 44100:
+       case 88200:
+               set_max9485_clk(MAX9485_MCLK_FREQ_112896);
+               clk = 11289600;
+               break;
+       }
+
+       fmt = SND_SOC_DAIFMT_I2S |
+             SND_SOC_DAIFMT_NB_NF |
+             SND_SOC_DAIFMT_CBS_CFS;
+
+       /* setup the CODEC DAI */
+       ret = snd_soc_dai_set_fmt(codec_dai, fmt);
+       if (ret < 0)
+               return ret;
+
+       ret = snd_soc_dai_set_sysclk(codec_dai, 0, clk, 0);
+       if (ret < 0)
+               return ret;
+
+       /* setup the CPU DAI */
+       ret = snd_soc_dai_set_pll(cpu_dai, 0, 0, 0, clk);
+       if (ret < 0)
+               return ret;
+
+       ret = snd_soc_dai_set_fmt(cpu_dai, fmt);
+       if (ret < 0)
+               return ret;
+
+       ret = snd_soc_dai_set_clkdiv(cpu_dai, PXA_SSP_DIV_SCR, 4);
+       if (ret < 0)
+               return ret;
+
+       ret = snd_soc_dai_set_sysclk(cpu_dai, PXA_SSP_CLK_EXT, 0, 1);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+
+static struct snd_soc_ops raumfeld_cs4270_ops = {
+       .startup = raumfeld_cs4270_startup,
+       .hw_params = raumfeld_cs4270_hw_params,
+};
+
+static int raumfeld_line_suspend(struct platform_device *pdev, pm_message_t state)
+{
+       raumfeld_enable_audio(false);
+       return 0;
+}
+
+static int raumfeld_line_resume(struct platform_device *pdev)
+{
+       raumfeld_enable_audio(true);
+       return 0;
+}
+
+static struct snd_soc_dai_link raumfeld_line_dai = {
+       .name           = "CS4270",
+       .stream_name    = "CS4270",
+       .cpu_dai        = &pxa_ssp_dai[PXA_DAI_SSP1],
+       .codec_dai      = &cs4270_dai,
+       .ops            = &raumfeld_cs4270_ops,
+};
+
+static struct snd_soc_card snd_soc_line_raumfeld = {
+       .name           = "Raumfeld analog",
+       .platform       = &pxa2xx_soc_platform,
+       .dai_link       = &raumfeld_line_dai,
+       .suspend_post   = raumfeld_line_suspend,
+       .resume_pre     = raumfeld_line_resume,
+       .num_links      = 1,
+};
+
+
+/* AK4104 */
+
+static int raumfeld_ak4104_hw_params(struct snd_pcm_substream *substream,
+                                    struct snd_pcm_hw_params *params)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
+       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+       int fmt, ret = 0, clk = 0;
+
+       switch (params_rate(params)) {
+       case 8000:
+       case 16000:
+       case 48000:
+       case 96000:
+               set_max9485_clk(MAX9485_MCLK_FREQ_122880);
+               clk = 12288000;
+               break;
+       case 11025:
+       case 22050:
+       case 44100:
+       case 88200:
+               set_max9485_clk(MAX9485_MCLK_FREQ_112896);
+               clk = 11289600;
+               break;
+       }
+
+       fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF;
+
+       /* setup the CODEC DAI */
+       ret = snd_soc_dai_set_fmt(codec_dai, fmt | SND_SOC_DAIFMT_CBS_CFS);
+       if (ret < 0)
+               return ret;
+
+       /* setup the CPU DAI */
+       ret = snd_soc_dai_set_pll(cpu_dai, 0, 0, 0, clk);
+       if (ret < 0)
+               return ret;
+
+       ret = snd_soc_dai_set_fmt(cpu_dai, fmt | SND_SOC_DAIFMT_CBS_CFS);
+       if (ret < 0)
+               return ret;
+
+       ret = snd_soc_dai_set_clkdiv(cpu_dai, PXA_SSP_DIV_SCR, 4);
+       if (ret < 0)
+               return ret;
+
+       ret = snd_soc_dai_set_sysclk(cpu_dai, PXA_SSP_CLK_EXT, 0, 1);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+
+static struct snd_soc_ops raumfeld_ak4104_ops = {
+       .hw_params = raumfeld_ak4104_hw_params,
+};
+
+static struct snd_soc_dai_link raumfeld_spdif_dai = {
+       .name           = "ak4104",
+       .stream_name    = "Playback",
+       .cpu_dai        = &pxa_ssp_dai[PXA_DAI_SSP2],
+       .codec_dai      = &ak4104_dai,
+       .ops            = &raumfeld_ak4104_ops,
+};
+
+static struct snd_soc_card snd_soc_spdif_raumfeld = {
+       .name           = "Raumfeld S/PDIF",
+       .platform       = &pxa2xx_soc_platform,
+       .dai_link       = &raumfeld_spdif_dai,
+       .num_links      = 1
+};
+
+/* raumfeld_audio audio subsystem */
+static struct snd_soc_device raumfeld_line_devdata = {
+       .card = &snd_soc_line_raumfeld,
+       .codec_dev = &soc_codec_device_cs4270,
+};
+
+static struct snd_soc_device raumfeld_spdif_devdata = {
+       .card = &snd_soc_spdif_raumfeld,
+       .codec_dev = &soc_codec_device_ak4104,
+};
+
+static struct platform_device *raumfeld_audio_line_device;
+static struct platform_device *raumfeld_audio_spdif_device;
+
+static int __init raumfeld_audio_init(void)
+{
+       int ret;
+
+       if (!machine_is_raumfeld_speaker() &&
+           !machine_is_raumfeld_connector())
+               return 0;
+
+       max9486_client = i2c_new_device(i2c_get_adapter(0),
+                                       &max9486_hwmon_info);
+
+       if (!max9486_client)
+               return -ENOMEM;
+
+       set_max9485_clk(MAX9485_MCLK_FREQ_122880);
+
+       /* LINE */
+       raumfeld_audio_line_device = platform_device_alloc("soc-audio", 0);
+       if (!raumfeld_audio_line_device)
+               return -ENOMEM;
+
+       platform_set_drvdata(raumfeld_audio_line_device,
+                            &raumfeld_line_devdata);
+       raumfeld_line_devdata.dev = &raumfeld_audio_line_device->dev;
+       ret = platform_device_add(raumfeld_audio_line_device);
+       if (ret)
+               platform_device_put(raumfeld_audio_line_device);
+
+       /* no S/PDIF on Speakers */
+       if (machine_is_raumfeld_speaker())
+               return ret;
+
+       /* S/PDIF */
+       raumfeld_audio_spdif_device = platform_device_alloc("soc-audio", 1);
+       if (!raumfeld_audio_spdif_device) {
+               platform_device_put(raumfeld_audio_line_device);
+               return -ENOMEM;
+       }
+
+       platform_set_drvdata(raumfeld_audio_spdif_device,
+                            &raumfeld_spdif_devdata);
+       raumfeld_spdif_devdata.dev = &raumfeld_audio_spdif_device->dev;
+       ret = platform_device_add(raumfeld_audio_spdif_device);
+       if (ret) {
+               platform_device_put(raumfeld_audio_line_device);
+               platform_device_put(raumfeld_audio_spdif_device);
+       }
+
+       raumfeld_enable_audio(true);
+
+       return ret;
+}
+
+static void __exit raumfeld_audio_exit(void)
+{
+       raumfeld_enable_audio(false);
+
+       platform_device_unregister(raumfeld_audio_line_device);
+
+       if (machine_is_raumfeld_connector())
+               platform_device_unregister(raumfeld_audio_spdif_device);
+
+       i2c_unregister_device(max9486_client);
+
+       gpio_free(GPIO_MCLK_RESET);
+       gpio_free(GPIO_CODEC_RESET);
+       gpio_free(GPIO_SPDIF_RESET);
+}
+
+module_init(raumfeld_audio_init);
+module_exit(raumfeld_audio_exit);
+
+/* Module information */
+MODULE_AUTHOR("Daniel Mack <daniel@caiaq.de>");
+MODULE_DESCRIPTION("Raumfeld audio SoC");
+MODULE_LICENSE("GPL");
index 9a386b4..dd678ae 100644 (file)
@@ -74,7 +74,8 @@ static const struct snd_soc_dapm_route audio_map[] = {
 static int zylonite_wm9713_init(struct snd_soc_codec *codec)
 {
        if (clk_pout)
-               snd_soc_dai_set_pll(&codec->dai[0], 0, clk_get_rate(pout), 0);
+               snd_soc_dai_set_pll(&codec->dai[0], 0, 0,
+                                   clk_get_rate(pout), 0);
 
        snd_soc_dapm_new_controls(codec, zylonite_dapm_widgets,
                                  ARRAY_SIZE(zylonite_dapm_widgets));
@@ -128,7 +129,7 @@ static int zylonite_voice_hw_params(struct snd_pcm_substream *substream,
        if (ret < 0)
                return ret;
 
-       ret = snd_soc_dai_set_pll(cpu_dai, 0, 0, pll_out);
+       ret = snd_soc_dai_set_pll(cpu_dai, 0, 0, 0, pll_out);
        if (ret < 0)
                return ret;
 
index 923428f..b489f1a 100644 (file)
@@ -24,6 +24,9 @@ config SND_S3C64XX_SOC_I2S
        select SND_S3C_I2SV2_SOC
        select S3C64XX_DMA
 
+config SND_S3C_SOC_PCM
+       tristate
+
 config SND_S3C2443_SOC_AC97
        tristate
        select S3C2410_DMA
@@ -56,6 +59,15 @@ config SND_S3C24XX_SOC_JIVE_WM8750
        help
          Sat Y if you want to add support for SoC audio on the Jive.
 
+config SND_S3C64XX_SOC_WM8580
+       tristate "SoC I2S Audio support for WM8580 on SMDK64XX"
+       depends on SND_S3C24XX_SOC && (MACH_SMDK6400 || MACH_SMDK6410)
+       depends on BROKEN
+       select SND_SOC_WM8580
+       select SND_S3C64XX_SOC_I2S
+       help
+         Sat Y if you want to add support for SoC audio on the SMDK64XX.
+
 config SND_S3C24XX_SOC_SMDK2443_WM9710
        tristate "SoC AC97 Audio support for SMDK2443 - WM9710"
        depends on SND_S3C24XX_SOC && MACH_SMDK2443
index 99f5a7d..b744657 100644 (file)
@@ -1,10 +1,11 @@
 # S3c24XX Platform Support
-snd-soc-s3c24xx-objs := s3c24xx-pcm.o
+snd-soc-s3c24xx-objs := s3c-dma.o
 snd-soc-s3c24xx-i2s-objs := s3c24xx-i2s.o
 snd-soc-s3c2412-i2s-objs := s3c2412-i2s.o
 snd-soc-s3c64xx-i2s-objs := s3c64xx-i2s.o
 snd-soc-s3c2443-ac97-objs := s3c2443-ac97.o
 snd-soc-s3c-i2s-v2-objs := s3c-i2s-v2.o
+snd-soc-s3c-pcm-objs := s3c-pcm.o
 
 obj-$(CONFIG_SND_S3C24XX_SOC) += snd-soc-s3c24xx.o
 obj-$(CONFIG_SND_S3C24XX_SOC_I2S) += snd-soc-s3c24xx-i2s.o
@@ -12,6 +13,7 @@ obj-$(CONFIG_SND_S3C2443_SOC_AC97) += snd-soc-s3c2443-ac97.o
 obj-$(CONFIG_SND_S3C2412_SOC_I2S) += snd-soc-s3c2412-i2s.o
 obj-$(CONFIG_SND_S3C64XX_SOC_I2S) += snd-soc-s3c64xx-i2s.o
 obj-$(CONFIG_SND_S3C_I2SV2_SOC) += snd-soc-s3c-i2s-v2.o
+obj-$(CONFIG_SND_S3C_SOC_PCM) += snd-soc-s3c-pcm.o
 
 # S3C24XX Machine Support
 snd-soc-jive-wm8750-objs := jive_wm8750.o
@@ -23,6 +25,7 @@ snd-soc-s3c24xx-uda134x-objs := s3c24xx_uda134x.o
 snd-soc-s3c24xx-simtec-objs := s3c24xx_simtec.o
 snd-soc-s3c24xx-simtec-hermes-objs := s3c24xx_simtec_hermes.o
 snd-soc-s3c24xx-simtec-tlv320aic23-objs := s3c24xx_simtec_tlv320aic23.o
+snd-soc-smdk64xx-wm8580-objs := smdk64xx_wm8580.o
 
 obj-$(CONFIG_SND_S3C24XX_SOC_JIVE_WM8750) += snd-soc-jive-wm8750.o
 obj-$(CONFIG_SND_S3C24XX_SOC_NEO1973_WM8753) += snd-soc-neo1973-wm8753.o
@@ -33,4 +36,5 @@ obj-$(CONFIG_SND_S3C24XX_SOC_S3C24XX_UDA134X) += snd-soc-s3c24xx-uda134x.o
 obj-$(CONFIG_SND_S3C24XX_SOC_SIMTEC) += snd-soc-s3c24xx-simtec.o
 obj-$(CONFIG_SND_S3C24XX_SOC_SIMTEC_HERMES) += snd-soc-s3c24xx-simtec-hermes.o
 obj-$(CONFIG_SND_S3C24XX_SOC_SIMTEC_TLV320AIC23) += snd-soc-s3c24xx-simtec-tlv320aic23.o
+obj-$(CONFIG_SND_S3C64XX_SOC_WM8580) += snd-soc-smdk64xx-wm8580.o
 
index 93e6c87..59dc2c6 100644 (file)
@@ -25,7 +25,7 @@
 
 #include <asm/mach-types.h>
 
-#include "s3c24xx-pcm.h"
+#include "s3c-dma.h"
 #include "s3c2412-i2s.h"
 
 #include "../codecs/wm8750.h"
index 12c7148..d00d359 100644 (file)
@@ -24,7 +24,7 @@
 #include <sound/soc-dapm.h>
 
 #include "../codecs/ac97.h"
-#include "s3c24xx-pcm.h"
+#include "s3c-dma.h"
 #include "s3c24xx-ac97.h"
 
 static struct snd_soc_card ln2440sbc;
index 0c52e36..dea83d3 100644 (file)
@@ -32,7 +32,7 @@
 #include <asm/io.h>
 #include <mach/gta02.h>
 #include "../codecs/wm8753.h"
-#include "s3c24xx-pcm.h"
+#include "s3c-dma.h"
 #include "s3c24xx-i2s.h"
 
 static struct snd_soc_card neo1973_gta02;
@@ -119,7 +119,7 @@ static int neo1973_gta02_hifi_hw_params(struct snd_pcm_substream *substream,
                return ret;
 
        /* codec PLL input is PCLK/4 */
-       ret = snd_soc_dai_set_pll(codec_dai, WM8753_PLL1,
+       ret = snd_soc_dai_set_pll(codec_dai, WM8753_PLL1, 0,
                iis_clkrate / 4, pll_out);
        if (ret < 0)
                return ret;
@@ -133,7 +133,7 @@ static int neo1973_gta02_hifi_hw_free(struct snd_pcm_substream *substream)
        struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
 
        /* disable the PLL */
-       return snd_soc_dai_set_pll(codec_dai, WM8753_PLL1, 0, 0);
+       return snd_soc_dai_set_pll(codec_dai, WM8753_PLL1, 0, 0, 0);
 }
 
 /*
@@ -183,7 +183,7 @@ static int neo1973_gta02_voice_hw_params(
                return ret;
 
        /* configue and enable PLL for 12.288MHz output */
-       ret = snd_soc_dai_set_pll(codec_dai, WM8753_PLL2,
+       ret = snd_soc_dai_set_pll(codec_dai, WM8753_PLL2, 0,
                iis_clkrate / 4, 12288000);
        if (ret < 0)
                return ret;
@@ -197,7 +197,7 @@ static int neo1973_gta02_voice_hw_free(struct snd_pcm_substream *substream)
        struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
 
        /* disable the PLL */
-       return snd_soc_dai_set_pll(codec_dai, WM8753_PLL2, 0, 0);
+       return snd_soc_dai_set_pll(codec_dai, WM8753_PLL2, 0, 0, 0);
 }
 
 static struct snd_soc_ops neo1973_gta02_voice_ops = {
index 906709e..0cb4f86 100644 (file)
@@ -29,7 +29,6 @@
 #include <mach/regs-clock.h>
 #include <mach/regs-gpio.h>
 #include <mach/hardware.h>
-#include <plat/audio.h>
 #include <linux/io.h>
 #include <mach/spi-gpio.h>
 
@@ -37,7 +36,7 @@
 
 #include "../codecs/wm8753.h"
 #include "lm4857.h"
-#include "s3c24xx-pcm.h"
+#include "s3c-dma.h"
 #include "s3c24xx-i2s.h"
 
 /* define the scenarios */
@@ -137,7 +136,7 @@ static int neo1973_hifi_hw_params(struct snd_pcm_substream *substream,
                return ret;
 
        /* codec PLL input is PCLK/4 */
-       ret = snd_soc_dai_set_pll(codec_dai, WM8753_PLL1,
+       ret = snd_soc_dai_set_pll(codec_dai, WM8753_PLL1, 0,
                iis_clkrate / 4, pll_out);
        if (ret < 0)
                return ret;
@@ -153,7 +152,7 @@ static int neo1973_hifi_hw_free(struct snd_pcm_substream *substream)
        pr_debug("Entered %s\n", __func__);
 
        /* disable the PLL */
-       return snd_soc_dai_set_pll(codec_dai, WM8753_PLL1, 0, 0);
+       return snd_soc_dai_set_pll(codec_dai, WM8753_PLL1, 0, 0, 0);
 }
 
 /*
@@ -203,7 +202,7 @@ static int neo1973_voice_hw_params(struct snd_pcm_substream *substream,
                return ret;
 
        /* configue and enable PLL for 12.288MHz output */
-       ret = snd_soc_dai_set_pll(codec_dai, WM8753_PLL2,
+       ret = snd_soc_dai_set_pll(codec_dai, WM8753_PLL2, 0,
                iis_clkrate / 4, 12288000);
        if (ret < 0)
                return ret;
@@ -219,7 +218,7 @@ static int neo1973_voice_hw_free(struct snd_pcm_substream *substream)
        pr_debug("Entered %s\n", __func__);
 
        /* disable the PLL */
-       return snd_soc_dai_set_pll(codec_dai, WM8753_PLL2, 0, 0);
+       return snd_soc_dai_set_pll(codec_dai, WM8753_PLL2, 0, 0, 0);
 }
 
 static struct snd_soc_ops neo1973_voice_ops = {
similarity index 82%
rename from sound/soc/s3c24xx/s3c24xx-pcm.c
rename to sound/soc/s3c24xx/s3c-dma.c
index 1f35c6f..7725e26 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * s3c24xx-pcm.c  --  ALSA Soc Audio Layer
+ * s3c-dma.c  --  ALSA Soc Audio Layer
  *
  * (c) 2006 Wolfson Microelectronics PLC.
  * Graeme Gregory graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com
 #include <asm/dma.h>
 #include <mach/hardware.h>
 #include <mach/dma.h>
-#include <plat/audio.h>
 
-#include "s3c24xx-pcm.h"
+#include "s3c-dma.h"
 
-static const struct snd_pcm_hardware s3c24xx_pcm_hardware = {
+static const struct snd_pcm_hardware s3c_dma_hardware = {
        .info                   = SNDRV_PCM_INFO_INTERLEAVED |
                                    SNDRV_PCM_INFO_BLOCK_TRANSFER |
                                    SNDRV_PCM_INFO_MMAP |
@@ -63,15 +62,15 @@ struct s3c24xx_runtime_data {
        dma_addr_t dma_start;
        dma_addr_t dma_pos;
        dma_addr_t dma_end;
-       struct s3c24xx_pcm_dma_params *params;
+       struct s3c_dma_params *params;
 };
 
-/* s3c24xx_pcm_enqueue
+/* s3c_dma_enqueue
  *
  * place a dma buffer onto the queue for the dma system
  * to handle.
 */
-static void s3c24xx_pcm_enqueue(struct snd_pcm_substream *substream)
+static void s3c_dma_enqueue(struct snd_pcm_substream *substream)
 {
        struct s3c24xx_runtime_data *prtd = substream->runtime->private_data;
        dma_addr_t pos = prtd->dma_pos;
@@ -80,12 +79,13 @@ static void s3c24xx_pcm_enqueue(struct snd_pcm_substream *substream)
 
        pr_debug("Entered %s\n", __func__);
 
-       if (s3c_dma_has_circular()) {
+       if (s3c_dma_has_circular())
                limit = (prtd->dma_end - prtd->dma_start) / prtd->dma_period;
-       else
+       else
                limit = prtd->dma_limit;
 
-       pr_debug("%s: loaded %d, limit %d\n", __func__, prtd->dma_loaded, limit);
+       pr_debug("%s: loaded %d, limit %d\n",
+                               __func__, prtd->dma_loaded, limit);
 
        while (prtd->dma_loaded < limit) {
                unsigned long len = prtd->dma_period;
@@ -133,19 +133,19 @@ static void s3c24xx_audio_buffdone(struct s3c2410_dma_chan *channel,
        spin_lock(&prtd->lock);
        if (prtd->state & ST_RUNNING && !s3c_dma_has_circular()) {
                prtd->dma_loaded--;
-               s3c24xx_pcm_enqueue(substream);
+               s3c_dma_enqueue(substream);
        }
 
        spin_unlock(&prtd->lock);
 }
 
-static int s3c24xx_pcm_hw_params(struct snd_pcm_substream *substream,
+static int s3c_dma_hw_params(struct snd_pcm_substream *substream,
        struct snd_pcm_hw_params *params)
 {
        struct snd_pcm_runtime *runtime = substream->runtime;
        struct s3c24xx_runtime_data *prtd = runtime->private_data;
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct s3c24xx_pcm_dma_params *dma = rtd->dai->cpu_dai->dma_data;
+       struct s3c_dma_params *dma = rtd->dai->cpu_dai->dma_data;
        unsigned long totbytes = params_buffer_bytes(params);
        int ret = 0;
 
@@ -198,7 +198,7 @@ static int s3c24xx_pcm_hw_params(struct snd_pcm_substream *substream,
        return 0;
 }
 
-static int s3c24xx_pcm_hw_free(struct snd_pcm_substream *substream)
+static int s3c_dma_hw_free(struct snd_pcm_substream *substream)
 {
        struct s3c24xx_runtime_data *prtd = substream->runtime->private_data;
 
@@ -215,7 +215,7 @@ static int s3c24xx_pcm_hw_free(struct snd_pcm_substream *substream)
        return 0;
 }
 
-static int s3c24xx_pcm_prepare(struct snd_pcm_substream *substream)
+static int s3c_dma_prepare(struct snd_pcm_substream *substream)
 {
        struct s3c24xx_runtime_data *prtd = substream->runtime->private_data;
        int ret = 0;
@@ -248,12 +248,12 @@ static int s3c24xx_pcm_prepare(struct snd_pcm_substream *substream)
        prtd->dma_pos = prtd->dma_start;
 
        /* enqueue dma buffers */
-       s3c24xx_pcm_enqueue(substream);
+       s3c_dma_enqueue(substream);
 
        return ret;
 }
 
-static int s3c24xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
+static int s3c_dma_trigger(struct snd_pcm_substream *substream, int cmd)
 {
        struct s3c24xx_runtime_data *prtd = substream->runtime->private_data;
        int ret = 0;
@@ -288,7 +288,7 @@ static int s3c24xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
 }
 
 static snd_pcm_uframes_t
-s3c24xx_pcm_pointer(struct snd_pcm_substream *substream)
+s3c_dma_pointer(struct snd_pcm_substream *substream)
 {
        struct snd_pcm_runtime *runtime = substream->runtime;
        struct s3c24xx_runtime_data *prtd = runtime->private_data;
@@ -323,7 +323,7 @@ s3c24xx_pcm_pointer(struct snd_pcm_substream *substream)
        return bytes_to_frames(substream->runtime, res);
 }
 
-static int s3c24xx_pcm_open(struct snd_pcm_substream *substream)
+static int s3c_dma_open(struct snd_pcm_substream *substream)
 {
        struct snd_pcm_runtime *runtime = substream->runtime;
        struct s3c24xx_runtime_data *prtd;
@@ -331,7 +331,7 @@ static int s3c24xx_pcm_open(struct snd_pcm_substream *substream)
        pr_debug("Entered %s\n", __func__);
 
        snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
-       snd_soc_set_runtime_hwparams(substream, &s3c24xx_pcm_hardware);
+       snd_soc_set_runtime_hwparams(substream, &s3c_dma_hardware);
 
        prtd = kzalloc(sizeof(struct s3c24xx_runtime_data), GFP_KERNEL);
        if (prtd == NULL)
@@ -343,7 +343,7 @@ static int s3c24xx_pcm_open(struct snd_pcm_substream *substream)
        return 0;
 }
 
-static int s3c24xx_pcm_close(struct snd_pcm_substream *substream)
+static int s3c_dma_close(struct snd_pcm_substream *substream)
 {
        struct snd_pcm_runtime *runtime = substream->runtime;
        struct s3c24xx_runtime_data *prtd = runtime->private_data;
@@ -351,14 +351,14 @@ static int s3c24xx_pcm_close(struct snd_pcm_substream *substream)
        pr_debug("Entered %s\n", __func__);
 
        if (!prtd)
-               pr_debug("s3c24xx_pcm_close called with prtd == NULL\n");
+               pr_debug("s3c_dma_close called with prtd == NULL\n");
 
        kfree(prtd);
 
        return 0;
 }
 
-static int s3c24xx_pcm_mmap(struct snd_pcm_substream *substream,
+static int s3c_dma_mmap(struct snd_pcm_substream *substream,
        struct vm_area_struct *vma)
 {
        struct snd_pcm_runtime *runtime = substream->runtime;
@@ -371,23 +371,23 @@ static int s3c24xx_pcm_mmap(struct snd_pcm_substream *substream,
                                     runtime->dma_bytes);
 }
 
-static struct snd_pcm_ops s3c24xx_pcm_ops = {
-       .open           = s3c24xx_pcm_open,
-       .close          = s3c24xx_pcm_close,
+static struct snd_pcm_ops s3c_dma_ops = {
+       .open           = s3c_dma_open,
+       .close          = s3c_dma_close,
        .ioctl          = snd_pcm_lib_ioctl,
-       .hw_params      = s3c24xx_pcm_hw_params,
-       .hw_free        = s3c24xx_pcm_hw_free,
-       .prepare        = s3c24xx_pcm_prepare,
-       .trigger        = s3c24xx_pcm_trigger,
-       .pointer        = s3c24xx_pcm_pointer,
-       .mmap           = s3c24xx_pcm_mmap,
+       .hw_params      = s3c_dma_hw_params,
+       .hw_free        = s3c_dma_hw_free,
+       .prepare        = s3c_dma_prepare,
+       .trigger        = s3c_dma_trigger,
+       .pointer        = s3c_dma_pointer,
+       .mmap           = s3c_dma_mmap,
 };
 
-static int s3c24xx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
+static int s3c_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
 {
        struct snd_pcm_substream *substream = pcm->streams[stream].substream;
        struct snd_dma_buffer *buf = &substream->dma_buffer;
-       size_t size = s3c24xx_pcm_hardware.buffer_bytes_max;
+       size_t size = s3c_dma_hardware.buffer_bytes_max;
 
        pr_debug("Entered %s\n", __func__);
 
@@ -402,7 +402,7 @@ static int s3c24xx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
        return 0;
 }
 
-static void s3c24xx_pcm_free_dma_buffers(struct snd_pcm *pcm)
+static void s3c_dma_free_dma_buffers(struct snd_pcm *pcm)
 {
        struct snd_pcm_substream *substream;
        struct snd_dma_buffer *buf;
@@ -425,9 +425,9 @@ static void s3c24xx_pcm_free_dma_buffers(struct snd_pcm *pcm)
        }
 }
 
-static u64 s3c24xx_pcm_dmamask = DMA_BIT_MASK(32);
+static u64 s3c_dma_mask = DMA_BIT_MASK(32);
 
-static int s3c24xx_pcm_new(struct snd_card *card,
+static int s3c_dma_new(struct snd_card *card,
        struct snd_soc_dai *dai, struct snd_pcm *pcm)
 {
        int ret = 0;
@@ -435,19 +435,19 @@ static int s3c24xx_pcm_new(struct snd_card *card,
        pr_debug("Entered %s\n", __func__);
 
        if (!card->dev->dma_mask)
-               card->dev->dma_mask = &s3c24xx_pcm_dmamask;
+               card->dev->dma_mask = &s3c_dma_mask;
        if (!card->dev->coherent_dma_mask)
                card->dev->coherent_dma_mask = 0xffffffff;
 
        if (dai->playback.channels_min) {
-               ret = s3c24xx_pcm_preallocate_dma_buffer(pcm,
+               ret = s3c_preallocate_dma_buffer(pcm,
                        SNDRV_PCM_STREAM_PLAYBACK);
                if (ret)
                        goto out;
        }
 
        if (dai->capture.channels_min) {
-               ret = s3c24xx_pcm_preallocate_dma_buffer(pcm,
+               ret = s3c_preallocate_dma_buffer(pcm,
                        SNDRV_PCM_STREAM_CAPTURE);
                if (ret)
                        goto out;
@@ -458,9 +458,9 @@ static int s3c24xx_pcm_new(struct snd_card *card,
 
 struct snd_soc_platform s3c24xx_soc_platform = {
        .name           = "s3c24xx-audio",
-       .pcm_ops        = &s3c24xx_pcm_ops,
-       .pcm_new        = s3c24xx_pcm_new,
-       .pcm_free       = s3c24xx_pcm_free_dma_buffers,
+       .pcm_ops        = &s3c_dma_ops,
+       .pcm_new        = s3c_dma_new,
+       .pcm_free       = s3c_dma_free_dma_buffers,
 };
 EXPORT_SYMBOL_GPL(s3c24xx_soc_platform);
 
@@ -477,5 +477,5 @@ static void __exit s3c24xx_soc_platform_exit(void)
 module_exit(s3c24xx_soc_platform_exit);
 
 MODULE_AUTHOR("Ben Dooks, <ben@simtec.co.uk>");
-MODULE_DESCRIPTION("Samsung S3C24XX PCM DMA module");
+MODULE_DESCRIPTION("Samsung S3C Audio DMA module");
 MODULE_LICENSE("GPL");
similarity index 87%
rename from sound/soc/s3c24xx/s3c24xx-pcm.h
rename to sound/soc/s3c24xx/s3c-dma.h
index 0088c79..69bb6bf 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  s3c24xx-pcm.h --
+ *  s3c-dma.h --
  *
  *  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
@@ -9,13 +9,13 @@
  *  ALSA PCM interface for the Samsung S3C24xx CPU
  */
 
-#ifndef _S3C24XX_PCM_H
-#define _S3C24XX_PCM_H
+#ifndef _S3C_AUDIO_H
+#define _S3C_AUDIO_H
 
 #define ST_RUNNING             (1<<0)
 #define ST_OPENED              (1<<1)
 
-struct s3c24xx_pcm_dma_params {
+struct s3c_dma_params {
        struct s3c2410_dma_client *client;      /* stream identifier */
        int channel;                            /* Channel ID */
        dma_addr_t dma_addr;
index 9bc4aa3..e994d83 100644 (file)
 
 #include <plat/regs-s3c2412-iis.h>
 
-#include <plat/audio.h>
 #include <mach/dma.h>
 
 #include "s3c-i2s-v2.h"
-#include "s3c24xx-pcm.h"
+#include "s3c-dma.h"
 
 #undef S3C_IIS_V2_SUPPORTED
 
@@ -312,12 +311,15 @@ static int s3c2412_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
 
        switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
        case SND_SOC_DAIFMT_RIGHT_J:
+               iismod |= S3C2412_IISMOD_LR_RLOW;
                iismod |= S3C2412_IISMOD_SDF_MSB;
                break;
        case SND_SOC_DAIFMT_LEFT_J:
+               iismod |= S3C2412_IISMOD_LR_RLOW;
                iismod |= S3C2412_IISMOD_SDF_LSB;
                break;
        case SND_SOC_DAIFMT_I2S:
+               iismod &= ~S3C2412_IISMOD_LR_RLOW;
                iismod |= S3C2412_IISMOD_SDF_IIS;
                break;
        default:
@@ -392,7 +394,7 @@ static int s3c2412_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
        int capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE);
        unsigned long irqs;
        int ret = 0;
-       int channel = ((struct s3c24xx_pcm_dma_params *)
+       int channel = ((struct s3c_dma_params *)
                  rtd->dai->cpu_dai->dma_data)->channel;
 
        pr_debug("Entered %s\n", __func__);
@@ -467,6 +469,31 @@ static int s3c2412_i2s_set_clkdiv(struct snd_soc_dai *cpu_dai,
 
        switch (div_id) {
        case S3C_I2SV2_DIV_BCLK:
+               if (div > 3) {
+                       /* convert value to bit field */
+
+                       switch (div) {
+                       case 16:
+                               div = S3C2412_IISMOD_BCLK_16FS;
+                               break;
+
+                       case 32:
+                               div = S3C2412_IISMOD_BCLK_32FS;
+                               break;
+
+                       case 24:
+                               div = S3C2412_IISMOD_BCLK_24FS;
+                               break;
+
+                       case 48:
+                               div = S3C2412_IISMOD_BCLK_48FS;
+                               break;
+
+                       default:
+                               return -EINVAL;
+                       }
+               }
+
                reg = readl(i2s->regs + S3C2412_IISMOD);
                reg &= ~S3C2412_IISMOD_BCLK_MASK;
                writel(reg | div, i2s->regs + S3C2412_IISMOD);
@@ -626,7 +653,7 @@ int s3c_i2sv2_probe(struct platform_device *pdev,
        }
 
        i2s->iis_pclk = clk_get(dev, "iis");
-       if (i2s->iis_pclk == NULL) {
+       if (IS_ERR(i2s->iis_pclk)) {
                dev_err(dev, "failed to get iis_clock\n");
                iounmap(i2s->regs);
                return -ENOENT;
index f66854a..ecf8eaa 100644 (file)
@@ -49,8 +49,8 @@ struct s3c_i2sv2_info {
 
        unsigned char    master;
 
-       struct s3c24xx_pcm_dma_params   *dma_playback;
-       struct s3c24xx_pcm_dma_params   *dma_capture;
+       struct s3c_dma_params   *dma_playback;
+       struct s3c_dma_params   *dma_capture;
 
        u32              suspend_iismod;
        u32              suspend_iiscon;
diff --git a/sound/soc/s3c24xx/s3c-pcm.c b/sound/soc/s3c24xx/s3c-pcm.c
new file mode 100644 (file)
index 0000000..9e61a7c
--- /dev/null
@@ -0,0 +1,552 @@
+/* sound/soc/s3c24xx/s3c-pcm.c
+ *
+ * ALSA SoC Audio Layer - S3C PCM-Controller driver
+ *
+ * Copyright (c) 2009 Samsung Electronics Co. Ltd
+ * Author: Jaswinder Singh <jassi.brar@samsung.com>
+ * based upon I2S drivers by Ben Dooks.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/kernel.h>
+#include <linux/gpio.h>
+#include <linux/io.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+
+#include <plat/audio.h>
+#include <plat/dma.h>
+
+#include "s3c-dma.h"
+#include "s3c-pcm.h"
+
+static struct s3c2410_dma_client s3c_pcm_dma_client_out = {
+       .name           = "PCM Stereo out"
+};
+
+static struct s3c2410_dma_client s3c_pcm_dma_client_in = {
+       .name           = "PCM Stereo in"
+};
+
+static struct s3c_dma_params s3c_pcm_stereo_out[] = {
+       [0] = {
+               .client         = &s3c_pcm_dma_client_out,
+               .dma_size       = 4,
+       },
+       [1] = {
+               .client         = &s3c_pcm_dma_client_out,
+               .dma_size       = 4,
+       },
+};
+
+static struct s3c_dma_params s3c_pcm_stereo_in[] = {
+       [0] = {
+               .client         = &s3c_pcm_dma_client_in,
+               .dma_size       = 4,
+       },
+       [1] = {
+               .client         = &s3c_pcm_dma_client_in,
+               .dma_size       = 4,
+       },
+};
+
+static struct s3c_pcm_info s3c_pcm[2];
+
+static inline struct s3c_pcm_info *to_info(struct snd_soc_dai *cpu_dai)
+{
+       return cpu_dai->private_data;
+}
+
+static void s3c_pcm_snd_txctrl(struct s3c_pcm_info *pcm, int on)
+{
+       void __iomem *regs = pcm->regs;
+       u32 ctl, clkctl;
+
+       clkctl = readl(regs + S3C_PCM_CLKCTL);
+       ctl = readl(regs + S3C_PCM_CTL);
+       ctl &= ~(S3C_PCM_CTL_TXDIPSTICK_MASK
+                        << S3C_PCM_CTL_TXDIPSTICK_SHIFT);
+
+       if (on) {
+               ctl |= S3C_PCM_CTL_TXDMA_EN;
+               ctl |= S3C_PCM_CTL_TXFIFO_EN;
+               ctl |= S3C_PCM_CTL_ENABLE;
+               ctl |= (0x20<<S3C_PCM_CTL_TXDIPSTICK_SHIFT);
+               clkctl |= S3C_PCM_CLKCTL_SERCLK_EN;
+       } else {
+               ctl &= ~S3C_PCM_CTL_TXDMA_EN;
+               ctl &= ~S3C_PCM_CTL_TXFIFO_EN;
+
+               if (!(ctl & S3C_PCM_CTL_RXFIFO_EN)) {
+                       ctl &= ~S3C_PCM_CTL_ENABLE;
+                       if (!pcm->idleclk)
+                               clkctl |= S3C_PCM_CLKCTL_SERCLK_EN;
+               }
+       }
+
+       writel(clkctl, regs + S3C_PCM_CLKCTL);
+       writel(ctl, regs + S3C_PCM_CTL);
+}
+
+static void s3c_pcm_snd_rxctrl(struct s3c_pcm_info *pcm, int on)
+{
+       void __iomem *regs = pcm->regs;
+       u32 ctl, clkctl;
+
+       ctl = readl(regs + S3C_PCM_CTL);
+       clkctl = readl(regs + S3C_PCM_CLKCTL);
+
+       if (on) {
+               ctl |= S3C_PCM_CTL_RXDMA_EN;
+               ctl |= S3C_PCM_CTL_RXFIFO_EN;
+               ctl |= S3C_PCM_CTL_ENABLE;
+               clkctl |= S3C_PCM_CLKCTL_SERCLK_EN;
+       } else {
+               ctl &= ~S3C_PCM_CTL_RXDMA_EN;
+               ctl &= ~S3C_PCM_CTL_RXFIFO_EN;
+
+               if (!(ctl & S3C_PCM_CTL_TXFIFO_EN)) {
+                       ctl &= ~S3C_PCM_CTL_ENABLE;
+                       if (!pcm->idleclk)
+                               clkctl |= S3C_PCM_CLKCTL_SERCLK_EN;
+               }
+       }
+
+       writel(clkctl, regs + S3C_PCM_CLKCTL);
+       writel(ctl, regs + S3C_PCM_CTL);
+}
+
+static int s3c_pcm_trigger(struct snd_pcm_substream *substream, int cmd,
+                              struct snd_soc_dai *dai)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct s3c_pcm_info *pcm = to_info(rtd->dai->cpu_dai);
+       unsigned long flags;
+
+       dev_dbg(pcm->dev, "Entered %s\n", __func__);
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+       case SNDRV_PCM_TRIGGER_RESUME:
+       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+               spin_lock_irqsave(&pcm->lock, flags);
+
+               if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+                       s3c_pcm_snd_rxctrl(pcm, 1);
+               else
+                       s3c_pcm_snd_txctrl(pcm, 1);
+
+               spin_unlock_irqrestore(&pcm->lock, flags);
+               break;
+
+       case SNDRV_PCM_TRIGGER_STOP:
+       case SNDRV_PCM_TRIGGER_SUSPEND:
+       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+               spin_lock_irqsave(&pcm->lock, flags);
+
+               if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+                       s3c_pcm_snd_rxctrl(pcm, 0);
+               else
+                       s3c_pcm_snd_txctrl(pcm, 0);
+
+               spin_unlock_irqrestore(&pcm->lock, flags);
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int s3c_pcm_hw_params(struct snd_pcm_substream *substream,
+                                struct snd_pcm_hw_params *params,
+                                struct snd_soc_dai *socdai)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_dai_link *dai = rtd->dai;
+       struct s3c_pcm_info *pcm = to_info(dai->cpu_dai);
+       void __iomem *regs = pcm->regs;
+       struct clk *clk;
+       int sclk_div, sync_div;
+       unsigned long flags;
+       u32 clkctl;
+
+       dev_dbg(pcm->dev, "Entered %s\n", __func__);
+
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+               dai->cpu_dai->dma_data = pcm->dma_playback;
+       else
+               dai->cpu_dai->dma_data = pcm->dma_capture;
+
+       /* Strictly check for sample size */
+       switch (params_format(params)) {
+       case SNDRV_PCM_FORMAT_S16_LE:
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       spin_lock_irqsave(&pcm->lock, flags);
+
+       /* Get hold of the PCMSOURCE_CLK */
+       clkctl = readl(regs + S3C_PCM_CLKCTL);
+       if (clkctl & S3C_PCM_CLKCTL_SERCLKSEL_PCLK)
+               clk = pcm->pclk;
+       else
+               clk = pcm->cclk;
+
+       /* Set the SCLK divider */
+       sclk_div = clk_get_rate(clk) / pcm->sclk_per_fs /
+                                       params_rate(params) / 2 - 1;
+
+       clkctl &= ~(S3C_PCM_CLKCTL_SCLKDIV_MASK
+                       << S3C_PCM_CLKCTL_SCLKDIV_SHIFT);
+       clkctl |= ((sclk_div & S3C_PCM_CLKCTL_SCLKDIV_MASK)
+                       << S3C_PCM_CLKCTL_SCLKDIV_SHIFT);
+
+       /* Set the SYNC divider */
+       sync_div = pcm->sclk_per_fs - 1;
+
+       clkctl &= ~(S3C_PCM_CLKCTL_SYNCDIV_MASK
+                               << S3C_PCM_CLKCTL_SYNCDIV_SHIFT);
+       clkctl |= ((sync_div & S3C_PCM_CLKCTL_SYNCDIV_MASK)
+                               << S3C_PCM_CLKCTL_SYNCDIV_SHIFT);
+
+       writel(clkctl, regs + S3C_PCM_CLKCTL);
+
+       spin_unlock_irqrestore(&pcm->lock, flags);
+
+       dev_dbg(pcm->dev, "PCMSOURCE_CLK-%lu SCLK=%ufs \
+                               SCLK_DIV=%d SYNC_DIV=%d\n",
+                               clk_get_rate(clk), pcm->sclk_per_fs,
+                               sclk_div, sync_div);
+
+       return 0;
+}
+
+static int s3c_pcm_set_fmt(struct snd_soc_dai *cpu_dai,
+                              unsigned int fmt)
+{
+       struct s3c_pcm_info *pcm = to_info(cpu_dai);
+       void __iomem *regs = pcm->regs;
+       unsigned long flags;
+       int ret = 0;
+       u32 ctl;
+
+       dev_dbg(pcm->dev, "Entered %s\n", __func__);
+
+       spin_lock_irqsave(&pcm->lock, flags);
+
+       ctl = readl(regs + S3C_PCM_CTL);
+
+       switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+       case SND_SOC_DAIFMT_NB_NF:
+               /* Nothing to do, NB_NF by default */
+               break;
+       default:
+               dev_err(pcm->dev, "Unsupported clock inversion!\n");
+               ret = -EINVAL;
+               goto exit;
+       }
+
+       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_CBS_CFS:
+               /* Nothing to do, Master by default */
+               break;
+       default:
+               dev_err(pcm->dev, "Unsupported master/slave format!\n");
+               ret = -EINVAL;
+               goto exit;
+       }
+
+       switch (fmt & SND_SOC_DAIFMT_CLOCK_MASK) {
+       case SND_SOC_DAIFMT_CONT:
+               pcm->idleclk = 1;
+               break;
+       case SND_SOC_DAIFMT_GATED:
+               pcm->idleclk = 0;
+               break;
+       default:
+               dev_err(pcm->dev, "Invalid Clock gating request!\n");
+               ret = -EINVAL;
+               goto exit;
+       }
+
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_DSP_A:
+               ctl |= S3C_PCM_CTL_TXMSB_AFTER_FSYNC;
+               ctl |= S3C_PCM_CTL_RXMSB_AFTER_FSYNC;
+               break;
+       case SND_SOC_DAIFMT_DSP_B:
+               ctl &= ~S3C_PCM_CTL_TXMSB_AFTER_FSYNC;
+               ctl &= ~S3C_PCM_CTL_RXMSB_AFTER_FSYNC;
+               break;
+       default:
+               dev_err(pcm->dev, "Unsupported data format!\n");
+               ret = -EINVAL;
+               goto exit;
+       }
+
+       writel(ctl, regs + S3C_PCM_CTL);
+
+exit:
+       spin_unlock_irqrestore(&pcm->lock, flags);
+
+       return ret;
+}
+
+static int s3c_pcm_set_clkdiv(struct snd_soc_dai *cpu_dai,
+                                               int div_id, int div)
+{
+       struct s3c_pcm_info *pcm = to_info(cpu_dai);
+
+       switch (div_id) {
+       case S3C_PCM_SCLK_PER_FS:
+               pcm->sclk_per_fs = div;
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int s3c_pcm_set_sysclk(struct snd_soc_dai *cpu_dai,
+                                 int clk_id, unsigned int freq, int dir)
+{
+       struct s3c_pcm_info *pcm = to_info(cpu_dai);
+       void __iomem *regs = pcm->regs;
+       u32 clkctl = readl(regs + S3C_PCM_CLKCTL);
+
+       switch (clk_id) {
+       case S3C_PCM_CLKSRC_PCLK:
+               clkctl |= S3C_PCM_CLKCTL_SERCLKSEL_PCLK;
+               break;
+
+       case S3C_PCM_CLKSRC_MUX:
+               clkctl &= ~S3C_PCM_CLKCTL_SERCLKSEL_PCLK;
+
+               if (clk_get_rate(pcm->cclk) != freq)
+                       clk_set_rate(pcm->cclk, freq);
+
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       writel(clkctl, regs + S3C_PCM_CLKCTL);
+
+       return 0;
+}
+
+static struct snd_soc_dai_ops s3c_pcm_dai_ops = {
+       .set_sysclk     = s3c_pcm_set_sysclk,
+       .set_clkdiv     = s3c_pcm_set_clkdiv,
+       .trigger        = s3c_pcm_trigger,
+       .hw_params      = s3c_pcm_hw_params,
+       .set_fmt        = s3c_pcm_set_fmt,
+};
+
+#define S3C_PCM_RATES  SNDRV_PCM_RATE_8000_96000
+
+#define S3C_PCM_DECLARE(n)                     \
+{                                                              \
+       .name            = "samsung-pcm",                       \
+       .id              = (n),                         \
+       .symmetric_rates = 1,                                   \
+       .ops = &s3c_pcm_dai_ops,                                \
+       .playback = {                                           \
+               .channels_min   = 2,                            \
+               .channels_max   = 2,                            \
+               .rates          = S3C_PCM_RATES,                \
+               .formats        = SNDRV_PCM_FMTBIT_S16_LE,      \
+       },                                                      \
+       .capture = {                                            \
+               .channels_min   = 2,                            \
+               .channels_max   = 2,                            \
+               .rates          = S3C_PCM_RATES,                \
+               .formats        = SNDRV_PCM_FMTBIT_S16_LE,      \
+       },                                                      \
+}
+
+struct snd_soc_dai s3c_pcm_dai[] = {
+       S3C_PCM_DECLARE(0),
+       S3C_PCM_DECLARE(1),
+};
+EXPORT_SYMBOL_GPL(s3c_pcm_dai);
+
+static __devinit int s3c_pcm_dev_probe(struct platform_device *pdev)
+{
+       struct s3c_pcm_info *pcm;
+       struct snd_soc_dai *dai;
+       struct resource *mem_res, *dmatx_res, *dmarx_res;
+       struct s3c_audio_pdata *pcm_pdata;
+       int ret;
+
+       /* Check for valid device index */
+       if ((pdev->id < 0) || pdev->id >= ARRAY_SIZE(s3c_pcm)) {
+               dev_err(&pdev->dev, "id %d out of range\n", pdev->id);
+               return -EINVAL;
+       }
+
+       pcm_pdata = pdev->dev.platform_data;
+
+       /* Check for availability of necessary resource */
+       dmatx_res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
+       if (!dmatx_res) {
+               dev_err(&pdev->dev, "Unable to get PCM-TX dma resource\n");
+               return -ENXIO;
+       }
+
+       dmarx_res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
+       if (!dmarx_res) {
+               dev_err(&pdev->dev, "Unable to get PCM-RX dma resource\n");
+               return -ENXIO;
+       }
+
+       mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!mem_res) {
+               dev_err(&pdev->dev, "Unable to get register resource\n");
+               return -ENXIO;
+       }
+
+       if (pcm_pdata && pcm_pdata->cfg_gpio && pcm_pdata->cfg_gpio(pdev)) {
+               dev_err(&pdev->dev, "Unable to configure gpio\n");
+               return -EINVAL;
+       }
+
+       pcm = &s3c_pcm[pdev->id];
+       pcm->dev = &pdev->dev;
+
+       spin_lock_init(&pcm->lock);
+
+       dai = &s3c_pcm_dai[pdev->id];
+       dai->dev = &pdev->dev;
+
+       /* Default is 128fs */
+       pcm->sclk_per_fs = 128;
+
+       pcm->cclk = clk_get(&pdev->dev, "audio-bus");
+       if (IS_ERR(pcm->cclk)) {
+               dev_err(&pdev->dev, "failed to get audio-bus\n");
+               ret = PTR_ERR(pcm->cclk);
+               goto err1;
+       }
+       clk_enable(pcm->cclk);
+
+       /* record our pcm structure for later use in the callbacks */
+       dai->private_data = pcm;
+
+       if (!request_mem_region(mem_res->start,
+                               resource_size(mem_res), "samsung-pcm")) {
+               dev_err(&pdev->dev, "Unable to request register region\n");
+               ret = -EBUSY;
+               goto err2;
+       }
+
+       pcm->regs = ioremap(mem_res->start, 0x100);
+       if (pcm->regs == NULL) {
+               dev_err(&pdev->dev, "cannot ioremap registers\n");
+               ret = -ENXIO;
+               goto err3;
+       }
+
+       pcm->pclk = clk_get(&pdev->dev, "pcm");
+       if (IS_ERR(pcm->pclk)) {
+               dev_err(&pdev->dev, "failed to get pcm_clock\n");
+               ret = -ENOENT;
+               goto err4;
+       }
+       clk_enable(pcm->pclk);
+
+       ret = snd_soc_register_dai(dai);
+       if (ret != 0) {
+               dev_err(&pdev->dev, "failed to get pcm_clock\n");
+               goto err5;
+       }
+
+       s3c_pcm_stereo_in[pdev->id].dma_addr = mem_res->start
+                                                       + S3C_PCM_RXFIFO;
+       s3c_pcm_stereo_out[pdev->id].dma_addr = mem_res->start
+                                                       + S3C_PCM_TXFIFO;
+
+       s3c_pcm_stereo_in[pdev->id].channel = dmarx_res->start;
+       s3c_pcm_stereo_out[pdev->id].channel = dmatx_res->start;
+
+       pcm->dma_capture = &s3c_pcm_stereo_in[pdev->id];
+       pcm->dma_playback = &s3c_pcm_stereo_out[pdev->id];
+
+       return 0;
+
+err5:
+       clk_disable(pcm->pclk);
+       clk_put(pcm->pclk);
+err4:
+       iounmap(pcm->regs);
+err3:
+       release_mem_region(mem_res->start, resource_size(mem_res));
+err2:
+       clk_disable(pcm->cclk);
+       clk_put(pcm->cclk);
+err1:
+       return ret;
+}
+
+static __devexit int s3c_pcm_dev_remove(struct platform_device *pdev)
+{
+       struct s3c_pcm_info *pcm = &s3c_pcm[pdev->id];
+       struct resource *mem_res;
+
+       iounmap(pcm->regs);
+
+       mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       release_mem_region(mem_res->start, resource_size(mem_res));
+
+       clk_disable(pcm->cclk);
+       clk_disable(pcm->pclk);
+       clk_put(pcm->pclk);
+       clk_put(pcm->cclk);
+
+       return 0;
+}
+
+static struct platform_driver s3c_pcm_driver = {
+       .probe  = s3c_pcm_dev_probe,
+       .remove = s3c_pcm_dev_remove,
+       .driver = {
+               .name = "samsung-pcm",
+               .owner = THIS_MODULE,
+       },
+};
+
+static int __init s3c_pcm_init(void)
+{
+       return platform_driver_register(&s3c_pcm_driver);
+}
+module_init(s3c_pcm_init);
+
+static void __exit s3c_pcm_exit(void)
+{
+       platform_driver_unregister(&s3c_pcm_driver);
+}
+module_exit(s3c_pcm_exit);
+
+/* Module information */
+MODULE_AUTHOR("Jaswinder Singh, <jassi.brar@samsung.com>");
+MODULE_DESCRIPTION("S3C PCM Controller Driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/s3c24xx/s3c-pcm.h b/sound/soc/s3c24xx/s3c-pcm.h
new file mode 100644 (file)
index 0000000..69ff997
--- /dev/null
@@ -0,0 +1,123 @@
+/*  sound/soc/s3c24xx/s3c-pcm.h
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#ifndef __S3C_PCM_H
+#define __S3C_PCM_H __FILE__
+
+/*Register Offsets */
+#define S3C_PCM_CTL    (0x00)
+#define S3C_PCM_CLKCTL (0x04)
+#define S3C_PCM_TXFIFO (0x08)
+#define S3C_PCM_RXFIFO (0x0C)
+#define S3C_PCM_IRQCTL (0x10)
+#define S3C_PCM_IRQSTAT        (0x14)
+#define S3C_PCM_FIFOSTAT       (0x18)
+#define S3C_PCM_CLRINT (0x20)
+
+/* PCM_CTL Bit-Fields */
+#define S3C_PCM_CTL_TXDIPSTICK_MASK            (0x3f)
+#define S3C_PCM_CTL_TXDIPSTICK_SHIFT   (13)
+#define S3C_PCM_CTL_RXDIPSTICK_MSK             (0x3f<<7)
+#define S3C_PCM_CTL_TXDMA_EN           (0x1<<6)
+#define S3C_PCM_CTL_RXDMA_EN           (0x1<<5)
+#define S3C_PCM_CTL_TXMSB_AFTER_FSYNC  (0x1<<4)
+#define S3C_PCM_CTL_RXMSB_AFTER_FSYNC  (0x1<<3)
+#define S3C_PCM_CTL_TXFIFO_EN          (0x1<<2)
+#define S3C_PCM_CTL_RXFIFO_EN          (0x1<<1)
+#define S3C_PCM_CTL_ENABLE                     (0x1<<0)
+
+/* PCM_CLKCTL Bit-Fields */
+#define S3C_PCM_CLKCTL_SERCLK_EN               (0x1<<19)
+#define S3C_PCM_CLKCTL_SERCLKSEL_PCLK  (0x1<<18)
+#define S3C_PCM_CLKCTL_SCLKDIV_MASK            (0x1ff)
+#define S3C_PCM_CLKCTL_SYNCDIV_MASK            (0x1ff)
+#define S3C_PCM_CLKCTL_SCLKDIV_SHIFT   (9)
+#define S3C_PCM_CLKCTL_SYNCDIV_SHIFT   (0)
+
+/* PCM_TXFIFO Bit-Fields */
+#define S3C_PCM_TXFIFO_DVALID  (0x1<<16)
+#define S3C_PCM_TXFIFO_DATA_MSK        (0xffff<<0)
+
+/* PCM_RXFIFO Bit-Fields */
+#define S3C_PCM_RXFIFO_DVALID  (0x1<<16)
+#define S3C_PCM_RXFIFO_DATA_MSK        (0xffff<<0)
+
+/* PCM_IRQCTL Bit-Fields */
+#define S3C_PCM_IRQCTL_IRQEN           (0x1<<14)
+#define S3C_PCM_IRQCTL_WRDEN           (0x1<<12)
+#define S3C_PCM_IRQCTL_TXEMPTYEN               (0x1<<11)
+#define S3C_PCM_IRQCTL_TXALMSTEMPTYEN  (0x1<<10)
+#define S3C_PCM_IRQCTL_TXFULLEN                (0x1<<9)
+#define S3C_PCM_IRQCTL_TXALMSTFULLEN   (0x1<<8)
+#define S3C_PCM_IRQCTL_TXSTARVEN               (0x1<<7)
+#define S3C_PCM_IRQCTL_TXERROVRFLEN            (0x1<<6)
+#define S3C_PCM_IRQCTL_RXEMPTEN                (0x1<<5)
+#define S3C_PCM_IRQCTL_RXALMSTEMPTEN   (0x1<<4)
+#define S3C_PCM_IRQCTL_RXFULLEN                (0x1<<3)
+#define S3C_PCM_IRQCTL_RXALMSTFULLEN   (0x1<<2)
+#define S3C_PCM_IRQCTL_RXSTARVEN               (0x1<<1)
+#define S3C_PCM_IRQCTL_RXERROVRFLEN            (0x1<<0)
+
+/* PCM_IRQSTAT Bit-Fields */
+#define S3C_PCM_IRQSTAT_IRQPND         (0x1<<13)
+#define S3C_PCM_IRQSTAT_WRD_XFER               (0x1<<12)
+#define S3C_PCM_IRQSTAT_TXEMPTY                (0x1<<11)
+#define S3C_PCM_IRQSTAT_TXALMSTEMPTY   (0x1<<10)
+#define S3C_PCM_IRQSTAT_TXFULL         (0x1<<9)
+#define S3C_PCM_IRQSTAT_TXALMSTFULL            (0x1<<8)
+#define S3C_PCM_IRQSTAT_TXSTARV                (0x1<<7)
+#define S3C_PCM_IRQSTAT_TXERROVRFL             (0x1<<6)
+#define S3C_PCM_IRQSTAT_RXEMPT         (0x1<<5)
+#define S3C_PCM_IRQSTAT_RXALMSTEMPT            (0x1<<4)
+#define S3C_PCM_IRQSTAT_RXFULL         (0x1<<3)
+#define S3C_PCM_IRQSTAT_RXALMSTFULL            (0x1<<2)
+#define S3C_PCM_IRQSTAT_RXSTARV                (0x1<<1)
+#define S3C_PCM_IRQSTAT_RXERROVRFL             (0x1<<0)
+
+/* PCM_FIFOSTAT Bit-Fields */
+#define S3C_PCM_FIFOSTAT_TXCNT_MSK             (0x3f<<14)
+#define S3C_PCM_FIFOSTAT_TXFIFOEMPTY   (0x1<<13)
+#define S3C_PCM_FIFOSTAT_TXFIFOALMSTEMPTY      (0x1<<12)
+#define S3C_PCM_FIFOSTAT_TXFIFOFULL            (0x1<<11)
+#define S3C_PCM_FIFOSTAT_TXFIFOALMSTFULL       (0x1<<10)
+#define S3C_PCM_FIFOSTAT_RXCNT_MSK             (0x3f<<4)
+#define S3C_PCM_FIFOSTAT_RXFIFOEMPTY   (0x1<<3)
+#define S3C_PCM_FIFOSTAT_RXFIFOALMSTEMPTY      (0x1<<2)
+#define S3C_PCM_FIFOSTAT_RXFIFOFULL            (0x1<<1)
+#define S3C_PCM_FIFOSTAT_RXFIFOALMSTFULL       (0x1<<0)
+
+#define S3C_PCM_CLKSRC_PCLK    0
+#define S3C_PCM_CLKSRC_MUX     1
+
+#define S3C_PCM_SCLK_PER_FS    0
+
+/**
+ * struct s3c_pcm_info - S3C PCM Controller information
+ * @dev: The parent device passed to use from the probe.
+ * @regs: The pointer to the device register block.
+ * @dma_playback: DMA information for playback channel.
+ * @dma_capture: DMA information for capture channel.
+ */
+struct s3c_pcm_info {
+       spinlock_t lock;
+       struct device   *dev;
+       void __iomem    *regs;
+
+       unsigned int sclk_per_fs;
+
+       /* Whether to keep PCMSCLK enabled even when idle(no active xfer) */
+       unsigned int idleclk;
+
+       struct clk      *pclk;
+       struct clk      *cclk;
+
+       struct s3c_dma_params   *dma_playback;
+       struct s3c_dma_params   *dma_capture;
+};
+
+#endif /* __S3C_PCM_H */
index a587ec4..359e593 100644 (file)
 
 #include <plat/regs-s3c2412-iis.h>
 
-#include <plat/audio.h>
 #include <mach/regs-gpio.h>
 #include <mach/dma.h>
 
-#include "s3c24xx-pcm.h"
+#include "s3c-dma.h"
 #include "s3c2412-i2s.h"
 
 #define S3C2412_I2S_DEBUG 0
@@ -51,14 +50,14 @@ static struct s3c2410_dma_client s3c2412_dma_client_in = {
        .name           = "I2S PCM Stereo in"
 };
 
-static struct s3c24xx_pcm_dma_params s3c2412_i2s_pcm_stereo_out = {
+static struct s3c_dma_params s3c2412_i2s_pcm_stereo_out = {
        .client         = &s3c2412_dma_client_out,
        .channel        = DMACH_I2S_OUT,
        .dma_addr       = S3C2410_PA_IIS + S3C2412_IISTXD,
        .dma_size       = 4,
 };
 
-static struct s3c24xx_pcm_dma_params s3c2412_i2s_pcm_stereo_in = {
+static struct s3c_dma_params s3c2412_i2s_pcm_stereo_in = {
        .client         = &s3c2412_dma_client_in,
        .channel        = DMACH_I2S_IN,
        .dma_addr       = S3C2410_PA_IIS + S3C2412_IISRXD,
index fc1beb0..0191e3a 100644 (file)
 #include <plat/regs-ac97.h>
 #include <mach/regs-gpio.h>
 #include <mach/regs-clock.h>
-#include <plat/audio.h>
 #include <asm/dma.h>
 #include <mach/dma.h>
 
-#include "s3c24xx-pcm.h"
+#include "s3c-dma.h"
 #include "s3c24xx-ac97.h"
 
 struct s3c24xx_ac97_info {
@@ -189,21 +188,21 @@ static struct s3c2410_dma_client s3c2443_dma_client_micin = {
        .name = "AC97 Mic Mono in"
 };
 
-static struct s3c24xx_pcm_dma_params s3c2443_ac97_pcm_stereo_out = {
+static struct s3c_dma_params s3c2443_ac97_pcm_stereo_out = {
        .client         = &s3c2443_dma_client_out,
        .channel        = DMACH_PCM_OUT,
        .dma_addr       = S3C2440_PA_AC97 + S3C_AC97_PCM_DATA,
        .dma_size       = 4,
 };
 
-static struct s3c24xx_pcm_dma_params s3c2443_ac97_pcm_stereo_in = {
+static struct s3c_dma_params s3c2443_ac97_pcm_stereo_in = {
        .client         = &s3c2443_dma_client_in,
        .channel        = DMACH_PCM_IN,
        .dma_addr       = S3C2440_PA_AC97 + S3C_AC97_PCM_DATA,
        .dma_size       = 4,
 };
 
-static struct s3c24xx_pcm_dma_params s3c2443_ac97_mic_mono_in = {
+static struct s3c_dma_params s3c2443_ac97_mic_mono_in = {
        .client         = &s3c2443_dma_client_micin,
        .channel        = DMACH_MIC_IN,
        .dma_addr       = S3C2440_PA_AC97 + S3C_AC97_MIC_DATA,
@@ -291,7 +290,7 @@ static int s3c2443_ac97_trigger(struct snd_pcm_substream *substream, int cmd,
 {
        u32 ac_glbctrl;
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       int channel = ((struct s3c24xx_pcm_dma_params *)
+       int channel = ((struct s3c_dma_params *)
                  rtd->dai->cpu_dai->dma_data)->channel;
 
        ac_glbctrl = readl(s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
@@ -340,7 +339,7 @@ static int s3c2443_ac97_mic_trigger(struct snd_pcm_substream *substream,
 {
        u32 ac_glbctrl;
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       int channel = ((struct s3c24xx_pcm_dma_params *)
+       int channel = ((struct s3c_dma_params *)
                  rtd->dai->cpu_dai->dma_data)->channel;
 
        ac_glbctrl = readl(s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
index 40e2c47..0bc5950 100644 (file)
 #include <mach/hardware.h>
 #include <mach/regs-gpio.h>
 #include <mach/regs-clock.h>
-#include <plat/audio.h>
+
 #include <asm/dma.h>
 #include <mach/dma.h>
 
 #include <plat/regs-iis.h>
 
-#include "s3c24xx-pcm.h"
+#include "s3c-dma.h"
 #include "s3c24xx-i2s.h"
 
 static struct s3c2410_dma_client s3c24xx_dma_client_out = {
@@ -49,14 +49,14 @@ static struct s3c2410_dma_client s3c24xx_dma_client_in = {
        .name = "I2S PCM Stereo in"
 };
 
-static struct s3c24xx_pcm_dma_params s3c24xx_i2s_pcm_stereo_out = {
+static struct s3c_dma_params s3c24xx_i2s_pcm_stereo_out = {
        .client         = &s3c24xx_dma_client_out,
        .channel        = DMACH_I2S_OUT,
        .dma_addr       = S3C2410_PA_IIS + S3C2410_IISFIFO,
        .dma_size       = 2,
 };
 
-static struct s3c24xx_pcm_dma_params s3c24xx_i2s_pcm_stereo_in = {
+static struct s3c_dma_params s3c24xx_i2s_pcm_stereo_in = {
        .client         = &s3c24xx_dma_client_in,
        .channel        = DMACH_I2S_IN,
        .dma_addr       = S3C2410_PA_IIS + S3C2410_IISFIFO,
@@ -258,12 +258,12 @@ static int s3c24xx_i2s_hw_params(struct snd_pcm_substream *substream,
        switch (params_format(params)) {
        case SNDRV_PCM_FORMAT_S8:
                iismod &= ~S3C2410_IISMOD_16BIT;
-               ((struct s3c24xx_pcm_dma_params *)
+               ((struct s3c_dma_params *)
                  rtd->dai->cpu_dai->dma_data)->dma_size = 1;
                break;
        case SNDRV_PCM_FORMAT_S16_LE:
                iismod |= S3C2410_IISMOD_16BIT;
-               ((struct s3c24xx_pcm_dma_params *)
+               ((struct s3c_dma_params *)
                  rtd->dai->cpu_dai->dma_data)->dma_size = 2;
                break;
        default:
@@ -280,7 +280,7 @@ static int s3c24xx_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
 {
        int ret = 0;
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       int channel = ((struct s3c24xx_pcm_dma_params *)
+       int channel = ((struct s3c_dma_params *)
                  rtd->dai->cpu_dai->dma_data)->channel;
 
        pr_debug("Entered %s\n", __func__);
index 1966e0d..507b2ed 100644 (file)
@@ -21,7 +21,7 @@
 
 #include <plat/audio-simtec.h>
 
-#include "s3c24xx-pcm.h"
+#include "s3c-dma.h"
 #include "s3c24xx-i2s.h"
 #include "s3c24xx_simtec.h"
 
index 8346bd9..bdf8951 100644 (file)
@@ -18,7 +18,7 @@
 
 #include <plat/audio-simtec.h>
 
-#include "s3c24xx-pcm.h"
+#include "s3c-dma.h"
 #include "s3c24xx-i2s.h"
 #include "s3c24xx_simtec.h"
 
index 25797e0..185c0ac 100644 (file)
@@ -18,7 +18,7 @@
 
 #include <plat/audio-simtec.h>
 
-#include "s3c24xx-pcm.h"
+#include "s3c-dma.h"
 #include "s3c24xx-i2s.h"
 #include "s3c24xx_simtec.h"
 
index c215d32..052d596 100644 (file)
@@ -24,7 +24,7 @@
 
 #include <plat/regs-iis.h>
 
-#include "s3c24xx-pcm.h"
+#include "s3c-dma.h"
 #include "s3c24xx-i2s.h"
 #include "../codecs/uda134x.h"
 
index 105a77e..cc7edb5 100644 (file)
 #include <plat/gpio-bank-d.h>
 #include <plat/gpio-bank-e.h>
 #include <plat/gpio-cfg.h>
-#include <plat/audio.h>
 
 #include <mach/map.h>
 #include <mach/dma.h>
 
-#include "s3c24xx-pcm.h"
+#include "s3c-dma.h"
 #include "s3c64xx-i2s.h"
 
 static struct s3c2410_dma_client s3c64xx_dma_client_out = {
@@ -47,7 +46,7 @@ static struct s3c2410_dma_client s3c64xx_dma_client_in = {
        .name           = "I2S PCM Stereo in"
 };
 
-static struct s3c24xx_pcm_dma_params s3c64xx_i2s_pcm_stereo_out[2] = {
+static struct s3c_dma_params s3c64xx_i2s_pcm_stereo_out[2] = {
        [0] = {
                .channel        = DMACH_I2S0_OUT,
                .client         = &s3c64xx_dma_client_out,
@@ -62,7 +61,7 @@ static struct s3c24xx_pcm_dma_params s3c64xx_i2s_pcm_stereo_out[2] = {
        },
 };
 
-static struct s3c24xx_pcm_dma_params s3c64xx_i2s_pcm_stereo_in[2] = {
+static struct s3c_dma_params s3c64xx_i2s_pcm_stereo_in[2] = {
        [0] = {
                .channel        = DMACH_I2S0_IN,
                .client         = &s3c64xx_dma_client_in,
@@ -99,6 +98,19 @@ static int s3c64xx_i2s_set_sysclk(struct snd_soc_dai *cpu_dai,
                iismod |= S3C64XX_IISMOD_IMS_SYSMUX;
                break;
 
+       case S3C64XX_CLKSRC_CDCLK:
+               switch (dir) {
+               case SND_SOC_CLOCK_IN:
+                       iismod |= S3C64XX_IISMOD_CDCLKCON;
+                       break;
+               case SND_SOC_CLOCK_OUT:
+                       iismod &= ~S3C64XX_IISMOD_CDCLKCON;
+                       break;
+               default:
+                       return -EINVAL;
+               }
+               break;
+
        default:
                return -EINVAL;
        }
@@ -111,8 +123,12 @@ static int s3c64xx_i2s_set_sysclk(struct snd_soc_dai *cpu_dai,
 struct clk *s3c64xx_i2s_get_clock(struct snd_soc_dai *dai)
 {
        struct s3c_i2sv2_info *i2s = to_info(dai);
+       u32 iismod = readl(i2s->regs + S3C2412_IISMOD);
 
-       return i2s->iis_cclk;
+       if (iismod & S3C64XX_IISMOD_IMS_SYSMUX)
+               return i2s->iis_cclk;
+       else
+               return i2s->iis_pclk;
 }
 EXPORT_SYMBOL_GPL(s3c64xx_i2s_get_clock);
 
index 02148ce..abe7253 100644 (file)
@@ -25,6 +25,7 @@ struct clk;
 
 #define S3C64XX_CLKSRC_PCLK    (0)
 #define S3C64XX_CLKSRC_MUX     (1)
+#define S3C64XX_CLKSRC_CDCLK    (2)
 
 extern struct snd_soc_dai s3c64xx_i2s_dai[];
 
index a2a4f53..12b783b 100644 (file)
@@ -20,7 +20,7 @@
 #include <sound/soc-dapm.h>
 
 #include "../codecs/ac97.h"
-#include "s3c24xx-pcm.h"
+#include "s3c-dma.h"
 #include "s3c24xx-ac97.h"
 
 static struct snd_soc_card smdk2443;
diff --git a/sound/soc/s3c24xx/smdk64xx_wm8580.c b/sound/soc/s3c24xx/smdk64xx_wm8580.c
new file mode 100644 (file)
index 0000000..efe4901
--- /dev/null
@@ -0,0 +1,268 @@
+/*
+ *  smdk64xx_wm8580.c
+ *
+ *  Copyright (c) 2009 Samsung Electronics Co. Ltd
+ *  Author: 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 as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ */
+
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+
+#include "../codecs/wm8580.h"
+#include "s3c-dma.h"
+#include "s3c64xx-i2s.h"
+
+#define S3C64XX_I2S_V4 2
+
+/* SMDK64XX has a 12MHZ crystal attached to WM8580 */
+#define SMDK64XX_WM8580_FREQ 12000000
+
+static int smdk64xx_hw_params(struct snd_pcm_substream *substream,
+       struct snd_pcm_hw_params *params)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+       struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
+       unsigned int pll_out;
+       int bfs, rfs, ret;
+
+       switch (params_format(params)) {
+       case SNDRV_PCM_FORMAT_U8:
+       case SNDRV_PCM_FORMAT_S8:
+               bfs = 16;
+               break;
+       case SNDRV_PCM_FORMAT_U16_LE:
+       case SNDRV_PCM_FORMAT_S16_LE:
+               bfs = 32;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       /* The Fvco for WM8580 PLLs must fall within [90,100]MHz.
+        * This criterion can't be met if we request PLL output
+        * as {8000x256, 64000x256, 11025x256}Hz.
+        * As a wayout, we rather change rfs to a minimum value that
+        * results in (params_rate(params) * rfs), and itself, acceptable
+        * to both - the CODEC and the CPU.
+        */
+       switch (params_rate(params)) {
+       case 16000:
+       case 22050:
+       case 32000:
+       case 44100:
+       case 48000:
+       case 88200:
+       case 96000:
+               rfs = 256;
+               break;
+       case 64000:
+               rfs = 384;
+               break;
+       case 8000:
+       case 11025:
+               rfs = 512;
+               break;
+       default:
+               return -EINVAL;
+       }
+       pll_out = params_rate(params) * rfs;
+
+       /* Set the Codec DAI configuration */
+       ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S
+                                        | SND_SOC_DAIFMT_NB_NF
+                                        | SND_SOC_DAIFMT_CBM_CFM);
+       if (ret < 0)
+               return ret;
+
+       /* Set the AP DAI configuration */
+       ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S
+                                        | SND_SOC_DAIFMT_NB_NF
+                                        | SND_SOC_DAIFMT_CBM_CFM);
+       if (ret < 0)
+               return ret;
+
+       ret = snd_soc_dai_set_sysclk(cpu_dai, S3C64XX_CLKSRC_CDCLK,
+                                       0, SND_SOC_CLOCK_IN);
+       if (ret < 0)
+               return ret;
+
+       /* We use PCLK for basic ops in SoC-Slave mode */
+       ret = snd_soc_dai_set_sysclk(cpu_dai, S3C64XX_CLKSRC_PCLK,
+                                       0, SND_SOC_CLOCK_IN);
+       if (ret < 0)
+               return ret;
+
+       /* Set WM8580 to drive MCLK from its PLLA */
+       ret = snd_soc_dai_set_clkdiv(codec_dai, WM8580_MCLK,
+                                       WM8580_CLKSRC_PLLA);
+       if (ret < 0)
+               return ret;
+
+       /* Explicitly set WM8580-DAC to source from MCLK */
+       ret = snd_soc_dai_set_clkdiv(codec_dai, WM8580_DAC_CLKSEL,
+                                       WM8580_CLKSRC_MCLK);
+       if (ret < 0)
+               return ret;
+
+       ret = snd_soc_dai_set_pll(codec_dai, WM8580_PLLA, 0,
+                                       SMDK64XX_WM8580_FREQ, pll_out);
+       if (ret < 0)
+               return ret;
+
+       ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C_I2SV2_DIV_BCLK, bfs);
+       if (ret < 0)
+               return ret;
+
+       ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C_I2SV2_DIV_RCLK, rfs);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+
+/*
+ * SMDK64XX WM8580 DAI operations.
+ */
+static struct snd_soc_ops smdk64xx_ops = {
+       .hw_params = smdk64xx_hw_params,
+};
+
+/* SMDK64xx Playback widgets */
+static const struct snd_soc_dapm_widget wm8580_dapm_widgets_pbk[] = {
+       SND_SOC_DAPM_HP("Front-L/R", NULL),
+       SND_SOC_DAPM_HP("Center/Sub", NULL),
+       SND_SOC_DAPM_HP("Rear-L/R", NULL),
+};
+
+/* SMDK64xx Capture widgets */
+static const struct snd_soc_dapm_widget wm8580_dapm_widgets_cpt[] = {
+       SND_SOC_DAPM_MIC("MicIn", NULL),
+       SND_SOC_DAPM_LINE("LineIn", NULL),
+};
+
+/* SMDK-PAIFTX connections */
+static const struct snd_soc_dapm_route audio_map_tx[] = {
+       /* MicIn feeds AINL */
+       {"AINL", NULL, "MicIn"},
+
+       /* LineIn feeds AINL/R */
+       {"AINL", NULL, "LineIn"},
+       {"AINR", NULL, "LineIn"},
+};
+
+/* SMDK-PAIFRX connections */
+static const struct snd_soc_dapm_route audio_map_rx[] = {
+       /* Front Left/Right are fed VOUT1L/R */
+       {"Front-L/R", NULL, "VOUT1L"},
+       {"Front-L/R", NULL, "VOUT1R"},
+
+       /* Center/Sub are fed VOUT2L/R */
+       {"Center/Sub", NULL, "VOUT2L"},
+       {"Center/Sub", NULL, "VOUT2R"},
+
+       /* Rear Left/Right are fed VOUT3L/R */
+       {"Rear-L/R", NULL, "VOUT3L"},
+       {"Rear-L/R", NULL, "VOUT3R"},
+};
+
+static int smdk64xx_wm8580_init_paiftx(struct snd_soc_codec *codec)
+{
+       /* Add smdk64xx specific Capture widgets */
+       snd_soc_dapm_new_controls(codec, wm8580_dapm_widgets_cpt,
+                                 ARRAY_SIZE(wm8580_dapm_widgets_cpt));
+
+       /* Set up PAIFTX audio path */
+       snd_soc_dapm_add_routes(codec, audio_map_tx, ARRAY_SIZE(audio_map_tx));
+
+       /* Enabling the microphone requires the fitting of a 0R
+        * resistor to connect the line from the microphone jack.
+        */
+       snd_soc_dapm_disable_pin(codec, "MicIn");
+
+       /* signal a DAPM event */
+       snd_soc_dapm_sync(codec);
+
+       return 0;
+}
+
+static int smdk64xx_wm8580_init_paifrx(struct snd_soc_codec *codec)
+{
+       /* Add smdk64xx specific Playback widgets */
+       snd_soc_dapm_new_controls(codec, wm8580_dapm_widgets_pbk,
+                                 ARRAY_SIZE(wm8580_dapm_widgets_pbk));
+
+       /* Set up PAIFRX audio path */
+       snd_soc_dapm_add_routes(codec, audio_map_rx, ARRAY_SIZE(audio_map_rx));
+
+       /* signal a DAPM event */
+       snd_soc_dapm_sync(codec);
+
+       return 0;
+}
+
+static struct snd_soc_dai_link smdk64xx_dai[] = {
+{ /* Primary Playback i/f */
+       .name = "WM8580 PAIF RX",
+       .stream_name = "Playback",
+       .cpu_dai = &s3c64xx_i2s_dai[S3C64XX_I2S_V4],
+       .codec_dai = &wm8580_dai[WM8580_DAI_PAIFRX],
+       .init = smdk64xx_wm8580_init_paifrx,
+       .ops = &smdk64xx_ops,
+},
+{ /* Primary Capture i/f */
+       .name = "WM8580 PAIF TX",
+       .stream_name = "Capture",
+       .cpu_dai = &s3c64xx_i2s_dai[S3C64XX_I2S_V4],
+       .codec_dai = &wm8580_dai[WM8580_DAI_PAIFTX],
+       .init = smdk64xx_wm8580_init_paiftx,
+       .ops = &smdk64xx_ops,
+},
+};
+
+static struct snd_soc_card smdk64xx = {
+       .name = "smdk64xx",
+       .platform = &s3c24xx_soc_platform,
+       .dai_link = smdk64xx_dai,
+       .num_links = ARRAY_SIZE(smdk64xx_dai),
+};
+
+static struct snd_soc_device smdk64xx_snd_devdata = {
+       .card = &smdk64xx,
+       .codec_dev = &soc_codec_dev_wm8580,
+};
+
+static struct platform_device *smdk64xx_snd_device;
+
+static int __init smdk64xx_audio_init(void)
+{
+       int ret;
+
+       smdk64xx_snd_device = platform_device_alloc("soc-audio", -1);
+       if (!smdk64xx_snd_device)
+               return -ENOMEM;
+
+       platform_set_drvdata(smdk64xx_snd_device, &smdk64xx_snd_devdata);
+       smdk64xx_snd_devdata.dev = &smdk64xx_snd_device->dev;
+       ret = platform_device_add(smdk64xx_snd_device);
+
+       if (ret)
+               platform_device_put(smdk64xx_snd_device);
+
+       return ret;
+}
+module_init(smdk64xx_audio_init);
+
+MODULE_AUTHOR("Jaswinder Singh, jassi.brar@samsung.com");
+MODULE_DESCRIPTION("ALSA SoC SMDK64XX WM8580");
+MODULE_LICENSE("GPL");
index 83b8028..0eb1722 100644 (file)
@@ -423,7 +423,7 @@ static void s6000_pcm_free(struct snd_pcm *pcm)
        snd_pcm_lib_preallocate_free_for_all(pcm);
 }
 
-static u64 s6000_pcm_dmamask = DMA_32BIT_MASK;
+static u64 s6000_pcm_dmamask = DMA_BIT_MASK(32);
 
 static int s6000_pcm_new(struct snd_card *card,
                         struct snd_soc_dai *dai, struct snd_pcm *pcm)
@@ -435,7 +435,7 @@ static int s6000_pcm_new(struct snd_card *card,
        if (!card->dev->dma_mask)
                card->dev->dma_mask = &s6000_pcm_dmamask;
        if (!card->dev->coherent_dma_mask)
-               card->dev->coherent_dma_mask = DMA_32BIT_MASK;
+               card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
 
        if (params->dma_in) {
                s6dmac_disable_chan(DMA_MASK_DMAC(params->dma_in),
index 9154b43..9e69765 100644 (file)
@@ -23,7 +23,6 @@ config SND_SOC_SH4_SSI
 config SND_SOC_SH4_FSI
        tristate "SH4 FSI support"
        depends on CPU_SUBTYPE_SH7724
-        select SH_DMA
        help
          This option enables FSI sound support
 
index 4412324..9c49c11 100644 (file)
@@ -17,7 +17,7 @@
 #include <linux/platform_device.h>
 #include <linux/delay.h>
 #include <linux/list.h>
-#include <linux/clk.h>
+#include <linux/pm_runtime.h>
 #include <linux/io.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
@@ -26,8 +26,6 @@
 #include <sound/pcm_params.h>
 #include <sound/sh_fsi.h>
 #include <asm/atomic.h>
-#include <asm/dma.h>
-#include <asm/dma-sh.h>
 
 #define DO_FMT         0x0000
 #define DOFF_CTL       0x0004
@@ -97,7 +95,6 @@ struct fsi_priv {
 
        int fifo_max;
        int chan;
-       int dma_chan;
 
        int byte_offset;
        int period_len;
@@ -108,7 +105,6 @@ struct fsi_priv {
 struct fsi_master {
        void __iomem *base;
        int irq;
-       struct clk *clk;
        struct fsi_priv fsia;
        struct fsi_priv fsib;
        struct sh_fsi_platform_info *info;
@@ -308,62 +304,6 @@ static int fsi_get_fifo_residue(struct fsi_priv *fsi, int is_play)
        return residue;
 }
 
-static int fsi_get_residue(struct fsi_priv *fsi, int is_play)
-{
-       int residue;
-       int width;
-       struct snd_pcm_runtime *runtime;
-
-       runtime = fsi->substream->runtime;
-
-       /* get 1 channel data width */
-       width = frames_to_bytes(runtime, 1) / fsi->chan;
-
-       if (2 == width)
-               residue = fsi_get_fifo_residue(fsi, is_play);
-       else
-               residue = get_dma_residue(fsi->dma_chan);
-
-       return residue;
-}
-
-/************************************************************************
-
-
-               basic dma function
-
-
-************************************************************************/
-#define PORTA_DMA 0
-#define PORTB_DMA 1
-
-static int fsi_get_dma_chan(void)
-{
-       if (0 != request_dma(PORTA_DMA, "fsia"))
-               return -EIO;
-
-       if (0 != request_dma(PORTB_DMA, "fsib")) {
-               free_dma(PORTA_DMA);
-               return -EIO;
-       }
-
-       master->fsia.dma_chan = PORTA_DMA;
-       master->fsib.dma_chan = PORTB_DMA;
-
-       return 0;
-}
-
-static void fsi_free_dma_chan(void)
-{
-       dma_wait_for_completion(PORTA_DMA);
-       dma_wait_for_completion(PORTB_DMA);
-       free_dma(PORTA_DMA);
-       free_dma(PORTB_DMA);
-
-       master->fsia.dma_chan = -1;
-       master->fsib.dma_chan = -1;
-}
-
 /************************************************************************
 
 
@@ -435,44 +375,6 @@ static void fsi_soft_all_reset(void)
        mdelay(10);
 }
 
-static void fsi_16data_push(struct fsi_priv *fsi,
-                          struct snd_pcm_runtime *runtime,
-                          int send)
-{
-       u16 *dma_start;
-       u32 snd;
-       int i;
-
-       /* get dma start position for FSI */
-       dma_start = (u16 *)runtime->dma_area;
-       dma_start += fsi->byte_offset / 2;
-
-       /*
-        * soft dma
-        * FSI can not use DMA when 16bpp
-        */
-       for (i = 0; i < send; i++) {
-               snd = (u32)dma_start[i];
-               fsi_reg_write(fsi, DODT, snd << 8);
-       }
-}
-
-static void fsi_32data_push(struct fsi_priv *fsi,
-                          struct snd_pcm_runtime *runtime,
-                          int send)
-{
-       u32 *dma_start;
-
-       /* get dma start position for FSI */
-       dma_start = (u32 *)runtime->dma_area;
-       dma_start += fsi->byte_offset / 4;
-
-       dma_wait_for_completion(fsi->dma_chan);
-       dma_configure_channel(fsi->dma_chan, (SM_INC|0x400|TS_32|TM_BUR));
-       dma_write(fsi->dma_chan, (u32)dma_start,
-                 (u32)(fsi->base + DODT), send * 4);
-}
-
 /* playback interrupt */
 static int fsi_data_push(struct fsi_priv *fsi)
 {
@@ -481,6 +383,8 @@ static int fsi_data_push(struct fsi_priv *fsi)
        int send;
        int fifo_free;
        int width;
+       u8 *start;
+       int i;
 
        if (!fsi                        ||
            !fsi->substream             ||
@@ -515,12 +419,22 @@ static int fsi_data_push(struct fsi_priv *fsi)
        if (fifo_free < send)
                send = fifo_free;
 
-       if (2 == width)
-               fsi_16data_push(fsi, runtime, send);
-       else if (4 == width)
-               fsi_32data_push(fsi, runtime, send);
-       else
+       start = runtime->dma_area;
+       start += fsi->byte_offset;
+
+       switch (width) {
+       case 2:
+               for (i = 0; i < send; i++)
+                       fsi_reg_write(fsi, DODT,
+                                     ((u32)*((u16 *)start + i) << 8));
+               break;
+       case 4:
+               for (i = 0; i < send; i++)
+                       fsi_reg_write(fsi, DODT, *((u32 *)start + i));
+               break;
+       default:
                return -EINVAL;
+       }
 
        fsi->byte_offset += send * width;
 
@@ -532,6 +446,75 @@ static int fsi_data_push(struct fsi_priv *fsi)
        return 0;
 }
 
+static int fsi_data_pop(struct fsi_priv *fsi)
+{
+       struct snd_pcm_runtime *runtime;
+       struct snd_pcm_substream *substream = NULL;
+       int free;
+       int fifo_fill;
+       int width;
+       u8 *start;
+       int i;
+
+       if (!fsi                        ||
+           !fsi->substream             ||
+           !fsi->substream->runtime)
+               return -EINVAL;
+
+       runtime = fsi->substream->runtime;
+
+       /* FSI FIFO has limit.
+        * So, this driver can not send periods data at a time
+        */
+       if (fsi->byte_offset >=
+           fsi->period_len * (fsi->periods + 1)) {
+
+               substream = fsi->substream;
+               fsi->periods = (fsi->periods + 1) % runtime->periods;
+
+               if (0 == fsi->periods)
+                       fsi->byte_offset = 0;
+       }
+
+       /* get 1 channel data width */
+       width = frames_to_bytes(runtime, 1) / fsi->chan;
+
+       /* get free space for alsa */
+       free = (fsi->buffer_len - fsi->byte_offset) / width;
+
+       /* get recv size */
+       fifo_fill = fsi_get_fifo_residue(fsi, 0);
+
+       if (free < fifo_fill)
+               fifo_fill = free;
+
+       start = runtime->dma_area;
+       start += fsi->byte_offset;
+
+       switch (width) {
+       case 2:
+               for (i = 0; i < fifo_fill; i++)
+                       *((u16 *)start + i) =
+                               (u16)(fsi_reg_read(fsi, DIDT) >> 8);
+               break;
+       case 4:
+               for (i = 0; i < fifo_fill; i++)
+                       *((u32 *)start + i) = fsi_reg_read(fsi, DIDT);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       fsi->byte_offset += fifo_fill * width;
+
+       fsi_irq_enable(fsi, 0);
+
+       if (substream)
+               snd_pcm_period_elapsed(substream);
+
+       return 0;
+}
+
 static irqreturn_t fsi_interrupt(int irq, void *data)
 {
        u32 status = fsi_master_read(SOFT_RST) & ~0x00000010;
@@ -545,6 +528,10 @@ static irqreturn_t fsi_interrupt(int irq, void *data)
                fsi_data_push(&master->fsia);
        if (int_st & INT_B_OUT)
                fsi_data_push(&master->fsib);
+       if (int_st & INT_A_IN)
+               fsi_data_pop(&master->fsia);
+       if (int_st & INT_B_IN)
+               fsi_data_pop(&master->fsib);
 
        fsi_master_write(INT_ST, 0x0000000);
 
@@ -571,7 +558,7 @@ static int fsi_dai_startup(struct snd_pcm_substream *substream,
        int is_master;
        int ret = 0;
 
-       clk_enable(master->clk);
+       pm_runtime_get_sync(dai->dev);
 
        /* CKG1 */
        data = is_play ? (1 << 0) : (1 << 4);
@@ -664,8 +651,6 @@ static int fsi_dai_startup(struct snd_pcm_substream *substream,
        }
 
        fsi_reg_write(fsi, reg, data);
-       dev_dbg(dai->dev, "use %s format (%d channel) use %d DMAC\n",
-               msg, fsi->chan, fsi->dma_chan);
 
        /*
         * clear clk reset if master mode
@@ -688,7 +673,7 @@ static void fsi_dai_shutdown(struct snd_pcm_substream *substream,
        fsi_irq_disable(fsi, is_play);
        fsi_clk_ctrl(fsi, 0);
 
-       clk_disable(master->clk);
+       pm_runtime_put_sync(dai->dev);
 }
 
 static int fsi_dai_trigger(struct snd_pcm_substream *substream, int cmd,
@@ -699,16 +684,12 @@ static int fsi_dai_trigger(struct snd_pcm_substream *substream, int cmd,
        int is_play = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
        int ret = 0;
 
-       /* capture not supported */
-       if (!is_play)
-               return -ENODEV;
-
        switch (cmd) {
        case SNDRV_PCM_TRIGGER_START:
                fsi_stream_push(fsi, substream,
                                frames_to_bytes(runtime, runtime->buffer_size),
                                frames_to_bytes(runtime, runtime->period_size));
-               ret = fsi_data_push(fsi);
+               ret = is_play ? fsi_data_push(fsi) : fsi_data_pop(fsi);
                break;
        case SNDRV_PCM_TRIGGER_STOP:
                fsi_irq_disable(fsi, is_play);
@@ -780,10 +761,9 @@ static snd_pcm_uframes_t fsi_pointer(struct snd_pcm_substream *substream)
 {
        struct snd_pcm_runtime *runtime = substream->runtime;
        struct fsi_priv *fsi = fsi_get(substream);
-       int is_play = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
        long location;
 
-       location = (fsi->byte_offset - 1) - fsi_get_residue(fsi, is_play);
+       location = (fsi->byte_offset - 1);
        if (location < 0)
                location = 0;
 
@@ -845,7 +825,12 @@ struct snd_soc_dai fsi_soc_dai[] = {
                        .channels_min   = 1,
                        .channels_max   = 8,
                },
-               /* capture not supported */
+               .capture = {
+                       .rates          = FSI_RATES,
+                       .formats        = FSI_FMTS,
+                       .channels_min   = 1,
+                       .channels_max   = 8,
+               },
                .ops = &fsi_dai_ops,
        },
        {
@@ -857,7 +842,12 @@ struct snd_soc_dai fsi_soc_dai[] = {
                        .channels_min   = 1,
                        .channels_max   = 8,
                },
-               /* capture not supported */
+               .capture = {
+                       .rates          = FSI_RATES,
+                       .formats        = FSI_FMTS,
+                       .channels_min   = 1,
+                       .channels_max   = 8,
+               },
                .ops = &fsi_dai_ops,
        },
 };
@@ -881,7 +871,6 @@ EXPORT_SYMBOL_GPL(fsi_soc_platform);
 static int fsi_probe(struct platform_device *pdev)
 {
        struct resource *res;
-       char clk_name[8];
        unsigned int irq;
        int ret;
 
@@ -912,23 +901,8 @@ static int fsi_probe(struct platform_device *pdev)
        master->fsia.base       = master->base;
        master->fsib.base       = master->base + 0x40;
 
-       master->fsia.dma_chan = -1;
-       master->fsib.dma_chan = -1;
-
-       ret = fsi_get_dma_chan();
-       if (ret < 0) {
-               dev_err(&pdev->dev, "cannot get dma api\n");
-               goto exit_iounmap;
-       }
-
-       /* FSI is based on SPU mstp */
-       snprintf(clk_name, sizeof(clk_name), "spu%d", pdev->id);
-       master->clk = clk_get(NULL, clk_name);
-       if (IS_ERR(master->clk)) {
-               dev_err(&pdev->dev, "cannot get %s mstp\n", clk_name);
-               ret = -EIO;
-               goto exit_free_dma;
-       }
+       pm_runtime_enable(&pdev->dev);
+       pm_runtime_resume(&pdev->dev);
 
        fsi_soc_dai[0].dev              = &pdev->dev;
        fsi_soc_dai[1].dev              = &pdev->dev;
@@ -938,7 +912,7 @@ static int fsi_probe(struct platform_device *pdev)
        ret = request_irq(irq, &fsi_interrupt, IRQF_DISABLED, "fsi", master);
        if (ret) {
                dev_err(&pdev->dev, "irq request err\n");
-               goto exit_free_dma;
+               goto exit_iounmap;
        }
 
        ret = snd_soc_register_platform(&fsi_soc_platform);
@@ -951,10 +925,9 @@ static int fsi_probe(struct platform_device *pdev)
 
 exit_free_irq:
        free_irq(irq, master);
-exit_free_dma:
-       fsi_free_dma_chan();
 exit_iounmap:
        iounmap(master->base);
+       pm_runtime_disable(&pdev->dev);
 exit_kfree:
        kfree(master);
        master = NULL;
@@ -967,9 +940,7 @@ static int fsi_remove(struct platform_device *pdev)
        snd_soc_unregister_dais(fsi_soc_dai, ARRAY_SIZE(fsi_soc_dai));
        snd_soc_unregister_platform(&fsi_soc_platform);
 
-       clk_put(master->clk);
-
-       fsi_free_dma_chan();
+       pm_runtime_disable(&pdev->dev);
 
        free_irq(master->irq, master);
 
@@ -979,9 +950,27 @@ static int fsi_remove(struct platform_device *pdev)
        return 0;
 }
 
+static int fsi_runtime_nop(struct device *dev)
+{
+       /* Runtime PM callback shared between ->runtime_suspend()
+        * and ->runtime_resume(). Simply returns success.
+        *
+        * This driver re-initializes all registers after
+        * pm_runtime_get_sync() anyway so there is no need
+        * to save and restore registers here.
+        */
+       return 0;
+}
+
+static struct dev_pm_ops fsi_pm_ops = {
+       .runtime_suspend        = fsi_runtime_nop,
+       .runtime_resume         = fsi_runtime_nop,
+};
+
 static struct platform_driver fsi_driver = {
        .driver         = {
                .name   = "sh_fsi",
+               .pm     = &fsi_pm_ops,
        },
        .probe          = fsi_probe,
        .remove         = fsi_remove,
index c8ceddc..d2505e8 100644 (file)
@@ -77,6 +77,35 @@ static int snd_soc_7_9_spi_write(void *control_data, const char *data,
 #define snd_soc_7_9_spi_write NULL
 #endif
 
+static int snd_soc_8_8_write(struct snd_soc_codec *codec, unsigned int reg,
+                            unsigned int value)
+{
+       u8 *cache = codec->reg_cache;
+       u8 data[2];
+
+       BUG_ON(codec->volatile_register);
+
+       data[0] = reg & 0xff;
+       data[1] = value & 0xff;
+
+       if (reg < codec->reg_cache_size)
+               cache[reg] = value;
+
+       if (codec->hw_write(codec->control_data, data, 2) == 2)
+               return 0;
+       else
+               return -EIO;
+}
+
+static unsigned int snd_soc_8_8_read(struct snd_soc_codec *codec,
+                                    unsigned int reg)
+{
+       u8 *cache = codec->reg_cache;
+       if (reg >= codec->reg_cache_size)
+               return -1;
+       return cache[reg];
+}
+
 static int snd_soc_8_16_write(struct snd_soc_codec *codec, unsigned int reg,
                              unsigned int value)
 {
@@ -150,9 +179,20 @@ static struct {
        unsigned int (*read)(struct snd_soc_codec *, unsigned int);
        unsigned int (*i2c_read)(struct snd_soc_codec *, unsigned int);
 } io_types[] = {
-       { 7, 9, snd_soc_7_9_write, snd_soc_7_9_spi_write, snd_soc_7_9_read },
-       { 8, 16, snd_soc_8_16_write, NULL, snd_soc_8_16_read,
-         snd_soc_8_16_read_i2c },
+       {
+               .addr_bits = 7, .data_bits = 9,
+               .write = snd_soc_7_9_write, .read = snd_soc_7_9_read,
+               .spi_write = snd_soc_7_9_spi_write 
+       },
+       {
+               .addr_bits = 8, .data_bits = 8,
+               .write = snd_soc_8_8_write, .read = snd_soc_8_8_read,
+       },
+       {
+               .addr_bits = 8, .data_bits = 16,
+               .write = snd_soc_8_16_write, .read = snd_soc_8_16_read,
+               .i2c_read = snd_soc_8_16_read_i2c,
+       },
 };
 
 /**
index 0a1b2f6..ef8f282 100644 (file)
@@ -37,7 +37,6 @@
 #include <sound/initval.h>
 
 static DEFINE_MUTEX(pcm_mutex);
-static DEFINE_MUTEX(io_mutex);
 static DECLARE_WAIT_QUEUE_HEAD(soc_pm_waitq);
 
 #ifdef CONFIG_DEBUG_FS
@@ -81,6 +80,173 @@ static int run_delayed_work(struct delayed_work *dwork)
        return ret;
 }
 
+/* codec register dump */
+static ssize_t soc_codec_reg_show(struct snd_soc_codec *codec, char *buf)
+{
+       int i, step = 1, count = 0;
+
+       if (!codec->reg_cache_size)
+               return 0;
+
+       if (codec->reg_cache_step)
+               step = codec->reg_cache_step;
+
+       count += sprintf(buf, "%s registers\n", codec->name);
+       for (i = 0; i < codec->reg_cache_size; i += step) {
+               if (codec->readable_register && !codec->readable_register(i))
+                       continue;
+
+               count += sprintf(buf + count, "%2x: ", i);
+               if (count >= PAGE_SIZE - 1)
+                       break;
+
+               if (codec->display_register)
+                       count += codec->display_register(codec, buf + count,
+                                                        PAGE_SIZE - count, i);
+               else
+                       count += snprintf(buf + count, PAGE_SIZE - count,
+                                         "%4x", codec->read(codec, i));
+
+               if (count >= PAGE_SIZE - 1)
+                       break;
+
+               count += snprintf(buf + count, PAGE_SIZE - count, "\n");
+               if (count >= PAGE_SIZE - 1)
+                       break;
+       }
+
+       /* Truncate count; min() would cause a warning */
+       if (count >= PAGE_SIZE)
+               count = PAGE_SIZE - 1;
+
+       return count;
+}
+static ssize_t codec_reg_show(struct device *dev,
+       struct device_attribute *attr, char *buf)
+{
+       struct snd_soc_device *devdata = dev_get_drvdata(dev);
+       return soc_codec_reg_show(devdata->card->codec, buf);
+}
+
+static DEVICE_ATTR(codec_reg, 0444, codec_reg_show, NULL);
+
+#ifdef CONFIG_DEBUG_FS
+static int codec_reg_open_file(struct inode *inode, struct file *file)
+{
+       file->private_data = inode->i_private;
+       return 0;
+}
+
+static ssize_t codec_reg_read_file(struct file *file, char __user *user_buf,
+                              size_t count, loff_t *ppos)
+{
+       ssize_t ret;
+       struct snd_soc_codec *codec = file->private_data;
+       char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+       ret = soc_codec_reg_show(codec, buf);
+       if (ret >= 0)
+               ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
+       kfree(buf);
+       return ret;
+}
+
+static ssize_t codec_reg_write_file(struct file *file,
+               const char __user *user_buf, size_t count, loff_t *ppos)
+{
+       char buf[32];
+       int buf_size;
+       char *start = buf;
+       unsigned long reg, value;
+       int step = 1;
+       struct snd_soc_codec *codec = file->private_data;
+
+       buf_size = min(count, (sizeof(buf)-1));
+       if (copy_from_user(buf, user_buf, buf_size))
+               return -EFAULT;
+       buf[buf_size] = 0;
+
+       if (codec->reg_cache_step)
+               step = codec->reg_cache_step;
+
+       while (*start == ' ')
+               start++;
+       reg = simple_strtoul(start, &start, 16);
+       if ((reg >= codec->reg_cache_size) || (reg % step))
+               return -EINVAL;
+       while (*start == ' ')
+               start++;
+       if (strict_strtoul(start, 16, &value))
+               return -EINVAL;
+       codec->write(codec, reg, value);
+       return buf_size;
+}
+
+static const struct file_operations codec_reg_fops = {
+       .open = codec_reg_open_file,
+       .read = codec_reg_read_file,
+       .write = codec_reg_write_file,
+};
+
+static void soc_init_codec_debugfs(struct snd_soc_codec *codec)
+{
+       char codec_root[128];
+
+       if (codec->dev)
+               snprintf(codec_root, sizeof(codec_root),
+                       "%s.%s", codec->name, dev_name(codec->dev));
+       else
+               snprintf(codec_root, sizeof(codec_root),
+                       "%s", codec->name);
+
+       codec->debugfs_codec_root = debugfs_create_dir(codec_root,
+                                                      debugfs_root);
+       if (!codec->debugfs_codec_root) {
+               printk(KERN_WARNING
+                      "ASoC: Failed to create codec debugfs directory\n");
+               return;
+       }
+
+       codec->debugfs_reg = debugfs_create_file("codec_reg", 0644,
+                                                codec->debugfs_codec_root,
+                                                codec, &codec_reg_fops);
+       if (!codec->debugfs_reg)
+               printk(KERN_WARNING
+                      "ASoC: Failed to create codec register debugfs file\n");
+
+       codec->debugfs_pop_time = debugfs_create_u32("dapm_pop_time", 0744,
+                                                    codec->debugfs_codec_root,
+                                                    &codec->pop_time);
+       if (!codec->debugfs_pop_time)
+               printk(KERN_WARNING
+                      "Failed to create pop time debugfs file\n");
+
+       codec->debugfs_dapm = debugfs_create_dir("dapm",
+                                                codec->debugfs_codec_root);
+       if (!codec->debugfs_dapm)
+               printk(KERN_WARNING
+                      "Failed to create DAPM debugfs directory\n");
+
+       snd_soc_dapm_debugfs_init(codec);
+}
+
+static void soc_cleanup_codec_debugfs(struct snd_soc_codec *codec)
+{
+       debugfs_remove_recursive(codec->debugfs_codec_root);
+}
+
+#else
+
+static inline void soc_init_codec_debugfs(struct snd_soc_codec *codec)
+{
+}
+
+static inline void soc_cleanup_codec_debugfs(struct snd_soc_codec *codec)
+{
+}
+#endif
+
 #ifdef CONFIG_SND_SOC_AC97_BUS
 /* unregister ac97 codec */
 static int soc_ac97_dev_unregister(struct snd_soc_codec *codec)
@@ -790,45 +956,6 @@ static int soc_resume(struct device *dev)
 
        return 0;
 }
-
-/**
- * snd_soc_suspend_device: Notify core of device suspend
- *
- * @dev: Device being suspended.
- *
- * In order to ensure that the entire audio subsystem is suspended in a
- * coordinated fashion ASoC devices should suspend themselves when
- * called by ASoC.  When the standard kernel suspend process asks the
- * device to suspend it should call this function to initiate a suspend
- * of the entire ASoC card.
- *
- * \note Currently this function is stubbed out.
- */
-int snd_soc_suspend_device(struct device *dev)
-{
-       return 0;
-}
-EXPORT_SYMBOL_GPL(snd_soc_suspend_device);
-
-/**
- * snd_soc_resume_device: Notify core of device resume
- *
- * @dev: Device being resumed.
- *
- * In order to ensure that the entire audio subsystem is resumed in a
- * coordinated fashion ASoC devices should resume themselves when called
- * by ASoC.  When the standard kernel resume process asks the device
- * to resume it should call this function.  Once all the components of
- * the card have notified that they are ready to be resumed the card
- * will be resumed.
- *
- * \note Currently this function is stubbed out.
- */
-int snd_soc_resume_device(struct device *dev)
-{
-       return 0;
-}
-EXPORT_SYMBOL_GPL(snd_soc_resume_device);
 #else
 #define soc_suspend    NULL
 #define soc_resume     NULL
@@ -843,6 +970,7 @@ static void snd_soc_instantiate_card(struct snd_soc_card *card)
                                                    struct platform_device,
                                                    dev);
        struct snd_soc_codec_device *codec_dev = card->socdev->codec_dev;
+       struct snd_soc_codec *codec;
        struct snd_soc_platform *platform;
        struct snd_soc_dai *dai;
        int i, found, ret, ac97;
@@ -931,6 +1059,7 @@ static void snd_soc_instantiate_card(struct snd_soc_card *card)
                if (ret < 0)
                        goto cpu_dai_err;
        }
+       codec = card->codec;
 
        if (platform->probe) {
                ret = platform->probe(pdev);
@@ -945,10 +1074,69 @@ static void snd_soc_instantiate_card(struct snd_soc_card *card)
        INIT_WORK(&card->deferred_resume_work, soc_resume_deferred);
 #endif
 
+       for (i = 0; i < card->num_links; i++) {
+               if (card->dai_link[i].init) {
+                       ret = card->dai_link[i].init(codec);
+                       if (ret < 0) {
+                               printk(KERN_ERR "asoc: failed to init %s\n",
+                                       card->dai_link[i].stream_name);
+                               continue;
+                       }
+               }
+               if (card->dai_link[i].codec_dai->ac97_control)
+                       ac97 = 1;
+       }
+
+       snprintf(codec->card->shortname, sizeof(codec->card->shortname),
+                "%s",  card->name);
+       snprintf(codec->card->longname, sizeof(codec->card->longname),
+                "%s (%s)", card->name, codec->name);
+
+       /* Make sure all DAPM widgets are instantiated */
+       snd_soc_dapm_new_widgets(codec);
+
+       ret = snd_card_register(codec->card);
+       if (ret < 0) {
+               printk(KERN_ERR "asoc: failed to register soundcard for %s\n",
+                               codec->name);
+               goto card_err;
+       }
+
+       mutex_lock(&codec->mutex);
+#ifdef CONFIG_SND_SOC_AC97_BUS
+       /* Only instantiate AC97 if not already done by the adaptor
+        * for the generic AC97 subsystem.
+        */
+       if (ac97 && strcmp(codec->name, "AC97") != 0) {
+               ret = soc_ac97_dev_register(codec);
+               if (ret < 0) {
+                       printk(KERN_ERR "asoc: AC97 device register failed\n");
+                       snd_card_free(codec->card);
+                       mutex_unlock(&codec->mutex);
+                       goto card_err;
+               }
+       }
+#endif
+
+       ret = snd_soc_dapm_sys_add(card->socdev->dev);
+       if (ret < 0)
+               printk(KERN_WARNING "asoc: failed to add dapm sysfs entries\n");
+
+       ret = device_create_file(card->socdev->dev, &dev_attr_codec_reg);
+       if (ret < 0)
+               printk(KERN_WARNING "asoc: failed to add codec sysfs files\n");
+
+       soc_init_codec_debugfs(codec);
+       mutex_unlock(&codec->mutex);
+
        card->instantiated = 1;
 
        return;
 
+card_err:
+       if (platform->remove)
+               platform->remove(pdev);
+
 platform_err:
        if (codec_dev->remove)
                codec_dev->remove(pdev);
@@ -1151,157 +1339,6 @@ int snd_soc_codec_volatile_register(struct snd_soc_codec *codec, int reg)
 }
 EXPORT_SYMBOL_GPL(snd_soc_codec_volatile_register);
 
-/* codec register dump */
-static ssize_t soc_codec_reg_show(struct snd_soc_codec *codec, char *buf)
-{
-       int i, step = 1, count = 0;
-
-       if (!codec->reg_cache_size)
-               return 0;
-
-       if (codec->reg_cache_step)
-               step = codec->reg_cache_step;
-
-       count += sprintf(buf, "%s registers\n", codec->name);
-       for (i = 0; i < codec->reg_cache_size; i += step) {
-               if (codec->readable_register && !codec->readable_register(i))
-                       continue;
-
-               count += sprintf(buf + count, "%2x: ", i);
-               if (count >= PAGE_SIZE - 1)
-                       break;
-
-               if (codec->display_register)
-                       count += codec->display_register(codec, buf + count,
-                                                        PAGE_SIZE - count, i);
-               else
-                       count += snprintf(buf + count, PAGE_SIZE - count,
-                                         "%4x", codec->read(codec, i));
-
-               if (count >= PAGE_SIZE - 1)
-                       break;
-
-               count += snprintf(buf + count, PAGE_SIZE - count, "\n");
-               if (count >= PAGE_SIZE - 1)
-                       break;
-       }
-
-       /* Truncate count; min() would cause a warning */
-       if (count >= PAGE_SIZE)
-               count = PAGE_SIZE - 1;
-
-       return count;
-}
-static ssize_t codec_reg_show(struct device *dev,
-       struct device_attribute *attr, char *buf)
-{
-       struct snd_soc_device *devdata = dev_get_drvdata(dev);
-       return soc_codec_reg_show(devdata->card->codec, buf);
-}
-
-static DEVICE_ATTR(codec_reg, 0444, codec_reg_show, NULL);
-
-#ifdef CONFIG_DEBUG_FS
-static int codec_reg_open_file(struct inode *inode, struct file *file)
-{
-       file->private_data = inode->i_private;
-       return 0;
-}
-
-static ssize_t codec_reg_read_file(struct file *file, char __user *user_buf,
-                              size_t count, loff_t *ppos)
-{
-       ssize_t ret;
-       struct snd_soc_codec *codec = file->private_data;
-       char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
-       if (!buf)
-               return -ENOMEM;
-       ret = soc_codec_reg_show(codec, buf);
-       if (ret >= 0)
-               ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
-       kfree(buf);
-       return ret;
-}
-
-static ssize_t codec_reg_write_file(struct file *file,
-               const char __user *user_buf, size_t count, loff_t *ppos)
-{
-       char buf[32];
-       int buf_size;
-       char *start = buf;
-       unsigned long reg, value;
-       int step = 1;
-       struct snd_soc_codec *codec = file->private_data;
-
-       buf_size = min(count, (sizeof(buf)-1));
-       if (copy_from_user(buf, user_buf, buf_size))
-               return -EFAULT;
-       buf[buf_size] = 0;
-
-       if (codec->reg_cache_step)
-               step = codec->reg_cache_step;
-
-       while (*start == ' ')
-               start++;
-       reg = simple_strtoul(start, &start, 16);
-       if ((reg >= codec->reg_cache_size) || (reg % step))
-               return -EINVAL;
-       while (*start == ' ')
-               start++;
-       if (strict_strtoul(start, 16, &value))
-               return -EINVAL;
-       codec->write(codec, reg, value);
-       return buf_size;
-}
-
-static const struct file_operations codec_reg_fops = {
-       .open = codec_reg_open_file,
-       .read = codec_reg_read_file,
-       .write = codec_reg_write_file,
-};
-
-static void soc_init_codec_debugfs(struct snd_soc_codec *codec)
-{
-       codec->debugfs_reg = debugfs_create_file("codec_reg", 0644,
-                                                debugfs_root, codec,
-                                                &codec_reg_fops);
-       if (!codec->debugfs_reg)
-               printk(KERN_WARNING
-                      "ASoC: Failed to create codec register debugfs file\n");
-
-       codec->debugfs_pop_time = debugfs_create_u32("dapm_pop_time", 0744,
-                                                    debugfs_root,
-                                                    &codec->pop_time);
-       if (!codec->debugfs_pop_time)
-               printk(KERN_WARNING
-                      "Failed to create pop time debugfs file\n");
-
-       codec->debugfs_dapm = debugfs_create_dir("dapm", debugfs_root);
-       if (!codec->debugfs_dapm)
-               printk(KERN_WARNING
-                      "Failed to create DAPM debugfs directory\n");
-
-       snd_soc_dapm_debugfs_init(codec);
-}
-
-static void soc_cleanup_codec_debugfs(struct snd_soc_codec *codec)
-{
-       debugfs_remove_recursive(codec->debugfs_dapm);
-       debugfs_remove(codec->debugfs_pop_time);
-       debugfs_remove(codec->debugfs_reg);
-}
-
-#else
-
-static inline void soc_init_codec_debugfs(struct snd_soc_codec *codec)
-{
-}
-
-static inline void soc_cleanup_codec_debugfs(struct snd_soc_codec *codec)
-{
-}
-#endif
-
 /**
  * snd_soc_new_ac97_codec - initailise AC97 device
  * @codec: audio codec
@@ -1369,19 +1406,41 @@ int snd_soc_update_bits(struct snd_soc_codec *codec, unsigned short reg,
        int change;
        unsigned int old, new;
 
-       mutex_lock(&io_mutex);
        old = snd_soc_read(codec, reg);
        new = (old & ~mask) | value;
        change = old != new;
        if (change)
                snd_soc_write(codec, reg, new);
 
-       mutex_unlock(&io_mutex);
        return change;
 }
 EXPORT_SYMBOL_GPL(snd_soc_update_bits);
 
 /**
+ * snd_soc_update_bits_locked - update codec register bits
+ * @codec: audio codec
+ * @reg: codec register
+ * @mask: register mask
+ * @value: new value
+ *
+ * Writes new register value, and takes the codec mutex.
+ *
+ * Returns 1 for change else 0.
+ */
+static int snd_soc_update_bits_locked(struct snd_soc_codec *codec,
+                               unsigned short reg, unsigned int mask,
+                               unsigned int value)
+{
+       int change;
+
+       mutex_lock(&codec->mutex);
+       change = snd_soc_update_bits(codec, reg, mask, value);
+       mutex_unlock(&codec->mutex);
+
+       return change;
+}
+
+/**
  * snd_soc_test_bits - test register for change
  * @codec: audio codec
  * @reg: codec register
@@ -1399,11 +1458,9 @@ int snd_soc_test_bits(struct snd_soc_codec *codec, unsigned short reg,
        int change;
        unsigned int old, new;
 
-       mutex_lock(&io_mutex);
        old = snd_soc_read(codec, reg);
        new = (old & ~mask) | value;
        change = old != new;
-       mutex_unlock(&io_mutex);
 
        return change;
 }
@@ -1450,89 +1507,16 @@ int snd_soc_new_pcms(struct snd_soc_device *socdev, int idx, const char *xid)
                        mutex_unlock(&codec->mutex);
                        return ret;
                }
-       }
-
-       mutex_unlock(&codec->mutex);
-       return ret;
-}
-EXPORT_SYMBOL_GPL(snd_soc_new_pcms);
-
-/**
- * snd_soc_init_card - register sound card
- * @socdev: the SoC audio device
- *
- * Register a SoC sound card. Also registers an AC97 device if the
- * codec is AC97 for ad hoc devices.
- *
- * Returns 0 for success, else error.
- */
-int snd_soc_init_card(struct snd_soc_device *socdev)
-{
-       struct snd_soc_card *card = socdev->card;
-       struct snd_soc_codec *codec = card->codec;
-       int ret = 0, i, ac97 = 0, err = 0;
-
-       for (i = 0; i < card->num_links; i++) {
-               if (card->dai_link[i].init) {
-                       err = card->dai_link[i].init(codec);
-                       if (err < 0) {
-                               printk(KERN_ERR "asoc: failed to init %s\n",
-                                       card->dai_link[i].stream_name);
-                               continue;
-                       }
-               }
                if (card->dai_link[i].codec_dai->ac97_control) {
-                       ac97 = 1;
                        snd_ac97_dev_add_pdata(codec->ac97,
                                card->dai_link[i].cpu_dai->ac97_pdata);
                }
        }
-       snprintf(codec->card->shortname, sizeof(codec->card->shortname),
-                "%s",  card->name);
-       snprintf(codec->card->longname, sizeof(codec->card->longname),
-                "%s (%s)", card->name, codec->name);
-
-       /* Make sure all DAPM widgets are instantiated */
-       snd_soc_dapm_new_widgets(codec);
-
-       ret = snd_card_register(codec->card);
-       if (ret < 0) {
-               printk(KERN_ERR "asoc: failed to register soundcard for %s\n",
-                               codec->name);
-               goto out;
-       }
-
-       mutex_lock(&codec->mutex);
-#ifdef CONFIG_SND_SOC_AC97_BUS
-       /* Only instantiate AC97 if not already done by the adaptor
-        * for the generic AC97 subsystem.
-        */
-       if (ac97 && strcmp(codec->name, "AC97") != 0) {
-               ret = soc_ac97_dev_register(codec);
-               if (ret < 0) {
-                       printk(KERN_ERR "asoc: AC97 device register failed\n");
-                       snd_card_free(codec->card);
-                       mutex_unlock(&codec->mutex);
-                       goto out;
-               }
-       }
-#endif
-
-       err = snd_soc_dapm_sys_add(socdev->dev);
-       if (err < 0)
-               printk(KERN_WARNING "asoc: failed to add dapm sysfs entries\n");
-
-       err = device_create_file(socdev->dev, &dev_attr_codec_reg);
-       if (err < 0)
-               printk(KERN_WARNING "asoc: failed to add codec sysfs files\n");
 
-       soc_init_codec_debugfs(codec);
        mutex_unlock(&codec->mutex);
-
-out:
        return ret;
 }
-EXPORT_SYMBOL_GPL(snd_soc_init_card);
+EXPORT_SYMBOL_GPL(snd_soc_new_pcms);
 
 /**
  * snd_soc_free_pcms - free sound card and pcms
@@ -1734,7 +1718,7 @@ int snd_soc_put_enum_double(struct snd_kcontrol *kcontrol,
                mask |= (bitmask - 1) << e->shift_r;
        }
 
-       return snd_soc_update_bits(codec, e->reg, mask, val);
+       return snd_soc_update_bits_locked(codec, e->reg, mask, val);
 }
 EXPORT_SYMBOL_GPL(snd_soc_put_enum_double);
 
@@ -1808,7 +1792,7 @@ int snd_soc_put_value_enum_double(struct snd_kcontrol *kcontrol,
                mask |= e->mask << e->shift_r;
        }
 
-       return snd_soc_update_bits(codec, e->reg, mask, val);
+       return snd_soc_update_bits_locked(codec, e->reg, mask, val);
 }
 EXPORT_SYMBOL_GPL(snd_soc_put_value_enum_double);
 
@@ -1969,7 +1953,7 @@ int snd_soc_put_volsw(struct snd_kcontrol *kcontrol,
                val_mask |= mask << rshift;
                val |= val2 << rshift;
        }
-       return snd_soc_update_bits(codec, reg, val_mask, val);
+       return snd_soc_update_bits_locked(codec, reg, val_mask, val);
 }
 EXPORT_SYMBOL_GPL(snd_soc_put_volsw);
 
@@ -2075,11 +2059,11 @@ int snd_soc_put_volsw_2r(struct snd_kcontrol *kcontrol,
        val = val << shift;
        val2 = val2 << shift;
 
-       err = snd_soc_update_bits(codec, reg, val_mask, val);
+       err = snd_soc_update_bits_locked(codec, reg, val_mask, val);
        if (err < 0)
                return err;
 
-       err = snd_soc_update_bits(codec, reg2, val_mask, val2);
+       err = snd_soc_update_bits_locked(codec, reg2, val_mask, val2);
        return err;
 }
 EXPORT_SYMBOL_GPL(snd_soc_put_volsw_2r);
@@ -2158,7 +2142,7 @@ int snd_soc_put_volsw_s8(struct snd_kcontrol *kcontrol,
        val = (ucontrol->value.integer.value[0]+min) & 0xff;
        val |= ((ucontrol->value.integer.value[1]+min) & 0xff) << 8;
 
-       return snd_soc_update_bits(codec, reg, 0xffff, val);
+       return snd_soc_update_bits_locked(codec, reg, 0xffff, val);
 }
 EXPORT_SYMBOL_GPL(snd_soc_put_volsw_s8);
 
@@ -2205,16 +2189,18 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_clkdiv);
  * snd_soc_dai_set_pll - configure DAI PLL.
  * @dai: DAI
  * @pll_id: DAI specific PLL ID
+ * @source: DAI specific source for the PLL
  * @freq_in: PLL input clock frequency in Hz
  * @freq_out: requested PLL output clock frequency in Hz
  *
  * Configures and enables PLL to generate output clock based on input clock.
  */
-int snd_soc_dai_set_pll(struct snd_soc_dai *dai,
-       int pll_id, unsigned int freq_in, unsigned int freq_out)
+int snd_soc_dai_set_pll(struct snd_soc_dai *dai, int pll_id, int source,
+       unsigned int freq_in, unsigned int freq_out)
 {
        if (dai->ops && dai->ops->set_pll)
-               return dai->ops->set_pll(dai, pll_id, freq_in, freq_out);
+               return dai->ops->set_pll(dai, pll_id, source,
+                                        freq_in, freq_out);
        else
                return -EINVAL;
 }
@@ -2259,6 +2245,30 @@ int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai,
 EXPORT_SYMBOL_GPL(snd_soc_dai_set_tdm_slot);
 
 /**
+ * snd_soc_dai_set_channel_map - configure DAI audio channel map
+ * @dai: DAI
+ * @tx_num: how many TX channels
+ * @tx_slot: pointer to an array which imply the TX slot number channel
+ *           0~num-1 uses
+ * @rx_num: how many RX channels
+ * @rx_slot: pointer to an array which imply the RX slot number channel
+ *           0~num-1 uses
+ *
+ * configure the relationship between channel number and TDM slot number.
+ */
+int snd_soc_dai_set_channel_map(struct snd_soc_dai *dai,
+       unsigned int tx_num, unsigned int *tx_slot,
+       unsigned int rx_num, unsigned int *rx_slot)
+{
+       if (dai->ops && dai->ops->set_channel_map)
+               return dai->ops->set_channel_map(dai, tx_num, tx_slot,
+                       rx_num, rx_slot);
+       else
+               return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(snd_soc_dai_set_channel_map);
+
+/**
  * snd_soc_dai_set_tristate - configure DAI system or master clock.
  * @dai: DAI
  * @tristate: tristate enable
index 66d4c16..0d294ef 100644 (file)
@@ -719,6 +719,10 @@ static int dapm_supply_check_power(struct snd_soc_dapm_widget *w)
 
        /* Check if one of our outputs is connected */
        list_for_each_entry(path, &w->sinks, list_source) {
+               if (path->connected &&
+                   !path->connected(path->source, path->sink))
+                       continue;
+
                if (path->sink && path->sink->power_check &&
                    path->sink->power_check(path->sink)) {
                        power = 1;
@@ -1152,6 +1156,9 @@ static ssize_t dapm_widget_power_read_file(struct file *file,
                                w->active ? "active" : "inactive");
 
        list_for_each_entry(p, &w->sources, list_sink) {
+               if (p->connected && !p->connected(w, p->sink))
+                       continue;
+
                if (p->connect)
                        ret += snprintf(buf + ret, PAGE_SIZE - ret,
                                        " in  %s %s\n",
@@ -1159,6 +1166,9 @@ static ssize_t dapm_widget_power_read_file(struct file *file,
                                        p->source->name);
        }
        list_for_each_entry(p, &w->sinks, list_source) {
+               if (p->connected && !p->connected(w, p->sink))
+                       continue;
+
                if (p->connect)
                        ret += snprintf(buf + ret, PAGE_SIZE - ret,
                                        " out %s %s\n",
@@ -1206,8 +1216,8 @@ void snd_soc_dapm_debugfs_init(struct snd_soc_codec *codec)
 
 /* test and update the power status of a mux widget */
 static int dapm_mux_update_power(struct snd_soc_dapm_widget *widget,
-                                struct snd_kcontrol *kcontrol, int mask,
-                                int mux, int val, struct soc_enum *e)
+                                struct snd_kcontrol *kcontrol, int change,
+                                int mux, struct soc_enum *e)
 {
        struct snd_soc_dapm_path *path;
        int found = 0;
@@ -1216,7 +1226,7 @@ static int dapm_mux_update_power(struct snd_soc_dapm_widget *widget,
            widget->id != snd_soc_dapm_value_mux)
                return -ENODEV;
 
-       if (!snd_soc_test_bits(widget->codec, e->reg, mask, val))
+       if (!change)
                return 0;
 
        /* find dapm widget path assoc with kcontrol */
@@ -1401,10 +1411,13 @@ int snd_soc_dapm_sync(struct snd_soc_codec *codec)
 EXPORT_SYMBOL_GPL(snd_soc_dapm_sync);
 
 static int snd_soc_dapm_add_route(struct snd_soc_codec *codec,
-       const char *sink, const char *control, const char *source)
+                                 const struct snd_soc_dapm_route *route)
 {
        struct snd_soc_dapm_path *path;
        struct snd_soc_dapm_widget *wsource = NULL, *wsink = NULL, *w;
+       const char *sink = route->sink;
+       const char *control = route->control;
+       const char *source = route->source;
        int ret = 0;
 
        /* find src and dest widgets */
@@ -1428,6 +1441,7 @@ static int snd_soc_dapm_add_route(struct snd_soc_codec *codec,
 
        path->source = wsource;
        path->sink = wsink;
+       path->connected = route->connected;
        INIT_LIST_HEAD(&path->list);
        INIT_LIST_HEAD(&path->list_source);
        INIT_LIST_HEAD(&path->list_sink);
@@ -1528,8 +1542,7 @@ int snd_soc_dapm_add_routes(struct snd_soc_codec *codec,
        int i, ret;
 
        for (i = 0; i < num; i++) {
-               ret = snd_soc_dapm_add_route(codec, route->sink,
-                                            route->control, route->source);
+               ret = snd_soc_dapm_add_route(codec, route);
                if (ret < 0) {
                        printk(KERN_ERR "Failed to add route %s->%s\n",
                               route->source,
@@ -1766,7 +1779,7 @@ int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol,
 {
        struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol);
        struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
-       unsigned int val, mux;
+       unsigned int val, mux, change;
        unsigned int mask, bitmask;
        int ret = 0;
 
@@ -1786,20 +1799,21 @@ int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol,
 
        mutex_lock(&widget->codec->mutex);
        widget->value = val;
-       dapm_mux_update_power(widget, kcontrol, mask, mux, val, e);
-       if (widget->event) {
-               if (widget->event_flags & SND_SOC_DAPM_PRE_REG) {
-                       ret = widget->event(widget,
-                               kcontrol, SND_SOC_DAPM_PRE_REG);
-                       if (ret < 0)
-                               goto out;
-               }
-               ret = snd_soc_update_bits(widget->codec, e->reg, mask, val);
-               if (widget->event_flags & SND_SOC_DAPM_POST_REG)
-                       ret = widget->event(widget,
-                               kcontrol, SND_SOC_DAPM_POST_REG);
-       } else
-               ret = snd_soc_update_bits(widget->codec, e->reg, mask, val);
+       change = snd_soc_test_bits(widget->codec, e->reg, mask, val);
+       dapm_mux_update_power(widget, kcontrol, change, mux, e);
+
+       if (widget->event_flags & SND_SOC_DAPM_PRE_REG) {
+               ret = widget->event(widget,
+                                   kcontrol, SND_SOC_DAPM_PRE_REG);
+               if (ret < 0)
+                       goto out;
+       }
+
+       ret = snd_soc_update_bits(widget->codec, e->reg, mask, val);
+
+       if (widget->event_flags & SND_SOC_DAPM_POST_REG)
+               ret = widget->event(widget,
+                                   kcontrol, SND_SOC_DAPM_POST_REG);
 
 out:
        mutex_unlock(&widget->codec->mutex);
@@ -1808,6 +1822,54 @@ out:
 EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_double);
 
 /**
+ * snd_soc_dapm_get_enum_virt - Get virtual DAPM mux
+ * @kcontrol: mixer control
+ * @ucontrol: control element information
+ *
+ * Returns 0 for success.
+ */
+int snd_soc_dapm_get_enum_virt(struct snd_kcontrol *kcontrol,
+                              struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol);
+
+       ucontrol->value.enumerated.item[0] = widget->value;
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_dapm_get_enum_virt);
+
+/**
+ * snd_soc_dapm_put_enum_virt - Set virtual DAPM mux
+ * @kcontrol: mixer control
+ * @ucontrol: control element information
+ *
+ * Returns 0 for success.
+ */
+int snd_soc_dapm_put_enum_virt(struct snd_kcontrol *kcontrol,
+                              struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol);
+       struct soc_enum *e =
+               (struct soc_enum *)kcontrol->private_value;
+       int change;
+       int ret = 0;
+
+       if (ucontrol->value.enumerated.item[0] >= e->max)
+               return -EINVAL;
+
+       mutex_lock(&widget->codec->mutex);
+
+       change = widget->value != ucontrol->value.enumerated.item[0];
+       widget->value = ucontrol->value.enumerated.item[0];
+       dapm_mux_update_power(widget, kcontrol, change, widget->value, e);
+
+       mutex_unlock(&widget->codec->mutex);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_virt);
+
+/**
  * snd_soc_dapm_get_value_enum_double - dapm semi enumerated double mixer get
  *                                     callback
  * @kcontrol: mixer control
@@ -1865,7 +1927,7 @@ int snd_soc_dapm_put_value_enum_double(struct snd_kcontrol *kcontrol,
 {
        struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol);
        struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
-       unsigned int val, mux;
+       unsigned int val, mux, change;
        unsigned int mask;
        int ret = 0;
 
@@ -1883,20 +1945,21 @@ int snd_soc_dapm_put_value_enum_double(struct snd_kcontrol *kcontrol,
 
        mutex_lock(&widget->codec->mutex);
        widget->value = val;
-       dapm_mux_update_power(widget, kcontrol, mask, mux, val, e);
-       if (widget->event) {
-               if (widget->event_flags & SND_SOC_DAPM_PRE_REG) {
-                       ret = widget->event(widget,
-                               kcontrol, SND_SOC_DAPM_PRE_REG);
-                       if (ret < 0)
-                               goto out;
-               }
-               ret = snd_soc_update_bits(widget->codec, e->reg, mask, val);
-               if (widget->event_flags & SND_SOC_DAPM_POST_REG)
-                       ret = widget->event(widget,
-                               kcontrol, SND_SOC_DAPM_POST_REG);
-       } else
-               ret = snd_soc_update_bits(widget->codec, e->reg, mask, val);
+       change = snd_soc_test_bits(widget->codec, e->reg, mask, val);
+       dapm_mux_update_power(widget, kcontrol, change, mux, e);
+
+       if (widget->event_flags & SND_SOC_DAPM_PRE_REG) {
+               ret = widget->event(widget,
+                                   kcontrol, SND_SOC_DAPM_PRE_REG);
+               if (ret < 0)
+                       goto out;
+       }
+
+       ret = snd_soc_update_bits(widget->codec, e->reg, mask, val);
+
+       if (widget->event_flags & SND_SOC_DAPM_POST_REG)
+               ret = widget->event(widget,
+                                   kcontrol, SND_SOC_DAPM_POST_REG);
 
 out:
        mutex_unlock(&widget->codec->mutex);
index 1d455ab..3c07a94 100644 (file)
@@ -58,7 +58,7 @@ EXPORT_SYMBOL_GPL(snd_soc_jack_new);
  */
 void snd_soc_jack_report(struct snd_soc_jack *jack, int status, int mask)
 {
-       struct snd_soc_codec *codec = jack->card->codec;
+       struct snd_soc_codec *codec;
        struct snd_soc_jack_pin *pin;
        int enable;
        int oldstatus;
@@ -67,6 +67,7 @@ void snd_soc_jack_report(struct snd_soc_jack *jack, int status, int mask)
                WARN_ON_ONCE(!jack);
                return;
        }
+       codec = jack->card->codec;
 
        mutex_lock(&codec->mutex);
 
@@ -162,6 +163,9 @@ static void snd_soc_jack_gpio_detect(struct snd_soc_jack_gpio *gpio)
        else
                report = 0;
 
+       if (gpio->jack_status_check)
+               report = gpio->jack_status_check();
+
        snd_soc_jack_report(jack, report, gpio->report);
 }
 
diff --git a/sound/soc/soc-utils.c b/sound/soc/soc-utils.c
new file mode 100644 (file)
index 0000000..1d07b93
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * soc-util.c  --  ALSA SoC Audio Layer utility functions
+ *
+ * Copyright 2009 Wolfson Microelectronics PLC.
+ *
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *         Liam Girdwood <lrg@slimlogic.co.uk>
+ *         
+ *
+ *  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 <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+int snd_soc_calc_frame_size(int sample_size, int channels, int tdm_slots)
+{
+       return sample_size * channels * tdm_slots;
+}
+EXPORT_SYMBOL_GPL(snd_soc_calc_frame_size);
+
+int snd_soc_params_to_frame_size(struct snd_pcm_hw_params *params)
+{
+       int sample_size;
+
+       switch (params_format(params)) {
+       case SNDRV_PCM_FORMAT_S16_LE:
+       case SNDRV_PCM_FORMAT_S16_BE:
+               sample_size = 16;
+               break;
+       case SNDRV_PCM_FORMAT_S20_3LE:
+       case SNDRV_PCM_FORMAT_S20_3BE:
+               sample_size = 20;
+               break;
+       case SNDRV_PCM_FORMAT_S24_LE:
+       case SNDRV_PCM_FORMAT_S24_BE:
+               sample_size = 24;
+               break;
+       case SNDRV_PCM_FORMAT_S32_LE:
+       case SNDRV_PCM_FORMAT_S32_BE:
+               sample_size = 32;
+               break;
+       default:
+               return -ENOTSUPP;
+       }
+
+       return snd_soc_calc_frame_size(sample_size, params_channels(params),
+                                      1);
+}
+EXPORT_SYMBOL_GPL(snd_soc_params_to_frame_size);
+
+int snd_soc_calc_bclk(int fs, int sample_size, int channels, int tdm_slots)
+{
+       return fs * snd_soc_calc_frame_size(sample_size, channels, tdm_slots);
+}
+EXPORT_SYMBOL_GPL(snd_soc_calc_bclk);
+
+int snd_soc_params_to_bclk(struct snd_pcm_hw_params *params)
+{
+       int ret;
+
+       ret = snd_soc_params_to_frame_size(params);
+
+       if (ret > 0)
+               return ret * params_rate(params);
+       else
+               return ret;
+}
+EXPORT_SYMBOL_GPL(snd_soc_params_to_bclk);
index 8db0374..b074a59 100644 (file)
@@ -2893,7 +2893,9 @@ static int snd_usb_create_streams(struct snd_usb_audio *chip, int ctrlif)
                if ((altsd->bInterfaceClass == USB_CLASS_AUDIO ||
                     altsd->bInterfaceClass == USB_CLASS_VENDOR_SPEC) &&
                    altsd->bInterfaceSubClass == USB_SUBCLASS_MIDI_STREAMING) {
-                       if (snd_usb_create_midi_interface(chip, iface, NULL) < 0) {
+                       int err = snd_usbmidi_create(chip->card, iface,
+                                                    &chip->midi_list, NULL);
+                       if (err < 0) {
                                snd_printk(KERN_ERR "%d:%u:%d: cannot create sequencer device\n", dev->devnum, ctrlif, j);
                                continue;
                        }
@@ -3038,12 +3040,11 @@ static int create_uaxx_quirk(struct snd_usb_audio *chip,
                        .type = QUIRK_MIDI_FIXED_ENDPOINT,
                        .data = &uaxx_ep
                };
-               if (chip->usb_id == USB_ID(0x0582, 0x002b))
-                       return snd_usb_create_midi_interface(chip, iface,
-                                                            &ua700_quirk);
-               else
-                       return snd_usb_create_midi_interface(chip, iface,
-                                                            &uaxx_quirk);
+               const struct snd_usb_audio_quirk *quirk =
+                       chip->usb_id == USB_ID(0x0582, 0x002b)
+                       ? &ua700_quirk : &uaxx_quirk;
+               return snd_usbmidi_create(chip->card, iface,
+                                         &chip->midi_list, quirk);
        }
 
        if (altsd->bNumEndpoints != 1)
@@ -3370,6 +3371,13 @@ static int audiophile_skip_setting_quirk(struct snd_usb_audio *chip,
        return 0; /* keep this altsetting */
 }
 
+static int create_any_midi_quirk(struct snd_usb_audio *chip,
+                                struct usb_interface *intf,
+                                const struct snd_usb_audio_quirk *quirk)
+{
+       return snd_usbmidi_create(chip->card, intf, &chip->midi_list, quirk);
+}
+
 /*
  * audio-interface quirks
  *
@@ -3387,14 +3395,14 @@ static int snd_usb_create_quirk(struct snd_usb_audio *chip,
        static const quirk_func_t quirk_funcs[] = {
                [QUIRK_IGNORE_INTERFACE] = ignore_interface_quirk,
                [QUIRK_COMPOSITE] = create_composite_quirk,
-               [QUIRK_MIDI_STANDARD_INTERFACE] = snd_usb_create_midi_interface,
-               [QUIRK_MIDI_FIXED_ENDPOINT] = snd_usb_create_midi_interface,
-               [QUIRK_MIDI_YAMAHA] = snd_usb_create_midi_interface,
-               [QUIRK_MIDI_MIDIMAN] = snd_usb_create_midi_interface,
-               [QUIRK_MIDI_NOVATION] = snd_usb_create_midi_interface,
-               [QUIRK_MIDI_FASTLANE] = snd_usb_create_midi_interface,
-               [QUIRK_MIDI_EMAGIC] = snd_usb_create_midi_interface,
-               [QUIRK_MIDI_CME] = snd_usb_create_midi_interface,
+               [QUIRK_MIDI_STANDARD_INTERFACE] = create_any_midi_quirk,
+               [QUIRK_MIDI_FIXED_ENDPOINT] = create_any_midi_quirk,
+               [QUIRK_MIDI_YAMAHA] = create_any_midi_quirk,
+               [QUIRK_MIDI_MIDIMAN] = create_any_midi_quirk,
+               [QUIRK_MIDI_NOVATION] = create_any_midi_quirk,
+               [QUIRK_MIDI_FASTLANE] = create_any_midi_quirk,
+               [QUIRK_MIDI_EMAGIC] = create_any_midi_quirk,
+               [QUIRK_MIDI_CME] = create_any_midi_quirk,
                [QUIRK_AUDIO_STANDARD_INTERFACE] = create_standard_audio_quirk,
                [QUIRK_AUDIO_FIXED_ENDPOINT] = create_fixed_stream_quirk,
                [QUIRK_AUDIO_EDIROL_UA1000] = create_ua1000_quirk,
index e9a3a9d..40ba811 100644 (file)
@@ -132,7 +132,6 @@ struct snd_usb_audio {
        int pcm_devs;
 
        struct list_head midi_list;     /* list of midi interfaces */
-       int next_midi_device;
 
        struct list_head mixer_list;    /* list of mixer interfaces */
 };
@@ -227,8 +226,10 @@ int snd_usb_create_mixer(struct snd_usb_audio *chip, int ctrlif,
                         int ignore_error);
 void snd_usb_mixer_disconnect(struct list_head *p);
 
-int snd_usb_create_midi_interface(struct snd_usb_audio *chip, struct usb_interface *iface,
-                                 const struct snd_usb_audio_quirk *quirk);
+int snd_usbmidi_create(struct snd_card *card,
+                      struct usb_interface *iface,
+                      struct list_head *midi_list,
+                      const struct snd_usb_audio_quirk *quirk);
 void snd_usbmidi_input_stop(struct list_head* p);
 void snd_usbmidi_input_start(struct list_head* p);
 void snd_usbmidi_disconnect(struct list_head *p);
index 0eff19c..6e89b83 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * usbmidi.c - ALSA USB MIDI driver
  *
- * Copyright (c) 2002-2007 Clemens Ladisch
+ * Copyright (c) 2002-2009 Clemens Ladisch
  * All rights reserved.
  *
  * Based on the OSS usb-midi driver by NAGANO Daisuke,
@@ -47,6 +47,7 @@
 #include <linux/usb.h>
 #include <linux/wait.h>
 #include <sound/core.h>
+#include <sound/control.h>
 #include <sound/rawmidi.h>
 #include <sound/asequencer.h>
 #include "usbaudio.h"
@@ -101,7 +102,8 @@ struct usb_protocol_ops {
 };
 
 struct snd_usb_midi {
-       struct snd_usb_audio *chip;
+       struct usb_device *dev;
+       struct snd_card *card;
        struct usb_interface *iface;
        const struct snd_usb_audio_quirk *quirk;
        struct snd_rawmidi *rmidi;
@@ -109,13 +111,19 @@ struct snd_usb_midi {
        struct list_head list;
        struct timer_list error_timer;
        spinlock_t disc_lock;
+       struct mutex mutex;
+       u32 usb_id;
+       int next_midi_device;
 
        struct snd_usb_midi_endpoint {
                struct snd_usb_midi_out_endpoint *out;
                struct snd_usb_midi_in_endpoint *in;
        } endpoints[MIDI_MAX_ENDPOINTS];
        unsigned long input_triggered;
+       unsigned int opened;
        unsigned char disconnected;
+
+       struct snd_kcontrol *roland_load_ctl;
 };
 
 struct snd_usb_midi_out_endpoint {
@@ -255,7 +263,7 @@ static void snd_usbmidi_in_urb_complete(struct urb* urb)
                }
        }
 
-       urb->dev = ep->umidi->chip->dev;
+       urb->dev = ep->umidi->dev;
        snd_usbmidi_submit_urb(urb, GFP_ATOMIC);
 }
 
@@ -296,7 +304,7 @@ static void snd_usbmidi_do_output(struct snd_usb_midi_out_endpoint* ep)
        unsigned long flags;
 
        spin_lock_irqsave(&ep->buffer_lock, flags);
-       if (ep->umidi->chip->shutdown) {
+       if (ep->umidi->disconnected) {
                spin_unlock_irqrestore(&ep->buffer_lock, flags);
                return;
        }
@@ -312,7 +320,7 @@ static void snd_usbmidi_do_output(struct snd_usb_midi_out_endpoint* ep)
 
                        dump_urb("sending", urb->transfer_buffer,
                                 urb->transfer_buffer_length);
-                       urb->dev = ep->umidi->chip->dev;
+                       urb->dev = ep->umidi->dev;
                        if (snd_usbmidi_submit_urb(urb, GFP_ATOMIC) < 0)
                                break;
                        ep->active_urbs |= 1 << urb_index;
@@ -349,7 +357,7 @@ static void snd_usbmidi_error_timer(unsigned long data)
                if (in && in->error_resubmit) {
                        in->error_resubmit = 0;
                        for (j = 0; j < INPUT_URBS; ++j) {
-                               in->urbs[j]->dev = umidi->chip->dev;
+                               in->urbs[j]->dev = umidi->dev;
                                snd_usbmidi_submit_urb(in->urbs[j], GFP_ATOMIC);
                        }
                }
@@ -369,7 +377,7 @@ static int send_bulk_static_data(struct snd_usb_midi_out_endpoint* ep,
                return -ENOMEM;
        dump_urb("sending", buf, len);
        if (ep->urbs[0].urb)
-               err = usb_bulk_msg(ep->umidi->chip->dev, ep->urbs[0].urb->pipe,
+               err = usb_bulk_msg(ep->umidi->dev, ep->urbs[0].urb->pipe,
                                   buf, len, NULL, 250);
        kfree(buf);
        return err;
@@ -724,8 +732,7 @@ static void snd_usbmidi_us122l_output(struct snd_usb_midi_out_endpoint *ep,
 
        if (!ep->ports[0].active)
                return;
-       count = snd_usb_get_speed(ep->umidi->chip->dev) == USB_SPEED_HIGH
-               ? 1 : 2;
+       count = snd_usb_get_speed(ep->umidi->dev) == USB_SPEED_HIGH ? 1 : 2;
        count = snd_rawmidi_transmit(ep->ports[0].substream,
                                     urb->transfer_buffer,
                                     count);
@@ -879,6 +886,50 @@ static struct usb_protocol_ops snd_usbmidi_emagic_ops = {
 };
 
 
+static void update_roland_altsetting(struct snd_usb_midi* umidi)
+{
+       struct usb_interface *intf;
+       struct usb_host_interface *hostif;
+       struct usb_interface_descriptor *intfd;
+       int is_light_load;
+
+       intf = umidi->iface;
+       is_light_load = intf->cur_altsetting != intf->altsetting;
+       if (umidi->roland_load_ctl->private_value == is_light_load)
+               return;
+       hostif = &intf->altsetting[umidi->roland_load_ctl->private_value];
+       intfd = get_iface_desc(hostif);
+       snd_usbmidi_input_stop(&umidi->list);
+       usb_set_interface(umidi->dev, intfd->bInterfaceNumber,
+                         intfd->bAlternateSetting);
+       snd_usbmidi_input_start(&umidi->list);
+}
+
+static void substream_open(struct snd_rawmidi_substream *substream, int open)
+{
+       struct snd_usb_midi* umidi = substream->rmidi->private_data;
+       struct snd_kcontrol *ctl;
+
+       mutex_lock(&umidi->mutex);
+       if (open) {
+               if (umidi->opened++ == 0 && umidi->roland_load_ctl) {
+                       ctl = umidi->roland_load_ctl;
+                       ctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_INACTIVE;
+                       snd_ctl_notify(umidi->card,
+                                      SNDRV_CTL_EVENT_MASK_INFO, &ctl->id);
+                       update_roland_altsetting(umidi);
+               }
+       } else {
+               if (--umidi->opened == 0 && umidi->roland_load_ctl) {
+                       ctl = umidi->roland_load_ctl;
+                       ctl->vd[0].access &= ~SNDRV_CTL_ELEM_ACCESS_INACTIVE;
+                       snd_ctl_notify(umidi->card,
+                                      SNDRV_CTL_EVENT_MASK_INFO, &ctl->id);
+               }
+       }
+       mutex_unlock(&umidi->mutex);
+}
+
 static int snd_usbmidi_output_open(struct snd_rawmidi_substream *substream)
 {
        struct snd_usb_midi* umidi = substream->rmidi->private_data;
@@ -898,11 +949,13 @@ static int snd_usbmidi_output_open(struct snd_rawmidi_substream *substream)
        }
        substream->runtime->private_data = port;
        port->state = STATE_UNKNOWN;
+       substream_open(substream, 1);
        return 0;
 }
 
 static int snd_usbmidi_output_close(struct snd_rawmidi_substream *substream)
 {
+       substream_open(substream, 0);
        return 0;
 }
 
@@ -912,7 +965,7 @@ static void snd_usbmidi_output_trigger(struct snd_rawmidi_substream *substream,
 
        port->active = up;
        if (up) {
-               if (port->ep->umidi->chip->shutdown) {
+               if (port->ep->umidi->disconnected) {
                        /* gobble up remaining bytes to prevent wait in
                         * snd_rawmidi_drain_output */
                        while (!snd_rawmidi_transmit_empty(substream))
@@ -954,11 +1007,13 @@ static void snd_usbmidi_output_drain(struct snd_rawmidi_substream *substream)
 
 static int snd_usbmidi_input_open(struct snd_rawmidi_substream *substream)
 {
+       substream_open(substream, 1);
        return 0;
 }
 
 static int snd_usbmidi_input_close(struct snd_rawmidi_substream *substream)
 {
+       substream_open(substream, 0);
        return 0;
 }
 
@@ -988,7 +1043,7 @@ static struct snd_rawmidi_ops snd_usbmidi_input_ops = {
 static void free_urb_and_buffer(struct snd_usb_midi *umidi, struct urb *urb,
                                unsigned int buffer_length)
 {
-       usb_buffer_free(umidi->chip->dev, buffer_length,
+       usb_buffer_free(umidi->dev, buffer_length,
                        urb->transfer_buffer, urb->transfer_dma);
        usb_free_urb(urb);
 }
@@ -1035,24 +1090,24 @@ static int snd_usbmidi_in_endpoint_create(struct snd_usb_midi* umidi,
                }
        }
        if (ep_info->in_interval)
-               pipe = usb_rcvintpipe(umidi->chip->dev, ep_info->in_ep);
+               pipe = usb_rcvintpipe(umidi->dev, ep_info->in_ep);
        else
-               pipe = usb_rcvbulkpipe(umidi->chip->dev, ep_info->in_ep);
-       length = usb_maxpacket(umidi->chip->dev, pipe, 0);
+               pipe = usb_rcvbulkpipe(umidi->dev, ep_info->in_ep);
+       length = usb_maxpacket(umidi->dev, pipe, 0);
        for (i = 0; i < INPUT_URBS; ++i) {
-               buffer = usb_buffer_alloc(umidi->chip->dev, length, GFP_KERNEL,
+               buffer = usb_buffer_alloc(umidi->dev, length, GFP_KERNEL,
                                          &ep->urbs[i]->transfer_dma);
                if (!buffer) {
                        snd_usbmidi_in_endpoint_delete(ep);
                        return -ENOMEM;
                }
                if (ep_info->in_interval)
-                       usb_fill_int_urb(ep->urbs[i], umidi->chip->dev,
+                       usb_fill_int_urb(ep->urbs[i], umidi->dev,
                                         pipe, buffer, length,
                                         snd_usbmidi_in_urb_complete,
                                         ep, ep_info->in_interval);
                else
-                       usb_fill_bulk_urb(ep->urbs[i], umidi->chip->dev,
+                       usb_fill_bulk_urb(ep->urbs[i], umidi->dev,
                                          pipe, buffer, length,
                                          snd_usbmidi_in_urb_complete, ep);
                ep->urbs[i]->transfer_flags = URB_NO_TRANSFER_DMA_MAP;
@@ -1062,15 +1117,6 @@ static int snd_usbmidi_in_endpoint_create(struct snd_usb_midi* umidi,
        return 0;
 }
 
-static unsigned int snd_usbmidi_count_bits(unsigned int x)
-{
-       unsigned int bits;
-
-       for (bits = 0; x; ++bits)
-               x &= x - 1;
-       return bits;
-}
-
 /*
  * Frees an output endpoint.
  * May be called when ep hasn't been initialized completely.
@@ -1113,15 +1159,15 @@ static int snd_usbmidi_out_endpoint_create(struct snd_usb_midi* umidi,
                ep->urbs[i].ep = ep;
        }
        if (ep_info->out_interval)
-               pipe = usb_sndintpipe(umidi->chip->dev, ep_info->out_ep);
+               pipe = usb_sndintpipe(umidi->dev, ep_info->out_ep);
        else
-               pipe = usb_sndbulkpipe(umidi->chip->dev, ep_info->out_ep);
-       if (umidi->chip->usb_id == USB_ID(0x0a92, 0x1020)) /* ESI M4U */
+               pipe = usb_sndbulkpipe(umidi->dev, ep_info->out_ep);
+       if (umidi->usb_id == USB_ID(0x0a92, 0x1020)) /* ESI M4U */
                ep->max_transfer = 4;
        else
-               ep->max_transfer = usb_maxpacket(umidi->chip->dev, pipe, 1);
+               ep->max_transfer = usb_maxpacket(umidi->dev, pipe, 1);
        for (i = 0; i < OUTPUT_URBS; ++i) {
-               buffer = usb_buffer_alloc(umidi->chip->dev,
+               buffer = usb_buffer_alloc(umidi->dev,
                                          ep->max_transfer, GFP_KERNEL,
                                          &ep->urbs[i].urb->transfer_dma);
                if (!buffer) {
@@ -1129,12 +1175,12 @@ static int snd_usbmidi_out_endpoint_create(struct snd_usb_midi* umidi,
                        return -ENOMEM;
                }
                if (ep_info->out_interval)
-                       usb_fill_int_urb(ep->urbs[i].urb, umidi->chip->dev,
+                       usb_fill_int_urb(ep->urbs[i].urb, umidi->dev,
                                         pipe, buffer, ep->max_transfer,
                                         snd_usbmidi_out_urb_complete,
                                         &ep->urbs[i], ep_info->out_interval);
                else
-                       usb_fill_bulk_urb(ep->urbs[i].urb, umidi->chip->dev,
+                       usb_fill_bulk_urb(ep->urbs[i].urb, umidi->dev,
                                          pipe, buffer, ep->max_transfer,
                                          snd_usbmidi_out_urb_complete,
                                          &ep->urbs[i]);
@@ -1172,6 +1218,7 @@ static void snd_usbmidi_free(struct snd_usb_midi* umidi)
                if (ep->in)
                        snd_usbmidi_in_endpoint_delete(ep->in);
        }
+       mutex_destroy(&umidi->mutex);
        kfree(umidi);
 }
 
@@ -1367,7 +1414,7 @@ static struct port_info *find_port_info(struct snd_usb_midi* umidi, int number)
        int i;
 
        for (i = 0; i < ARRAY_SIZE(snd_usbmidi_port_info); ++i) {
-               if (snd_usbmidi_port_info[i].id == umidi->chip->usb_id &&
+               if (snd_usbmidi_port_info[i].id == umidi->usb_id &&
                    snd_usbmidi_port_info[i].port == number)
                        return &snd_usbmidi_port_info[i];
        }
@@ -1405,7 +1452,7 @@ static void snd_usbmidi_init_substream(struct snd_usb_midi* umidi,
        port_info = find_port_info(umidi, number);
        name_format = port_info ? port_info->name : "%s MIDI %d";
        snprintf(substream->name, sizeof(substream->name),
-                name_format, umidi->chip->card->shortname, number + 1);
+                name_format, umidi->card->shortname, number + 1);
 
        *rsubstream = substream;
 }
@@ -1503,7 +1550,7 @@ static int snd_usbmidi_get_ms_info(struct snd_usb_midi* umidi,
                        endpoints[epidx].out_ep = usb_endpoint_num(ep);
                        if (usb_endpoint_xfer_int(ep))
                                endpoints[epidx].out_interval = ep->bInterval;
-                       else if (snd_usb_get_speed(umidi->chip->dev) == USB_SPEED_LOW)
+                       else if (snd_usb_get_speed(umidi->dev) == USB_SPEED_LOW)
                                /*
                                 * Low speed bulk transfers don't exist, so
                                 * force interrupt transfers for devices like
@@ -1523,7 +1570,7 @@ static int snd_usbmidi_get_ms_info(struct snd_usb_midi* umidi,
                        endpoints[epidx].in_ep = usb_endpoint_num(ep);
                        if (usb_endpoint_xfer_int(ep))
                                endpoints[epidx].in_interval = ep->bInterval;
-                       else if (snd_usb_get_speed(umidi->chip->dev) == USB_SPEED_LOW)
+                       else if (snd_usb_get_speed(umidi->dev) == USB_SPEED_LOW)
                                endpoints[epidx].in_interval = 1;
                        endpoints[epidx].in_cables = (1 << ms_ep->bNumEmbMIDIJack) - 1;
                        snd_printdd(KERN_INFO "EP %02X: %d jack(s)\n",
@@ -1533,6 +1580,52 @@ static int snd_usbmidi_get_ms_info(struct snd_usb_midi* umidi,
        return 0;
 }
 
+static int roland_load_info(struct snd_kcontrol *kcontrol,
+                           struct snd_ctl_elem_info *info)
+{
+       static const char *const names[] = { "High Load", "Light Load" };
+
+       info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+       info->count = 1;
+       info->value.enumerated.items = 2;
+       if (info->value.enumerated.item > 1)
+               info->value.enumerated.item = 1;
+       strcpy(info->value.enumerated.name, names[info->value.enumerated.item]);
+       return 0;
+}
+
+static int roland_load_get(struct snd_kcontrol *kcontrol,
+                          struct snd_ctl_elem_value *value)
+{
+       value->value.enumerated.item[0] = kcontrol->private_value;
+       return 0;
+}
+
+static int roland_load_put(struct snd_kcontrol *kcontrol,
+                          struct snd_ctl_elem_value *value)
+{
+       struct snd_usb_midi* umidi = kcontrol->private_data;
+       int changed;
+
+       if (value->value.enumerated.item[0] > 1)
+               return -EINVAL;
+       mutex_lock(&umidi->mutex);
+       changed = value->value.enumerated.item[0] != kcontrol->private_value;
+       if (changed)
+               kcontrol->private_value = value->value.enumerated.item[0];
+       mutex_unlock(&umidi->mutex);
+       return changed;
+}
+
+static struct snd_kcontrol_new roland_load_ctl = {
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       .name = "MIDI Input Mode",
+       .info = roland_load_info,
+       .get = roland_load_get,
+       .put = roland_load_put,
+       .private_value = 1,
+};
+
 /*
  * On Roland devices, use the second alternate setting to be able to use
  * the interrupt input endpoint.
@@ -1556,8 +1649,12 @@ static void snd_usbmidi_switch_roland_altsetting(struct snd_usb_midi* umidi)
 
        snd_printdd(KERN_INFO "switching to altsetting %d with int ep\n",
                    intfd->bAlternateSetting);
-       usb_set_interface(umidi->chip->dev, intfd->bInterfaceNumber,
+       usb_set_interface(umidi->dev, intfd->bInterfaceNumber,
                          intfd->bAlternateSetting);
+
+       umidi->roland_load_ctl = snd_ctl_new1(&roland_load_ctl, umidi);
+       if (snd_ctl_add(umidi->card, umidi->roland_load_ctl) < 0)
+               umidi->roland_load_ctl = NULL;
 }
 
 /*
@@ -1573,7 +1670,7 @@ static int snd_usbmidi_detect_endpoints(struct snd_usb_midi* umidi,
        struct usb_endpoint_descriptor* epd;
        int i, out_eps = 0, in_eps = 0;
 
-       if (USB_ID_VENDOR(umidi->chip->usb_id) == 0x0582)
+       if (USB_ID_VENDOR(umidi->usb_id) == 0x0582)
                snd_usbmidi_switch_roland_altsetting(umidi);
 
        if (endpoint[0].out_ep || endpoint[0].in_ep)
@@ -1760,12 +1857,12 @@ static int snd_usbmidi_create_rawmidi(struct snd_usb_midi* umidi,
        struct snd_rawmidi *rmidi;
        int err;
 
-       err = snd_rawmidi_new(umidi->chip->card, "USB MIDI",
-                             umidi->chip->next_midi_device++,
+       err = snd_rawmidi_new(umidi->card, "USB MIDI",
+                             umidi->next_midi_device++,
                              out_ports, in_ports, &rmidi);
        if (err < 0)
                return err;
-       strcpy(rmidi->name, umidi->chip->card->shortname);
+       strcpy(rmidi->name, umidi->card->shortname);
        rmidi->info_flags = SNDRV_RAWMIDI_INFO_OUTPUT |
                            SNDRV_RAWMIDI_INFO_INPUT |
                            SNDRV_RAWMIDI_INFO_DUPLEX;
@@ -1804,7 +1901,7 @@ static void snd_usbmidi_input_start_ep(struct snd_usb_midi_in_endpoint* ep)
                return;
        for (i = 0; i < INPUT_URBS; ++i) {
                struct urb* urb = ep->urbs[i];
-               urb->dev = ep->umidi->chip->dev;
+               urb->dev = ep->umidi->dev;
                snd_usbmidi_submit_urb(urb, GFP_KERNEL);
        }
 }
@@ -1825,9 +1922,10 @@ void snd_usbmidi_input_start(struct list_head* p)
 /*
  * Creates and registers everything needed for a MIDI streaming interface.
  */
-int snd_usb_create_midi_interface(struct snd_usb_audio* chip,
-                                 struct usb_interface* iface,
-                                 const struct snd_usb_audio_quirk* quirk)
+int snd_usbmidi_create(struct snd_card *card,
+                      struct usb_interface* iface,
+                      struct list_head *midi_list,
+                      const struct snd_usb_audio_quirk* quirk)
 {
        struct snd_usb_midi* umidi;
        struct snd_usb_midi_endpoint_info endpoints[MIDI_MAX_ENDPOINTS];
@@ -1837,12 +1935,16 @@ int snd_usb_create_midi_interface(struct snd_usb_audio* chip,
        umidi = kzalloc(sizeof(*umidi), GFP_KERNEL);
        if (!umidi)
                return -ENOMEM;
-       umidi->chip = chip;
+       umidi->dev = interface_to_usbdev(iface);
+       umidi->card = card;
        umidi->iface = iface;
        umidi->quirk = quirk;
        umidi->usb_protocol_ops = &snd_usbmidi_standard_ops;
        init_timer(&umidi->error_timer);
        spin_lock_init(&umidi->disc_lock);
+       mutex_init(&umidi->mutex);
+       umidi->usb_id = USB_ID(le16_to_cpu(umidi->dev->descriptor.idVendor),
+                              le16_to_cpu(umidi->dev->descriptor.idProduct));
        umidi->error_timer.function = snd_usbmidi_error_timer;
        umidi->error_timer.data = (unsigned long)umidi;
 
@@ -1851,7 +1953,7 @@ int snd_usb_create_midi_interface(struct snd_usb_audio* chip,
        switch (quirk ? quirk->type : QUIRK_MIDI_STANDARD_INTERFACE) {
        case QUIRK_MIDI_STANDARD_INTERFACE:
                err = snd_usbmidi_get_ms_info(umidi, endpoints);
-               if (chip->usb_id == USB_ID(0x0763, 0x0150)) /* M-Audio Uno */
+               if (umidi->usb_id == USB_ID(0x0763, 0x0150)) /* M-Audio Uno */
                        umidi->usb_protocol_ops =
                                &snd_usbmidi_maudio_broken_running_status_ops;
                break;
@@ -1887,7 +1989,7 @@ int snd_usb_create_midi_interface(struct snd_usb_audio* chip,
                 * interface 0, so we have to make sure that the USB core looks
                 * again at interface 0 by calling usb_set_interface() on it.
                 */
-               usb_set_interface(umidi->chip->dev, 0, 0);
+               usb_set_interface(umidi->dev, 0, 0);
                err = snd_usbmidi_detect_per_port_endpoints(umidi, endpoints);
                break;
        case QUIRK_MIDI_EMAGIC:
@@ -1914,8 +2016,8 @@ int snd_usb_create_midi_interface(struct snd_usb_audio* chip,
        out_ports = 0;
        in_ports = 0;
        for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i) {
-               out_ports += snd_usbmidi_count_bits(endpoints[i].out_cables);
-               in_ports += snd_usbmidi_count_bits(endpoints[i].in_cables);
+               out_ports += hweight16(endpoints[i].out_cables);
+               in_ports += hweight16(endpoints[i].in_cables);
        }
        err = snd_usbmidi_create_rawmidi(umidi, out_ports, in_ports);
        if (err < 0) {
@@ -1933,14 +2035,14 @@ int snd_usb_create_midi_interface(struct snd_usb_audio* chip,
                return err;
        }
 
-       list_add(&umidi->list, &umidi->chip->midi_list);
+       list_add_tail(&umidi->list, midi_list);
 
        for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i)
                snd_usbmidi_input_start_ep(umidi->endpoints[i].in);
        return 0;
 }
 
-EXPORT_SYMBOL(snd_usb_create_midi_interface);
+EXPORT_SYMBOL(snd_usbmidi_create);
 EXPORT_SYMBOL(snd_usbmidi_input_stop);
 EXPORT_SYMBOL(snd_usbmidi_input_start);
 EXPORT_SYMBOL(snd_usbmidi_disconnect);
index 3e5d66c..77c3588 100644 (file)
@@ -277,6 +277,22 @@ static struct usbmix_name_map scratch_live_map[] = {
        { 0 } /* terminator */
 };
 
+/* "Gamesurround Muse Pocket LT" looks same like "Sound Blaster MP3+"
+ *  most importand difference is SU[8], it should be set to "Capture Source"
+ *  to make alsamixer and PA working properly.
+ *  FIXME: or mp3plus_map should use "Capture Source" too,
+ *  so this maps can be merget
+ */
+static struct usbmix_name_map hercules_usb51_map[] = {
+       { 8, "Capture Source" },        /* SU, default "PCM Capture Source" */
+       { 9, "Master Playback" },       /* FU, default "Speaker Playback" */
+       { 10, "Mic Boost", 7 },         /* FU, default "Auto Gain Input" */
+       { 11, "Line Capture" },         /* FU, default "PCM Capture" */
+       { 13, "Mic Bypass Playback" },  /* FU, default "Mic Playback" */
+       { 14, "Line Bypass Playback" }, /* FU, default "Line Playback" */
+       { 0 }                           /* terminator */
+};
+
 /*
  * Control map entries
  */
@@ -316,6 +332,13 @@ static struct usbmix_ctl_map usbmix_ctl_maps[] = {
                .ignore_ctl_error = 1,
        },
        {
+               /* Hercules Gamesurround Muse Pocket LT
+                * (USB 5.1 Channel Audio Adapter)
+                */
+               .id = USB_ID(0x06f8, 0xc000),
+               .map = hercules_usb51_map,
+       },
+       {
                .id = USB_ID(0x08bb, 0x2702),
                .map = linex_map,
                .ignore_ctl_error = 1,
index f6f201e..a892bda 100644 (file)
@@ -1563,6 +1563,29 @@ YAMAHA_DEVICE(0x7010, "UB99"),
                }
        }
 },
+{
+       /* has ID 0x00ea when not in Advanced Driver mode */
+       USB_DEVICE_VENDOR_SPEC(0x0582, 0x00e9),
+       .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
+               /* .vendor_name = "Roland", */
+               /* .product_name = "UA-1G", */
+               .ifnum = QUIRK_ANY_INTERFACE,
+               .type = QUIRK_COMPOSITE,
+               .data = (const struct snd_usb_audio_quirk[]) {
+                       {
+                               .ifnum = 0,
+                               .type = QUIRK_AUDIO_STANDARD_INTERFACE
+                       },
+                       {
+                               .ifnum = 1,
+                               .type = QUIRK_AUDIO_STANDARD_INTERFACE
+                       },
+                       {
+                               .ifnum = -1
+                       }
+               }
+       }
+},
 
 /* Guillemot devices */
 {
index 99f3376..f71cd28 100644 (file)
@@ -59,11 +59,33 @@ static int us122l_create_usbmidi(struct snd_card *card)
                .type = QUIRK_MIDI_US122L,
                .data = &quirk_data
        };
-       struct usb_device *dev = US122L(card)->chip.dev;
+       struct usb_device *dev = US122L(card)->dev;
        struct usb_interface *iface = usb_ifnum_to_if(dev, 1);
 
-       return snd_usb_create_midi_interface(&US122L(card)->chip,
-                                            iface, &quirk);
+       return snd_usbmidi_create(card, iface,
+                                 &US122L(card)->midi_list, &quirk);
+}
+
+static int us144_create_usbmidi(struct snd_card *card)
+{
+       static struct snd_usb_midi_endpoint_info quirk_data = {
+               .out_ep = 4,
+               .in_ep = 3,
+               .out_cables =   0x001,
+               .in_cables =    0x001
+       };
+       static struct snd_usb_audio_quirk quirk = {
+               .vendor_name =  "US144",
+               .product_name = NAME_ALLCAPS,
+               .ifnum =        0,
+               .type = QUIRK_MIDI_US122L,
+               .data = &quirk_data
+       };
+       struct usb_device *dev = US122L(card)->dev;
+       struct usb_interface *iface = usb_ifnum_to_if(dev, 0);
+
+       return snd_usbmidi_create(card, iface,
+                                 &US122L(card)->midi_list, &quirk);
 }
 
 /*
@@ -171,7 +193,12 @@ static int usb_stream_hwdep_open(struct snd_hwdep *hw, struct file *file)
 
        if (!us122l->first)
                us122l->first = file;
-       iface = usb_ifnum_to_if(us122l->chip.dev, 1);
+
+       if (us122l->dev->descriptor.idProduct == USB_ID_US144) {
+               iface = usb_ifnum_to_if(us122l->dev, 0);
+               usb_autopm_get_interface(iface);
+       }
+       iface = usb_ifnum_to_if(us122l->dev, 1);
        usb_autopm_get_interface(iface);
        return 0;
 }
@@ -179,8 +206,14 @@ static int usb_stream_hwdep_open(struct snd_hwdep *hw, struct file *file)
 static int usb_stream_hwdep_release(struct snd_hwdep *hw, struct file *file)
 {
        struct us122l   *us122l = hw->private_data;
-       struct usb_interface *iface = usb_ifnum_to_if(us122l->chip.dev, 1);
+       struct usb_interface *iface;
        snd_printdd(KERN_DEBUG "%p %p\n", hw, file);
+
+       if (us122l->dev->descriptor.idProduct == USB_ID_US144) {
+               iface = usb_ifnum_to_if(us122l->dev, 0);
+               usb_autopm_put_interface(iface);
+       }
+       iface = usb_ifnum_to_if(us122l->dev, 1);
        usb_autopm_put_interface(iface);
        if (us122l->first == file)
                us122l->first = NULL;
@@ -264,7 +297,7 @@ static unsigned int usb_stream_hwdep_poll(struct snd_hwdep *hw,
 static void us122l_stop(struct us122l *us122l)
 {
        struct list_head *p;
-       list_for_each(p, &us122l->chip.midi_list)
+       list_for_each(p, &us122l->midi_list)
                snd_usbmidi_input_stop(p);
 
        usb_stream_stop(&us122l->sk);
@@ -297,7 +330,7 @@ static bool us122l_start(struct us122l *us122l,
        unsigned use_packsize = 0;
        bool success = false;
 
-       if (us122l->chip.dev->speed == USB_SPEED_HIGH) {
+       if (us122l->dev->speed == USB_SPEED_HIGH) {
                /* The us-122l's descriptor defaults to iso max_packsize 78,
                   which isn't needed for samplerates <= 48000.
                   Lets save some memory:
@@ -314,11 +347,11 @@ static bool us122l_start(struct us122l *us122l,
                        break;
                }
        }
-       if (!usb_stream_new(&us122l->sk, us122l->chip.dev, 1, 2,
+       if (!usb_stream_new(&us122l->sk, us122l->dev, 1, 2,
                            rate, use_packsize, period_frames, 6))
                goto out;
 
-       err = us122l_set_sample_rate(us122l->chip.dev, rate);
+       err = us122l_set_sample_rate(us122l->dev, rate);
        if (err < 0) {
                us122l_stop(us122l);
                snd_printk(KERN_ERR "us122l_set_sample_rate error \n");
@@ -330,7 +363,7 @@ static bool us122l_start(struct us122l *us122l,
                snd_printk(KERN_ERR "us122l_start error %i \n", err);
                goto out;
        }
-       list_for_each(p, &us122l->chip.midi_list)
+       list_for_each(p, &us122l->midi_list)
                snd_usbmidi_input_start(p);
        success = true;
 out:
@@ -357,7 +390,7 @@ static int usb_stream_hwdep_ioctl(struct snd_hwdep *hw, struct file *file,
                err = -ENXIO;
                goto free;
        }
-       high_speed = us122l->chip.dev->speed == USB_SPEED_HIGH;
+       high_speed = us122l->dev->speed == USB_SPEED_HIGH;
        if ((cfg->sample_rate != 44100 && cfg->sample_rate != 48000  &&
             (!high_speed ||
              (cfg->sample_rate != 88200 && cfg->sample_rate != 96000))) ||
@@ -417,7 +450,7 @@ static int usb_stream_hwdep_new(struct snd_card *card)
 {
        int err;
        struct snd_hwdep *hw;
-       struct usb_device *dev = US122L(card)->chip.dev;
+       struct usb_device *dev = US122L(card)->dev;
 
        err = snd_hwdep_new(card, SND_USB_STREAM_ID, 0, &hw);
        if (err < 0)
@@ -443,19 +476,29 @@ static bool us122l_create_card(struct snd_card *card)
        int err;
        struct us122l *us122l = US122L(card);
 
-       err = usb_set_interface(us122l->chip.dev, 1, 1);
+       if (us122l->dev->descriptor.idProduct == USB_ID_US144) {
+               err = usb_set_interface(us122l->dev, 0, 1);
+               if (err) {
+                       snd_printk(KERN_ERR "usb_set_interface error \n");
+                       return false;
+               }
+       }
+       err = usb_set_interface(us122l->dev, 1, 1);
        if (err) {
                snd_printk(KERN_ERR "usb_set_interface error \n");
                return false;
        }
 
-       pt_info_set(us122l->chip.dev, 0x11);
-       pt_info_set(us122l->chip.dev, 0x10);
+       pt_info_set(us122l->dev, 0x11);
+       pt_info_set(us122l->dev, 0x10);
 
        if (!us122l_start(us122l, 44100, 256))
                return false;
 
-       err = us122l_create_usbmidi(card);
+       if (us122l->dev->descriptor.idProduct == USB_ID_US144)
+               err = us144_create_usbmidi(card);
+       else
+               err = us122l_create_usbmidi(card);
        if (err < 0) {
                snd_printk(KERN_ERR "us122l_create_usbmidi error %i \n", err);
                us122l_stop(us122l);
@@ -465,7 +508,7 @@ static bool us122l_create_card(struct snd_card *card)
        if (err < 0) {
 /* release the midi resources */
                struct list_head *p;
-               list_for_each(p, &us122l->chip.midi_list)
+               list_for_each(p, &us122l->midi_list)
                        snd_usbmidi_disconnect(p);
 
                us122l_stop(us122l);
@@ -477,7 +520,7 @@ static bool us122l_create_card(struct snd_card *card)
 static void snd_us122l_free(struct snd_card *card)
 {
        struct us122l   *us122l = US122L(card);
-       int             index = us122l->chip.index;
+       int             index = us122l->card_index;
        if (index >= 0  &&  index < SNDRV_CARDS)
                snd_us122l_card_used[index] = 0;
 }
@@ -497,13 +540,12 @@ static int usx2y_create_card(struct usb_device *device, struct snd_card **cardp)
                              sizeof(struct us122l), &card);
        if (err < 0)
                return err;
-       snd_us122l_card_used[US122L(card)->chip.index = dev] = 1;
+       snd_us122l_card_used[US122L(card)->card_index = dev] = 1;
        card->private_free = snd_us122l_free;
-       US122L(card)->chip.dev = device;
-       US122L(card)->chip.card = card;
+       US122L(card)->dev = device;
        mutex_init(&US122L(card)->mutex);
        init_waitqueue_head(&US122L(card)->sk.sleep);
-       INIT_LIST_HEAD(&US122L(card)->chip.midi_list);
+       INIT_LIST_HEAD(&US122L(card)->midi_list);
        strcpy(card->driver, "USB "NAME_ALLCAPS"");
        sprintf(card->shortname, "TASCAM "NAME_ALLCAPS"");
        sprintf(card->longname, "%s (%x:%x if %d at %03d/%03d)",
@@ -511,8 +553,8 @@ static int usx2y_create_card(struct usb_device *device, struct snd_card **cardp)
                le16_to_cpu(device->descriptor.idVendor),
                le16_to_cpu(device->descriptor.idProduct),
                0,
-               US122L(card)->chip.dev->bus->busnum,
-               US122L(card)->chip.dev->devnum
+               US122L(card)->dev->bus->busnum,
+               US122L(card)->dev->devnum
                );
        *cardp = card;
        return 0;
@@ -542,6 +584,7 @@ static int us122l_usb_probe(struct usb_interface *intf,
                return err;
        }
 
+       usb_get_intf(usb_ifnum_to_if(device, 0));
        usb_get_dev(device);
        *cardp = card;
        return 0;
@@ -550,9 +593,16 @@ static int us122l_usb_probe(struct usb_interface *intf,
 static int snd_us122l_probe(struct usb_interface *intf,
                            const struct usb_device_id *id)
 {
+       struct usb_device *device = interface_to_usbdev(intf);
        struct snd_card *card;
        int err;
 
+       if (device->descriptor.idProduct == USB_ID_US144
+               && device->speed == USB_SPEED_HIGH) {
+               snd_printk(KERN_ERR "disable ehci-hcd to run US-144 \n");
+               return -ENODEV;
+       }
+
        snd_printdd(KERN_DEBUG"%p:%i\n",
                    intf, intf->cur_altsetting->desc.bInterfaceNumber);
        if (intf->cur_altsetting->desc.bInterfaceNumber != 1)
@@ -584,15 +634,15 @@ static void snd_us122l_disconnect(struct usb_interface *intf)
        mutex_lock(&us122l->mutex);
        us122l_stop(us122l);
        mutex_unlock(&us122l->mutex);
-       us122l->chip.shutdown = 1;
 
 /* release the midi resources */
-       list_for_each(p, &us122l->chip.midi_list) {
+       list_for_each(p, &us122l->midi_list) {
                snd_usbmidi_disconnect(p);
        }
 
-       usb_put_intf(intf);
-       usb_put_dev(us122l->chip.dev);
+       usb_put_intf(usb_ifnum_to_if(us122l->dev, 0));
+       usb_put_intf(usb_ifnum_to_if(us122l->dev, 1));
+       usb_put_dev(us122l->dev);
 
        while (atomic_read(&us122l->mmap_count))
                msleep(500);
@@ -615,7 +665,7 @@ static int snd_us122l_suspend(struct usb_interface *intf, pm_message_t message)
        if (!us122l)
                return 0;
 
-       list_for_each(p, &us122l->chip.midi_list)
+       list_for_each(p, &us122l->midi_list)
                snd_usbmidi_input_stop(p);
 
        mutex_lock(&us122l->mutex);
@@ -642,16 +692,23 @@ static int snd_us122l_resume(struct usb_interface *intf)
 
        mutex_lock(&us122l->mutex);
        /* needed, doesn't restart without: */
-       err = usb_set_interface(us122l->chip.dev, 1, 1);
+       if (us122l->dev->descriptor.idProduct == USB_ID_US144) {
+               err = usb_set_interface(us122l->dev, 0, 1);
+               if (err) {
+                       snd_printk(KERN_ERR "usb_set_interface error \n");
+                       goto unlock;
+               }
+       }
+       err = usb_set_interface(us122l->dev, 1, 1);
        if (err) {
                snd_printk(KERN_ERR "usb_set_interface error \n");
                goto unlock;
        }
 
-       pt_info_set(us122l->chip.dev, 0x11);
-       pt_info_set(us122l->chip.dev, 0x10);
+       pt_info_set(us122l->dev, 0x11);
+       pt_info_set(us122l->dev, 0x10);
 
-       err = us122l_set_sample_rate(us122l->chip.dev,
+       err = us122l_set_sample_rate(us122l->dev,
                                     us122l->sk.s->cfg.sample_rate);
        if (err < 0) {
                snd_printk(KERN_ERR "us122l_set_sample_rate error \n");
@@ -661,7 +718,7 @@ static int snd_us122l_resume(struct usb_interface *intf)
        if (err)
                goto unlock;
 
-       list_for_each(p, &us122l->chip.midi_list)
+       list_for_each(p, &us122l->midi_list)
                snd_usbmidi_input_start(p);
 unlock:
        mutex_unlock(&us122l->mutex);
@@ -675,11 +732,11 @@ static struct usb_device_id snd_us122l_usb_id_table[] = {
                .idVendor =     0x0644,
                .idProduct =    USB_ID_US122L
        },
-/*     { */            /* US-144 maybe works when @USB1.1. Untested. */
-/*             .match_flags =  USB_DEVICE_ID_MATCH_DEVICE, */
-/*             .idVendor =     0x0644, */
-/*             .idProduct =    USB_ID_US144 */
-/*     }, */
+       {       /* US-144 only works at USB1.1! Disable module ehci-hcd. */
+               .match_flags =  USB_DEVICE_ID_MATCH_DEVICE,
+               .idVendor =     0x0644,
+               .idProduct =    USB_ID_US144
+       },
        { /* terminator */ }
 };
 
index 3d10c4b..4daf198 100644 (file)
@@ -3,7 +3,8 @@
 
 
 struct us122l {
-       struct snd_usb_audio    chip;
+       struct usb_device       *dev;
+       int                     card_index;
        int                     stride;
        struct usb_stream_kernel sk;
 
@@ -12,6 +13,7 @@ struct us122l {
        unsigned                second_periods_polled;
        struct file             *master;
        struct file             *slave;
+       struct list_head        midi_list;
 
        atomic_t                mmap_count;
 };
index 52e04b2..1879b72 100644 (file)
@@ -114,7 +114,7 @@ static int snd_usX2Y_hwdep_dsp_status(struct snd_hwdep *hw,
        struct usX2Ydev *us428 = hw->private_data;
        int id = -1;
 
-       switch (le16_to_cpu(us428->chip.dev->descriptor.idProduct)) {
+       switch (le16_to_cpu(us428->dev->descriptor.idProduct)) {
        case USB_ID_US122:
                id = USX2Y_TYPE_122;
                break;
@@ -164,14 +164,14 @@ static int usX2Y_create_usbmidi(struct snd_card *card)
                        .type = QUIRK_MIDI_FIXED_ENDPOINT,
                .data = &quirk_data_2
        };
-       struct usb_device *dev = usX2Y(card)->chip.dev;
+       struct usb_device *dev = usX2Y(card)->dev;
        struct usb_interface *iface = usb_ifnum_to_if(dev, 0);
        struct snd_usb_audio_quirk *quirk =
                le16_to_cpu(dev->descriptor.idProduct) == USB_ID_US428 ?
                &quirk_2 : &quirk_1;
 
        snd_printdd("usX2Y_create_usbmidi \n");
-       return snd_usb_create_midi_interface(&usX2Y(card)->chip, iface, quirk);
+       return snd_usbmidi_create(card, iface, &usX2Y(card)->midi_list, quirk);
 }
 
 static int usX2Y_create_alsa_devices(struct snd_card *card)
@@ -202,7 +202,7 @@ static int snd_usX2Y_hwdep_dsp_load(struct snd_hwdep *hw,
        snd_printdd( "dsp_load %s\n", dsp->name);
 
        if (access_ok(VERIFY_READ, dsp->image, dsp->length)) {
-               struct usb_device* dev = priv->chip.dev;
+               struct usb_device* dev = priv->dev;
                char *buf;
 
                buf = memdup_user(dsp->image, dsp->length);
index cb4bb83..c42350e 100644 (file)
@@ -239,8 +239,8 @@ static void i_usX2Y_In04Int(struct urb *urb)
                                for (j = 0; j < URBS_AsyncSeq  &&  !err; ++j)
                                        if (0 == usX2Y->AS04.urb[j]->status) {
                                                struct us428_p4out *p4out = us428ctls->p4out + send;    // FIXME if more than 1 p4out is new, 1 gets lost.
-                                               usb_fill_bulk_urb(usX2Y->AS04.urb[j], usX2Y->chip.dev,
-                                                                 usb_sndbulkpipe(usX2Y->chip.dev, 0x04), &p4out->val.vol, 
+                                               usb_fill_bulk_urb(usX2Y->AS04.urb[j], usX2Y->dev,
+                                                                 usb_sndbulkpipe(usX2Y->dev, 0x04), &p4out->val.vol,
                                                                  p4out->type == eLT_Light ? sizeof(struct us428_lights) : 5,
                                                                  i_usX2Y_Out04Int, usX2Y);
                                                err = usb_submit_urb(usX2Y->AS04.urb[j], GFP_ATOMIC);
@@ -253,7 +253,7 @@ static void i_usX2Y_In04Int(struct urb *urb)
        if (err)
                snd_printk(KERN_ERR "In04Int() usb_submit_urb err=%i\n", err);
 
-       urb->dev = usX2Y->chip.dev;
+       urb->dev = usX2Y->dev;
        usb_submit_urb(urb, GFP_ATOMIC);
 }
 
@@ -273,8 +273,8 @@ int usX2Y_AsyncSeq04_init(struct usX2Ydev *usX2Y)
                                err = -ENOMEM;
                                break;
                        }
-                       usb_fill_bulk_urb(      usX2Y->AS04.urb[i], usX2Y->chip.dev,
-                                               usb_sndbulkpipe(usX2Y->chip.dev, 0x04),
+                       usb_fill_bulk_urb(      usX2Y->AS04.urb[i], usX2Y->dev,
+                                               usb_sndbulkpipe(usX2Y->dev, 0x04),
                                                usX2Y->AS04.buffer + URB_DataLen_AsyncSeq*i, 0,
                                                i_usX2Y_Out04Int, usX2Y
                                );
@@ -293,7 +293,7 @@ int usX2Y_In04_init(struct usX2Ydev *usX2Y)
        }
         
        init_waitqueue_head(&usX2Y->In04WaitQueue);
-       usb_fill_int_urb(usX2Y->In04urb, usX2Y->chip.dev, usb_rcvintpipe(usX2Y->chip.dev, 0x4),
+       usb_fill_int_urb(usX2Y->In04urb, usX2Y->dev, usb_rcvintpipe(usX2Y->dev, 0x4),
                         usX2Y->In04Buf, 21,
                         i_usX2Y_In04Int, usX2Y,
                         10);
@@ -348,13 +348,12 @@ static int usX2Y_create_card(struct usb_device *device, struct snd_card **cardp)
                              sizeof(struct usX2Ydev), &card);
        if (err < 0)
                return err;
-       snd_usX2Y_card_used[usX2Y(card)->chip.index = dev] = 1;
+       snd_usX2Y_card_used[usX2Y(card)->card_index = dev] = 1;
        card->private_free = snd_usX2Y_card_private_free;
-       usX2Y(card)->chip.dev = device;
-       usX2Y(card)->chip.card = card;
+       usX2Y(card)->dev = device;
        init_waitqueue_head(&usX2Y(card)->prepare_wait_queue);
        mutex_init(&usX2Y(card)->prepare_mutex);
-       INIT_LIST_HEAD(&usX2Y(card)->chip.midi_list);
+       INIT_LIST_HEAD(&usX2Y(card)->midi_list);
        strcpy(card->driver, "USB "NAME_ALLCAPS"");
        sprintf(card->shortname, "TASCAM "NAME_ALLCAPS"");
        sprintf(card->longname, "%s (%x:%x if %d at %03d/%03d)",
@@ -362,7 +361,7 @@ static int usX2Y_create_card(struct usb_device *device, struct snd_card **cardp)
                le16_to_cpu(device->descriptor.idVendor),
                le16_to_cpu(device->descriptor.idProduct),
                0,//us428(card)->usbmidi.ifnum,
-               usX2Y(card)->chip.dev->bus->busnum, usX2Y(card)->chip.dev->devnum
+               usX2Y(card)->dev->bus->busnum, usX2Y(card)->dev->devnum
                );
        *cardp = card;
        return 0;
@@ -432,8 +431,8 @@ static void snd_usX2Y_card_private_free(struct snd_card *card)
        usb_free_urb(usX2Y(card)->In04urb);
        if (usX2Y(card)->us428ctls_sharedmem)
                snd_free_pages(usX2Y(card)->us428ctls_sharedmem, sizeof(*usX2Y(card)->us428ctls_sharedmem));
-       if (usX2Y(card)->chip.index >= 0  &&  usX2Y(card)->chip.index < SNDRV_CARDS)
-               snd_usX2Y_card_used[usX2Y(card)->chip.index] = 0;
+       if (usX2Y(card)->card_index >= 0  &&  usX2Y(card)->card_index < SNDRV_CARDS)
+               snd_usX2Y_card_used[usX2Y(card)->card_index] = 0;
 }
 
 /*
@@ -445,13 +444,12 @@ static void usX2Y_usb_disconnect(struct usb_device *device, void* ptr)
                struct snd_card *card = ptr;
                struct usX2Ydev *usX2Y = usX2Y(card);
                struct list_head *p;
-               usX2Y->chip.shutdown = 1;
                usX2Y->chip_status = USX2Y_STAT_CHIP_HUP;
                usX2Y_unlinkSeq(&usX2Y->AS04);
                usb_kill_urb(usX2Y->In04urb);
                snd_card_disconnect(card);
                /* release the midi resources */
-               list_for_each(p, &usX2Y->chip.midi_list) {
+               list_for_each(p, &usX2Y->midi_list) {
                        snd_usbmidi_disconnect(p);
                }
                if (usX2Y->us428ctls_sharedmem) 
index 456b5fd..1d174ce 100644 (file)
@@ -22,7 +22,8 @@ struct snd_usX2Y_urbSeq {
 #include "usx2yhwdeppcm.h"
 
 struct usX2Ydev {
-       struct snd_usb_audio    chip;
+       struct usb_device       *dev;
+       int                     card_index;
        int                     stride;
        struct urb              *In04urb;
        void                    *In04Buf;
@@ -42,6 +43,9 @@ struct usX2Ydev {
        struct snd_usX2Y_substream      *subs[4];
        struct snd_usX2Y_substream      * volatile  prepare_subs;
        wait_queue_head_t       prepare_wait_queue;
+       struct list_head        midi_list;
+       struct list_head        pcm_list;
+       int                     pcm_devs;
 };
 
 
index 9efd27f..74a67a8 100644 (file)
@@ -199,7 +199,7 @@ static int usX2Y_urb_submit(struct snd_usX2Y_substream *subs, struct urb *urb, i
                return -ENODEV;
        urb->start_frame = (frame + NRURBS * nr_of_packs());  // let hcd do rollover sanity checks
        urb->hcpriv = NULL;
-       urb->dev = subs->usX2Y->chip.dev; /* we need to set this at each time */
+       urb->dev = subs->usX2Y->dev; /* we need to set this at each time */
        if ((err = usb_submit_urb(urb, GFP_ATOMIC)) < 0) {
                snd_printk(KERN_ERR "usb_submit_urb() returned %i\n", err);
                return err;
@@ -300,7 +300,7 @@ static void usX2Y_error_sequence(struct usX2Ydev *usX2Y,
 "Sequence Error!(hcd_frame=%i ep=%i%s;wait=%i,frame=%i).\n"
 "Most propably some urb of usb-frame %i is still missing.\n"
 "Cause could be too long delays in usb-hcd interrupt handling.\n",
-                  usb_get_current_frame_number(usX2Y->chip.dev),
+                  usb_get_current_frame_number(usX2Y->dev),
                   subs->endpoint, usb_pipein(urb->pipe) ? "in" : "out",
                   usX2Y->wait_iso_frame, urb->start_frame, usX2Y->wait_iso_frame);
        usX2Y_clients_stop(usX2Y);
@@ -313,7 +313,7 @@ static void i_usX2Y_urb_complete(struct urb *urb)
 
        if (unlikely(atomic_read(&subs->state) < state_PREPARED)) {
                snd_printdd("hcd_frame=%i ep=%i%s status=%i start_frame=%i\n",
-                           usb_get_current_frame_number(usX2Y->chip.dev),
+                           usb_get_current_frame_number(usX2Y->dev),
                            subs->endpoint, usb_pipein(urb->pipe) ? "in" : "out",
                            urb->status, urb->start_frame);
                return;
@@ -424,7 +424,7 @@ static int usX2Y_urbs_allocate(struct snd_usX2Y_substream *subs)
        int i;
        unsigned int pipe;
        int is_playback = subs == subs->usX2Y->subs[SNDRV_PCM_STREAM_PLAYBACK];
-       struct usb_device *dev = subs->usX2Y->chip.dev;
+       struct usb_device *dev = subs->usX2Y->dev;
 
        pipe = is_playback ? usb_sndisocpipe(dev, subs->endpoint) :
                        usb_rcvisocpipe(dev, subs->endpoint);
@@ -500,7 +500,7 @@ static int usX2Y_urbs_start(struct snd_usX2Y_substream *subs)
                        unsigned long pack;
                        if (0 == i)
                                atomic_set(&subs->state, state_STARTING3);
-                       urb->dev = usX2Y->chip.dev;
+                       urb->dev = usX2Y->dev;
                        urb->transfer_flags = URB_ISO_ASAP;
                        for (pack = 0; pack < nr_of_packs(); pack++) {
                                urb->iso_frame_desc[pack].offset = subs->maxpacksize * pack;
@@ -692,7 +692,7 @@ static int usX2Y_rate_set(struct usX2Ydev *usX2Y, int rate)
                        }
                        ((char*)(usbdata + i))[0] = ra[i].c1;
                        ((char*)(usbdata + i))[1] = ra[i].c2;
-                       usb_fill_bulk_urb(us->urb[i], usX2Y->chip.dev, usb_sndbulkpipe(usX2Y->chip.dev, 4),
+                       usb_fill_bulk_urb(us->urb[i], usX2Y->dev, usb_sndbulkpipe(usX2Y->dev, 4),
                                          usbdata + i, 2, i_usX2Y_04Int, usX2Y);
 #ifdef OLD_USB
                        us->urb[i]->transfer_flags = USB_QUEUE_BULK;
@@ -740,17 +740,17 @@ static int usX2Y_format_set(struct usX2Ydev *usX2Y, snd_pcm_format_t format)
                alternate = 1;
                usX2Y->stride = 4;
        }
-       list_for_each(p, &usX2Y->chip.midi_list) {
+       list_for_each(p, &usX2Y->midi_list) {
                snd_usbmidi_input_stop(p);
        }
        usb_kill_urb(usX2Y->In04urb);
-       if ((err = usb_set_interface(usX2Y->chip.dev, 0, alternate))) {
+       if ((err = usb_set_interface(usX2Y->dev, 0, alternate))) {
                snd_printk(KERN_ERR "usb_set_interface error \n");
                return err;
        }
-       usX2Y->In04urb->dev = usX2Y->chip.dev;
+       usX2Y->In04urb->dev = usX2Y->dev;
        err = usb_submit_urb(usX2Y->In04urb, GFP_KERNEL);
-       list_for_each(p, &usX2Y->chip.midi_list) {
+       list_for_each(p, &usX2Y->midi_list) {
                snd_usbmidi_input_start(p);
        }
        usX2Y->format = format;
@@ -955,7 +955,7 @@ static int usX2Y_audio_stream_new(struct snd_card *card, int playback_endpoint,
        struct snd_pcm *pcm;
        int err, i;
        struct snd_usX2Y_substream **usX2Y_substream =
-               usX2Y(card)->subs + 2 * usX2Y(card)->chip.pcm_devs;
+               usX2Y(card)->subs + 2 * usX2Y(card)->pcm_devs;
 
        for (i = playback_endpoint ? SNDRV_PCM_STREAM_PLAYBACK : SNDRV_PCM_STREAM_CAPTURE;
             i <= SNDRV_PCM_STREAM_CAPTURE; ++i) {
@@ -971,7 +971,7 @@ static int usX2Y_audio_stream_new(struct snd_card *card, int playback_endpoint,
                usX2Y_substream[SNDRV_PCM_STREAM_PLAYBACK]->endpoint = playback_endpoint;
        usX2Y_substream[SNDRV_PCM_STREAM_CAPTURE]->endpoint = capture_endpoint;
 
-       err = snd_pcm_new(card, NAME_ALLCAPS" Audio", usX2Y(card)->chip.pcm_devs,
+       err = snd_pcm_new(card, NAME_ALLCAPS" Audio", usX2Y(card)->pcm_devs,
                          playback_endpoint ? 1 : 0, 1,
                          &pcm);
        if (err < 0) {
@@ -987,7 +987,7 @@ static int usX2Y_audio_stream_new(struct snd_card *card, int playback_endpoint,
        pcm->private_free = snd_usX2Y_pcm_private_free;
        pcm->info_flags = 0;
 
-       sprintf(pcm->name, NAME_ALLCAPS" Audio #%d", usX2Y(card)->chip.pcm_devs);
+       sprintf(pcm->name, NAME_ALLCAPS" Audio #%d", usX2Y(card)->pcm_devs);
 
        if ((playback_endpoint &&
             0 > (err = snd_pcm_lib_preallocate_pages(pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream,
@@ -1001,7 +1001,7 @@ static int usX2Y_audio_stream_new(struct snd_card *card, int playback_endpoint,
                snd_usX2Y_pcm_private_free(pcm);
                return err;
        }
-       usX2Y(card)->chip.pcm_devs++;
+       usX2Y(card)->pcm_devs++;
 
        return 0;
 }
@@ -1013,14 +1013,14 @@ int usX2Y_audio_create(struct snd_card *card)
 {
        int err = 0;
        
-       INIT_LIST_HEAD(&usX2Y(card)->chip.pcm_list);
+       INIT_LIST_HEAD(&usX2Y(card)->pcm_list);
 
        if (0 > (err = usX2Y_audio_stream_new(card, 0xA, 0x8)))
                return err;
-       if (le16_to_cpu(usX2Y(card)->chip.dev->descriptor.idProduct) == USB_ID_US428)
+       if (le16_to_cpu(usX2Y(card)->dev->descriptor.idProduct) == USB_ID_US428)
             if (0 > (err = usX2Y_audio_stream_new(card, 0, 0xA)))
                     return err;
-       if (le16_to_cpu(usX2Y(card)->chip.dev->descriptor.idProduct) != USB_ID_US122)
+       if (le16_to_cpu(usX2Y(card)->dev->descriptor.idProduct) != USB_ID_US122)
                err = usX2Y_rate_set(usX2Y(card), 44100);       // Lets us428 recognize output-volume settings, disturbs us122.
        return err;
 }
index 4b2304c..9ed6c39 100644 (file)
@@ -234,7 +234,7 @@ static void i_usX2Y_usbpcm_urb_complete(struct urb *urb)
 
        if (unlikely(atomic_read(&subs->state) < state_PREPARED)) {
                snd_printdd("hcd_frame=%i ep=%i%s status=%i start_frame=%i\n",
-                           usb_get_current_frame_number(usX2Y->chip.dev),
+                           usb_get_current_frame_number(usX2Y->dev),
                            subs->endpoint, usb_pipein(urb->pipe) ? "in" : "out",
                            urb->status, urb->start_frame);
                return;
@@ -318,7 +318,7 @@ static int usX2Y_usbpcm_urbs_allocate(struct snd_usX2Y_substream *subs)
        int i;
        unsigned int pipe;
        int is_playback = subs == subs->usX2Y->subs[SNDRV_PCM_STREAM_PLAYBACK];
-       struct usb_device *dev = subs->usX2Y->chip.dev;
+       struct usb_device *dev = subs->usX2Y->dev;
 
        pipe = is_playback ? usb_sndisocpipe(dev, subs->endpoint) :
                        usb_rcvisocpipe(dev, subs->endpoint);
@@ -441,7 +441,7 @@ static int usX2Y_usbpcm_urbs_start(struct snd_usX2Y_substream *subs)
                                        unsigned long pack;
                                        if (0 == u)
                                                atomic_set(&subs->state, state_STARTING3);
-                                       urb->dev = usX2Y->chip.dev;
+                                       urb->dev = usX2Y->dev;
                                        urb->transfer_flags = URB_ISO_ASAP;
                                        for (pack = 0; pack < nr_of_packs(); pack++) {
                                                urb->iso_frame_desc[pack].offset = subs->maxpacksize * (pack + u * nr_of_packs());
@@ -741,7 +741,7 @@ int usX2Y_hwdep_pcm_new(struct snd_card *card)
        int err;
        struct snd_hwdep *hw;
        struct snd_pcm *pcm;
-       struct usb_device *dev = usX2Y(card)->chip.dev;
+       struct usb_device *dev = usX2Y(card)->dev;
        if (1 != nr_of_packs())
                return 0;
 
index 0854f11..fe08660 100644 (file)
@@ -12,6 +12,7 @@ perf*.1
 perf*.xml
 perf*.html
 common-cmds.h
+perf.data
 tags
 TAGS
 cscope*
diff --git a/tools/perf/Documentation/perf-bench.txt b/tools/perf/Documentation/perf-bench.txt
new file mode 100644 (file)
index 0000000..ae525ac
--- /dev/null
@@ -0,0 +1,120 @@
+perf-bench(1)
+============
+
+NAME
+----
+perf-bench - General framework for benchmark suites
+
+SYNOPSIS
+--------
+[verse]
+'perf bench' [<common options>] <subsystem> <suite> [<options>]
+
+DESCRIPTION
+-----------
+This 'perf bench' command is general framework for benchmark suites.
+
+COMMON OPTIONS
+--------------
+-f::
+--format=::
+Specify format style.
+Current available format styles are,
+
+'default'::
+Default style. This is mainly for human reading.
+---------------------
+% perf bench sched pipe                      # with no style specify
+(executing 1000000 pipe operations between two tasks)
+        Total time:5.855 sec
+                5.855061 usecs/op
+               170792 ops/sec
+---------------------
+
+'simple'::
+This simple style is friendly for automated
+processing by scripts.
+---------------------
+% perf bench --format=simple sched pipe      # specified simple
+5.988
+---------------------
+
+SUBSYSTEM
+---------
+
+'sched'::
+       Scheduler and IPC mechanisms.
+
+SUITES FOR 'sched'
+~~~~~~~~~~~~~~~~~~
+*messaging*::
+Suite for evaluating performance of scheduler and IPC mechanisms.
+Based on hackbench by Rusty Russell.
+
+Options of *pipe*
+^^^^^^^^^^^^^^^^^
+-p::
+--pipe::
+Use pipe() instead of socketpair()
+
+-t::
+--thread::
+Be multi thread instead of multi process
+
+-g::
+--group=::
+Specify number of groups
+
+-l::
+--loop=::
+Specify number of loops
+
+Example of *messaging*
+^^^^^^^^^^^^^^^^^^^^^^
+
+---------------------
+% perf bench sched messaging                 # run with default
+options (20 sender and receiver processes per group)
+(10 groups == 400 processes run)
+
+      Total time:0.308 sec
+
+% perf bench sched messaging -t -g 20        # be multi-thread,with 20 groups
+(20 sender and receiver threads per group)
+(20 groups == 800 threads run)
+
+      Total time:0.582 sec
+---------------------
+
+*pipe*::
+Suite for pipe() system call.
+Based on pipe-test-1m.c by Ingo Molnar.
+
+Options of *pipe*
+^^^^^^^^^^^^^^^^^
+-l::
+--loop=::
+Specify number of loops.
+
+Example of *pipe*
+^^^^^^^^^^^^^^^^^
+
+---------------------
+% perf bench sched pipe
+(executing 1000000 pipe operations between two tasks)
+
+        Total time:8.091 sec
+                8.091833 usecs/op
+                123581 ops/sec
+
+% perf bench sched pipe -l 1000              # loop 1000
+(executing 1000 pipe operations between two tasks)
+
+        Total time:0.016 sec
+                16.948000 usecs/op
+                59004 ops/sec
+---------------------
+
+SEE ALSO
+--------
+linkperf:perf[1]
diff --git a/tools/perf/Documentation/perf-buildid-list.txt b/tools/perf/Documentation/perf-buildid-list.txt
new file mode 100644 (file)
index 0000000..01b642c
--- /dev/null
@@ -0,0 +1,34 @@
+perf-buildid-list(1)
+====================
+
+NAME
+----
+perf-buildid-list - List the buildids in a perf.data file
+
+SYNOPSIS
+--------
+[verse]
+'perf buildid-list <options>'
+
+DESCRIPTION
+-----------
+This command displays the buildids found in a perf.data file, so that other
+tools can be used to fetch packages with matching symbol tables for use by
+perf report.
+
+OPTIONS
+-------
+-i::
+--input=::
+        Input file name. (default: perf.data)
+-f::
+--force::
+       Don't do ownership validation.
+-v::
+--verbose::
+       Be more verbose.
+
+SEE ALSO
+--------
+linkperf:perf-record[1], linkperf:perf-top[1],
+linkperf:perf-report[1]
diff --git a/tools/perf/Documentation/perf-kmem.txt b/tools/perf/Documentation/perf-kmem.txt
new file mode 100644 (file)
index 0000000..44b0ce3
--- /dev/null
@@ -0,0 +1,44 @@
+perf-kmem(1)
+==============
+
+NAME
+----
+perf-kmem - Tool to trace/measure kernel memory(slab) properties
+
+SYNOPSIS
+--------
+[verse]
+'perf kmem' {record} [<options>]
+
+DESCRIPTION
+-----------
+There's two variants of perf kmem:
+
+  'perf kmem record <command>' to record the kmem events
+  of an arbitrary workload.
+
+  'perf kmem' to report kernel memory statistics.
+
+OPTIONS
+-------
+-i <file>::
+--input=<file>::
+       Select the input file (default: perf.data)
+
+--stat=<caller|alloc>::
+       Select per callsite or per allocation statistics
+
+-s <key[,key2...]>::
+--sort=<key[,key2...]>::
+       Sort the output (default: frag,hit,bytes)
+
+-l <num>::
+--line=<num>::
+       Print n lines only
+
+--raw-ip::
+       Print raw ip instead of symbol
+
+SEE ALSO
+--------
+linkperf:perf-record[1]
diff --git a/tools/perf/Documentation/perf-probe.txt b/tools/perf/Documentation/perf-probe.txt
new file mode 100644 (file)
index 0000000..9270594
--- /dev/null
@@ -0,0 +1,49 @@
+perf-probe(1)
+=============
+
+NAME
+----
+perf-probe - Define new dynamic tracepoints
+
+SYNOPSIS
+--------
+[verse]
+'perf probe' [options] --add 'PROBE' [--add 'PROBE' ...]
+or
+'perf probe' [options] 'PROBE' ['PROBE' ...]
+
+
+DESCRIPTION
+-----------
+This command defines dynamic tracepoint events, by symbol and registers
+without debuginfo, or by C expressions (C line numbers, C function names,
+and C local variables) with debuginfo.
+
+
+OPTIONS
+-------
+-k::
+--vmlinux=PATH::
+       Specify vmlinux path which has debuginfo (Dwarf binary).
+
+-v::
+--verbose::
+        Be more verbose (show parsed arguments, etc).
+
+-a::
+--add::
+       Define a probe point (see PROBE SYNTAX for detail)
+
+PROBE SYNTAX
+------------
+Probe points are defined by following syntax.
+
+ "FUNC[+OFFS|:RLN|%return][@SRC]|SRC:ALN [ARG ...]"
+
+'FUNC' specifies a probed function name, and it may have one of the following options; '+OFFS' is the offset from function entry address in bytes, 'RLN' is the relative-line number from function entry line, and '%return' means that it probes function return. In addition, 'SRC' specifies a source file which has that function.
+It is also possible to specify a probe point by the source line number by using 'SRC:ALN' syntax, where 'SRC' is the source file path and 'ALN' is the line number.
+'ARG' specifies the arguments of this probe point. You can use the name of local variable, or kprobe-tracer argument format (e.g. $retval, %ax, etc).
+
+SEE ALSO
+--------
+linkperf:perf-trace[1], linkperf:perf-record[1]
index 0ff23de..fc46c0b 100644 (file)
@@ -26,11 +26,19 @@ OPTIONS
 
 -e::
 --event=::
-       Select the PMU event. Selection can be a symbolic event name
-       (use 'perf list' to list all events) or a raw PMU
-       event (eventsel+umask) in the form of rNNN where NNN is a
-       hexadecimal event descriptor.
+       Select the PMU event. Selection can be:
 
+        - a symbolic event name        (use 'perf list' to list all events)
+
+        - a raw PMU event (eventsel+umask) in the form of rNNN where NNN is a
+         hexadecimal event descriptor.
+
+        - a hardware breakpoint event in the form of '\mem:addr[:access]'
+          where addr is the address in memory you want to break in.
+          Access is the memory access type (read, write, execute) it can
+          be passed as follows: '\mem:addr[:[r][w][x]]'.
+          If you want to profile read-write accesses in 0x1000, just set
+          'mem:0x1000:rw'.
 -a::
         System-wide collection.
 
index 59f0b84..9dccb18 100644 (file)
@@ -24,11 +24,11 @@ OPTIONS
 --dsos=::
        Only consider symbols in these dsos. CSV that understands
        file://filename entries.
--n
---show-nr-samples
+-n::
+--show-nr-samples::
        Show the number of samples for each symbol
--T
---threads
+-T::
+--threads::
        Show per-thread event counters
 -C::
 --comms=::
index a791009..4b17883 100644 (file)
@@ -31,9 +31,12 @@ OPTIONS
 -w::
 --width=::
         Select the width of the SVG file (default: 1000)
--p::
+-P::
 --power-only::
         Only output the CPU power section of the diagram
+-p::
+--process::
+        Select the processes to display, by name or PID
 
 
 SEE ALSO
diff --git a/tools/perf/Documentation/perf-trace-perl.txt b/tools/perf/Documentation/perf-trace-perl.txt
new file mode 100644 (file)
index 0000000..c5f55f4
--- /dev/null
@@ -0,0 +1,219 @@
+perf-trace-perl(1)
+==================
+
+NAME
+----
+perf-trace-perl - Process trace data with a Perl script
+
+SYNOPSIS
+--------
+[verse]
+'perf trace' [-s [lang]:script[.ext] ]
+
+DESCRIPTION
+-----------
+
+This perf trace option is used to process perf trace data using perf's
+built-in Perl interpreter.  It reads and processes the input file and
+displays the results of the trace analysis implemented in the given
+Perl script, if any.
+
+STARTER SCRIPTS
+---------------
+
+You can avoid reading the rest of this document by running 'perf trace
+-g perl' in the same directory as an existing perf.data trace file.
+That will generate a starter script containing a handler for each of
+the event types in the trace file; it simply prints every available
+field for each event in the trace file.
+
+You can also look at the existing scripts in
+~/libexec/perf-core/scripts/perl for typical examples showing how to
+do basic things like aggregate event data, print results, etc.  Also,
+the check-perf-trace.pl script, while not interesting for its results,
+attempts to exercise all of the main scripting features.
+
+EVENT HANDLERS
+--------------
+
+When perf trace is invoked using a trace script, a user-defined
+'handler function' is called for each event in the trace.  If there's
+no handler function defined for a given event type, the event is
+ignored (or passed to a 'trace_handled' function, see below) and the
+next event is processed.
+
+Most of the event's field values are passed as arguments to the
+handler function; some of the less common ones aren't - those are
+available as calls back into the perf executable (see below).
+
+As an example, the following perf record command can be used to record
+all sched_wakeup events in the system:
+
+ # perf record -c 1 -f -a -M -R -e sched:sched_wakeup
+
+Traces meant to be processed using a script should be recorded with
+the above options: -c 1 says to sample every event, -a to enable
+system-wide collection, -M to multiplex the output, and -R to collect
+raw samples.
+
+The format file for the sched_wakep event defines the following fields
+(see /sys/kernel/debug/tracing/events/sched/sched_wakeup/format):
+
+----
+ format:
+        field:unsigned short common_type;
+        field:unsigned char common_flags;
+        field:unsigned char common_preempt_count;
+        field:int common_pid;
+        field:int common_lock_depth;
+
+        field:char comm[TASK_COMM_LEN];
+        field:pid_t pid;
+        field:int prio;
+        field:int success;
+        field:int target_cpu;
+----
+
+The handler function for this event would be defined as:
+
+----
+sub sched::sched_wakeup
+{
+   my ($event_name, $context, $common_cpu, $common_secs,
+       $common_nsecs, $common_pid, $common_comm,
+       $comm, $pid, $prio, $success, $target_cpu) = @_;
+}
+----
+
+The handler function takes the form subsystem::event_name.
+
+The $common_* arguments in the handler's argument list are the set of
+arguments passed to all event handlers; some of the fields correspond
+to the common_* fields in the format file, but some are synthesized,
+and some of the common_* fields aren't common enough to to be passed
+to every event as arguments but are available as library functions.
+
+Here's a brief description of each of the invariant event args:
+
+ $event_name               the name of the event as text
+ $context                  an opaque 'cookie' used in calls back into perf
+ $common_cpu               the cpu the event occurred on
+ $common_secs              the secs portion of the event timestamp
+ $common_nsecs             the nsecs portion of the event timestamp
+ $common_pid               the pid of the current task
+ $common_comm              the name of the current process
+
+All of the remaining fields in the event's format file have
+counterparts as handler function arguments of the same name, as can be
+seen in the example above.
+
+The above provides the basics needed to directly access every field of
+every event in a trace, which covers 90% of what you need to know to
+write a useful trace script.  The sections below cover the rest.
+
+SCRIPT LAYOUT
+-------------
+
+Every perf trace Perl script should start by setting up a Perl module
+search path and 'use'ing a few support modules (see module
+descriptions below):
+
+----
+ use lib "$ENV{'PERF_EXEC_PATH'}/scripts/perl/Perf-Trace-Util/lib";
+ use lib "./Perf-Trace-Util/lib";
+ use Perf::Trace::Core;
+ use Perf::Trace::Context;
+ use Perf::Trace::Util;
+----
+
+The rest of the script can contain handler functions and support
+functions in any order.
+
+Aside from the event handler functions discussed above, every script
+can implement a set of optional functions:
+
+*trace_begin*, if defined, is called before any event is processed and
+gives scripts a chance to do setup tasks:
+
+----
+ sub trace_begin
+ {
+ }
+----
+
+*trace_end*, if defined, is called after all events have been
+ processed and gives scripts a chance to do end-of-script tasks, such
+ as display results:
+
+----
+sub trace_end
+{
+}
+----
+
+*trace_unhandled*, if defined, is called after for any event that
+ doesn't have a handler explicitly defined for it.  The standard set
+ of common arguments are passed into it:
+
+----
+sub trace_unhandled
+{
+    my ($event_name, $context, $common_cpu, $common_secs,
+        $common_nsecs, $common_pid, $common_comm) = @_;
+}
+----
+
+The remaining sections provide descriptions of each of the available
+built-in perf trace Perl modules and their associated functions.
+
+AVAILABLE MODULES AND FUNCTIONS
+-------------------------------
+
+The following sections describe the functions and variables available
+via the various Perf::Trace::* Perl modules.  To use the functions and
+variables from the given module, add the corresponding 'use
+Perf::Trace::XXX' line to your perf trace script.
+
+Perf::Trace::Core Module
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+These functions provide some essential functions to user scripts.
+
+The *flag_str* and *symbol_str* functions provide human-readable
+strings for flag and symbolic fields.  These correspond to the strings
+and values parsed from the 'print fmt' fields of the event format
+files:
+
+  flag_str($event_name, $field_name, $field_value) - returns the string represention corresponding to $field_value for the flag field $field_name of event $event_name
+  symbol_str($event_name, $field_name, $field_value) - returns the string represention corresponding to $field_value for the symbolic field $field_name of event $event_name
+
+Perf::Trace::Context Module
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Some of the 'common' fields in the event format file aren't all that
+common, but need to be made accessible to user scripts nonetheless.
+
+Perf::Trace::Context defines a set of functions that can be used to
+access this data in the context of the current event.  Each of these
+functions expects a $context variable, which is the same as the
+$context variable passed into every event handler as the second
+argument.
+
+ common_pc($context) - returns common_preempt count for the current event
+ common_flags($context) - returns common_flags for the current event
+ common_lock_depth($context) - returns common_lock_depth for the current event
+
+Perf::Trace::Util Module
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+Various utility functions for use with perf trace:
+
+  nsecs($secs, $nsecs) - returns total nsecs given secs/nsecs pair
+  nsecs_secs($nsecs) - returns whole secs portion given nsecs
+  nsecs_nsecs($nsecs) - returns nsecs remainder given nsecs
+  nsecs_str($nsecs) - returns printable string in the form secs.nsecs
+  avg($total, $n) - returns average given a sum and a total number of values
+
+SEE ALSO
+--------
+linkperf:perf-trace[1]
index 41ed753..07065ef 100644 (file)
@@ -20,6 +20,15 @@ OPTIONS
 --dump-raw-trace=::
         Display verbose dump of the trace data.
 
+-s::
+--script=::
+        Process trace data with the given script ([lang]:script[.ext]).
+
+-g::
+--gen-script=::
+        Generate perf-trace.[ext] starter script for given language,
+        using current perf.data.
+
 SEE ALSO
 --------
-linkperf:perf-record[1]
+linkperf:perf-record[1], linkperf:perf-trace-perl[1]
index 7e190d5..23ec660 100644 (file)
@@ -2,6 +2,7 @@
 all::
 
 # Define V=1 to have a more verbose compile.
+# Define V=2 to have an even more verbose compile.
 #
 # Define SNPRINTF_RETURNS_BOGUS if your are on a system which snprintf()
 # or vsnprintf() return -1 instead of number of characters which would
@@ -145,6 +146,10 @@ all::
 # Define NO_EXTERNAL_GREP if you don't want "perf grep" to ever call
 # your external grep (e.g., if your system lacks grep, if its grep is
 # broken, or spawning external process is slower than built-in grep perf has).
+#
+# Define LDFLAGS=-static to build a static binary.
+#
+# Define EXTRA_CFLAGS=-m64 or EXTRA_CFLAGS=-m32 as appropriate for cross-builds.
 
 PERF-VERSION-FILE: .FORCE-PERF-VERSION-FILE
        @$(SHELL_PATH) util/PERF-VERSION-GEN
@@ -157,20 +162,6 @@ uname_R := $(shell sh -c 'uname -r 2>/dev/null || echo not')
 uname_P := $(shell sh -c 'uname -p 2>/dev/null || echo not')
 uname_V := $(shell sh -c 'uname -v 2>/dev/null || echo not')
 
-#
-# Add -m32 for cross-builds:
-#
-ifdef NO_64BIT
-  MBITS := -m32
-else
-  #
-  # If we're on a 64-bit kernel, use -m64:
-  #
-  ifneq ($(patsubst %64,%,$(uname_M)),$(uname_M))
-    MBITS := -m64
-  endif
-endif
-
 # CFLAGS and LDFLAGS are for the users to override from the command line.
 
 #
@@ -200,8 +191,15 @@ EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wold-style-definition
 EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wstrict-prototypes
 EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wdeclaration-after-statement
 
-CFLAGS = $(MBITS) -ggdb3 -Wall -Wextra -std=gnu99 -Werror -O6 -fstack-protector-all -D_FORTIFY_SOURCE=2 $(EXTRA_WARNINGS)
-LDFLAGS = -lpthread -lrt -lelf -lm
+ifeq ("$(origin DEBUG)", "command line")
+  PERF_DEBUG = $(DEBUG)
+endif
+ifndef PERF_DEBUG
+  CFLAGS_OPTIMIZE = -O6
+endif
+
+CFLAGS = -ggdb3 -Wall -Wextra -std=gnu99 -Werror $(CFLAGS_OPTIMIZE) -D_FORTIFY_SOURCE=2 $(EXTRA_WARNINGS) $(EXTRA_CFLAGS)
+EXTLIBS = -lpthread -lrt -lelf -lm
 ALL_CFLAGS = $(CFLAGS)
 ALL_LDFLAGS = $(LDFLAGS)
 STRIP ?= strip
@@ -252,6 +250,9 @@ PTHREAD_LIBS = -lpthread
 # explicitly what architecture to check for. Fix this up for yours..
 SPARSE_FLAGS = -D__BIG_ENDIAN__ -D__powerpc__
 
+ifeq ($(shell sh -c "echo 'int foo(void) {char X[2]; return 3;}' | $(CC) -x c -c -Werror -fstack-protector-all - -o /dev/null "$(QUIET_STDERR)" && echo y"), y)
+  CFLAGS := $(CFLAGS) -fstack-protector-all
+endif
 
 
 ### --- END CONFIGURATION SECTION ---
@@ -327,8 +328,28 @@ LIB_FILE=libperf.a
 LIB_H += ../../include/linux/perf_event.h
 LIB_H += ../../include/linux/rbtree.h
 LIB_H += ../../include/linux/list.h
+LIB_H += ../../include/linux/stringify.h
+LIB_H += util/include/linux/bitmap.h
+LIB_H += util/include/linux/bitops.h
+LIB_H += util/include/linux/compiler.h
+LIB_H += util/include/linux/ctype.h
+LIB_H += util/include/linux/kernel.h
 LIB_H += util/include/linux/list.h
+LIB_H += util/include/linux/module.h
+LIB_H += util/include/linux/poison.h
+LIB_H += util/include/linux/prefetch.h
+LIB_H += util/include/linux/rbtree.h
+LIB_H += util/include/linux/string.h
+LIB_H += util/include/linux/types.h
+LIB_H += util/include/asm/asm-offsets.h
+LIB_H += util/include/asm/bitops.h
+LIB_H += util/include/asm/byteorder.h
+LIB_H += util/include/asm/swab.h
+LIB_H += util/include/asm/system.h
+LIB_H += util/include/asm/uaccess.h
 LIB_H += perf.h
+LIB_H += util/debugfs.h
+LIB_H += util/event.h
 LIB_H += util/types.h
 LIB_H += util/levenshtein.h
 LIB_H += util/parse-options.h
@@ -342,15 +363,22 @@ LIB_H += util/strlist.h
 LIB_H += util/run-command.h
 LIB_H += util/sigchain.h
 LIB_H += util/symbol.h
-LIB_H += util/module.h
 LIB_H += util/color.h
 LIB_H += util/values.h
+LIB_H += util/sort.h
+LIB_H += util/hist.h
+LIB_H += util/thread.h
+LIB_H += util/data_map.h
+LIB_H += util/probe-finder.h
+LIB_H += util/probe-event.h
 
 LIB_OBJS += util/abspath.o
 LIB_OBJS += util/alias.o
 LIB_OBJS += util/config.o
 LIB_OBJS += util/ctype.o
+LIB_OBJS += util/debugfs.o
 LIB_OBJS += util/environment.o
+LIB_OBJS += util/event.o
 LIB_OBJS += util/exec_cmd.o
 LIB_OBJS += util/help.o
 LIB_OBJS += util/levenshtein.o
@@ -358,6 +386,9 @@ LIB_OBJS += util/parse-options.o
 LIB_OBJS += util/parse-events.o
 LIB_OBJS += util/path.o
 LIB_OBJS += util/rbtree.o
+LIB_OBJS += util/bitmap.o
+LIB_OBJS += util/hweight.o
+LIB_OBJS += util/find_next_bit.o
 LIB_OBJS += util/run-command.o
 LIB_OBJS += util/quote.o
 LIB_OBJS += util/strbuf.o
@@ -367,7 +398,6 @@ LIB_OBJS += util/usage.o
 LIB_OBJS += util/wrapper.o
 LIB_OBJS += util/sigchain.o
 LIB_OBJS += util/symbol.o
-LIB_OBJS += util/module.o
 LIB_OBJS += util/color.o
 LIB_OBJS += util/pager.o
 LIB_OBJS += util/header.o
@@ -379,11 +409,25 @@ LIB_OBJS += util/thread.o
 LIB_OBJS += util/trace-event-parse.o
 LIB_OBJS += util/trace-event-read.o
 LIB_OBJS += util/trace-event-info.o
+LIB_OBJS += util/trace-event-perl.o
 LIB_OBJS += util/svghelper.o
+LIB_OBJS += util/sort.o
+LIB_OBJS += util/hist.o
+LIB_OBJS += util/data_map.o
+LIB_OBJS += util/probe-event.o
 
 BUILTIN_OBJS += builtin-annotate.o
+
+BUILTIN_OBJS += builtin-bench.o
+
+# Benchmark modules
+BUILTIN_OBJS += bench/sched-messaging.o
+BUILTIN_OBJS += bench/sched-pipe.o
+BUILTIN_OBJS += bench/mem-memcpy.o
+
 BUILTIN_OBJS += builtin-help.o
 BUILTIN_OBJS += builtin-sched.o
+BUILTIN_OBJS += builtin-buildid-list.o
 BUILTIN_OBJS += builtin-list.o
 BUILTIN_OBJS += builtin-record.o
 BUILTIN_OBJS += builtin-report.o
@@ -391,9 +435,16 @@ BUILTIN_OBJS += builtin-stat.o
 BUILTIN_OBJS += builtin-timechart.o
 BUILTIN_OBJS += builtin-top.o
 BUILTIN_OBJS += builtin-trace.o
+BUILTIN_OBJS += builtin-probe.o
+BUILTIN_OBJS += builtin-kmem.o
 
 PERFLIBS = $(LIB_FILE)
 
+ifeq ($(V), 2)
+       QUIET_STDERR = ">/dev/null"
+else
+       QUIET_STDERR = ">/dev/null 2>&1"
+endif
 #
 # Platform specific tweaks
 #
@@ -421,36 +472,58 @@ ifeq ($(uname_S),Darwin)
        PTHREAD_LIBS =
 endif
 
-ifeq ($(shell sh -c "(echo '\#include <libelf.h>'; echo 'int main(void) { Elf * elf = elf_begin(0, ELF_C_READ, 0); return (long)elf; }') | $(CC) -x c - $(ALL_CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -o /dev/null $(ALL_LDFLAGS) > /dev/null 2>&1 && echo y"), y)
-       ifneq ($(shell sh -c "(echo '\#include <libelf.h>'; echo 'int main(void) { Elf * elf = elf_begin(0, ELF_C_READ_MMAP, 0); return (long)elf; }') | $(CC) -x c - $(ALL_CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -o /dev/null $(ALL_LDFLAGS) > /dev/null 2>&1 && echo y"), y)
+ifeq ($(shell sh -c "(echo '\#include <libelf.h>'; echo 'int main(void) { Elf * elf = elf_begin(0, ELF_C_READ, 0); return (long)elf; }') | $(CC) -x c - $(ALL_CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -o /dev/null $(ALL_LDFLAGS) $(EXTLIBS) "$(QUIET_STDERR)" && echo y"), y)
+ifneq ($(shell sh -c "(echo '\#include <gnu/libc-version.h>'; echo 'int main(void) { const char * version = gnu_get_libc_version(); return (long)version; }') | $(CC) -x c - $(ALL_CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -o /dev/null $(ALL_LDFLAGS) $(EXTLIBS) "$(QUIET_STDERR)" && echo y"), y)
+       msg := $(error No gnu/libc-version.h found, please install glibc-dev[el]/glibc-static);
+endif
+
+       ifneq ($(shell sh -c "(echo '\#include <libelf.h>'; echo 'int main(void) { Elf * elf = elf_begin(0, ELF_C_READ_MMAP, 0); return (long)elf; }') | $(CC) -x c - $(ALL_CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -o /dev/null $(ALL_LDFLAGS) $(EXTLIBS) "$(QUIET_STDERR)" && echo y"), y)
                BASIC_CFLAGS += -DLIBELF_NO_MMAP
        endif
 else
        msg := $(error No libelf.h/libelf found, please install libelf-dev/elfutils-libelf-devel and glibc-dev[el]);
 endif
 
+ifneq ($(shell sh -c "(echo '\#include <libdwarf/dwarf.h>'; echo '\#include <libdwarf/libdwarf.h>'; echo 'int main(void) { Dwarf_Debug dbg; Dwarf_Error err; Dwarf_Ranges *rng; dwarf_init(0, DW_DLC_READ, 0, 0, &dbg, &err); dwarf_get_ranges(dbg, 0, &rng, 0, 0, &err); return (long)dbg; }') | $(CC) -x c - $(ALL_CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -ldwarf -lelf -o /dev/null $(ALL_LDFLAGS) $(EXTLIBS) "$(QUIET_STDERR)" && echo y"), y)
+       msg := $(warning No libdwarf.h found or old libdwarf.h found, disables dwarf support. Please install libdwarf-dev/libdwarf-devel >= 20081231);
+       BASIC_CFLAGS += -DNO_LIBDWARF
+else
+       EXTLIBS += -lelf -ldwarf
+       LIB_OBJS += util/probe-finder.o
+endif
+
+PERL_EMBED_LDOPTS = `perl -MExtUtils::Embed -e ldopts 2>/dev/null`
+PERL_EMBED_CCOPTS = `perl -MExtUtils::Embed -e ccopts 2>/dev/null`
+
+ifneq ($(shell sh -c "(echo '\#include <EXTERN.h>'; echo '\#include <perl.h>'; echo 'int main(void) { perl_alloc(); return 0; }') | $(CC) -x c - $(PERL_EMBED_CCOPTS) -o /dev/null $(PERL_EMBED_LDOPTS) > /dev/null 2>&1 && echo y"), y)
+       BASIC_CFLAGS += -DNO_LIBPERL
+else
+       ALL_LDFLAGS += $(PERL_EMBED_LDOPTS)
+       LIB_OBJS += scripts/perl/Perf-Trace-Util/Context.o
+endif
+
 ifdef NO_DEMANGLE
        BASIC_CFLAGS += -DNO_DEMANGLE
 else
-       has_bfd := $(shell sh -c "(echo '\#include <bfd.h>'; echo 'int main(void) { bfd_demangle(0, 0, 0); return 0; }') | $(CC) -x c - $(ALL_CFLAGS) -o /dev/null $(ALL_LDFLAGS) -lbfd > /dev/null 2>&1 && echo y")
+       has_bfd := $(shell sh -c "(echo '\#include <bfd.h>'; echo 'int main(void) { bfd_demangle(0, 0, 0); return 0; }') | $(CC) -x c - $(ALL_CFLAGS) -o /dev/null $(ALL_LDFLAGS) $(EXTLIBS) -lbfd "$(QUIET_STDERR)" && echo y")
 
        ifeq ($(has_bfd),y)
                EXTLIBS += -lbfd
        else
-               has_bfd_iberty := $(shell sh -c "(echo '\#include <bfd.h>'; echo 'int main(void) { bfd_demangle(0, 0, 0); return 0; }') | $(CC) -x c - $(ALL_CFLAGS) -o /dev/null $(ALL_LDFLAGS) -lbfd -liberty > /dev/null 2>&1 && echo y")
+               has_bfd_iberty := $(shell sh -c "(echo '\#include <bfd.h>'; echo 'int main(void) { bfd_demangle(0, 0, 0); return 0; }') | $(CC) -x c - $(ALL_CFLAGS) -o /dev/null $(ALL_LDFLAGS) $(EXTLIBS) -lbfd -liberty "$(QUIET_STDERR)" && echo y")
                ifeq ($(has_bfd_iberty),y)
                        EXTLIBS += -lbfd -liberty
                else
-                       has_bfd_iberty_z := $(shell sh -c "(echo '\#include <bfd.h>'; echo 'int main(void) { bfd_demangle(0, 0, 0); return 0; }') | $(CC) -x c - $(ALL_CFLAGS) -o /dev/null $(ALL_LDFLAGS) -lbfd -liberty -lz > /dev/null 2>&1 && echo y")
+                       has_bfd_iberty_z := $(shell sh -c "(echo '\#include <bfd.h>'; echo 'int main(void) { bfd_demangle(0, 0, 0); return 0; }') | $(CC) -x c - $(ALL_CFLAGS) -o /dev/null $(ALL_LDFLAGS) $(EXTLIBS) -lbfd -liberty -lz "$(QUIET_STDERR)" && echo y")
                        ifeq ($(has_bfd_iberty_z),y)
                                EXTLIBS += -lbfd -liberty -lz
                        else
-                               has_cplus_demangle := $(shell sh -c "(echo 'extern char *cplus_demangle(const char *, int);'; echo 'int main(void) { cplus_demangle(0, 0); return 0; }') | $(CC) -x c - $(ALL_CFLAGS) -o /dev/null $(ALL_LDFLAGS) -liberty > /dev/null 2>&1 && echo y")
+                               has_cplus_demangle := $(shell sh -c "(echo 'extern char *cplus_demangle(const char *, int);'; echo 'int main(void) { cplus_demangle(0, 0); return 0; }') | $(CC) -x c - $(ALL_CFLAGS) -o /dev/null $(ALL_LDFLAGS) $(EXTLIBS) -liberty "$(QUIET_STDERR)" && echo y")
                                ifeq ($(has_cplus_demangle),y)
                                        EXTLIBS += -liberty
                                        BASIC_CFLAGS += -DHAVE_CPLUS_DEMANGLE
                                else
-                                       msg := $(warning No bfd.h/libbfd found, install binutils-dev[el] to gain symbol demangling)
+                                       msg := $(warning No bfd.h/libbfd found, install binutils-dev[el]/zlib-static to gain symbol demangling)
                                        BASIC_CFLAGS += -DNO_DEMANGLE
                                endif
                        endif
@@ -787,6 +860,25 @@ util/config.o: util/config.c PERF-CFLAGS
 util/rbtree.o: ../../lib/rbtree.c PERF-CFLAGS
        $(QUIET_CC)$(CC) -o util/rbtree.o -c $(ALL_CFLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $<
 
+# some perf warning policies can't fit to lib/bitmap.c, eg: it warns about variable shadowing
+# from <string.h> that comes from kernel headers wrapping.
+KBITMAP_FLAGS=`echo $(ALL_CFLAGS) | sed s/-Wshadow// | sed s/-Wswitch-default// | sed s/-Wextra//`
+
+util/bitmap.o: ../../lib/bitmap.c PERF-CFLAGS
+       $(QUIET_CC)$(CC) -o util/bitmap.o -c $(KBITMAP_FLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $<
+
+util/hweight.o: ../../lib/hweight.c PERF-CFLAGS
+       $(QUIET_CC)$(CC) -o util/hweight.o -c $(ALL_CFLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $<
+
+util/find_next_bit.o: ../../lib/find_next_bit.c PERF-CFLAGS
+       $(QUIET_CC)$(CC) -o util/find_next_bit.o -c $(ALL_CFLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $<
+
+util/trace-event-perl.o: util/trace-event-perl.c PERF-CFLAGS
+       $(QUIET_CC)$(CC) -o util/trace-event-perl.o -c $(ALL_CFLAGS) $(PERL_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-shadow $<
+
+scripts/perl/Perf-Trace-Util/Context.o: scripts/perl/Perf-Trace-Util/Context.c PERF-CFLAGS
+       $(QUIET_CC)$(CC) -o scripts/perl/Perf-Trace-Util/Context.o -c $(ALL_CFLAGS) $(PERL_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-nested-externs $<
+
 perf-%$X: %.o $(PERFLIBS)
        $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS)
 
@@ -894,6 +986,13 @@ export perfexec_instdir
 install: all
        $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(bindir_SQ)'
        $(INSTALL) perf$X '$(DESTDIR_SQ)$(bindir_SQ)'
+       $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/Perf-Trace-Util/lib/Perf/Trace'
+       $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/bin'
+       $(INSTALL) scripts/perl/Perf-Trace-Util/lib/Perf/Trace/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/Perf-Trace-Util/lib/Perf/Trace'
+       $(INSTALL) scripts/perl/*.pl -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl'
+       $(INSTALL) scripts/perl/bin/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/bin'
+       $(INSTALL) scripts/perl/Perf-Trace-Util/Makefile.PL -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/Perf-Trace-Util'
+       $(INSTALL) scripts/perl/Perf-Trace-Util/README -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/Perf-Trace-Util'
 ifdef BUILT_INS
        $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)'
        $(INSTALL) $(BUILT_INS) '$(DESTDIR_SQ)$(perfexec_instdir_SQ)'
@@ -979,7 +1078,7 @@ distclean: clean
 #      $(RM) configure
 
 clean:
-       $(RM) *.o */*.o $(LIB_FILE)
+       $(RM) *.o */*.o */*/*.o */*/*/*.o $(LIB_FILE)
        $(RM) $(ALL_PROGRAMS) $(BUILT_INS) perf$X
        $(RM) $(TEST_PROGRAMS)
        $(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo common-cmds.h TAGS tags cscope*
diff --git a/tools/perf/bench/bench.h b/tools/perf/bench/bench.h
new file mode 100644 (file)
index 0000000..f7781c6
--- /dev/null
@@ -0,0 +1,17 @@
+#ifndef BENCH_H
+#define BENCH_H
+
+extern int bench_sched_messaging(int argc, const char **argv, const char *prefix);
+extern int bench_sched_pipe(int argc, const char **argv, const char *prefix);
+extern int bench_mem_memcpy(int argc, const char **argv, const char *prefix __used);
+
+#define BENCH_FORMAT_DEFAULT_STR       "default"
+#define BENCH_FORMAT_DEFAULT           0
+#define BENCH_FORMAT_SIMPLE_STR                "simple"
+#define BENCH_FORMAT_SIMPLE            1
+
+#define BENCH_FORMAT_UNKNOWN           -1
+
+extern int bench_format;
+
+#endif
diff --git a/tools/perf/bench/mem-memcpy.c b/tools/perf/bench/mem-memcpy.c
new file mode 100644 (file)
index 0000000..8977317
--- /dev/null
@@ -0,0 +1,193 @@
+/*
+ * mem-memcpy.c
+ *
+ * memcpy: Simple memory copy in various ways
+ *
+ * Written by Hitoshi Mitake <mitake@dcl.info.waseda.ac.jp>
+ */
+#include <ctype.h>
+
+#include "../perf.h"
+#include "../util/util.h"
+#include "../util/parse-options.h"
+#include "../util/string.h"
+#include "../util/header.h"
+#include "bench.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/time.h>
+#include <errno.h>
+
+#define K 1024
+
+static const char      *length_str     = "1MB";
+static const char      *routine        = "default";
+static int             use_clock       = 0;
+static int             clock_fd;
+
+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)"),
+       OPT_STRING('r', "routine", &routine, "default",
+                   "Specify routine to copy"),
+       OPT_BOOLEAN('c', "clock", &use_clock,
+                   "Use CPU clock for measuring"),
+       OPT_END()
+};
+
+struct routine {
+       const char *name;
+       const char *desc;
+       void * (*fn)(void *dst, const void *src, size_t len);
+};
+
+struct routine routines[] = {
+       { "default",
+         "Default memcpy() provided by glibc",
+         memcpy },
+       { NULL,
+         NULL,
+         NULL   }
+};
+
+static const char * const bench_mem_memcpy_usage[] = {
+       "perf bench mem memcpy <options>",
+       NULL
+};
+
+static struct perf_event_attr clock_attr = {
+       .type           = PERF_TYPE_HARDWARE,
+       .config         = PERF_COUNT_HW_CPU_CYCLES
+};
+
+static void init_clock(void)
+{
+       clock_fd = sys_perf_event_open(&clock_attr, getpid(), -1, -1, 0);
+
+       if (clock_fd < 0 && errno == ENOSYS)
+               die("No CONFIG_PERF_EVENTS=y kernel support configured?\n");
+       else
+               BUG_ON(clock_fd < 0);
+}
+
+static u64 get_clock(void)
+{
+       int ret;
+       u64 clk;
+
+       ret = read(clock_fd, &clk, sizeof(u64));
+       BUG_ON(ret != sizeof(u64));
+
+       return clk;
+}
+
+static double timeval2double(struct timeval *ts)
+{
+       return (double)ts->tv_sec +
+               (double)ts->tv_usec / (double)1000000;
+}
+
+int bench_mem_memcpy(int argc, const char **argv,
+                    const char *prefix __used)
+{
+       int i;
+       void *dst, *src;
+       size_t length;
+       double bps = 0.0;
+       struct timeval tv_start, tv_end, tv_diff;
+       u64 clock_start, clock_end, clock_diff;
+
+       clock_start = clock_end = clock_diff = 0ULL;
+       argc = parse_options(argc, argv, options,
+                            bench_mem_memcpy_usage, 0);
+
+       tv_diff.tv_sec = 0;
+       tv_diff.tv_usec = 0;
+       length = (size_t)perf_atoll((char *)length_str);
+
+       if ((s64)length <= 0) {
+               fprintf(stderr, "Invalid length:%s\n", length_str);
+               return 1;
+       }
+
+       for (i = 0; routines[i].name; i++) {
+               if (!strcmp(routines[i].name, routine))
+                       break;
+       }
+       if (!routines[i].name) {
+               printf("Unknown routine:%s\n", routine);
+               printf("Available routines...\n");
+               for (i = 0; routines[i].name; i++) {
+                       printf("\t%s ... %s\n",
+                              routines[i].name, routines[i].desc);
+               }
+               return 1;
+       }
+
+       dst = zalloc(length);
+       if (!dst)
+               die("memory allocation failed - maybe length is too large?\n");
+
+       src = zalloc(length);
+       if (!src)
+               die("memory allocation failed - maybe length is too large?\n");
+
+       if (bench_format == BENCH_FORMAT_DEFAULT) {
+               printf("# Copying %s Bytes from %p to %p ...\n\n",
+                      length_str, src, dst);
+       }
+
+       if (use_clock) {
+               init_clock();
+               clock_start = get_clock();
+       } else {
+               BUG_ON(gettimeofday(&tv_start, NULL));
+       }
+
+       routines[i].fn(dst, src, length);
+
+       if (use_clock) {
+               clock_end = get_clock();
+               clock_diff = clock_end - clock_start;
+       } else {
+               BUG_ON(gettimeofday(&tv_end, NULL));
+               timersub(&tv_end, &tv_start, &tv_diff);
+               bps = (double)((double)length / timeval2double(&tv_diff));
+       }
+
+       switch (bench_format) {
+       case BENCH_FORMAT_DEFAULT:
+               if (use_clock) {
+                       printf(" %14lf Clock/Byte\n",
+                              (double)clock_diff / (double)length);
+               } else {
+                       if (bps < K)
+                               printf(" %14lf B/Sec\n", bps);
+                       else if (bps < K * K)
+                               printf(" %14lfd KB/Sec\n", bps / 1024);
+                       else if (bps < K * K * K)
+                               printf(" %14lf MB/Sec\n", bps / 1024 / 1024);
+                       else {
+                               printf(" %14lf GB/Sec\n",
+                                      bps / 1024 / 1024 / 1024);
+                       }
+               }
+               break;
+       case BENCH_FORMAT_SIMPLE:
+               if (use_clock) {
+                       printf("%14lf\n",
+                              (double)clock_diff / (double)length);
+               } else
+                       printf("%lf\n", bps);
+               break;
+       default:
+               /* reaching this means there's some disaster: */
+               die("unknown format: %d\n", bench_format);
+               break;
+       }
+
+       return 0;
+}
diff --git a/tools/perf/bench/sched-messaging.c b/tools/perf/bench/sched-messaging.c
new file mode 100644 (file)
index 0000000..605a2a9
--- /dev/null
@@ -0,0 +1,336 @@
+/*
+ *
+ * builtin-bench-messaging.c
+ *
+ * messaging: Benchmark for scheduler and IPC mechanisms
+ *
+ * Based on hackbench by Rusty Russell <rusty@rustcorp.com.au>
+ * Ported to perf by Hitoshi Mitake <mitake@dcl.info.waseda.ac.jp>
+ *
+ */
+
+#include "../perf.h"
+#include "../util/util.h"
+#include "../util/parse-options.h"
+#include "../builtin.h"
+#include "bench.h"
+
+/* Test groups of 20 processes spraying to 20 receivers */
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/wait.h>
+#include <sys/time.h>
+#include <sys/poll.h>
+#include <limits.h>
+
+#define DATASIZE 100
+
+static int use_pipes = 0;
+static unsigned int loops = 100;
+static unsigned int thread_mode = 0;
+static unsigned int num_groups = 10;
+
+struct sender_context {
+       unsigned int num_fds;
+       int ready_out;
+       int wakefd;
+       int out_fds[0];
+};
+
+struct receiver_context {
+       unsigned int num_packets;
+       int in_fds[2];
+       int ready_out;
+       int wakefd;
+};
+
+static void barf(const char *msg)
+{
+       fprintf(stderr, "%s (error: %s)\n", msg, strerror(errno));
+       exit(1);
+}
+
+static void fdpair(int fds[2])
+{
+       if (use_pipes) {
+               if (pipe(fds) == 0)
+                       return;
+       } else {
+               if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds) == 0)
+                       return;
+       }
+
+       barf(use_pipes ? "pipe()" : "socketpair()");
+}
+
+/* Block until we're ready to go */
+static void ready(int ready_out, int wakefd)
+{
+       char dummy;
+       struct pollfd pollfd = { .fd = wakefd, .events = POLLIN };
+
+       /* Tell them we're ready. */
+       if (write(ready_out, &dummy, 1) != 1)
+               barf("CLIENT: ready write");
+
+       /* Wait for "GO" signal */
+       if (poll(&pollfd, 1, -1) != 1)
+               barf("poll");
+}
+
+/* Sender sprays loops messages down each file descriptor */
+static void *sender(struct sender_context *ctx)
+{
+       char data[DATASIZE];
+       unsigned int i, j;
+
+       ready(ctx->ready_out, ctx->wakefd);
+
+       /* Now pump to every receiver. */
+       for (i = 0; i < loops; i++) {
+               for (j = 0; j < ctx->num_fds; j++) {
+                       int ret, done = 0;
+
+again:
+                       ret = write(ctx->out_fds[j], data + done,
+                                   sizeof(data)-done);
+                       if (ret < 0)
+                               barf("SENDER: write");
+                       done += ret;
+                       if (done < DATASIZE)
+                               goto again;
+               }
+       }
+
+       return NULL;
+}
+
+
+/* One receiver per fd */
+static void *receiver(struct receiver_context* ctx)
+{
+       unsigned int i;
+
+       if (!thread_mode)
+               close(ctx->in_fds[1]);
+
+       /* Wait for start... */
+       ready(ctx->ready_out, ctx->wakefd);
+
+       /* Receive them all */
+       for (i = 0; i < ctx->num_packets; i++) {
+               char data[DATASIZE];
+               int ret, done = 0;
+
+again:
+               ret = read(ctx->in_fds[0], data + done, DATASIZE - done);
+               if (ret < 0)
+                       barf("SERVER: read");
+               done += ret;
+               if (done < DATASIZE)
+                       goto again;
+       }
+
+       return NULL;
+}
+
+static pthread_t create_worker(void *ctx, void *(*func)(void *))
+{
+       pthread_attr_t attr;
+       pthread_t childid;
+       int err;
+
+       if (!thread_mode) {
+               /* process mode */
+               /* Fork the receiver. */
+               switch (fork()) {
+               case -1:
+                       barf("fork()");
+                       break;
+               case 0:
+                       (*func) (ctx);
+                       exit(0);
+                       break;
+               default:
+                       break;
+               }
+
+               return (pthread_t)0;
+       }
+
+       if (pthread_attr_init(&attr) != 0)
+               barf("pthread_attr_init:");
+
+#ifndef __ia64__
+       if (pthread_attr_setstacksize(&attr, PTHREAD_STACK_MIN) != 0)
+               barf("pthread_attr_setstacksize");
+#endif
+
+       err = pthread_create(&childid, &attr, func, ctx);
+       if (err != 0) {
+               fprintf(stderr, "pthread_create failed: %s (%d)\n",
+                       strerror(err), err);
+               exit(-1);
+       }
+       return childid;
+}
+
+static void reap_worker(pthread_t id)
+{
+       int proc_status;
+       void *thread_status;
+
+       if (!thread_mode) {
+               /* process mode */
+               wait(&proc_status);
+               if (!WIFEXITED(proc_status))
+                       exit(1);
+       } else {
+               pthread_join(id, &thread_status);
+       }
+}
+
+/* One group of senders and receivers */
+static unsigned int group(pthread_t *pth,
+               unsigned int num_fds,
+               int ready_out,
+               int wakefd)
+{
+       unsigned int i;
+       struct sender_context *snd_ctx = malloc(sizeof(struct sender_context)
+                       + num_fds * sizeof(int));
+
+       if (!snd_ctx)
+               barf("malloc()");
+
+       for (i = 0; i < num_fds; i++) {
+               int fds[2];
+               struct receiver_context *ctx = malloc(sizeof(*ctx));
+
+               if (!ctx)
+                       barf("malloc()");
+
+
+               /* Create the pipe between client and server */
+               fdpair(fds);
+
+               ctx->num_packets = num_fds * loops;
+               ctx->in_fds[0] = fds[0];
+               ctx->in_fds[1] = fds[1];
+               ctx->ready_out = ready_out;
+               ctx->wakefd = wakefd;
+
+               pth[i] = create_worker(ctx, (void *)receiver);
+
+               snd_ctx->out_fds[i] = fds[1];
+               if (!thread_mode)
+                       close(fds[0]);
+       }
+
+       /* Now we have all the fds, fork the senders */
+       for (i = 0; i < num_fds; i++) {
+               snd_ctx->ready_out = ready_out;
+               snd_ctx->wakefd = wakefd;
+               snd_ctx->num_fds = num_fds;
+
+               pth[num_fds+i] = create_worker(snd_ctx, (void *)sender);
+       }
+
+       /* Close the fds we have left */
+       if (!thread_mode)
+               for (i = 0; i < num_fds; i++)
+                       close(snd_ctx->out_fds[i]);
+
+       /* Return number of children to reap */
+       return num_fds * 2;
+}
+
+static const struct option options[] = {
+       OPT_BOOLEAN('p', "pipe", &use_pipes,
+                   "Use pipe() instead of socketpair()"),
+       OPT_BOOLEAN('t', "thread", &thread_mode,
+                   "Be multi thread instead of multi process"),
+       OPT_INTEGER('g', "group", &num_groups,
+                   "Specify number of groups"),
+       OPT_INTEGER('l', "loop", &loops,
+                   "Specify number of loops"),
+       OPT_END()
+};
+
+static const char * const bench_sched_message_usage[] = {
+       "perf bench sched messaging <options>",
+       NULL
+};
+
+int bench_sched_messaging(int argc, const char **argv,
+                   const char *prefix __used)
+{
+       unsigned int i, total_children;
+       struct timeval start, stop, diff;
+       unsigned int num_fds = 20;
+       int readyfds[2], wakefds[2];
+       char dummy;
+       pthread_t *pth_tab;
+
+       argc = parse_options(argc, argv, options,
+                            bench_sched_message_usage, 0);
+
+       pth_tab = malloc(num_fds * 2 * num_groups * sizeof(pthread_t));
+       if (!pth_tab)
+               barf("main:malloc()");
+
+       fdpair(readyfds);
+       fdpair(wakefds);
+
+       total_children = 0;
+       for (i = 0; i < num_groups; i++)
+               total_children += group(pth_tab+total_children, num_fds,
+                                       readyfds[1], wakefds[0]);
+
+       /* Wait for everyone to be ready */
+       for (i = 0; i < total_children; i++)
+               if (read(readyfds[0], &dummy, 1) != 1)
+                       barf("Reading for readyfds");
+
+       gettimeofday(&start, NULL);
+
+       /* Kick them off */
+       if (write(wakefds[1], &dummy, 1) != 1)
+               barf("Writing to start them");
+
+       /* Reap them all */
+       for (i = 0; i < total_children; i++)
+               reap_worker(pth_tab[i]);
+
+       gettimeofday(&stop, NULL);
+
+       timersub(&stop, &start, &diff);
+
+       switch (bench_format) {
+       case BENCH_FORMAT_DEFAULT:
+               printf("# %d sender and receiver %s per group\n",
+                      num_fds, thread_mode ? "threads" : "processes");
+               printf("# %d groups == %d %s run\n\n",
+                      num_groups, num_groups * 2 * num_fds,
+                      thread_mode ? "threads" : "processes");
+               printf(" %14s: %lu.%03lu [sec]\n", "Total time",
+                      diff.tv_sec, diff.tv_usec/1000);
+               break;
+       case BENCH_FORMAT_SIMPLE:
+               printf("%lu.%03lu\n", diff.tv_sec, diff.tv_usec/1000);
+               break;
+       default:
+               /* reaching here is something disaster */
+               fprintf(stderr, "Unknown format:%d\n", bench_format);
+               exit(1);
+               break;
+       }
+
+       return 0;
+}
diff --git a/tools/perf/bench/sched-pipe.c b/tools/perf/bench/sched-pipe.c
new file mode 100644 (file)
index 0000000..238185f
--- /dev/null
@@ -0,0 +1,124 @@
+/*
+ *
+ * builtin-bench-pipe.c
+ *
+ * pipe: Benchmark for pipe()
+ *
+ * Based on pipe-test-1m.c by Ingo Molnar <mingo@redhat.com>
+ *  http://people.redhat.com/mingo/cfs-scheduler/tools/pipe-test-1m.c
+ * Ported to perf by Hitoshi Mitake <mitake@dcl.info.waseda.ac.jp>
+ *
+ */
+
+#include "../perf.h"
+#include "../util/util.h"
+#include "../util/parse-options.h"
+#include "../builtin.h"
+#include "bench.h"
+
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <sys/wait.h>
+#include <linux/unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+#include <sys/time.h>
+#include <sys/types.h>
+
+#define LOOPS_DEFAULT 1000000
+static int loops = LOOPS_DEFAULT;
+
+static const struct option options[] = {
+       OPT_INTEGER('l', "loop", &loops,
+                   "Specify number of loops"),
+       OPT_END()
+};
+
+static const char * const bench_sched_pipe_usage[] = {
+       "perf bench sched pipe <options>",
+       NULL
+};
+
+int bench_sched_pipe(int argc, const char **argv,
+                    const char *prefix __used)
+{
+       int pipe_1[2], pipe_2[2];
+       int m = 0, i;
+       struct timeval start, stop, diff;
+       unsigned long long result_usec = 0;
+
+       /*
+        * why does "ret" exist?
+        * discarding returned value of read(), write()
+        * causes error in building environment for perf
+        */
+       int ret, wait_stat;
+       pid_t pid, retpid;
+
+       argc = parse_options(argc, argv, options,
+                            bench_sched_pipe_usage, 0);
+
+       assert(!pipe(pipe_1));
+       assert(!pipe(pipe_2));
+
+       pid = fork();
+       assert(pid >= 0);
+
+       gettimeofday(&start, NULL);
+
+       if (!pid) {
+               for (i = 0; i < loops; i++) {
+                       ret = read(pipe_1[0], &m, sizeof(int));
+                       ret = write(pipe_2[1], &m, sizeof(int));
+               }
+       } else {
+               for (i = 0; i < loops; i++) {
+                       ret = write(pipe_1[1], &m, sizeof(int));
+                       ret = read(pipe_2[0], &m, sizeof(int));
+               }
+       }
+
+       gettimeofday(&stop, NULL);
+       timersub(&stop, &start, &diff);
+
+       if (pid) {
+               retpid = waitpid(pid, &wait_stat, 0);
+               assert((retpid == pid) && WIFEXITED(wait_stat));
+               return 0;
+       }
+
+       switch (bench_format) {
+       case BENCH_FORMAT_DEFAULT:
+               printf("# Extecuted %d pipe operations between two tasks\n\n",
+                       loops);
+
+               result_usec = diff.tv_sec * 1000000;
+               result_usec += diff.tv_usec;
+
+               printf(" %14s: %lu.%03lu [sec]\n\n", "Total time",
+                      diff.tv_sec, diff.tv_usec/1000);
+
+               printf(" %14lf usecs/op\n",
+                      (double)result_usec / (double)loops);
+               printf(" %14d ops/sec\n",
+                      (int)((double)loops /
+                            ((double)result_usec / (double)1000000)));
+               break;
+
+       case BENCH_FORMAT_SIMPLE:
+               printf("%lu.%03lu\n",
+                      diff.tv_sec, diff.tv_usec / 1000);
+               break;
+
+       default:
+               /* reaching here is something disaster */
+               fprintf(stderr, "Unknown format:%d\n", bench_format);
+               exit(1);
+               break;
+       }
+
+       return 0;
+}
index 1ec7416..0bf2e8f 100644 (file)
 #include "perf.h"
 #include "util/debug.h"
 
+#include "util/event.h"
 #include "util/parse-options.h"
 #include "util/parse-events.h"
 #include "util/thread.h"
+#include "util/sort.h"
+#include "util/hist.h"
+#include "util/data_map.h"
 
 static char            const *input_name = "perf.data";
 
-static char            default_sort_order[] = "comm,symbol";
-static char            *sort_order = default_sort_order;
-
 static int             force;
-static int             input;
-static int             show_mask = SHOW_KERNEL | SHOW_USER | SHOW_HV;
 
 static int             full_paths;
 
 static int             print_line;
 
-static unsigned long   page_size;
-static unsigned long   mmap_window = 32;
-
-static struct rb_root  threads;
-static struct thread   *last_match;
-
+struct sym_hist {
+       u64             sum;
+       u64             ip[0];
+};
 
 struct sym_ext {
        struct rb_node  node;
@@ -49,247 +46,38 @@ struct sym_ext {
        char            *path;
 };
 
-/*
- * histogram, sorted on item, collects counts
- */
-
-static struct rb_root hist;
-
-struct hist_entry {
-       struct rb_node   rb_node;
-
-       struct thread    *thread;
-       struct map       *map;
-       struct dso       *dso;
-       struct symbol    *sym;
-       u64      ip;
-       char             level;
-
-       uint32_t         count;
-};
-
-/*
- * configurable sorting bits
- */
-
-struct sort_entry {
-       struct list_head list;
-
-       const char *header;
-
-       int64_t (*cmp)(struct hist_entry *, struct hist_entry *);
-       int64_t (*collapse)(struct hist_entry *, struct hist_entry *);
-       size_t  (*print)(FILE *fp, struct hist_entry *);
-};
-
-/* --sort pid */
-
-static int64_t
-sort__thread_cmp(struct hist_entry *left, struct hist_entry *right)
-{
-       return right->thread->pid - left->thread->pid;
-}
-
-static size_t
-sort__thread_print(FILE *fp, struct hist_entry *self)
-{
-       return fprintf(fp, "%16s:%5d", self->thread->comm ?: "", self->thread->pid);
-}
-
-static struct sort_entry sort_thread = {
-       .header = "         Command:  Pid",
-       .cmp    = sort__thread_cmp,
-       .print  = sort__thread_print,
-};
-
-/* --sort comm */
-
-static int64_t
-sort__comm_cmp(struct hist_entry *left, struct hist_entry *right)
-{
-       return right->thread->pid - left->thread->pid;
-}
-
-static int64_t
-sort__comm_collapse(struct hist_entry *left, struct hist_entry *right)
-{
-       char *comm_l = left->thread->comm;
-       char *comm_r = right->thread->comm;
-
-       if (!comm_l || !comm_r) {
-               if (!comm_l && !comm_r)
-                       return 0;
-               else if (!comm_l)
-                       return -1;
-               else
-                       return 1;
-       }
-
-       return strcmp(comm_l, comm_r);
-}
-
-static size_t
-sort__comm_print(FILE *fp, struct hist_entry *self)
-{
-       return fprintf(fp, "%16s", self->thread->comm);
-}
-
-static struct sort_entry sort_comm = {
-       .header         = "         Command",
-       .cmp            = sort__comm_cmp,
-       .collapse       = sort__comm_collapse,
-       .print          = sort__comm_print,
-};
-
-/* --sort dso */
-
-static int64_t
-sort__dso_cmp(struct hist_entry *left, struct hist_entry *right)
-{
-       struct dso *dso_l = left->dso;
-       struct dso *dso_r = right->dso;
-
-       if (!dso_l || !dso_r) {
-               if (!dso_l && !dso_r)
-                       return 0;
-               else if (!dso_l)
-                       return -1;
-               else
-                       return 1;
-       }
-
-       return strcmp(dso_l->name, dso_r->name);
-}
-
-static size_t
-sort__dso_print(FILE *fp, struct hist_entry *self)
-{
-       if (self->dso)
-               return fprintf(fp, "%-25s", self->dso->name);
-
-       return fprintf(fp, "%016llx         ", (u64)self->ip);
-}
-
-static struct sort_entry sort_dso = {
-       .header = "Shared Object            ",
-       .cmp    = sort__dso_cmp,
-       .print  = sort__dso_print,
-};
-
-/* --sort symbol */
-
-static int64_t
-sort__sym_cmp(struct hist_entry *left, struct hist_entry *right)
-{
-       u64 ip_l, ip_r;
-
-       if (left->sym == right->sym)
-               return 0;
-
-       ip_l = left->sym ? left->sym->start : left->ip;
-       ip_r = right->sym ? right->sym->start : right->ip;
-
-       return (int64_t)(ip_r - ip_l);
-}
-
-static size_t
-sort__sym_print(FILE *fp, struct hist_entry *self)
-{
-       size_t ret = 0;
-
-       if (verbose)
-               ret += fprintf(fp, "%#018llx  ", (u64)self->ip);
-
-       if (self->sym) {
-               ret += fprintf(fp, "[%c] %s",
-                       self->dso == kernel_dso ? 'k' : '.', self->sym->name);
-       } else {
-               ret += fprintf(fp, "%#016llx", (u64)self->ip);
-       }
-
-       return ret;
-}
-
-static struct sort_entry sort_sym = {
-       .header = "Symbol",
-       .cmp    = sort__sym_cmp,
-       .print  = sort__sym_print,
-};
-
-static int sort__need_collapse = 0;
-
-struct sort_dimension {
-       const char              *name;
-       struct sort_entry       *entry;
-       int                     taken;
+struct sym_priv {
+       struct sym_hist *hist;
+       struct sym_ext  *ext;
 };
 
-static struct sort_dimension sort_dimensions[] = {
-       { .name = "pid",        .entry = &sort_thread,  },
-       { .name = "comm",       .entry = &sort_comm,    },
-       { .name = "dso",        .entry = &sort_dso,     },
-       { .name = "symbol",     .entry = &sort_sym,     },
+static struct symbol_conf symbol_conf = {
+       .priv_size        = sizeof(struct sym_priv),
+       .try_vmlinux_path = true,
 };
 
-static LIST_HEAD(hist_entry__sort_list);
+static const char *sym_hist_filter;
 
-static int sort_dimension__add(char *tok)
+static int symbol_filter(struct map *map __used, struct symbol *sym)
 {
-       unsigned int i;
-
-       for (i = 0; i < ARRAY_SIZE(sort_dimensions); i++) {
-               struct sort_dimension *sd = &sort_dimensions[i];
-
-               if (sd->taken)
-                       continue;
-
-               if (strncasecmp(tok, sd->name, strlen(tok)))
-                       continue;
-
-               if (sd->entry->collapse)
-                       sort__need_collapse = 1;
-
-               list_add_tail(&sd->entry->list, &hist_entry__sort_list);
-               sd->taken = 1;
+       if (sym_hist_filter == NULL ||
+           strcmp(sym->name, sym_hist_filter) == 0) {
+               struct sym_priv *priv = symbol__priv(sym);
+               const int size = (sizeof(*priv->hist) +
+                                 (sym->end - sym->start) * sizeof(u64));
 
+               priv->hist = malloc(size);
+               if (priv->hist)
+                       memset(priv->hist, 0, size);
                return 0;
        }
-
-       return -ESRCH;
-}
-
-static int64_t
-hist_entry__cmp(struct hist_entry *left, struct hist_entry *right)
-{
-       struct sort_entry *se;
-       int64_t cmp = 0;
-
-       list_for_each_entry(se, &hist_entry__sort_list, list) {
-               cmp = se->cmp(left, right);
-               if (cmp)
-                       break;
-       }
-
-       return cmp;
-}
-
-static int64_t
-hist_entry__collapse(struct hist_entry *left, struct hist_entry *right)
-{
-       struct sort_entry *se;
-       int64_t cmp = 0;
-
-       list_for_each_entry(se, &hist_entry__sort_list, list) {
-               int64_t (*f)(struct hist_entry *, struct hist_entry *);
-
-               f = se->collapse ?: se->cmp;
-
-               cmp = f(left, right);
-               if (cmp)
-                       break;
-       }
-
-       return cmp;
+       /*
+        * FIXME: We should really filter it out, as we don't want to go thru symbols
+        * we're not interested, and if a DSO ends up with no symbols, delete it too,
+        * but right now the kernel loading routines in symbol.c bail out if no symbols
+        * are found, fix it later.
+        */
+       return 0;
 }
 
 /*
@@ -299,380 +87,81 @@ static void hist_hit(struct hist_entry *he, u64 ip)
 {
        unsigned int sym_size, offset;
        struct symbol *sym = he->sym;
+       struct sym_priv *priv;
+       struct sym_hist *h;
 
        he->count++;
 
-       if (!sym || !sym->hist)
+       if (!sym || !he->map)
+               return;
+
+       priv = symbol__priv(sym);
+       if (!priv->hist)
                return;
 
        sym_size = sym->end - sym->start;
        offset = ip - sym->start;
 
+       if (verbose)
+               fprintf(stderr, "%s: ip=%Lx\n", __func__,
+                       he->map->unmap_ip(he->map, ip));
+
        if (offset >= sym_size)
                return;
 
-       sym->hist_sum++;
-       sym->hist[offset]++;
+       h = priv->hist;
+       h->sum++;
+       h->ip[offset]++;
 
        if (verbose >= 3)
                printf("%p %s: count++ [ip: %p, %08Lx] => %Ld\n",
                        (void *)(unsigned long)he->sym->start,
                        he->sym->name,
                        (void *)(unsigned long)ip, ip - he->sym->start,
-                       sym->hist[offset]);
+                       h->ip[offset]);
 }
 
-static int
-hist_entry__add(struct thread *thread, struct map *map, struct dso *dso,
-               struct symbol *sym, u64 ip, char level)
+static int hist_entry__add(struct addr_location *al, u64 count)
 {
-       struct rb_node **p = &hist.rb_node;
-       struct rb_node *parent = NULL;
-       struct hist_entry *he;
-       struct hist_entry entry = {
-               .thread = thread,
-               .map    = map,
-               .dso    = dso,
-               .sym    = sym,
-               .ip     = ip,
-               .level  = level,
-               .count  = 1,
-       };
-       int cmp;
-
-       while (*p != NULL) {
-               parent = *p;
-               he = rb_entry(parent, struct hist_entry, rb_node);
-
-               cmp = hist_entry__cmp(&entry, he);
-
-               if (!cmp) {
-                       hist_hit(he, ip);
-
-                       return 0;
-               }
-
-               if (cmp < 0)
-                       p = &(*p)->rb_left;
-               else
-                       p = &(*p)->rb_right;
-       }
-
-       he = malloc(sizeof(*he));
-       if (!he)
+       bool hit;
+       struct hist_entry *he = __hist_entry__add(al, NULL, count, &hit);
+       if (he == NULL)
                return -ENOMEM;
-       *he = entry;
-       rb_link_node(&he->rb_node, parent, p);
-       rb_insert_color(&he->rb_node, &hist);
-
+       hist_hit(he, al->addr);
        return 0;
 }
 
-static void hist_entry__free(struct hist_entry *he)
-{
-       free(he);
-}
-
-/*
- * collapse the histogram
- */
-
-static struct rb_root collapse_hists;
-
-static void collapse__insert_entry(struct hist_entry *he)
-{
-       struct rb_node **p = &collapse_hists.rb_node;
-       struct rb_node *parent = NULL;
-       struct hist_entry *iter;
-       int64_t cmp;
-
-       while (*p != NULL) {
-               parent = *p;
-               iter = rb_entry(parent, struct hist_entry, rb_node);
-
-               cmp = hist_entry__collapse(iter, he);
-
-               if (!cmp) {
-                       iter->count += he->count;
-                       hist_entry__free(he);
-                       return;
-               }
-
-               if (cmp < 0)
-                       p = &(*p)->rb_left;
-               else
-                       p = &(*p)->rb_right;
-       }
-
-       rb_link_node(&he->rb_node, parent, p);
-       rb_insert_color(&he->rb_node, &collapse_hists);
-}
-
-static void collapse__resort(void)
-{
-       struct rb_node *next;
-       struct hist_entry *n;
-
-       if (!sort__need_collapse)
-               return;
-
-       next = rb_first(&hist);
-       while (next) {
-               n = rb_entry(next, struct hist_entry, rb_node);
-               next = rb_next(&n->rb_node);
-
-               rb_erase(&n->rb_node, &hist);
-               collapse__insert_entry(n);
-       }
-}
-
-/*
- * reverse the map, sort on count.
- */
-
-static struct rb_root output_hists;
-
-static void output__insert_entry(struct hist_entry *he)
+static int process_sample_event(event_t *event)
 {
-       struct rb_node **p = &output_hists.rb_node;
-       struct rb_node *parent = NULL;
-       struct hist_entry *iter;
+       struct addr_location al;
 
-       while (*p != NULL) {
-               parent = *p;
-               iter = rb_entry(parent, struct hist_entry, rb_node);
+       dump_printf("(IP, %d): %d: %p\n", event->header.misc,
+                   event->ip.pid, (void *)(long)event->ip.ip);
 
-               if (he->count > iter->count)
-                       p = &(*p)->rb_left;
-               else
-                       p = &(*p)->rb_right;
-       }
-
-       rb_link_node(&he->rb_node, parent, p);
-       rb_insert_color(&he->rb_node, &output_hists);
-}
-
-static void output__resort(void)
-{
-       struct rb_node *next;
-       struct hist_entry *n;
-       struct rb_root *tree = &hist;
-
-       if (sort__need_collapse)
-               tree = &collapse_hists;
-
-       next = rb_first(tree);
-
-       while (next) {
-               n = rb_entry(next, struct hist_entry, rb_node);
-               next = rb_next(&n->rb_node);
-
-               rb_erase(&n->rb_node, tree);
-               output__insert_entry(n);
-       }
-}
-
-static unsigned long total = 0,
-                    total_mmap = 0,
-                    total_comm = 0,
-                    total_fork = 0,
-                    total_unknown = 0;
-
-static int
-process_sample_event(event_t *event, unsigned long offset, unsigned long head)
-{
-       char level;
-       int show = 0;
-       struct dso *dso = NULL;
-       struct thread *thread;
-       u64 ip = event->ip.ip;
-       struct map *map = NULL;
-
-       thread = threads__findnew(event->ip.pid, &threads, &last_match);
-
-       dump_printf("%p [%p]: PERF_EVENT (IP, %d): %d: %p\n",
-               (void *)(offset + head),
-               (void *)(long)(event->header.size),
-               event->header.misc,
-               event->ip.pid,
-               (void *)(long)ip);
-
-       dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid);
-
-       if (thread == NULL) {
+       if (event__preprocess_sample(event, &al, symbol_filter) < 0) {
                fprintf(stderr, "problem processing %d event, skipping it.\n",
                        event->header.type);
                return -1;
        }
 
-       if (event->header.misc & PERF_RECORD_MISC_KERNEL) {
-               show = SHOW_KERNEL;
-               level = 'k';
-
-               dso = kernel_dso;
-
-               dump_printf(" ...... dso: %s\n", dso->name);
-
-       } else if (event->header.misc & PERF_RECORD_MISC_USER) {
-
-               show = SHOW_USER;
-               level = '.';
-
-               map = thread__find_map(thread, ip);
-               if (map != NULL) {
-                       ip = map->map_ip(map, ip);
-                       dso = map->dso;
-               } else {
-                       /*
-                        * If this is outside of all known maps,
-                        * and is a negative address, try to look it
-                        * up in the kernel dso, as it might be a
-                        * vsyscall (which executes in user-mode):
-                        */
-                       if ((long long)ip < 0)
-                               dso = kernel_dso;
-               }
-               dump_printf(" ...... dso: %s\n", dso ? dso->name : "<not found>");
-
-       } else {
-               show = SHOW_HV;
-               level = 'H';
-               dump_printf(" ...... dso: [hypervisor]\n");
-       }
-
-       if (show & show_mask) {
-               struct symbol *sym = NULL;
-
-               if (dso)
-                       sym = dso->find_symbol(dso, ip);
-
-               if (hist_entry__add(thread, map, dso, sym, ip, level)) {
-                       fprintf(stderr,
-               "problem incrementing symbol count, skipping event\n");
-                       return -1;
-               }
-       }
-       total++;
-
-       return 0;
-}
-
-static int
-process_mmap_event(event_t *event, unsigned long offset, unsigned long head)
-{
-       struct thread *thread;
-       struct map *map = map__new(&event->mmap, NULL, 0);
-
-       thread = threads__findnew(event->mmap.pid, &threads, &last_match);
-
-       dump_printf("%p [%p]: PERF_RECORD_MMAP %d: [%p(%p) @ %p]: %s\n",
-               (void *)(offset + head),
-               (void *)(long)(event->header.size),
-               event->mmap.pid,
-               (void *)(long)event->mmap.start,
-               (void *)(long)event->mmap.len,
-               (void *)(long)event->mmap.pgoff,
-               event->mmap.filename);
-
-       if (thread == NULL || map == NULL) {
-               dump_printf("problem processing PERF_RECORD_MMAP, skipping event.\n");
-               return 0;
-       }
-
-       thread__insert_map(thread, map);
-       total_mmap++;
-
-       return 0;
-}
-
-static int
-process_comm_event(event_t *event, unsigned long offset, unsigned long head)
-{
-       struct thread *thread;
-
-       thread = threads__findnew(event->comm.pid, &threads, &last_match);
-       dump_printf("%p [%p]: PERF_RECORD_COMM: %s:%d\n",
-               (void *)(offset + head),
-               (void *)(long)(event->header.size),
-               event->comm.comm, event->comm.pid);
-
-       if (thread == NULL ||
-           thread__set_comm(thread, event->comm.comm)) {
-               dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n");
-               return -1;
-       }
-       total_comm++;
-
-       return 0;
-}
-
-static int
-process_fork_event(event_t *event, unsigned long offset, unsigned long head)
-{
-       struct thread *thread;
-       struct thread *parent;
-
-       thread = threads__findnew(event->fork.pid, &threads, &last_match);
-       parent = threads__findnew(event->fork.ppid, &threads, &last_match);
-       dump_printf("%p [%p]: PERF_RECORD_FORK: %d:%d\n",
-               (void *)(offset + head),
-               (void *)(long)(event->header.size),
-               event->fork.pid, event->fork.ppid);
-
-       /*
-        * A thread clone will have the same PID for both
-        * parent and child.
-        */
-       if (thread == parent)
-               return 0;
-
-       if (!thread || !parent || thread__fork(thread, parent)) {
-               dump_printf("problem processing PERF_RECORD_FORK, skipping event.\n");
-               return -1;
-       }
-       total_fork++;
-
-       return 0;
-}
-
-static int
-process_event(event_t *event, unsigned long offset, unsigned long head)
-{
-       switch (event->header.type) {
-       case PERF_RECORD_SAMPLE:
-               return process_sample_event(event, offset, head);
-
-       case PERF_RECORD_MMAP:
-               return process_mmap_event(event, offset, head);
-
-       case PERF_RECORD_COMM:
-               return process_comm_event(event, offset, head);
-
-       case PERF_RECORD_FORK:
-               return process_fork_event(event, offset, head);
-       /*
-        * We dont process them right now but they are fine:
-        */
-
-       case PERF_RECORD_THROTTLE:
-       case PERF_RECORD_UNTHROTTLE:
-               return 0;
-
-       default:
+       if (hist_entry__add(&al, 1)) {
+               fprintf(stderr, "problem incrementing symbol count, "
+                               "skipping event\n");
                return -1;
        }
 
        return 0;
 }
 
-static int
-parse_line(FILE *file, struct symbol *sym, u64 start, u64 len)
+static int parse_line(FILE *file, struct hist_entry *he, u64 len)
 {
+       struct symbol *sym = he->sym;
        char *line = NULL, *tmp, *tmp2;
        static const char *prev_line;
        static const char *prev_color;
        unsigned int offset;
        size_t line_len;
+       u64 start;
        s64 line_ip;
        int ret;
        char *c;
@@ -709,22 +198,26 @@ parse_line(FILE *file, struct symbol *sym, u64 start, u64 len)
                        line_ip = -1;
        }
 
+       start = he->map->unmap_ip(he->map, sym->start);
+
        if (line_ip != -1) {
                const char *path = NULL;
                unsigned int hits = 0;
                double percent = 0.0;
                const char *color;
-               struct sym_ext *sym_ext = sym->priv;
+               struct sym_priv *priv = symbol__priv(sym);
+               struct sym_ext *sym_ext = priv->ext;
+               struct sym_hist *h = priv->hist;
 
                offset = line_ip - start;
                if (offset < len)
-                       hits = sym->hist[offset];
+                       hits = h->ip[offset];
 
                if (offset < len && sym_ext) {
                        path = sym_ext[offset].path;
                        percent = sym_ext[offset].percent;
-               } else if (sym->hist_sum)
-                       percent = 100.0 * hits / sym->hist_sum;
+               } else if (h->sum)
+                       percent = 100.0 * hits / h->sum;
 
                color = get_percent_color(percent);
 
@@ -777,9 +270,10 @@ static void insert_source_line(struct sym_ext *sym_ext)
        rb_insert_color(&sym_ext->node, &root_sym_ext);
 }
 
-static void free_source_line(struct symbol *sym, int len)
+static void free_source_line(struct hist_entry *he, int len)
 {
-       struct sym_ext *sym_ext = sym->priv;
+       struct sym_priv *priv = symbol__priv(he->sym);
+       struct sym_ext *sym_ext = priv->ext;
        int i;
 
        if (!sym_ext)
@@ -789,26 +283,30 @@ static void free_source_line(struct symbol *sym, int len)
                free(sym_ext[i].path);
        free(sym_ext);
 
-       sym->priv = NULL;
+       priv->ext = NULL;
        root_sym_ext = RB_ROOT;
 }
 
 /* Get the filename:line for the colored entries */
 static void
-get_source_line(struct symbol *sym, u64 start, int len, const char *filename)
+get_source_line(struct hist_entry *he, int len, const char *filename)
 {
+       struct symbol *sym = he->sym;
+       u64 start;
        int i;
        char cmd[PATH_MAX * 2];
        struct sym_ext *sym_ext;
+       struct sym_priv *priv = symbol__priv(sym);
+       struct sym_hist *h = priv->hist;
 
-       if (!sym->hist_sum)
+       if (!h->sum)
                return;
 
-       sym->priv = calloc(len, sizeof(struct sym_ext));
-       if (!sym->priv)
+       sym_ext = priv->ext = calloc(len, sizeof(struct sym_ext));
+       if (!priv->ext)
                return;
 
-       sym_ext = sym->priv;
+       start = he->map->unmap_ip(he->map, sym->start);
 
        for (i = 0; i < len; i++) {
                char *path = NULL;
@@ -816,7 +314,7 @@ get_source_line(struct symbol *sym, u64 start, int len, const char *filename)
                u64 offset;
                FILE *fp;
 
-               sym_ext[i].percent = 100.0 * sym->hist[i] / sym->hist_sum;
+               sym_ext[i].percent = 100.0 * h->ip[i] / h->sum;
                if (sym_ext[i].percent <= 0.5)
                        continue;
 
@@ -870,33 +368,34 @@ static void print_summary(const char *filename)
        }
 }
 
-static void annotate_sym(struct dso *dso, struct symbol *sym)
+static void annotate_sym(struct hist_entry *he)
 {
-       const char *filename = dso->name, *d_filename;
-       u64 start, end, len;
+       struct map *map = he->map;
+       struct dso *dso = map->dso;
+       struct symbol *sym = he->sym;
+       const char *filename = dso->long_name, *d_filename;
+       u64 len;
        char command[PATH_MAX*2];
        FILE *file;
 
        if (!filename)
                return;
-       if (sym->module)
-               filename = sym->module->path;
-       else if (dso == kernel_dso)
-               filename = vmlinux_name;
-
-       start = sym->obj_start;
-       if (!start)
-               start = sym->start;
+
+       if (verbose)
+               fprintf(stderr, "%s: filename=%s, sym=%s, start=%Lx, end=%Lx\n",
+                       __func__, filename, sym->name,
+                       map->unmap_ip(map, sym->start),
+                       map->unmap_ip(map, sym->end));
+
        if (full_paths)
                d_filename = filename;
        else
                d_filename = basename(filename);
 
-       end = start + sym->end - sym->start + 1;
        len = sym->end - sym->start;
 
        if (print_line) {
-               get_source_line(sym, start, len, filename);
+               get_source_line(he, len, filename);
                print_summary(filename);
        }
 
@@ -905,10 +404,12 @@ static void annotate_sym(struct dso *dso, struct symbol *sym)
        printf("------------------------------------------------\n");
 
        if (verbose >= 2)
-               printf("annotating [%p] %30s : [%p] %30s\n", dso, dso->name, sym, sym->name);
+               printf("annotating [%p] %30s : [%p] %30s\n",
+                      dso, dso->long_name, sym, sym->name);
 
        sprintf(command, "objdump --start-address=0x%016Lx --stop-address=0x%016Lx -dS %s|grep -v %s",
-                       (u64)start, (u64)end, filename, filename);
+               map->unmap_ip(map, sym->start), map->unmap_ip(map, sym->end),
+               filename, filename);
 
        if (verbose >= 3)
                printf("doing: %s\n", command);
@@ -918,159 +419,78 @@ static void annotate_sym(struct dso *dso, struct symbol *sym)
                return;
 
        while (!feof(file)) {
-               if (parse_line(file, sym, start, len) < 0)
+               if (parse_line(file, he, len) < 0)
                        break;
        }
 
        pclose(file);
        if (print_line)
-               free_source_line(sym, len);
+               free_source_line(he, len);
 }
 
 static void find_annotations(void)
 {
        struct rb_node *nd;
-       struct dso *dso;
-       int count = 0;
-
-       list_for_each_entry(dso, &dsos, node) {
-
-               for (nd = rb_first(&dso->syms); nd; nd = rb_next(nd)) {
-                       struct symbol *sym = rb_entry(nd, struct symbol, rb_node);
-
-                       if (sym->hist) {
-                               annotate_sym(dso, sym);
-                               count++;
-                       }
-               }
-       }
-
-       if (!count)
-               printf(" Error: symbol '%s' not present amongst the samples.\n", sym_hist_filter);
-}
-
-static int __cmd_annotate(void)
-{
-       int ret, rc = EXIT_FAILURE;
-       unsigned long offset = 0;
-       unsigned long head = 0;
-       struct stat input_stat;
-       event_t *event;
-       uint32_t size;
-       char *buf;
-
-       register_idle_thread(&threads, &last_match);
-
-       input = open(input_name, O_RDONLY);
-       if (input < 0) {
-               perror("failed to open file");
-               exit(-1);
-       }
-
-       ret = fstat(input, &input_stat);
-       if (ret < 0) {
-               perror("failed to stat file");
-               exit(-1);
-       }
-
-       if (!force && input_stat.st_uid && (input_stat.st_uid != geteuid())) {
-               fprintf(stderr, "file: %s not owned by current user or root\n", input_name);
-               exit(-1);
-       }
-
-       if (!input_stat.st_size) {
-               fprintf(stderr, "zero-sized file, nothing to do!\n");
-               exit(0);
-       }
-
-       if (load_kernel() < 0) {
-               perror("failed to load kernel symbols");
-               return EXIT_FAILURE;
-       }
-
-remap:
-       buf = (char *)mmap(NULL, page_size * mmap_window, PROT_READ,
-                          MAP_SHARED, input, offset);
-       if (buf == MAP_FAILED) {
-               perror("failed to mmap file");
-               exit(-1);
-       }
-
-more:
-       event = (event_t *)(buf + head);
 
-       size = event->header.size;
-       if (!size)
-               size = 8;
+       for (nd = rb_first(&output_hists); nd; nd = rb_next(nd)) {
+               struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node);
+               struct sym_priv *priv;
 
-       if (head + event->header.size >= page_size * mmap_window) {
-               unsigned long shift = page_size * (head / page_size);
-               int munmap_ret;
-
-               munmap_ret = munmap(buf, page_size * mmap_window);
-               assert(munmap_ret == 0);
-
-               offset += shift;
-               head -= shift;
-               goto remap;
-       }
-
-       size = event->header.size;
-
-       dump_printf("%p [%p]: event: %d\n",
-                       (void *)(offset + head),
-                       (void *)(long)event->header.size,
-                       event->header.type);
-
-       if (!size || process_event(event, offset, head) < 0) {
-
-               dump_printf("%p [%p]: skipping unknown header type: %d\n",
-                       (void *)(offset + head),
-                       (void *)(long)(event->header.size),
-                       event->header.type);
+               if (he->sym == NULL)
+                       continue;
 
-               total_unknown++;
+               priv = symbol__priv(he->sym);
+               if (priv->hist == NULL)
+                       continue;
 
+               annotate_sym(he);
                /*
-                * assume we lost track of the stream, check alignment, and
-                * increment a single u64 in the hope to catch on again 'soon'.
+                * Since we have a hist_entry per IP for the same symbol, free
+                * he->sym->hist to signal we already processed this symbol.
                 */
-
-               if (unlikely(head & 7))
-                       head &= ~7ULL;
-
-               size = 8;
+               free(priv->hist);
+               priv->hist = NULL;
        }
+}
 
-       head += size;
+static struct perf_file_handler file_handler = {
+       .process_sample_event   = process_sample_event,
+       .process_mmap_event     = event__process_mmap,
+       .process_comm_event     = event__process_comm,
+       .process_fork_event     = event__process_task,
+};
 
-       if (offset + head < (unsigned long)input_stat.st_size)
-               goto more;
+static int __cmd_annotate(void)
+{
+       struct perf_header *header;
+       struct thread *idle;
+       int ret;
 
-       rc = EXIT_SUCCESS;
-       close(input);
+       idle = register_idle_thread();
+       register_perf_file_handler(&file_handler);
 
-       dump_printf("      IP events: %10ld\n", total);
-       dump_printf("    mmap events: %10ld\n", total_mmap);
-       dump_printf("    comm events: %10ld\n", total_comm);
-       dump_printf("    fork events: %10ld\n", total_fork);
-       dump_printf(" unknown events: %10ld\n", total_unknown);
+       ret = mmap_dispatch_perf_file(&header, input_name, 0, 0,
+                                     &event__cwdlen, &event__cwd);
+       if (ret)
+               return ret;
 
-       if (dump_trace)
+       if (dump_trace) {
+               event__print_totals();
                return 0;
+       }
 
-       if (verbose >= 3)
-               threads__fprintf(stdout, &threads);
+       if (verbose > 3)
+               threads__fprintf(stdout);
 
-       if (verbose >= 2)
+       if (verbose > 2)
                dsos__fprintf(stdout);
 
        collapse__resort();
-       output__resort();
+       output__resort(event__total[0]);
 
        find_annotations();
 
-       return rc;
+       return ret;
 }
 
 static const char * const annotate_usage[] = {
@@ -1088,8 +508,9 @@ static const struct option options[] = {
                    "be more verbose (show symbol address, etc)"),
        OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
                    "dump raw trace in ASCII"),
-       OPT_STRING('k', "vmlinux", &vmlinux_name, "file", "vmlinux pathname"),
-       OPT_BOOLEAN('m', "modules", &modules,
+       OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
+                  "file", "vmlinux pathname"),
+       OPT_BOOLEAN('m', "modules", &symbol_conf.use_modules,
                    "load module symbols - WARNING: use only with -k and LIVE kernel"),
        OPT_BOOLEAN('l', "print-line", &print_line,
                    "print matching source lines (may be slow)"),
@@ -1115,9 +536,8 @@ static void setup_sorting(void)
 
 int cmd_annotate(int argc, const char **argv, const char *prefix __used)
 {
-       symbol__init();
-
-       page_size = getpagesize();
+       if (symbol__init(&symbol_conf) < 0)
+               return -1;
 
        argc = parse_options(argc, argv, options, annotate_usage, 0);
 
@@ -1134,10 +554,13 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __used)
                sym_hist_filter = argv[0];
        }
 
-       if (!sym_hist_filter)
-               usage_with_options(annotate_usage, options);
-
        setup_pager();
 
+       if (field_sep && *field_sep == '.') {
+               fputs("'.' is the only non valid --field-separator argument\n",
+                               stderr);
+               exit(129);
+       }
+
        return __cmd_annotate();
 }
diff --git a/tools/perf/builtin-bench.c b/tools/perf/builtin-bench.c
new file mode 100644 (file)
index 0000000..e043eb8
--- /dev/null
@@ -0,0 +1,196 @@
+/*
+ *
+ * builtin-bench.c
+ *
+ * General benchmarking subsystem provided by perf
+ *
+ * Copyright (C) 2009, Hitoshi Mitake <mitake@dcl.info.waseda.ac.jp>
+ *
+ */
+
+/*
+ *
+ * Available subsystem list:
+ *  sched ... scheduler and IPC mechanism
+ *  mem   ... memory access performance
+ *
+ */
+
+#include "perf.h"
+#include "util/util.h"
+#include "util/parse-options.h"
+#include "builtin.h"
+#include "bench/bench.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+struct bench_suite {
+       const char *name;
+       const char *summary;
+       int (*fn)(int, const char **, const char *);
+};
+
+static struct bench_suite sched_suites[] = {
+       { "messaging",
+         "Benchmark for scheduler and IPC mechanisms",
+         bench_sched_messaging },
+       { "pipe",
+         "Flood of communication over pipe() between two processes",
+         bench_sched_pipe      },
+       { NULL,
+         NULL,
+         NULL                  }
+};
+
+static struct bench_suite mem_suites[] = {
+       { "memcpy",
+         "Simple memory copy in various ways",
+         bench_mem_memcpy },
+       { NULL,
+         NULL,
+         NULL             }
+};
+
+struct bench_subsys {
+       const char *name;
+       const char *summary;
+       struct bench_suite *suites;
+};
+
+static struct bench_subsys subsystems[] = {
+       { "sched",
+         "scheduler and IPC mechanism",
+         sched_suites },
+       { "mem",
+         "memory access performance",
+         mem_suites },
+       { NULL,
+         NULL,
+         NULL       }
+};
+
+static void dump_suites(int subsys_index)
+{
+       int i;
+
+       printf("List of available suites for %s...\n\n",
+              subsystems[subsys_index].name);
+
+       for (i = 0; subsystems[subsys_index].suites[i].name; i++)
+               printf("\t%s: %s\n",
+                      subsystems[subsys_index].suites[i].name,
+                      subsystems[subsys_index].suites[i].summary);
+
+       printf("\n");
+       return;
+}
+
+static char *bench_format_str;
+int bench_format = BENCH_FORMAT_DEFAULT;
+
+static const struct option bench_options[] = {
+       OPT_STRING('f', "format", &bench_format_str, "default",
+                   "Specify format style"),
+       OPT_END()
+};
+
+static const char * const bench_usage[] = {
+       "perf bench [<common options>] <subsystem> <suite> [<options>]",
+       NULL
+};
+
+static void print_usage(void)
+{
+       int i;
+
+       printf("Usage: \n");
+       for (i = 0; bench_usage[i]; i++)
+               printf("\t%s\n", bench_usage[i]);
+       printf("\n");
+
+       printf("List of available subsystems...\n\n");
+
+       for (i = 0; subsystems[i].name; i++)
+               printf("\t%s: %s\n",
+                      subsystems[i].name, subsystems[i].summary);
+       printf("\n");
+}
+
+static int bench_str2int(char *str)
+{
+       if (!str)
+               return BENCH_FORMAT_DEFAULT;
+
+       if (!strcmp(str, BENCH_FORMAT_DEFAULT_STR))
+               return BENCH_FORMAT_DEFAULT;
+       else if (!strcmp(str, BENCH_FORMAT_SIMPLE_STR))
+               return BENCH_FORMAT_SIMPLE;
+
+       return BENCH_FORMAT_UNKNOWN;
+}
+
+int cmd_bench(int argc, const char **argv, const char *prefix __used)
+{
+       int i, j, status = 0;
+
+       if (argc < 2) {
+               /* No subsystem specified. */
+               print_usage();
+               goto end;
+       }
+
+       argc = parse_options(argc, argv, bench_options, bench_usage,
+                            PARSE_OPT_STOP_AT_NON_OPTION);
+
+       bench_format = bench_str2int(bench_format_str);
+       if (bench_format == BENCH_FORMAT_UNKNOWN) {
+               printf("Unknown format descriptor:%s\n", bench_format_str);
+               goto end;
+       }
+
+       if (argc < 1) {
+               print_usage();
+               goto end;
+       }
+
+       for (i = 0; subsystems[i].name; i++) {
+               if (strcmp(subsystems[i].name, argv[0]))
+                       continue;
+
+               if (argc < 2) {
+                       /* No suite specified. */
+                       dump_suites(i);
+                       goto end;
+               }
+
+               for (j = 0; subsystems[i].suites[j].name; j++) {
+                       if (strcmp(subsystems[i].suites[j].name, argv[1]))
+                               continue;
+
+                       if (bench_format == BENCH_FORMAT_DEFAULT)
+                               printf("# Running %s/%s benchmark...\n",
+                                      subsystems[i].name,
+                                      subsystems[i].suites[j].name);
+                       status = subsystems[i].suites[j].fn(argc - 1,
+                                                           argv + 1, prefix);
+                       goto end;
+               }
+
+               if (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) {
+                       dump_suites(i);
+                       goto end;
+               }
+
+               printf("Unknown suite:%s for %s\n", argv[1], argv[0]);
+               status = 1;
+               goto end;
+       }
+
+       printf("Unknown subsystem:%s\n", argv[0]);
+       status = 1;
+
+end:
+       return status;
+}
diff --git a/tools/perf/builtin-buildid-list.c b/tools/perf/builtin-buildid-list.c
new file mode 100644 (file)
index 0000000..7dee9d1
--- /dev/null
@@ -0,0 +1,116 @@
+/*
+ * builtin-buildid-list.c
+ *
+ * Builtin buildid-list command: list buildids in perf.data
+ *
+ * Copyright (C) 2009, Red Hat Inc.
+ * Copyright (C) 2009, Arnaldo Carvalho de Melo <acme@redhat.com>
+ */
+#include "builtin.h"
+#include "perf.h"
+#include "util/cache.h"
+#include "util/data_map.h"
+#include "util/debug.h"
+#include "util/header.h"
+#include "util/parse-options.h"
+#include "util/symbol.h"
+
+static char const *input_name = "perf.data";
+static int force;
+
+static const char *const buildid_list_usage[] = {
+       "perf report [<options>]",
+       NULL
+};
+
+static const struct option options[] = {
+       OPT_STRING('i', "input", &input_name, "file",
+                   "input file name"),
+       OPT_BOOLEAN('f', "force", &force, "don't complain, do it"),
+       OPT_BOOLEAN('v', "verbose", &verbose,
+                   "be more verbose"),
+       OPT_END()
+};
+
+static int perf_file_section__process_buildids(struct perf_file_section *self,
+                                              int feat, int fd)
+{
+       if (feat != HEADER_BUILD_ID)
+               return 0;
+
+       if (lseek(fd, self->offset, SEEK_SET) < 0) {
+               pr_warning("Failed to lseek to %Ld offset for buildids!\n",
+                          self->offset);
+               return -1;
+       }
+
+       if (perf_header__read_build_ids(fd, self->offset, self->size)) {
+               pr_warning("Failed to read buildids!\n");
+               return -1;
+       }
+
+       return 0;
+}
+
+static int __cmd_buildid_list(void)
+{
+       int err = -1;
+       struct perf_header *header;
+       struct perf_file_header f_header;
+       struct stat input_stat;
+       int input = open(input_name, O_RDONLY);
+
+       if (input < 0) {
+               pr_err("failed to open file: %s", input_name);
+               if (!strcmp(input_name, "perf.data"))
+                       pr_err("  (try 'perf record' first)");
+               pr_err("\n");
+               goto out;
+       }
+
+       err = fstat(input, &input_stat);
+       if (err < 0) {
+               perror("failed to stat file");
+               goto out_close;
+       }
+
+       if (!force && input_stat.st_uid && (input_stat.st_uid != geteuid())) {
+               pr_err("file %s not owned by current user or root\n",
+                      input_name);
+               goto out_close;
+       }
+
+       if (!input_stat.st_size) {
+               pr_info("zero-sized file, nothing to do!\n");
+               goto out_close;
+       }
+
+       err = -1;
+       header = perf_header__new();
+       if (header == NULL)
+               goto out_close;
+
+       if (perf_file_header__read(&f_header, header, input) < 0) {
+               pr_warning("incompatible file format");
+               goto out_close;
+       }
+
+       err = perf_header__process_sections(header, input,
+                                        perf_file_section__process_buildids);
+
+       if (err < 0)
+               goto out_close;
+
+       dsos__fprintf_buildid(stdout);
+out_close:
+       close(input);
+out:
+       return err;
+}
+
+int cmd_buildid_list(int argc, const char **argv, const char *prefix __used)
+{
+       argc = parse_options(argc, argv, options, buildid_list_usage, 0);
+       setup_pager();
+       return __cmd_buildid_list();
+}
index 4fb8734..9f810b1 100644 (file)
@@ -61,8 +61,7 @@ static const char *get_man_viewer_info(const char *name)
 {
        struct man_viewer_info_list *viewer;
 
-       for (viewer = man_viewer_info_list; viewer; viewer = viewer->next)
-       {
+       for (viewer = man_viewer_info_list; viewer; viewer = viewer->next) {
                if (!strcasecmp(name, viewer->name))
                        return viewer->info;
        }
@@ -115,7 +114,7 @@ static int check_emacsclient_version(void)
        return 0;
 }
 
-static void exec_woman_emacs(const charpath, const char *page)
+static void exec_woman_emacs(const char *path, const char *page)
 {
        if (!check_emacsclient_version()) {
                /* This works only with emacsclient version >= 22. */
@@ -129,7 +128,7 @@ static void exec_woman_emacs(const char* path, const char *page)
        }
 }
 
-static void exec_man_konqueror(const charpath, const char *page)
+static void exec_man_konqueror(const char *path, const char *page)
 {
        const char *display = getenv("DISPLAY");
        if (display && *display) {
@@ -157,7 +156,7 @@ static void exec_man_konqueror(const char* path, const char *page)
        }
 }
 
-static void exec_man_man(const charpath, const char *page)
+static void exec_man_man(const char *path, const char *page)
 {
        if (!path)
                path = "man";
@@ -180,7 +179,7 @@ static void add_man_viewer(const char *name)
 
        while (*p)
                p = &((*p)->next);
-       *p = calloc(1, (sizeof(**p) + len + 1));
+       *p = zalloc(sizeof(**p) + len + 1);
        strncpy((*p)->name, name, len);
 }
 
@@ -195,7 +194,7 @@ static void do_add_man_viewer_info(const char *name,
                                   size_t len,
                                   const char *value)
 {
-       struct man_viewer_info_list *new = calloc(1, sizeof(*new) + len + 1);
+       struct man_viewer_info_list *new = zalloc(sizeof(*new) + len + 1);
 
        strncpy(new->name, name, len);
        new->info = strdup(value);
@@ -364,9 +363,8 @@ static void show_man_page(const char *perf_cmd)
 
        setup_man_path();
        for (viewer = man_viewer_list; viewer; viewer = viewer->next)
-       {
                exec_viewer(viewer->name, page); /* will return when unable */
-       }
+
        if (fallback)
                exec_viewer(fallback, page);
        exec_viewer("man", page);
diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c
new file mode 100644 (file)
index 0000000..047fef7
--- /dev/null
@@ -0,0 +1,807 @@
+#include "builtin.h"
+#include "perf.h"
+
+#include "util/util.h"
+#include "util/cache.h"
+#include "util/symbol.h"
+#include "util/thread.h"
+#include "util/header.h"
+
+#include "util/parse-options.h"
+#include "util/trace-event.h"
+
+#include "util/debug.h"
+#include "util/data_map.h"
+
+#include <linux/rbtree.h>
+
+struct alloc_stat;
+typedef int (*sort_fn_t)(struct alloc_stat *, struct alloc_stat *);
+
+static char const              *input_name = "perf.data";
+
+static struct perf_header      *header;
+static u64                     sample_type;
+
+static int                     alloc_flag;
+static int                     caller_flag;
+
+static int                     alloc_lines = -1;
+static int                     caller_lines = -1;
+
+static bool                    raw_ip;
+
+static char                    default_sort_order[] = "frag,hit,bytes";
+
+static int                     *cpunode_map;
+static int                     max_cpu_num;
+
+struct alloc_stat {
+       u64     call_site;
+       u64     ptr;
+       u64     bytes_req;
+       u64     bytes_alloc;
+       u32     hit;
+       u32     pingpong;
+
+       short   alloc_cpu;
+
+       struct rb_node node;
+};
+
+static struct rb_root root_alloc_stat;
+static struct rb_root root_alloc_sorted;
+static struct rb_root root_caller_stat;
+static struct rb_root root_caller_sorted;
+
+static unsigned long total_requested, total_allocated;
+static unsigned long nr_allocs, nr_cross_allocs;
+
+struct raw_event_sample {
+       u32 size;
+       char data[0];
+};
+
+#define PATH_SYS_NODE  "/sys/devices/system/node"
+
+static void init_cpunode_map(void)
+{
+       FILE *fp;
+       int i;
+
+       fp = fopen("/sys/devices/system/cpu/kernel_max", "r");
+       if (!fp) {
+               max_cpu_num = 4096;
+               return;
+       }
+
+       if (fscanf(fp, "%d", &max_cpu_num) < 1)
+               die("Failed to read 'kernel_max' from sysfs");
+       max_cpu_num++;
+
+       cpunode_map = calloc(max_cpu_num, sizeof(int));
+       if (!cpunode_map)
+               die("calloc");
+       for (i = 0; i < max_cpu_num; i++)
+               cpunode_map[i] = -1;
+       fclose(fp);
+}
+
+static void setup_cpunode_map(void)
+{
+       struct dirent *dent1, *dent2;
+       DIR *dir1, *dir2;
+       unsigned int cpu, mem;
+       char buf[PATH_MAX];
+
+       init_cpunode_map();
+
+       dir1 = opendir(PATH_SYS_NODE);
+       if (!dir1)
+               return;
+
+       while (true) {
+               dent1 = readdir(dir1);
+               if (!dent1)
+                       break;
+
+               if (sscanf(dent1->d_name, "node%u", &mem) < 1)
+                       continue;
+
+               snprintf(buf, PATH_MAX, "%s/%s", PATH_SYS_NODE, dent1->d_name);
+               dir2 = opendir(buf);
+               if (!dir2)
+                       continue;
+               while (true) {
+                       dent2 = readdir(dir2);
+                       if (!dent2)
+                               break;
+                       if (sscanf(dent2->d_name, "cpu%u", &cpu) < 1)
+                               continue;
+                       cpunode_map[cpu] = mem;
+               }
+       }
+}
+
+static void insert_alloc_stat(unsigned long call_site, unsigned long ptr,
+                             int bytes_req, int bytes_alloc, int cpu)
+{
+       struct rb_node **node = &root_alloc_stat.rb_node;
+       struct rb_node *parent = NULL;
+       struct alloc_stat *data = NULL;
+
+       while (*node) {
+               parent = *node;
+               data = rb_entry(*node, struct alloc_stat, node);
+
+               if (ptr > data->ptr)
+                       node = &(*node)->rb_right;
+               else if (ptr < data->ptr)
+                       node = &(*node)->rb_left;
+               else
+                       break;
+       }
+
+       if (data && data->ptr == ptr) {
+               data->hit++;
+               data->bytes_req += bytes_req;
+               data->bytes_alloc += bytes_req;
+       } else {
+               data = malloc(sizeof(*data));
+               if (!data)
+                       die("malloc");
+               data->ptr = ptr;
+               data->pingpong = 0;
+               data->hit = 1;
+               data->bytes_req = bytes_req;
+               data->bytes_alloc = bytes_alloc;
+
+               rb_link_node(&data->node, parent, node);
+               rb_insert_color(&data->node, &root_alloc_stat);
+       }
+       data->call_site = call_site;
+       data->alloc_cpu = cpu;
+}
+
+static void insert_caller_stat(unsigned long call_site,
+                             int bytes_req, int bytes_alloc)
+{
+       struct rb_node **node = &root_caller_stat.rb_node;
+       struct rb_node *parent = NULL;
+       struct alloc_stat *data = NULL;
+
+       while (*node) {
+               parent = *node;
+               data = rb_entry(*node, struct alloc_stat, node);
+
+               if (call_site > data->call_site)
+                       node = &(*node)->rb_right;
+               else if (call_site < data->call_site)
+                       node = &(*node)->rb_left;
+               else
+                       break;
+       }
+
+       if (data && data->call_site == call_site) {
+               data->hit++;
+               data->bytes_req += bytes_req;
+               data->bytes_alloc += bytes_req;
+       } else {
+               data = malloc(sizeof(*data));
+               if (!data)
+                       die("malloc");
+               data->call_site = call_site;
+               data->pingpong = 0;
+               data->hit = 1;
+               data->bytes_req = bytes_req;
+               data->bytes_alloc = bytes_alloc;
+
+               rb_link_node(&data->node, parent, node);
+               rb_insert_color(&data->node, &root_caller_stat);
+       }
+}
+
+static void process_alloc_event(struct raw_event_sample *raw,
+                               struct event *event,
+                               int cpu,
+                               u64 timestamp __used,
+                               struct thread *thread __used,
+                               int node)
+{
+       unsigned long call_site;
+       unsigned long ptr;
+       int bytes_req;
+       int bytes_alloc;
+       int node1, node2;
+
+       ptr = raw_field_value(event, "ptr", raw->data);
+       call_site = raw_field_value(event, "call_site", raw->data);
+       bytes_req = raw_field_value(event, "bytes_req", raw->data);
+       bytes_alloc = raw_field_value(event, "bytes_alloc", raw->data);
+
+       insert_alloc_stat(call_site, ptr, bytes_req, bytes_alloc, cpu);
+       insert_caller_stat(call_site, bytes_req, bytes_alloc);
+
+       total_requested += bytes_req;
+       total_allocated += bytes_alloc;
+
+       if (node) {
+               node1 = cpunode_map[cpu];
+               node2 = raw_field_value(event, "node", raw->data);
+               if (node1 != node2)
+                       nr_cross_allocs++;
+       }
+       nr_allocs++;
+}
+
+static int ptr_cmp(struct alloc_stat *, struct alloc_stat *);
+static int callsite_cmp(struct alloc_stat *, struct alloc_stat *);
+
+static struct alloc_stat *search_alloc_stat(unsigned long ptr,
+                                           unsigned long call_site,
+                                           struct rb_root *root,
+                                           sort_fn_t sort_fn)
+{
+       struct rb_node *node = root->rb_node;
+       struct alloc_stat key = { .ptr = ptr, .call_site = call_site };
+
+       while (node) {
+               struct alloc_stat *data;
+               int cmp;
+
+               data = rb_entry(node, struct alloc_stat, node);
+
+               cmp = sort_fn(&key, data);
+               if (cmp < 0)
+                       node = node->rb_left;
+               else if (cmp > 0)
+                       node = node->rb_right;
+               else
+                       return data;
+       }
+       return NULL;
+}
+
+static void process_free_event(struct raw_event_sample *raw,
+                              struct event *event,
+                              int cpu,
+                              u64 timestamp __used,
+                              struct thread *thread __used)
+{
+       unsigned long ptr;
+       struct alloc_stat *s_alloc, *s_caller;
+
+       ptr = raw_field_value(event, "ptr", raw->data);
+
+       s_alloc = search_alloc_stat(ptr, 0, &root_alloc_stat, ptr_cmp);
+       if (!s_alloc)
+               return;
+
+       if (cpu != s_alloc->alloc_cpu) {
+               s_alloc->pingpong++;
+
+               s_caller = search_alloc_stat(0, s_alloc->call_site,
+                                            &root_caller_stat, callsite_cmp);
+               assert(s_caller);
+               s_caller->pingpong++;
+       }
+       s_alloc->alloc_cpu = -1;
+}
+
+static void
+process_raw_event(event_t *raw_event __used, void *more_data,
+                 int cpu, u64 timestamp, struct thread *thread)
+{
+       struct raw_event_sample *raw = more_data;
+       struct event *event;
+       int type;
+
+       type = trace_parse_common_type(raw->data);
+       event = trace_find_event(type);
+
+       if (!strcmp(event->name, "kmalloc") ||
+           !strcmp(event->name, "kmem_cache_alloc")) {
+               process_alloc_event(raw, event, cpu, timestamp, thread, 0);
+               return;
+       }
+
+       if (!strcmp(event->name, "kmalloc_node") ||
+           !strcmp(event->name, "kmem_cache_alloc_node")) {
+               process_alloc_event(raw, event, cpu, timestamp, thread, 1);
+               return;
+       }
+
+       if (!strcmp(event->name, "kfree") ||
+           !strcmp(event->name, "kmem_cache_free")) {
+               process_free_event(raw, event, cpu, timestamp, thread);
+               return;
+       }
+}
+
+static int process_sample_event(event_t *event)
+{
+       u64 ip = event->ip.ip;
+       u64 timestamp = -1;
+       u32 cpu = -1;
+       u64 period = 1;
+       void *more_data = event->ip.__more_data;
+       struct thread *thread = threads__findnew(event->ip.pid);
+
+       if (sample_type & PERF_SAMPLE_TIME) {
+               timestamp = *(u64 *)more_data;
+               more_data += sizeof(u64);
+       }
+
+       if (sample_type & PERF_SAMPLE_CPU) {
+               cpu = *(u32 *)more_data;
+               more_data += sizeof(u32);
+               more_data += sizeof(u32); /* reserved */
+       }
+
+       if (sample_type & PERF_SAMPLE_PERIOD) {
+               period = *(u64 *)more_data;
+               more_data += sizeof(u64);
+       }
+
+       dump_printf("(IP, %d): %d/%d: %p period: %Ld\n",
+               event->header.misc,
+               event->ip.pid, event->ip.tid,
+               (void *)(long)ip,
+               (long long)period);
+
+       if (thread == NULL) {
+               pr_debug("problem processing %d event, skipping it.\n",
+                        event->header.type);
+               return -1;
+       }
+
+       dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid);
+
+       process_raw_event(event, more_data, cpu, timestamp, thread);
+
+       return 0;
+}
+
+static int sample_type_check(u64 type)
+{
+       sample_type = type;
+
+       if (!(sample_type & PERF_SAMPLE_RAW)) {
+               fprintf(stderr,
+                       "No trace sample to read. Did you call perf record "
+                       "without -R?");
+               return -1;
+       }
+
+       return 0;
+}
+
+static struct perf_file_handler file_handler = {
+       .process_sample_event   = process_sample_event,
+       .process_comm_event     = event__process_comm,
+       .sample_type_check      = sample_type_check,
+};
+
+static int read_events(void)
+{
+       register_idle_thread();
+       register_perf_file_handler(&file_handler);
+
+       return mmap_dispatch_perf_file(&header, input_name, 0, 0,
+                                      &event__cwdlen, &event__cwd);
+}
+
+static double fragmentation(unsigned long n_req, unsigned long n_alloc)
+{
+       if (n_alloc == 0)
+               return 0.0;
+       else
+               return 100.0 - (100.0 * n_req / n_alloc);
+}
+
+static void __print_result(struct rb_root *root, int n_lines, int is_caller)
+{
+       struct rb_node *next;
+
+       printf("%.102s\n", graph_dotted_line);
+       printf(" %-34s |",  is_caller ? "Callsite": "Alloc Ptr");
+       printf(" Total_alloc/Per | Total_req/Per   | Hit   | Ping-pong | Frag\n");
+       printf("%.102s\n", graph_dotted_line);
+
+       next = rb_first(root);
+
+       while (next && n_lines--) {
+               struct alloc_stat *data = rb_entry(next, struct alloc_stat,
+                                                  node);
+               struct symbol *sym = NULL;
+               char buf[BUFSIZ];
+               u64 addr;
+
+               if (is_caller) {
+                       addr = data->call_site;
+                       if (!raw_ip)
+                               sym = thread__find_function(kthread, addr, NULL);
+               } else
+                       addr = data->ptr;
+
+               if (sym != NULL)
+                       snprintf(buf, sizeof(buf), "%s+%Lx", sym->name,
+                                addr - sym->start);
+               else
+                       snprintf(buf, sizeof(buf), "%#Lx", addr);
+               printf(" %-34s |", buf);
+
+               printf(" %9llu/%-5lu | %9llu/%-5lu | %6lu | %8lu | %6.3f%%\n",
+                      (unsigned long long)data->bytes_alloc,
+                      (unsigned long)data->bytes_alloc / data->hit,
+                      (unsigned long long)data->bytes_req,
+                      (unsigned long)data->bytes_req / data->hit,
+                      (unsigned long)data->hit,
+                      (unsigned long)data->pingpong,
+                      fragmentation(data->bytes_req, data->bytes_alloc));
+
+               next = rb_next(next);
+       }
+
+       if (n_lines == -1)
+               printf(" ...                                | ...             | ...             | ...    | ...      | ...   \n");
+
+       printf("%.102s\n", graph_dotted_line);
+}
+
+static void print_summary(void)
+{
+       printf("\nSUMMARY\n=======\n");
+       printf("Total bytes requested: %lu\n", total_requested);
+       printf("Total bytes allocated: %lu\n", total_allocated);
+       printf("Total bytes wasted on internal fragmentation: %lu\n",
+              total_allocated - total_requested);
+       printf("Internal fragmentation: %f%%\n",
+              fragmentation(total_requested, total_allocated));
+       printf("Cross CPU allocations: %lu/%lu\n", nr_cross_allocs, nr_allocs);
+}
+
+static void print_result(void)
+{
+       if (caller_flag)
+               __print_result(&root_caller_sorted, caller_lines, 1);
+       if (alloc_flag)
+               __print_result(&root_alloc_sorted, alloc_lines, 0);
+       print_summary();
+}
+
+struct sort_dimension {
+       const char              name[20];
+       sort_fn_t               cmp;
+       struct list_head        list;
+};
+
+static LIST_HEAD(caller_sort);
+static LIST_HEAD(alloc_sort);
+
+static void sort_insert(struct rb_root *root, struct alloc_stat *data,
+                       struct list_head *sort_list)
+{
+       struct rb_node **new = &(root->rb_node);
+       struct rb_node *parent = NULL;
+       struct sort_dimension *sort;
+
+       while (*new) {
+               struct alloc_stat *this;
+               int cmp = 0;
+
+               this = rb_entry(*new, struct alloc_stat, node);
+               parent = *new;
+
+               list_for_each_entry(sort, sort_list, list) {
+                       cmp = sort->cmp(data, this);
+                       if (cmp)
+                               break;
+               }
+
+               if (cmp > 0)
+                       new = &((*new)->rb_left);
+               else
+                       new = &((*new)->rb_right);
+       }
+
+       rb_link_node(&data->node, parent, new);
+       rb_insert_color(&data->node, root);
+}
+
+static void __sort_result(struct rb_root *root, struct rb_root *root_sorted,
+                         struct list_head *sort_list)
+{
+       struct rb_node *node;
+       struct alloc_stat *data;
+
+       for (;;) {
+               node = rb_first(root);
+               if (!node)
+                       break;
+
+               rb_erase(node, root);
+               data = rb_entry(node, struct alloc_stat, node);
+               sort_insert(root_sorted, data, sort_list);
+       }
+}
+
+static void sort_result(void)
+{
+       __sort_result(&root_alloc_stat, &root_alloc_sorted, &alloc_sort);
+       __sort_result(&root_caller_stat, &root_caller_sorted, &caller_sort);
+}
+
+static int __cmd_kmem(void)
+{
+       setup_pager();
+       read_events();
+       sort_result();
+       print_result();
+
+       return 0;
+}
+
+static const char * const kmem_usage[] = {
+       "perf kmem [<options>] {record}",
+       NULL
+};
+
+static int ptr_cmp(struct alloc_stat *l, struct alloc_stat *r)
+{
+       if (l->ptr < r->ptr)
+               return -1;
+       else if (l->ptr > r->ptr)
+               return 1;
+       return 0;
+}
+
+static struct sort_dimension ptr_sort_dimension = {
+       .name   = "ptr",
+       .cmp    = ptr_cmp,
+};
+
+static int callsite_cmp(struct alloc_stat *l, struct alloc_stat *r)
+{
+       if (l->call_site < r->call_site)
+               return -1;
+       else if (l->call_site > r->call_site)
+               return 1;
+       return 0;
+}
+
+static struct sort_dimension callsite_sort_dimension = {
+       .name   = "callsite",
+       .cmp    = callsite_cmp,
+};
+
+static int hit_cmp(struct alloc_stat *l, struct alloc_stat *r)
+{
+       if (l->hit < r->hit)
+               return -1;
+       else if (l->hit > r->hit)
+               return 1;
+       return 0;
+}
+
+static struct sort_dimension hit_sort_dimension = {
+       .name   = "hit",
+       .cmp    = hit_cmp,
+};
+
+static int bytes_cmp(struct alloc_stat *l, struct alloc_stat *r)
+{
+       if (l->bytes_alloc < r->bytes_alloc)
+               return -1;
+       else if (l->bytes_alloc > r->bytes_alloc)
+               return 1;
+       return 0;
+}
+
+static struct sort_dimension bytes_sort_dimension = {
+       .name   = "bytes",
+       .cmp    = bytes_cmp,
+};
+
+static int frag_cmp(struct alloc_stat *l, struct alloc_stat *r)
+{
+       double x, y;
+
+       x = fragmentation(l->bytes_req, l->bytes_alloc);
+       y = fragmentation(r->bytes_req, r->bytes_alloc);
+
+       if (x < y)
+               return -1;
+       else if (x > y)
+               return 1;
+       return 0;
+}
+
+static struct sort_dimension frag_sort_dimension = {
+       .name   = "frag",
+       .cmp    = frag_cmp,
+};
+
+static int pingpong_cmp(struct alloc_stat *l, struct alloc_stat *r)
+{
+       if (l->pingpong < r->pingpong)
+               return -1;
+       else if (l->pingpong > r->pingpong)
+               return 1;
+       return 0;
+}
+
+static struct sort_dimension pingpong_sort_dimension = {
+       .name   = "pingpong",
+       .cmp    = pingpong_cmp,
+};
+
+static struct sort_dimension *avail_sorts[] = {
+       &ptr_sort_dimension,
+       &callsite_sort_dimension,
+       &hit_sort_dimension,
+       &bytes_sort_dimension,
+       &frag_sort_dimension,
+       &pingpong_sort_dimension,
+};
+
+#define NUM_AVAIL_SORTS        \
+       (int)(sizeof(avail_sorts) / sizeof(struct sort_dimension *))
+
+static int sort_dimension__add(const char *tok, struct list_head *list)
+{
+       struct sort_dimension *sort;
+       int i;
+
+       for (i = 0; i < NUM_AVAIL_SORTS; i++) {
+               if (!strcmp(avail_sorts[i]->name, tok)) {
+                       sort = malloc(sizeof(*sort));
+                       if (!sort)
+                               die("malloc");
+                       memcpy(sort, avail_sorts[i], sizeof(*sort));
+                       list_add_tail(&sort->list, list);
+                       return 0;
+               }
+       }
+
+       return -1;
+}
+
+static int setup_sorting(struct list_head *sort_list, const char *arg)
+{
+       char *tok;
+       char *str = strdup(arg);
+
+       if (!str)
+               die("strdup");
+
+       while (true) {
+               tok = strsep(&str, ",");
+               if (!tok)
+                       break;
+               if (sort_dimension__add(tok, sort_list) < 0) {
+                       error("Unknown --sort key: '%s'", tok);
+                       return -1;
+               }
+       }
+
+       free(str);
+       return 0;
+}
+
+static int parse_sort_opt(const struct option *opt __used,
+                         const char *arg, int unset __used)
+{
+       if (!arg)
+               return -1;
+
+       if (caller_flag > alloc_flag)
+               return setup_sorting(&caller_sort, arg);
+       else
+               return setup_sorting(&alloc_sort, arg);
+
+       return 0;
+}
+
+static int parse_stat_opt(const struct option *opt __used,
+                         const char *arg, int unset __used)
+{
+       if (!arg)
+               return -1;
+
+       if (strcmp(arg, "alloc") == 0)
+               alloc_flag = (caller_flag + 1);
+       else if (strcmp(arg, "caller") == 0)
+               caller_flag = (alloc_flag + 1);
+       else
+               return -1;
+       return 0;
+}
+
+static int parse_line_opt(const struct option *opt __used,
+                         const char *arg, int unset __used)
+{
+       int lines;
+
+       if (!arg)
+               return -1;
+
+       lines = strtoul(arg, NULL, 10);
+
+       if (caller_flag > alloc_flag)
+               caller_lines = lines;
+       else
+               alloc_lines = lines;
+
+       return 0;
+}
+
+static const struct option kmem_options[] = {
+       OPT_STRING('i', "input", &input_name, "file",
+                  "input file name"),
+       OPT_CALLBACK(0, "stat", NULL, "<alloc>|<caller>",
+                    "stat selector, Pass 'alloc' or 'caller'.",
+                    parse_stat_opt),
+       OPT_CALLBACK('s', "sort", NULL, "key[,key2...]",
+                    "sort by keys: ptr, call_site, bytes, hit, pingpong, frag",
+                    parse_sort_opt),
+       OPT_CALLBACK('l', "line", NULL, "num",
+                    "show n lins",
+                    parse_line_opt),
+       OPT_BOOLEAN(0, "raw-ip", &raw_ip, "show raw ip instead of symbol"),
+       OPT_END()
+};
+
+static const char *record_args[] = {
+       "record",
+       "-a",
+       "-R",
+       "-M",
+       "-f",
+       "-c", "1",
+       "-e", "kmem:kmalloc",
+       "-e", "kmem:kmalloc_node",
+       "-e", "kmem:kfree",
+       "-e", "kmem:kmem_cache_alloc",
+       "-e", "kmem:kmem_cache_alloc_node",
+       "-e", "kmem:kmem_cache_free",
+};
+
+static int __cmd_record(int argc, const char **argv)
+{
+       unsigned int rec_argc, i, j;
+       const char **rec_argv;
+
+       rec_argc = ARRAY_SIZE(record_args) + argc - 1;
+       rec_argv = calloc(rec_argc + 1, sizeof(char *));
+
+       for (i = 0; i < ARRAY_SIZE(record_args); i++)
+               rec_argv[i] = strdup(record_args[i]);
+
+       for (j = 1; j < (unsigned int)argc; j++, i++)
+               rec_argv[i] = argv[j];
+
+       return cmd_record(i, rec_argv, NULL);
+}
+
+int cmd_kmem(int argc, const char **argv, const char *prefix __used)
+{
+       symbol__init(0);
+
+       argc = parse_options(argc, argv, kmem_options, kmem_usage, 0);
+
+       if (argc && !strncmp(argv[0], "rec", 3))
+               return __cmd_record(argc, argv);
+       else if (argc)
+               usage_with_options(kmem_usage, kmem_options);
+
+       if (list_empty(&caller_sort))
+               setup_sorting(&caller_sort, default_sort_order);
+       if (list_empty(&alloc_sort))
+               setup_sorting(&alloc_sort, default_sort_order);
+
+       setup_cpunode_map();
+
+       return __cmd_kmem();
+}
+
diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c
new file mode 100644 (file)
index 0000000..a58e11b
--- /dev/null
@@ -0,0 +1,242 @@
+/*
+ * builtin-probe.c
+ *
+ * Builtin probe command: Set up probe events by C expression
+ *
+ * Written by Masami Hiramatsu <mhiramat@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ */
+#define _GNU_SOURCE
+#include <sys/utsname.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+
+#undef _GNU_SOURCE
+#include "perf.h"
+#include "builtin.h"
+#include "util/util.h"
+#include "util/event.h"
+#include "util/debug.h"
+#include "util/parse-options.h"
+#include "util/parse-events.h" /* For debugfs_path */
+#include "util/probe-finder.h"
+#include "util/probe-event.h"
+
+/* Default vmlinux search paths */
+#define NR_SEARCH_PATH 3
+const char *default_search_path[NR_SEARCH_PATH] = {
+"/lib/modules/%s/build/vmlinux",               /* Custom build kernel */
+"/usr/lib/debug/lib/modules/%s/vmlinux",       /* Red Hat debuginfo */
+"/boot/vmlinux-debug-%s",                      /* Ubuntu */
+};
+
+#define MAX_PATH_LEN 256
+#define MAX_PROBES 128
+
+/* Session management structure */
+static struct {
+       char *vmlinux;
+       char *release;
+       int need_dwarf;
+       int nr_probe;
+       struct probe_point probes[MAX_PROBES];
+} session;
+
+static bool listing;
+
+/* Parse an event definition. Note that any error must die. */
+static void parse_probe_event(const char *str)
+{
+       struct probe_point *pp = &session.probes[session.nr_probe];
+
+       pr_debug("probe-definition(%d): %s\n", session.nr_probe, str);
+       if (++session.nr_probe == MAX_PROBES)
+               die("Too many probes (> %d) are specified.", MAX_PROBES);
+
+       /* Parse perf-probe event into probe_point */
+       session.need_dwarf = parse_perf_probe_event(str, pp);
+
+       pr_debug("%d arguments\n", pp->nr_args);
+}
+
+static int opt_add_probe_event(const struct option *opt __used,
+                             const char *str, int unset __used)
+{
+       if (str)
+               parse_probe_event(str);
+       return 0;
+}
+
+#ifndef NO_LIBDWARF
+static int open_default_vmlinux(void)
+{
+       struct utsname uts;
+       char fname[MAX_PATH_LEN];
+       int fd, ret, i;
+
+       ret = uname(&uts);
+       if (ret) {
+               pr_debug("uname() failed.\n");
+               return -errno;
+       }
+       session.release = uts.release;
+       for (i = 0; i < NR_SEARCH_PATH; i++) {
+               ret = snprintf(fname, MAX_PATH_LEN,
+                              default_search_path[i], session.release);
+               if (ret >= MAX_PATH_LEN || ret < 0) {
+                       pr_debug("Filename(%d,%s) is too long.\n", i,
+                               uts.release);
+                       errno = E2BIG;
+                       return -E2BIG;
+               }
+               pr_debug("try to open %s\n", fname);
+               fd = open(fname, O_RDONLY);
+               if (fd >= 0)
+                       break;
+       }
+       return fd;
+}
+#endif
+
+static const char * const probe_usage[] = {
+       "perf probe [<options>] 'PROBEDEF' ['PROBEDEF' ...]",
+       "perf probe [<options>] --add 'PROBEDEF' [--add 'PROBEDEF' ...]",
+       "perf probe --list",
+       NULL
+};
+
+static const struct option options[] = {
+       OPT_BOOLEAN('v', "verbose", &verbose,
+                   "be more verbose (show parsed arguments, etc)"),
+#ifndef NO_LIBDWARF
+       OPT_STRING('k', "vmlinux", &session.vmlinux, "file",
+               "vmlinux/module pathname"),
+#endif
+       OPT_BOOLEAN('l', "list", &listing, "list up current probes"),
+       OPT_CALLBACK('a', "add", NULL,
+#ifdef NO_LIBDWARF
+               "FUNC[+OFFS|%return] [ARG ...]",
+#else
+               "FUNC[+OFFS|%return|:RLN][@SRC]|SRC:ALN [ARG ...]",
+#endif
+               "probe point definition, where\n"
+               "\t\tGRP:\tGroup name (optional)\n"
+               "\t\tNAME:\tEvent name\n"
+               "\t\tFUNC:\tFunction name\n"
+               "\t\tOFFS:\tOffset from function entry (in byte)\n"
+               "\t\t%return:\tPut the probe at function return\n"
+#ifdef NO_LIBDWARF
+               "\t\tARG:\tProbe argument (only \n"
+#else
+               "\t\tSRC:\tSource code path\n"
+               "\t\tRLN:\tRelative line number from function entry.\n"
+               "\t\tALN:\tAbsolute line number in file.\n"
+               "\t\tARG:\tProbe argument (local variable name or\n"
+#endif
+               "\t\t\tkprobe-tracer argument format.)\n",
+               opt_add_probe_event),
+       OPT_END()
+};
+
+int cmd_probe(int argc, const char **argv, const char *prefix __used)
+{
+       int i, j, ret;
+#ifndef NO_LIBDWARF
+       int fd;
+#endif
+       struct probe_point *pp;
+
+       argc = parse_options(argc, argv, options, probe_usage,
+                            PARSE_OPT_STOP_AT_NON_OPTION);
+       for (i = 0; i < argc; i++)
+               parse_probe_event(argv[i]);
+
+       if ((session.nr_probe == 0 && !listing) ||
+           (session.nr_probe != 0 && listing))
+               usage_with_options(probe_usage, options);
+
+       if (listing) {
+               show_perf_probe_events();
+               return 0;
+       }
+
+       if (session.need_dwarf)
+#ifdef NO_LIBDWARF
+               die("Debuginfo-analysis is not supported");
+#else  /* !NO_LIBDWARF */
+               pr_debug("Some probes require debuginfo.\n");
+
+       if (session.vmlinux)
+               fd = open(session.vmlinux, O_RDONLY);
+       else
+               fd = open_default_vmlinux();
+       if (fd < 0) {
+               if (session.need_dwarf)
+                       die("Could not open vmlinux/module file.");
+
+               pr_warning("Could not open vmlinux/module file."
+                          " Try to use symbols.\n");
+               goto end_dwarf;
+       }
+
+       /* Searching probe points */
+       for (j = 0; j < session.nr_probe; j++) {
+               pp = &session.probes[j];
+               if (pp->found)
+                       continue;
+
+               lseek(fd, SEEK_SET, 0);
+               ret = find_probepoint(fd, pp);
+               if (ret < 0) {
+                       if (session.need_dwarf)
+                               die("Could not analyze debuginfo.");
+
+                       pr_warning("An error occurred in debuginfo analysis. Try to use symbols.\n");
+                       break;
+               }
+               if (ret == 0)   /* No error but failed to find probe point. */
+                       die("No probe point found.");
+       }
+       close(fd);
+
+end_dwarf:
+#endif /* !NO_LIBDWARF */
+
+       /* Synthesize probes without dwarf */
+       for (j = 0; j < session.nr_probe; j++) {
+               pp = &session.probes[j];
+               if (pp->found)  /* This probe is already found. */
+                       continue;
+
+               ret = synthesize_trace_kprobe_event(pp);
+               if (ret == -E2BIG)
+                       die("probe point definition becomes too long.");
+               else if (ret < 0)
+                       die("Failed to synthesize a probe point.");
+       }
+
+       /* Settng up probe points */
+       add_trace_kprobe_events(session.probes, session.nr_probe);
+       return 0;
+}
+
index a4be453..0e519c6 100644 (file)
 #include "util/header.h"
 #include "util/event.h"
 #include "util/debug.h"
-#include "util/trace-event.h"
+#include "util/symbol.h"
 
 #include <unistd.h>
 #include <sched.h>
 
-#define ALIGN(x, a)            __ALIGN_MASK(x, (typeof(x))(a)-1)
-#define __ALIGN_MASK(x, mask)  (((x)+(mask))&~(mask))
-
 static int                     fd[MAX_NR_CPUS][MAX_COUNTERS];
 
-static long                    default_interval                = 100000;
+static long                    default_interval                =      0;
 
-static int                     nr_cpus                         = 0;
+static int                     nr_cpus                         =      0;
 static unsigned int            page_size;
-static unsigned int            mmap_pages                      = 128;
-static int                     freq                            = 0;
+static unsigned int            mmap_pages                      =    128;
+static int                     freq                            =   1000;
 static int                     output;
 static const char              *output_name                    = "perf.data";
-static int                     group                           = 0;
-static unsigned int            realtime_prio                   = 0;
-static int                     raw_samples                     = 0;
-static int                     system_wide                     = 0;
-static int                     profile_cpu                     = -1;
-static pid_t                   target_pid                      = -1;
-static pid_t                   child_pid                       = -1;
-static int                     inherit                         = 1;
-static int                     force                           = 0;
-static int                     append_file                     = 0;
-static int                     call_graph                      = 0;
-static int                     inherit_stat                    = 0;
-static int                     no_samples                      = 0;
-static int                     sample_address                  = 0;
-static int                     multiplex                       = 0;
-static int                     multiplex_fd                    = -1;
-
-static long                    samples;
+static int                     group                           =      0;
+static unsigned int            realtime_prio                   =      0;
+static int                     raw_samples                     =      0;
+static int                     system_wide                     =      0;
+static int                     profile_cpu                     =     -1;
+static pid_t                   target_pid                      =     -1;
+static pid_t                   child_pid                       =     -1;
+static int                     inherit                         =      1;
+static int                     force                           =      0;
+static int                     append_file                     =      0;
+static int                     call_graph                      =      0;
+static int                     inherit_stat                    =      0;
+static int                     no_samples                      =      0;
+static int                     sample_address                  =      0;
+static int                     multiplex                       =      0;
+static int                     multiplex_fd                    =     -1;
+
+static long                    samples                         =      0;
 static struct timeval          last_read;
 static struct timeval          this_read;
 
-static u64                     bytes_written;
+static u64                     bytes_written                   =      0;
 
 static struct pollfd           event_array[MAX_NR_CPUS * MAX_COUNTERS];
 
-static int                     nr_poll;
-static int                     nr_cpu;
+static int                     nr_poll                         =      0;
+static int                     nr_cpu                          =      0;
 
-static int                     file_new = 1;
+static int                     file_new                        =      1;
 
-struct perf_header             *header;
+struct perf_header             *header                         =   NULL;
 
 struct mmap_data {
        int                     counter;
@@ -113,6 +110,24 @@ static void write_output(void *buf, size_t size)
        }
 }
 
+static void write_event(event_t *buf, size_t size)
+{
+       /*
+       * Add it to the list of DSOs, so that when we finish this
+        * record session we can pick the available build-ids.
+        */
+       if (buf->header.type == PERF_RECORD_MMAP)
+               dsos__findnew(buf->mmap.filename);
+
+       write_output(buf, size);
+}
+
+static int process_synthesized_event(event_t *event)
+{
+       write_event(event, event->header.size);
+       return 0;
+}
+
 static void mmap_read(struct mmap_data *md)
 {
        unsigned int head = mmap_read_head(md);
@@ -161,14 +176,14 @@ static void mmap_read(struct mmap_data *md)
                size = md->mask + 1 - (old & md->mask);
                old += size;
 
-               write_output(buf, size);
+               write_event(buf, size);
        }
 
        buf = &data[old & md->mask];
        size = head - old;
        old += size;
 
-       write_output(buf, size);
+       write_event(buf, size);
 
        md->prev = old;
        mmap_write_tail(md, old);
@@ -195,168 +210,6 @@ static void sig_atexit(void)
        kill(getpid(), signr);
 }
 
-static pid_t pid_synthesize_comm_event(pid_t pid, int full)
-{
-       struct comm_event comm_ev;
-       char filename[PATH_MAX];
-       char bf[BUFSIZ];
-       FILE *fp;
-       size_t size = 0;
-       DIR *tasks;
-       struct dirent dirent, *next;
-       pid_t tgid = 0;
-
-       snprintf(filename, sizeof(filename), "/proc/%d/status", pid);
-
-       fp = fopen(filename, "r");
-       if (fp == NULL) {
-               /*
-                * We raced with a task exiting - just return:
-                */
-               if (verbose)
-                       fprintf(stderr, "couldn't open %s\n", filename);
-               return 0;
-       }
-
-       memset(&comm_ev, 0, sizeof(comm_ev));
-       while (!comm_ev.comm[0] || !comm_ev.pid) {
-               if (fgets(bf, sizeof(bf), fp) == NULL)
-                       goto out_failure;
-
-               if (memcmp(bf, "Name:", 5) == 0) {
-                       char *name = bf + 5;
-                       while (*name && isspace(*name))
-                               ++name;
-                       size = strlen(name) - 1;
-                       memcpy(comm_ev.comm, name, size++);
-               } else if (memcmp(bf, "Tgid:", 5) == 0) {
-                       char *tgids = bf + 5;
-                       while (*tgids && isspace(*tgids))
-                               ++tgids;
-                       tgid = comm_ev.pid = atoi(tgids);
-               }
-       }
-
-       comm_ev.header.type = PERF_RECORD_COMM;
-       size = ALIGN(size, sizeof(u64));
-       comm_ev.header.size = sizeof(comm_ev) - (sizeof(comm_ev.comm) - size);
-
-       if (!full) {
-               comm_ev.tid = pid;
-
-               write_output(&comm_ev, comm_ev.header.size);
-               goto out_fclose;
-       }
-
-       snprintf(filename, sizeof(filename), "/proc/%d/task", pid);
-
-       tasks = opendir(filename);
-       while (!readdir_r(tasks, &dirent, &next) && next) {
-               char *end;
-               pid = strtol(dirent.d_name, &end, 10);
-               if (*end)
-                       continue;
-
-               comm_ev.tid = pid;
-
-               write_output(&comm_ev, comm_ev.header.size);
-       }
-       closedir(tasks);
-
-out_fclose:
-       fclose(fp);
-       return tgid;
-
-out_failure:
-       fprintf(stderr, "couldn't get COMM and pgid, malformed %s\n",
-               filename);
-       exit(EXIT_FAILURE);
-}
-
-static void pid_synthesize_mmap_samples(pid_t pid, pid_t tgid)
-{
-       char filename[PATH_MAX];
-       FILE *fp;
-
-       snprintf(filename, sizeof(filename), "/proc/%d/maps", pid);
-
-       fp = fopen(filename, "r");
-       if (fp == NULL) {
-               /*
-                * We raced with a task exiting - just return:
-                */
-               if (verbose)
-                       fprintf(stderr, "couldn't open %s\n", filename);
-               return;
-       }
-       while (1) {
-               char bf[BUFSIZ], *pbf = bf;
-               struct mmap_event mmap_ev = {
-                       .header = { .type = PERF_RECORD_MMAP },
-               };
-               int n;
-               size_t size;
-               if (fgets(bf, sizeof(bf), fp) == NULL)
-                       break;
-
-               /* 00400000-0040c000 r-xp 00000000 fd:01 41038  /bin/cat */
-               n = hex2u64(pbf, &mmap_ev.start);
-               if (n < 0)
-                       continue;
-               pbf += n + 1;
-               n = hex2u64(pbf, &mmap_ev.len);
-               if (n < 0)
-                       continue;
-               pbf += n + 3;
-               if (*pbf == 'x') { /* vm_exec */
-                       char *execname = strchr(bf, '/');
-
-                       /* Catch VDSO */
-                       if (execname == NULL)
-                               execname = strstr(bf, "[vdso]");
-
-                       if (execname == NULL)
-                               continue;
-
-                       size = strlen(execname);
-                       execname[size - 1] = '\0'; /* Remove \n */
-                       memcpy(mmap_ev.filename, execname, size);
-                       size = ALIGN(size, sizeof(u64));
-                       mmap_ev.len -= mmap_ev.start;
-                       mmap_ev.header.size = (sizeof(mmap_ev) -
-                                              (sizeof(mmap_ev.filename) - size));
-                       mmap_ev.pid = tgid;
-                       mmap_ev.tid = pid;
-
-                       write_output(&mmap_ev, mmap_ev.header.size);
-               }
-       }
-
-       fclose(fp);
-}
-
-static void synthesize_all(void)
-{
-       DIR *proc;
-       struct dirent dirent, *next;
-
-       proc = opendir("/proc");
-
-       while (!readdir_r(proc, &dirent, &next) && next) {
-               char *end;
-               pid_t pid, tgid;
-
-               pid = strtol(dirent.d_name, &end, 10);
-               if (*end) /* only interested in proper numerical dirents */
-                       continue;
-
-               tgid = pid_synthesize_comm_event(pid, 1);
-               pid_synthesize_mmap_samples(pid, tgid);
-       }
-
-       closedir(proc);
-}
-
 static int group_fd;
 
 static struct perf_header_attr *get_header_attr(struct perf_event_attr *a, int nr)
@@ -367,7 +220,11 @@ static struct perf_header_attr *get_header_attr(struct perf_event_attr *a, int n
                h_attr = header->attr[nr];
        } else {
                h_attr = perf_header_attr__new(a);
-               perf_header__add_attr(header, h_attr);
+               if (h_attr != NULL)
+                       if (perf_header__add_attr(header, h_attr) < 0) {
+                               perf_header_attr__delete(h_attr);
+                               h_attr = NULL;
+                       }
        }
 
        return h_attr;
@@ -375,9 +232,11 @@ static struct perf_header_attr *get_header_attr(struct perf_event_attr *a, int n
 
 static void create_counter(int counter, int cpu, pid_t pid)
 {
+       char *filter = filters[counter];
        struct perf_event_attr *attr = attrs + counter;
        struct perf_header_attr *h_attr;
        int track = !counter; /* only the first counter needs these */
+       int ret;
        struct {
                u64 count;
                u64 time_enabled;
@@ -448,11 +307,19 @@ try_again:
                printf("\n");
                error("perfcounter syscall returned with %d (%s)\n",
                        fd[nr_cpu][counter], strerror(err));
+
+#if defined(__i386__) || defined(__x86_64__)
+               if (attr->type == PERF_TYPE_HARDWARE && err == EOPNOTSUPP)
+                       die("No hardware sampling interrupt available. No APIC? If so then you can boot the kernel with the \"lapic\" boot parameter to force-enable it.\n");
+#endif
+
                die("No CONFIG_PERF_EVENTS=y kernel support configured?\n");
                exit(-1);
        }
 
        h_attr = get_header_attr(attr, counter);
+       if (h_attr == NULL)
+               die("nomem\n");
 
        if (!file_new) {
                if (memcmp(&h_attr->attr, attr, sizeof(*attr))) {
@@ -466,7 +333,10 @@ try_again:
                exit(-1);
        }
 
-       perf_header_attr__add_id(h_attr, read_data.id);
+       if (perf_header_attr__add_id(h_attr, read_data.id) < 0) {
+               pr_warning("Not enough memory to add id\n");
+               exit(-1);
+       }
 
        assert(fd[nr_cpu][counter] >= 0);
        fcntl(fd[nr_cpu][counter], F_SETFL, O_NONBLOCK);
@@ -480,7 +350,6 @@ try_again:
                multiplex_fd = fd[nr_cpu][counter];
 
        if (multiplex && fd[nr_cpu][counter] != multiplex_fd) {
-               int ret;
 
                ret = ioctl(fd[nr_cpu][counter], PERF_EVENT_IOC_SET_OUTPUT, multiplex_fd);
                assert(ret != -1);
@@ -500,6 +369,16 @@ try_again:
                }
        }
 
+       if (filter != NULL) {
+               ret = ioctl(fd[nr_cpu][counter],
+                           PERF_EVENT_IOC_SET_FILTER, filter);
+               if (ret) {
+                       error("failed to set filter with %d (%s)\n", errno,
+                             strerror(errno));
+                       exit(-1);
+               }
+       }
+
        ioctl(fd[nr_cpu][counter], PERF_EVENT_IOC_ENABLE);
 }
 
@@ -518,7 +397,7 @@ static void atexit_header(void)
 {
        header->data_size += bytes_written;
 
-       perf_header__write(header, output);
+       perf_header__write(header, output, true);
 }
 
 static int __cmd_record(int argc, const char **argv)
@@ -527,7 +406,7 @@ static int __cmd_record(int argc, const char **argv)
        struct stat st;
        pid_t pid = 0;
        int flags;
-       int ret;
+       int err;
        unsigned long waking = 0;
 
        page_size = sysconf(_SC_PAGE_SIZE);
@@ -561,22 +440,29 @@ static int __cmd_record(int argc, const char **argv)
                exit(-1);
        }
 
-       if (!file_new)
-               header = perf_header__read(output);
-       else
-               header = perf_header__new();
+       header = perf_header__new();
+       if (header == NULL) {
+               pr_err("Not enough memory for reading perf file header\n");
+               return -1;
+       }
 
+       if (!file_new) {
+               err = perf_header__read(header, output);
+               if (err < 0)
+                       return err;
+       }
 
        if (raw_samples) {
-               read_tracing_data(attrs, nr_counters);
+               perf_header__set_feat(header, HEADER_TRACE_INFO);
        } else {
                for (i = 0; i < nr_counters; i++) {
                        if (attrs[i].sample_type & PERF_SAMPLE_RAW) {
-                               read_tracing_data(attrs, nr_counters);
+                               perf_header__set_feat(header, HEADER_TRACE_INFO);
                                break;
                        }
                }
        }
+
        atexit(atexit_header);
 
        if (!system_wide) {
@@ -594,25 +480,36 @@ static int __cmd_record(int argc, const char **argv)
                }
        }
 
-       if (file_new)
-               perf_header__write(header, output);
+       if (file_new) {
+               err = perf_header__write(header, output, false);
+               if (err < 0)
+                       return err;
+       }
 
-       if (!system_wide) {
-               pid_t tgid = pid_synthesize_comm_event(pid, 0);
-               pid_synthesize_mmap_samples(pid, tgid);
-       } else
-               synthesize_all();
+       if (!system_wide)
+               event__synthesize_thread(pid, process_synthesized_event);
+       else
+               event__synthesize_threads(process_synthesized_event);
 
        if (target_pid == -1 && argc) {
                pid = fork();
                if (pid < 0)
-                       perror("failed to fork");
+                       die("failed to fork");
 
                if (!pid) {
                        if (execvp(argv[0], (char **)argv)) {
                                perror(argv[0]);
                                exit(-1);
                        }
+               } else {
+                       /*
+                        * Wait a bit for the execv'ed child to appear
+                        * and be updated in /proc
+                        * FIXME: Do you know a less heuristical solution?
+                        */
+                       usleep(1000);
+                       event__synthesize_thread(pid,
+                                                process_synthesized_event);
                }
 
                child_pid = pid;
@@ -623,7 +520,7 @@ static int __cmd_record(int argc, const char **argv)
 
                param.sched_priority = realtime_prio;
                if (sched_setscheduler(0, SCHED_FIFO, &param)) {
-                       printf("Could not set realtime priority.\n");
+                       pr_err("Could not set realtime priority.\n");
                        exit(-1);
                }
        }
@@ -641,7 +538,7 @@ static int __cmd_record(int argc, const char **argv)
                if (hits == samples) {
                        if (done)
                                break;
-                       ret = poll(event_array, nr_poll, -1);
+                       err = poll(event_array, nr_poll, -1);
                        waking++;
                }
 
@@ -677,6 +574,8 @@ static const struct option options[] = {
        OPT_CALLBACK('e', "event", NULL, "event",
                     "event selector. use 'perf list' to list available events",
                     parse_events),
+       OPT_CALLBACK(0, "filter", NULL, "filter",
+                    "event filter", parse_filter),
        OPT_INTEGER('p', "pid", &target_pid,
                    "record events on existing pid"),
        OPT_INTEGER('r', "realtime", &realtime_prio,
@@ -720,6 +619,8 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
 {
        int counter;
 
+       symbol__init(0);
+
        argc = parse_options(argc, argv, options, record_usage,
                PARSE_OPT_STOP_AT_NON_OPTION);
        if (!argc && target_pid == -1 && !system_wide)
@@ -731,6 +632,18 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
                attrs[0].config = PERF_COUNT_HW_CPU_CYCLES;
        }
 
+       /*
+        * User specified count overrides default frequency.
+        */
+       if (default_interval)
+               freq = 0;
+       else if (freq) {
+               default_interval = freq;
+       } else {
+               fprintf(stderr, "frequency and count are zero, aborting\n");
+               exit(EXIT_FAILURE);
+       }
+
        for (counter = 0; counter < nr_counters; counter++) {
                if (attrs[counter].sample_period)
                        continue;
index 19669c2..383c4ab 100644 (file)
 #include "util/parse-options.h"
 #include "util/parse-events.h"
 
+#include "util/data_map.h"
 #include "util/thread.h"
+#include "util/sort.h"
+#include "util/hist.h"
 
 static char            const *input_name = "perf.data";
 
-static char            default_sort_order[] = "comm,dso,symbol";
-static char            *sort_order = default_sort_order;
 static char            *dso_list_str, *comm_list_str, *sym_list_str,
                        *col_width_list_str;
 static struct strlist  *dso_list, *comm_list, *sym_list;
-static char            *field_sep;
 
 static int             force;
-static int             input;
-static int             show_mask = SHOW_KERNEL | SHOW_USER | SHOW_HV;
 
 static int             full_paths;
 static int             show_nr_samples;
@@ -50,374 +48,38 @@ static struct perf_read_values     show_threads_values;
 static char            default_pretty_printing_style[] = "normal";
 static char            *pretty_printing_style = default_pretty_printing_style;
 
-static unsigned long   page_size;
-static unsigned long   mmap_window = 32;
-
-static char            default_parent_pattern[] = "^sys_|^do_page_fault";
-static char            *parent_pattern = default_parent_pattern;
-static regex_t         parent_regex;
-
 static int             exclude_other = 1;
 
 static char            callchain_default_opt[] = "fractal,0.5";
 
-static int             callchain;
-
-static char            __cwd[PATH_MAX];
-static char            *cwd = __cwd;
-static int             cwdlen;
-
-static struct rb_root  threads;
-static struct thread   *last_match;
-
 static struct perf_header *header;
 
-static
-struct callchain_param callchain_param = {
-       .mode   = CHAIN_GRAPH_REL,
-       .min_percent = 0.5
-};
-
 static u64             sample_type;
 
-static int repsep_fprintf(FILE *fp, const char *fmt, ...)
-{
-       int n;
-       va_list ap;
-
-       va_start(ap, fmt);
-       if (!field_sep)
-               n = vfprintf(fp, fmt, ap);
-       else {
-               char *bf = NULL;
-               n = vasprintf(&bf, fmt, ap);
-               if (n > 0) {
-                       char *sep = bf;
-
-                       while (1) {
-                               sep = strchr(sep, *field_sep);
-                               if (sep == NULL)
-                                       break;
-                               *sep = '.';
-                       }
-               }
-               fputs(bf, fp);
-               free(bf);
-       }
-       va_end(ap);
-       return n;
-}
-
-static unsigned int dsos__col_width,
-                   comms__col_width,
-                   threads__col_width;
+struct symbol_conf     symbol_conf;
 
-/*
- * histogram, sorted on item, collects counts
- */
-
-static struct rb_root hist;
-
-struct hist_entry {
-       struct rb_node          rb_node;
-
-       struct thread           *thread;
-       struct map              *map;
-       struct dso              *dso;
-       struct symbol           *sym;
-       struct symbol           *parent;
-       u64                     ip;
-       char                    level;
-       struct callchain_node   callchain;
-       struct rb_root          sorted_chain;
-
-       u64                     count;
-};
-
-/*
- * configurable sorting bits
- */
-
-struct sort_entry {
-       struct list_head list;
-
-       const char *header;
-
-       int64_t (*cmp)(struct hist_entry *, struct hist_entry *);
-       int64_t (*collapse)(struct hist_entry *, struct hist_entry *);
-       size_t  (*print)(FILE *fp, struct hist_entry *, unsigned int width);
-       unsigned int *width;
-       bool    elide;
-};
-
-static int64_t cmp_null(void *l, void *r)
-{
-       if (!l && !r)
-               return 0;
-       else if (!l)
-               return -1;
-       else
-               return 1;
-}
-
-/* --sort pid */
-
-static int64_t
-sort__thread_cmp(struct hist_entry *left, struct hist_entry *right)
-{
-       return right->thread->pid - left->thread->pid;
-}
 
 static size_t
-sort__thread_print(FILE *fp, struct hist_entry *self, unsigned int width)
+callchain__fprintf_left_margin(FILE *fp, int left_margin)
 {
-       return repsep_fprintf(fp, "%*s:%5d", width - 6,
-                             self->thread->comm ?: "", self->thread->pid);
-}
-
-static struct sort_entry sort_thread = {
-       .header = "Command:  Pid",
-       .cmp    = sort__thread_cmp,
-       .print  = sort__thread_print,
-       .width  = &threads__col_width,
-};
-
-/* --sort comm */
-
-static int64_t
-sort__comm_cmp(struct hist_entry *left, struct hist_entry *right)
-{
-       return right->thread->pid - left->thread->pid;
-}
-
-static int64_t
-sort__comm_collapse(struct hist_entry *left, struct hist_entry *right)
-{
-       char *comm_l = left->thread->comm;
-       char *comm_r = right->thread->comm;
-
-       if (!comm_l || !comm_r)
-               return cmp_null(comm_l, comm_r);
-
-       return strcmp(comm_l, comm_r);
-}
-
-static size_t
-sort__comm_print(FILE *fp, struct hist_entry *self, unsigned int width)
-{
-       return repsep_fprintf(fp, "%*s", width, self->thread->comm);
-}
-
-static struct sort_entry sort_comm = {
-       .header         = "Command",
-       .cmp            = sort__comm_cmp,
-       .collapse       = sort__comm_collapse,
-       .print          = sort__comm_print,
-       .width          = &comms__col_width,
-};
-
-/* --sort dso */
-
-static int64_t
-sort__dso_cmp(struct hist_entry *left, struct hist_entry *right)
-{
-       struct dso *dso_l = left->dso;
-       struct dso *dso_r = right->dso;
-
-       if (!dso_l || !dso_r)
-               return cmp_null(dso_l, dso_r);
-
-       return strcmp(dso_l->name, dso_r->name);
-}
-
-static size_t
-sort__dso_print(FILE *fp, struct hist_entry *self, unsigned int width)
-{
-       if (self->dso)
-               return repsep_fprintf(fp, "%-*s", width, self->dso->name);
-
-       return repsep_fprintf(fp, "%*llx", width, (u64)self->ip);
-}
-
-static struct sort_entry sort_dso = {
-       .header = "Shared Object",
-       .cmp    = sort__dso_cmp,
-       .print  = sort__dso_print,
-       .width  = &dsos__col_width,
-};
-
-/* --sort symbol */
-
-static int64_t
-sort__sym_cmp(struct hist_entry *left, struct hist_entry *right)
-{
-       u64 ip_l, ip_r;
-
-       if (left->sym == right->sym)
-               return 0;
-
-       ip_l = left->sym ? left->sym->start : left->ip;
-       ip_r = right->sym ? right->sym->start : right->ip;
-
-       return (int64_t)(ip_r - ip_l);
-}
-
-static size_t
-sort__sym_print(FILE *fp, struct hist_entry *self, unsigned int width __used)
-{
-       size_t ret = 0;
+       int i;
+       int ret;
 
-       if (verbose)
-               ret += repsep_fprintf(fp, "%#018llx %c ", (u64)self->ip,
-                                     dso__symtab_origin(self->dso));
+       ret = fprintf(fp, "            ");
 
-       ret += repsep_fprintf(fp, "[%c] ", self->level);
-       if (self->sym) {
-               ret += repsep_fprintf(fp, "%s", self->sym->name);
-
-               if (self->sym->module)
-                       ret += repsep_fprintf(fp, "\t[%s]",
-                                            self->sym->module->name);
-       } else {
-               ret += repsep_fprintf(fp, "%#016llx", (u64)self->ip);
-       }
+       for (i = 0; i < left_margin; i++)
+               ret += fprintf(fp, " ");
 
        return ret;
 }
 
-static struct sort_entry sort_sym = {
-       .header = "Symbol",
-       .cmp    = sort__sym_cmp,
-       .print  = sort__sym_print,
-};
-
-/* --sort parent */
-
-static int64_t
-sort__parent_cmp(struct hist_entry *left, struct hist_entry *right)
-{
-       struct symbol *sym_l = left->parent;
-       struct symbol *sym_r = right->parent;
-
-       if (!sym_l || !sym_r)
-               return cmp_null(sym_l, sym_r);
-
-       return strcmp(sym_l->name, sym_r->name);
-}
-
-static size_t
-sort__parent_print(FILE *fp, struct hist_entry *self, unsigned int width)
-{
-       return repsep_fprintf(fp, "%-*s", width,
-                             self->parent ? self->parent->name : "[other]");
-}
-
-static unsigned int parent_symbol__col_width;
-
-static struct sort_entry sort_parent = {
-       .header = "Parent symbol",
-       .cmp    = sort__parent_cmp,
-       .print  = sort__parent_print,
-       .width  = &parent_symbol__col_width,
-};
-
-static int sort__need_collapse = 0;
-static int sort__has_parent = 0;
-
-struct sort_dimension {
-       const char              *name;
-       struct sort_entry       *entry;
-       int                     taken;
-};
-
-static struct sort_dimension sort_dimensions[] = {
-       { .name = "pid",        .entry = &sort_thread,  },
-       { .name = "comm",       .entry = &sort_comm,    },
-       { .name = "dso",        .entry = &sort_dso,     },
-       { .name = "symbol",     .entry = &sort_sym,     },
-       { .name = "parent",     .entry = &sort_parent,  },
-};
-
-static LIST_HEAD(hist_entry__sort_list);
-
-static int sort_dimension__add(const char *tok)
-{
-       unsigned int i;
-
-       for (i = 0; i < ARRAY_SIZE(sort_dimensions); i++) {
-               struct sort_dimension *sd = &sort_dimensions[i];
-
-               if (sd->taken)
-                       continue;
-
-               if (strncasecmp(tok, sd->name, strlen(tok)))
-                       continue;
-
-               if (sd->entry->collapse)
-                       sort__need_collapse = 1;
-
-               if (sd->entry == &sort_parent) {
-                       int ret = regcomp(&parent_regex, parent_pattern, REG_EXTENDED);
-                       if (ret) {
-                               char err[BUFSIZ];
-
-                               regerror(ret, &parent_regex, err, sizeof(err));
-                               fprintf(stderr, "Invalid regex: %s\n%s",
-                                       parent_pattern, err);
-                               exit(-1);
-                       }
-                       sort__has_parent = 1;
-               }
-
-               list_add_tail(&sd->entry->list, &hist_entry__sort_list);
-               sd->taken = 1;
-
-               return 0;
-       }
-
-       return -ESRCH;
-}
-
-static int64_t
-hist_entry__cmp(struct hist_entry *left, struct hist_entry *right)
-{
-       struct sort_entry *se;
-       int64_t cmp = 0;
-
-       list_for_each_entry(se, &hist_entry__sort_list, list) {
-               cmp = se->cmp(left, right);
-               if (cmp)
-                       break;
-       }
-
-       return cmp;
-}
-
-static int64_t
-hist_entry__collapse(struct hist_entry *left, struct hist_entry *right)
-{
-       struct sort_entry *se;
-       int64_t cmp = 0;
-
-       list_for_each_entry(se, &hist_entry__sort_list, list) {
-               int64_t (*f)(struct hist_entry *, struct hist_entry *);
-
-               f = se->collapse ?: se->cmp;
-
-               cmp = f(left, right);
-               if (cmp)
-                       break;
-       }
-
-       return cmp;
-}
-
-static size_t ipchain__fprintf_graph_line(FILE *fp, int depth, int depth_mask)
+static size_t ipchain__fprintf_graph_line(FILE *fp, int depth, int depth_mask,
+                                         int left_margin)
 {
        int i;
        size_t ret = 0;
 
-       ret += fprintf(fp, "%s", "                ");
+       ret += callchain__fprintf_left_margin(fp, left_margin);
 
        for (i = 0; i < depth; i++)
                if (depth_mask & (1 << i))
@@ -432,12 +94,12 @@ static size_t ipchain__fprintf_graph_line(FILE *fp, int depth, int depth_mask)
 static size_t
 ipchain__fprintf_graph(FILE *fp, struct callchain_list *chain, int depth,
                       int depth_mask, int count, u64 total_samples,
-                      int hits)
+                      int hits, int left_margin)
 {
        int i;
        size_t ret = 0;
 
-       ret += fprintf(fp, "%s", "                ");
+       ret += callchain__fprintf_left_margin(fp, left_margin);
        for (i = 0; i < depth; i++) {
                if (depth_mask & (1 << i))
                        ret += fprintf(fp, "|");
@@ -475,8 +137,9 @@ static void init_rem_hits(void)
 }
 
 static size_t
-callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
-                       u64 total_samples, int depth, int depth_mask)
+__callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
+                          u64 total_samples, int depth, int depth_mask,
+                          int left_margin)
 {
        struct rb_node *node, *next;
        struct callchain_node *child;
@@ -517,7 +180,8 @@ callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
                 * But we keep the older depth mask for the line seperator
                 * to keep the level link until we reach the last child
                 */
-               ret += ipchain__fprintf_graph_line(fp, depth, depth_mask);
+               ret += ipchain__fprintf_graph_line(fp, depth, depth_mask,
+                                                  left_margin);
                i = 0;
                list_for_each_entry(chain, &child->val, list) {
                        if (chain->ip >= PERF_CONTEXT_MAX)
@@ -525,11 +189,13 @@ callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
                        ret += ipchain__fprintf_graph(fp, chain, depth,
                                                      new_depth_mask, i++,
                                                      new_total,
-                                                     cumul);
+                                                     cumul,
+                                                     left_margin);
                }
-               ret += callchain__fprintf_graph(fp, child, new_total,
-                                               depth + 1,
-                                               new_depth_mask | (1 << depth));
+               ret += __callchain__fprintf_graph(fp, child, new_total,
+                                                 depth + 1,
+                                                 new_depth_mask | (1 << depth),
+                                                 left_margin);
                node = next;
        }
 
@@ -543,9 +209,48 @@ callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
 
                ret += ipchain__fprintf_graph(fp, &rem_hits, depth,
                                              new_depth_mask, 0, new_total,
-                                             remaining);
+                                             remaining, left_margin);
+       }
+
+       return ret;
+}
+
+
+static size_t
+callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
+                        u64 total_samples, int left_margin)
+{
+       struct callchain_list *chain;
+       bool printed = false;
+       int i = 0;
+       int ret = 0;
+
+       list_for_each_entry(chain, &self->val, list) {
+               if (chain->ip >= PERF_CONTEXT_MAX)
+                       continue;
+
+               if (!i++ && sort__first_dimension == SORT_SYM)
+                       continue;
+
+               if (!printed) {
+                       ret += callchain__fprintf_left_margin(fp, left_margin);
+                       ret += fprintf(fp, "|\n");
+                       ret += callchain__fprintf_left_margin(fp, left_margin);
+                       ret += fprintf(fp, "---");
+
+                       left_margin += 3;
+                       printed = true;
+               } else
+                       ret += callchain__fprintf_left_margin(fp, left_margin);
+
+               if (chain->sym)
+                       ret += fprintf(fp, " %s\n", chain->sym->name);
+               else
+                       ret += fprintf(fp, " %p\n", (void *)(long)chain->ip);
        }
 
+       ret += __callchain__fprintf_graph(fp, self, total_samples, 1, 1, left_margin);
+
        return ret;
 }
 
@@ -577,7 +282,7 @@ callchain__fprintf_flat(FILE *fp, struct callchain_node *self,
 
 static size_t
 hist_entry_callchain__fprintf(FILE *fp, struct hist_entry *self,
-                             u64 total_samples)
+                             u64 total_samples, int left_margin)
 {
        struct rb_node *rb_node;
        struct callchain_node *chain;
@@ -597,8 +302,8 @@ hist_entry_callchain__fprintf(FILE *fp, struct hist_entry *self,
                        break;
                case CHAIN_GRAPH_ABS: /* Falldown */
                case CHAIN_GRAPH_REL:
-                       ret += callchain__fprintf_graph(fp, chain,
-                                                       total_samples, 1, 1);
+                       ret += callchain__fprintf_graph(fp, chain, total_samples,
+                                                       left_margin);
                case CHAIN_NONE:
                default:
                        break;
@@ -610,7 +315,6 @@ hist_entry_callchain__fprintf(FILE *fp, struct hist_entry *self,
        return ret;
 }
 
-
 static size_t
 hist_entry__fprintf(FILE *fp, struct hist_entry *self, u64 total_samples)
 {
@@ -644,8 +348,19 @@ hist_entry__fprintf(FILE *fp, struct hist_entry *self, u64 total_samples)
 
        ret += fprintf(fp, "\n");
 
-       if (callchain)
-               hist_entry_callchain__fprintf(fp, self, total_samples);
+       if (callchain) {
+               int left_margin = 0;
+
+               if (sort__first_dimension == SORT_COMM) {
+                       se = list_first_entry(&hist_entry__sort_list, typeof(*se),
+                                               list);
+                       left_margin = se->width ? *se->width : 0;
+                       left_margin -= thread__comm_len(self->thread);
+               }
+
+               hist_entry_callchain__fprintf(fp, self, total_samples,
+                                             left_margin);
+       }
 
        return ret;
 }
@@ -693,63 +408,6 @@ static int thread__set_comm_adjust(struct thread *self, const char *comm)
        return 0;
 }
 
-
-static struct symbol *
-resolve_symbol(struct thread *thread, struct map **mapp,
-              struct dso **dsop, u64 *ipp)
-{
-       struct dso *dso = dsop ? *dsop : NULL;
-       struct map *map = mapp ? *mapp : NULL;
-       u64 ip = *ipp;
-
-       if (!thread)
-               return NULL;
-
-       if (dso)
-               goto got_dso;
-
-       if (map)
-               goto got_map;
-
-       map = thread__find_map(thread, ip);
-       if (map != NULL) {
-               /*
-                * We have to do this here as we may have a dso
-                * with no symbol hit that has a name longer than
-                * the ones with symbols sampled.
-                */
-               if (!sort_dso.elide && !map->dso->slen_calculated)
-                       dso__calc_col_width(map->dso);
-
-               if (mapp)
-                       *mapp = map;
-got_map:
-               ip = map->map_ip(map, ip);
-
-               dso = map->dso;
-       } else {
-               /*
-                * If this is outside of all known maps,
-                * and is a negative address, try to look it
-                * up in the kernel dso, as it might be a
-                * vsyscall (which executes in user-mode):
-                */
-               if ((long long)ip < 0)
-               dso = kernel_dso;
-       }
-       dump_printf(" ...... dso: %s\n", dso ? dso->name : "<not found>");
-       dump_printf(" ...... map: %Lx -> %Lx\n", *ipp, ip);
-       *ipp  = ip;
-
-       if (dsop)
-               *dsop = dso;
-
-       if (!dso)
-               return NULL;
-got_dso:
-       return dso->find_symbol(dso, ip);
-}
-
 static int call__match(struct symbol *sym)
 {
        if (sym->name && !regexec(&parent_regex, sym->name, 0, NULL, 0))
@@ -758,11 +416,11 @@ static int call__match(struct symbol *sym)
        return 0;
 }
 
-static struct symbol **
-resolve_callchain(struct thread *thread, struct map *map __used,
-                   struct ip_callchain *chain, struct hist_entry *entry)
+static struct symbol **resolve_callchain(struct thread *thread,
+                                        struct ip_callchain *chain,
+                                        struct symbol **parent)
 {
-       u64 context = PERF_CONTEXT_MAX;
+       u8 cpumode = PERF_RECORD_MISC_USER;
        struct symbol **syms = NULL;
        unsigned int i;
 
@@ -776,34 +434,31 @@ resolve_callchain(struct thread *thread, struct map *map __used,
 
        for (i = 0; i < chain->nr; i++) {
                u64 ip = chain->ips[i];
-               struct dso *dso = NULL;
-               struct symbol *sym;
+               struct addr_location al;
 
                if (ip >= PERF_CONTEXT_MAX) {
-                       context = ip;
+                       switch (ip) {
+                       case PERF_CONTEXT_HV:
+                               cpumode = PERF_RECORD_MISC_HYPERVISOR;  break;
+                       case PERF_CONTEXT_KERNEL:
+                               cpumode = PERF_RECORD_MISC_KERNEL;      break;
+                       case PERF_CONTEXT_USER:
+                               cpumode = PERF_RECORD_MISC_USER;        break;
+                       default:
+                               break;
+                       }
                        continue;
                }
 
-               switch (context) {
-               case PERF_CONTEXT_HV:
-                       dso = hypervisor_dso;
-                       break;
-               case PERF_CONTEXT_KERNEL:
-                       dso = kernel_dso;
-                       break;
-               default:
-                       break;
-               }
-
-               sym = resolve_symbol(thread, NULL, &dso, &ip);
-
-               if (sym) {
-                       if (sort__has_parent && call__match(sym) &&
-                           !entry->parent)
-                               entry->parent = sym;
+               thread__find_addr_location(thread, cpumode, MAP__FUNCTION,
+                                          ip, &al, NULL);
+               if (al.sym != NULL) {
+                       if (sort__has_parent && !*parent &&
+                           call__match(al.sym))
+                               *parent = al.sym;
                        if (!callchain)
                                break;
-                       syms[i] = sym;
+                       syms[i] = al.sym;
                }
        }
 
@@ -814,178 +469,33 @@ resolve_callchain(struct thread *thread, struct map *map __used,
  * collect histogram counts
  */
 
-static int
-hist_entry__add(struct thread *thread, struct map *map, struct dso *dso,
-               struct symbol *sym, u64 ip, struct ip_callchain *chain,
-               char level, u64 count)
+static int hist_entry__add(struct addr_location *al,
+                          struct ip_callchain *chain, u64 count)
 {
-       struct rb_node **p = &hist.rb_node;
-       struct rb_node *parent = NULL;
+       struct symbol **syms = NULL, *parent = NULL;
+       bool hit;
        struct hist_entry *he;
-       struct symbol **syms = NULL;
-       struct hist_entry entry = {
-               .thread = thread,
-               .map    = map,
-               .dso    = dso,
-               .sym    = sym,
-               .ip     = ip,
-               .level  = level,
-               .count  = count,
-               .parent = NULL,
-               .sorted_chain = RB_ROOT
-       };
-       int cmp;
 
        if ((sort__has_parent || callchain) && chain)
-               syms = resolve_callchain(thread, map, chain, &entry);
+               syms = resolve_callchain(al->thread, chain, &parent);
 
-       while (*p != NULL) {
-               parent = *p;
-               he = rb_entry(parent, struct hist_entry, rb_node);
+       he = __hist_entry__add(al, parent, count, &hit);
+       if (he == NULL)
+               return -ENOMEM;
 
-               cmp = hist_entry__cmp(&entry, he);
+       if (hit)
+               he->count += count;
 
-               if (!cmp) {
-                       he->count += count;
-                       if (callchain) {
-                               append_chain(&he->callchain, chain, syms);
-                               free(syms);
-                       }
-                       return 0;
-               }
-
-               if (cmp < 0)
-                       p = &(*p)->rb_left;
-               else
-                       p = &(*p)->rb_right;
-       }
-
-       he = malloc(sizeof(*he));
-       if (!he)
-               return -ENOMEM;
-       *he = entry;
        if (callchain) {
-               callchain_init(&he->callchain);
+               if (!hit)
+                       callchain_init(&he->callchain);
                append_chain(&he->callchain, chain, syms);
                free(syms);
        }
-       rb_link_node(&he->rb_node, parent, p);
-       rb_insert_color(&he->rb_node, &hist);
 
        return 0;
 }
 
-static void hist_entry__free(struct hist_entry *he)
-{
-       free(he);
-}
-
-/*
- * collapse the histogram
- */
-
-static struct rb_root collapse_hists;
-
-static void collapse__insert_entry(struct hist_entry *he)
-{
-       struct rb_node **p = &collapse_hists.rb_node;
-       struct rb_node *parent = NULL;
-       struct hist_entry *iter;
-       int64_t cmp;
-
-       while (*p != NULL) {
-               parent = *p;
-               iter = rb_entry(parent, struct hist_entry, rb_node);
-
-               cmp = hist_entry__collapse(iter, he);
-
-               if (!cmp) {
-                       iter->count += he->count;
-                       hist_entry__free(he);
-                       return;
-               }
-
-               if (cmp < 0)
-                       p = &(*p)->rb_left;
-               else
-                       p = &(*p)->rb_right;
-       }
-
-       rb_link_node(&he->rb_node, parent, p);
-       rb_insert_color(&he->rb_node, &collapse_hists);
-}
-
-static void collapse__resort(void)
-{
-       struct rb_node *next;
-       struct hist_entry *n;
-
-       if (!sort__need_collapse)
-               return;
-
-       next = rb_first(&hist);
-       while (next) {
-               n = rb_entry(next, struct hist_entry, rb_node);
-               next = rb_next(&n->rb_node);
-
-               rb_erase(&n->rb_node, &hist);
-               collapse__insert_entry(n);
-       }
-}
-
-/*
- * reverse the map, sort on count.
- */
-
-static struct rb_root output_hists;
-
-static void output__insert_entry(struct hist_entry *he, u64 min_callchain_hits)
-{
-       struct rb_node **p = &output_hists.rb_node;
-       struct rb_node *parent = NULL;
-       struct hist_entry *iter;
-
-       if (callchain)
-               callchain_param.sort(&he->sorted_chain, &he->callchain,
-                                     min_callchain_hits, &callchain_param);
-
-       while (*p != NULL) {
-               parent = *p;
-               iter = rb_entry(parent, struct hist_entry, rb_node);
-
-               if (he->count > iter->count)
-                       p = &(*p)->rb_left;
-               else
-                       p = &(*p)->rb_right;
-       }
-
-       rb_link_node(&he->rb_node, parent, p);
-       rb_insert_color(&he->rb_node, &output_hists);
-}
-
-static void output__resort(u64 total_samples)
-{
-       struct rb_node *next;
-       struct hist_entry *n;
-       struct rb_root *tree = &hist;
-       u64 min_callchain_hits;
-
-       min_callchain_hits = total_samples * (callchain_param.min_percent / 100);
-
-       if (sort__need_collapse)
-               tree = &collapse_hists;
-
-       next = rb_first(tree);
-
-       while (next) {
-               n = rb_entry(next, struct hist_entry, rb_node);
-               next = rb_next(&n->rb_node);
-
-               rb_erase(&n->rb_node, tree);
-               output__insert_entry(n, min_callchain_hits);
-       }
-}
-
 static size_t output__fprintf(FILE *fp, u64 total_samples)
 {
        struct hist_entry *pos;
@@ -1080,13 +590,6 @@ print_entries:
        return ret;
 }
 
-static unsigned long total = 0,
-                    total_mmap = 0,
-                    total_comm = 0,
-                    total_fork = 0,
-                    total_unknown = 0,
-                    total_lost = 0;
-
 static int validate_chain(struct ip_callchain *chain, event_t *event)
 {
        unsigned int chain_size;
@@ -1100,30 +603,22 @@ static int validate_chain(struct ip_callchain *chain, event_t *event)
        return 0;
 }
 
-static int
-process_sample_event(event_t *event, unsigned long offset, unsigned long head)
+static int process_sample_event(event_t *event)
 {
-       char level;
-       int show = 0;
-       struct dso *dso = NULL;
-       struct thread *thread;
        u64 ip = event->ip.ip;
        u64 period = 1;
-       struct map *map = NULL;
        void *more_data = event->ip.__more_data;
        struct ip_callchain *chain = NULL;
        int cpumode;
-
-       thread = threads__findnew(event->ip.pid, &threads, &last_match);
+       struct addr_location al;
+       struct thread *thread = threads__findnew(event->ip.pid);
 
        if (sample_type & PERF_SAMPLE_PERIOD) {
                period = *(u64 *)more_data;
                more_data += sizeof(u64);
        }
 
-       dump_printf("%p [%p]: PERF_RECORD_SAMPLE (IP, %d): %d/%d: %p period: %Ld\n",
-               (void *)(offset + head),
-               (void *)(long)(event->header.size),
+       dump_printf("(IP, %d): %d/%d: %p period: %Ld\n",
                event->header.misc,
                event->ip.pid, event->ip.tid,
                (void *)(long)ip,
@@ -1137,7 +632,8 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head)
                dump_printf("... chain: nr:%Lu\n", chain->nr);
 
                if (validate_chain(chain, event) < 0) {
-                       eprintf("call-chain problem with event, skipping it.\n");
+                       pr_debug("call-chain problem with event, "
+                                "skipping it.\n");
                        return 0;
                }
 
@@ -1147,163 +643,64 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head)
                }
        }
 
-       dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid);
-
        if (thread == NULL) {
-               eprintf("problem processing %d event, skipping it.\n",
+               pr_debug("problem processing %d event, skipping it.\n",
                        event->header.type);
                return -1;
        }
 
+       dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid);
+
        if (comm_list && !strlist__has_entry(comm_list, thread->comm))
                return 0;
 
        cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
 
-       if (cpumode == PERF_RECORD_MISC_KERNEL) {
-               show = SHOW_KERNEL;
-               level = 'k';
-
-               dso = kernel_dso;
-
-               dump_printf(" ...... dso: %s\n", dso->name);
-
-       } else if (cpumode == PERF_RECORD_MISC_USER) {
-
-               show = SHOW_USER;
-               level = '.';
-
-       } else {
-               show = SHOW_HV;
-               level = 'H';
-
-               dso = hypervisor_dso;
-
-               dump_printf(" ...... dso: [hypervisor]\n");
-       }
-
-       if (show & show_mask) {
-               struct symbol *sym = resolve_symbol(thread, &map, &dso, &ip);
-
-               if (dso_list && (!dso || !dso->name ||
-                                !strlist__has_entry(dso_list, dso->name)))
-                       return 0;
-
-               if (sym_list && (!sym || !strlist__has_entry(sym_list, sym->name)))
-                       return 0;
-
-               if (hist_entry__add(thread, map, dso, sym, ip, chain, level, period)) {
-                       eprintf("problem incrementing symbol count, skipping event\n");
-                       return -1;
-               }
-       }
-       total += period;
-
-       return 0;
-}
+       thread__find_addr_location(thread, cpumode,
+                                  MAP__FUNCTION, ip, &al, NULL);
+       /*
+        * We have to do this here as we may have a dso with no symbol hit that
+        * has a name longer than the ones with symbols sampled.
+        */
+       if (al.map && !sort_dso.elide && !al.map->dso->slen_calculated)
+               dso__calc_col_width(al.map->dso);
+
+       if (dso_list &&
+           (!al.map || !al.map->dso ||
+            !(strlist__has_entry(dso_list, al.map->dso->short_name) ||
+              (al.map->dso->short_name != al.map->dso->long_name &&
+               strlist__has_entry(dso_list, al.map->dso->long_name)))))
+               return 0;
 
-static int
-process_mmap_event(event_t *event, unsigned long offset, unsigned long head)
-{
-       struct thread *thread;
-       struct map *map = map__new(&event->mmap, cwd, cwdlen);
-
-       thread = threads__findnew(event->mmap.pid, &threads, &last_match);
-
-       dump_printf("%p [%p]: PERF_RECORD_MMAP %d/%d: [%p(%p) @ %p]: %s\n",
-               (void *)(offset + head),
-               (void *)(long)(event->header.size),
-               event->mmap.pid,
-               event->mmap.tid,
-               (void *)(long)event->mmap.start,
-               (void *)(long)event->mmap.len,
-               (void *)(long)event->mmap.pgoff,
-               event->mmap.filename);
-
-       if (thread == NULL || map == NULL) {
-               dump_printf("problem processing PERF_RECORD_MMAP, skipping event.\n");
+       if (sym_list && al.sym && !strlist__has_entry(sym_list, al.sym->name))
                return 0;
+
+       if (hist_entry__add(&al, chain, period)) {
+               pr_debug("problem incrementing symbol count, skipping event\n");
+               return -1;
        }
 
-       thread__insert_map(thread, map);
-       total_mmap++;
+       event__stats.total += period;
 
        return 0;
 }
 
-static int
-process_comm_event(event_t *event, unsigned long offset, unsigned long head)
+static int process_comm_event(event_t *event)
 {
-       struct thread *thread;
-
-       thread = threads__findnew(event->comm.pid, &threads, &last_match);
+       struct thread *thread = threads__findnew(event->comm.pid);
 
-       dump_printf("%p [%p]: PERF_RECORD_COMM: %s:%d\n",
-               (void *)(offset + head),
-               (void *)(long)(event->header.size),
-               event->comm.comm, event->comm.pid);
+       dump_printf(": %s:%d\n", event->comm.comm, event->comm.pid);
 
        if (thread == NULL ||
            thread__set_comm_adjust(thread, event->comm.comm)) {
                dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n");
                return -1;
        }
-       total_comm++;
-
-       return 0;
-}
-
-static int
-process_task_event(event_t *event, unsigned long offset, unsigned long head)
-{
-       struct thread *thread;
-       struct thread *parent;
-
-       thread = threads__findnew(event->fork.pid, &threads, &last_match);
-       parent = threads__findnew(event->fork.ppid, &threads, &last_match);
-
-       dump_printf("%p [%p]: PERF_RECORD_%s: (%d:%d):(%d:%d)\n",
-               (void *)(offset + head),
-               (void *)(long)(event->header.size),
-               event->header.type == PERF_RECORD_FORK ? "FORK" : "EXIT",
-               event->fork.pid, event->fork.tid,
-               event->fork.ppid, event->fork.ptid);
-
-       /*
-        * A thread clone will have the same PID for both
-        * parent and child.
-        */
-       if (thread == parent)
-               return 0;
-
-       if (event->header.type == PERF_RECORD_EXIT)
-               return 0;
-
-       if (!thread || !parent || thread__fork(thread, parent)) {
-               dump_printf("problem processing PERF_RECORD_FORK, skipping event.\n");
-               return -1;
-       }
-       total_fork++;
 
        return 0;
 }
 
-static int
-process_lost_event(event_t *event, unsigned long offset, unsigned long head)
-{
-       dump_printf("%p [%p]: PERF_RECORD_LOST: id:%Ld: lost:%Ld\n",
-               (void *)(offset + head),
-               (void *)(long)(event->header.size),
-               event->lost.id,
-               event->lost.lost);
-
-       total_lost += event->lost.lost;
-
-       return 0;
-}
-
-static int
-process_read_event(event_t *event, unsigned long offset, unsigned long head)
+static int process_read_event(event_t *event)
 {
        struct perf_event_attr *attr;
 
@@ -1319,238 +716,91 @@ process_read_event(event_t *event, unsigned long offset, unsigned long head)
                                           event->read.value);
        }
 
-       dump_printf("%p [%p]: PERF_RECORD_READ: %d %d %s %Lu\n",
-                       (void *)(offset + head),
-                       (void *)(long)(event->header.size),
-                       event->read.pid,
-                       event->read.tid,
-                       attr ? __event_name(attr->type, attr->config)
-                            : "FAIL",
-                       event->read.value);
-
-       return 0;
-}
-
-static int
-process_event(event_t *event, unsigned long offset, unsigned long head)
-{
-       trace_event(event);
-
-       switch (event->header.type) {
-       case PERF_RECORD_SAMPLE:
-               return process_sample_event(event, offset, head);
-
-       case PERF_RECORD_MMAP:
-               return process_mmap_event(event, offset, head);
-
-       case PERF_RECORD_COMM:
-               return process_comm_event(event, offset, head);
-
-       case PERF_RECORD_FORK:
-       case PERF_RECORD_EXIT:
-               return process_task_event(event, offset, head);
-
-       case PERF_RECORD_LOST:
-               return process_lost_event(event, offset, head);
-
-       case PERF_RECORD_READ:
-               return process_read_event(event, offset, head);
-
-       /*
-        * We dont process them right now but they are fine:
-        */
-
-       case PERF_RECORD_THROTTLE:
-       case PERF_RECORD_UNTHROTTLE:
-               return 0;
-
-       default:
-               return -1;
-       }
+       dump_printf(": %d %d %s %Lu\n", event->read.pid, event->read.tid,
+                   attr ? __event_name(attr->type, attr->config) : "FAIL",
+                   event->read.value);
 
        return 0;
 }
 
-static int __cmd_report(void)
+static int sample_type_check(u64 type)
 {
-       int ret, rc = EXIT_FAILURE;
-       unsigned long offset = 0;
-       unsigned long head, shift;
-       struct stat input_stat;
-       struct thread *idle;
-       event_t *event;
-       uint32_t size;
-       char *buf;
-
-       idle = register_idle_thread(&threads, &last_match);
-       thread__comm_adjust(idle);
-
-       if (show_threads)
-               perf_read_values_init(&show_threads_values);
-
-       input = open(input_name, O_RDONLY);
-       if (input < 0) {
-               fprintf(stderr, " failed to open file: %s", input_name);
-               if (!strcmp(input_name, "perf.data"))
-                       fprintf(stderr, "  (try 'perf record' first)");
-               fprintf(stderr, "\n");
-               exit(-1);
-       }
-
-       ret = fstat(input, &input_stat);
-       if (ret < 0) {
-               perror("failed to stat file");
-               exit(-1);
-       }
-
-       if (!force && input_stat.st_uid && (input_stat.st_uid != geteuid())) {
-               fprintf(stderr, "file: %s not owned by current user or root\n", input_name);
-               exit(-1);
-       }
-
-       if (!input_stat.st_size) {
-               fprintf(stderr, "zero-sized file, nothing to do!\n");
-               exit(0);
-       }
-
-       header = perf_header__read(input);
-       head = header->data_offset;
-
-       sample_type = perf_header__sample_type(header);
+       sample_type = type;
 
        if (!(sample_type & PERF_SAMPLE_CALLCHAIN)) {
                if (sort__has_parent) {
                        fprintf(stderr, "selected --sort parent, but no"
                                        " callchain data. Did you call"
                                        " perf record without -g?\n");
-                       exit(-1);
+                       return -1;
                }
                if (callchain) {
                        fprintf(stderr, "selected -g but no callchain data."
                                        " Did you call perf record without"
                                        " -g?\n");
-                       exit(-1);
+                       return -1;
                }
        } else if (callchain_param.mode != CHAIN_NONE && !callchain) {
                        callchain = 1;
                        if (register_callchain_param(&callchain_param) < 0) {
                                fprintf(stderr, "Can't register callchain"
                                                " params\n");
-                               exit(-1);
+                               return -1;
                        }
        }
 
-       if (load_kernel() < 0) {
-               perror("failed to load kernel symbols");
-               return EXIT_FAILURE;
-       }
-
-       if (!full_paths) {
-               if (getcwd(__cwd, sizeof(__cwd)) == NULL) {
-                       perror("failed to get the current directory");
-                       return EXIT_FAILURE;
-               }
-               cwdlen = strlen(cwd);
-       } else {
-               cwd = NULL;
-               cwdlen = 0;
-       }
-
-       shift = page_size * (head / page_size);
-       offset += shift;
-       head -= shift;
-
-remap:
-       buf = (char *)mmap(NULL, page_size * mmap_window, PROT_READ,
-                          MAP_SHARED, input, offset);
-       if (buf == MAP_FAILED) {
-               perror("failed to mmap file");
-               exit(-1);
-       }
-
-more:
-       event = (event_t *)(buf + head);
-
-       size = event->header.size;
-       if (!size)
-               size = 8;
-
-       if (head + event->header.size >= page_size * mmap_window) {
-               int munmap_ret;
-
-               shift = page_size * (head / page_size);
-
-               munmap_ret = munmap(buf, page_size * mmap_window);
-               assert(munmap_ret == 0);
-
-               offset += shift;
-               head -= shift;
-               goto remap;
-       }
-
-       size = event->header.size;
-
-       dump_printf("\n%p [%p]: event: %d\n",
-                       (void *)(offset + head),
-                       (void *)(long)event->header.size,
-                       event->header.type);
-
-       if (!size || process_event(event, offset, head) < 0) {
-
-               dump_printf("%p [%p]: skipping unknown header type: %d\n",
-                       (void *)(offset + head),
-                       (void *)(long)(event->header.size),
-                       event->header.type);
-
-               total_unknown++;
-
-               /*
-                * assume we lost track of the stream, check alignment, and
-                * increment a single u64 in the hope to catch on again 'soon'.
-                */
+       return 0;
+}
 
-               if (unlikely(head & 7))
-                       head &= ~7ULL;
+static struct perf_file_handler file_handler = {
+       .process_sample_event   = process_sample_event,
+       .process_mmap_event     = event__process_mmap,
+       .process_comm_event     = process_comm_event,
+       .process_exit_event     = event__process_task,
+       .process_fork_event     = event__process_task,
+       .process_lost_event     = event__process_lost,
+       .process_read_event     = process_read_event,
+       .sample_type_check      = sample_type_check,
+};
 
-               size = 8;
-       }
 
-       head += size;
+static int __cmd_report(void)
+{
+       struct thread *idle;
+       int ret;
 
-       if (offset + head >= header->data_offset + header->data_size)
-               goto done;
+       idle = register_idle_thread();
+       thread__comm_adjust(idle);
 
-       if (offset + head < (unsigned long)input_stat.st_size)
-               goto more;
+       if (show_threads)
+               perf_read_values_init(&show_threads_values);
 
-done:
-       rc = EXIT_SUCCESS;
-       close(input);
+       register_perf_file_handler(&file_handler);
 
-       dump_printf("      IP events: %10ld\n", total);
-       dump_printf("    mmap events: %10ld\n", total_mmap);
-       dump_printf("    comm events: %10ld\n", total_comm);
-       dump_printf("    fork events: %10ld\n", total_fork);
-       dump_printf("    lost events: %10ld\n", total_lost);
-       dump_printf(" unknown events: %10ld\n", total_unknown);
+       ret = mmap_dispatch_perf_file(&header, input_name, force,
+                                     full_paths, &event__cwdlen, &event__cwd);
+       if (ret)
+               return ret;
 
-       if (dump_trace)
+       if (dump_trace) {
+               event__print_totals();
                return 0;
+       }
 
-       if (verbose >= 3)
-               threads__fprintf(stdout, &threads);
+       if (verbose > 3)
+               threads__fprintf(stdout);
 
-       if (verbose >= 2)
+       if (verbose > 2)
                dsos__fprintf(stdout);
 
        collapse__resort();
-       output__resort(total);
-       output__fprintf(stdout, total);
+       output__resort(event__stats.total);
+       output__fprintf(stdout, event__stats.total);
 
        if (show_threads)
                perf_read_values_destroy(&show_threads_values);
 
-       return rc;
+       return ret;
 }
 
 static int
@@ -1606,7 +856,8 @@ setup:
        return 0;
 }
 
-static const char * const report_usage[] = {
+//static const char * const report_usage[] = {
+const char * const report_usage[] = {
        "perf report [<options>] <command>",
        NULL
 };
@@ -1618,9 +869,10 @@ static const struct option options[] = {
                    "be more verbose (show symbol address, etc)"),
        OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
                    "dump raw trace in ASCII"),
-       OPT_STRING('k', "vmlinux", &vmlinux_name, "file", "vmlinux pathname"),
+       OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
+                  "file", "vmlinux pathname"),
        OPT_BOOLEAN('f', "force", &force, "don't complain, do it"),
-       OPT_BOOLEAN('m', "modules", &modules,
+       OPT_BOOLEAN('m', "modules", &symbol_conf.use_modules,
                    "load module symbols - WARNING: use only with -k and LIVE kernel"),
        OPT_BOOLEAN('n', "show-nr-samples", &show_nr_samples,
                    "Show a column with the number of samples"),
@@ -1690,9 +942,8 @@ static void setup_list(struct strlist **list, const char *list_str,
 
 int cmd_report(int argc, const char **argv, const char *prefix __used)
 {
-       symbol__init();
-
-       page_size = getpagesize();
+       if (symbol__init(&symbol_conf) < 0)
+               return -1;
 
        argc = parse_options(argc, argv, options, report_usage, 0);
 
index ce2d5be..26b782f 100644 (file)
@@ -11,6 +11,7 @@
 #include "util/trace-event.h"
 
 #include "util/debug.h"
+#include "util/data_map.h"
 
 #include <sys/types.h>
 #include <sys/prctl.h>
 #include <math.h>
 
 static char                    const *input_name = "perf.data";
-static int                     input;
-static unsigned long           page_size;
-static unsigned long           mmap_window = 32;
-
-static unsigned long           total_comm = 0;
-
-static struct rb_root          threads;
-static struct thread           *last_match;
 
 static struct perf_header      *header;
 static u64                     sample_type;
@@ -35,11 +28,11 @@ static u64                  sample_type;
 static char                    default_sort_order[] = "avg, max, switch, runtime";
 static char                    *sort_order = default_sort_order;
 
+static int                     profile_cpu = -1;
+
 #define PR_SET_NAME            15               /* Set process name */
 #define MAX_CPUS               4096
 
-#define BUG_ON(x)              assert(!(x))
-
 static u64                     run_measurement_overhead;
 static u64                     sleep_measurement_overhead;
 
@@ -74,6 +67,7 @@ enum sched_event_type {
        SCHED_EVENT_RUN,
        SCHED_EVENT_SLEEP,
        SCHED_EVENT_WAKEUP,
+       SCHED_EVENT_MIGRATION,
 };
 
 struct sched_atom {
@@ -226,7 +220,7 @@ static void calibrate_sleep_measurement_overhead(void)
 static struct sched_atom *
 get_new_event(struct task_desc *task, u64 timestamp)
 {
-       struct sched_atom *event = calloc(1, sizeof(*event));
+       struct sched_atom *event = zalloc(sizeof(*event));
        unsigned long idx = task->nr_events;
        size_t size;
 
@@ -294,7 +288,7 @@ add_sched_event_wakeup(struct task_desc *task, u64 timestamp,
                return;
        }
 
-       wakee_event->wait_sem = calloc(1, sizeof(*wakee_event->wait_sem));
+       wakee_event->wait_sem = zalloc(sizeof(*wakee_event->wait_sem));
        sem_init(wakee_event->wait_sem, 0, 0);
        wakee_event->specific_wait = 1;
        event->wait_sem = wakee_event->wait_sem;
@@ -324,7 +318,7 @@ static struct task_desc *register_pid(unsigned long pid, const char *comm)
        if (task)
                return task;
 
-       task = calloc(1, sizeof(*task));
+       task = zalloc(sizeof(*task));
        task->pid = pid;
        task->nr = nr_tasks;
        strcpy(task->comm, comm);
@@ -398,6 +392,8 @@ process_sched_event(struct task_desc *this_task __used, struct sched_atom *atom)
                                ret = sem_post(atom->wait_sem);
                        BUG_ON(ret);
                        break;
+               case SCHED_EVENT_MIGRATION:
+                       break;
                default:
                        BUG_ON(1);
        }
@@ -632,29 +628,6 @@ static void test_calibrations(void)
        printf("the sleep test took %Ld nsecs\n", T1-T0);
 }
 
-static int
-process_comm_event(event_t *event, unsigned long offset, unsigned long head)
-{
-       struct thread *thread;
-
-       thread = threads__findnew(event->comm.pid, &threads, &last_match);
-
-       dump_printf("%p [%p]: perf_event_comm: %s:%d\n",
-               (void *)(offset + head),
-               (void *)(long)(event->header.size),
-               event->comm.comm, event->comm.pid);
-
-       if (thread == NULL ||
-           thread__set_comm(thread, event->comm.comm)) {
-               dump_printf("problem processing perf_event_comm, skipping event.\n");
-               return -1;
-       }
-       total_comm++;
-
-       return 0;
-}
-
-
 struct raw_event_sample {
        u32 size;
        char data[0];
@@ -745,6 +718,22 @@ struct trace_fork_event {
        u32 child_pid;
 };
 
+struct trace_migrate_task_event {
+       u32 size;
+
+       u16 common_type;
+       u8 common_flags;
+       u8 common_preempt_count;
+       u32 common_pid;
+       u32 common_tgid;
+
+       char comm[16];
+       u32 pid;
+
+       u32 prio;
+       u32 cpu;
+};
+
 struct trace_sched_handler {
        void (*switch_event)(struct trace_switch_event *,
                             struct event *,
@@ -769,6 +758,12 @@ struct trace_sched_handler {
                           int cpu,
                           u64 timestamp,
                           struct thread *thread);
+
+       void (*migrate_task_event)(struct trace_migrate_task_event *,
+                          struct event *,
+                          int cpu,
+                          u64 timestamp,
+                          struct thread *thread);
 };
 
 
@@ -941,9 +936,7 @@ __thread_latency_insert(struct rb_root *root, struct work_atoms *data,
 
 static void thread_atoms_insert(struct thread *thread)
 {
-       struct work_atoms *atoms;
-
-       atoms = calloc(sizeof(*atoms), 1);
+       struct work_atoms *atoms = zalloc(sizeof(*atoms));
        if (!atoms)
                die("No memory");
 
@@ -975,9 +968,7 @@ add_sched_out_event(struct work_atoms *atoms,
                    char run_state,
                    u64 timestamp)
 {
-       struct work_atom *atom;
-
-       atom = calloc(sizeof(*atom), 1);
+       struct work_atom *atom = zalloc(sizeof(*atom));
        if (!atom)
                die("Non memory");
 
@@ -1058,8 +1049,8 @@ latency_switch_event(struct trace_switch_event *switch_event,
                die("hm, delta: %Ld < 0 ?\n", delta);
 
 
-       sched_out = threads__findnew(switch_event->prev_pid, &threads, &last_match);
-       sched_in = threads__findnew(switch_event->next_pid, &threads, &last_match);
+       sched_out = threads__findnew(switch_event->prev_pid);
+       sched_in = threads__findnew(switch_event->next_pid);
 
        out_events = thread_atoms_search(&atom_root, sched_out, &cmp_pid);
        if (!out_events) {
@@ -1092,13 +1083,10 @@ latency_runtime_event(struct trace_runtime_event *runtime_event,
                     u64 timestamp,
                     struct thread *this_thread __used)
 {
-       struct work_atoms *atoms;
-       struct thread *thread;
+       struct thread *thread = threads__findnew(runtime_event->pid);
+       struct work_atoms *atoms = thread_atoms_search(&atom_root, thread, &cmp_pid);
 
        BUG_ON(cpu >= MAX_CPUS || cpu < 0);
-
-       thread = threads__findnew(runtime_event->pid, &threads, &last_match);
-       atoms = thread_atoms_search(&atom_root, thread, &cmp_pid);
        if (!atoms) {
                thread_atoms_insert(thread);
                atoms = thread_atoms_search(&atom_root, thread, &cmp_pid);
@@ -1125,7 +1113,7 @@ latency_wakeup_event(struct trace_wakeup_event *wakeup_event,
        if (!wakeup_event->success)
                return;
 
-       wakee = threads__findnew(wakeup_event->pid, &threads, &last_match);
+       wakee = threads__findnew(wakeup_event->pid);
        atoms = thread_atoms_search(&atom_root, wakee, &cmp_pid);
        if (!atoms) {
                thread_atoms_insert(wakee);
@@ -1139,7 +1127,12 @@ latency_wakeup_event(struct trace_wakeup_event *wakeup_event,
 
        atom = list_entry(atoms->work_list.prev, struct work_atom, list);
 
-       if (atom->state != THREAD_SLEEPING)
+       /*
+        * You WILL be missing events if you've recorded only
+        * one CPU, or are only looking at only one, so don't
+        * make useless noise.
+        */
+       if (profile_cpu == -1 && atom->state != THREAD_SLEEPING)
                nr_state_machine_bugs++;
 
        nr_timestamps++;
@@ -1152,11 +1145,51 @@ latency_wakeup_event(struct trace_wakeup_event *wakeup_event,
        atom->wake_up_time = timestamp;
 }
 
+static void
+latency_migrate_task_event(struct trace_migrate_task_event *migrate_task_event,
+                    struct event *__event __used,
+                    int cpu __used,
+                    u64 timestamp,
+                    struct thread *thread __used)
+{
+       struct work_atoms *atoms;
+       struct work_atom *atom;
+       struct thread *migrant;
+
+       /*
+        * Only need to worry about migration when profiling one CPU.
+        */
+       if (profile_cpu == -1)
+               return;
+
+       migrant = threads__findnew(migrate_task_event->pid);
+       atoms = thread_atoms_search(&atom_root, migrant, &cmp_pid);
+       if (!atoms) {
+               thread_atoms_insert(migrant);
+               register_pid(migrant->pid, migrant->comm);
+               atoms = thread_atoms_search(&atom_root, migrant, &cmp_pid);
+               if (!atoms)
+                       die("migration-event: Internal tree error");
+               add_sched_out_event(atoms, 'R', timestamp);
+       }
+
+       BUG_ON(list_empty(&atoms->work_list));
+
+       atom = list_entry(atoms->work_list.prev, struct work_atom, list);
+       atom->sched_in_time = atom->sched_out_time = atom->wake_up_time = timestamp;
+
+       nr_timestamps++;
+
+       if (atom->sched_out_time > timestamp)
+               nr_unordered_timestamps++;
+}
+
 static struct trace_sched_handler lat_ops  = {
        .wakeup_event           = latency_wakeup_event,
        .switch_event           = latency_switch_event,
        .runtime_event          = latency_runtime_event,
        .fork_event             = latency_fork_event,
+       .migrate_task_event     = latency_migrate_task_event,
 };
 
 static void output_lat_thread(struct work_atoms *work_list)
@@ -1385,8 +1418,8 @@ map_switch_event(struct trace_switch_event *switch_event,
                die("hm, delta: %Ld < 0 ?\n", delta);
 
 
-       sched_out = threads__findnew(switch_event->prev_pid, &threads, &last_match);
-       sched_in = threads__findnew(switch_event->next_pid, &threads, &last_match);
+       sched_out = threads__findnew(switch_event->prev_pid);
+       sched_in = threads__findnew(switch_event->next_pid);
 
        curr_thread[this_cpu] = sched_in;
 
@@ -1517,6 +1550,26 @@ process_sched_exit_event(struct event *event,
 }
 
 static void
+process_sched_migrate_task_event(struct raw_event_sample *raw,
+                          struct event *event,
+                          int cpu __used,
+                          u64 timestamp __used,
+                          struct thread *thread __used)
+{
+       struct trace_migrate_task_event migrate_task_event;
+
+       FILL_COMMON_FIELDS(migrate_task_event, event, raw->data);
+
+       FILL_ARRAY(migrate_task_event, comm, event, raw->data);
+       FILL_FIELD(migrate_task_event, pid, event, raw->data);
+       FILL_FIELD(migrate_task_event, prio, event, raw->data);
+       FILL_FIELD(migrate_task_event, cpu, event, raw->data);
+
+       if (trace_handler->migrate_task_event)
+               trace_handler->migrate_task_event(&migrate_task_event, event, cpu, timestamp, thread);
+}
+
+static void
 process_raw_event(event_t *raw_event __used, void *more_data,
                  int cpu, u64 timestamp, struct thread *thread)
 {
@@ -1539,23 +1592,23 @@ process_raw_event(event_t *raw_event __used, void *more_data,
                process_sched_fork_event(raw, event, cpu, timestamp, thread);
        if (!strcmp(event->name, "sched_process_exit"))
                process_sched_exit_event(event, cpu, timestamp, thread);
+       if (!strcmp(event->name, "sched_migrate_task"))
+               process_sched_migrate_task_event(raw, event, cpu, timestamp, thread);
 }
 
-static int
-process_sample_event(event_t *event, unsigned long offset, unsigned long head)
+static int process_sample_event(event_t *event)
 {
-       char level;
-       int show = 0;
-       struct dso *dso = NULL;
        struct thread *thread;
        u64 ip = event->ip.ip;
        u64 timestamp = -1;
        u32 cpu = -1;
        u64 period = 1;
        void *more_data = event->ip.__more_data;
-       int cpumode;
 
-       thread = threads__findnew(event->ip.pid, &threads, &last_match);
+       if (!(sample_type & PERF_SAMPLE_RAW))
+               return 0;
+
+       thread = threads__findnew(event->ip.pid);
 
        if (sample_type & PERF_SAMPLE_TIME) {
                timestamp = *(u64 *)more_data;
@@ -1573,177 +1626,64 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head)
                more_data += sizeof(u64);
        }
 
-       dump_printf("%p [%p]: PERF_RECORD_SAMPLE (IP, %d): %d/%d: %p period: %Ld\n",
-               (void *)(offset + head),
-               (void *)(long)(event->header.size),
+       dump_printf("(IP, %d): %d/%d: %p period: %Ld\n",
                event->header.misc,
                event->ip.pid, event->ip.tid,
                (void *)(long)ip,
                (long long)period);
 
-       dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid);
-
        if (thread == NULL) {
-               eprintf("problem processing %d event, skipping it.\n",
-                       event->header.type);
+               pr_debug("problem processing %d event, skipping it.\n",
+                        event->header.type);
                return -1;
        }
 
-       cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
-
-       if (cpumode == PERF_RECORD_MISC_KERNEL) {
-               show = SHOW_KERNEL;
-               level = 'k';
-
-               dso = kernel_dso;
-
-               dump_printf(" ...... dso: %s\n", dso->name);
-
-       } else if (cpumode == PERF_RECORD_MISC_USER) {
-
-               show = SHOW_USER;
-               level = '.';
-
-       } else {
-               show = SHOW_HV;
-               level = 'H';
-
-               dso = hypervisor_dso;
+       dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid);
 
-               dump_printf(" ...... dso: [hypervisor]\n");
-       }
+       if (profile_cpu != -1 && profile_cpu != (int) cpu)
+               return 0;
 
-       if (sample_type & PERF_SAMPLE_RAW)
-               process_raw_event(event, more_data, cpu, timestamp, thread);
+       process_raw_event(event, more_data, cpu, timestamp, thread);
 
        return 0;
 }
 
-static int
-process_event(event_t *event, unsigned long offset, unsigned long head)
+static int process_lost_event(event_t *event __used)
 {
-       trace_event(event);
-
-       nr_events++;
-       switch (event->header.type) {
-       case PERF_RECORD_MMAP:
-               return 0;
-       case PERF_RECORD_LOST:
-               nr_lost_chunks++;
-               nr_lost_events += event->lost.lost;
-               return 0;
-
-       case PERF_RECORD_COMM:
-               return process_comm_event(event, offset, head);
+       nr_lost_chunks++;
+       nr_lost_events += event->lost.lost;
 
-       case PERF_RECORD_EXIT ... PERF_RECORD_READ:
-               return 0;
+       return 0;
+}
 
-       case PERF_RECORD_SAMPLE:
-               return process_sample_event(event, offset, head);
+static int sample_type_check(u64 type)
+{
+       sample_type = type;
 
-       case PERF_RECORD_MAX:
-       default:
+       if (!(sample_type & PERF_SAMPLE_RAW)) {
+               fprintf(stderr,
+                       "No trace sample to read. Did you call perf record "
+                       "without -R?");
                return -1;
        }
 
        return 0;
 }
 
+static struct perf_file_handler file_handler = {
+       .process_sample_event   = process_sample_event,
+       .process_comm_event     = event__process_comm,
+       .process_lost_event     = process_lost_event,
+       .sample_type_check      = sample_type_check,
+};
+
 static int read_events(void)
 {
-       int ret, rc = EXIT_FAILURE;
-       unsigned long offset = 0;
-       unsigned long head = 0;
-       struct stat perf_stat;
-       event_t *event;
-       uint32_t size;
-       char *buf;
-
-       trace_report();
-       register_idle_thread(&threads, &last_match);
-
-       input = open(input_name, O_RDONLY);
-       if (input < 0) {
-               perror("failed to open file");
-               exit(-1);
-       }
-
-       ret = fstat(input, &perf_stat);
-       if (ret < 0) {
-               perror("failed to stat file");
-               exit(-1);
-       }
-
-       if (!perf_stat.st_size) {
-               fprintf(stderr, "zero-sized file, nothing to do!\n");
-               exit(0);
-       }
-       header = perf_header__read(input);
-       head = header->data_offset;
-       sample_type = perf_header__sample_type(header);
-
-       if (!(sample_type & PERF_SAMPLE_RAW))
-               die("No trace sample to read. Did you call perf record "
-                   "without -R?");
-
-       if (load_kernel() < 0) {
-               perror("failed to load kernel symbols");
-               return EXIT_FAILURE;
-       }
-
-remap:
-       buf = (char *)mmap(NULL, page_size * mmap_window, PROT_READ,
-                          MAP_SHARED, input, offset);
-       if (buf == MAP_FAILED) {
-               perror("failed to mmap file");
-               exit(-1);
-       }
-
-more:
-       event = (event_t *)(buf + head);
-
-       size = event->header.size;
-       if (!size)
-               size = 8;
-
-       if (head + event->header.size >= page_size * mmap_window) {
-               unsigned long shift = page_size * (head / page_size);
-               int res;
-
-               res = munmap(buf, page_size * mmap_window);
-               assert(res == 0);
-
-               offset += shift;
-               head -= shift;
-               goto remap;
-       }
-
-       size = event->header.size;
-
-
-       if (!size || process_event(event, offset, head) < 0) {
-
-               /*
-                * assume we lost track of the stream, check alignment, and
-                * increment a single u64 in the hope to catch on again 'soon'.
-                */
-
-               if (unlikely(head & 7))
-                       head &= ~7ULL;
-
-               size = 8;
-       }
-
-       head += size;
-
-       if (offset + head < (unsigned long)perf_stat.st_size)
-               goto more;
-
-       rc = EXIT_SUCCESS;
-       close(input);
+       register_idle_thread();
+       register_perf_file_handler(&file_handler);
 
-       return rc;
+       return mmap_dispatch_perf_file(&header, input_name, 0, 0,
+                                      &event__cwdlen, &event__cwd);
 }
 
 static void print_bad_events(void)
@@ -1883,6 +1823,8 @@ static const struct option latency_options[] = {
                   "sort by key(s): runtime, switch, avg, max"),
        OPT_BOOLEAN('v', "verbose", &verbose,
                    "be more verbose (show symbol address, etc)"),
+       OPT_INTEGER('C', "CPU", &profile_cpu,
+                   "CPU to profile on"),
        OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
                    "dump raw trace in ASCII"),
        OPT_END()
@@ -1960,8 +1902,7 @@ static int __cmd_record(int argc, const char **argv)
 
 int cmd_sched(int argc, const char **argv, const char *prefix __used)
 {
-       symbol__init();
-       page_size = getpagesize();
+       symbol__init(0);
 
        argc = parse_options(argc, argv, sched_options, sched_usage,
                             PARSE_OPT_STOP_AT_NON_OPTION);
index 3db31e7..c70d720 100644 (file)
 
 static struct perf_event_attr default_attrs[] = {
 
-  { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_TASK_CLOCK     },
-  { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_CONTEXT_SWITCHES},
-  { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_CPU_MIGRATIONS },
-  { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_PAGE_FAULTS    },
-
-  { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_CPU_CYCLES     },
-  { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_INSTRUCTIONS   },
-  { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_CACHE_REFERENCES},
-  { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_CACHE_MISSES   },
+  { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_TASK_CLOCK             },
+  { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_CONTEXT_SWITCHES       },
+  { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_CPU_MIGRATIONS         },
+  { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_PAGE_FAULTS            },
+
+  { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_CPU_CYCLES             },
+  { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_INSTRUCTIONS           },
+  { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_BRANCH_INSTRUCTIONS    },
+  { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_BRANCH_MISSES          },
+  { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_CACHE_REFERENCES       },
+  { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_CACHE_MISSES           },
 
 };
 
@@ -125,6 +127,7 @@ struct stats                        event_res_stats[MAX_COUNTERS][3];
 struct stats                   runtime_nsecs_stats;
 struct stats                   walltime_nsecs_stats;
 struct stats                   runtime_cycles_stats;
+struct stats                   runtime_branches_stats;
 
 #define MATCH_EVENT(t, c, counter)                     \
        (attrs[counter].type == PERF_TYPE_##t &&        \
@@ -235,6 +238,8 @@ static void read_counter(int counter)
                update_stats(&runtime_nsecs_stats, count[0]);
        if (MATCH_EVENT(HARDWARE, HW_CPU_CYCLES, counter))
                update_stats(&runtime_cycles_stats, count[0]);
+       if (MATCH_EVENT(HARDWARE, HW_BRANCH_INSTRUCTIONS, counter))
+               update_stats(&runtime_branches_stats, count[0]);
 }
 
 static int run_perf_stat(int argc __used, const char **argv)
@@ -352,7 +357,16 @@ static void abs_printout(int counter, double avg)
                        ratio = avg / total;
 
                fprintf(stderr, " # %10.3f IPC  ", ratio);
-       } else {
+       } else if (MATCH_EVENT(HARDWARE, HW_BRANCH_MISSES, counter) &&
+                       runtime_branches_stats.n != 0) {
+               total = avg_stats(&runtime_branches_stats);
+
+               if (total)
+                       ratio = avg * 100 / total;
+
+               fprintf(stderr, " # %10.3f %%    ", ratio);
+
+       } else if (runtime_nsecs_stats.n != 0) {
                total = avg_stats(&runtime_nsecs_stats);
 
                if (total)
index e8a510d..cb58b66 100644 (file)
 #include "util/header.h"
 #include "util/parse-options.h"
 #include "util/parse-events.h"
+#include "util/event.h"
+#include "util/data_map.h"
 #include "util/svghelper.h"
 
 static char            const *input_name = "perf.data";
 static char            const *output_name = "output.svg";
 
 
-static unsigned long   page_size;
-static unsigned long   mmap_window = 32;
 static u64             sample_type;
 
 static unsigned int    numcpus;
@@ -49,8 +49,6 @@ static u64            first_time, last_time;
 static int             power_only;
 
 
-static struct perf_header      *header;
-
 struct per_pid;
 struct per_pidcomm;
 
@@ -153,6 +151,17 @@ static struct wake_event     *wake_events;
 
 struct sample_wrapper *all_samples;
 
+
+struct process_filter;
+struct process_filter {
+       char                    *name;
+       int                     pid;
+       struct process_filter   *next;
+};
+
+static struct process_filter *process_filter;
+
+
 static struct per_pid *find_create_pid(int pid)
 {
        struct per_pid *cursor = all_data;
@@ -763,11 +772,11 @@ static void draw_wakeups(void)
                                c = p->all;
                                while (c) {
                                        if (c->Y && c->start_time <= we->time && c->end_time >= we->time) {
-                                               if (p->pid == we->waker) {
+                                               if (p->pid == we->waker && !from) {
                                                        from = c->Y;
                                                        task_from = strdup(c->comm);
                                                }
-                                               if (p->pid == we->wakee) {
+                                               if (p->pid == we->wakee && !to) {
                                                        to = c->Y;
                                                        task_to = strdup(c->comm);
                                                }
@@ -882,12 +891,89 @@ static void draw_process_bars(void)
        }
 }
 
+static void add_process_filter(const char *string)
+{
+       struct process_filter *filt;
+       int pid;
+
+       pid = strtoull(string, NULL, 10);
+       filt = malloc(sizeof(struct process_filter));
+       if (!filt)
+               return;
+
+       filt->name = strdup(string);
+       filt->pid  = pid;
+       filt->next = process_filter;
+
+       process_filter = filt;
+}
+
+static int passes_filter(struct per_pid *p, struct per_pidcomm *c)
+{
+       struct process_filter *filt;
+       if (!process_filter)
+               return 1;
+
+       filt = process_filter;
+       while (filt) {
+               if (filt->pid && p->pid == filt->pid)
+                       return 1;
+               if (strcmp(filt->name, c->comm) == 0)
+                       return 1;
+               filt = filt->next;
+       }
+       return 0;
+}
+
+static int determine_display_tasks_filtered(void)
+{
+       struct per_pid *p;
+       struct per_pidcomm *c;
+       int count = 0;
+
+       p = all_data;
+       while (p) {
+               p->display = 0;
+               if (p->start_time == 1)
+                       p->start_time = first_time;
+
+               /* no exit marker, task kept running to the end */
+               if (p->end_time == 0)
+                       p->end_time = last_time;
+
+               c = p->all;
+
+               while (c) {
+                       c->display = 0;
+
+                       if (c->start_time == 1)
+                               c->start_time = first_time;
+
+                       if (passes_filter(p, c)) {
+                               c->display = 1;
+                               p->display = 1;
+                               count++;
+                       }
+
+                       if (c->end_time == 0)
+                               c->end_time = last_time;
+
+                       c = c->next;
+               }
+               p = p->next;
+       }
+       return count;
+}
+
 static int determine_display_tasks(u64 threshold)
 {
        struct per_pid *p;
        struct per_pidcomm *c;
        int count = 0;
 
+       if (process_filter)
+               return determine_display_tasks_filtered();
+
        p = all_data;
        while (p) {
                p->display = 0;
@@ -957,36 +1043,6 @@ static void write_svg_file(const char *filename)
        svg_close();
 }
 
-static int
-process_event(event_t *event)
-{
-
-       switch (event->header.type) {
-
-       case PERF_RECORD_COMM:
-               return process_comm_event(event);
-       case PERF_RECORD_FORK:
-               return process_fork_event(event);
-       case PERF_RECORD_EXIT:
-               return process_exit_event(event);
-       case PERF_RECORD_SAMPLE:
-               return queue_sample_event(event);
-
-       /*
-        * We dont process them right now but they are fine:
-        */
-       case PERF_RECORD_MMAP:
-       case PERF_RECORD_THROTTLE:
-       case PERF_RECORD_UNTHROTTLE:
-               return 0;
-
-       default:
-               return -1;
-       }
-
-       return 0;
-}
-
 static void process_samples(void)
 {
        struct sample_wrapper *cursor;
@@ -1002,107 +1058,38 @@ static void process_samples(void)
        }
 }
 
-
-static int __cmd_timechart(void)
+static int sample_type_check(u64 type)
 {
-       int ret, rc = EXIT_FAILURE;
-       unsigned long offset = 0;
-       unsigned long head, shift;
-       struct stat statbuf;
-       event_t *event;
-       uint32_t size;
-       char *buf;
-       int input;
-
-       input = open(input_name, O_RDONLY);
-       if (input < 0) {
-               fprintf(stderr, " failed to open file: %s", input_name);
-               if (!strcmp(input_name, "perf.data"))
-                       fprintf(stderr, "  (try 'perf record' first)");
-               fprintf(stderr, "\n");
-               exit(-1);
-       }
-
-       ret = fstat(input, &statbuf);
-       if (ret < 0) {
-               perror("failed to stat file");
-               exit(-1);
-       }
-
-       if (!statbuf.st_size) {
-               fprintf(stderr, "zero-sized file, nothing to do!\n");
-               exit(0);
-       }
-
-       header = perf_header__read(input);
-       head = header->data_offset;
-
-       sample_type = perf_header__sample_type(header);
+       sample_type = type;
 
-       shift = page_size * (head / page_size);
-       offset += shift;
-       head -= shift;
-
-remap:
-       buf = (char *)mmap(NULL, page_size * mmap_window, PROT_READ,
-                          MAP_SHARED, input, offset);
-       if (buf == MAP_FAILED) {
-               perror("failed to mmap file");
-               exit(-1);
-       }
-
-more:
-       event = (event_t *)(buf + head);
-
-       size = event->header.size;
-       if (!size)
-               size = 8;
-
-       if (head + event->header.size >= page_size * mmap_window) {
-               int ret2;
-
-               shift = page_size * (head / page_size);
-
-               ret2 = munmap(buf, page_size * mmap_window);
-               assert(ret2 == 0);
-
-               offset += shift;
-               head -= shift;
-               goto remap;
-       }
-
-       size = event->header.size;
-
-       if (!size || process_event(event) < 0) {
-
-               printf("%p [%p]: skipping unknown header type: %d\n",
-                       (void *)(offset + head),
-                       (void *)(long)(event->header.size),
-                       event->header.type);
-
-               /*
-                * assume we lost track of the stream, check alignment, and
-                * increment a single u64 in the hope to catch on again 'soon'.
-                */
-
-               if (unlikely(head & 7))
-                       head &= ~7ULL;
-
-               size = 8;
+       if (!(sample_type & PERF_SAMPLE_RAW)) {
+               fprintf(stderr, "No trace samples found in the file.\n"
+                               "Have you used 'perf timechart record' to record it?\n");
+               return -1;
        }
 
-       head += size;
+       return 0;
+}
 
-       if (offset + head >= header->data_offset + header->data_size)
-               goto done;
+static struct perf_file_handler file_handler = {
+       .process_comm_event     = process_comm_event,
+       .process_fork_event     = process_fork_event,
+       .process_exit_event     = process_exit_event,
+       .process_sample_event   = queue_sample_event,
+       .sample_type_check      = sample_type_check,
+};
 
-       if (offset + head < (unsigned long)statbuf.st_size)
-               goto more;
+static int __cmd_timechart(void)
+{
+       struct perf_header *header;
+       int ret;
 
-done:
-       rc = EXIT_SUCCESS;
-       close(input);
+       register_perf_file_handler(&file_handler);
 
+       ret = mmap_dispatch_perf_file(&header, input_name, 0, 0,
+                                     &event__cwdlen, &event__cwd);
+       if (ret)
+               return EXIT_FAILURE;
 
        process_samples();
 
@@ -1112,9 +1099,10 @@ done:
 
        write_svg_file(output_name);
 
-       printf("Written %2.1f seconds of trace to %s.\n", (last_time - first_time) / 1000000000.0, output_name);
+       pr_info("Written %2.1f seconds of trace to %s.\n",
+               (last_time - first_time) / 1000000000.0, output_name);
 
-       return rc;
+       return EXIT_SUCCESS;
 }
 
 static const char * const timechart_usage[] = {
@@ -1153,6 +1141,14 @@ static int __cmd_record(int argc, const char **argv)
        return cmd_record(i, rec_argv, NULL);
 }
 
+static int
+parse_process(const struct option *opt __used, const char *arg, int __used unset)
+{
+       if (arg)
+               add_process_filter(arg);
+       return 0;
+}
+
 static const struct option options[] = {
        OPT_STRING('i', "input", &input_name, "file",
                    "input file name"),
@@ -1160,17 +1156,18 @@ static const struct option options[] = {
                    "output file name"),
        OPT_INTEGER('w', "width", &svg_page_width,
                    "page width"),
-       OPT_BOOLEAN('p', "power-only", &power_only,
+       OPT_BOOLEAN('P', "power-only", &power_only,
                    "output power data only"),
+       OPT_CALLBACK('p', "process", NULL, "process",
+                     "process selector. Pass a pid or process name.",
+                      parse_process),
        OPT_END()
 };
 
 
 int cmd_timechart(int argc, const char **argv, const char *prefix __used)
 {
-       symbol__init();
-
-       page_size = getpagesize();
+       symbol__init(0);
 
        argc = parse_options(argc, argv, options, timechart_usage,
                        PARSE_OPT_STOP_AT_NON_OPTION);
index e23bc74..e0a374d 100644 (file)
@@ -22,6 +22,7 @@
 
 #include "util/symbol.h"
 #include "util/color.h"
+#include "util/thread.h"
 #include "util/util.h"
 #include <linux/rbtree.h>
 #include "util/parse-options.h"
 
 static int                     fd[MAX_NR_CPUS][MAX_COUNTERS];
 
-static int                     system_wide                     =  0;
+static int                     system_wide                     =      0;
 
-static int                     default_interval                = 100000;
+static int                     default_interval                =      0;
 
-static int                     count_filter                    =  5;
-static int                     print_entries                   = 15;
+static int                     count_filter                    =      5;
+static int                     print_entries;
 
-static int                     target_pid                      = -1;
-static int                     inherit                         =  0;
-static int                     profile_cpu                     = -1;
-static int                     nr_cpus                         =  0;
-static unsigned int            realtime_prio                   =  0;
-static int                     group                           =  0;
+static int                     target_pid                      =     -1;
+static int                     inherit                         =      0;
+static int                     profile_cpu                     =     -1;
+static int                     nr_cpus                         =      0;
+static unsigned int            realtime_prio                   =      0;
+static int                     group                           =      0;
 static unsigned int            page_size;
-static unsigned int            mmap_pages                      = 16;
-static int                     freq                            =  0;
+static unsigned int            mmap_pages                      =     16;
+static int                     freq                            =   1000; /* 1 KHz */
 
-static int                     delay_secs                      =  2;
-static int                     zero;
-static int                     dump_symtab;
+static int                     delay_secs                      =      2;
+static int                     zero                            =      0;
+static int                     dump_symtab                     =      0;
+
+static bool                    hide_kernel_symbols             =  false;
+static bool                    hide_user_symbols               =  false;
+static struct winsize          winsize;
+struct symbol_conf             symbol_conf;
 
 /*
  * Source
@@ -86,83 +92,126 @@ struct source_line {
        struct source_line      *next;
 };
 
-static char                    *sym_filter                     =  NULL;
-struct sym_entry               *sym_filter_entry               =  NULL;
-static int                     sym_pcnt_filter                 =  5;
-static int                     sym_counter                     =  0;
-static int                     display_weighted                = -1;
+static char                    *sym_filter                     =   NULL;
+struct sym_entry               *sym_filter_entry               =   NULL;
+static int                     sym_pcnt_filter                 =      5;
+static int                     sym_counter                     =      0;
+static int                     display_weighted                =     -1;
 
 /*
  * Symbols
  */
 
-static u64                     min_ip;
-static u64                     max_ip = -1ll;
+struct sym_entry_source {
+       struct source_line      *source;
+       struct source_line      *lines;
+       struct source_line      **lines_tail;
+       pthread_mutex_t         lock;
+};
 
 struct sym_entry {
        struct rb_node          rb_node;
        struct list_head        node;
-       unsigned long           count[MAX_COUNTERS];
        unsigned long           snap_count;
        double                  weight;
        int                     skip;
-       struct source_line      *source;
-       struct source_line      *lines;
-       struct source_line      **lines_tail;
-       pthread_mutex_t         source_lock;
+       u16                     name_len;
+       u8                      origin;
+       struct map              *map;
+       struct sym_entry_source *src;
+       unsigned long           count[0];
 };
 
 /*
  * Source functions
  */
 
+static inline struct symbol *sym_entry__symbol(struct sym_entry *self)
+{
+       return ((void *)self) + symbol_conf.priv_size;
+}
+
+static void get_term_dimensions(struct winsize *ws)
+{
+       char *s = getenv("LINES");
+
+       if (s != NULL) {
+               ws->ws_row = atoi(s);
+               s = getenv("COLUMNS");
+               if (s != NULL) {
+                       ws->ws_col = atoi(s);
+                       if (ws->ws_row && ws->ws_col)
+                               return;
+               }
+       }
+#ifdef TIOCGWINSZ
+       if (ioctl(1, TIOCGWINSZ, ws) == 0 &&
+           ws->ws_row && ws->ws_col)
+               return;
+#endif
+       ws->ws_row = 25;
+       ws->ws_col = 80;
+}
+
+static void update_print_entries(struct winsize *ws)
+{
+       print_entries = ws->ws_row;
+
+       if (print_entries > 9)
+               print_entries -= 9;
+}
+
+static void sig_winch_handler(int sig __used)
+{
+       get_term_dimensions(&winsize);
+       update_print_entries(&winsize);
+}
+
 static void parse_source(struct sym_entry *syme)
 {
        struct symbol *sym;
-       struct module *module;
-       struct section *section = NULL;
+       struct sym_entry_source *source;
+       struct map *map;
        FILE *file;
        char command[PATH_MAX*2];
-       const char *path = vmlinux_name;
-       u64 start, end, len;
+       const char *path;
+       u64 len;
 
        if (!syme)
                return;
 
-       if (syme->lines) {
-               pthread_mutex_lock(&syme->source_lock);
-               goto out_assign;
+       if (syme->src == NULL) {
+               syme->src = zalloc(sizeof(*source));
+               if (syme->src == NULL)
+                       return;
+               pthread_mutex_init(&syme->src->lock, NULL);
        }
 
-       sym = (struct symbol *)(syme + 1);
-       module = sym->module;
-
-       if (module)
-               path = module->path;
-       if (!path)
-               return;
-
-       start = sym->obj_start;
-       if (!start)
-               start = sym->start;
+       source = syme->src;
 
-       if (module) {
-               section = module->sections->find_section(module->sections, ".text");
-               if (section)
-                       start -= section->vma;
+       if (source->lines) {
+               pthread_mutex_lock(&source->lock);
+               goto out_assign;
        }
 
-       end = start + sym->end - sym->start + 1;
+       sym = sym_entry__symbol(syme);
+       map = syme->map;
+       path = map->dso->long_name;
+
        len = sym->end - sym->start;
 
-       sprintf(command, "objdump --start-address=0x%016Lx --stop-address=0x%016Lx -dS %s", start, end, path);
+       sprintf(command,
+               "objdump --start-address=0x%016Lx "
+                        "--stop-address=0x%016Lx -dS %s",
+               map->unmap_ip(map, sym->start),
+               map->unmap_ip(map, sym->end), path);
 
        file = popen(command, "r");
        if (!file)
                return;
 
-       pthread_mutex_lock(&syme->source_lock);
-       syme->lines_tail = &syme->lines;
+       pthread_mutex_lock(&source->lock);
+       source->lines_tail = &source->lines;
        while (!feof(file)) {
                struct source_line *src;
                size_t dummy = 0;
@@ -182,24 +231,22 @@ static void parse_source(struct sym_entry *syme)
                        *c = 0;
 
                src->next = NULL;
-               *syme->lines_tail = src;
-               syme->lines_tail = &src->next;
+               *source->lines_tail = src;
+               source->lines_tail = &src->next;
 
                if (strlen(src->line)>8 && src->line[8] == ':') {
                        src->eip = strtoull(src->line, NULL, 16);
-                       if (section)
-                               src->eip += section->vma;
+                       src->eip = map->unmap_ip(map, src->eip);
                }
                if (strlen(src->line)>8 && src->line[16] == ':') {
                        src->eip = strtoull(src->line, NULL, 16);
-                       if (section)
-                               src->eip += section->vma;
+                       src->eip = map->unmap_ip(map, src->eip);
                }
        }
        pclose(file);
 out_assign:
        sym_filter_entry = syme;
-       pthread_mutex_unlock(&syme->source_lock);
+       pthread_mutex_unlock(&source->lock);
 }
 
 static void __zero_source_counters(struct sym_entry *syme)
@@ -207,7 +254,7 @@ static void __zero_source_counters(struct sym_entry *syme)
        int i;
        struct source_line *line;
 
-       line = syme->lines;
+       line = syme->src->lines;
        while (line) {
                for (i = 0; i < nr_counters; i++)
                        line->count[i] = 0;
@@ -222,13 +269,13 @@ static void record_precise_ip(struct sym_entry *syme, int counter, u64 ip)
        if (syme != sym_filter_entry)
                return;
 
-       if (pthread_mutex_trylock(&syme->source_lock))
+       if (pthread_mutex_trylock(&syme->src->lock))
                return;
 
-       if (!syme->source)
+       if (syme->src == NULL || syme->src->source == NULL)
                goto out_unlock;
 
-       for (line = syme->lines; line; line = line->next) {
+       for (line = syme->src->lines; line; line = line->next) {
                if (line->eip == ip) {
                        line->count[counter]++;
                        break;
@@ -237,32 +284,25 @@ static void record_precise_ip(struct sym_entry *syme, int counter, u64 ip)
                        break;
        }
 out_unlock:
-       pthread_mutex_unlock(&syme->source_lock);
+       pthread_mutex_unlock(&syme->src->lock);
 }
 
 static void lookup_sym_source(struct sym_entry *syme)
 {
-       struct symbol *symbol = (struct symbol *)(syme + 1);
+       struct symbol *symbol = sym_entry__symbol(syme);
        struct source_line *line;
        char pattern[PATH_MAX];
-       char *idx;
 
        sprintf(pattern, "<%s>:", symbol->name);
 
-       if (symbol->module) {
-               idx = strstr(pattern, "\t");
-               if (idx)
-                       *idx = 0;
-       }
-
-       pthread_mutex_lock(&syme->source_lock);
-       for (line = syme->lines; line; line = line->next) {
+       pthread_mutex_lock(&syme->src->lock);
+       for (line = syme->src->lines; line; line = line->next) {
                if (strstr(line->line, pattern)) {
-                       syme->source = line;
+                       syme->src->source = line;
                        break;
                }
        }
-       pthread_mutex_unlock(&syme->source_lock);
+       pthread_mutex_unlock(&syme->src->lock);
 }
 
 static void show_lines(struct source_line *queue, int count, int total)
@@ -292,24 +332,24 @@ static void show_details(struct sym_entry *syme)
        if (!syme)
                return;
 
-       if (!syme->source)
+       if (!syme->src->source)
                lookup_sym_source(syme);
 
-       if (!syme->source)
+       if (!syme->src->source)
                return;
 
-       symbol = (struct symbol *)(syme + 1);
+       symbol = sym_entry__symbol(syme);
        printf("Showing %s for %s\n", event_name(sym_counter), symbol->name);
        printf("  Events  Pcnt (>=%d%%)\n", sym_pcnt_filter);
 
-       pthread_mutex_lock(&syme->source_lock);
-       line = syme->source;
+       pthread_mutex_lock(&syme->src->lock);
+       line = syme->src->source;
        while (line) {
                total += line->count[sym_counter];
                line = line->next;
        }
 
-       line = syme->source;
+       line = syme->src->source;
        while (line) {
                float pcnt = 0.0;
 
@@ -334,13 +374,13 @@ static void show_details(struct sym_entry *syme)
                line->count[sym_counter] = zero ? 0 : line->count[sym_counter] * 7 / 8;
                line = line->next;
        }
-       pthread_mutex_unlock(&syme->source_lock);
+       pthread_mutex_unlock(&syme->src->lock);
        if (more)
                printf("%d lines not displayed, maybe increase display entries [e]\n", more);
 }
 
 /*
- * Symbols will be added here in record_ip and will get out
+ * Symbols will be added here in event__process_sample and will get out
  * after decayed.
  */
 static LIST_HEAD(active_symbols);
@@ -411,6 +451,8 @@ static void print_sym_table(void)
        struct sym_entry *syme, *n;
        struct rb_root tmp = RB_ROOT;
        struct rb_node *nd;
+       int sym_width = 0, dso_width = 0, max_dso_width;
+       const int win_width = winsize.ws_col - 1;
 
        samples = userspace_samples = 0;
 
@@ -422,6 +464,14 @@ static void print_sym_table(void)
        list_for_each_entry_safe_from(syme, n, &active_symbols, node) {
                syme->snap_count = syme->count[snap];
                if (syme->snap_count != 0) {
+
+                       if ((hide_user_symbols &&
+                            syme->origin == PERF_RECORD_MISC_USER) ||
+                           (hide_kernel_symbols &&
+                            syme->origin == PERF_RECORD_MISC_KERNEL)) {
+                               list_remove_active_sym(syme);
+                               continue;
+                       }
                        syme->weight = sym_weight(syme);
                        rb_insert_active_sym(&tmp, syme);
                        sum_ksamples += syme->snap_count;
@@ -434,8 +484,7 @@ static void print_sym_table(void)
 
        puts(CONSOLE_CLEAR);
 
-       printf(
-"------------------------------------------------------------------------------\n");
+       printf("%-*.*s\n", win_width, win_width, graph_dotted_line);
        printf( "   PerfTop:%8.0f irqs/sec  kernel:%4.1f%% [",
                samples_per_sec,
                100.0 - (100.0*((samples_per_sec-ksamples_per_sec)/samples_per_sec)));
@@ -473,33 +522,57 @@ static void print_sym_table(void)
                        printf(", %d CPUs)\n", nr_cpus);
        }
 
-       printf("------------------------------------------------------------------------------\n\n");
+       printf("%-*.*s\n", win_width, win_width, graph_dotted_line);
 
        if (sym_filter_entry) {
                show_details(sym_filter_entry);
                return;
        }
 
+       /*
+        * Find the longest symbol name that will be displayed
+        */
+       for (nd = rb_first(&tmp); nd; nd = rb_next(nd)) {
+               syme = rb_entry(nd, struct sym_entry, rb_node);
+               if (++printed > print_entries ||
+                   (int)syme->snap_count < count_filter)
+                       continue;
+
+               if (syme->map->dso->long_name_len > dso_width)
+                       dso_width = syme->map->dso->long_name_len;
+
+               if (syme->name_len > sym_width)
+                       sym_width = syme->name_len;
+       }
+
+       printed = 0;
+
+       max_dso_width = winsize.ws_col - sym_width - 29;
+       if (dso_width > max_dso_width)
+               dso_width = max_dso_width;
+       putchar('\n');
        if (nr_counters == 1)
-               printf("             samples    pcnt");
+               printf("             samples  pcnt");
        else
-               printf("   weight    samples    pcnt");
+               printf("   weight    samples  pcnt");
 
        if (verbose)
                printf("         RIP       ");
-       printf("   kernel function\n");
-       printf("   %s    _______   _____",
+       printf(" %-*.*s DSO\n", sym_width, sym_width, "function");
+       printf("   %s    _______ _____",
               nr_counters == 1 ? "      " : "______");
        if (verbose)
-               printf("   ________________");
-       printf("   _______________\n\n");
+               printf(" ________________");
+       printf(" %-*.*s", sym_width, sym_width, graph_line);
+       printf(" %-*.*s", dso_width, dso_width, graph_line);
+       puts("\n");
 
        for (nd = rb_first(&tmp); nd; nd = rb_next(nd)) {
                struct symbol *sym;
                double pcnt;
 
                syme = rb_entry(nd, struct sym_entry, rb_node);
-               sym = (struct symbol *)(syme + 1);
+               sym = sym_entry__symbol(syme);
 
                if (++printed > print_entries || (int)syme->snap_count < count_filter)
                        continue;
@@ -508,17 +581,18 @@ static void print_sym_table(void)
                                         sum_ksamples));
 
                if (nr_counters == 1 || !display_weighted)
-                       printf("%20.2f ", syme->weight);
+                       printf("%20.2f ", syme->weight);
                else
-                       printf("%9.1f %10ld ", syme->weight, syme->snap_count);
+                       printf("%9.1f %10ld ", syme->weight, syme->snap_count);
 
                percent_color_fprintf(stdout, "%4.1f%%", pcnt);
                if (verbose)
-                       printf(" - %016llx", sym->start);
-               printf(" : %s", sym->name);
-               if (sym->module)
-                       printf("\t[%s]", sym->module->name);
-               printf("\n");
+                       printf(" %016llx", sym->start);
+               printf(" %-*.*s", sym_width, sym_width, sym->name);
+               printf(" %-*.*s\n", dso_width, dso_width,
+                      dso_width >= syme->map->dso->long_name_len ?
+                                       syme->map->dso->long_name :
+                                       syme->map->dso->short_name);
        }
 }
 
@@ -565,10 +639,10 @@ static void prompt_symbol(struct sym_entry **target, const char *msg)
 
        /* zero counters of active symbol */
        if (syme) {
-               pthread_mutex_lock(&syme->source_lock);
+               pthread_mutex_lock(&syme->src->lock);
                __zero_source_counters(syme);
                *target = NULL;
-               pthread_mutex_unlock(&syme->source_lock);
+               pthread_mutex_unlock(&syme->src->lock);
        }
 
        fprintf(stdout, "\n%s: ", msg);
@@ -584,7 +658,7 @@ static void prompt_symbol(struct sym_entry **target, const char *msg)
        pthread_mutex_unlock(&active_symbols_lock);
 
        list_for_each_entry_safe_from(syme, n, &active_symbols, node) {
-               struct symbol *sym = (struct symbol *)(syme + 1);
+               struct symbol *sym = sym_entry__symbol(syme);
 
                if (!strcmp(buf, sym->name)) {
                        found = syme;
@@ -608,7 +682,7 @@ static void print_mapped_keys(void)
        char *name = NULL;
 
        if (sym_filter_entry) {
-               struct symbol *sym = (struct symbol *)(sym_filter_entry+1);
+               struct symbol *sym = sym_entry__symbol(sym_filter_entry);
                name = sym->name;
        }
 
@@ -621,7 +695,7 @@ static void print_mapped_keys(void)
 
        fprintf(stdout, "\t[f]     profile display filter (count).    \t(%d)\n", count_filter);
 
-       if (vmlinux_name) {
+       if (symbol_conf.vmlinux_name) {
                fprintf(stdout, "\t[F]     annotate display filter (percent). \t(%d%%)\n", sym_pcnt_filter);
                fprintf(stdout, "\t[s]     annotate symbol.                   \t(%s)\n", name?: "NULL");
                fprintf(stdout, "\t[S]     stop annotation.\n");
@@ -630,6 +704,12 @@ static void print_mapped_keys(void)
        if (nr_counters > 1)
                fprintf(stdout, "\t[w]     toggle display weighted/count[E]r. \t(%d)\n", display_weighted ? 1 : 0);
 
+       fprintf(stdout,
+               "\t[K]     hide kernel_symbols symbols.             \t(%s)\n",
+               hide_kernel_symbols ? "yes" : "no");
+       fprintf(stdout,
+               "\t[U]     hide user symbols.               \t(%s)\n",
+               hide_user_symbols ? "yes" : "no");
        fprintf(stdout, "\t[z]     toggle sample zeroing.             \t(%d)\n", zero ? 1 : 0);
        fprintf(stdout, "\t[qQ]    quit.\n");
 }
@@ -643,6 +723,8 @@ static int key_mapped(int c)
                case 'z':
                case 'q':
                case 'Q':
+               case 'K':
+               case 'U':
                        return 1;
                case 'E':
                case 'w':
@@ -650,7 +732,7 @@ static int key_mapped(int c)
                case 'F':
                case 's':
                case 'S':
-                       return vmlinux_name ? 1 : 0;
+                       return symbol_conf.vmlinux_name ? 1 : 0;
                default:
                        break;
        }
@@ -691,6 +773,11 @@ static void handle_keypress(int c)
                        break;
                case 'e':
                        prompt_integer(&print_entries, "Enter display entries (lines)");
+                       if (print_entries == 0) {
+                               sig_winch_handler(SIGWINCH);
+                               signal(SIGWINCH, sig_winch_handler);
+                       } else
+                               signal(SIGWINCH, SIG_DFL);
                        break;
                case 'E':
                        if (nr_counters > 1) {
@@ -715,9 +802,14 @@ static void handle_keypress(int c)
                case 'F':
                        prompt_percent(&sym_pcnt_filter, "Enter details display event filter (percent)");
                        break;
+               case 'K':
+                       hide_kernel_symbols = !hide_kernel_symbols;
+                       break;
                case 'q':
                case 'Q':
                        printf("exiting.\n");
+                       if (dump_symtab)
+                               dsos__fprintf(stderr);
                        exit(0);
                case 's':
                        prompt_symbol(&sym_filter_entry, "Enter details symbol");
@@ -728,12 +820,15 @@ static void handle_keypress(int c)
                        else {
                                struct sym_entry *syme = sym_filter_entry;
 
-                               pthread_mutex_lock(&syme->source_lock);
+                               pthread_mutex_lock(&syme->src->lock);
                                sym_filter_entry = NULL;
                                __zero_source_counters(syme);
-                               pthread_mutex_unlock(&syme->source_lock);
+                               pthread_mutex_unlock(&syme->src->lock);
                        }
                        break;
+               case 'U':
+                       hide_user_symbols = !hide_user_symbols;
+                       break;
                case 'w':
                        display_weighted = ~display_weighted;
                        break;
@@ -790,7 +885,7 @@ static const char *skip_symbols[] = {
        NULL
 };
 
-static int symbol_filter(struct dso *self, struct symbol *sym)
+static int symbol_filter(struct map *map, struct symbol *sym)
 {
        struct sym_entry *syme;
        const char *name = sym->name;
@@ -812,8 +907,9 @@ static int symbol_filter(struct dso *self, struct symbol *sym)
            strstr(name, "_text_end"))
                return 1;
 
-       syme = dso__sym_priv(self, sym);
-       pthread_mutex_init(&syme->source_lock, NULL);
+       syme = symbol__priv(sym);
+       syme->map = map;
+       syme->src = NULL;
        if (!sym_filter_entry && sym_filter && !strcmp(name, sym_filter))
                sym_filter_entry = syme;
 
@@ -824,75 +920,65 @@ static int symbol_filter(struct dso *self, struct symbol *sym)
                }
        }
 
-       return 0;
-}
-
-static int parse_symbols(void)
-{
-       struct rb_node *node;
-       struct symbol  *sym;
-       int use_modules = vmlinux_name ? 1 : 0;
-
-       kernel_dso = dso__new("[kernel]", sizeof(struct sym_entry));
-       if (kernel_dso == NULL)
-               return -1;
-
-       if (dso__load_kernel(kernel_dso, vmlinux_name, symbol_filter, verbose, use_modules) <= 0)
-               goto out_delete_dso;
-
-       node = rb_first(&kernel_dso->syms);
-       sym = rb_entry(node, struct symbol, rb_node);
-       min_ip = sym->start;
-
-       node = rb_last(&kernel_dso->syms);
-       sym = rb_entry(node, struct symbol, rb_node);
-       max_ip = sym->end;
-
-       if (dump_symtab)
-               dso__fprintf(kernel_dso, stderr);
+       if (!syme->skip)
+               syme->name_len = strlen(sym->name);
 
        return 0;
-
-out_delete_dso:
-       dso__delete(kernel_dso);
-       kernel_dso = NULL;
-       return -1;
 }
 
-/*
- * Binary search in the histogram table and record the hit:
- */
-static void record_ip(u64 ip, int counter)
+static void event__process_sample(const event_t *self, int counter)
 {
-       struct symbol *sym = dso__find_symbol(kernel_dso, ip);
-
-       if (sym != NULL) {
-               struct sym_entry *syme = dso__sym_priv(kernel_dso, sym);
-
-               if (!syme->skip) {
-                       syme->count[counter]++;
-                       record_precise_ip(syme, counter, ip);
-                       pthread_mutex_lock(&active_symbols_lock);
-                       if (list_empty(&syme->node) || !syme->node.next)
-                               __list_insert_active_sym(syme);
-                       pthread_mutex_unlock(&active_symbols_lock);
+       u64 ip = self->ip.ip;
+       struct sym_entry *syme;
+       struct addr_location al;
+       u8 origin = self->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
+
+       switch (origin) {
+       case PERF_RECORD_MISC_USER:
+               if (hide_user_symbols)
                        return;
-               }
+               break;
+       case PERF_RECORD_MISC_KERNEL:
+               if (hide_kernel_symbols)
+                       return;
+               break;
+       default:
+               return;
        }
 
-       samples--;
+       if (event__preprocess_sample(self, &al, symbol_filter) < 0 ||
+           al.sym == NULL)
+               return;
+
+       syme = symbol__priv(al.sym);
+       if (!syme->skip) {
+               syme->count[counter]++;
+               syme->origin = origin;
+               record_precise_ip(syme, counter, ip);
+               pthread_mutex_lock(&active_symbols_lock);
+               if (list_empty(&syme->node) || !syme->node.next)
+                       __list_insert_active_sym(syme);
+               pthread_mutex_unlock(&active_symbols_lock);
+               if (origin == PERF_RECORD_MISC_USER)
+                       ++userspace_samples;
+               ++samples;
+       }
 }
 
-static void process_event(u64 ip, int counter, int user)
+static int event__process(event_t *event)
 {
-       samples++;
-
-       if (user) {
-               userspace_samples++;
-               return;
+       switch (event->header.type) {
+       case PERF_RECORD_COMM:
+               event__process_comm(event);
+               break;
+       case PERF_RECORD_MMAP:
+               event__process_mmap(event);
+               break;
+       default:
+               break;
        }
 
-       record_ip(ip, counter);
+       return 0;
 }
 
 struct mmap_data {
@@ -913,8 +999,6 @@ static unsigned int mmap_read_head(struct mmap_data *md)
        return head;
 }
 
-struct timeval last_read, this_read;
-
 static void mmap_read_counter(struct mmap_data *md)
 {
        unsigned int head = mmap_read_head(md);
@@ -922,8 +1006,6 @@ static void mmap_read_counter(struct mmap_data *md)
        unsigned char *data = md->base + page_size;
        int diff;
 
-       gettimeofday(&this_read, NULL);
-
        /*
         * If we're further behind than half the buffer, there's a chance
         * the writer will bite our tail and mess up the samples under us.
@@ -934,14 +1016,7 @@ static void mmap_read_counter(struct mmap_data *md)
         */
        diff = head - old;
        if (diff > md->mask / 2 || diff < 0) {
-               struct timeval iv;
-               unsigned long msecs;
-
-               timersub(&this_read, &last_read, &iv);
-               msecs = iv.tv_sec*1000 + iv.tv_usec/1000;
-
-               fprintf(stderr, "WARNING: failed to keep up with mmap data."
-                               "  Last read %lu msecs ago.\n", msecs);
+               fprintf(stderr, "WARNING: failed to keep up with mmap data.\n");
 
                /*
                 * head points to a known good entry, start there.
@@ -949,8 +1024,6 @@ static void mmap_read_counter(struct mmap_data *md)
                old = head;
        }
 
-       last_read = this_read;
-
        for (; old != head;) {
                event_t *event = (event_t *)&data[old & md->mask];
 
@@ -978,13 +1051,11 @@ static void mmap_read_counter(struct mmap_data *md)
                        event = &event_copy;
                }
 
+               if (event->header.type == PERF_RECORD_SAMPLE)
+                       event__process_sample(event, md->counter);
+               else
+                       event__process(event);
                old += size;
-
-               if (event->header.type == PERF_RECORD_SAMPLE) {
-                       int user =
-       (event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK) == PERF_RECORD_MISC_USER;
-                       process_event(event->ip.ip, md->counter, user);
-               }
        }
 
        md->prev = old;
@@ -1018,8 +1089,15 @@ static void start_counter(int i, int counter)
        attr = attrs + counter;
 
        attr->sample_type       = PERF_SAMPLE_IP | PERF_SAMPLE_TID;
-       attr->freq              = freq;
+
+       if (freq) {
+               attr->sample_type       |= PERF_SAMPLE_PERIOD;
+               attr->freq              = 1;
+               attr->sample_freq       = freq;
+       }
+
        attr->inherit           = (cpu < 0) && inherit;
+       attr->mmap              = 1;
 
 try_again:
        fd[i][counter] = sys_perf_event_open(attr, target_pid, cpu, group_fd, 0);
@@ -1078,6 +1156,11 @@ static int __cmd_top(void)
        int i, counter;
        int ret;
 
+       if (target_pid != -1)
+               event__synthesize_thread(target_pid, event__process);
+       else
+               event__synthesize_threads(event__process);
+
        for (i = 0; i < nr_cpus; i++) {
                group_fd = -1;
                for (counter = 0; counter < nr_counters; counter++)
@@ -1133,7 +1216,10 @@ static const struct option options[] = {
                            "system-wide collection from all CPUs"),
        OPT_INTEGER('C', "CPU", &profile_cpu,
                    "CPU to profile on"),
-       OPT_STRING('k', "vmlinux", &vmlinux_name, "file", "vmlinux pathname"),
+       OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
+                  "file", "vmlinux pathname"),
+       OPT_BOOLEAN('K', "hide_kernel_symbols", &hide_kernel_symbols,
+                   "hide kernel symbols"),
        OPT_INTEGER('m', "mmap-pages", &mmap_pages,
                    "number of mmap data pages"),
        OPT_INTEGER('r', "realtime", &realtime_prio,
@@ -1156,6 +1242,8 @@ static const struct option options[] = {
                    "profile at this frequency"),
        OPT_INTEGER('E', "entries", &print_entries,
                    "display this many functions"),
+       OPT_BOOLEAN('U', "hide_user_symbols", &hide_user_symbols,
+                   "hide user symbols"),
        OPT_BOOLEAN('v', "verbose", &verbose,
                    "be more verbose (show counter open errors, etc)"),
        OPT_END()
@@ -1165,19 +1253,12 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
 {
        int counter;
 
-       symbol__init();
-
        page_size = sysconf(_SC_PAGE_SIZE);
 
        argc = parse_options(argc, argv, options, top_usage, 0);
        if (argc)
                usage_with_options(top_usage, options);
 
-       if (freq) {
-               default_interval = freq;
-               freq = 1;
-       }
-
        /* CPU and PID are mutually exclusive */
        if (target_pid != -1 && profile_cpu != -1) {
                printf("WARNING: PID switch overriding CPU\n");
@@ -1188,13 +1269,31 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
        if (!nr_counters)
                nr_counters = 1;
 
+       symbol_conf.priv_size = (sizeof(struct sym_entry) +
+                                (nr_counters + 1) * sizeof(unsigned long));
+       if (symbol_conf.vmlinux_name == NULL)
+               symbol_conf.try_vmlinux_path = true;
+       if (symbol__init(&symbol_conf) < 0)
+               return -1;
+
        if (delay_secs < 1)
                delay_secs = 1;
 
-       parse_symbols();
        parse_source(sym_filter_entry);
 
        /*
+        * User specified count overrides default frequency.
+        */
+       if (default_interval)
+               freq = 0;
+       else if (freq) {
+               default_interval = freq;
+       } else {
+               fprintf(stderr, "frequency and count are zero, aborting\n");
+               exit(EXIT_FAILURE);
+       }
+
+       /*
         * Fill in the ones not specifically initialized via -c:
         */
        for (counter = 0; counter < nr_counters; counter++) {
@@ -1211,5 +1310,11 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
        if (target_pid != -1 || profile_cpu != -1)
                nr_cpus = 1;
 
+       get_term_dimensions(&winsize);
+       if (print_entries == 0) {
+               update_print_entries(&winsize);
+               signal(SIGWINCH, sig_winch_handler);
+       }
+
        return __cmd_top();
 }
index 0c5e4f7..abb914a 100644 (file)
@@ -5,66 +5,73 @@
 #include "util/symbol.h"
 #include "util/thread.h"
 #include "util/header.h"
+#include "util/exec_cmd.h"
+#include "util/trace-event.h"
 
-#include "util/parse-options.h"
+static char const              *script_name;
+static char const              *generate_script_lang;
 
-#include "perf.h"
-#include "util/debug.h"
+static int default_start_script(const char *script __attribute((unused)))
+{
+       return 0;
+}
 
-#include "util/trace-event.h"
+static int default_stop_script(void)
+{
+       return 0;
+}
 
-static char            const *input_name = "perf.data";
-static int             input;
-static unsigned long   page_size;
-static unsigned long   mmap_window = 32;
+static int default_generate_script(const char *outfile __attribute ((unused)))
+{
+       return 0;
+}
 
-static unsigned long   total = 0;
-static unsigned long   total_comm = 0;
+static struct scripting_ops default_scripting_ops = {
+       .start_script           = default_start_script,
+       .stop_script            = default_stop_script,
+       .process_event          = print_event,
+       .generate_script        = default_generate_script,
+};
+
+static struct scripting_ops    *scripting_ops;
 
-static struct rb_root  threads;
-static struct thread   *last_match;
+static void setup_scripting(void)
+{
+       /* make sure PERF_EXEC_PATH is set for scripts */
+       perf_set_argv_exec_path(perf_exec_path());
 
-static struct perf_header *header;
-static u64             sample_type;
+       setup_perl_scripting();
 
+       scripting_ops = &default_scripting_ops;
+}
 
-static int
-process_comm_event(event_t *event, unsigned long offset, unsigned long head)
+static int cleanup_scripting(void)
 {
-       struct thread *thread;
+       return scripting_ops->stop_script();
+}
 
-       thread = threads__findnew(event->comm.pid, &threads, &last_match);
+#include "util/parse-options.h"
 
-       dump_printf("%p [%p]: PERF_RECORD_COMM: %s:%d\n",
-               (void *)(offset + head),
-               (void *)(long)(event->header.size),
-               event->comm.comm, event->comm.pid);
+#include "perf.h"
+#include "util/debug.h"
 
-       if (thread == NULL ||
-           thread__set_comm(thread, event->comm.comm)) {
-               dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n");
-               return -1;
-       }
-       total_comm++;
+#include "util/trace-event.h"
+#include "util/data_map.h"
+#include "util/exec_cmd.h"
 
-       return 0;
-}
+static char const              *input_name = "perf.data";
 
-static int
-process_sample_event(event_t *event, unsigned long offset, unsigned long head)
+static struct perf_header      *header;
+static u64                     sample_type;
+
+static int process_sample_event(event_t *event)
 {
-       char level;
-       int show = 0;
-       struct dso *dso = NULL;
-       struct thread *thread;
        u64 ip = event->ip.ip;
        u64 timestamp = -1;
        u32 cpu = -1;
        u64 period = 1;
        void *more_data = event->ip.__more_data;
-       int cpumode;
-
-       thread = threads__findnew(event->ip.pid, &threads, &last_match);
+       struct thread *thread = threads__findnew(event->ip.pid);
 
        if (sample_type & PERF_SAMPLE_TIME) {
                timestamp = *(u64 *)more_data;
@@ -82,45 +89,19 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head)
                more_data += sizeof(u64);
        }
 
-       dump_printf("%p [%p]: PERF_RECORD_SAMPLE (IP, %d): %d/%d: %p period: %Ld\n",
-               (void *)(offset + head),
-               (void *)(long)(event->header.size),
+       dump_printf("(IP, %d): %d/%d: %p period: %Ld\n",
                event->header.misc,
                event->ip.pid, event->ip.tid,
                (void *)(long)ip,
                (long long)period);
 
-       dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid);
-
        if (thread == NULL) {
-               eprintf("problem processing %d event, skipping it.\n",
-                       event->header.type);
+               pr_debug("problem processing %d event, skipping it.\n",
+                        event->header.type);
                return -1;
        }
 
-       cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
-
-       if (cpumode == PERF_RECORD_MISC_KERNEL) {
-               show = SHOW_KERNEL;
-               level = 'k';
-
-               dso = kernel_dso;
-
-               dump_printf(" ...... dso: %s\n", dso->name);
-
-       } else if (cpumode == PERF_RECORD_MISC_USER) {
-
-               show = SHOW_USER;
-               level = '.';
-
-       } else {
-               show = SHOW_HV;
-               level = 'H';
-
-               dso = hypervisor_dso;
-
-               dump_printf(" ...... dso: [hypervisor]\n");
-       }
+       dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid);
 
        if (sample_type & PERF_SAMPLE_RAW) {
                struct {
@@ -133,128 +114,189 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head)
                 * field, although it should be the same than this perf
                 * event pid
                 */
-               print_event(cpu, raw->data, raw->size, timestamp, thread->comm);
+               scripting_ops->process_event(cpu, raw->data, raw->size,
+                                            timestamp, thread->comm);
        }
-       total += period;
+       event__stats.total += period;
 
        return 0;
 }
 
-static int
-process_event(event_t *event, unsigned long offset, unsigned long head)
+static int sample_type_check(u64 type)
 {
-       trace_event(event);
-
-       switch (event->header.type) {
-       case PERF_RECORD_MMAP ... PERF_RECORD_LOST:
-               return 0;
-
-       case PERF_RECORD_COMM:
-               return process_comm_event(event, offset, head);
-
-       case PERF_RECORD_EXIT ... PERF_RECORD_READ:
-               return 0;
-
-       case PERF_RECORD_SAMPLE:
-               return process_sample_event(event, offset, head);
+       sample_type = type;
 
-       case PERF_RECORD_MAX:
-       default:
+       if (!(sample_type & PERF_SAMPLE_RAW)) {
+               fprintf(stderr,
+                       "No trace sample to read. Did you call perf record "
+                       "without -R?");
                return -1;
        }
 
        return 0;
 }
 
+static struct perf_file_handler file_handler = {
+       .process_sample_event   = process_sample_event,
+       .process_comm_event     = event__process_comm,
+       .sample_type_check      = sample_type_check,
+};
+
 static int __cmd_trace(void)
 {
-       int ret, rc = EXIT_FAILURE;
-       unsigned long offset = 0;
-       unsigned long head = 0;
-       struct stat perf_stat;
-       event_t *event;
-       uint32_t size;
-       char *buf;
-
-       trace_report();
-       register_idle_thread(&threads, &last_match);
-
-       input = open(input_name, O_RDONLY);
-       if (input < 0) {
-               perror("failed to open file");
-               exit(-1);
-       }
+       register_idle_thread();
+       register_perf_file_handler(&file_handler);
 
-       ret = fstat(input, &perf_stat);
-       if (ret < 0) {
-               perror("failed to stat file");
-               exit(-1);
-       }
+       return mmap_dispatch_perf_file(&header, input_name,
+                                      0, 0, &event__cwdlen, &event__cwd);
+}
 
-       if (!perf_stat.st_size) {
-               fprintf(stderr, "zero-sized file, nothing to do!\n");
-               exit(0);
-       }
-       header = perf_header__read(input);
-       head = header->data_offset;
-       sample_type = perf_header__sample_type(header);
+struct script_spec {
+       struct list_head        node;
+       struct scripting_ops    *ops;
+       char                    spec[0];
+};
 
-       if (!(sample_type & PERF_SAMPLE_RAW))
-               die("No trace sample to read. Did you call perf record "
-                   "without -R?");
+LIST_HEAD(script_specs);
 
-       if (load_kernel() < 0) {
-               perror("failed to load kernel symbols");
-               return EXIT_FAILURE;
-       }
+static struct script_spec *script_spec__new(const char *spec,
+                                           struct scripting_ops *ops)
+{
+       struct script_spec *s = malloc(sizeof(*s) + strlen(spec) + 1);
 
-remap:
-       buf = (char *)mmap(NULL, page_size * mmap_window, PROT_READ,
-                          MAP_SHARED, input, offset);
-       if (buf == MAP_FAILED) {
-               perror("failed to mmap file");
-               exit(-1);
+       if (s != NULL) {
+               strcpy(s->spec, spec);
+               s->ops = ops;
        }
 
-more:
-       event = (event_t *)(buf + head);
+       return s;
+}
 
-       if (head + event->header.size >= page_size * mmap_window) {
-               unsigned long shift = page_size * (head / page_size);
-               int res;
+static void script_spec__delete(struct script_spec *s)
+{
+       free(s->spec);
+       free(s);
+}
 
-               res = munmap(buf, page_size * mmap_window);
-               assert(res == 0);
+static void script_spec__add(struct script_spec *s)
+{
+       list_add_tail(&s->node, &script_specs);
+}
 
-               offset += shift;
-               head -= shift;
-               goto remap;
-       }
+static struct script_spec *script_spec__find(const char *spec)
+{
+       struct script_spec *s;
 
-       size = event->header.size;
+       list_for_each_entry(s, &script_specs, node)
+               if (strcasecmp(s->spec, spec) == 0)
+                       return s;
+       return NULL;
+}
 
-       if (!size || process_event(event, offset, head) < 0) {
+static struct script_spec *script_spec__findnew(const char *spec,
+                                               struct scripting_ops *ops)
+{
+       struct script_spec *s = script_spec__find(spec);
 
-               /*
-                * assume we lost track of the stream, check alignment, and
-                * increment a single u64 in the hope to catch on again 'soon'.
-                */
+       if (s)
+               return s;
 
-               if (unlikely(head & 7))
-                       head &= ~7ULL;
+       s = script_spec__new(spec, ops);
+       if (!s)
+               goto out_delete_spec;
 
-               size = 8;
-       }
+       script_spec__add(s);
+
+       return s;
 
-       head += size;
+out_delete_spec:
+       script_spec__delete(s);
+
+       return NULL;
+}
 
-       if (offset + head < (unsigned long)perf_stat.st_size)
-               goto more;
+int script_spec_register(const char *spec, struct scripting_ops *ops)
+{
+       struct script_spec *s;
+
+       s = script_spec__find(spec);
+       if (s)
+               return -1;
 
-       rc = EXIT_SUCCESS;
-       close(input);
+       s = script_spec__findnew(spec, ops);
+       if (!s)
+               return -1;
+
+       return 0;
+}
+
+static struct scripting_ops *script_spec__lookup(const char *spec)
+{
+       struct script_spec *s = script_spec__find(spec);
+       if (!s)
+               return NULL;
 
-       return rc;
+       return s->ops;
+}
+
+static void list_available_languages(void)
+{
+       struct script_spec *s;
+
+       fprintf(stderr, "\n");
+       fprintf(stderr, "Scripting language extensions (used in "
+               "perf trace -s [spec:]script.[spec]):\n\n");
+
+       list_for_each_entry(s, &script_specs, node)
+               fprintf(stderr, "  %-42s [%s]\n", s->spec, s->ops->name);
+
+       fprintf(stderr, "\n");
+}
+
+static int parse_scriptname(const struct option *opt __used,
+                           const char *str, int unset __used)
+{
+       char spec[PATH_MAX];
+       const char *script, *ext;
+       int len;
+
+       if (strcmp(str, "list") == 0) {
+               list_available_languages();
+               return 0;
+       }
+
+       script = strchr(str, ':');
+       if (script) {
+               len = script - str;
+               if (len >= PATH_MAX) {
+                       fprintf(stderr, "invalid language specifier");
+                       return -1;
+               }
+               strncpy(spec, str, len);
+               spec[len] = '\0';
+               scripting_ops = script_spec__lookup(spec);
+               if (!scripting_ops) {
+                       fprintf(stderr, "invalid language specifier");
+                       return -1;
+               }
+               script++;
+       } else {
+               script = str;
+               ext = strchr(script, '.');
+               if (!ext) {
+                       fprintf(stderr, "invalid script extension");
+                       return -1;
+               }
+               scripting_ops = script_spec__lookup(++ext);
+               if (!scripting_ops) {
+                       fprintf(stderr, "invalid script extension");
+                       return -1;
+               }
+       }
+
+       script_name = strdup(script);
+
+       return 0;
 }
 
 static const char * const annotate_usage[] = {
@@ -267,13 +309,24 @@ static const struct option options[] = {
                    "dump raw trace in ASCII"),
        OPT_BOOLEAN('v', "verbose", &verbose,
                    "be more verbose (show symbol address, etc)"),
+       OPT_BOOLEAN('l', "latency", &latency_format,
+                   "show latency attributes (irqs/preemption disabled, etc)"),
+       OPT_CALLBACK('s', "script", NULL, "name",
+                    "script file name (lang:script name, script name, or *)",
+                    parse_scriptname),
+       OPT_STRING('g', "gen-script", &generate_script_lang, "lang",
+                  "generate perf-trace.xx script in specified language"),
+
        OPT_END()
 };
 
 int cmd_trace(int argc, const char **argv, const char *prefix __used)
 {
-       symbol__init();
-       page_size = getpagesize();
+       int err;
+
+       symbol__init(0);
+
+       setup_scripting();
 
        argc = parse_options(argc, argv, options, annotate_usage, 0);
        if (argc) {
@@ -287,5 +340,50 @@ int cmd_trace(int argc, const char **argv, const char *prefix __used)
 
        setup_pager();
 
-       return __cmd_trace();
+       if (generate_script_lang) {
+               struct stat perf_stat;
+
+               int input = open(input_name, O_RDONLY);
+               if (input < 0) {
+                       perror("failed to open file");
+                       exit(-1);
+               }
+
+               err = fstat(input, &perf_stat);
+               if (err < 0) {
+                       perror("failed to stat file");
+                       exit(-1);
+               }
+
+               if (!perf_stat.st_size) {
+                       fprintf(stderr, "zero-sized file, nothing to do!\n");
+                       exit(0);
+               }
+
+               scripting_ops = script_spec__lookup(generate_script_lang);
+               if (!scripting_ops) {
+                       fprintf(stderr, "invalid language specifier");
+                       return -1;
+               }
+
+               header = perf_header__new();
+               if (header == NULL)
+                       return -1;
+
+               perf_header__read(header, input);
+               err = scripting_ops->generate_script("perf-trace");
+               goto out;
+       }
+
+       if (script_name) {
+               err = scripting_ops->start_script(script_name);
+               if (err)
+                       goto out;
+       }
+
+       err = __cmd_trace();
+
+       cleanup_scripting();
+out:
+       return err;
 }
index e11d8d2..a3d8bf6 100644 (file)
@@ -15,6 +15,8 @@ extern int read_line_with_nul(char *buf, int size, FILE *file);
 extern int check_pager_config(const char *cmd);
 
 extern int cmd_annotate(int argc, const char **argv, const char *prefix);
+extern int cmd_bench(int argc, const char **argv, const char *prefix);
+extern int cmd_buildid_list(int argc, const char **argv, const char *prefix);
 extern int cmd_help(int argc, const char **argv, const char *prefix);
 extern int cmd_sched(int argc, const char **argv, const char *prefix);
 extern int cmd_list(int argc, const char **argv, const char *prefix);
@@ -25,5 +27,7 @@ extern int cmd_timechart(int argc, const char **argv, const char *prefix);
 extern int cmd_top(int argc, const char **argv, const char *prefix);
 extern int cmd_trace(int argc, const char **argv, const char *prefix);
 extern int cmd_version(int argc, const char **argv, const char *prefix);
+extern int cmd_probe(int argc, const char **argv, const char *prefix);
+extern int cmd_kmem(int argc, const char **argv, const char *prefix);
 
 #endif
index 00326e2..02b09ea 100644 (file)
@@ -3,6 +3,8 @@
 # command name                 category [deprecated] [common]
 #
 perf-annotate                  mainporcelain common
+perf-bench                     mainporcelain common
+perf-buildid-list              mainporcelain common
 perf-list                      mainporcelain common
 perf-sched                     mainporcelain common
 perf-record                    mainporcelain common
@@ -11,3 +13,5 @@ perf-stat                     mainporcelain common
 perf-timechart                 mainporcelain common
 perf-top                       mainporcelain common
 perf-trace                     mainporcelain common
+perf-probe                     mainporcelain common
+perf-kmem                      mainporcelain common
index fdd42a8..f000c30 100644 (file)
@@ -137,6 +137,8 @@ enum sw_event_ids {
        PERF_COUNT_SW_CPU_MIGRATIONS    = 4,
        PERF_COUNT_SW_PAGE_FAULTS_MIN   = 5,
        PERF_COUNT_SW_PAGE_FAULTS_MAJ   = 6,
+       PERF_COUNT_SW_ALIGNMENT_FAULTS  = 7,
+       PERF_COUNT_SW_EMULATION_FAULTS  = 8,
 };
 
 Counters of the type PERF_TYPE_TRACEPOINT are available when the ftrace event
index 19fc7fe..cf64049 100644 (file)
@@ -14,6 +14,7 @@
 #include "util/run-command.h"
 #include "util/parse-events.h"
 #include "util/string.h"
+#include "util/debugfs.h"
 
 const char perf_usage_string[] =
        "perf [--version] [--help] COMMAND [ARGS]";
@@ -89,8 +90,8 @@ static int handle_options(const char*** argv, int* argc, int* envchanged)
                /*
                 * Check remaining flags.
                 */
-               if (!prefixcmp(cmd, "--exec-path")) {
-                       cmd += 11;
+               if (!prefixcmp(cmd, CMD_EXEC_PATH)) {
+                       cmd += strlen(CMD_EXEC_PATH);
                        if (*cmd == '=')
                                perf_set_argv_exec_path(cmd + 1);
                        else {
@@ -117,8 +118,8 @@ static int handle_options(const char*** argv, int* argc, int* envchanged)
                        (*argv)++;
                        (*argc)--;
                        handled++;
-               } else if (!prefixcmp(cmd, "--perf-dir=")) {
-                       setenv(PERF_DIR_ENVIRONMENT, cmd + 10, 1);
+               } else if (!prefixcmp(cmd, CMD_PERF_DIR)) {
+                       setenv(PERF_DIR_ENVIRONMENT, cmd + strlen(CMD_PERF_DIR), 1);
                        if (envchanged)
                                *envchanged = 1;
                } else if (!strcmp(cmd, "--work-tree")) {
@@ -131,8 +132,8 @@ static int handle_options(const char*** argv, int* argc, int* envchanged)
                                *envchanged = 1;
                        (*argv)++;
                        (*argc)--;
-               } else if (!prefixcmp(cmd, "--work-tree=")) {
-                       setenv(PERF_WORK_TREE_ENVIRONMENT, cmd + 12, 1);
+               } else if (!prefixcmp(cmd, CMD_WORK_TREE)) {
+                       setenv(PERF_WORK_TREE_ENVIRONMENT, cmd + strlen(CMD_WORK_TREE), 1);
                        if (envchanged)
                                *envchanged = 1;
                } else if (!strcmp(cmd, "--debugfs-dir")) {
@@ -146,8 +147,8 @@ static int handle_options(const char*** argv, int* argc, int* envchanged)
                                *envchanged = 1;
                        (*argv)++;
                        (*argc)--;
-               } else if (!prefixcmp(cmd, "--debugfs-dir=")) {
-                       strncpy(debugfs_mntpt, cmd + 14, MAXPATHLEN);
+               } else if (!prefixcmp(cmd, CMD_DEBUGFS_DIR)) {
+                       strncpy(debugfs_mntpt, cmd + strlen(CMD_DEBUGFS_DIR), MAXPATHLEN);
                        debugfs_mntpt[MAXPATHLEN - 1] = '\0';
                        if (envchanged)
                                *envchanged = 1;
@@ -284,17 +285,21 @@ static void handle_internal_command(int argc, const char **argv)
 {
        const char *cmd = argv[0];
        static struct cmd_struct commands[] = {
-               { "help", cmd_help, 0 },
-               { "list", cmd_list, 0 },
-               { "record", cmd_record, 0 },
-               { "report", cmd_report, 0 },
-               { "stat", cmd_stat, 0 },
-               { "timechart", cmd_timechart, 0 },
-               { "top", cmd_top, 0 },
-               { "annotate", cmd_annotate, 0 },
-               { "version", cmd_version, 0 },
-               { "trace", cmd_trace, 0 },
-               { "sched", cmd_sched, 0 },
+               { "buildid-list", cmd_buildid_list, 0 },
+               { "help",       cmd_help,       0 },
+               { "list",       cmd_list,       0 },
+               { "record",     cmd_record,     0 },
+               { "report",     cmd_report,     0 },
+               { "bench",      cmd_bench,      0 },
+               { "stat",       cmd_stat,       0 },
+               { "timechart",  cmd_timechart,  0 },
+               { "top",        cmd_top,        0 },
+               { "annotate",   cmd_annotate,   0 },
+               { "version",    cmd_version,    0 },
+               { "trace",      cmd_trace,      0 },
+               { "sched",      cmd_sched,      0 },
+               { "probe",      cmd_probe,      0 },
+               { "kmem",       cmd_kmem,       0 },
        };
        unsigned int i;
        static const char ext[] = STRIP_EXTENSION;
@@ -382,45 +387,12 @@ static int run_argv(int *argcp, const char ***argv)
 /* mini /proc/mounts parser: searching for "^blah /mount/point debugfs" */
 static void get_debugfs_mntpt(void)
 {
-       FILE *file;
-       char fs_type[100];
-       char debugfs[MAXPATHLEN];
+       const char *path = debugfs_find_mountpoint();
 
-       /*
-        * try the standard location
-        */
-       if (valid_debugfs_mount("/sys/kernel/debug/") == 0) {
-               strcpy(debugfs_mntpt, "/sys/kernel/debug/");
-               return;
-       }
-
-       /*
-        * try the sane location
-        */
-       if (valid_debugfs_mount("/debug/") == 0) {
-               strcpy(debugfs_mntpt, "/debug/");
-               return;
-       }
-
-       /*
-        * give up and parse /proc/mounts
-        */
-       file = fopen("/proc/mounts", "r");
-       if (file == NULL)
-               return;
-
-       while (fscanf(file, "%*s %"
-                     STR(MAXPATHLEN)
-                     "s %99s %*s %*d %*d\n",
-                     debugfs, fs_type) == 2) {
-               if (strcmp(fs_type, "debugfs") == 0)
-                       break;
-       }
-       fclose(file);
-       if (strcmp(fs_type, "debugfs") == 0) {
-               strncpy(debugfs_mntpt, debugfs, MAXPATHLEN);
-               debugfs_mntpt[MAXPATHLEN - 1] = '\0';
-       }
+       if (path)
+               strncpy(debugfs_mntpt, path, sizeof(debugfs_mntpt));
+       else
+               debugfs_mntpt[0] = '\0';
 }
 
 int main(int argc, const char **argv)
index 8cc4623..454d5d5 100644 (file)
 #define cpu_relax()    asm volatile("":::"memory")
 #endif
 
+#ifdef __alpha__
+#include "../../arch/alpha/include/asm/unistd.h"
+#define rmb()          asm volatile("mb" ::: "memory")
+#define cpu_relax()    asm volatile("" ::: "memory")
+#endif
+
+#ifdef __ia64__
+#include "../../arch/ia64/include/asm/unistd.h"
+#define rmb()          asm volatile ("mf" ::: "memory")
+#define cpu_relax()    asm volatile ("hint @pause" ::: "memory")
+#endif
+
 #include <time.h>
 #include <unistd.h>
 #include <sys/types.h>
diff --git a/tools/perf/scripts/perl/Perf-Trace-Util/Context.c b/tools/perf/scripts/perl/Perf-Trace-Util/Context.c
new file mode 100644 (file)
index 0000000..af78d9a
--- /dev/null
@@ -0,0 +1,134 @@
+/*
+ * This file was generated automatically by ExtUtils::ParseXS version 2.18_02 from the
+ * contents of Context.xs. Do not edit this file, edit Context.xs instead.
+ *
+ *     ANY CHANGES MADE HERE WILL BE LOST! 
+ *
+ */
+
+#line 1 "Context.xs"
+/*
+ * Context.xs.  XS interfaces for perf trace.
+ *
+ * Copyright (C) 2009 Tom Zanussi <tzanussi@gmail.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  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 "EXTERN.h"
+#include "perl.h"
+#include "XSUB.h"
+#include "../../../util/trace-event-perl.h"
+
+#ifndef PERL_UNUSED_VAR
+#  define PERL_UNUSED_VAR(var) if (0) var = var
+#endif
+
+#line 41 "Context.c"
+
+XS(XS_Perf__Trace__Context_common_pc); /* prototype to pass -Wmissing-prototypes */
+XS(XS_Perf__Trace__Context_common_pc)
+{
+#ifdef dVAR
+    dVAR; dXSARGS;
+#else
+    dXSARGS;
+#endif
+    if (items != 1)
+       Perl_croak(aTHX_ "Usage: %s(%s)", "Perf::Trace::Context::common_pc", "context");
+    PERL_UNUSED_VAR(cv); /* -W */
+    {
+       struct scripting_context *      context = INT2PTR(struct scripting_context *,SvIV(ST(0)));
+       int     RETVAL;
+       dXSTARG;
+
+       RETVAL = common_pc(context);
+       XSprePUSH; PUSHi((IV)RETVAL);
+    }
+    XSRETURN(1);
+}
+
+
+XS(XS_Perf__Trace__Context_common_flags); /* prototype to pass -Wmissing-prototypes */
+XS(XS_Perf__Trace__Context_common_flags)
+{
+#ifdef dVAR
+    dVAR; dXSARGS;
+#else
+    dXSARGS;
+#endif
+    if (items != 1)
+       Perl_croak(aTHX_ "Usage: %s(%s)", "Perf::Trace::Context::common_flags", "context");
+    PERL_UNUSED_VAR(cv); /* -W */
+    {
+       struct scripting_context *      context = INT2PTR(struct scripting_context *,SvIV(ST(0)));
+       int     RETVAL;
+       dXSTARG;
+
+       RETVAL = common_flags(context);
+       XSprePUSH; PUSHi((IV)RETVAL);
+    }
+    XSRETURN(1);
+}
+
+
+XS(XS_Perf__Trace__Context_common_lock_depth); /* prototype to pass -Wmissing-prototypes */
+XS(XS_Perf__Trace__Context_common_lock_depth)
+{
+#ifdef dVAR
+    dVAR; dXSARGS;
+#else
+    dXSARGS;
+#endif
+    if (items != 1)
+       Perl_croak(aTHX_ "Usage: %s(%s)", "Perf::Trace::Context::common_lock_depth", "context");
+    PERL_UNUSED_VAR(cv); /* -W */
+    {
+       struct scripting_context *      context = INT2PTR(struct scripting_context *,SvIV(ST(0)));
+       int     RETVAL;
+       dXSTARG;
+
+       RETVAL = common_lock_depth(context);
+       XSprePUSH; PUSHi((IV)RETVAL);
+    }
+    XSRETURN(1);
+}
+
+#ifdef __cplusplus
+extern "C"
+#endif
+XS(boot_Perf__Trace__Context); /* prototype to pass -Wmissing-prototypes */
+XS(boot_Perf__Trace__Context)
+{
+#ifdef dVAR
+    dVAR; dXSARGS;
+#else
+    dXSARGS;
+#endif
+    const char* file = __FILE__;
+
+    PERL_UNUSED_VAR(cv); /* -W */
+    PERL_UNUSED_VAR(items); /* -W */
+    XS_VERSION_BOOTCHECK ;
+
+        newXSproto("Perf::Trace::Context::common_pc", XS_Perf__Trace__Context_common_pc, file, "$");
+        newXSproto("Perf::Trace::Context::common_flags", XS_Perf__Trace__Context_common_flags, file, "$");
+        newXSproto("Perf::Trace::Context::common_lock_depth", XS_Perf__Trace__Context_common_lock_depth, file, "$");
+    if (PL_unitcheckav)
+         call_list(PL_scopestack_ix, PL_unitcheckav);
+    XSRETURN_YES;
+}
+
diff --git a/tools/perf/scripts/perl/Perf-Trace-Util/Context.xs b/tools/perf/scripts/perl/Perf-Trace-Util/Context.xs
new file mode 100644 (file)
index 0000000..fb78006
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * Context.xs.  XS interfaces for perf trace.
+ *
+ * Copyright (C) 2009 Tom Zanussi <tzanussi@gmail.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  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 "EXTERN.h"
+#include "perl.h"
+#include "XSUB.h"
+#include "../../../util/trace-event-perl.h"
+
+MODULE = Perf::Trace::Context          PACKAGE = Perf::Trace::Context
+PROTOTYPES: ENABLE
+
+int
+common_pc(context)
+       struct scripting_context * context
+
+int
+common_flags(context)
+       struct scripting_context * context
+
+int
+common_lock_depth(context)
+       struct scripting_context * context
+
diff --git a/tools/perf/scripts/perl/Perf-Trace-Util/Makefile.PL b/tools/perf/scripts/perl/Perf-Trace-Util/Makefile.PL
new file mode 100644 (file)
index 0000000..decdeb0
--- /dev/null
@@ -0,0 +1,17 @@
+use 5.010000;
+use ExtUtils::MakeMaker;
+# See lib/ExtUtils/MakeMaker.pm for details of how to influence
+# the contents of the Makefile that is written.
+WriteMakefile(
+    NAME              => 'Perf::Trace::Context',
+    VERSION_FROM      => 'lib/Perf/Trace/Context.pm', # finds $VERSION
+    PREREQ_PM         => {}, # e.g., Module::Name => 1.1
+    ($] >= 5.005 ?     ## Add these new keywords supported since 5.005
+      (ABSTRACT_FROM  => 'lib/Perf/Trace/Context.pm', # retrieve abstract from module
+       AUTHOR         => 'Tom Zanussi <tzanussi@gmail.com>') : ()),
+    LIBS              => [''], # e.g., '-lm'
+    DEFINE            => '-I ../..', # e.g., '-DHAVE_SOMETHING'
+    INC               => '-I.', # e.g., '-I. -I/usr/include/other'
+       # Un-comment this if you add C files to link with later:
+    OBJECT            => 'Context.o', # link all the C files too
+);
diff --git a/tools/perf/scripts/perl/Perf-Trace-Util/README b/tools/perf/scripts/perl/Perf-Trace-Util/README
new file mode 100644 (file)
index 0000000..9a97076
--- /dev/null
@@ -0,0 +1,59 @@
+Perf-Trace-Util version 0.01
+============================
+
+This module contains utility functions for use with perf trace.
+
+Core.pm and Util.pm are pure Perl modules; Core.pm contains routines
+that the core perf support for Perl calls on and should always be
+'used', while Util.pm contains useful but optional utility functions
+that scripts may want to use.  Context.pm contains the Perl->C
+interface that allows scripts to access data in the embedding perf
+executable; scripts wishing to do that should 'use Context.pm'.
+
+The Perl->C perf interface is completely driven by Context.xs.  If you
+want to add new Perl functions that end up accessing C data in the
+perf executable, you add desciptions of the new functions here.
+scripting_context is a pointer to the perf data in the perf executable
+that you want to access - it's passed as the second parameter,
+$context, to all handler functions.
+
+After you do that:
+
+  perl Makefile.PL   # to create a Makefile for the next step
+  make               # to create Context.c
+
+  edit Context.c to add const to the char* file = __FILE__ line in
+  XS(boot_Perf__Trace__Context) to silence a warning/error.
+
+  You can delete the Makefile, object files and anything else that was
+  generated e.g. blib and shared library, etc, except for of course
+  Context.c
+
+  You should then be able to run the normal perf make as usual.
+
+INSTALLATION
+
+Building perf with perf trace Perl scripting should install this
+module in the right place.
+
+You should make sure libperl and ExtUtils/Embed.pm are installed first
+e.g. apt-get install libperl-dev or yum install perl-ExtUtils-Embed.
+
+DEPENDENCIES
+
+This module requires these other modules and libraries:
+
+  None
+
+COPYRIGHT AND LICENCE
+
+Copyright (C) 2009 by Tom Zanussi <tzanussi@gmail.com>
+
+This library is free software; you can redistribute it and/or modify
+it under the same terms as Perl itself, either Perl version 5.10.0 or,
+at your option, any later version of Perl 5 you may have available.
+
+Alternatively, this software may be distributed under the terms of the
+GNU General Public License ("GPL") version 2 as published by the Free
+Software Foundation.
+
diff --git a/tools/perf/scripts/perl/Perf-Trace-Util/lib/Perf/Trace/Context.pm b/tools/perf/scripts/perl/Perf-Trace-Util/lib/Perf/Trace/Context.pm
new file mode 100644 (file)
index 0000000..6c7f365
--- /dev/null
@@ -0,0 +1,55 @@
+package Perf::Trace::Context;
+
+use 5.010000;
+use strict;
+use warnings;
+
+require Exporter;
+
+our @ISA = qw(Exporter);
+
+our %EXPORT_TAGS = ( 'all' => [ qw(
+) ] );
+
+our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
+
+our @EXPORT = qw(
+       common_pc common_flags common_lock_depth
+);
+
+our $VERSION = '0.01';
+
+require XSLoader;
+XSLoader::load('Perf::Trace::Context', $VERSION);
+
+1;
+__END__
+=head1 NAME
+
+Perf::Trace::Context - Perl extension for accessing functions in perf.
+
+=head1 SYNOPSIS
+
+  use Perf::Trace::Context;
+
+=head1 SEE ALSO
+
+Perf (trace) documentation
+
+=head1 AUTHOR
+
+Tom Zanussi, E<lt>tzanussi@gmail.com<gt>
+
+=head1 COPYRIGHT AND LICENSE
+
+Copyright (C) 2009 by Tom Zanussi
+
+This library is free software; you can redistribute it and/or modify
+it under the same terms as Perl itself, either Perl version 5.10.0 or,
+at your option, any later version of Perl 5 you may have available.
+
+Alternatively, this software may be distributed under the terms of the
+GNU General Public License ("GPL") version 2 as published by the Free
+Software Foundation.
+
+=cut
diff --git a/tools/perf/scripts/perl/Perf-Trace-Util/lib/Perf/Trace/Core.pm b/tools/perf/scripts/perl/Perf-Trace-Util/lib/Perf/Trace/Core.pm
new file mode 100644 (file)
index 0000000..9df376a
--- /dev/null
@@ -0,0 +1,192 @@
+package Perf::Trace::Core;
+
+use 5.010000;
+use strict;
+use warnings;
+
+require Exporter;
+
+our @ISA = qw(Exporter);
+
+our %EXPORT_TAGS = ( 'all' => [ qw(
+) ] );
+
+our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
+
+our @EXPORT = qw(
+define_flag_field define_flag_value flag_str dump_flag_fields
+define_symbolic_field define_symbolic_value symbol_str dump_symbolic_fields
+trace_flag_str
+);
+
+our $VERSION = '0.01';
+
+my %trace_flags = (0x00 => "NONE",
+                  0x01 => "IRQS_OFF",
+                  0x02 => "IRQS_NOSUPPORT",
+                  0x04 => "NEED_RESCHED",
+                  0x08 => "HARDIRQ",
+                  0x10 => "SOFTIRQ");
+
+sub trace_flag_str
+{
+    my ($value) = @_;
+
+    my $string;
+
+    my $print_delim = 0;
+
+    foreach my $idx (sort {$a <=> $b} keys %trace_flags) {
+       if (!$value && !$idx) {
+           $string .= "NONE";
+           last;
+       }
+
+       if ($idx && ($value & $idx) == $idx) {
+           if ($print_delim) {
+               $string .= " | ";
+           }
+           $string .= "$trace_flags{$idx}";
+           $print_delim = 1;
+           $value &= ~$idx;
+       }
+    }
+
+    return $string;
+}
+
+my %flag_fields;
+my %symbolic_fields;
+
+sub flag_str
+{
+    my ($event_name, $field_name, $value) = @_;
+
+    my $string;
+
+    if ($flag_fields{$event_name}{$field_name}) {
+       my $print_delim = 0;
+       foreach my $idx (sort {$a <=> $b} keys %{$flag_fields{$event_name}{$field_name}{"values"}}) {
+           if (!$value && !$idx) {
+               $string .= "$flag_fields{$event_name}{$field_name}{'values'}{$idx}";
+               last;
+           }
+           if ($idx && ($value & $idx) == $idx) {
+               if ($print_delim && $flag_fields{$event_name}{$field_name}{'delim'}) {
+                   $string .= " $flag_fields{$event_name}{$field_name}{'delim'} ";
+               }
+               $string .= "$flag_fields{$event_name}{$field_name}{'values'}{$idx}";
+               $print_delim = 1;
+               $value &= ~$idx;
+           }
+       }
+    }
+
+    return $string;
+}
+
+sub define_flag_field
+{
+    my ($event_name, $field_name, $delim) = @_;
+
+    $flag_fields{$event_name}{$field_name}{"delim"} = $delim;
+}
+
+sub define_flag_value
+{
+    my ($event_name, $field_name, $value, $field_str) = @_;
+
+    $flag_fields{$event_name}{$field_name}{"values"}{$value} = $field_str;
+}
+
+sub dump_flag_fields
+{
+    for my $event (keys %flag_fields) {
+       print "event $event:\n";
+       for my $field (keys %{$flag_fields{$event}}) {
+           print "    field: $field:\n";
+           print "        delim: $flag_fields{$event}{$field}{'delim'}\n";
+           foreach my $idx (sort {$a <=> $b} keys %{$flag_fields{$event}{$field}{"values"}}) {
+               print "        value $idx: $flag_fields{$event}{$field}{'values'}{$idx}\n";
+           }
+       }
+    }
+}
+
+sub symbol_str
+{
+    my ($event_name, $field_name, $value) = @_;
+
+    if ($symbolic_fields{$event_name}{$field_name}) {
+       foreach my $idx (sort {$a <=> $b} keys %{$symbolic_fields{$event_name}{$field_name}{"values"}}) {
+           if (!$value && !$idx) {
+               return "$symbolic_fields{$event_name}{$field_name}{'values'}{$idx}";
+               last;
+           }
+           if ($value == $idx) {
+               return "$symbolic_fields{$event_name}{$field_name}{'values'}{$idx}";
+           }
+       }
+    }
+
+    return undef;
+}
+
+sub define_symbolic_field
+{
+    my ($event_name, $field_name) = @_;
+
+    # nothing to do, really
+}
+
+sub define_symbolic_value
+{
+    my ($event_name, $field_name, $value, $field_str) = @_;
+
+    $symbolic_fields{$event_name}{$field_name}{"values"}{$value} = $field_str;
+}
+
+sub dump_symbolic_fields
+{
+    for my $event (keys %symbolic_fields) {
+       print "event $event:\n";
+       for my $field (keys %{$symbolic_fields{$event}}) {
+           print "    field: $field:\n";
+           foreach my $idx (sort {$a <=> $b} keys %{$symbolic_fields{$event}{$field}{"values"}}) {
+               print "        value $idx: $symbolic_fields{$event}{$field}{'values'}{$idx}\n";
+           }
+       }
+    }
+}
+
+1;
+__END__
+=head1 NAME
+
+Perf::Trace::Core - Perl extension for perf trace
+
+=head1 SYNOPSIS
+
+  use Perf::Trace::Core
+
+=head1 SEE ALSO
+
+Perf (trace) documentation
+
+=head1 AUTHOR
+
+Tom Zanussi, E<lt>tzanussi@gmail.com<gt>
+
+=head1 COPYRIGHT AND LICENSE
+
+Copyright (C) 2009 by Tom Zanussi
+
+This library is free software; you can redistribute it and/or modify
+it under the same terms as Perl itself, either Perl version 5.10.0 or,
+at your option, any later version of Perl 5 you may have available.
+
+Alternatively, this software may be distributed under the terms of the
+GNU General Public License ("GPL") version 2 as published by the Free
+Software Foundation.
+
+=cut
diff --git a/tools/perf/scripts/perl/Perf-Trace-Util/lib/Perf/Trace/Util.pm b/tools/perf/scripts/perl/Perf-Trace-Util/lib/Perf/Trace/Util.pm
new file mode 100644 (file)
index 0000000..052f132
--- /dev/null
@@ -0,0 +1,88 @@
+package Perf::Trace::Util;
+
+use 5.010000;
+use strict;
+use warnings;
+
+require Exporter;
+
+our @ISA = qw(Exporter);
+
+our %EXPORT_TAGS = ( 'all' => [ qw(
+) ] );
+
+our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
+
+our @EXPORT = qw(
+avg nsecs nsecs_secs nsecs_nsecs nsecs_usecs print_nsecs
+);
+
+our $VERSION = '0.01';
+
+sub avg
+{
+    my ($total, $n) = @_;
+
+    return $total / $n;
+}
+
+my $NSECS_PER_SEC    = 1000000000;
+
+sub nsecs
+{
+    my ($secs, $nsecs) = @_;
+
+    return $secs * $NSECS_PER_SEC + $nsecs;
+}
+
+sub nsecs_secs {
+    my ($nsecs) = @_;
+
+    return $nsecs / $NSECS_PER_SEC;
+}
+
+sub nsecs_nsecs {
+    my ($nsecs) = @_;
+
+    return $nsecs - nsecs_secs($nsecs);
+}
+
+sub nsecs_str {
+    my ($nsecs) = @_;
+
+    my $str = sprintf("%5u.%09u", nsecs_secs($nsecs), nsecs_nsecs($nsecs));
+
+    return $str;
+}
+
+1;
+__END__
+=head1 NAME
+
+Perf::Trace::Util - Perl extension for perf trace
+
+=head1 SYNOPSIS
+
+  use Perf::Trace::Util;
+
+=head1 SEE ALSO
+
+Perf (trace) documentation
+
+=head1 AUTHOR
+
+Tom Zanussi, E<lt>tzanussi@gmail.com<gt>
+
+=head1 COPYRIGHT AND LICENSE
+
+Copyright (C) 2009 by Tom Zanussi
+
+This library is free software; you can redistribute it and/or modify
+it under the same terms as Perl itself, either Perl version 5.10.0 or,
+at your option, any later version of Perl 5 you may have available.
+
+Alternatively, this software may be distributed under the terms of the
+GNU General Public License ("GPL") version 2 as published by the Free
+Software Foundation.
+
+=cut
diff --git a/tools/perf/scripts/perl/Perf-Trace-Util/typemap b/tools/perf/scripts/perl/Perf-Trace-Util/typemap
new file mode 100644 (file)
index 0000000..8408368
--- /dev/null
@@ -0,0 +1 @@
+struct scripting_context * T_PTR
diff --git a/tools/perf/scripts/perl/bin/check-perf-trace-record b/tools/perf/scripts/perl/bin/check-perf-trace-record
new file mode 100644 (file)
index 0000000..c7ec5de
--- /dev/null
@@ -0,0 +1,7 @@
+#!/bin/bash
+perf record -c 1 -f -a -M -R -e kmem:kmalloc -e irq:softirq_entry
+
+
+
+
+
diff --git a/tools/perf/scripts/perl/bin/check-perf-trace-report b/tools/perf/scripts/perl/bin/check-perf-trace-report
new file mode 100644 (file)
index 0000000..89948b0
--- /dev/null
@@ -0,0 +1,5 @@
+#!/bin/bash
+perf trace -s ~/libexec/perf-core/scripts/perl/check-perf-trace.pl
+
+
+
diff --git a/tools/perf/scripts/perl/bin/rw-by-file-record b/tools/perf/scripts/perl/bin/rw-by-file-record
new file mode 100644 (file)
index 0000000..b25056e
--- /dev/null
@@ -0,0 +1,2 @@
+#!/bin/bash
+perf record -c 1 -f -a -M -R -e syscalls:sys_enter_read -e syscalls:sys_enter_write
diff --git a/tools/perf/scripts/perl/bin/rw-by-file-report b/tools/perf/scripts/perl/bin/rw-by-file-report
new file mode 100644 (file)
index 0000000..f5dcf9c
--- /dev/null
@@ -0,0 +1,5 @@
+#!/bin/bash
+perf trace -s ~/libexec/perf-core/scripts/perl/rw-by-file.pl
+
+
+
diff --git a/tools/perf/scripts/perl/bin/rw-by-pid-record b/tools/perf/scripts/perl/bin/rw-by-pid-record
new file mode 100644 (file)
index 0000000..8903979
--- /dev/null
@@ -0,0 +1,2 @@
+#!/bin/bash
+perf record -c 1 -f -a -M -R -e syscalls:sys_enter_read -e syscalls:sys_exit_read -e syscalls:sys_enter_write -e syscalls:sys_exit_write
diff --git a/tools/perf/scripts/perl/bin/rw-by-pid-report b/tools/perf/scripts/perl/bin/rw-by-pid-report
new file mode 100644 (file)
index 0000000..cea16f7
--- /dev/null
@@ -0,0 +1,5 @@
+#!/bin/bash
+perf trace -s ~/libexec/perf-core/scripts/perl/rw-by-pid.pl
+
+
+
diff --git a/tools/perf/scripts/perl/bin/wakeup-latency-record b/tools/perf/scripts/perl/bin/wakeup-latency-record
new file mode 100644 (file)
index 0000000..6abedda
--- /dev/null
@@ -0,0 +1,6 @@
+#!/bin/bash
+perf record -c 1 -f -a -M -R -e sched:sched_switch -e sched:sched_wakeup
+
+
+
+
diff --git a/tools/perf/scripts/perl/bin/wakeup-latency-report b/tools/perf/scripts/perl/bin/wakeup-latency-report
new file mode 100644 (file)
index 0000000..85769dc
--- /dev/null
@@ -0,0 +1,5 @@
+#!/bin/bash
+perf trace -s ~/libexec/perf-core/scripts/perl/wakeup-latency.pl
+
+
+
diff --git a/tools/perf/scripts/perl/bin/workqueue-stats-record b/tools/perf/scripts/perl/bin/workqueue-stats-record
new file mode 100644 (file)
index 0000000..fce6637
--- /dev/null
@@ -0,0 +1,2 @@
+#!/bin/bash
+perf record -c 1 -f -a -M -R -e workqueue:workqueue_creation -e workqueue:workqueue_destruction -e workqueue:workqueue_execution -e workqueue:workqueue_insertion
diff --git a/tools/perf/scripts/perl/bin/workqueue-stats-report b/tools/perf/scripts/perl/bin/workqueue-stats-report
new file mode 100644 (file)
index 0000000..aa68435
--- /dev/null
@@ -0,0 +1,6 @@
+#!/bin/bash
+perf trace -s ~/libexec/perf-core/scripts/perl/workqueue-stats.pl
+
+
+
+
diff --git a/tools/perf/scripts/perl/check-perf-trace.pl b/tools/perf/scripts/perl/check-perf-trace.pl
new file mode 100644 (file)
index 0000000..4e7dc0a
--- /dev/null
@@ -0,0 +1,106 @@
+# perf trace event handlers, generated by perf trace -g perl
+# (c) 2009, Tom Zanussi <tzanussi@gmail.com>
+# Licensed under the terms of the GNU GPL License version 2
+
+# This script tests basic functionality such as flag and symbol
+# strings, common_xxx() calls back into perf, begin, end, unhandled
+# events, etc.  Basically, if this script runs successfully and
+# displays expected results, perl scripting support should be ok.
+
+use lib "$ENV{'PERF_EXEC_PATH'}/scripts/perl/Perf-Trace-Util/lib";
+use lib "./Perf-Trace-Util/lib";
+use Perf::Trace::Core;
+use Perf::Trace::Context;
+use Perf::Trace::Util;
+
+sub trace_begin
+{
+    print "trace_begin\n";
+}
+
+sub trace_end
+{
+    print "trace_end\n";
+
+    print_unhandled();
+}
+
+sub irq::softirq_entry
+{
+       my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
+           $common_pid, $common_comm,
+           $vec) = @_;
+
+       print_header($event_name, $common_cpu, $common_secs, $common_nsecs,
+                    $common_pid, $common_comm);
+
+       print_uncommon($context);
+
+       printf("vec=%s\n",
+              symbol_str("irq::softirq_entry", "vec", $vec));
+}
+
+sub kmem::kmalloc
+{
+       my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
+           $common_pid, $common_comm,
+           $call_site, $ptr, $bytes_req, $bytes_alloc,
+           $gfp_flags) = @_;
+
+       print_header($event_name, $common_cpu, $common_secs, $common_nsecs,
+                    $common_pid, $common_comm);
+
+       print_uncommon($context);
+
+       printf("call_site=%p, ptr=%p, bytes_req=%u, bytes_alloc=%u, ".
+              "gfp_flags=%s\n",
+              $call_site, $ptr, $bytes_req, $bytes_alloc,
+
+              flag_str("kmem::kmalloc", "gfp_flags", $gfp_flags));
+}
+
+# print trace fields not included in handler args
+sub print_uncommon
+{
+    my ($context) = @_;
+
+    printf("common_preempt_count=%d, common_flags=%s, common_lock_depth=%d, ",
+          common_pc($context), trace_flag_str(common_flags($context)),
+          common_lock_depth($context));
+
+}
+
+my %unhandled;
+
+sub print_unhandled
+{
+    if ((scalar keys %unhandled) == 0) {
+       return;
+    }
+
+    print "\nunhandled events:\n\n";
+
+    printf("%-40s  %10s\n", "event", "count");
+    printf("%-40s  %10s\n", "----------------------------------------",
+          "-----------");
+
+    foreach my $event_name (keys %unhandled) {
+       printf("%-40s  %10d\n", $event_name, $unhandled{$event_name});
+    }
+}
+
+sub trace_unhandled
+{
+    my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
+       $common_pid, $common_comm) = @_;
+
+    $unhandled{$event_name}++;
+}
+
+sub print_header
+{
+       my ($event_name, $cpu, $secs, $nsecs, $pid, $comm) = @_;
+
+       printf("%-20s %5u %05u.%09u %8u %-20s ",
+              $event_name, $cpu, $secs, $nsecs, $pid, $comm);
+}
diff --git a/tools/perf/scripts/perl/rw-by-file.pl b/tools/perf/scripts/perl/rw-by-file.pl
new file mode 100644 (file)
index 0000000..61f9156
--- /dev/null
@@ -0,0 +1,105 @@
+#!/usr/bin/perl -w
+# (c) 2009, Tom Zanussi <tzanussi@gmail.com>
+# Licensed under the terms of the GNU GPL License version 2
+
+# Display r/w activity for files read/written to for a given program
+
+# The common_* event handler fields are the most useful fields common to
+# all events.  They don't necessarily correspond to the 'common_*' fields
+# in the status files.  Those fields not available as handler params can
+# be retrieved via script functions of the form get_common_*().
+
+use 5.010000;
+use strict;
+use warnings;
+
+use lib "$ENV{'PERF_EXEC_PATH'}/scripts/perl/Perf-Trace-Util/lib";
+use lib "./Perf-Trace-Util/lib";
+use Perf::Trace::Core;
+use Perf::Trace::Util;
+
+# change this to the comm of the program you're interested in
+my $for_comm = "perf";
+
+my %reads;
+my %writes;
+
+sub syscalls::sys_enter_read
+{
+    my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
+       $common_pid, $common_comm, $nr, $fd, $buf, $count) = @_;
+
+    if ($common_comm eq $for_comm) {
+       $reads{$fd}{bytes_requested} += $count;
+       $reads{$fd}{total_reads}++;
+    }
+}
+
+sub syscalls::sys_enter_write
+{
+    my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
+       $common_pid, $common_comm, $nr, $fd, $buf, $count) = @_;
+
+    if ($common_comm eq $for_comm) {
+       $writes{$fd}{bytes_written} += $count;
+       $writes{$fd}{total_writes}++;
+    }
+}
+
+sub trace_end
+{
+    printf("file read counts for $for_comm:\n\n");
+
+    printf("%6s  %10s  %10s\n", "fd", "# reads", "bytes_requested");
+    printf("%6s  %10s  %10s\n", "------", "----------", "-----------");
+
+    foreach my $fd (sort {$reads{$b}{bytes_requested} <=>
+                             $reads{$a}{bytes_requested}} keys %reads) {
+       my $total_reads = $reads{$fd}{total_reads};
+       my $bytes_requested = $reads{$fd}{bytes_requested};
+       printf("%6u  %10u  %10u\n", $fd, $total_reads, $bytes_requested);
+    }
+
+    printf("\nfile write counts for $for_comm:\n\n");
+
+    printf("%6s  %10s  %10s\n", "fd", "# writes", "bytes_written");
+    printf("%6s  %10s  %10s\n", "------", "----------", "-----------");
+
+    foreach my $fd (sort {$writes{$b}{bytes_written} <=>
+                             $writes{$a}{bytes_written}} keys %writes) {
+       my $total_writes = $writes{$fd}{total_writes};
+       my $bytes_written = $writes{$fd}{bytes_written};
+       printf("%6u  %10u  %10u\n", $fd, $total_writes, $bytes_written);
+    }
+
+    print_unhandled();
+}
+
+my %unhandled;
+
+sub print_unhandled
+{
+    if ((scalar keys %unhandled) == 0) {
+       return;
+    }
+
+    print "\nunhandled events:\n\n";
+
+    printf("%-40s  %10s\n", "event", "count");
+    printf("%-40s  %10s\n", "----------------------------------------",
+          "-----------");
+
+    foreach my $event_name (keys %unhandled) {
+       printf("%-40s  %10d\n", $event_name, $unhandled{$event_name});
+    }
+}
+
+sub trace_unhandled
+{
+    my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
+       $common_pid, $common_comm) = @_;
+
+    $unhandled{$event_name}++;
+}
+
+
diff --git a/tools/perf/scripts/perl/rw-by-pid.pl b/tools/perf/scripts/perl/rw-by-pid.pl
new file mode 100644 (file)
index 0000000..da601fa
--- /dev/null
@@ -0,0 +1,170 @@
+#!/usr/bin/perl -w
+# (c) 2009, Tom Zanussi <tzanussi@gmail.com>
+# Licensed under the terms of the GNU GPL License version 2
+
+# Display r/w activity for all processes
+
+# The common_* event handler fields are the most useful fields common to
+# all events.  They don't necessarily correspond to the 'common_*' fields
+# in the status files.  Those fields not available as handler params can
+# be retrieved via script functions of the form get_common_*().
+
+use 5.010000;
+use strict;
+use warnings;
+
+use lib "$ENV{'PERF_EXEC_PATH'}/scripts/perl/Perf-Trace-Util/lib";
+use lib "./Perf-Trace-Util/lib";
+use Perf::Trace::Core;
+use Perf::Trace::Util;
+
+my %reads;
+my %writes;
+
+sub syscalls::sys_exit_read
+{
+    my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
+       $common_pid, $common_comm,
+       $nr, $ret) = @_;
+
+    if ($ret > 0) {
+       $reads{$common_pid}{bytes_read} += $ret;
+    } else {
+       if (!defined ($reads{$common_pid}{bytes_read})) {
+           $reads{$common_pid}{bytes_read} = 0;
+       }
+       $reads{$common_pid}{errors}{$ret}++;
+    }
+}
+
+sub syscalls::sys_enter_read
+{
+    my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
+       $common_pid, $common_comm,
+       $nr, $fd, $buf, $count) = @_;
+
+    $reads{$common_pid}{bytes_requested} += $count;
+    $reads{$common_pid}{total_reads}++;
+    $reads{$common_pid}{comm} = $common_comm;
+}
+
+sub syscalls::sys_exit_write
+{
+    my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
+       $common_pid, $common_comm,
+       $nr, $ret) = @_;
+
+    if ($ret <= 0) {
+       $writes{$common_pid}{errors}{$ret}++;
+    }
+}
+
+sub syscalls::sys_enter_write
+{
+    my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
+       $common_pid, $common_comm,
+       $nr, $fd, $buf, $count) = @_;
+
+    $writes{$common_pid}{bytes_written} += $count;
+    $writes{$common_pid}{total_writes}++;
+    $writes{$common_pid}{comm} = $common_comm;
+}
+
+sub trace_end
+{
+    printf("read counts by pid:\n\n");
+
+    printf("%6s  %20s  %10s  %10s  %10s\n", "pid", "comm",
+          "# reads", "bytes_requested", "bytes_read");
+    printf("%6s  %-20s  %10s  %10s  %10s\n", "------", "--------------------",
+          "-----------", "----------", "----------");
+
+    foreach my $pid (sort {$reads{$b}{bytes_read} <=>
+                              $reads{$a}{bytes_read}} keys %reads) {
+       my $comm = $reads{$pid}{comm};
+       my $total_reads = $reads{$pid}{total_reads};
+       my $bytes_requested = $reads{$pid}{bytes_requested};
+       my $bytes_read = $reads{$pid}{bytes_read};
+
+       printf("%6s  %-20s  %10s  %10s  %10s\n", $pid, $comm,
+              $total_reads, $bytes_requested, $bytes_read);
+    }
+
+    printf("\nfailed reads by pid:\n\n");
+
+    printf("%6s  %20s  %6s  %10s\n", "pid", "comm", "error #", "# errors");
+    printf("%6s  %20s  %6s  %10s\n", "------", "--------------------",
+          "------", "----------");
+
+    foreach my $pid (keys %reads) {
+       my $comm = $reads{$pid}{comm};
+       foreach my $err (sort {$reads{$b}{comm} cmp $reads{$a}{comm}}
+                        keys %{$reads{$pid}{errors}}) {
+           my $errors = $reads{$pid}{errors}{$err};
+
+           printf("%6d  %-20s  %6d  %10s\n", $pid, $comm, $err, $errors);
+       }
+    }
+
+    printf("\nwrite counts by pid:\n\n");
+
+    printf("%6s  %20s  %10s  %10s\n", "pid", "comm",
+          "# writes", "bytes_written");
+    printf("%6s  %-20s  %10s  %10s\n", "------", "--------------------",
+          "-----------", "----------");
+
+    foreach my $pid (sort {$writes{$b}{bytes_written} <=>
+                              $writes{$a}{bytes_written}} keys %writes) {
+       my $comm = $writes{$pid}{comm};
+       my $total_writes = $writes{$pid}{total_writes};
+       my $bytes_written = $writes{$pid}{bytes_written};
+
+       printf("%6s  %-20s  %10s  %10s\n", $pid, $comm,
+              $total_writes, $bytes_written);
+    }
+
+    printf("\nfailed writes by pid:\n\n");
+
+    printf("%6s  %20s  %6s  %10s\n", "pid", "comm", "error #", "# errors");
+    printf("%6s  %20s  %6s  %10s\n", "------", "--------------------",
+          "------", "----------");
+
+    foreach my $pid (keys %writes) {
+       my $comm = $writes{$pid}{comm};
+       foreach my $err (sort {$writes{$b}{comm} cmp $writes{$a}{comm}}
+                        keys %{$writes{$pid}{errors}}) {
+           my $errors = $writes{$pid}{errors}{$err};
+
+           printf("%6d  %-20s  %6d  %10s\n", $pid, $comm, $err, $errors);
+       }
+    }
+
+    print_unhandled();
+}
+
+my %unhandled;
+
+sub print_unhandled
+{
+    if ((scalar keys %unhandled) == 0) {
+       return;
+    }
+
+    print "\nunhandled events:\n\n";
+
+    printf("%-40s  %10s\n", "event", "count");
+    printf("%-40s  %10s\n", "----------------------------------------",
+          "-----------");
+
+    foreach my $event_name (keys %unhandled) {
+       printf("%-40s  %10d\n", $event_name, $unhandled{$event_name});
+    }
+}
+
+sub trace_unhandled
+{
+    my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
+       $common_pid, $common_comm) = @_;
+
+    $unhandled{$event_name}++;
+}
diff --git a/tools/perf/scripts/perl/wakeup-latency.pl b/tools/perf/scripts/perl/wakeup-latency.pl
new file mode 100644 (file)
index 0000000..ed58ef2
--- /dev/null
@@ -0,0 +1,103 @@
+#!/usr/bin/perl -w
+# (c) 2009, Tom Zanussi <tzanussi@gmail.com>
+# Licensed under the terms of the GNU GPL License version 2
+
+# Display avg/min/max wakeup latency
+
+# The common_* event handler fields are the most useful fields common to
+# all events.  They don't necessarily correspond to the 'common_*' fields
+# in the status files.  Those fields not available as handler params can
+# be retrieved via script functions of the form get_common_*().
+
+use 5.010000;
+use strict;
+use warnings;
+
+use lib "$ENV{'PERF_EXEC_PATH'}/scripts/perl/Perf-Trace-Util/lib";
+use lib "./Perf-Trace-Util/lib";
+use Perf::Trace::Core;
+use Perf::Trace::Util;
+
+my %last_wakeup;
+
+my $max_wakeup_latency;
+my $min_wakeup_latency;
+my $total_wakeup_latency;
+my $total_wakeups;
+
+sub sched::sched_switch
+{
+    my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
+       $common_pid, $common_comm,
+       $prev_comm, $prev_pid, $prev_prio, $prev_state, $next_comm, $next_pid,
+       $next_prio) = @_;
+
+    my $wakeup_ts = $last_wakeup{$common_cpu}{ts};
+    if ($wakeup_ts) {
+       my $switch_ts = nsecs($common_secs, $common_nsecs);
+       my $wakeup_latency = $switch_ts - $wakeup_ts;
+       if ($wakeup_latency > $max_wakeup_latency) {
+           $max_wakeup_latency = $wakeup_latency;
+       }
+       if ($wakeup_latency < $min_wakeup_latency) {
+           $min_wakeup_latency = $wakeup_latency;
+       }
+       $total_wakeup_latency += $wakeup_latency;
+       $total_wakeups++;
+    }
+    $last_wakeup{$common_cpu}{ts} = 0;
+}
+
+sub sched::sched_wakeup
+{
+    my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
+       $common_pid, $common_comm,
+       $comm, $pid, $prio, $success, $target_cpu) = @_;
+
+    $last_wakeup{$target_cpu}{ts} = nsecs($common_secs, $common_nsecs);
+}
+
+sub trace_begin
+{
+    $min_wakeup_latency = 1000000000;
+    $max_wakeup_latency = 0;
+}
+
+sub trace_end
+{
+    printf("wakeup_latency stats:\n\n");
+    print "total_wakeups: $total_wakeups\n";
+    printf("avg_wakeup_latency (ns): %u\n",
+          avg($total_wakeup_latency, $total_wakeups));
+    printf("min_wakeup_latency (ns): %u\n", $min_wakeup_latency);
+    printf("max_wakeup_latency (ns): %u\n", $max_wakeup_latency);
+
+    print_unhandled();
+}
+
+my %unhandled;
+
+sub print_unhandled
+{
+    if ((scalar keys %unhandled) == 0) {
+       return;
+    }
+
+    print "\nunhandled events:\n\n";
+
+    printf("%-40s  %10s\n", "event", "count");
+    printf("%-40s  %10s\n", "----------------------------------------",
+          "-----------");
+
+    foreach my $event_name (keys %unhandled) {
+       printf("%-40s  %10d\n", $event_name, $unhandled{$event_name});
+    }
+}
+
+sub trace_unhandled
+{
+    my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
+       $common_pid, $common_comm) = @_;
+
+    $unhandled{$event_name}++;
+}
diff --git a/tools/perf/scripts/perl/workqueue-stats.pl b/tools/perf/scripts/perl/workqueue-stats.pl
new file mode 100644 (file)
index 0000000..511302c
--- /dev/null
@@ -0,0 +1,129 @@
+#!/usr/bin/perl -w
+# (c) 2009, Tom Zanussi <tzanussi@gmail.com>
+# Licensed under the terms of the GNU GPL License version 2
+
+# Displays workqueue stats
+#
+# Usage:
+#
+#   perf record -c 1 -f -a -R -e workqueue:workqueue_creation -e
+#     workqueue:workqueue_destruction -e workqueue:workqueue_execution
+#     -e workqueue:workqueue_insertion
+#
+#   perf trace -p -s tools/perf/scripts/perl/workqueue-stats.pl
+
+use 5.010000;
+use strict;
+use warnings;
+
+use lib "$ENV{'PERF_EXEC_PATH'}/scripts/perl/Perf-Trace-Util/lib";
+use lib "./Perf-Trace-Util/lib";
+use Perf::Trace::Core;
+use Perf::Trace::Util;
+
+my @cpus;
+
+sub workqueue::workqueue_destruction
+{
+    my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
+       $common_pid, $common_comm,
+       $thread_comm, $thread_pid) = @_;
+
+    $cpus[$common_cpu]{$thread_pid}{destroyed}++;
+    $cpus[$common_cpu]{$thread_pid}{comm} = $thread_comm;
+}
+
+sub workqueue::workqueue_creation
+{
+    my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
+       $common_pid, $common_comm,
+       $thread_comm, $thread_pid, $cpu) = @_;
+
+    $cpus[$common_cpu]{$thread_pid}{created}++;
+    $cpus[$common_cpu]{$thread_pid}{comm} = $thread_comm;
+}
+
+sub workqueue::workqueue_execution
+{
+    my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
+       $common_pid, $common_comm,
+       $thread_comm, $thread_pid, $func) = @_;
+
+    $cpus[$common_cpu]{$thread_pid}{executed}++;
+    $cpus[$common_cpu]{$thread_pid}{comm} = $thread_comm;
+}
+
+sub workqueue::workqueue_insertion
+{
+    my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
+       $common_pid, $common_comm,
+       $thread_comm, $thread_pid, $func) = @_;
+
+    $cpus[$common_cpu]{$thread_pid}{inserted}++;
+    $cpus[$common_cpu]{$thread_pid}{comm} = $thread_comm;
+}
+
+sub trace_end
+{
+    print "workqueue work stats:\n\n";
+    my $cpu = 0;
+    printf("%3s %6s %6s\t%-20s\n", "cpu", "ins", "exec", "name");
+    printf("%3s %6s %6s\t%-20s\n", "---", "---", "----", "----");
+    foreach my $pidhash (@cpus) {
+       while ((my $pid, my $wqhash) = each %$pidhash) {
+           my $ins = $$wqhash{'inserted'};
+           my $exe = $$wqhash{'executed'};
+           my $comm = $$wqhash{'comm'};
+           if ($ins || $exe) {
+               printf("%3u %6u %6u\t%-20s\n", $cpu, $ins, $exe, $comm);
+           }
+       }
+       $cpu++;
+    }
+
+    $cpu = 0;
+    print "\nworkqueue lifecycle stats:\n\n";
+    printf("%3s %6s %6s\t%-20s\n", "cpu", "created", "destroyed", "name");
+    printf("%3s %6s %6s\t%-20s\n", "---", "-------", "---------", "----");
+    foreach my $pidhash (@cpus) {
+       while ((my $pid, my $wqhash) = each %$pidhash) {
+           my $created = $$wqhash{'created'};
+           my $destroyed = $$wqhash{'destroyed'};
+           my $comm = $$wqhash{'comm'};
+           if ($created || $destroyed) {
+               printf("%3u %6u %6u\t%-20s\n", $cpu, $created, $destroyed,
+                      $comm);
+           }
+       }
+       $cpu++;
+    }
+
+    print_unhandled();
+}
+
+my %unhandled;
+
+sub print_unhandled
+{
+    if ((scalar keys %unhandled) == 0) {
+       return;
+    }
+
+    print "\nunhandled events:\n\n";
+
+    printf("%-40s  %10s\n", "event", "count");
+    printf("%-40s  %10s\n", "----------------------------------------",
+          "-----------");
+
+    foreach my $event_name (keys %unhandled) {
+       printf("%-40s  %10d\n", $event_name, $unhandled{$event_name});
+    }
+}
+
+sub trace_unhandled
+{
+    my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
+       $common_pid, $common_comm) = @_;
+
+    $unhandled{$event_name}++;
+}
index 6f8ea9d..918eb37 100644 (file)
@@ -1,10 +1,15 @@
-#ifndef CACHE_H
-#define CACHE_H
+#ifndef __PERF_CACHE_H
+#define __PERF_CACHE_H
 
 #include "util.h"
 #include "strbuf.h"
 #include "../perf.h"
 
+#define CMD_EXEC_PATH "--exec-path"
+#define CMD_PERF_DIR "--perf-dir="
+#define CMD_WORK_TREE "--work-tree="
+#define CMD_DEBUGFS_DIR "--debugfs-dir="
+
 #define PERF_DIR_ENVIRONMENT "PERF_DIR"
 #define PERF_WORK_TREE_ENVIRONMENT "PERF_WORK_TREE"
 #define DEFAULT_PERF_DIR_ENVIRONMENT ".perf"
@@ -117,4 +122,4 @@ extern char *perf_pathdup(const char *fmt, ...)
 
 extern size_t strlcpy(char *dest, const char *src, size_t size);
 
-#endif /* CACHE_H */
+#endif /* __PERF_CACHE_H */
index 3b8380f..b3b7125 100644 (file)
@@ -206,7 +206,7 @@ fill_node(struct callchain_node *node, struct ip_callchain *chain,
        }
        node->val_nr = chain->nr - start;
        if (!node->val_nr)
-               printf("Warning: empty node in callchain tree\n");
+               pr_warning("Warning: empty node in callchain tree\n");
 }
 
 static void
index 43cf3ea..ad4626d 100644 (file)
@@ -58,4 +58,4 @@ static inline u64 cumul_hits(struct callchain_node *node)
 int register_callchain_param(struct callchain_param *param);
 void append_chain(struct callchain_node *root, struct ip_callchain *chain,
                  struct symbol **syms);
-#endif
+#endif /* __PERF_CALLCHAIN_H */
index 58d5975..24e8809 100644 (file)
@@ -1,5 +1,5 @@
-#ifndef COLOR_H
-#define COLOR_H
+#ifndef __PERF_COLOR_H
+#define __PERF_COLOR_H
 
 /* "\033[1;38;5;2xx;48;5;2xxm\0" is 23 bytes */
 #define COLOR_MAXLEN 24
@@ -39,4 +39,4 @@ int color_fwrite_lines(FILE *fp, const char *color, size_t count, const char *bu
 int percent_color_fprintf(FILE *fp, const char *fmt, double percent);
 const char *get_percent_color(double percent);
 
-#endif /* COLOR_H */
+#endif /* __PERF_COLOR_H */
index 0b791bd..3507362 100644 (file)
@@ -29,3 +29,11 @@ unsigned char sane_ctype[256] = {
        A, A, A, A, A, A, A, A, A, A, A, R, R, P, P, 0,         /* 112..127 */
        /* Nothing in the 128.. range */
 };
+
+const char *graph_line =
+       "_____________________________________________________________________"
+       "_____________________________________________________________________";
+const char *graph_dotted_line =
+       "---------------------------------------------------------------------"
+       "---------------------------------------------------------------------"
+       "---------------------------------------------------------------------";
diff --git a/tools/perf/util/data_map.c b/tools/perf/util/data_map.c
new file mode 100644 (file)
index 0000000..ca0bedf
--- /dev/null
@@ -0,0 +1,291 @@
+#include "data_map.h"
+#include "symbol.h"
+#include "util.h"
+#include "debug.h"
+
+
+static struct perf_file_handler *curr_handler;
+static unsigned long   mmap_window = 32;
+static char            __cwd[PATH_MAX];
+
+static int process_event_stub(event_t *event __used)
+{
+       dump_printf(": unhandled!\n");
+       return 0;
+}
+
+void register_perf_file_handler(struct perf_file_handler *handler)
+{
+       if (!handler->process_sample_event)
+               handler->process_sample_event = process_event_stub;
+       if (!handler->process_mmap_event)
+               handler->process_mmap_event = process_event_stub;
+       if (!handler->process_comm_event)
+               handler->process_comm_event = process_event_stub;
+       if (!handler->process_fork_event)
+               handler->process_fork_event = process_event_stub;
+       if (!handler->process_exit_event)
+               handler->process_exit_event = process_event_stub;
+       if (!handler->process_lost_event)
+               handler->process_lost_event = process_event_stub;
+       if (!handler->process_read_event)
+               handler->process_read_event = process_event_stub;
+       if (!handler->process_throttle_event)
+               handler->process_throttle_event = process_event_stub;
+       if (!handler->process_unthrottle_event)
+               handler->process_unthrottle_event = process_event_stub;
+
+       curr_handler = handler;
+}
+
+static const char *event__name[] = {
+       [0]                      = "TOTAL",
+       [PERF_RECORD_MMAP]       = "MMAP",
+       [PERF_RECORD_LOST]       = "LOST",
+       [PERF_RECORD_COMM]       = "COMM",
+       [PERF_RECORD_EXIT]       = "EXIT",
+       [PERF_RECORD_THROTTLE]   = "THROTTLE",
+       [PERF_RECORD_UNTHROTTLE] = "UNTHROTTLE",
+       [PERF_RECORD_FORK]       = "FORK",
+       [PERF_RECORD_READ]       = "READ",
+       [PERF_RECORD_SAMPLE]     = "SAMPLE",
+};
+
+unsigned long event__total[PERF_RECORD_MAX];
+
+void event__print_totals(void)
+{
+       int i;
+       for (i = 0; i < PERF_RECORD_MAX; ++i)
+               pr_info("%10s events: %10ld\n",
+                       event__name[i], event__total[i]);
+}
+
+static int
+process_event(event_t *event, unsigned long offset, unsigned long head)
+{
+       trace_event(event);
+
+       if (event->header.type < PERF_RECORD_MAX) {
+               dump_printf("%p [%p]: PERF_RECORD_%s",
+                           (void *)(offset + head),
+                           (void *)(long)(event->header.size),
+                           event__name[event->header.type]);
+               ++event__total[0];
+               ++event__total[event->header.type];
+       }
+
+       switch (event->header.type) {
+       case PERF_RECORD_SAMPLE:
+               return curr_handler->process_sample_event(event);
+       case PERF_RECORD_MMAP:
+               return curr_handler->process_mmap_event(event);
+       case PERF_RECORD_COMM:
+               return curr_handler->process_comm_event(event);
+       case PERF_RECORD_FORK:
+               return curr_handler->process_fork_event(event);
+       case PERF_RECORD_EXIT:
+               return curr_handler->process_exit_event(event);
+       case PERF_RECORD_LOST:
+               return curr_handler->process_lost_event(event);
+       case PERF_RECORD_READ:
+               return curr_handler->process_read_event(event);
+       case PERF_RECORD_THROTTLE:
+               return curr_handler->process_throttle_event(event);
+       case PERF_RECORD_UNTHROTTLE:
+               return curr_handler->process_unthrottle_event(event);
+       default:
+               curr_handler->total_unknown++;
+               return -1;
+       }
+}
+
+int perf_header__read_build_ids(int input, off_t offset, off_t size)
+{
+       struct build_id_event bev;
+       char filename[PATH_MAX];
+       off_t limit = offset + size;
+       int err = -1;
+
+       while (offset < limit) {
+               struct dso *dso;
+               ssize_t len;
+
+               if (read(input, &bev, sizeof(bev)) != sizeof(bev))
+                       goto out;
+
+               len = bev.header.size - sizeof(bev);
+               if (read(input, filename, len) != len)
+                       goto out;
+
+               dso = dsos__findnew(filename);
+               if (dso != NULL)
+                       dso__set_build_id(dso, &bev.build_id);
+
+               offset += bev.header.size;
+       }
+       err = 0;
+out:
+       return err;
+}
+
+int mmap_dispatch_perf_file(struct perf_header **pheader,
+                           const char *input_name,
+                           int force,
+                           int full_paths,
+                           int *cwdlen,
+                           char **cwd)
+{
+       int err;
+       struct perf_header *header;
+       unsigned long head, shift;
+       unsigned long offset = 0;
+       struct stat input_stat;
+       size_t  page_size;
+       u64 sample_type;
+       event_t *event;
+       uint32_t size;
+       int input;
+       char *buf;
+
+       if (curr_handler == NULL) {
+               pr_debug("Forgot to register perf file handler\n");
+               return -EINVAL;
+       }
+
+       page_size = getpagesize();
+
+       input = open(input_name, O_RDONLY);
+       if (input < 0) {
+               pr_err("Failed to open file: %s", input_name);
+               if (!strcmp(input_name, "perf.data"))
+                       pr_err("  (try 'perf record' first)");
+               pr_err("\n");
+               return -errno;
+       }
+
+       if (fstat(input, &input_stat) < 0) {
+               pr_err("failed to stat file");
+               err = -errno;
+               goto out_close;
+       }
+
+       err = -EACCES;
+       if (!force && input_stat.st_uid && (input_stat.st_uid != geteuid())) {
+               pr_err("file: %s not owned by current user or root\n",
+                       input_name);
+               goto out_close;
+       }
+
+       if (input_stat.st_size == 0) {
+               pr_info("zero-sized file, nothing to do!\n");
+               goto done;
+       }
+
+       err = -ENOMEM;
+       header = perf_header__new();
+       if (header == NULL)
+               goto out_close;
+
+       err = perf_header__read(header, input);
+       if (err < 0)
+               goto out_delete;
+       *pheader = header;
+       head = header->data_offset;
+
+       sample_type = perf_header__sample_type(header);
+
+       err = -EINVAL;
+       if (curr_handler->sample_type_check &&
+           curr_handler->sample_type_check(sample_type) < 0)
+               goto out_delete;
+
+       if (!full_paths) {
+               if (getcwd(__cwd, sizeof(__cwd)) == NULL) {
+                       pr_err("failed to get the current directory\n");
+                       err = -errno;
+                       goto out_delete;
+               }
+               *cwd = __cwd;
+               *cwdlen = strlen(*cwd);
+       } else {
+               *cwd = NULL;
+               *cwdlen = 0;
+       }
+
+       shift = page_size * (head / page_size);
+       offset += shift;
+       head -= shift;
+
+remap:
+       buf = mmap(NULL, page_size * mmap_window, PROT_READ,
+                  MAP_SHARED, input, offset);
+       if (buf == MAP_FAILED) {
+               pr_err("failed to mmap file\n");
+               err = -errno;
+               goto out_delete;
+       }
+
+more:
+       event = (event_t *)(buf + head);
+
+       size = event->header.size;
+       if (!size)
+               size = 8;
+
+       if (head + event->header.size >= page_size * mmap_window) {
+               int munmap_ret;
+
+               shift = page_size * (head / page_size);
+
+               munmap_ret = munmap(buf, page_size * mmap_window);
+               assert(munmap_ret == 0);
+
+               offset += shift;
+               head -= shift;
+               goto remap;
+       }
+
+       size = event->header.size;
+
+       dump_printf("\n%p [%p]: event: %d\n",
+                       (void *)(offset + head),
+                       (void *)(long)event->header.size,
+                       event->header.type);
+
+       if (!size || process_event(event, offset, head) < 0) {
+
+               dump_printf("%p [%p]: skipping unknown header type: %d\n",
+                       (void *)(offset + head),
+                       (void *)(long)(event->header.size),
+                       event->header.type);
+
+               /*
+                * assume we lost track of the stream, check alignment, and
+                * increment a single u64 in the hope to catch on again 'soon'.
+                */
+
+               if (unlikely(head & 7))
+                       head &= ~7ULL;
+
+               size = 8;
+       }
+
+       head += size;
+
+       if (offset + head >= header->data_offset + header->data_size)
+               goto done;
+
+       if (offset + head < (unsigned long)input_stat.st_size)
+               goto more;
+
+done:
+       err = 0;
+out_close:
+       close(input);
+
+       return err;
+out_delete:
+       perf_header__delete(header);
+       goto out_close;
+}
diff --git a/tools/perf/util/data_map.h b/tools/perf/util/data_map.h
new file mode 100644 (file)
index 0000000..3180ff7
--- /dev/null
@@ -0,0 +1,32 @@
+#ifndef __PERF_DATAMAP_H
+#define __PERF_DATAMAP_H
+
+#include "event.h"
+#include "header.h"
+
+typedef int (*event_type_handler_t)(event_t *);
+
+struct perf_file_handler {
+       event_type_handler_t    process_sample_event;
+       event_type_handler_t    process_mmap_event;
+       event_type_handler_t    process_comm_event;
+       event_type_handler_t    process_fork_event;
+       event_type_handler_t    process_exit_event;
+       event_type_handler_t    process_lost_event;
+       event_type_handler_t    process_read_event;
+       event_type_handler_t    process_throttle_event;
+       event_type_handler_t    process_unthrottle_event;
+       int                     (*sample_type_check)(u64 sample_type);
+       unsigned long           total_unknown;
+};
+
+void register_perf_file_handler(struct perf_file_handler *handler);
+int mmap_dispatch_perf_file(struct perf_header **pheader,
+                           const char *input_name,
+                           int force,
+                           int full_paths,
+                           int *cwdlen,
+                           char **cwd);
+int perf_header__read_build_ids(int input, off_t offset, off_t file_size);
+
+#endif
index e8ca98f..28d520d 100644 (file)
 int verbose = 0;
 int dump_trace = 0;
 
-int eprintf(const char *fmt, ...)
+int eprintf(int level, const char *fmt, ...)
 {
        va_list args;
        int ret = 0;
 
-       if (verbose) {
+       if (verbose >= level) {
                va_start(args, fmt);
                ret = vfprintf(stderr, fmt, args);
                va_end(args);
index 437eea5..c6c24c5 100644 (file)
@@ -1,8 +1,15 @@
 /* For debugging general purposes */
+#ifndef __PERF_DEBUG_H
+#define __PERF_DEBUG_H
+
+#include "event.h"
 
 extern int verbose;
 extern int dump_trace;
 
-int eprintf(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
+int eprintf(int level,
+           const char *fmt, ...) __attribute__((format(printf, 2, 3)));
 int dump_printf(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
 void trace_event(event_t *event);
+
+#endif /* __PERF_DEBUG_H */
diff --git a/tools/perf/util/debugfs.c b/tools/perf/util/debugfs.c
new file mode 100644 (file)
index 0000000..06b73ee
--- /dev/null
@@ -0,0 +1,241 @@
+#include "util.h"
+#include "debugfs.h"
+#include "cache.h"
+
+static int debugfs_premounted;
+static char debugfs_mountpoint[MAX_PATH+1];
+
+static const char *debugfs_known_mountpoints[] = {
+       "/sys/kernel/debug/",
+       "/debug/",
+       0,
+};
+
+/* use this to force a umount */
+void debugfs_force_cleanup(void)
+{
+       debugfs_find_mountpoint();
+       debugfs_premounted = 0;
+       debugfs_umount();
+}
+
+/* construct a full path to a debugfs element */
+int debugfs_make_path(const char *element, char *buffer, int size)
+{
+       int len;
+
+       if (strlen(debugfs_mountpoint) == 0) {
+               buffer[0] = '\0';
+               return -1;
+       }
+
+       len = strlen(debugfs_mountpoint) + strlen(element) + 1;
+       if (len >= size)
+               return len+1;
+
+       snprintf(buffer, size-1, "%s/%s", debugfs_mountpoint, element);
+       return 0;
+}
+
+static int debugfs_found;
+
+/* find the path to the mounted debugfs */
+const char *debugfs_find_mountpoint(void)
+{
+       const char **ptr;
+       char type[100];
+       FILE *fp;
+
+       if (debugfs_found)
+               return (const char *) debugfs_mountpoint;
+
+       ptr = debugfs_known_mountpoints;
+       while (*ptr) {
+               if (debugfs_valid_mountpoint(*ptr) == 0) {
+                       debugfs_found = 1;
+                       strcpy(debugfs_mountpoint, *ptr);
+                       return debugfs_mountpoint;
+               }
+               ptr++;
+       }
+
+       /* give up and parse /proc/mounts */
+       fp = fopen("/proc/mounts", "r");
+       if (fp == NULL)
+               die("Can't open /proc/mounts for read");
+
+       while (fscanf(fp, "%*s %"
+                     STR(MAX_PATH)
+                     "s %99s %*s %*d %*d\n",
+                     debugfs_mountpoint, type) == 2) {
+               if (strcmp(type, "debugfs") == 0)
+                       break;
+       }
+       fclose(fp);
+
+       if (strcmp(type, "debugfs") != 0)
+               return NULL;
+
+       debugfs_found = 1;
+
+       return debugfs_mountpoint;
+}
+
+/* verify that a mountpoint is actually a debugfs instance */
+
+int debugfs_valid_mountpoint(const char *debugfs)
+{
+       struct statfs st_fs;
+
+       if (statfs(debugfs, &st_fs) < 0)
+               return -ENOENT;
+       else if (st_fs.f_type != (long) DEBUGFS_MAGIC)
+               return -ENOENT;
+
+       return 0;
+}
+
+
+int debugfs_valid_entry(const char *path)
+{
+       struct stat st;
+
+       if (stat(path, &st))
+               return -errno;
+
+       return 0;
+}
+
+/* mount the debugfs somewhere */
+
+int debugfs_mount(const char *mountpoint)
+{
+       char mountcmd[128];
+
+       /* see if it's already mounted */
+       if (debugfs_find_mountpoint()) {
+               debugfs_premounted = 1;
+               return 0;
+       }
+
+       /* if not mounted and no argument */
+       if (mountpoint == NULL) {
+               /* see if environment variable set */
+               mountpoint = getenv(PERF_DEBUGFS_ENVIRONMENT);
+               /* if no environment variable, use default */
+               if (mountpoint == NULL)
+                       mountpoint = "/sys/kernel/debug";
+       }
+
+       /* save the mountpoint */
+       strncpy(debugfs_mountpoint, mountpoint, sizeof(debugfs_mountpoint));
+
+       /* mount it */
+       snprintf(mountcmd, sizeof(mountcmd),
+                "/bin/mount -t debugfs debugfs %s", mountpoint);
+       return system(mountcmd);
+}
+
+/* umount the debugfs */
+
+int debugfs_umount(void)
+{
+       char umountcmd[128];
+       int ret;
+
+       /* if it was already mounted, leave it */
+       if (debugfs_premounted)
+               return 0;
+
+       /* make sure it's a valid mount point */
+       ret = debugfs_valid_mountpoint(debugfs_mountpoint);
+       if (ret)
+               return ret;
+
+       snprintf(umountcmd, sizeof(umountcmd),
+                "/bin/umount %s", debugfs_mountpoint);
+       return system(umountcmd);
+}
+
+int debugfs_write(const char *entry, const char *value)
+{
+       char path[MAX_PATH+1];
+       int ret, count;
+       int fd;
+
+       /* construct the path */
+       snprintf(path, sizeof(path), "%s/%s", debugfs_mountpoint, entry);
+
+       /* verify that it exists */
+       ret = debugfs_valid_entry(path);
+       if (ret)
+               return ret;
+
+       /* get how many chars we're going to write */
+       count = strlen(value);
+
+       /* open the debugfs entry */
+       fd = open(path, O_RDWR);
+       if (fd < 0)
+               return -errno;
+
+       while (count > 0) {
+               /* write it */
+               ret = write(fd, value, count);
+               if (ret <= 0) {
+                       if (ret == EAGAIN)
+                               continue;
+                       close(fd);
+                       return -errno;
+               }
+               count -= ret;
+       }
+
+       /* close it */
+       close(fd);
+
+       /* return success */
+       return 0;
+}
+
+/*
+ * read a debugfs entry
+ * returns the number of chars read or a negative errno
+ */
+int debugfs_read(const char *entry, char *buffer, size_t size)
+{
+       char path[MAX_PATH+1];
+       int ret;
+       int fd;
+
+       /* construct the path */
+       snprintf(path, sizeof(path), "%s/%s", debugfs_mountpoint, entry);
+
+       /* verify that it exists */
+       ret = debugfs_valid_entry(path);
+       if (ret)
+               return ret;
+
+       /* open the debugfs entry */
+       fd = open(path, O_RDONLY);
+       if (fd < 0)
+               return -errno;
+
+       do {
+               /* read it */
+               ret = read(fd, buffer, size);
+               if (ret == 0) {
+                       close(fd);
+                       return EOF;
+               }
+       } while (ret < 0 && errno == EAGAIN);
+
+       /* close it */
+       close(fd);
+
+       /* make *sure* there's a null character at the end */
+       buffer[ret] = '\0';
+
+       /* return the number of chars read */
+       return ret;
+}
diff --git a/tools/perf/util/debugfs.h b/tools/perf/util/debugfs.h
new file mode 100644 (file)
index 0000000..3cd14f9
--- /dev/null
@@ -0,0 +1,25 @@
+#ifndef __DEBUGFS_H__
+#define __DEBUGFS_H__
+
+#include <sys/mount.h>
+
+#ifndef MAX_PATH
+# define MAX_PATH 256
+#endif
+
+#ifndef STR
+# define _STR(x) #x
+# define STR(x) _STR(x)
+#endif
+
+extern const char *debugfs_find_mountpoint(void);
+extern int debugfs_valid_mountpoint(const char *debugfs);
+extern int debugfs_valid_entry(const char *path);
+extern int debugfs_mount(const char *mountpoint);
+extern int debugfs_umount(void);
+extern int debugfs_write(const char *entry, const char *value);
+extern int debugfs_read(const char *entry, char *buffer, size_t size);
+extern void debugfs_force_cleanup(void);
+extern int debugfs_make_path(const char *element, char *buffer, int size);
+
+#endif /* __DEBUGFS_H__ */
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
new file mode 100644 (file)
index 0000000..414b89d
--- /dev/null
@@ -0,0 +1,312 @@
+#include <linux/types.h>
+#include "event.h"
+#include "debug.h"
+#include "string.h"
+#include "thread.h"
+
+static pid_t event__synthesize_comm(pid_t pid, int full,
+                                   int (*process)(event_t *event))
+{
+       event_t ev;
+       char filename[PATH_MAX];
+       char bf[BUFSIZ];
+       FILE *fp;
+       size_t size = 0;
+       DIR *tasks;
+       struct dirent dirent, *next;
+       pid_t tgid = 0;
+
+       snprintf(filename, sizeof(filename), "/proc/%d/status", pid);
+
+       fp = fopen(filename, "r");
+       if (fp == NULL) {
+out_race:
+               /*
+                * We raced with a task exiting - just return:
+                */
+               pr_debug("couldn't open %s\n", filename);
+               return 0;
+       }
+
+       memset(&ev.comm, 0, sizeof(ev.comm));
+       while (!ev.comm.comm[0] || !ev.comm.pid) {
+               if (fgets(bf, sizeof(bf), fp) == NULL)
+                       goto out_failure;
+
+               if (memcmp(bf, "Name:", 5) == 0) {
+                       char *name = bf + 5;
+                       while (*name && isspace(*name))
+                               ++name;
+                       size = strlen(name) - 1;
+                       memcpy(ev.comm.comm, name, size++);
+               } else if (memcmp(bf, "Tgid:", 5) == 0) {
+                       char *tgids = bf + 5;
+                       while (*tgids && isspace(*tgids))
+                               ++tgids;
+                       tgid = ev.comm.pid = atoi(tgids);
+               }
+       }
+
+       ev.comm.header.type = PERF_RECORD_COMM;
+       size = ALIGN(size, sizeof(u64));
+       ev.comm.header.size = sizeof(ev.comm) - (sizeof(ev.comm.comm) - size);
+
+       if (!full) {
+               ev.comm.tid = pid;
+
+               process(&ev);
+               goto out_fclose;
+       }
+
+       snprintf(filename, sizeof(filename), "/proc/%d/task", pid);
+
+       tasks = opendir(filename);
+       if (tasks == NULL)
+               goto out_race;
+
+       while (!readdir_r(tasks, &dirent, &next) && next) {
+               char *end;
+               pid = strtol(dirent.d_name, &end, 10);
+               if (*end)
+                       continue;
+
+               ev.comm.tid = pid;
+
+               process(&ev);
+       }
+       closedir(tasks);
+
+out_fclose:
+       fclose(fp);
+       return tgid;
+
+out_failure:
+       pr_warning("couldn't get COMM and pgid, malformed %s\n", filename);
+       return -1;
+}
+
+static int event__synthesize_mmap_events(pid_t pid, pid_t tgid,
+                                        int (*process)(event_t *event))
+{
+       char filename[PATH_MAX];
+       FILE *fp;
+
+       snprintf(filename, sizeof(filename), "/proc/%d/maps", pid);
+
+       fp = fopen(filename, "r");
+       if (fp == NULL) {
+               /*
+                * We raced with a task exiting - just return:
+                */
+               pr_debug("couldn't open %s\n", filename);
+               return -1;
+       }
+
+       while (1) {
+               char bf[BUFSIZ], *pbf = bf;
+               event_t ev = {
+                       .header = { .type = PERF_RECORD_MMAP },
+               };
+               int n;
+               size_t size;
+               if (fgets(bf, sizeof(bf), fp) == NULL)
+                       break;
+
+               /* 00400000-0040c000 r-xp 00000000 fd:01 41038  /bin/cat */
+               n = hex2u64(pbf, &ev.mmap.start);
+               if (n < 0)
+                       continue;
+               pbf += n + 1;
+               n = hex2u64(pbf, &ev.mmap.len);
+               if (n < 0)
+                       continue;
+               pbf += n + 3;
+               if (*pbf == 'x') { /* vm_exec */
+                       char *execname = strchr(bf, '/');
+
+                       /* Catch VDSO */
+                       if (execname == NULL)
+                               execname = strstr(bf, "[vdso]");
+
+                       if (execname == NULL)
+                               continue;
+
+                       size = strlen(execname);
+                       execname[size - 1] = '\0'; /* Remove \n */
+                       memcpy(ev.mmap.filename, execname, size);
+                       size = ALIGN(size, sizeof(u64));
+                       ev.mmap.len -= ev.mmap.start;
+                       ev.mmap.header.size = (sizeof(ev.mmap) -
+                                              (sizeof(ev.mmap.filename) - size));
+                       ev.mmap.pid = tgid;
+                       ev.mmap.tid = pid;
+
+                       process(&ev);
+               }
+       }
+
+       fclose(fp);
+       return 0;
+}
+
+int event__synthesize_thread(pid_t pid, int (*process)(event_t *event))
+{
+       pid_t tgid = event__synthesize_comm(pid, 1, process);
+       if (tgid == -1)
+               return -1;
+       return event__synthesize_mmap_events(pid, tgid, process);
+}
+
+void event__synthesize_threads(int (*process)(event_t *event))
+{
+       DIR *proc;
+       struct dirent dirent, *next;
+
+       proc = opendir("/proc");
+
+       while (!readdir_r(proc, &dirent, &next) && next) {
+               char *end;
+               pid_t pid = strtol(dirent.d_name, &end, 10);
+
+               if (*end) /* only interested in proper numerical dirents */
+                       continue;
+
+               event__synthesize_thread(pid, process);
+       }
+
+       closedir(proc);
+}
+
+char *event__cwd;
+int  event__cwdlen;
+
+struct events_stats event__stats;
+
+int event__process_comm(event_t *self)
+{
+       struct thread *thread = threads__findnew(self->comm.pid);
+
+       dump_printf(": %s:%d\n", self->comm.comm, self->comm.pid);
+
+       if (thread == NULL || thread__set_comm(thread, self->comm.comm)) {
+               dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n");
+               return -1;
+       }
+
+       return 0;
+}
+
+int event__process_lost(event_t *self)
+{
+       dump_printf(": id:%Ld: lost:%Ld\n", self->lost.id, self->lost.lost);
+       event__stats.lost += self->lost.lost;
+       return 0;
+}
+
+int event__process_mmap(event_t *self)
+{
+       struct thread *thread = threads__findnew(self->mmap.pid);
+       struct map *map = map__new(&self->mmap, MAP__FUNCTION,
+                                  event__cwd, event__cwdlen);
+
+       dump_printf(" %d/%d: [%p(%p) @ %p]: %s\n",
+                   self->mmap.pid, self->mmap.tid,
+                   (void *)(long)self->mmap.start,
+                   (void *)(long)self->mmap.len,
+                   (void *)(long)self->mmap.pgoff,
+                   self->mmap.filename);
+
+       if (thread == NULL || map == NULL)
+               dump_printf("problem processing PERF_RECORD_MMAP, skipping event.\n");
+       else
+               thread__insert_map(thread, map);
+
+       return 0;
+}
+
+int event__process_task(event_t *self)
+{
+       struct thread *thread = threads__findnew(self->fork.pid);
+       struct thread *parent = threads__findnew(self->fork.ppid);
+
+       dump_printf("(%d:%d):(%d:%d)\n", self->fork.pid, self->fork.tid,
+                   self->fork.ppid, self->fork.ptid);
+       /*
+        * A thread clone will have the same PID for both parent and child.
+        */
+       if (thread == parent)
+               return 0;
+
+       if (self->header.type == PERF_RECORD_EXIT)
+               return 0;
+
+       if (thread == NULL || parent == NULL ||
+           thread__fork(thread, parent) < 0) {
+               dump_printf("problem processing PERF_RECORD_FORK, skipping event.\n");
+               return -1;
+       }
+
+       return 0;
+}
+
+void thread__find_addr_location(struct thread *self, u8 cpumode,
+                               enum map_type type, u64 addr,
+                               struct addr_location *al,
+                               symbol_filter_t filter)
+{
+       struct thread *thread = al->thread = self;
+
+       al->addr = addr;
+
+       if (cpumode & PERF_RECORD_MISC_KERNEL) {
+               al->level = 'k';
+               thread = kthread;
+       } else if (cpumode & PERF_RECORD_MISC_USER)
+               al->level = '.';
+       else {
+               al->level = 'H';
+               al->map = NULL;
+               al->sym = NULL;
+               return;
+       }
+try_again:
+       al->map = thread__find_map(thread, type, al->addr);
+       if (al->map == NULL) {
+               /*
+                * If this is outside of all known maps, and is a negative
+                * address, try to look it up in the kernel dso, as it might be
+                * a vsyscall or vdso (which executes in user-mode).
+                *
+                * XXX This is nasty, we should have a symbol list in the
+                * "[vdso]" dso, but for now lets use the old trick of looking
+                * in the whole kernel symbol list.
+                */
+               if ((long long)al->addr < 0 && thread != kthread) {
+                       thread = kthread;
+                       goto try_again;
+               }
+               al->sym = NULL;
+       } else {
+               al->addr = al->map->map_ip(al->map, al->addr);
+               al->sym = map__find_symbol(al->map, al->addr, filter);
+       }
+}
+
+int event__preprocess_sample(const event_t *self, struct addr_location *al,
+                            symbol_filter_t filter)
+{
+       u8 cpumode = self->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
+       struct thread *thread = threads__findnew(self->ip.pid);
+
+       if (thread == NULL)
+               return -1;
+
+       dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid);
+
+       thread__find_addr_location(thread, cpumode, MAP__FUNCTION,
+                                  self->ip.ip, al, filter);
+       dump_printf(" ...... dso: %s\n",
+                   al->map ? al->map->dso->long_name :
+                       al->level == 'H' ? "[hypervisor]" : "<not found>");
+       return 0;
+}
index 2c9c26d..a4cc810 100644 (file)
@@ -1,14 +1,10 @@
 #ifndef __PERF_RECORD_H
 #define __PERF_RECORD_H
+
 #include "../perf.h"
 #include "util.h"
 #include <linux/list.h>
-
-enum {
-       SHOW_KERNEL     = 1,
-       SHOW_USER       = 2,
-       SHOW_HV         = 4,
-};
+#include <linux/rbtree.h>
 
 /*
  * PERF_SAMPLE_IP | PERF_SAMPLE_TID | *
@@ -65,6 +61,13 @@ struct sample_event{
        u64 array[];
 };
 
+#define BUILD_ID_SIZE 20
+
+struct build_id_event {
+       struct perf_event_header header;
+       u8                       build_id[ALIGN(BUILD_ID_SIZE, sizeof(u64))];
+       char                     filename[];
+};
 
 typedef union event_union {
        struct perf_event_header        header;
@@ -77,12 +80,30 @@ typedef union event_union {
        struct sample_event             sample;
 } event_t;
 
+struct events_stats {
+       unsigned long total;
+       unsigned long lost;
+};
+
+void event__print_totals(void);
+
+enum map_type {
+       MAP__FUNCTION = 0,
+
+       MAP__NR_TYPES,
+};
+
 struct map {
-       struct list_head        node;
+       union {
+               struct rb_node  rb_node;
+               struct list_head node;
+       };
        u64                     start;
        u64                     end;
+       enum map_type           type;
        u64                     pgoff;
        u64                     (*map_ip)(struct map *, u64);
+       u64                     (*unmap_ip)(struct map *, u64);
        struct dso              *dso;
 };
 
@@ -91,14 +112,48 @@ static inline u64 map__map_ip(struct map *map, u64 ip)
        return ip - map->start + map->pgoff;
 }
 
-static inline u64 vdso__map_ip(struct map *map __used, u64 ip)
+static inline u64 map__unmap_ip(struct map *map, u64 ip)
+{
+       return ip + map->start - map->pgoff;
+}
+
+static inline u64 identity__map_ip(struct map *map __used, u64 ip)
 {
        return ip;
 }
 
-struct map *map__new(struct mmap_event *event, char *cwd, int cwdlen);
+struct symbol;
+
+typedef int (*symbol_filter_t)(struct map *map, struct symbol *sym);
+
+void map__init(struct map *self, enum map_type type,
+              u64 start, u64 end, u64 pgoff, struct dso *dso);
+struct map *map__new(struct mmap_event *event, enum map_type,
+                    char *cwd, int cwdlen);
+void map__delete(struct map *self);
 struct map *map__clone(struct map *self);
 int map__overlap(struct map *l, struct map *r);
 size_t map__fprintf(struct map *self, FILE *fp);
+struct symbol *map__find_symbol(struct map *self, u64 addr,
+                               symbol_filter_t filter);
+void map__fixup_start(struct map *self);
+void map__fixup_end(struct map *self);
+
+int event__synthesize_thread(pid_t pid, int (*process)(event_t *event));
+void event__synthesize_threads(int (*process)(event_t *event));
+
+extern char *event__cwd;
+extern int  event__cwdlen;
+extern struct events_stats event__stats;
+extern unsigned long event__total[PERF_RECORD_MAX];
+
+int event__process_comm(event_t *self);
+int event__process_lost(event_t *self);
+int event__process_mmap(event_t *self);
+int event__process_task(event_t *self);
+
+struct addr_location;
+int event__preprocess_sample(const event_t *self, struct addr_location *al,
+                            symbol_filter_t filter);
 
-#endif
+#endif /* __PERF_RECORD_H */
index effe25e..31647ac 100644 (file)
@@ -1,5 +1,5 @@
-#ifndef PERF_EXEC_CMD_H
-#define PERF_EXEC_CMD_H
+#ifndef __PERF_EXEC_CMD_H
+#define __PERF_EXEC_CMD_H
 
 extern void perf_set_argv_exec_path(const char *exec_path);
 extern const char *perf_extract_argv0_path(const char *path);
@@ -10,4 +10,4 @@ extern int execv_perf_cmd(const char **argv); /* NULL terminated */
 extern int execl_perf_cmd(const char *cmd, ...);
 extern const char *system_path(const char *path);
 
-#endif /* PERF_EXEC_CMD_H */
+#endif /* __PERF_EXEC_CMD_H */
index e306857..4805e6d 100644 (file)
@@ -2,9 +2,15 @@
 #include <unistd.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <linux/list.h>
 
 #include "util.h"
 #include "header.h"
+#include "../perf.h"
+#include "trace-event.h"
+#include "symbol.h"
+#include "data_map.h"
+#include "debug.h"
 
 /*
  * Create new perf.data header attribute:
@@ -13,32 +19,43 @@ struct perf_header_attr *perf_header_attr__new(struct perf_event_attr *attr)
 {
        struct perf_header_attr *self = malloc(sizeof(*self));
 
-       if (!self)
-               die("nomem");
-
-       self->attr = *attr;
-       self->ids = 0;
-       self->size = 1;
-       self->id = malloc(sizeof(u64));
-
-       if (!self->id)
-               die("nomem");
+       if (self != NULL) {
+               self->attr = *attr;
+               self->ids  = 0;
+               self->size = 1;
+               self->id   = malloc(sizeof(u64));
+               if (self->id == NULL) {
+                       free(self);
+                       self = NULL;
+               }
+       }
 
        return self;
 }
 
-void perf_header_attr__add_id(struct perf_header_attr *self, u64 id)
+void perf_header_attr__delete(struct perf_header_attr *self)
+{
+       free(self->id);
+       free(self);
+}
+
+int perf_header_attr__add_id(struct perf_header_attr *self, u64 id)
 {
        int pos = self->ids;
 
        self->ids++;
        if (self->ids > self->size) {
-               self->size *= 2;
-               self->id = realloc(self->id, self->size * sizeof(u64));
-               if (!self->id)
-                       die("nomem");
+               int nsize = self->size * 2;
+               u64 *nid = realloc(self->id, nsize * sizeof(u64));
+
+               if (nid == NULL)
+                       return -1;
+
+               self->size = nsize;
+               self->id = nid;
        }
        self->id[pos] = id;
+       return 0;
 }
 
 /*
@@ -46,42 +63,52 @@ void perf_header_attr__add_id(struct perf_header_attr *self, u64 id)
  */
 struct perf_header *perf_header__new(void)
 {
-       struct perf_header *self = malloc(sizeof(*self));
+       struct perf_header *self = zalloc(sizeof(*self));
 
-       if (!self)
-               die("nomem");
+       if (self != NULL) {
+               self->size = 1;
+               self->attr = malloc(sizeof(void *));
 
-       self->frozen = 0;
+               if (self->attr == NULL) {
+                       free(self);
+                       self = NULL;
+               }
+       }
 
-       self->attrs = 0;
-       self->size = 1;
-       self->attr = malloc(sizeof(void *));
+       return self;
+}
 
-       if (!self->attr)
-               die("nomem");
+void perf_header__delete(struct perf_header *self)
+{
+       int i;
 
-       self->data_offset = 0;
-       self->data_size = 0;
+       for (i = 0; i < self->attrs; ++i)
+               perf_header_attr__delete(self->attr[i]);
 
-       return self;
+       free(self->attr);
+       free(self);
 }
 
-void perf_header__add_attr(struct perf_header *self,
-                          struct perf_header_attr *attr)
+int perf_header__add_attr(struct perf_header *self,
+                         struct perf_header_attr *attr)
 {
-       int pos = self->attrs;
-
        if (self->frozen)
-               die("frozen");
+               return -1;
 
-       self->attrs++;
-       if (self->attrs > self->size) {
-               self->size *= 2;
-               self->attr = realloc(self->attr, self->size * sizeof(void *));
-               if (!self->attr)
-                       die("nomem");
+       if (self->attrs == self->size) {
+               int nsize = self->size * 2;
+               struct perf_header_attr **nattr;
+
+               nattr = realloc(self->attr, nsize * sizeof(void *));
+               if (nattr == NULL)
+                       return -1;
+
+               self->size = nsize;
+               self->attr = nattr;
        }
-       self->attr[pos] = attr;
+
+       self->attr[self->attrs++] = attr;
+       return 0;
 }
 
 #define MAX_EVENT_NAME 64
@@ -97,7 +124,7 @@ static struct perf_trace_event_type *events;
 void perf_header__push_event(u64 id, const char *name)
 {
        if (strlen(name) > MAX_EVENT_NAME)
-               printf("Event %s will be truncated\n", name);
+               pr_warning("Event %s will be truncated\n", name);
 
        if (!events) {
                events = malloc(sizeof(struct perf_trace_event_type));
@@ -128,44 +155,137 @@ static const char *__perf_magic = "PERFFILE";
 
 #define PERF_MAGIC     (*(u64 *)__perf_magic)
 
-struct perf_file_section {
-       u64 offset;
-       u64 size;
-};
-
 struct perf_file_attr {
        struct perf_event_attr  attr;
        struct perf_file_section        ids;
 };
 
-struct perf_file_header {
-       u64                             magic;
-       u64                             size;
-       u64                             attr_size;
-       struct perf_file_section        attrs;
-       struct perf_file_section        data;
-       struct perf_file_section        event_types;
-};
+void perf_header__set_feat(struct perf_header *self, int feat)
+{
+       set_bit(feat, self->adds_features);
+}
 
-static void do_write(int fd, void *buf, size_t size)
+bool perf_header__has_feat(const struct perf_header *self, int feat)
+{
+       return test_bit(feat, self->adds_features);
+}
+
+static int do_write(int fd, const void *buf, size_t size)
 {
        while (size) {
                int ret = write(fd, buf, size);
 
                if (ret < 0)
-                       die("failed to write");
+                       return -errno;
 
                size -= ret;
                buf += ret;
        }
+
+       return 0;
+}
+
+static int __dsos__write_buildid_table(struct list_head *head, int fd)
+{
+       struct dso *pos;
+
+       list_for_each_entry(pos, head, node) {
+               int err;
+               struct build_id_event b;
+               size_t len;
+
+               if (!pos->has_build_id)
+                       continue;
+               len = pos->long_name_len + 1;
+               len = ALIGN(len, 64);
+               memset(&b, 0, sizeof(b));
+               memcpy(&b.build_id, pos->build_id, sizeof(pos->build_id));
+               b.header.size = sizeof(b) + len;
+               err = do_write(fd, &b, sizeof(b));
+               if (err < 0)
+                       return err;
+               err = do_write(fd, pos->long_name, len);
+               if (err < 0)
+                       return err;
+       }
+
+       return 0;
 }
 
-void perf_header__write(struct perf_header *self, int fd)
+static int dsos__write_buildid_table(int fd)
+{
+       int err = __dsos__write_buildid_table(&dsos__kernel, fd);
+       if (err == 0)
+               err = __dsos__write_buildid_table(&dsos__user, fd);
+       return err;
+}
+
+static int perf_header__adds_write(struct perf_header *self, int fd)
+{
+       int nr_sections;
+       struct perf_file_section *feat_sec;
+       int sec_size;
+       u64 sec_start;
+       int idx = 0, err;
+
+       if (dsos__read_build_ids())
+               perf_header__set_feat(self, HEADER_BUILD_ID);
+
+       nr_sections = bitmap_weight(self->adds_features, HEADER_FEAT_BITS);
+       if (!nr_sections)
+               return 0;
+
+       feat_sec = calloc(sizeof(*feat_sec), nr_sections);
+       if (feat_sec == NULL)
+               return -ENOMEM;
+
+       sec_size = sizeof(*feat_sec) * nr_sections;
+
+       sec_start = self->data_offset + self->data_size;
+       lseek(fd, sec_start + sec_size, SEEK_SET);
+
+       if (perf_header__has_feat(self, HEADER_TRACE_INFO)) {
+               struct perf_file_section *trace_sec;
+
+               trace_sec = &feat_sec[idx++];
+
+               /* Write trace info */
+               trace_sec->offset = lseek(fd, 0, SEEK_CUR);
+               read_tracing_data(fd, attrs, nr_counters);
+               trace_sec->size = lseek(fd, 0, SEEK_CUR) - trace_sec->offset;
+       }
+
+
+       if (perf_header__has_feat(self, HEADER_BUILD_ID)) {
+               struct perf_file_section *buildid_sec;
+
+               buildid_sec = &feat_sec[idx++];
+
+               /* Write build-ids */
+               buildid_sec->offset = lseek(fd, 0, SEEK_CUR);
+               err = dsos__write_buildid_table(fd);
+               if (err < 0) {
+                       pr_debug("failed to write buildid table\n");
+                       goto out_free;
+               }
+               buildid_sec->size = lseek(fd, 0, SEEK_CUR) - buildid_sec->offset;
+       }
+
+       lseek(fd, sec_start, SEEK_SET);
+       err = do_write(fd, feat_sec, sec_size);
+       if (err < 0)
+               pr_debug("failed to write feature section\n");
+out_free:
+       free(feat_sec);
+       return err;
+}
+
+int perf_header__write(struct perf_header *self, int fd, bool at_exit)
 {
        struct perf_file_header f_header;
        struct perf_file_attr   f_attr;
        struct perf_header_attr *attr;
-       int i;
+       int i, err;
 
        lseek(fd, sizeof(f_header), SEEK_SET);
 
@@ -174,7 +294,11 @@ void perf_header__write(struct perf_header *self, int fd)
                attr = self->attr[i];
 
                attr->id_offset = lseek(fd, 0, SEEK_CUR);
-               do_write(fd, attr->id, attr->ids * sizeof(u64));
+               err = do_write(fd, attr->id, attr->ids * sizeof(u64));
+               if (err < 0) {
+                       pr_debug("failed to write perf header\n");
+                       return err;
+               }
        }
 
 
@@ -190,17 +314,31 @@ void perf_header__write(struct perf_header *self, int fd)
                                .size   = attr->ids * sizeof(u64),
                        }
                };
-               do_write(fd, &f_attr, sizeof(f_attr));
+               err = do_write(fd, &f_attr, sizeof(f_attr));
+               if (err < 0) {
+                       pr_debug("failed to write perf header attribute\n");
+                       return err;
+               }
        }
 
        self->event_offset = lseek(fd, 0, SEEK_CUR);
        self->event_size = event_count * sizeof(struct perf_trace_event_type);
-       if (events)
-               do_write(fd, events, self->event_size);
-
+       if (events) {
+               err = do_write(fd, events, self->event_size);
+               if (err < 0) {
+                       pr_debug("failed to write perf header events\n");
+                       return err;
+               }
+       }
 
        self->data_offset = lseek(fd, 0, SEEK_CUR);
 
+       if (at_exit) {
+               err = perf_header__adds_write(self, fd);
+               if (err < 0)
+                       return err;
+       }
+
        f_header = (struct perf_file_header){
                .magic     = PERF_MAGIC,
                .size      = sizeof(f_header),
@@ -219,11 +357,18 @@ void perf_header__write(struct perf_header *self, int fd)
                },
        };
 
+       memcpy(&f_header.adds_features, &self->adds_features, sizeof(self->adds_features));
+
        lseek(fd, 0, SEEK_SET);
-       do_write(fd, &f_header, sizeof(f_header));
+       err = do_write(fd, &f_header, sizeof(f_header));
+       if (err < 0) {
+               pr_debug("failed to write perf header\n");
+               return err;
+       }
        lseek(fd, self->data_offset + self->data_size, SEEK_SET);
 
        self->frozen = 1;
+       return 0;
 }
 
 static void do_read(int fd, void *buf, size_t size)
@@ -241,22 +386,109 @@ static void do_read(int fd, void *buf, size_t size)
        }
 }
 
-struct perf_header *perf_header__read(int fd)
+int perf_header__process_sections(struct perf_header *self, int fd,
+                                 int (*process)(struct perf_file_section *self,
+                                                int feat, int fd))
+{
+       struct perf_file_section *feat_sec;
+       int nr_sections;
+       int sec_size;
+       int idx = 0;
+       int err = 0, feat = 1;
+
+       nr_sections = bitmap_weight(self->adds_features, HEADER_FEAT_BITS);
+       if (!nr_sections)
+               return 0;
+
+       feat_sec = calloc(sizeof(*feat_sec), nr_sections);
+       if (!feat_sec)
+               return -1;
+
+       sec_size = sizeof(*feat_sec) * nr_sections;
+
+       lseek(fd, self->data_offset + self->data_size, SEEK_SET);
+
+       do_read(fd, feat_sec, sec_size);
+
+       while (idx < nr_sections && feat < HEADER_LAST_FEATURE) {
+               if (perf_header__has_feat(self, feat)) {
+                       struct perf_file_section *sec = &feat_sec[idx++];
+
+                       err = process(sec, feat, fd);
+                       if (err < 0)
+                               break;
+               }
+               ++feat;
+       }
+
+       free(feat_sec);
+       return err;
+};
+
+int perf_file_header__read(struct perf_file_header *self,
+                          struct perf_header *ph, int fd)
+{
+       lseek(fd, 0, SEEK_SET);
+       do_read(fd, self, sizeof(*self));
+
+       if (self->magic     != PERF_MAGIC ||
+           self->attr_size != sizeof(struct perf_file_attr))
+               return -1;
+
+       if (self->size != sizeof(*self)) {
+               /* Support the previous format */
+               if (self->size == offsetof(typeof(*self), adds_features))
+                       bitmap_zero(self->adds_features, HEADER_FEAT_BITS);
+               else
+                       return -1;
+       }
+
+       memcpy(&ph->adds_features, &self->adds_features,
+              sizeof(self->adds_features));
+
+       ph->event_offset = self->event_types.offset;
+       ph->event_size   = self->event_types.size;
+       ph->data_offset  = self->data.offset;
+       ph->data_size    = self->data.size;
+       return 0;
+}
+
+static int perf_file_section__process(struct perf_file_section *self,
+                                     int feat, int fd)
+{
+       if (lseek(fd, self->offset, SEEK_SET) < 0) {
+               pr_debug("Failed to lseek to %Ld offset for feature %d, "
+                        "continuing...\n", self->offset, feat);
+               return 0;
+       }
+
+       switch (feat) {
+       case HEADER_TRACE_INFO:
+               trace_report(fd);
+               break;
+
+       case HEADER_BUILD_ID:
+               if (perf_header__read_build_ids(fd, self->offset, self->size))
+                       pr_debug("Failed to read buildids, continuing...\n");
+               break;
+       default:
+               pr_debug("unknown feature %d, continuing...\n", feat);
+       }
+
+       return 0;
+}
+
+int perf_header__read(struct perf_header *self, int fd)
 {
-       struct perf_header      *self = perf_header__new();
        struct perf_file_header f_header;
        struct perf_file_attr   f_attr;
        u64                     f_id;
-
        int nr_attrs, nr_ids, i, j;
 
-       lseek(fd, 0, SEEK_SET);
-       do_read(fd, &f_header, sizeof(f_header));
-
-       if (f_header.magic      != PERF_MAGIC           ||
-           f_header.size       != sizeof(f_header)     ||
-           f_header.attr_size  != sizeof(f_attr))
-               die("incompatible file format");
+       if (perf_file_header__read(&f_header, self, fd) < 0) {
+               pr_debug("incompatible file format\n");
+               return -EINVAL;
+       }
 
        nr_attrs = f_header.attrs.size / sizeof(f_attr);
        lseek(fd, f_header.attrs.offset, SEEK_SET);
@@ -269,6 +501,8 @@ struct perf_header *perf_header__read(int fd)
                tmp = lseek(fd, 0, SEEK_CUR);
 
                attr = perf_header_attr__new(&f_attr.attr);
+               if (attr == NULL)
+                        return -ENOMEM;
 
                nr_ids = f_attr.ids.size / sizeof(u64);
                lseek(fd, f_attr.ids.offset, SEEK_SET);
@@ -276,31 +510,34 @@ struct perf_header *perf_header__read(int fd)
                for (j = 0; j < nr_ids; j++) {
                        do_read(fd, &f_id, sizeof(f_id));
 
-                       perf_header_attr__add_id(attr, f_id);
+                       if (perf_header_attr__add_id(attr, f_id) < 0) {
+                               perf_header_attr__delete(attr);
+                               return -ENOMEM;
+                       }
                }
-               perf_header__add_attr(self, attr);
+               if (perf_header__add_attr(self, attr) < 0) {
+                       perf_header_attr__delete(attr);
+                       return -ENOMEM;
+               }
+
                lseek(fd, tmp, SEEK_SET);
        }
 
        if (f_header.event_types.size) {
                lseek(fd, f_header.event_types.offset, SEEK_SET);
                events = malloc(f_header.event_types.size);
-               if (!events)
-                       die("nomem");
+               if (events == NULL)
+                       return -ENOMEM;
                do_read(fd, events, f_header.event_types.size);
                event_count =  f_header.event_types.size / sizeof(struct perf_trace_event_type);
        }
-       self->event_offset = f_header.event_types.offset;
-       self->event_size   = f_header.event_types.size;
 
-       self->data_offset = f_header.data.offset;
-       self->data_size   = f_header.data.size;
+       perf_header__process_sections(self, fd, perf_file_section__process);
 
        lseek(fd, self->data_offset, SEEK_SET);
 
        self->frozen = 1;
-
-       return self;
+       return 0;
 }
 
 u64 perf_header__sample_type(struct perf_header *header)
index a0761bc..d1dbe2b 100644 (file)
@@ -1,10 +1,13 @@
-#ifndef _PERF_HEADER_H
-#define _PERF_HEADER_H
+#ifndef __PERF_HEADER_H
+#define __PERF_HEADER_H
 
 #include "../../../include/linux/perf_event.h"
 #include <sys/types.h>
+#include <stdbool.h>
 #include "types.h"
 
+#include <linux/bitmap.h>
+
 struct perf_header_attr {
        struct perf_event_attr attr;
        int ids, size;
@@ -12,36 +15,71 @@ struct perf_header_attr {
        off_t id_offset;
 };
 
+enum {
+       HEADER_TRACE_INFO = 1,
+       HEADER_BUILD_ID,
+       HEADER_LAST_FEATURE,
+};
+
+#define HEADER_FEAT_BITS                       256
+
+struct perf_file_section {
+       u64 offset;
+       u64 size;
+};
+
+struct perf_file_header {
+       u64                             magic;
+       u64                             size;
+       u64                             attr_size;
+       struct perf_file_section        attrs;
+       struct perf_file_section        data;
+       struct perf_file_section        event_types;
+       DECLARE_BITMAP(adds_features, HEADER_FEAT_BITS);
+};
+
+struct perf_header;
+
+int perf_file_header__read(struct perf_file_header *self,
+                          struct perf_header *ph, int fd);
+
 struct perf_header {
-       int frozen;
-       int attrs, size;
+       int                     frozen;
+       int                     attrs, size;
        struct perf_header_attr **attr;
-       s64 attr_offset;
-       u64 data_offset;
-       u64 data_size;
-       u64 event_offset;
-       u64 event_size;
+       s64                     attr_offset;
+       u64                     data_offset;
+       u64                     data_size;
+       u64                     event_offset;
+       u64                     event_size;
+       DECLARE_BITMAP(adds_features, HEADER_FEAT_BITS);
 };
 
-struct perf_header *perf_header__read(int fd);
-void perf_header__write(struct perf_header *self, int fd);
+struct perf_header *perf_header__new(void);
+void perf_header__delete(struct perf_header *self);
 
-void perf_header__add_attr(struct perf_header *self,
-                          struct perf_header_attr *attr);
+int perf_header__read(struct perf_header *self, int fd);
+int perf_header__write(struct perf_header *self, int fd, bool at_exit);
+
+int perf_header__add_attr(struct perf_header *self,
+                         struct perf_header_attr *attr);
 
 void perf_header__push_event(u64 id, const char *name);
 char *perf_header__find_event(u64 id);
 
+struct perf_header_attr *perf_header_attr__new(struct perf_event_attr *attr);
+void perf_header_attr__delete(struct perf_header_attr *self);
 
-struct perf_header_attr *
-perf_header_attr__new(struct perf_event_attr *attr);
-void perf_header_attr__add_id(struct perf_header_attr *self, u64 id);
+int perf_header_attr__add_id(struct perf_header_attr *self, u64 id);
 
 u64 perf_header__sample_type(struct perf_header *header);
 struct perf_event_attr *
 perf_header__find_attr(u64 id, struct perf_header *header);
+void perf_header__set_feat(struct perf_header *self, int feat);
+bool perf_header__has_feat(const struct perf_header *self, int feat);
 
+int perf_header__process_sections(struct perf_header *self, int fd,
+                                 int (*process)(struct perf_file_section *self,
+                                                int feat, int fd));
 
-struct perf_header *perf_header__new(void);
-
-#endif /* _PERF_HEADER_H */
+#endif /* __PERF_HEADER_H */
index 7128783..7f5c6de 100644 (file)
@@ -1,5 +1,5 @@
-#ifndef HELP_H
-#define HELP_H
+#ifndef __PERF_HELP_H
+#define __PERF_HELP_H
 
 struct cmdnames {
        size_t alloc;
@@ -26,4 +26,4 @@ int is_in_cmdlist(struct cmdnames *c, const char *s);
 void list_commands(const char *title, struct cmdnames *main_cmds,
                   struct cmdnames *other_cmds);
 
-#endif /* HELP_H */
+#endif /* __PERF_HELP_H */
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
new file mode 100644 (file)
index 0000000..0ebf6ee
--- /dev/null
@@ -0,0 +1,202 @@
+#include "hist.h"
+
+struct rb_root hist;
+struct rb_root collapse_hists;
+struct rb_root output_hists;
+int callchain;
+
+struct callchain_param callchain_param = {
+       .mode   = CHAIN_GRAPH_REL,
+       .min_percent = 0.5
+};
+
+/*
+ * histogram, sorted on item, collects counts
+ */
+
+struct hist_entry *__hist_entry__add(struct addr_location *al,
+                                    struct symbol *sym_parent,
+                                    u64 count, bool *hit)
+{
+       struct rb_node **p = &hist.rb_node;
+       struct rb_node *parent = NULL;
+       struct hist_entry *he;
+       struct hist_entry entry = {
+               .thread = al->thread,
+               .map    = al->map,
+               .sym    = al->sym,
+               .ip     = al->addr,
+               .level  = al->level,
+               .count  = count,
+               .parent = sym_parent,
+       };
+       int cmp;
+
+       while (*p != NULL) {
+               parent = *p;
+               he = rb_entry(parent, struct hist_entry, rb_node);
+
+               cmp = hist_entry__cmp(&entry, he);
+
+               if (!cmp) {
+                       *hit = true;
+                       return he;
+               }
+
+               if (cmp < 0)
+                       p = &(*p)->rb_left;
+               else
+                       p = &(*p)->rb_right;
+       }
+
+       he = malloc(sizeof(*he));
+       if (!he)
+               return NULL;
+       *he = entry;
+       rb_link_node(&he->rb_node, parent, p);
+       rb_insert_color(&he->rb_node, &hist);
+       *hit = false;
+       return he;
+}
+
+int64_t
+hist_entry__cmp(struct hist_entry *left, struct hist_entry *right)
+{
+       struct sort_entry *se;
+       int64_t cmp = 0;
+
+       list_for_each_entry(se, &hist_entry__sort_list, list) {
+               cmp = se->cmp(left, right);
+               if (cmp)
+                       break;
+       }
+
+       return cmp;
+}
+
+int64_t
+hist_entry__collapse(struct hist_entry *left, struct hist_entry *right)
+{
+       struct sort_entry *se;
+       int64_t cmp = 0;
+
+       list_for_each_entry(se, &hist_entry__sort_list, list) {
+               int64_t (*f)(struct hist_entry *, struct hist_entry *);
+
+               f = se->collapse ?: se->cmp;
+
+               cmp = f(left, right);
+               if (cmp)
+                       break;
+       }
+
+       return cmp;
+}
+
+void hist_entry__free(struct hist_entry *he)
+{
+       free(he);
+}
+
+/*
+ * collapse the histogram
+ */
+
+void collapse__insert_entry(struct hist_entry *he)
+{
+       struct rb_node **p = &collapse_hists.rb_node;
+       struct rb_node *parent = NULL;
+       struct hist_entry *iter;
+       int64_t cmp;
+
+       while (*p != NULL) {
+               parent = *p;
+               iter = rb_entry(parent, struct hist_entry, rb_node);
+
+               cmp = hist_entry__collapse(iter, he);
+
+               if (!cmp) {
+                       iter->count += he->count;
+                       hist_entry__free(he);
+                       return;
+               }
+
+               if (cmp < 0)
+                       p = &(*p)->rb_left;
+               else
+                       p = &(*p)->rb_right;
+       }
+
+       rb_link_node(&he->rb_node, parent, p);
+       rb_insert_color(&he->rb_node, &collapse_hists);
+}
+
+void collapse__resort(void)
+{
+       struct rb_node *next;
+       struct hist_entry *n;
+
+       if (!sort__need_collapse)
+               return;
+
+       next = rb_first(&hist);
+       while (next) {
+               n = rb_entry(next, struct hist_entry, rb_node);
+               next = rb_next(&n->rb_node);
+
+               rb_erase(&n->rb_node, &hist);
+               collapse__insert_entry(n);
+       }
+}
+
+/*
+ * reverse the map, sort on count.
+ */
+
+void output__insert_entry(struct hist_entry *he, u64 min_callchain_hits)
+{
+       struct rb_node **p = &output_hists.rb_node;
+       struct rb_node *parent = NULL;
+       struct hist_entry *iter;
+
+       if (callchain)
+               callchain_param.sort(&he->sorted_chain, &he->callchain,
+                                     min_callchain_hits, &callchain_param);
+
+       while (*p != NULL) {
+               parent = *p;
+               iter = rb_entry(parent, struct hist_entry, rb_node);
+
+               if (he->count > iter->count)
+                       p = &(*p)->rb_left;
+               else
+                       p = &(*p)->rb_right;
+       }
+
+       rb_link_node(&he->rb_node, parent, p);
+       rb_insert_color(&he->rb_node, &output_hists);
+}
+
+void output__resort(u64 total_samples)
+{
+       struct rb_node *next;
+       struct hist_entry *n;
+       struct rb_root *tree = &hist;
+       u64 min_callchain_hits;
+
+       min_callchain_hits =
+               total_samples * (callchain_param.min_percent / 100);
+
+       if (sort__need_collapse)
+               tree = &collapse_hists;
+
+       next = rb_first(tree);
+
+       while (next) {
+               n = rb_entry(next, struct hist_entry, rb_node);
+               next = rb_next(&n->rb_node);
+
+               rb_erase(&n->rb_node, tree);
+               output__insert_entry(n, min_callchain_hits);
+       }
+}
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
new file mode 100644 (file)
index 0000000..3020db0
--- /dev/null
@@ -0,0 +1,50 @@
+#ifndef __PERF_HIST_H
+#define __PERF_HIST_H
+#include "../builtin.h"
+
+#include "util.h"
+
+#include "color.h"
+#include <linux/list.h>
+#include "cache.h"
+#include <linux/rbtree.h>
+#include "symbol.h"
+#include "string.h"
+#include "callchain.h"
+#include "strlist.h"
+#include "values.h"
+
+#include "../perf.h"
+#include "debug.h"
+#include "header.h"
+
+#include "parse-options.h"
+#include "parse-events.h"
+
+#include "thread.h"
+#include "sort.h"
+
+extern struct rb_root hist;
+extern struct rb_root collapse_hists;
+extern struct rb_root output_hists;
+extern int callchain;
+extern struct callchain_param callchain_param;
+extern unsigned long total;
+extern unsigned long total_mmap;
+extern unsigned long total_comm;
+extern unsigned long total_fork;
+extern unsigned long total_unknown;
+extern unsigned long total_lost;
+
+struct hist_entry *__hist_entry__add(struct addr_location *al,
+                                    struct symbol *parent,
+                                    u64 count, bool *hit);
+extern int64_t hist_entry__cmp(struct hist_entry *, struct hist_entry *);
+extern int64_t hist_entry__collapse(struct hist_entry *, struct hist_entry *);
+extern void hist_entry__free(struct hist_entry *);
+extern void collapse__insert_entry(struct hist_entry *);
+extern void collapse__resort(void);
+extern void output__insert_entry(struct hist_entry *, u64);
+extern void output__resort(u64);
+
+#endif /* __PERF_HIST_H */
diff --git a/tools/perf/util/include/asm/asm-offsets.h b/tools/perf/util/include/asm/asm-offsets.h
new file mode 100644 (file)
index 0000000..ed53894
--- /dev/null
@@ -0,0 +1 @@
+/* stub */
diff --git a/tools/perf/util/include/asm/bitops.h b/tools/perf/util/include/asm/bitops.h
new file mode 100644 (file)
index 0000000..58e9817
--- /dev/null
@@ -0,0 +1,18 @@
+#ifndef _PERF_ASM_BITOPS_H_
+#define _PERF_ASM_BITOPS_H_
+
+#include <sys/types.h>
+#include "../../types.h"
+#include <linux/compiler.h>
+
+/* CHECKME: Not sure both always match */
+#define BITS_PER_LONG  __WORDSIZE
+
+#include "../../../../include/asm-generic/bitops/__fls.h"
+#include "../../../../include/asm-generic/bitops/fls.h"
+#include "../../../../include/asm-generic/bitops/fls64.h"
+#include "../../../../include/asm-generic/bitops/__ffs.h"
+#include "../../../../include/asm-generic/bitops/ffz.h"
+#include "../../../../include/asm-generic/bitops/hweight.h"
+
+#endif
diff --git a/tools/perf/util/include/asm/bug.h b/tools/perf/util/include/asm/bug.h
new file mode 100644 (file)
index 0000000..7fcc681
--- /dev/null
@@ -0,0 +1,22 @@
+#ifndef _PERF_ASM_GENERIC_BUG_H
+#define _PERF_ASM_GENERIC_BUG_H
+
+#define __WARN_printf(arg...)  do { fprintf(stderr, arg); } while (0)
+
+#define WARN(condition, format...) ({          \
+       int __ret_warn_on = !!(condition);      \
+       if (unlikely(__ret_warn_on))            \
+               __WARN_printf(format);          \
+       unlikely(__ret_warn_on);                \
+})
+
+#define WARN_ONCE(condition, format...)        ({      \
+       static int __warned;                    \
+       int __ret_warn_once = !!(condition);    \
+                                               \
+       if (unlikely(__ret_warn_once))          \
+               if (WARN(!__warned, format))    \
+                       __warned = 1;           \
+       unlikely(__ret_warn_once);              \
+})
+#endif
diff --git a/tools/perf/util/include/asm/byteorder.h b/tools/perf/util/include/asm/byteorder.h
new file mode 100644 (file)
index 0000000..b722abe
--- /dev/null
@@ -0,0 +1,2 @@
+#include <asm/types.h>
+#include "../../../../include/linux/swab.h"
diff --git a/tools/perf/util/include/asm/swab.h b/tools/perf/util/include/asm/swab.h
new file mode 100644 (file)
index 0000000..ed53894
--- /dev/null
@@ -0,0 +1 @@
+/* stub */
diff --git a/tools/perf/util/include/asm/uaccess.h b/tools/perf/util/include/asm/uaccess.h
new file mode 100644 (file)
index 0000000..d0f72b8
--- /dev/null
@@ -0,0 +1,14 @@
+#ifndef _PERF_ASM_UACCESS_H_
+#define _PERF_ASM_UACCESS_H_
+
+#define __get_user(src, dest)                                          \
+({                                                                     \
+       (src) = *dest;                                                  \
+       0;                                                              \
+})
+
+#define get_user       __get_user
+
+#define access_ok(type, addr, size)    1
+
+#endif
diff --git a/tools/perf/util/include/linux/bitmap.h b/tools/perf/util/include/linux/bitmap.h
new file mode 100644 (file)
index 0000000..9450763
--- /dev/null
@@ -0,0 +1,3 @@
+#include "../../../../include/linux/bitmap.h"
+#include "../../../../include/asm-generic/bitops/find.h"
+#include <linux/errno.h>
diff --git a/tools/perf/util/include/linux/bitops.h b/tools/perf/util/include/linux/bitops.h
new file mode 100644 (file)
index 0000000..8d63116
--- /dev/null
@@ -0,0 +1,29 @@
+#ifndef _PERF_LINUX_BITOPS_H_
+#define _PERF_LINUX_BITOPS_H_
+
+#define __KERNEL__
+
+#define CONFIG_GENERIC_FIND_NEXT_BIT
+#define CONFIG_GENERIC_FIND_FIRST_BIT
+#include "../../../../include/linux/bitops.h"
+
+#undef __KERNEL__
+
+static inline void set_bit(int nr, unsigned long *addr)
+{
+       addr[nr / BITS_PER_LONG] |= 1UL << (nr % BITS_PER_LONG);
+}
+
+static __always_inline int test_bit(unsigned int nr, const unsigned long *addr)
+{
+       return ((1UL << (nr % BITS_PER_LONG)) &
+               (((unsigned long *)addr)[nr / BITS_PER_LONG])) != 0;
+}
+
+unsigned long generic_find_next_zero_le_bit(const unsigned long *addr, unsigned
+               long size, unsigned long offset);
+
+unsigned long generic_find_next_le_bit(const unsigned long *addr, unsigned
+               long size, unsigned long offset);
+
+#endif
diff --git a/tools/perf/util/include/linux/compiler.h b/tools/perf/util/include/linux/compiler.h
new file mode 100644 (file)
index 0000000..dfb0713
--- /dev/null
@@ -0,0 +1,10 @@
+#ifndef _PERF_LINUX_COMPILER_H_
+#define _PERF_LINUX_COMPILER_H_
+
+#ifndef __always_inline
+#define __always_inline        inline
+#endif
+#define __user
+#define __attribute_const__
+
+#endif
diff --git a/tools/perf/util/include/linux/ctype.h b/tools/perf/util/include/linux/ctype.h
new file mode 100644 (file)
index 0000000..a53d4ee
--- /dev/null
@@ -0,0 +1 @@
+#include "../util.h"
index a6b8739..21c0274 100644 (file)
@@ -1,6 +1,16 @@
 #ifndef PERF_LINUX_KERNEL_H_
 #define PERF_LINUX_KERNEL_H_
 
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d))
+
+#define ALIGN(x,a)             __ALIGN_MASK(x,(typeof(x))(a)-1)
+#define __ALIGN_MASK(x,mask)   (((x)+(mask))&~(mask))
+
 #ifndef offsetof
 #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
 #endif
        _max1 > _max2 ? _max1 : _max2; })
 #endif
 
+#ifndef min
+#define min(x, y) ({                           \
+       typeof(x) _min1 = (x);                  \
+       typeof(y) _min2 = (y);                  \
+       (void) (&_min1 == &_min2);              \
+       _min1 < _min2 ? _min1 : _min2; })
+#endif
+
+#ifndef BUG_ON
+#define BUG_ON(cond) assert(!(cond))
+#endif
+
+/*
+ * Both need more care to handle endianness
+ * (Don't use bitmap_copy_le() for now)
+ */
+#define cpu_to_le64(x) (x)
+#define cpu_to_le32(x) (x)
+
+static inline int
+vscnprintf(char *buf, size_t size, const char *fmt, va_list args)
+{
+       int i;
+       ssize_t ssize = size;
+
+       i = vsnprintf(buf, size, fmt, args);
+
+       return (i >= ssize) ? (ssize - 1) : i;
+}
+
+static inline int scnprintf(char * buf, size_t size, const char * fmt, ...)
+{
+       va_list args;
+       ssize_t ssize = size;
+       int i;
+
+       va_start(args, fmt);
+       i = vsnprintf(buf, size, fmt, args);
+       va_end(args);
+
+       return (i >= ssize) ? (ssize - 1) : i;
+}
+
+static inline unsigned long
+simple_strtoul(const char *nptr, char **endptr, int base)
+{
+       return strtoul(nptr, endptr, base);
+}
+
+#ifndef pr_fmt
+#define pr_fmt(fmt) fmt
+#endif
+
+#define pr_err(fmt, ...) \
+       do { fprintf(stderr, pr_fmt(fmt), ##__VA_ARGS__); } while (0)
+#define pr_warning(fmt, ...) \
+       do { fprintf(stderr, pr_fmt(fmt), ##__VA_ARGS__); } while (0)
+#define pr_info(fmt, ...) \
+       do { fprintf(stderr, pr_fmt(fmt), ##__VA_ARGS__); } while (0)
+#define pr_debug(fmt, ...) \
+       eprintf(1, pr_fmt(fmt), ##__VA_ARGS__)
+#define pr_debugN(n, fmt, ...) \
+       eprintf(n, pr_fmt(fmt), ##__VA_ARGS__)
+#define pr_debug2(fmt, ...) pr_debugN(2, pr_fmt(fmt), ##__VA_ARGS__)
+#define pr_debug3(fmt, ...) pr_debugN(3, pr_fmt(fmt), ##__VA_ARGS__)
+
 #endif
diff --git a/tools/perf/util/include/linux/string.h b/tools/perf/util/include/linux/string.h
new file mode 100644 (file)
index 0000000..3b2f590
--- /dev/null
@@ -0,0 +1 @@
+#include <string.h>
diff --git a/tools/perf/util/include/linux/types.h b/tools/perf/util/include/linux/types.h
new file mode 100644 (file)
index 0000000..196862a
--- /dev/null
@@ -0,0 +1,9 @@
+#ifndef _PERF_LINUX_TYPES_H_
+#define _PERF_LINUX_TYPES_H_
+
+#include <asm/types.h>
+
+#define DECLARE_BITMAP(name,bits) \
+       unsigned long name[BITS_TO_LONGS(bits)]
+
+#endif
index 0173abe..b0fcb6d 100644 (file)
@@ -1,8 +1,8 @@
-#ifndef LEVENSHTEIN_H
-#define LEVENSHTEIN_H
+#ifndef __PERF_LEVENSHTEIN_H
+#define __PERF_LEVENSHTEIN_H
 
 int levenshtein(const char *string1, const char *string2,
        int swap_penalty, int substition_penalty,
        int insertion_penalty, int deletion_penalty);
 
-#endif
+#endif /* __PERF_LEVENSHTEIN_H */
index 804e023..69f94fe 100644 (file)
@@ -3,6 +3,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <stdio.h>
+#include "debug.h"
 
 static inline int is_anon_memory(const char *filename)
 {
@@ -19,13 +20,28 @@ static int strcommon(const char *pathname, char *cwd, int cwdlen)
        return n;
 }
 
- struct map *map__new(struct mmap_event *event, char *cwd, int cwdlen)
+void map__init(struct map *self, enum map_type type,
+              u64 start, u64 end, u64 pgoff, struct dso *dso)
+{
+       self->type     = type;
+       self->start    = start;
+       self->end      = end;
+       self->pgoff    = pgoff;
+       self->dso      = dso;
+       self->map_ip   = map__map_ip;
+       self->unmap_ip = map__unmap_ip;
+       RB_CLEAR_NODE(&self->rb_node);
+}
+
+struct map *map__new(struct mmap_event *event, enum map_type type,
+                    char *cwd, int cwdlen)
 {
        struct map *self = malloc(sizeof(*self));
 
        if (self != NULL) {
                const char *filename = event->filename;
                char newfilename[PATH_MAX];
+               struct dso *dso;
                int anon;
 
                if (cwd) {
@@ -45,18 +61,15 @@ static int strcommon(const char *pathname, char *cwd, int cwdlen)
                        filename = newfilename;
                }
 
-               self->start = event->start;
-               self->end   = event->start + event->len;
-               self->pgoff = event->pgoff;
-
-               self->dso = dsos__findnew(filename);
-               if (self->dso == NULL)
+               dso = dsos__findnew(filename);
+               if (dso == NULL)
                        goto out_delete;
 
+               map__init(self, type, event->start, event->start + event->len,
+                         event->pgoff, dso);
+
                if (self->dso == vdso || anon)
-                       self->map_ip = vdso__map_ip;
-               else
-                       self->map_ip = map__map_ip;
+                       self->map_ip = self->unmap_ip = identity__map_ip;
        }
        return self;
 out_delete:
@@ -64,6 +77,72 @@ out_delete:
        return NULL;
 }
 
+void map__delete(struct map *self)
+{
+       free(self);
+}
+
+void map__fixup_start(struct map *self)
+{
+       struct rb_root *symbols = &self->dso->symbols[self->type];
+       struct rb_node *nd = rb_first(symbols);
+       if (nd != NULL) {
+               struct symbol *sym = rb_entry(nd, struct symbol, rb_node);
+               self->start = sym->start;
+       }
+}
+
+void map__fixup_end(struct map *self)
+{
+       struct rb_root *symbols = &self->dso->symbols[self->type];
+       struct rb_node *nd = rb_last(symbols);
+       if (nd != NULL) {
+               struct symbol *sym = rb_entry(nd, struct symbol, rb_node);
+               self->end = sym->end;
+       }
+}
+
+#define DSO__DELETED "(deleted)"
+
+struct symbol *map__find_symbol(struct map *self, u64 addr,
+                               symbol_filter_t filter)
+{
+       if (!dso__loaded(self->dso, self->type)) {
+               int nr = dso__load(self->dso, self, filter);
+
+               if (nr < 0) {
+                       if (self->dso->has_build_id) {
+                               char sbuild_id[BUILD_ID_SIZE * 2 + 1];
+
+                               build_id__sprintf(self->dso->build_id,
+                                                 sizeof(self->dso->build_id),
+                                                 sbuild_id);
+                               pr_warning("%s with build id %s not found",
+                                          self->dso->long_name, sbuild_id);
+                       } else
+                               pr_warning("Failed to open %s",
+                                          self->dso->long_name);
+                       pr_warning(", continuing without symbols\n");
+                       return NULL;
+               } else if (nr == 0) {
+                       const char *name = self->dso->long_name;
+                       const size_t len = strlen(name);
+                       const size_t real_len = len - sizeof(DSO__DELETED);
+
+                       if (len > sizeof(DSO__DELETED) &&
+                           strcmp(name + real_len + 1, DSO__DELETED) == 0) {
+                               pr_warning("%.*s was updated, restart the long running apps that use it!\n",
+                                          (int)real_len, name);
+                       } else {
+                               pr_warning("no symbols found in %s, maybe install a debug package?\n", name);
+                       }
+                       return NULL;
+               }
+       }
+
+       return self->dso->find_symbol(self->dso, self->type, addr);
+}
+
 struct map *map__clone(struct map *self)
 {
        struct map *map = malloc(sizeof(*self));
diff --git a/tools/perf/util/module.c b/tools/perf/util/module.c
deleted file mode 100644 (file)
index 0d8c85d..0000000
+++ /dev/null
@@ -1,545 +0,0 @@
-#include "util.h"
-#include "../perf.h"
-#include "string.h"
-#include "module.h"
-
-#include <libelf.h>
-#include <libgen.h>
-#include <gelf.h>
-#include <elf.h>
-#include <dirent.h>
-#include <sys/utsname.h>
-
-static unsigned int crc32(const char *p, unsigned int len)
-{
-       int i;
-       unsigned int crc = 0;
-
-       while (len--) {
-               crc ^= *p++;
-               for (i = 0; i < 8; i++)
-                       crc = (crc >> 1) ^ ((crc & 1) ? 0xedb88320 : 0);
-       }
-       return crc;
-}
-
-/* module section methods */
-
-struct sec_dso *sec_dso__new_dso(const char *name)
-{
-       struct sec_dso *self = malloc(sizeof(*self) + strlen(name) + 1);
-
-       if (self != NULL) {
-               strcpy(self->name, name);
-               self->secs = RB_ROOT;
-               self->find_section = sec_dso__find_section;
-       }
-
-       return self;
-}
-
-static void sec_dso__delete_section(struct section *self)
-{
-       free(((void *)self));
-}
-
-void sec_dso__delete_sections(struct sec_dso *self)
-{
-       struct section *pos;
-       struct rb_node *next = rb_first(&self->secs);
-
-       while (next) {
-               pos = rb_entry(next, struct section, rb_node);
-               next = rb_next(&pos->rb_node);
-               rb_erase(&pos->rb_node, &self->secs);
-               sec_dso__delete_section(pos);
-       }
-}
-
-void sec_dso__delete_self(struct sec_dso *self)
-{
-       sec_dso__delete_sections(self);
-       free(self);
-}
-
-static void sec_dso__insert_section(struct sec_dso *self, struct section *sec)
-{
-       struct rb_node **p = &self->secs.rb_node;
-       struct rb_node *parent = NULL;
-       const u64 hash = sec->hash;
-       struct section *s;
-
-       while (*p != NULL) {
-               parent = *p;
-               s = rb_entry(parent, struct section, rb_node);
-               if (hash < s->hash)
-                       p = &(*p)->rb_left;
-               else
-                       p = &(*p)->rb_right;
-       }
-       rb_link_node(&sec->rb_node, parent, p);
-       rb_insert_color(&sec->rb_node, &self->secs);
-}
-
-struct section *sec_dso__find_section(struct sec_dso *self, const char *name)
-{
-       struct rb_node *n;
-       u64 hash;
-       int len;
-
-       if (self == NULL)
-               return NULL;
-
-       len = strlen(name);
-       hash = crc32(name, len);
-
-       n = self->secs.rb_node;
-
-       while (n) {
-               struct section *s = rb_entry(n, struct section, rb_node);
-
-               if (hash < s->hash)
-                       n = n->rb_left;
-               else if (hash > s->hash)
-                       n = n->rb_right;
-               else {
-                       if (!strcmp(name, s->name))
-                               return s;
-                       else
-                               n = rb_next(&s->rb_node);
-               }
-       }
-
-       return NULL;
-}
-
-static size_t sec_dso__fprintf_section(struct section *self, FILE *fp)
-{
-       return fprintf(fp, "name:%s vma:%llx path:%s\n",
-                      self->name, self->vma, self->path);
-}
-
-size_t sec_dso__fprintf(struct sec_dso *self, FILE *fp)
-{
-       size_t ret = fprintf(fp, "dso: %s\n", self->name);
-
-       struct rb_node *nd;
-       for (nd = rb_first(&self->secs); nd; nd = rb_next(nd)) {
-               struct section *pos = rb_entry(nd, struct section, rb_node);
-               ret += sec_dso__fprintf_section(pos, fp);
-       }
-
-       return ret;
-}
-
-static struct section *section__new(const char *name, const char *path)
-{
-       struct section *self = calloc(1, sizeof(*self));
-
-       if (!self)
-               goto out_failure;
-
-       self->name = calloc(1, strlen(name) + 1);
-       if (!self->name)
-               goto out_failure;
-
-       self->path = calloc(1, strlen(path) + 1);
-       if (!self->path)
-               goto out_failure;
-
-       strcpy(self->name, name);
-       strcpy(self->path, path);
-       self->hash = crc32(self->name, strlen(name));
-
-       return self;
-
-out_failure:
-       if (self) {
-               if (self->name)
-                       free(self->name);
-               if (self->path)
-                       free(self->path);
-               free(self);
-       }
-
-       return NULL;
-}
-
-/* module methods */
-
-struct mod_dso *mod_dso__new_dso(const char *name)
-{
-       struct mod_dso *self = malloc(sizeof(*self) + strlen(name) + 1);
-
-       if (self != NULL) {
-               strcpy(self->name, name);
-               self->mods = RB_ROOT;
-               self->find_module = mod_dso__find_module;
-       }
-
-       return self;
-}
-
-static void mod_dso__delete_module(struct module *self)
-{
-       free(((void *)self));
-}
-
-void mod_dso__delete_modules(struct mod_dso *self)
-{
-       struct module *pos;
-       struct rb_node *next = rb_first(&self->mods);
-
-       while (next) {
-               pos = rb_entry(next, struct module, rb_node);
-               next = rb_next(&pos->rb_node);
-               rb_erase(&pos->rb_node, &self->mods);
-               mod_dso__delete_module(pos);
-       }
-}
-
-void mod_dso__delete_self(struct mod_dso *self)
-{
-       mod_dso__delete_modules(self);
-       free(self);
-}
-
-static void mod_dso__insert_module(struct mod_dso *self, struct module *mod)
-{
-       struct rb_node **p = &self->mods.rb_node;
-       struct rb_node *parent = NULL;
-       const u64 hash = mod->hash;
-       struct module *m;
-
-       while (*p != NULL) {
-               parent = *p;
-               m = rb_entry(parent, struct module, rb_node);
-               if (hash < m->hash)
-                       p = &(*p)->rb_left;
-               else
-                       p = &(*p)->rb_right;
-       }
-       rb_link_node(&mod->rb_node, parent, p);
-       rb_insert_color(&mod->rb_node, &self->mods);
-}
-
-struct module *mod_dso__find_module(struct mod_dso *self, const char *name)
-{
-       struct rb_node *n;
-       u64 hash;
-       int len;
-
-       if (self == NULL)
-               return NULL;
-
-       len = strlen(name);
-       hash = crc32(name, len);
-
-       n = self->mods.rb_node;
-
-       while (n) {
-               struct module *m = rb_entry(n, struct module, rb_node);
-
-               if (hash < m->hash)
-                       n = n->rb_left;
-               else if (hash > m->hash)
-                       n = n->rb_right;
-               else {
-                       if (!strcmp(name, m->name))
-                               return m;
-                       else
-                               n = rb_next(&m->rb_node);
-               }
-       }
-
-       return NULL;
-}
-
-static size_t mod_dso__fprintf_module(struct module *self, FILE *fp)
-{
-       return fprintf(fp, "name:%s path:%s\n", self->name, self->path);
-}
-
-size_t mod_dso__fprintf(struct mod_dso *self, FILE *fp)
-{
-       struct rb_node *nd;
-       size_t ret;
-
-       ret = fprintf(fp, "dso: %s\n", self->name);
-
-       for (nd = rb_first(&self->mods); nd; nd = rb_next(nd)) {
-               struct module *pos = rb_entry(nd, struct module, rb_node);
-
-               ret += mod_dso__fprintf_module(pos, fp);
-       }
-
-       return ret;
-}
-
-static struct module *module__new(const char *name, const char *path)
-{
-       struct module *self = calloc(1, sizeof(*self));
-
-       if (!self)
-               goto out_failure;
-
-       self->name = calloc(1, strlen(name) + 1);
-       if (!self->name)
-               goto out_failure;
-
-       self->path = calloc(1, strlen(path) + 1);
-       if (!self->path)
-               goto out_failure;
-
-       strcpy(self->name, name);
-       strcpy(self->path, path);
-       self->hash = crc32(self->name, strlen(name));
-
-       return self;
-
-out_failure:
-       if (self) {
-               if (self->name)
-                       free(self->name);
-               if (self->path)
-                       free(self->path);
-               free(self);
-       }
-
-       return NULL;
-}
-
-static int mod_dso__load_sections(struct module *mod)
-{
-       int count = 0, path_len;
-       struct dirent *entry;
-       char *line = NULL;
-       char *dir_path;
-       DIR *dir;
-       size_t n;
-
-       path_len = strlen("/sys/module/");
-       path_len += strlen(mod->name);
-       path_len += strlen("/sections/");
-
-       dir_path = calloc(1, path_len + 1);
-       if (dir_path == NULL)
-               goto out_failure;
-
-       strcat(dir_path, "/sys/module/");
-       strcat(dir_path, mod->name);
-       strcat(dir_path, "/sections/");
-
-       dir = opendir(dir_path);
-       if (dir == NULL)
-               goto out_free;
-
-       while ((entry = readdir(dir))) {
-               struct section *section;
-               char *path, *vma;
-               int line_len;
-               FILE *file;
-
-               if (!strcmp(".", entry->d_name) || !strcmp("..", entry->d_name))
-                       continue;
-
-               path = calloc(1, path_len + strlen(entry->d_name) + 1);
-               if (path == NULL)
-                       break;
-               strcat(path, dir_path);
-               strcat(path, entry->d_name);
-
-               file = fopen(path, "r");
-               if (file == NULL) {
-                       free(path);
-                       break;
-               }
-
-               line_len = getline(&line, &n, file);
-               if (line_len < 0) {
-                       free(path);
-                       fclose(file);
-                       break;
-               }
-
-               if (!line) {
-                       free(path);
-                       fclose(file);
-                       break;
-               }
-
-               line[--line_len] = '\0'; /* \n */
-
-               vma = strstr(line, "0x");
-               if (!vma) {
-                       free(path);
-                       fclose(file);
-                       break;
-               }
-               vma += 2;
-
-               section = section__new(entry->d_name, path);
-               if (!section) {
-                       fprintf(stderr, "load_sections: allocation error\n");
-                       free(path);
-                       fclose(file);
-                       break;
-               }
-
-               hex2u64(vma, &section->vma);
-               sec_dso__insert_section(mod->sections, section);
-
-               free(path);
-               fclose(file);
-               count++;
-       }
-
-       closedir(dir);
-       free(line);
-       free(dir_path);
-
-       return count;
-
-out_free:
-       free(dir_path);
-
-out_failure:
-       return count;
-}
-
-static int mod_dso__load_module_paths(struct mod_dso *self)
-{
-       struct utsname uts;
-       int count = 0, len, err = -1;
-       char *line = NULL;
-       FILE *file;
-       char *dpath, *dir;
-       size_t n;
-
-       if (uname(&uts) < 0)
-               return err;
-
-       len = strlen("/lib/modules/");
-       len += strlen(uts.release);
-       len += strlen("/modules.dep");
-
-       dpath = calloc(1, len + 1);
-       if (dpath == NULL)
-               return err;
-
-       strcat(dpath, "/lib/modules/");
-       strcat(dpath, uts.release);
-       strcat(dpath, "/modules.dep");
-
-       file = fopen(dpath, "r");
-       if (file == NULL)
-               goto out_failure;
-
-       dir = dirname(dpath);
-       if (!dir)
-               goto out_failure;
-       strcat(dir, "/");
-
-       while (!feof(file)) {
-               struct module *module;
-               char *name, *path, *tmp;
-               FILE *modfile;
-               int line_len;
-
-               line_len = getline(&line, &n, file);
-               if (line_len < 0)
-                       break;
-
-               if (!line)
-                       break;
-
-               line[--line_len] = '\0'; /* \n */
-
-               path = strchr(line, ':');
-               if (!path)
-                       break;
-               *path = '\0';
-
-               path = strdup(line);
-               if (!path)
-                       break;
-
-               if (!strstr(path, dir)) {
-                       if (strncmp(path, "kernel/", 7))
-                               break;
-
-                       free(path);
-                       path = calloc(1, strlen(dir) + strlen(line) + 1);
-                       if (!path)
-                               break;
-                       strcat(path, dir);
-                       strcat(path, line);
-               }
-
-               modfile = fopen(path, "r");
-               if (modfile == NULL)
-                       break;
-               fclose(modfile);
-
-               name = strdup(path);
-               if (!name)
-                       break;
-
-               name = strtok(name, "/");
-               tmp = name;
-
-               while (tmp) {
-                       tmp = strtok(NULL, "/");
-                       if (tmp)
-                               name = tmp;
-               }
-
-               name = strsep(&name, ".");
-               if (!name)
-                       break;
-
-               /* Quirk: replace '-' with '_' in all modules */
-               for (len = strlen(name); len; len--) {
-                       if (*(name+len) == '-')
-                               *(name+len) = '_';
-               }
-
-               module = module__new(name, path);
-               if (!module)
-                       break;
-               mod_dso__insert_module(self, module);
-
-               module->sections = sec_dso__new_dso("sections");
-               if (!module->sections)
-                       break;
-
-               module->active = mod_dso__load_sections(module);
-
-               if (module->active > 0)
-                       count++;
-       }
-
-       if (feof(file))
-               err = count;
-       else
-               fprintf(stderr, "load_module_paths: modules.dep parsing failure!\n");
-
-out_failure:
-       if (dpath)
-               free(dpath);
-       if (file)
-               fclose(file);
-       if (line)
-               free(line);
-
-       return err;
-}
-
-int mod_dso__load_modules(struct mod_dso *dso)
-{
-       int err;
-
-       err = mod_dso__load_module_paths(dso);
-
-       return err;
-}
diff --git a/tools/perf/util/module.h b/tools/perf/util/module.h
deleted file mode 100644 (file)
index 8a592ef..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-#ifndef _PERF_MODULE_
-#define _PERF_MODULE_ 1
-
-#include <linux/types.h>
-#include "../types.h"
-#include <linux/list.h>
-#include <linux/rbtree.h>
-
-struct section {
-       struct rb_node  rb_node;
-       u64             hash;
-       u64             vma;
-       char            *name;
-       char            *path;
-};
-
-struct sec_dso {
-       struct list_head node;
-       struct rb_root   secs;
-       struct section    *(*find_section)(struct sec_dso *, const char *name);
-       char             name[0];
-};
-
-struct module {
-       struct rb_node  rb_node;
-       u64             hash;
-       char            *name;
-       char            *path;
-       struct sec_dso  *sections;
-       int             active;
-};
-
-struct mod_dso {
-       struct list_head node;
-       struct rb_root   mods;
-       struct module    *(*find_module)(struct mod_dso *, const char *name);
-       char             name[0];
-};
-
-struct sec_dso *sec_dso__new_dso(const char *name);
-void sec_dso__delete_sections(struct sec_dso *self);
-void sec_dso__delete_self(struct sec_dso *self);
-size_t sec_dso__fprintf(struct sec_dso *self, FILE *fp);
-struct section *sec_dso__find_section(struct sec_dso *self, const char *name);
-
-struct mod_dso *mod_dso__new_dso(const char *name);
-void mod_dso__delete_modules(struct mod_dso *self);
-void mod_dso__delete_self(struct mod_dso *self);
-size_t mod_dso__fprintf(struct mod_dso *self, FILE *fp);
-struct module *mod_dso__find_module(struct mod_dso *self, const char *name);
-int mod_dso__load_modules(struct mod_dso *dso);
-
-#endif /* _PERF_MODULE_ */
index 8cfb48c..9e5dbd6 100644 (file)
@@ -1,4 +1,4 @@
-
+#include "../../../include/linux/hw_breakpoint.h"
 #include "util.h"
 #include "../perf.h"
 #include "parse-options.h"
@@ -7,10 +7,12 @@
 #include "string.h"
 #include "cache.h"
 #include "header.h"
+#include "debugfs.h"
 
-int                                    nr_counters;
+int                            nr_counters;
 
 struct perf_event_attr         attrs[MAX_COUNTERS];
+char                           *filters[MAX_COUNTERS];
 
 struct event_symbol {
        u8              type;
@@ -46,6 +48,8 @@ static struct event_symbol event_symbols[] = {
   { 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",     ""              },
 };
 
 #define __PERF_EVENT_FIELD(config, name) \
@@ -74,6 +78,8 @@ static const char *sw_event_names[] = {
        "CPU-migrations",
        "minor-faults",
        "major-faults",
+       "alignment-faults",
+       "emulation-faults",
 };
 
 #define MAX_ALIASES 8
@@ -148,16 +154,6 @@ static int tp_event_has_id(struct dirent *sys_dir, struct dirent *evt_dir)
 
 #define MAX_EVENT_LENGTH 512
 
-int valid_debugfs_mount(const char *debugfs)
-{
-       struct statfs st_fs;
-
-       if (statfs(debugfs, &st_fs) < 0)
-               return -ENOENT;
-       else if (st_fs.f_type != (long) DEBUGFS_MAGIC)
-               return -ENOENT;
-       return 0;
-}
 
 struct tracepoint_path *tracepoint_id_to_path(u64 config)
 {
@@ -170,7 +166,7 @@ struct tracepoint_path *tracepoint_id_to_path(u64 config)
        char evt_path[MAXPATHLEN];
        char dir_path[MAXPATHLEN];
 
-       if (valid_debugfs_mount(debugfs_path))
+       if (debugfs_valid_mountpoint(debugfs_path))
                return NULL;
 
        sys_dir = opendir(debugfs_path);
@@ -201,7 +197,7 @@ struct tracepoint_path *tracepoint_id_to_path(u64 config)
                        if (id == config) {
                                closedir(evt_dir);
                                closedir(sys_dir);
-                               path = calloc(1, sizeof(path));
+                               path = zalloc(sizeof(path));
                                path->system = malloc(MAX_EVENT_LENGTH);
                                if (!path->system) {
                                        free(path);
@@ -509,7 +505,7 @@ static enum event_result parse_tracepoint_event(const char **strp,
        char sys_name[MAX_EVENT_LENGTH];
        unsigned int sys_length, evt_length;
 
-       if (valid_debugfs_mount(debugfs_path))
+       if (debugfs_valid_mountpoint(debugfs_path))
                return 0;
 
        evt_name = strchr(*strp, ':');
@@ -544,6 +540,81 @@ static enum event_result parse_tracepoint_event(const char **strp,
                                                     attr, strp);
 }
 
+static enum event_result
+parse_breakpoint_type(const char *type, const char **strp,
+                     struct perf_event_attr *attr)
+{
+       int i;
+
+       for (i = 0; i < 3; i++) {
+               if (!type[i])
+                       break;
+
+               switch (type[i]) {
+               case 'r':
+                       attr->bp_type |= HW_BREAKPOINT_R;
+                       break;
+               case 'w':
+                       attr->bp_type |= HW_BREAKPOINT_W;
+                       break;
+               case 'x':
+                       attr->bp_type |= HW_BREAKPOINT_X;
+                       break;
+               default:
+                       return EVT_FAILED;
+               }
+       }
+       if (!attr->bp_type) /* Default */
+               attr->bp_type = HW_BREAKPOINT_R | HW_BREAKPOINT_W;
+
+       *strp = type + i;
+
+       return EVT_HANDLED;
+}
+
+static enum event_result
+parse_breakpoint_event(const char **strp, struct perf_event_attr *attr)
+{
+       const char *target;
+       const char *type;
+       char *endaddr;
+       u64 addr;
+       enum event_result err;
+
+       target = strchr(*strp, ':');
+       if (!target)
+               return EVT_FAILED;
+
+       if (strncmp(*strp, "mem", target - *strp) != 0)
+               return EVT_FAILED;
+
+       target++;
+
+       addr = strtoull(target, &endaddr, 0);
+       if (target == endaddr)
+               return EVT_FAILED;
+
+       attr->bp_addr = addr;
+       *strp = endaddr;
+
+       type = strchr(target, ':');
+
+       /* If no type is defined, just rw as default */
+       if (!type) {
+               attr->bp_type = HW_BREAKPOINT_R | HW_BREAKPOINT_W;
+       } else {
+               err = parse_breakpoint_type(++type, strp, attr);
+               if (err == EVT_FAILED)
+                       return EVT_FAILED;
+       }
+
+       /* We should find a nice way to override the access type */
+       attr->bp_len = HW_BREAKPOINT_LEN_4;
+       attr->type = PERF_TYPE_BREAKPOINT;
+
+       return EVT_HANDLED;
+}
+
 static int check_events(const char *str, unsigned int i)
 {
        int n;
@@ -677,6 +748,12 @@ parse_event_symbols(const char **str, struct perf_event_attr *attr)
        if (ret != EVT_FAILED)
                goto modifier;
 
+       ret = parse_breakpoint_event(str, attr);
+       if (ret != EVT_FAILED)
+               goto modifier;
+
+       fprintf(stderr, "invalid or unsupported event: '%s'\n", *str);
+       fprintf(stderr, "Run 'perf list' for a list of valid events\n");
        return EVT_FAILED;
 
 modifier:
@@ -708,7 +785,6 @@ static void store_event_type(const char *orgname)
        perf_header__push_event(id, orgname);
 }
 
-
 int parse_events(const struct option *opt __used, const char *str, int unset __used)
 {
        struct perf_event_attr attr;
@@ -745,6 +821,28 @@ int parse_events(const struct option *opt __used, const char *str, int unset __u
        return 0;
 }
 
+int parse_filter(const struct option *opt __used, const char *str,
+                int unset __used)
+{
+       int i = nr_counters - 1;
+       int len = strlen(str);
+
+       if (i < 0 || attrs[i].type != PERF_TYPE_TRACEPOINT) {
+               fprintf(stderr,
+                       "-F option should follow a -e tracepoint option\n");
+               return -1;
+       }
+
+       filters[i] = malloc(len + 1);
+       if (!filters[i]) {
+               fprintf(stderr, "not enough memory to hold filter string\n");
+               return -1;
+       }
+       strcpy(filters[i], str);
+
+       return 0;
+}
+
 static const char * const event_type_descriptors[] = {
        "",
        "Hardware event",
@@ -764,7 +862,7 @@ static void print_tracepoint_events(void)
        char evt_path[MAXPATHLEN];
        char dir_path[MAXPATHLEN];
 
-       if (valid_debugfs_mount(debugfs_path))
+       if (debugfs_valid_mountpoint(debugfs_path))
                return;
 
        sys_dir = opendir(debugfs_path);
@@ -782,7 +880,7 @@ static void print_tracepoint_events(void)
                for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next) {
                        snprintf(evt_path, MAXPATHLEN, "%s:%s",
                                 sys_dirent.d_name, evt_dirent.d_name);
-                       fprintf(stderr, "  %-42s [%s]\n", evt_path,
+                       printf("  %-42s [%s]\n", evt_path,
                                event_type_descriptors[PERF_TYPE_TRACEPOINT+1]);
                }
                closedir(evt_dir);
@@ -799,8 +897,8 @@ void print_events(void)
        unsigned int i, type, op, prev_type = -1;
        char name[40];
 
-       fprintf(stderr, "\n");
-       fprintf(stderr, "List of pre-defined events (to be used in -e):\n");
+       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 + 1;
@@ -808,19 +906,19 @@ void print_events(void)
                        type = 0;
 
                if (type != prev_type)
-                       fprintf(stderr, "\n");
+                       printf("\n");
 
                if (strlen(syms->alias))
                        sprintf(name, "%s OR %s", syms->symbol, syms->alias);
                else
                        strcpy(name, syms->symbol);
-               fprintf(stderr, "  %-42s [%s]\n", name,
+               printf("  %-42s [%s]\n", name,
                        event_type_descriptors[type]);
 
                prev_type = type;
        }
 
-       fprintf(stderr, "\n");
+       printf("\n");
        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 */
@@ -828,17 +926,20 @@ void print_events(void)
                                continue;
 
                        for (i = 0; i < PERF_COUNT_HW_CACHE_RESULT_MAX; i++) {
-                               fprintf(stderr, "  %-42s [%s]\n",
+                               printf("  %-42s [%s]\n",
                                        event_cache_name(type, op, i),
                                        event_type_descriptors[4]);
                        }
                }
        }
 
-       fprintf(stderr, "\n");
-       fprintf(stderr, "  %-42s [raw hardware event descriptor]\n",
+       printf("\n");
+       printf("  %-42s [raw hardware event descriptor]\n",
                "rNNN");
-       fprintf(stderr, "\n");
+       printf("\n");
+
+       printf("  %-42s [hardware breakpoint]\n", "mem:<addr>[:access]");
+       printf("\n");
 
        print_tracepoint_events();
 
index 30c6081..b8c1f64 100644 (file)
@@ -1,5 +1,5 @@
-#ifndef _PARSE_EVENTS_H
-#define _PARSE_EVENTS_H
+#ifndef __PERF_PARSE_EVENTS_H
+#define __PERF_PARSE_EVENTS_H
 /*
  * Parse symbolic events/counts passed in as options:
  */
@@ -17,11 +17,13 @@ extern struct tracepoint_path *tracepoint_id_to_path(u64 config);
 extern int                     nr_counters;
 
 extern struct perf_event_attr attrs[MAX_COUNTERS];
+extern char *filters[MAX_COUNTERS];
 
 extern const char *event_name(int ctr);
 extern const char *__event_name(int type, u64 config);
 
 extern int parse_events(const struct option *opt, const char *str, int unset);
+extern int parse_filter(const struct option *opt, const char *str, int unset);
 
 #define EVENTS_HELP_MAX (128*1024)
 
@@ -31,4 +33,4 @@ extern char debugfs_path[];
 extern int valid_debugfs_mount(const char *debugfs);
 
 
-#endif /* _PARSE_EVENTS_H */
+#endif /* __PERF_PARSE_EVENTS_H */
index 2ee248f..948805a 100644 (file)
@@ -1,5 +1,5 @@
-#ifndef PARSE_OPTIONS_H
-#define PARSE_OPTIONS_H
+#ifndef __PERF_PARSE_OPTIONS_H
+#define __PERF_PARSE_OPTIONS_H
 
 enum parse_opt_type {
        /* special types */
@@ -174,4 +174,4 @@ extern int parse_opt_verbosity_cb(const struct option *, const char *, int);
 
 extern const char *parse_options_fix_filename(const char *prefix, const char *file);
 
-#endif
+#endif /* __PERF_PARSE_OPTIONS_H */
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
new file mode 100644 (file)
index 0000000..cd7fbda
--- /dev/null
@@ -0,0 +1,484 @@
+/*
+ * probe-event.c : perf-probe definition to kprobe_events format converter
+ *
+ * Written by Masami Hiramatsu <mhiramat@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+#define _GNU_SOURCE
+#include <sys/utsname.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <limits.h>
+
+#undef _GNU_SOURCE
+#include "event.h"
+#include "string.h"
+#include "strlist.h"
+#include "debug.h"
+#include "parse-events.h"  /* For debugfs_path */
+#include "probe-event.h"
+
+#define MAX_CMDLEN 256
+#define MAX_PROBE_ARGS 128
+#define PERFPROBE_GROUP "probe"
+
+#define semantic_error(msg ...) die("Semantic error :" msg)
+
+/* If there is no space to write, returns -E2BIG. */
+static int e_snprintf(char *str, size_t size, const char *format, ...)
+{
+       int ret;
+       va_list ap;
+       va_start(ap, format);
+       ret = vsnprintf(str, size, format, ap);
+       va_end(ap);
+       if (ret >= (int)size)
+               ret = -E2BIG;
+       return ret;
+}
+
+/* Parse probepoint definition. */
+static void parse_perf_probe_probepoint(char *arg, struct probe_point *pp)
+{
+       char *ptr, *tmp;
+       char c, nc = 0;
+       /*
+        * <Syntax>
+        * perf probe SRC:LN
+        * perf probe FUNC[+OFFS|%return][@SRC]
+        */
+
+       ptr = strpbrk(arg, ":+@%");
+       if (ptr) {
+               nc = *ptr;
+               *ptr++ = '\0';
+       }
+
+       /* Check arg is function or file and copy it */
+       if (strchr(arg, '.'))   /* File */
+               pp->file = strdup(arg);
+       else                    /* Function */
+               pp->function = strdup(arg);
+       DIE_IF(pp->file == NULL && pp->function == NULL);
+
+       /* Parse other options */
+       while (ptr) {
+               arg = ptr;
+               c = nc;
+               ptr = strpbrk(arg, ":+@%");
+               if (ptr) {
+                       nc = *ptr;
+                       *ptr++ = '\0';
+               }
+               switch (c) {
+               case ':':       /* Line number */
+                       pp->line = strtoul(arg, &tmp, 0);
+                       if (*tmp != '\0')
+                               semantic_error("There is non-digit charactor"
+                                               " in line number.");
+                       break;
+               case '+':       /* Byte offset from a symbol */
+                       pp->offset = strtoul(arg, &tmp, 0);
+                       if (*tmp != '\0')
+                               semantic_error("There is non-digit charactor"
+                                               " in offset.");
+                       break;
+               case '@':       /* File name */
+                       if (pp->file)
+                               semantic_error("SRC@SRC is not allowed.");
+                       pp->file = strdup(arg);
+                       DIE_IF(pp->file == NULL);
+                       if (ptr)
+                               semantic_error("@SRC must be the last "
+                                              "option.");
+                       break;
+               case '%':       /* Probe places */
+                       if (strcmp(arg, "return") == 0) {
+                               pp->retprobe = 1;
+                       } else  /* Others not supported yet */
+                               semantic_error("%%%s is not supported.", arg);
+                       break;
+               default:
+                       DIE_IF("Program has a bug.");
+                       break;
+               }
+       }
+
+       /* Exclusion check */
+       if (pp->line && pp->offset)
+               semantic_error("Offset can't be used with line number.");
+
+       if (!pp->line && pp->file && !pp->function)
+               semantic_error("File always requires line number.");
+
+       if (pp->offset && !pp->function)
+               semantic_error("Offset requires an entry function.");
+
+       if (pp->retprobe && !pp->function)
+               semantic_error("Return probe requires an entry function.");
+
+       if ((pp->offset || pp->line) && pp->retprobe)
+               semantic_error("Offset/Line can't be used with return probe.");
+
+       pr_debug("symbol:%s file:%s line:%d offset:%d, return:%d\n",
+                pp->function, pp->file, pp->line, pp->offset, pp->retprobe);
+}
+
+/* Parse perf-probe event definition */
+int parse_perf_probe_event(const char *str, struct probe_point *pp)
+{
+       char **argv;
+       int argc, i, need_dwarf = 0;
+
+       argv = argv_split(str, &argc);
+       if (!argv)
+               die("argv_split failed.");
+       if (argc > MAX_PROBE_ARGS + 1)
+               semantic_error("Too many arguments");
+
+       /* Parse probe point */
+       parse_perf_probe_probepoint(argv[0], pp);
+       if (pp->file || pp->line)
+               need_dwarf = 1;
+
+       /* Copy arguments and ensure return probe has no C argument */
+       pp->nr_args = argc - 1;
+       pp->args = zalloc(sizeof(char *) * pp->nr_args);
+       for (i = 0; i < pp->nr_args; i++) {
+               pp->args[i] = strdup(argv[i + 1]);
+               if (!pp->args[i])
+                       die("Failed to copy argument.");
+               if (is_c_varname(pp->args[i])) {
+                       if (pp->retprobe)
+                               semantic_error("You can't specify local"
+                                               " variable for kretprobe");
+                       need_dwarf = 1;
+               }
+       }
+
+       argv_free(argv);
+       return need_dwarf;
+}
+
+/* Parse kprobe_events event into struct probe_point */
+void parse_trace_kprobe_event(const char *str, char **group, char **event,
+                             struct probe_point *pp)
+{
+       char pr;
+       char *p;
+       int ret, i, argc;
+       char **argv;
+
+       pr_debug("Parsing kprobe_events: %s\n", str);
+       argv = argv_split(str, &argc);
+       if (!argv)
+               die("argv_split failed.");
+       if (argc < 2)
+               semantic_error("Too less arguments.");
+
+       /* Scan event and group name. */
+       ret = sscanf(argv[0], "%c:%a[^/ \t]/%a[^ \t]",
+                    &pr, (float *)(void *)group, (float *)(void *)event);
+       if (ret != 3)
+               semantic_error("Failed to parse event name: %s", argv[0]);
+       pr_debug("Group:%s Event:%s probe:%c\n", *group, *event, pr);
+
+       if (!pp)
+               goto end;
+
+       pp->retprobe = (pr == 'r');
+
+       /* Scan function name and offset */
+       ret = sscanf(argv[1], "%a[^+]+%d", (float *)(void *)&pp->function, &pp->offset);
+       if (ret == 1)
+               pp->offset = 0;
+
+       /* kprobe_events doesn't have this information */
+       pp->line = 0;
+       pp->file = NULL;
+
+       pp->nr_args = argc - 2;
+       pp->args = zalloc(sizeof(char *) * pp->nr_args);
+       for (i = 0; i < pp->nr_args; i++) {
+               p = strchr(argv[i + 2], '=');
+               if (p)  /* We don't need which register is assigned. */
+                       *p = '\0';
+               pp->args[i] = strdup(argv[i + 2]);
+               if (!pp->args[i])
+                       die("Failed to copy argument.");
+       }
+
+end:
+       argv_free(argv);
+}
+
+int synthesize_perf_probe_event(struct probe_point *pp)
+{
+       char *buf;
+       char offs[64] = "", line[64] = "";
+       int i, len, ret;
+
+       pp->probes[0] = buf = zalloc(MAX_CMDLEN);
+       if (!buf)
+               die("Failed to allocate memory by zalloc.");
+       if (pp->offset) {
+               ret = e_snprintf(offs, 64, "+%d", pp->offset);
+               if (ret <= 0)
+                       goto error;
+       }
+       if (pp->line) {
+               ret = e_snprintf(line, 64, ":%d", pp->line);
+               if (ret <= 0)
+                       goto error;
+       }
+
+       if (pp->function)
+               ret = e_snprintf(buf, MAX_CMDLEN, "%s%s%s%s", pp->function,
+                                offs, pp->retprobe ? "%return" : "", line);
+       else
+               ret = e_snprintf(buf, MAX_CMDLEN, "%s%s%s%s", pp->file, line);
+       if (ret <= 0)
+               goto error;
+       len = ret;
+
+       for (i = 0; i < pp->nr_args; i++) {
+               ret = e_snprintf(&buf[len], MAX_CMDLEN - len, " %s",
+                                pp->args[i]);
+               if (ret <= 0)
+                       goto error;
+               len += ret;
+       }
+       pp->found = 1;
+
+       return pp->found;
+error:
+       free(pp->probes[0]);
+
+       return ret;
+}
+
+int synthesize_trace_kprobe_event(struct probe_point *pp)
+{
+       char *buf;
+       int i, len, ret;
+
+       pp->probes[0] = buf = zalloc(MAX_CMDLEN);
+       if (!buf)
+               die("Failed to allocate memory by zalloc.");
+       ret = e_snprintf(buf, MAX_CMDLEN, "%s+%d", pp->function, pp->offset);
+       if (ret <= 0)
+               goto error;
+       len = ret;
+
+       for (i = 0; i < pp->nr_args; i++) {
+               ret = e_snprintf(&buf[len], MAX_CMDLEN - len, " %s",
+                                pp->args[i]);
+               if (ret <= 0)
+                       goto error;
+               len += ret;
+       }
+       pp->found = 1;
+
+       return pp->found;
+error:
+       free(pp->probes[0]);
+
+       return ret;
+}
+
+static int open_kprobe_events(int flags, int mode)
+{
+       char buf[PATH_MAX];
+       int ret;
+
+       ret = e_snprintf(buf, PATH_MAX, "%s/../kprobe_events", debugfs_path);
+       if (ret < 0)
+               die("Failed to make kprobe_events path.");
+
+       ret = open(buf, flags, mode);
+       if (ret < 0) {
+               if (errno == ENOENT)
+                       die("kprobe_events file does not exist -"
+                           " please rebuild with CONFIG_KPROBE_TRACER.");
+               else
+                       die("Could not open kprobe_events file: %s",
+                           strerror(errno));
+       }
+       return ret;
+}
+
+/* Get raw string list of current kprobe_events */
+static struct strlist *get_trace_kprobe_event_rawlist(int fd)
+{
+       int ret, idx;
+       FILE *fp;
+       char buf[MAX_CMDLEN];
+       char *p;
+       struct strlist *sl;
+
+       sl = strlist__new(true, NULL);
+
+       fp = fdopen(dup(fd), "r");
+       while (!feof(fp)) {
+               p = fgets(buf, MAX_CMDLEN, fp);
+               if (!p)
+                       break;
+
+               idx = strlen(p) - 1;
+               if (p[idx] == '\n')
+                       p[idx] = '\0';
+               ret = strlist__add(sl, buf);
+               if (ret < 0)
+                       die("strlist__add failed: %s", strerror(-ret));
+       }
+       fclose(fp);
+
+       return sl;
+}
+
+/* Free and zero clear probe_point */
+static void clear_probe_point(struct probe_point *pp)
+{
+       int i;
+
+       if (pp->function)
+               free(pp->function);
+       if (pp->file)
+               free(pp->file);
+       for (i = 0; i < pp->nr_args; i++)
+               free(pp->args[i]);
+       if (pp->args)
+               free(pp->args);
+       for (i = 0; i < pp->found; i++)
+               free(pp->probes[i]);
+       memset(pp, 0, sizeof(pp));
+}
+
+/* List up current perf-probe events */
+void show_perf_probe_events(void)
+{
+       unsigned int i;
+       int fd;
+       char *group, *event;
+       struct probe_point pp;
+       struct strlist *rawlist;
+       struct str_node *ent;
+
+       fd = open_kprobe_events(O_RDONLY, 0);
+       rawlist = get_trace_kprobe_event_rawlist(fd);
+       close(fd);
+
+       for (i = 0; i < strlist__nr_entries(rawlist); i++) {
+               ent = strlist__entry(rawlist, i);
+               parse_trace_kprobe_event(ent->s, &group, &event, &pp);
+               synthesize_perf_probe_event(&pp);
+               printf("[%s:%s]\t%s\n", group, event, pp.probes[0]);
+               free(group);
+               free(event);
+               clear_probe_point(&pp);
+       }
+
+       strlist__delete(rawlist);
+}
+
+/* Get current perf-probe event names */
+static struct strlist *get_perf_event_names(int fd)
+{
+       unsigned int i;
+       char *group, *event;
+       struct strlist *sl, *rawlist;
+       struct str_node *ent;
+
+       rawlist = get_trace_kprobe_event_rawlist(fd);
+
+       sl = strlist__new(false, NULL);
+       for (i = 0; i < strlist__nr_entries(rawlist); i++) {
+               ent = strlist__entry(rawlist, i);
+               parse_trace_kprobe_event(ent->s, &group, &event, NULL);
+               strlist__add(sl, event);
+               free(group);
+       }
+
+       strlist__delete(rawlist);
+
+       return sl;
+}
+
+static int write_trace_kprobe_event(int fd, const char *buf)
+{
+       int ret;
+
+       ret = write(fd, buf, strlen(buf));
+       if (ret <= 0)
+               die("Failed to create event.");
+       else
+               printf("Added new event: %s\n", buf);
+
+       return ret;
+}
+
+static void get_new_event_name(char *buf, size_t len, const char *base,
+                              struct strlist *namelist)
+{
+       int i, ret;
+       for (i = 0; i < MAX_EVENT_INDEX; i++) {
+               ret = e_snprintf(buf, len, "%s_%d", base, i);
+               if (ret < 0)
+                       die("snprintf() failed: %s", strerror(-ret));
+               if (!strlist__has_entry(namelist, buf))
+                       break;
+       }
+       if (i == MAX_EVENT_INDEX)
+               die("Too many events are on the same function.");
+}
+
+void add_trace_kprobe_events(struct probe_point *probes, int nr_probes)
+{
+       int i, j, fd;
+       struct probe_point *pp;
+       char buf[MAX_CMDLEN];
+       char event[64];
+       struct strlist *namelist;
+
+       fd = open_kprobe_events(O_RDWR, O_APPEND);
+       /* Get current event names */
+       namelist = get_perf_event_names(fd);
+
+       for (j = 0; j < nr_probes; j++) {
+               pp = probes + j;
+               for (i = 0; i < pp->found; i++) {
+                       /* Get an unused new event name */
+                       get_new_event_name(event, 64, pp->function, namelist);
+                       snprintf(buf, MAX_CMDLEN, "%c:%s/%s %s\n",
+                                pp->retprobe ? 'r' : 'p',
+                                PERFPROBE_GROUP, event,
+                                pp->probes[i]);
+                       write_trace_kprobe_event(fd, buf);
+                       /* Add added event name to namelist */
+                       strlist__add(namelist, event);
+               }
+       }
+       close(fd);
+}
diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h
new file mode 100644 (file)
index 0000000..0c6fe56
--- /dev/null
@@ -0,0 +1,18 @@
+#ifndef _PROBE_EVENT_H
+#define _PROBE_EVENT_H
+
+#include "probe-finder.h"
+#include "strlist.h"
+
+extern int parse_perf_probe_event(const char *str, struct probe_point *pp);
+extern int synthesize_perf_probe_event(struct probe_point *pp);
+extern void parse_trace_kprobe_event(const char *str, char **group,
+                                    char **event, struct probe_point *pp);
+extern int synthesize_trace_kprobe_event(struct probe_point *pp);
+extern void add_trace_kprobe_events(struct probe_point *probes, int nr_probes);
+extern void show_perf_probe_events(void);
+
+/* Maximum index number of event-name postfix */
+#define MAX_EVENT_INDEX        1024
+
+#endif /*_PROBE_EVENT_H */
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
new file mode 100644 (file)
index 0000000..293cdfc
--- /dev/null
@@ -0,0 +1,732 @@
+/*
+ * probe-finder.c : C expression to kprobe event converter
+ *
+ * Written by Masami Hiramatsu <mhiramat@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 <sys/utsname.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <ctype.h>
+
+#include "event.h"
+#include "debug.h"
+#include "util.h"
+#include "probe-finder.h"
+
+
+/* Dwarf_Die Linkage to parent Die */
+struct die_link {
+       struct die_link *parent;        /* Parent die */
+       Dwarf_Die die;                  /* Current die */
+};
+
+static Dwarf_Debug __dw_debug;
+static Dwarf_Error __dw_error;
+
+/*
+ * Generic dwarf analysis helpers
+ */
+
+#define X86_32_MAX_REGS 8
+const char *x86_32_regs_table[X86_32_MAX_REGS] = {
+       "%ax",
+       "%cx",
+       "%dx",
+       "%bx",
+       "$stack",       /* Stack address instead of %sp */
+       "%bp",
+       "%si",
+       "%di",
+};
+
+#define X86_64_MAX_REGS 16
+const char *x86_64_regs_table[X86_64_MAX_REGS] = {
+       "%ax",
+       "%dx",
+       "%cx",
+       "%bx",
+       "%si",
+       "%di",
+       "%bp",
+       "%sp",
+       "%r8",
+       "%r9",
+       "%r10",
+       "%r11",
+       "%r12",
+       "%r13",
+       "%r14",
+       "%r15",
+};
+
+/* TODO: switching by dwarf address size */
+#ifdef __x86_64__
+#define ARCH_MAX_REGS X86_64_MAX_REGS
+#define arch_regs_table x86_64_regs_table
+#else
+#define ARCH_MAX_REGS X86_32_MAX_REGS
+#define arch_regs_table x86_32_regs_table
+#endif
+
+/* Return architecture dependent register string (for kprobe-tracer) */
+static const char *get_arch_regstr(unsigned int n)
+{
+       return (n <= ARCH_MAX_REGS) ? arch_regs_table[n] : NULL;
+}
+
+/*
+ * Compare the tail of two strings.
+ * Return 0 if whole of either string is same as another's tail part.
+ */
+static int strtailcmp(const char *s1, const char *s2)
+{
+       int i1 = strlen(s1);
+       int i2 = strlen(s2);
+       while (--i1 > 0 && --i2 > 0) {
+               if (s1[i1] != s2[i2])
+                       return s1[i1] - s2[i2];
+       }
+       return 0;
+}
+
+/* Find the fileno of the target file. */
+static Dwarf_Unsigned cu_find_fileno(Dwarf_Die cu_die, const char *fname)
+{
+       Dwarf_Signed cnt, i;
+       Dwarf_Unsigned found = 0;
+       char **srcs;
+       int ret;
+
+       if (!fname)
+               return 0;
+
+       ret = dwarf_srcfiles(cu_die, &srcs, &cnt, &__dw_error);
+       if (ret == DW_DLV_OK) {
+               for (i = 0; i < cnt && !found; i++) {
+                       if (strtailcmp(srcs[i], fname) == 0)
+                               found = i + 1;
+                       dwarf_dealloc(__dw_debug, srcs[i], DW_DLA_STRING);
+               }
+               for (; i < cnt; i++)
+                       dwarf_dealloc(__dw_debug, srcs[i], DW_DLA_STRING);
+               dwarf_dealloc(__dw_debug, srcs, DW_DLA_LIST);
+       }
+       if (found)
+               pr_debug("found fno: %d\n", (int)found);
+       return found;
+}
+
+/* Compare diename and tname */
+static int die_compare_name(Dwarf_Die dw_die, const char *tname)
+{
+       char *name;
+       int ret;
+       ret = dwarf_diename(dw_die, &name, &__dw_error);
+       DIE_IF(ret == DW_DLV_ERROR);
+       if (ret == DW_DLV_OK) {
+               ret = strcmp(tname, name);
+               dwarf_dealloc(__dw_debug, name, DW_DLA_STRING);
+       } else
+               ret = -1;
+       return ret;
+}
+
+/* Check the address is in the subprogram(function). */
+static int die_within_subprogram(Dwarf_Die sp_die, Dwarf_Addr addr,
+                                Dwarf_Signed *offs)
+{
+       Dwarf_Addr lopc, hipc;
+       int ret;
+
+       /* TODO: check ranges */
+       ret = dwarf_lowpc(sp_die, &lopc, &__dw_error);
+       DIE_IF(ret == DW_DLV_ERROR);
+       if (ret == DW_DLV_NO_ENTRY)
+               return 0;
+       ret = dwarf_highpc(sp_die, &hipc, &__dw_error);
+       DIE_IF(ret != DW_DLV_OK);
+       if (lopc <= addr && addr < hipc) {
+               *offs = addr - lopc;
+               return 1;
+       } else
+               return 0;
+}
+
+/* Check the die is inlined function */
+static Dwarf_Bool die_inlined_subprogram(Dwarf_Die dw_die)
+{
+       /* TODO: check strictly */
+       Dwarf_Bool inl;
+       int ret;
+
+       ret = dwarf_hasattr(dw_die, DW_AT_inline, &inl, &__dw_error);
+       DIE_IF(ret == DW_DLV_ERROR);
+       return inl;
+}
+
+/* Get the offset of abstruct_origin */
+static Dwarf_Off die_get_abstract_origin(Dwarf_Die dw_die)
+{
+       Dwarf_Attribute attr;
+       Dwarf_Off cu_offs;
+       int ret;
+
+       ret = dwarf_attr(dw_die, DW_AT_abstract_origin, &attr, &__dw_error);
+       DIE_IF(ret != DW_DLV_OK);
+       ret = dwarf_formref(attr, &cu_offs, &__dw_error);
+       DIE_IF(ret != DW_DLV_OK);
+       dwarf_dealloc(__dw_debug, attr, DW_DLA_ATTR);
+       return cu_offs;
+}
+
+/* Get entry pc(or low pc, 1st entry of ranges)  of the die */
+static Dwarf_Addr die_get_entrypc(Dwarf_Die dw_die)
+{
+       Dwarf_Attribute attr;
+       Dwarf_Addr addr;
+       Dwarf_Off offs;
+       Dwarf_Ranges *ranges;
+       Dwarf_Signed cnt;
+       int ret;
+
+       /* Try to get entry pc */
+       ret = dwarf_attr(dw_die, DW_AT_entry_pc, &attr, &__dw_error);
+       DIE_IF(ret == DW_DLV_ERROR);
+       if (ret == DW_DLV_OK) {
+               ret = dwarf_formaddr(attr, &addr, &__dw_error);
+               DIE_IF(ret != DW_DLV_OK);
+               dwarf_dealloc(__dw_debug, attr, DW_DLA_ATTR);
+               return addr;
+       }
+
+       /* Try to get low pc */
+       ret = dwarf_lowpc(dw_die, &addr, &__dw_error);
+       DIE_IF(ret == DW_DLV_ERROR);
+       if (ret == DW_DLV_OK)
+               return addr;
+
+       /* Try to get ranges */
+       ret = dwarf_attr(dw_die, DW_AT_ranges, &attr, &__dw_error);
+       DIE_IF(ret != DW_DLV_OK);
+       ret = dwarf_formref(attr, &offs, &__dw_error);
+       DIE_IF(ret != DW_DLV_OK);
+       ret = dwarf_get_ranges(__dw_debug, offs, &ranges, &cnt, NULL,
+                               &__dw_error);
+       DIE_IF(ret != DW_DLV_OK);
+       addr = ranges[0].dwr_addr1;
+       dwarf_ranges_dealloc(__dw_debug, ranges, cnt);
+       return addr;
+}
+
+/*
+ * Search a Die from Die tree.
+ * Note: cur_link->die should be deallocated in this function.
+ */
+static int __search_die_tree(struct die_link *cur_link,
+                            int (*die_cb)(struct die_link *, void *),
+                            void *data)
+{
+       Dwarf_Die new_die;
+       struct die_link new_link;
+       int ret;
+
+       if (!die_cb)
+               return 0;
+
+       /* Check current die */
+       while (!(ret = die_cb(cur_link, data))) {
+               /* Check child die */
+               ret = dwarf_child(cur_link->die, &new_die, &__dw_error);
+               DIE_IF(ret == DW_DLV_ERROR);
+               if (ret == DW_DLV_OK) {
+                       new_link.parent = cur_link;
+                       new_link.die = new_die;
+                       ret = __search_die_tree(&new_link, die_cb, data);
+                       if (ret)
+                               break;
+               }
+
+               /* Move to next sibling */
+               ret = dwarf_siblingof(__dw_debug, cur_link->die, &new_die,
+                                     &__dw_error);
+               DIE_IF(ret == DW_DLV_ERROR);
+               dwarf_dealloc(__dw_debug, cur_link->die, DW_DLA_DIE);
+               cur_link->die = new_die;
+               if (ret == DW_DLV_NO_ENTRY)
+                       return 0;
+       }
+       dwarf_dealloc(__dw_debug, cur_link->die, DW_DLA_DIE);
+       return ret;
+}
+
+/* Search a die in its children's die tree */
+static int search_die_from_children(Dwarf_Die parent_die,
+                                   int (*die_cb)(struct die_link *, void *),
+                                   void *data)
+{
+       struct die_link new_link;
+       int ret;
+
+       new_link.parent = NULL;
+       ret = dwarf_child(parent_die, &new_link.die, &__dw_error);
+       DIE_IF(ret == DW_DLV_ERROR);
+       if (ret == DW_DLV_OK)
+               return __search_die_tree(&new_link, die_cb, data);
+       else
+               return 0;
+}
+
+/* Find a locdesc corresponding to the address */
+static int attr_get_locdesc(Dwarf_Attribute attr, Dwarf_Locdesc *desc,
+                           Dwarf_Addr addr)
+{
+       Dwarf_Signed lcnt;
+       Dwarf_Locdesc **llbuf;
+       int ret, i;
+
+       ret = dwarf_loclist_n(attr, &llbuf, &lcnt, &__dw_error);
+       DIE_IF(ret != DW_DLV_OK);
+       ret = DW_DLV_NO_ENTRY;
+       for (i = 0; i < lcnt; ++i) {
+               if (llbuf[i]->ld_lopc <= addr &&
+                   llbuf[i]->ld_hipc > addr) {
+                       memcpy(desc, llbuf[i], sizeof(Dwarf_Locdesc));
+                       desc->ld_s =
+                               malloc(sizeof(Dwarf_Loc) * llbuf[i]->ld_cents);
+                       DIE_IF(desc->ld_s == NULL);
+                       memcpy(desc->ld_s, llbuf[i]->ld_s,
+                               sizeof(Dwarf_Loc) * llbuf[i]->ld_cents);
+                       ret = DW_DLV_OK;
+                       break;
+               }
+               dwarf_dealloc(__dw_debug, llbuf[i]->ld_s, DW_DLA_LOC_BLOCK);
+               dwarf_dealloc(__dw_debug, llbuf[i], DW_DLA_LOCDESC);
+       }
+       /* Releasing loop */
+       for (; i < lcnt; ++i) {
+               dwarf_dealloc(__dw_debug, llbuf[i]->ld_s, DW_DLA_LOC_BLOCK);
+               dwarf_dealloc(__dw_debug, llbuf[i], DW_DLA_LOCDESC);
+       }
+       dwarf_dealloc(__dw_debug, llbuf, DW_DLA_LIST);
+       return ret;
+}
+
+/* Get decl_file attribute value (file number) */
+static Dwarf_Unsigned die_get_decl_file(Dwarf_Die sp_die)
+{
+       Dwarf_Attribute attr;
+       Dwarf_Unsigned fno;
+       int ret;
+
+       ret = dwarf_attr(sp_die, DW_AT_decl_file, &attr, &__dw_error);
+       DIE_IF(ret != DW_DLV_OK);
+       dwarf_formudata(attr, &fno, &__dw_error);
+       DIE_IF(ret != DW_DLV_OK);
+       dwarf_dealloc(__dw_debug, attr, DW_DLA_ATTR);
+       return fno;
+}
+
+/* Get decl_line attribute value (line number) */
+static Dwarf_Unsigned die_get_decl_line(Dwarf_Die sp_die)
+{
+       Dwarf_Attribute attr;
+       Dwarf_Unsigned lno;
+       int ret;
+
+       ret = dwarf_attr(sp_die, DW_AT_decl_line, &attr, &__dw_error);
+       DIE_IF(ret != DW_DLV_OK);
+       dwarf_formudata(attr, &lno, &__dw_error);
+       DIE_IF(ret != DW_DLV_OK);
+       dwarf_dealloc(__dw_debug, attr, DW_DLA_ATTR);
+       return lno;
+}
+
+/*
+ * Probe finder related functions
+ */
+
+/* Show a location */
+static void show_location(Dwarf_Loc *loc, struct probe_finder *pf)
+{
+       Dwarf_Small op;
+       Dwarf_Unsigned regn;
+       Dwarf_Signed offs;
+       int deref = 0, ret;
+       const char *regs;
+
+       op = loc->lr_atom;
+
+       /* If this is based on frame buffer, set the offset */
+       if (op == DW_OP_fbreg) {
+               deref = 1;
+               offs = (Dwarf_Signed)loc->lr_number;
+               op = pf->fbloc.ld_s[0].lr_atom;
+               loc = &pf->fbloc.ld_s[0];
+       } else
+               offs = 0;
+
+       if (op >= DW_OP_breg0 && op <= DW_OP_breg31) {
+               regn = op - DW_OP_breg0;
+               offs += (Dwarf_Signed)loc->lr_number;
+               deref = 1;
+       } else if (op >= DW_OP_reg0 && op <= DW_OP_reg31) {
+               regn = op - DW_OP_reg0;
+       } else if (op == DW_OP_bregx) {
+               regn = loc->lr_number;
+               offs += (Dwarf_Signed)loc->lr_number2;
+               deref = 1;
+       } else if (op == DW_OP_regx) {
+               regn = loc->lr_number;
+       } else
+               die("Dwarf_OP %d is not supported.\n", op);
+
+       regs = get_arch_regstr(regn);
+       if (!regs)
+               die("%lld exceeds max register number.\n", regn);
+
+       if (deref)
+               ret = snprintf(pf->buf, pf->len,
+                                " %s=%+lld(%s)", pf->var, offs, regs);
+       else
+               ret = snprintf(pf->buf, pf->len, " %s=%s", pf->var, regs);
+       DIE_IF(ret < 0);
+       DIE_IF(ret >= pf->len);
+}
+
+/* Show a variables in kprobe event format */
+static void show_variable(Dwarf_Die vr_die, struct probe_finder *pf)
+{
+       Dwarf_Attribute attr;
+       Dwarf_Locdesc ld;
+       int ret;
+
+       ret = dwarf_attr(vr_die, DW_AT_location, &attr, &__dw_error);
+       if (ret != DW_DLV_OK)
+               goto error;
+       ret = attr_get_locdesc(attr, &ld, (pf->addr - pf->cu_base));
+       if (ret != DW_DLV_OK)
+               goto error;
+       /* TODO? */
+       DIE_IF(ld.ld_cents != 1);
+       show_location(&ld.ld_s[0], pf);
+       free(ld.ld_s);
+       dwarf_dealloc(__dw_debug, attr, DW_DLA_ATTR);
+       return ;
+error:
+       die("Failed to find the location of %s at this address.\n"
+           " Perhaps, it has been optimized out.\n", pf->var);
+}
+
+static int variable_callback(struct die_link *dlink, void *data)
+{
+       struct probe_finder *pf = (struct probe_finder *)data;
+       Dwarf_Half tag;
+       int ret;
+
+       ret = dwarf_tag(dlink->die, &tag, &__dw_error);
+       DIE_IF(ret == DW_DLV_ERROR);
+       if ((tag == DW_TAG_formal_parameter ||
+            tag == DW_TAG_variable) &&
+           (die_compare_name(dlink->die, pf->var) == 0)) {
+               show_variable(dlink->die, pf);
+               return 1;
+       }
+       /* TODO: Support struct members and arrays */
+       return 0;
+}
+
+/* Find a variable in a subprogram die */
+static void find_variable(Dwarf_Die sp_die, struct probe_finder *pf)
+{
+       int ret;
+
+       if (!is_c_varname(pf->var)) {
+               /* Output raw parameters */
+               ret = snprintf(pf->buf, pf->len, " %s", pf->var);
+               DIE_IF(ret < 0);
+               DIE_IF(ret >= pf->len);
+               return ;
+       }
+
+       pr_debug("Searching '%s' variable in context.\n", pf->var);
+       /* Search child die for local variables and parameters. */
+       ret = search_die_from_children(sp_die, variable_callback, pf);
+       if (!ret)
+               die("Failed to find '%s' in this function.\n", pf->var);
+}
+
+/* Get a frame base on the address */
+static void get_current_frame_base(Dwarf_Die sp_die, struct probe_finder *pf)
+{
+       Dwarf_Attribute attr;
+       int ret;
+
+       ret = dwarf_attr(sp_die, DW_AT_frame_base, &attr, &__dw_error);
+       DIE_IF(ret != DW_DLV_OK);
+       ret = attr_get_locdesc(attr, &pf->fbloc, (pf->addr - pf->cu_base));
+       DIE_IF(ret != DW_DLV_OK);
+       dwarf_dealloc(__dw_debug, attr, DW_DLA_ATTR);
+}
+
+static void free_current_frame_base(struct probe_finder *pf)
+{
+       free(pf->fbloc.ld_s);
+       memset(&pf->fbloc, 0, sizeof(Dwarf_Locdesc));
+}
+
+/* Show a probe point to output buffer */
+static void show_probepoint(Dwarf_Die sp_die, Dwarf_Signed offs,
+                           struct probe_finder *pf)
+{
+       struct probe_point *pp = pf->pp;
+       char *name;
+       char tmp[MAX_PROBE_BUFFER];
+       int ret, i, len;
+
+       /* Output name of probe point */
+       ret = dwarf_diename(sp_die, &name, &__dw_error);
+       DIE_IF(ret == DW_DLV_ERROR);
+       if (ret == DW_DLV_OK) {
+               ret = snprintf(tmp, MAX_PROBE_BUFFER, "%s+%u", name,
+                               (unsigned int)offs);
+               /* Copy the function name if possible */
+               if (!pp->function) {
+                       pp->function = strdup(name);
+                       pp->offset = offs;
+               }
+               dwarf_dealloc(__dw_debug, name, DW_DLA_STRING);
+       } else {
+               /* This function has no name. */
+               ret = snprintf(tmp, MAX_PROBE_BUFFER, "0x%llx", pf->addr);
+               if (!pp->function) {
+                       /* TODO: Use _stext */
+                       pp->function = strdup("");
+                       pp->offset = (int)pf->addr;
+               }
+       }
+       DIE_IF(ret < 0);
+       DIE_IF(ret >= MAX_PROBE_BUFFER);
+       len = ret;
+       pr_debug("Probe point found: %s\n", tmp);
+
+       /* Find each argument */
+       get_current_frame_base(sp_die, pf);
+       for (i = 0; i < pp->nr_args; i++) {
+               pf->var = pp->args[i];
+               pf->buf = &tmp[len];
+               pf->len = MAX_PROBE_BUFFER - len;
+               find_variable(sp_die, pf);
+               len += strlen(pf->buf);
+       }
+       free_current_frame_base(pf);
+
+       pp->probes[pp->found] = strdup(tmp);
+       pp->found++;
+}
+
+static int probeaddr_callback(struct die_link *dlink, void *data)
+{
+       struct probe_finder *pf = (struct probe_finder *)data;
+       Dwarf_Half tag;
+       Dwarf_Signed offs;
+       int ret;
+
+       ret = dwarf_tag(dlink->die, &tag, &__dw_error);
+       DIE_IF(ret == DW_DLV_ERROR);
+       /* Check the address is in this subprogram */
+       if (tag == DW_TAG_subprogram &&
+           die_within_subprogram(dlink->die, pf->addr, &offs)) {
+               show_probepoint(dlink->die, offs, pf);
+               return 1;
+       }
+       return 0;
+}
+
+/* Find probe point from its line number */
+static void find_by_line(struct probe_finder *pf)
+{
+       Dwarf_Signed cnt, i, clm;
+       Dwarf_Line *lines;
+       Dwarf_Unsigned lineno = 0;
+       Dwarf_Addr addr;
+       Dwarf_Unsigned fno;
+       int ret;
+
+       ret = dwarf_srclines(pf->cu_die, &lines, &cnt, &__dw_error);
+       DIE_IF(ret != DW_DLV_OK);
+
+       for (i = 0; i < cnt; i++) {
+               ret = dwarf_line_srcfileno(lines[i], &fno, &__dw_error);
+               DIE_IF(ret != DW_DLV_OK);
+               if (fno != pf->fno)
+                       continue;
+
+               ret = dwarf_lineno(lines[i], &lineno, &__dw_error);
+               DIE_IF(ret != DW_DLV_OK);
+               if (lineno != pf->lno)
+                       continue;
+
+               ret = dwarf_lineoff(lines[i], &clm, &__dw_error);
+               DIE_IF(ret != DW_DLV_OK);
+
+               ret = dwarf_lineaddr(lines[i], &addr, &__dw_error);
+               DIE_IF(ret != DW_DLV_OK);
+               pr_debug("Probe line found: line[%d]:%u,%d addr:0x%llx\n",
+                        (int)i, (unsigned)lineno, (int)clm, addr);
+               pf->addr = addr;
+               /* Search a real subprogram including this line, */
+               ret = search_die_from_children(pf->cu_die,
+                                              probeaddr_callback, pf);
+               if (ret == 0)
+                       die("Probe point is not found in subprograms.\n");
+               /* Continuing, because target line might be inlined. */
+       }
+       dwarf_srclines_dealloc(__dw_debug, lines, cnt);
+}
+
+/* Search function from function name */
+static int probefunc_callback(struct die_link *dlink, void *data)
+{
+       struct probe_finder *pf = (struct probe_finder *)data;
+       struct probe_point *pp = pf->pp;
+       struct die_link *lk;
+       Dwarf_Signed offs;
+       Dwarf_Half tag;
+       int ret;
+
+       ret = dwarf_tag(dlink->die, &tag, &__dw_error);
+       DIE_IF(ret == DW_DLV_ERROR);
+       if (tag == DW_TAG_subprogram) {
+               if (die_compare_name(dlink->die, pp->function) == 0) {
+                       if (pp->line) { /* Function relative line */
+                               pf->fno = die_get_decl_file(dlink->die);
+                               pf->lno = die_get_decl_line(dlink->die)
+                                        + pp->line;
+                               find_by_line(pf);
+                               return 1;
+                       }
+                       if (die_inlined_subprogram(dlink->die)) {
+                               /* Inlined function, save it. */
+                               ret = dwarf_die_CU_offset(dlink->die,
+                                                         &pf->inl_offs,
+                                                         &__dw_error);
+                               DIE_IF(ret != DW_DLV_OK);
+                               pr_debug("inline definition offset %lld\n",
+                                        pf->inl_offs);
+                               return 0;       /* Continue to search */
+                       }
+                       /* Get probe address */
+                       pf->addr = die_get_entrypc(dlink->die);
+                       pf->addr += pp->offset;
+                       /* TODO: Check the address in this function */
+                       show_probepoint(dlink->die, pp->offset, pf);
+                       return 1; /* Exit; no same symbol in this CU. */
+               }
+       } else if (tag == DW_TAG_inlined_subroutine && pf->inl_offs) {
+               if (die_get_abstract_origin(dlink->die) == pf->inl_offs) {
+                       /* Get probe address */
+                       pf->addr = die_get_entrypc(dlink->die);
+                       pf->addr += pp->offset;
+                       pr_debug("found inline addr: 0x%llx\n", pf->addr);
+                       /* Inlined function. Get a real subprogram */
+                       for (lk = dlink->parent; lk != NULL; lk = lk->parent) {
+                               tag = 0;
+                               dwarf_tag(lk->die, &tag, &__dw_error);
+                               DIE_IF(ret == DW_DLV_ERROR);
+                               if (tag == DW_TAG_subprogram &&
+                                   !die_inlined_subprogram(lk->die))
+                                       goto found;
+                       }
+                       die("Failed to find real subprogram.\n");
+found:
+                       /* Get offset from subprogram */
+                       ret = die_within_subprogram(lk->die, pf->addr, &offs);
+                       DIE_IF(!ret);
+                       show_probepoint(lk->die, offs, pf);
+                       /* Continue to search */
+               }
+       }
+       return 0;
+}
+
+static void find_by_func(struct probe_finder *pf)
+{
+       search_die_from_children(pf->cu_die, probefunc_callback, pf);
+}
+
+/* Find a probe point */
+int find_probepoint(int fd, struct probe_point *pp)
+{
+       Dwarf_Half addr_size = 0;
+       Dwarf_Unsigned next_cuh = 0;
+       int cu_number = 0, ret;
+       struct probe_finder pf = {.pp = pp};
+
+       ret = dwarf_init(fd, DW_DLC_READ, 0, 0, &__dw_debug, &__dw_error);
+       if (ret != DW_DLV_OK) {
+               pr_warning("No dwarf info found in the vmlinux - please rebuild with CONFIG_DEBUG_INFO.\n");
+               return -ENOENT;
+       }
+
+       pp->found = 0;
+       while (++cu_number) {
+               /* Search CU (Compilation Unit) */
+               ret = dwarf_next_cu_header(__dw_debug, NULL, NULL, NULL,
+                       &addr_size, &next_cuh, &__dw_error);
+               DIE_IF(ret == DW_DLV_ERROR);
+               if (ret == DW_DLV_NO_ENTRY)
+                       break;
+
+               /* Get the DIE(Debugging Information Entry) of this CU */
+               ret = dwarf_siblingof(__dw_debug, 0, &pf.cu_die, &__dw_error);
+               DIE_IF(ret != DW_DLV_OK);
+
+               /* Check if target file is included. */
+               if (pp->file)
+                       pf.fno = cu_find_fileno(pf.cu_die, pp->file);
+
+               if (!pp->file || pf.fno) {
+                       /* Save CU base address (for frame_base) */
+                       ret = dwarf_lowpc(pf.cu_die, &pf.cu_base, &__dw_error);
+                       DIE_IF(ret == DW_DLV_ERROR);
+                       if (ret == DW_DLV_NO_ENTRY)
+                               pf.cu_base = 0;
+                       if (pp->function)
+                               find_by_func(&pf);
+                       else {
+                               pf.lno = pp->line;
+                               find_by_line(&pf);
+                       }
+               }
+               dwarf_dealloc(__dw_debug, pf.cu_die, DW_DLA_DIE);
+       }
+       ret = dwarf_finish(__dw_debug, &__dw_error);
+       DIE_IF(ret != DW_DLV_OK);
+
+       return pp->found;
+}
+
diff --git a/tools/perf/util/probe-finder.h b/tools/perf/util/probe-finder.h
new file mode 100644 (file)
index 0000000..bdebca6
--- /dev/null
@@ -0,0 +1,57 @@
+#ifndef _PROBE_FINDER_H
+#define _PROBE_FINDER_H
+
+#define MAX_PATH_LEN 256
+#define MAX_PROBE_BUFFER 1024
+#define MAX_PROBES 128
+
+static inline int is_c_varname(const char *name)
+{
+       /* TODO */
+       return isalpha(name[0]) || name[0] == '_';
+}
+
+struct probe_point {
+       /* Inputs */
+       char    *file;          /* File name */
+       int     line;           /* Line number */
+
+       char    *function;      /* Function name */
+       int     offset;         /* Offset bytes */
+
+       int     nr_args;        /* Number of arguments */
+       char    **args;         /* Arguments */
+
+       int     retprobe;       /* Return probe */
+
+       /* Output */
+       int     found;          /* Number of found probe points */
+       char    *probes[MAX_PROBES];    /* Output buffers (will be allocated)*/
+};
+
+#ifndef NO_LIBDWARF
+extern int find_probepoint(int fd, struct probe_point *pp);
+
+#include <libdwarf/dwarf.h>
+#include <libdwarf/libdwarf.h>
+
+struct probe_finder {
+       struct probe_point      *pp;    /* Target probe point */
+
+       /* For function searching */
+       Dwarf_Addr      addr;           /* Address */
+       Dwarf_Unsigned  fno;            /* File number */
+       Dwarf_Unsigned  lno;            /* Line number */
+       Dwarf_Off       inl_offs;       /* Inline offset */
+       Dwarf_Die       cu_die;         /* Current CU */
+
+       /* For variable searching */
+       Dwarf_Addr      cu_base;        /* Current CU base address */
+       Dwarf_Locdesc   fbloc;          /* Location of Current Frame Base */
+       const char      *var;           /* Current variable name */
+       char            *buf;           /* Current output buffer */
+       int             len;            /* Length of output buffer */
+};
+#endif /* NO_LIBDWARF */
+
+#endif /*_PROBE_FINDER_H */
index a5454a1..b6a0197 100644 (file)
@@ -1,5 +1,5 @@
-#ifndef QUOTE_H
-#define QUOTE_H
+#ifndef __PERF_QUOTE_H
+#define __PERF_QUOTE_H
 
 #include <stddef.h>
 #include <stdio.h>
@@ -65,4 +65,4 @@ extern void perl_quote_print(FILE *stream, const char *src);
 extern void python_quote_print(FILE *stream, const char *src);
 extern void tcl_quote_print(FILE *stream, const char *src);
 
-#endif
+#endif /* __PERF_QUOTE_H */
index cc1837d..d790287 100644 (file)
@@ -1,5 +1,5 @@
-#ifndef RUN_COMMAND_H
-#define RUN_COMMAND_H
+#ifndef __PERF_RUN_COMMAND_H
+#define __PERF_RUN_COMMAND_H
 
 enum {
        ERR_RUN_COMMAND_FORK = 10000,
@@ -85,4 +85,4 @@ struct async {
 int start_async(struct async *async);
 int finish_async(struct async *async);
 
-#endif
+#endif /* __PERF_RUN_COMMAND_H */
index 618083b..1a53c11 100644 (file)
@@ -1,5 +1,5 @@
-#ifndef SIGCHAIN_H
-#define SIGCHAIN_H
+#ifndef __PERF_SIGCHAIN_H
+#define __PERF_SIGCHAIN_H
 
 typedef void (*sigchain_fun)(int);
 
@@ -8,4 +8,4 @@ int sigchain_pop(int sig);
 
 void sigchain_push_common(sigchain_fun f);
 
-#endif /* SIGCHAIN_H */
+#endif /* __PERF_SIGCHAIN_H */
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c
new file mode 100644 (file)
index 0000000..b490354
--- /dev/null
@@ -0,0 +1,290 @@
+#include "sort.h"
+
+regex_t                parent_regex;
+char           default_parent_pattern[] = "^sys_|^do_page_fault";
+char           *parent_pattern = default_parent_pattern;
+char           default_sort_order[] = "comm,dso,symbol";
+char           *sort_order = default_sort_order;
+int            sort__need_collapse = 0;
+int            sort__has_parent = 0;
+
+enum sort_type sort__first_dimension;
+
+unsigned int dsos__col_width;
+unsigned int comms__col_width;
+unsigned int threads__col_width;
+static unsigned int parent_symbol__col_width;
+char * field_sep;
+
+LIST_HEAD(hist_entry__sort_list);
+
+struct sort_entry sort_thread = {
+       .header = "Command:  Pid",
+       .cmp    = sort__thread_cmp,
+       .print  = sort__thread_print,
+       .width  = &threads__col_width,
+};
+
+struct sort_entry sort_comm = {
+       .header         = "Command",
+       .cmp            = sort__comm_cmp,
+       .collapse       = sort__comm_collapse,
+       .print          = sort__comm_print,
+       .width          = &comms__col_width,
+};
+
+struct sort_entry sort_dso = {
+       .header = "Shared Object",
+       .cmp    = sort__dso_cmp,
+       .print  = sort__dso_print,
+       .width  = &dsos__col_width,
+};
+
+struct sort_entry sort_sym = {
+       .header = "Symbol",
+       .cmp    = sort__sym_cmp,
+       .print  = sort__sym_print,
+};
+
+struct sort_entry sort_parent = {
+       .header = "Parent symbol",
+       .cmp    = sort__parent_cmp,
+       .print  = sort__parent_print,
+       .width  = &parent_symbol__col_width,
+};
+
+struct sort_dimension {
+       const char              *name;
+       struct sort_entry       *entry;
+       int                     taken;
+};
+
+static struct sort_dimension sort_dimensions[] = {
+       { .name = "pid",        .entry = &sort_thread,  },
+       { .name = "comm",       .entry = &sort_comm,    },
+       { .name = "dso",        .entry = &sort_dso,     },
+       { .name = "symbol",     .entry = &sort_sym,     },
+       { .name = "parent",     .entry = &sort_parent,  },
+};
+
+int64_t cmp_null(void *l, void *r)
+{
+       if (!l && !r)
+               return 0;
+       else if (!l)
+               return -1;
+       else
+               return 1;
+}
+
+/* --sort pid */
+
+int64_t
+sort__thread_cmp(struct hist_entry *left, struct hist_entry *right)
+{
+       return right->thread->pid - left->thread->pid;
+}
+
+int repsep_fprintf(FILE *fp, const char *fmt, ...)
+{
+       int n;
+       va_list ap;
+
+       va_start(ap, fmt);
+       if (!field_sep)
+               n = vfprintf(fp, fmt, ap);
+       else {
+               char *bf = NULL;
+               n = vasprintf(&bf, fmt, ap);
+               if (n > 0) {
+                       char *sep = bf;
+
+                       while (1) {
+                               sep = strchr(sep, *field_sep);
+                               if (sep == NULL)
+                                       break;
+                               *sep = '.';
+                       }
+               }
+               fputs(bf, fp);
+               free(bf);
+       }
+       va_end(ap);
+       return n;
+}
+
+size_t
+sort__thread_print(FILE *fp, struct hist_entry *self, unsigned int width)
+{
+       return repsep_fprintf(fp, "%*s:%5d", width - 6,
+                             self->thread->comm ?: "", self->thread->pid);
+}
+
+size_t
+sort__comm_print(FILE *fp, struct hist_entry *self, unsigned int width)
+{
+       return repsep_fprintf(fp, "%*s", width, self->thread->comm);
+}
+
+/* --sort dso */
+
+int64_t
+sort__dso_cmp(struct hist_entry *left, struct hist_entry *right)
+{
+       struct dso *dso_l = left->map ? left->map->dso : NULL;
+       struct dso *dso_r = right->map ? right->map->dso : NULL;
+       const char *dso_name_l, *dso_name_r;
+
+       if (!dso_l || !dso_r)
+               return cmp_null(dso_l, dso_r);
+
+       if (verbose) {
+               dso_name_l = dso_l->long_name;
+               dso_name_r = dso_r->long_name;
+       } else {
+               dso_name_l = dso_l->short_name;
+               dso_name_r = dso_r->short_name;
+       }
+
+       return strcmp(dso_name_l, dso_name_r);
+}
+
+size_t
+sort__dso_print(FILE *fp, struct hist_entry *self, unsigned int width)
+{
+       if (self->map && self->map->dso) {
+               const char *dso_name = !verbose ? self->map->dso->short_name :
+                                                 self->map->dso->long_name;
+               return repsep_fprintf(fp, "%-*s", width, dso_name);
+       }
+
+       return repsep_fprintf(fp, "%*llx", width, (u64)self->ip);
+}
+
+/* --sort symbol */
+
+int64_t
+sort__sym_cmp(struct hist_entry *left, struct hist_entry *right)
+{
+       u64 ip_l, ip_r;
+
+       if (left->sym == right->sym)
+               return 0;
+
+       ip_l = left->sym ? left->sym->start : left->ip;
+       ip_r = right->sym ? right->sym->start : right->ip;
+
+       return (int64_t)(ip_r - ip_l);
+}
+
+
+size_t
+sort__sym_print(FILE *fp, struct hist_entry *self, unsigned int width __used)
+{
+       size_t ret = 0;
+
+       if (verbose) {
+               char o = self->map ? dso__symtab_origin(self->map->dso) : '!';
+               ret += repsep_fprintf(fp, "%#018llx %c ", (u64)self->ip, o);
+       }
+
+       ret += repsep_fprintf(fp, "[%c] ", self->level);
+       if (self->sym)
+               ret += repsep_fprintf(fp, "%s", self->sym->name);
+       else
+               ret += repsep_fprintf(fp, "%#016llx", (u64)self->ip);
+
+       return ret;
+}
+
+/* --sort comm */
+
+int64_t
+sort__comm_cmp(struct hist_entry *left, struct hist_entry *right)
+{
+       return right->thread->pid - left->thread->pid;
+}
+
+int64_t
+sort__comm_collapse(struct hist_entry *left, struct hist_entry *right)
+{
+       char *comm_l = left->thread->comm;
+       char *comm_r = right->thread->comm;
+
+       if (!comm_l || !comm_r)
+               return cmp_null(comm_l, comm_r);
+
+       return strcmp(comm_l, comm_r);
+}
+
+/* --sort parent */
+
+int64_t
+sort__parent_cmp(struct hist_entry *left, struct hist_entry *right)
+{
+       struct symbol *sym_l = left->parent;
+       struct symbol *sym_r = right->parent;
+
+       if (!sym_l || !sym_r)
+               return cmp_null(sym_l, sym_r);
+
+       return strcmp(sym_l->name, sym_r->name);
+}
+
+size_t
+sort__parent_print(FILE *fp, struct hist_entry *self, unsigned int width)
+{
+       return repsep_fprintf(fp, "%-*s", width,
+                             self->parent ? self->parent->name : "[other]");
+}
+
+int sort_dimension__add(const char *tok)
+{
+       unsigned int i;
+
+       for (i = 0; i < ARRAY_SIZE(sort_dimensions); i++) {
+               struct sort_dimension *sd = &sort_dimensions[i];
+
+               if (sd->taken)
+                       continue;
+
+               if (strncasecmp(tok, sd->name, strlen(tok)))
+                       continue;
+
+               if (sd->entry->collapse)
+                       sort__need_collapse = 1;
+
+               if (sd->entry == &sort_parent) {
+                       int ret = regcomp(&parent_regex, parent_pattern, REG_EXTENDED);
+                       if (ret) {
+                               char err[BUFSIZ];
+
+                               regerror(ret, &parent_regex, err, sizeof(err));
+                               fprintf(stderr, "Invalid regex: %s\n%s",
+                                       parent_pattern, err);
+                               exit(-1);
+                       }
+                       sort__has_parent = 1;
+               }
+
+               if (list_empty(&hist_entry__sort_list)) {
+                       if (!strcmp(sd->name, "pid"))
+                               sort__first_dimension = SORT_PID;
+                       else if (!strcmp(sd->name, "comm"))
+                               sort__first_dimension = SORT_COMM;
+                       else if (!strcmp(sd->name, "dso"))
+                               sort__first_dimension = SORT_DSO;
+                       else if (!strcmp(sd->name, "symbol"))
+                               sort__first_dimension = SORT_SYM;
+                       else if (!strcmp(sd->name, "parent"))
+                               sort__first_dimension = SORT_PARENT;
+               }
+
+               list_add_tail(&sd->entry->list, &hist_entry__sort_list);
+               sd->taken = 1;
+
+               return 0;
+       }
+
+       return -ESRCH;
+}
diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h
new file mode 100644 (file)
index 0000000..333e664
--- /dev/null
@@ -0,0 +1,99 @@
+#ifndef __PERF_SORT_H
+#define __PERF_SORT_H
+#include "../builtin.h"
+
+#include "util.h"
+
+#include "color.h"
+#include <linux/list.h>
+#include "cache.h"
+#include <linux/rbtree.h>
+#include "symbol.h"
+#include "string.h"
+#include "callchain.h"
+#include "strlist.h"
+#include "values.h"
+
+#include "../perf.h"
+#include "debug.h"
+#include "header.h"
+
+#include "parse-options.h"
+#include "parse-events.h"
+
+#include "thread.h"
+#include "sort.h"
+
+extern regex_t parent_regex;
+extern char *sort_order;
+extern char default_parent_pattern[];
+extern char *parent_pattern;
+extern char default_sort_order[];
+extern int sort__need_collapse;
+extern int sort__has_parent;
+extern char *field_sep;
+extern struct sort_entry sort_comm;
+extern struct sort_entry sort_dso;
+extern struct sort_entry sort_sym;
+extern struct sort_entry sort_parent;
+extern unsigned int dsos__col_width;
+extern unsigned int comms__col_width;
+extern unsigned int threads__col_width;
+extern enum sort_type sort__first_dimension;
+
+struct hist_entry {
+       struct rb_node          rb_node;
+       u64                     count;
+       struct thread           *thread;
+       struct map              *map;
+       struct symbol           *sym;
+       u64                     ip;
+       char                    level;
+       struct symbol           *parent;
+       struct callchain_node   callchain;
+       struct rb_root          sorted_chain;
+};
+
+enum sort_type {
+       SORT_PID,
+       SORT_COMM,
+       SORT_DSO,
+       SORT_SYM,
+       SORT_PARENT
+};
+
+/*
+ * configurable sorting bits
+ */
+
+struct sort_entry {
+       struct list_head list;
+
+       const char *header;
+
+       int64_t (*cmp)(struct hist_entry *, struct hist_entry *);
+       int64_t (*collapse)(struct hist_entry *, struct hist_entry *);
+       size_t  (*print)(FILE *fp, struct hist_entry *, unsigned int width);
+       unsigned int *width;
+       bool    elide;
+};
+
+extern struct sort_entry sort_thread;
+extern struct list_head hist_entry__sort_list;
+
+extern int repsep_fprintf(FILE *fp, const char *fmt, ...);
+extern size_t sort__thread_print(FILE *, struct hist_entry *, unsigned int);
+extern size_t sort__comm_print(FILE *, struct hist_entry *, unsigned int);
+extern size_t sort__dso_print(FILE *, struct hist_entry *, unsigned int);
+extern size_t sort__sym_print(FILE *, struct hist_entry *, unsigned int __used);
+extern int64_t cmp_null(void *, void *);
+extern int64_t sort__thread_cmp(struct hist_entry *, struct hist_entry *);
+extern int64_t sort__comm_cmp(struct hist_entry *, struct hist_entry *);
+extern int64_t sort__comm_collapse(struct hist_entry *, struct hist_entry *);
+extern int64_t sort__dso_cmp(struct hist_entry *, struct hist_entry *);
+extern int64_t sort__sym_cmp(struct hist_entry *, struct hist_entry *);
+extern int64_t sort__parent_cmp(struct hist_entry *, struct hist_entry *);
+extern size_t sort__parent_print(FILE *, struct hist_entry *, unsigned int);
+extern int sort_dimension__add(const char *);
+
+#endif /* __PERF_SORT_H */
index d2aa86c..a3d121d 100644 (file)
@@ -1,5 +1,5 @@
-#ifndef STRBUF_H
-#define STRBUF_H
+#ifndef __PERF_STRBUF_H
+#define __PERF_STRBUF_H
 
 /*
  * Strbuf's can be use in many ways: as a byte array, or to store arbitrary
@@ -134,4 +134,4 @@ extern int launch_editor(const char *path, struct strbuf *buffer, const char *co
 extern int strbuf_branchname(struct strbuf *sb, const char *name);
 extern int strbuf_check_branch_ref(struct strbuf *sb, const char *name);
 
-#endif /* STRBUF_H */
+#endif /* __PERF_STRBUF_H */
index c93eca9..f24a8cc 100644 (file)
@@ -1,4 +1,5 @@
 #include "string.h"
+#include "util.h"
 
 static int hex(char ch)
 {
@@ -32,3 +33,196 @@ int hex2u64(const char *ptr, u64 *long_val)
 
        return p - ptr;
 }
+
+char *strxfrchar(char *s, char from, char to)
+{
+       char *p = s;
+
+       while ((p = strchr(p, from)) != NULL)
+               *p++ = to;
+
+       return s;
+}
+
+#define K 1024LL
+/*
+ * perf_atoll()
+ * Parse (\d+)(b|B|kb|KB|mb|MB|gb|GB|tb|TB) (e.g. "256MB")
+ * and return its numeric value
+ */
+s64 perf_atoll(const char *str)
+{
+       unsigned int i;
+       s64 length = -1, unit = 1;
+
+       if (!isdigit(str[0]))
+               goto out_err;
+
+       for (i = 1; i < strlen(str); i++) {
+               switch (str[i]) {
+               case 'B':
+               case 'b':
+                       break;
+               case 'K':
+                       if (str[i + 1] != 'B')
+                               goto out_err;
+                       else
+                               goto kilo;
+               case 'k':
+                       if (str[i + 1] != 'b')
+                               goto out_err;
+kilo:
+                       unit = K;
+                       break;
+               case 'M':
+                       if (str[i + 1] != 'B')
+                               goto out_err;
+                       else
+                               goto mega;
+               case 'm':
+                       if (str[i + 1] != 'b')
+                               goto out_err;
+mega:
+                       unit = K * K;
+                       break;
+               case 'G':
+                       if (str[i + 1] != 'B')
+                               goto out_err;
+                       else
+                               goto giga;
+               case 'g':
+                       if (str[i + 1] != 'b')
+                               goto out_err;
+giga:
+                       unit = K * K * K;
+                       break;
+               case 'T':
+                       if (str[i + 1] != 'B')
+                               goto out_err;
+                       else
+                               goto tera;
+               case 't':
+                       if (str[i + 1] != 'b')
+                               goto out_err;
+tera:
+                       unit = K * K * K * K;
+                       break;
+               case '\0':      /* only specified figures */
+                       unit = 1;
+                       break;
+               default:
+                       if (!isdigit(str[i]))
+                               goto out_err;
+                       break;
+               }
+       }
+
+       length = atoll(str) * unit;
+       goto out;
+
+out_err:
+       length = -1;
+out:
+       return length;
+}
+
+/*
+ * Helper function for splitting a string into an argv-like array.
+ * originaly copied from lib/argv_split.c
+ */
+static const char *skip_sep(const char *cp)
+{
+       while (*cp && isspace(*cp))
+               cp++;
+
+       return cp;
+}
+
+static const char *skip_arg(const char *cp)
+{
+       while (*cp && !isspace(*cp))
+               cp++;
+
+       return cp;
+}
+
+static int count_argc(const char *str)
+{
+       int count = 0;
+
+       while (*str) {
+               str = skip_sep(str);
+               if (*str) {
+                       count++;
+                       str = skip_arg(str);
+               }
+       }
+
+       return count;
+}
+
+/**
+ * argv_free - free an argv
+ * @argv - the argument vector to be freed
+ *
+ * Frees an argv and the strings it points to.
+ */
+void argv_free(char **argv)
+{
+       char **p;
+       for (p = argv; *p; p++)
+               free(*p);
+
+       free(argv);
+}
+
+/**
+ * argv_split - split a string at whitespace, returning an argv
+ * @str: the string to be split
+ * @argcp: returned argument count
+ *
+ * Returns an array of pointers to strings which are split out from
+ * @str.  This is performed by strictly splitting on white-space; no
+ * quote processing is performed.  Multiple whitespace characters are
+ * considered to be a single argument separator.  The returned array
+ * is always NULL-terminated.  Returns NULL on memory allocation
+ * failure.
+ */
+char **argv_split(const char *str, int *argcp)
+{
+       int argc = count_argc(str);
+       char **argv = zalloc(sizeof(*argv) * (argc+1));
+       char **argvp;
+
+       if (argv == NULL)
+               goto out;
+
+       if (argcp)
+               *argcp = argc;
+
+       argvp = argv;
+
+       while (*str) {
+               str = skip_sep(str);
+
+               if (*str) {
+                       const char *p = str;
+                       char *t;
+
+                       str = skip_arg(str);
+
+                       t = strndup(p, str-p);
+                       if (t == NULL)
+                               goto fail;
+                       *argvp++ = t;
+               }
+       }
+       *argvp = NULL;
+
+out:
+       return argv;
+
+fail:
+       argv_free(argv);
+       return NULL;
+}
index bf39dfa..bfecec2 100644 (file)
@@ -1,11 +1,15 @@
-#ifndef _PERF_STRING_H_
-#define _PERF_STRING_H_
+#ifndef __PERF_STRING_H_
+#define __PERF_STRING_H_
 
 #include "types.h"
 
 int hex2u64(const char *ptr, u64 *val);
+char *strxfrchar(char *s, char from, char to);
+s64 perf_atoll(const char *str);
+char **argv_split(const char *str, int *argcp);
+void argv_free(char **argv);
 
 #define _STR(x) #x
 #define STR(x) _STR(x)
 
-#endif
+#endif /* __PERF_STRING_H */
index 921818e..cb46593 100644 (file)
@@ -1,5 +1,5 @@
-#ifndef STRLIST_H_
-#define STRLIST_H_
+#ifndef __PERF_STRLIST_H
+#define __PERF_STRLIST_H
 
 #include <linux/rbtree.h>
 #include <stdbool.h>
@@ -36,4 +36,4 @@ static inline unsigned int strlist__nr_entries(const struct strlist *self)
 }
 
 int strlist__parse_list(struct strlist *self, const char *s);
-#endif /* STRLIST_H_ */
+#endif /* __PERF_STRLIST_H */
index cd93195..e078198 100644 (file)
@@ -1,5 +1,5 @@
-#ifndef _INCLUDE_GUARD_SVG_HELPER_
-#define _INCLUDE_GUARD_SVG_HELPER_
+#ifndef __PERF_SVGHELPER_H
+#define __PERF_SVGHELPER_H
 
 #include "types.h"
 
@@ -25,4 +25,4 @@ extern void svg_close(void);
 
 extern int svg_page_width;
 
-#endif
+#endif /* __PERF_SVGHELPER_H */
index 226f44a..fffcb93 100644 (file)
@@ -2,14 +2,20 @@
 #include "../perf.h"
 #include "string.h"
 #include "symbol.h"
+#include "thread.h"
 
 #include "debug.h"
 
+#include <asm/bug.h>
 #include <libelf.h>
 #include <gelf.h>
 #include <elf.h>
+#include <limits.h>
+#include <sys/utsname.h>
 
-const char *sym_hist_filter;
+#ifndef NT_GNU_BUILD_ID
+#define NT_GNU_BUILD_ID 3
+#endif
 
 enum dso_origin {
        DSO__ORIG_KERNEL = 0,
@@ -18,94 +24,189 @@ enum dso_origin {
        DSO__ORIG_UBUNTU,
        DSO__ORIG_BUILDID,
        DSO__ORIG_DSO,
+       DSO__ORIG_KMODULE,
        DSO__ORIG_NOT_FOUND,
 };
 
-static struct symbol *symbol__new(u64 start, u64 len,
-                                 const char *name, unsigned int priv_size,
-                                 u64 obj_start, int v)
+static void dsos__add(struct list_head *head, struct dso *dso);
+static struct map *thread__find_map_by_name(struct thread *self, char *name);
+static struct map *map__new2(u64 start, struct dso *dso, enum map_type type);
+struct symbol *dso__find_symbol(struct dso *self, enum map_type type, u64 addr);
+static int dso__load_kernel_sym(struct dso *self, struct map *map,
+                               struct thread *thread, symbol_filter_t filter);
+unsigned int symbol__priv_size;
+static int vmlinux_path__nr_entries;
+static char **vmlinux_path;
+
+static struct symbol_conf symbol_conf__defaults = {
+       .use_modules      = true,
+       .try_vmlinux_path = true,
+};
+
+static struct thread kthread_mem;
+struct thread *kthread = &kthread_mem;
+
+bool dso__loaded(const struct dso *self, enum map_type type)
 {
-       size_t namelen = strlen(name) + 1;
-       struct symbol *self = calloc(1, priv_size + sizeof(*self) + namelen);
+       return self->loaded & (1 << type);
+}
 
-       if (!self)
-               return NULL;
+static void dso__set_loaded(struct dso *self, enum map_type type)
+{
+       self->loaded |= (1 << type);
+}
 
-       if (v >= 2)
-               printf("new symbol: %016Lx [%08lx]: %s, hist: %p, obj_start: %p\n",
-                       (u64)start, (unsigned long)len, name, self->hist, (void *)(unsigned long)obj_start);
+static void symbols__fixup_end(struct rb_root *self)
+{
+       struct rb_node *nd, *prevnd = rb_first(self);
+       struct symbol *curr, *prev;
+
+       if (prevnd == NULL)
+               return;
 
-       self->obj_start= obj_start;
-       self->hist = NULL;
-       self->hist_sum = 0;
+       curr = rb_entry(prevnd, struct symbol, rb_node);
 
-       if (sym_hist_filter && !strcmp(name, sym_hist_filter))
-               self->hist = calloc(sizeof(u64), len);
+       for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) {
+               prev = curr;
+               curr = rb_entry(nd, struct symbol, rb_node);
 
-       if (priv_size) {
-               memset(self, 0, priv_size);
-               self = ((void *)self) + priv_size;
+               if (prev->end == prev->start)
+                       prev->end = curr->start - 1;
        }
+
+       /* Last entry */
+       if (curr->end == curr->start)
+               curr->end = roundup(curr->start, 4096);
+}
+
+static void __thread__fixup_maps_end(struct thread *self, enum map_type type)
+{
+       struct map *prev, *curr;
+       struct rb_node *nd, *prevnd = rb_first(&self->maps[type]);
+
+       if (prevnd == NULL)
+               return;
+
+       curr = rb_entry(prevnd, struct map, rb_node);
+
+       for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) {
+               prev = curr;
+               curr = rb_entry(nd, struct map, rb_node);
+               prev->end = curr->start - 1;
+       }
+
+       /*
+        * We still haven't the actual symbols, so guess the
+        * last map final address.
+        */
+       curr->end = ~0UL;
+}
+
+static void thread__fixup_maps_end(struct thread *self)
+{
+       int i;
+       for (i = 0; i < MAP__NR_TYPES; ++i)
+               __thread__fixup_maps_end(self, i);
+}
+
+static struct symbol *symbol__new(u64 start, u64 len, const char *name)
+{
+       size_t namelen = strlen(name) + 1;
+       struct symbol *self = zalloc(symbol__priv_size +
+                                    sizeof(*self) + namelen);
+       if (self == NULL)
+               return NULL;
+
+       if (symbol__priv_size)
+               self = ((void *)self) + symbol__priv_size;
+
        self->start = start;
        self->end   = len ? start + len - 1 : start;
+
+       pr_debug3("%s: %s %#Lx-%#Lx\n", __func__, name, start, self->end);
+
        memcpy(self->name, name, namelen);
 
        return self;
 }
 
-static void symbol__delete(struct symbol *self, unsigned int priv_size)
+static void symbol__delete(struct symbol *self)
 {
-       free(((void *)self) - priv_size);
+       free(((void *)self) - symbol__priv_size);
 }
 
 static size_t symbol__fprintf(struct symbol *self, FILE *fp)
 {
-       if (!self->module)
-               return fprintf(fp, " %llx-%llx %s\n",
+       return fprintf(fp, " %llx-%llx %s\n",
                       self->start, self->end, self->name);
-       else
-               return fprintf(fp, " %llx-%llx %s \t[%s]\n",
-                      self->start, self->end, self->name, self->module->name);
 }
 
-struct dso *dso__new(const char *name, unsigned int sym_priv_size)
+static void dso__set_long_name(struct dso *self, char *name)
+{
+       if (name == NULL)
+               return;
+       self->long_name = name;
+       self->long_name_len = strlen(name);
+}
+
+static void dso__set_basename(struct dso *self)
+{
+       self->short_name = basename(self->long_name);
+}
+
+struct dso *dso__new(const char *name)
 {
        struct dso *self = malloc(sizeof(*self) + strlen(name) + 1);
 
        if (self != NULL) {
+               int i;
                strcpy(self->name, name);
-               self->syms = RB_ROOT;
-               self->sym_priv_size = sym_priv_size;
+               dso__set_long_name(self, self->name);
+               self->short_name = self->name;
+               for (i = 0; i < MAP__NR_TYPES; ++i)
+                       self->symbols[i] = RB_ROOT;
                self->find_symbol = dso__find_symbol;
                self->slen_calculated = 0;
                self->origin = DSO__ORIG_NOT_FOUND;
+               self->loaded = 0;
+               self->has_build_id = 0;
        }
 
        return self;
 }
 
-static void dso__delete_symbols(struct dso *self)
+static void symbols__delete(struct rb_root *self)
 {
        struct symbol *pos;
-       struct rb_node *next = rb_first(&self->syms);
+       struct rb_node *next = rb_first(self);
 
        while (next) {
                pos = rb_entry(next, struct symbol, rb_node);
                next = rb_next(&pos->rb_node);
-               rb_erase(&pos->rb_node, &self->syms);
-               symbol__delete(pos, self->sym_priv_size);
+               rb_erase(&pos->rb_node, self);
+               symbol__delete(pos);
        }
 }
 
 void dso__delete(struct dso *self)
 {
-       dso__delete_symbols(self);
+       int i;
+       for (i = 0; i < MAP__NR_TYPES; ++i)
+               symbols__delete(&self->symbols[i]);
+       if (self->long_name != self->name)
+               free(self->long_name);
        free(self);
 }
 
-static void dso__insert_symbol(struct dso *self, struct symbol *sym)
+void dso__set_build_id(struct dso *self, void *build_id)
 {
-       struct rb_node **p = &self->syms.rb_node;
+       memcpy(self->build_id, build_id, sizeof(self->build_id));
+       self->has_build_id = 1;
+}
+
+static void symbols__insert(struct rb_root *self, struct symbol *sym)
+{
+       struct rb_node **p = &self->rb_node;
        struct rb_node *parent = NULL;
        const u64 ip = sym->start;
        struct symbol *s;
@@ -119,17 +220,17 @@ static void dso__insert_symbol(struct dso *self, struct symbol *sym)
                        p = &(*p)->rb_right;
        }
        rb_link_node(&sym->rb_node, parent, p);
-       rb_insert_color(&sym->rb_node, &self->syms);
+       rb_insert_color(&sym->rb_node, self);
 }
 
-struct symbol *dso__find_symbol(struct dso *self, u64 ip)
+static struct symbol *symbols__find(struct rb_root *self, u64 ip)
 {
        struct rb_node *n;
 
        if (self == NULL)
                return NULL;
 
-       n = self->syms.rb_node;
+       n = self->rb_node;
 
        while (n) {
                struct symbol *s = rb_entry(n, struct symbol, rb_node);
@@ -145,12 +246,42 @@ struct symbol *dso__find_symbol(struct dso *self, u64 ip)
        return NULL;
 }
 
-size_t dso__fprintf(struct dso *self, FILE *fp)
+struct symbol *dso__find_symbol(struct dso *self, enum map_type type, u64 addr)
 {
-       size_t ret = fprintf(fp, "dso: %s\n", self->name);
+       return symbols__find(&self->symbols[type], addr);
+}
+
+int build_id__sprintf(u8 *self, int len, char *bf)
+{
+       char *bid = bf;
+       u8 *raw = self;
+       int i;
+
+       for (i = 0; i < len; ++i) {
+               sprintf(bid, "%02x", *raw);
+               ++raw;
+               bid += 2;
+       }
+
+       return raw - self;
+}
+
+size_t dso__fprintf_buildid(struct dso *self, FILE *fp)
+{
+       char sbuild_id[BUILD_ID_SIZE * 2 + 1];
+
+       build_id__sprintf(self->build_id, sizeof(self->build_id), sbuild_id);
+       return fprintf(fp, "%s", sbuild_id);
+}
 
+size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp)
+{
        struct rb_node *nd;
-       for (nd = rb_first(&self->syms); nd; nd = rb_next(nd)) {
+       size_t ret = fprintf(fp, "dso: %s (", self->short_name);
+
+       ret += dso__fprintf_buildid(self, fp);
+       ret += fprintf(fp, ")\n");
+       for (nd = rb_first(&self->symbols[type]); nd; nd = rb_next(nd)) {
                struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
                ret += symbol__fprintf(pos, fp);
        }
@@ -158,13 +289,17 @@ size_t dso__fprintf(struct dso *self, FILE *fp)
        return ret;
 }
 
-static int dso__load_kallsyms(struct dso *self, symbol_filter_t filter, int v)
+/*
+ * Loads the function entries in /proc/kallsyms into kernel_map->dso,
+ * so that we can in the next step set the symbol ->end address and then
+ * call kernel_maps__split_kallsyms.
+ */
+static int dso__load_all_kallsyms(struct dso *self, struct map *map)
 {
-       struct rb_node *nd, *prevnd;
        char *line = NULL;
        size_t n;
+       struct rb_root *root = &self->symbols[map->type];
        FILE *file = fopen("/proc/kallsyms", "r");
-       int count = 0;
 
        if (file == NULL)
                goto out_failure;
@@ -174,6 +309,7 @@ static int dso__load_kallsyms(struct dso *self, symbol_filter_t filter, int v)
                struct symbol *sym;
                int line_len, len;
                char symbol_type;
+               char *symbol_name;
 
                line_len = getline(&line, &n, file);
                if (line_len < 0)
@@ -196,44 +332,26 @@ static int dso__load_kallsyms(struct dso *self, symbol_filter_t filter, int v)
                 */
                if (symbol_type != 'T' && symbol_type != 'W')
                        continue;
+
+               symbol_name = line + len + 2;
                /*
-                * Well fix up the end later, when we have all sorted.
+                * Will fix up the end later, when we have all symbols sorted.
                 */
-               sym = symbol__new(start, 0xdead, line + len + 2,
-                                 self->sym_priv_size, 0, v);
+               sym = symbol__new(start, 0, symbol_name);
 
                if (sym == NULL)
                        goto out_delete_line;
-
-               if (filter && filter(self, sym))
-                       symbol__delete(sym, self->sym_priv_size);
-               else {
-                       dso__insert_symbol(self, sym);
-                       count++;
-               }
-       }
-
-       /*
-        * Now that we have all sorted out, just set the ->end of all
-        * symbols
-        */
-       prevnd = rb_first(&self->syms);
-
-       if (prevnd == NULL)
-               goto out_delete_line;
-
-       for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) {
-               struct symbol *prev = rb_entry(prevnd, struct symbol, rb_node),
-                             *curr = rb_entry(nd, struct symbol, rb_node);
-
-               prev->end = curr->start - 1;
-               prevnd = nd;
+               /*
+                * We will pass the symbols to the filter later, in
+                * map__split_kallsyms, when we have split the maps per module
+                */
+               symbols__insert(root, sym);
        }
 
        free(line);
        fclose(file);
 
-       return count;
+       return 0;
 
 out_delete_line:
        free(line);
@@ -241,14 +359,114 @@ out_failure:
        return -1;
 }
 
-static int dso__load_perf_map(struct dso *self, symbol_filter_t filter, int v)
+/*
+ * Split the symbols into maps, making sure there are no overlaps, i.e. the
+ * kernel range is broken in several maps, named [kernel].N, as we don't have
+ * the original ELF section names vmlinux have.
+ */
+static int dso__split_kallsyms(struct dso *self, struct map *map, struct thread *thread,
+                              symbol_filter_t filter)
+{
+       struct map *curr_map = map;
+       struct symbol *pos;
+       int count = 0;
+       struct rb_root *root = &self->symbols[map->type];
+       struct rb_node *next = rb_first(root);
+       int kernel_range = 0;
+
+       while (next) {
+               char *module;
+
+               pos = rb_entry(next, struct symbol, rb_node);
+               next = rb_next(&pos->rb_node);
+
+               module = strchr(pos->name, '\t');
+               if (module) {
+                       if (!thread->use_modules)
+                               goto discard_symbol;
+
+                       *module++ = '\0';
+
+                       if (strcmp(self->name, module)) {
+                               curr_map = thread__find_map_by_name(thread, module);
+                               if (curr_map == NULL) {
+                                       pr_debug("/proc/{kallsyms,modules} "
+                                                "inconsistency!\n");
+                                       return -1;
+                               }
+                       }
+                       /*
+                        * So that we look just like we get from .ko files,
+                        * i.e. not prelinked, relative to map->start.
+                        */
+                       pos->start = curr_map->map_ip(curr_map, pos->start);
+                       pos->end   = curr_map->map_ip(curr_map, pos->end);
+               } else if (curr_map != map) {
+                       char dso_name[PATH_MAX];
+                       struct dso *dso;
+
+                       snprintf(dso_name, sizeof(dso_name), "[kernel].%d",
+                                kernel_range++);
+
+                       dso = dso__new(dso_name);
+                       if (dso == NULL)
+                               return -1;
+
+                       curr_map = map__new2(pos->start, dso, map->type);
+                       if (map == NULL) {
+                               dso__delete(dso);
+                               return -1;
+                       }
+
+                       curr_map->map_ip = curr_map->unmap_ip = identity__map_ip;
+                       __thread__insert_map(thread, curr_map);
+                       ++kernel_range;
+               }
+
+               if (filter && filter(curr_map, pos)) {
+discard_symbol:                rb_erase(&pos->rb_node, root);
+                       symbol__delete(pos);
+               } else {
+                       if (curr_map != map) {
+                               rb_erase(&pos->rb_node, root);
+                               symbols__insert(&curr_map->dso->symbols[curr_map->type], pos);
+                       }
+                       count++;
+               }
+       }
+
+       return count;
+}
+
+
+static int dso__load_kallsyms(struct dso *self, struct map *map,
+                             struct thread *thread, symbol_filter_t filter)
+{
+       if (dso__load_all_kallsyms(self, map) < 0)
+               return -1;
+
+       symbols__fixup_end(&self->symbols[map->type]);
+       self->origin = DSO__ORIG_KERNEL;
+
+       return dso__split_kallsyms(self, map, thread, filter);
+}
+
+size_t kernel_maps__fprintf(FILE *fp)
+{
+       size_t printed = fprintf(fp, "Kernel maps:\n");
+       printed += thread__fprintf_maps(kthread, fp);
+       return printed + fprintf(fp, "END kernel maps\n");
+}
+
+static int dso__load_perf_map(struct dso *self, struct map *map,
+                             symbol_filter_t filter)
 {
        char *line = NULL;
        size_t n;
        FILE *file;
        int nr_syms = 0;
 
-       file = fopen(self->name, "r");
+       file = fopen(self->long_name, "r");
        if (file == NULL)
                goto out_failure;
 
@@ -278,16 +496,15 @@ static int dso__load_perf_map(struct dso *self, symbol_filter_t filter, int v)
                if (len + 2 >= line_len)
                        continue;
 
-               sym = symbol__new(start, size, line + len,
-                                 self->sym_priv_size, start, v);
+               sym = symbol__new(start, size, line + len);
 
                if (sym == NULL)
                        goto out_delete_line;
 
-               if (filter && filter(self, sym))
-                       symbol__delete(sym, self->sym_priv_size);
+               if (filter && filter(map, sym))
+                       symbol__delete(sym);
                else {
-                       dso__insert_symbol(self, sym);
+                       symbols__insert(&self->symbols[map->type], sym);
                        nr_syms++;
                }
        }
@@ -393,7 +610,8 @@ static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep,
  * And always look at the original dso, not at debuginfo packages, that
  * have the PLT data stripped out (shdr_rel_plt.sh_type == SHT_NOBITS).
  */
-static int dso__synthesize_plt_symbols(struct  dso *self, int v)
+static int dso__synthesize_plt_symbols(struct  dso *self, struct map *map,
+                                      symbol_filter_t filter)
 {
        uint32_t nr_rel_entries, idx;
        GElf_Sym sym;
@@ -409,7 +627,7 @@ static int dso__synthesize_plt_symbols(struct  dso *self, int v)
        Elf *elf;
        int nr = 0, symidx, fd, err = 0;
 
-       fd = open(self->name, O_RDONLY);
+       fd = open(self->long_name, O_RDONLY);
        if (fd < 0)
                goto out;
 
@@ -477,12 +695,16 @@ static int dso__synthesize_plt_symbols(struct  dso *self, int v)
                                 "%s@plt", elf_sym__name(&sym, symstrs));
 
                        f = symbol__new(plt_offset, shdr_plt.sh_entsize,
-                                       sympltname, self->sym_priv_size, 0, v);
+                                       sympltname);
                        if (!f)
                                goto out_elf_end;
 
-                       dso__insert_symbol(self, f);
-                       ++nr;
+                       if (filter && filter(map, f))
+                               symbol__delete(f);
+                       else {
+                               symbols__insert(&self->symbols[map->type], f);
+                               ++nr;
+                       }
                }
        } else if (shdr_rel_plt.sh_type == SHT_REL) {
                GElf_Rel pos_mem, *pos;
@@ -495,12 +717,16 @@ static int dso__synthesize_plt_symbols(struct  dso *self, int v)
                                 "%s@plt", elf_sym__name(&sym, symstrs));
 
                        f = symbol__new(plt_offset, shdr_plt.sh_entsize,
-                                       sympltname, self->sym_priv_size, 0, v);
+                                       sympltname);
                        if (!f)
                                goto out_elf_end;
 
-                       dso__insert_symbol(self, f);
-                       ++nr;
+                       if (filter && filter(map, f))
+                               symbol__delete(f);
+                       else {
+                               symbols__insert(&self->symbols[map->type], f);
+                               ++nr;
+                       }
                }
        }
 
@@ -513,14 +739,18 @@ out_close:
        if (err == 0)
                return nr;
 out:
-       fprintf(stderr, "%s: problems reading %s PLT info.\n",
-               __func__, self->name);
+       pr_warning("%s: problems reading %s PLT info.\n",
+                  __func__, self->long_name);
        return 0;
 }
 
-static int dso__load_sym(struct dso *self, int fd, const char *name,
-                        symbol_filter_t filter, int v, struct module *mod)
+static int dso__load_sym(struct dso *self, struct map *map,
+                        struct thread *thread, const char *name, int fd,
+                        symbol_filter_t filter, int kernel, int kmodule)
 {
+       struct map *curr_map = map;
+       struct dso *curr_dso = self;
+       size_t dso_name_len = strlen(self->short_name);
        Elf_Data *symstrs, *secstrs;
        uint32_t nr_syms;
        int err = -1;
@@ -531,19 +761,16 @@ static int dso__load_sym(struct dso *self, int fd, const char *name,
        GElf_Sym sym;
        Elf_Scn *sec, *sec_strndx;
        Elf *elf;
-       int nr = 0, kernel = !strcmp("[kernel]", self->name);
+       int nr = 0;
 
        elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
        if (elf == NULL) {
-               if (v)
-                       fprintf(stderr, "%s: cannot read %s ELF file.\n",
-                               __func__, name);
+               pr_err("%s: cannot read %s ELF file.\n", __func__, name);
                goto out_close;
        }
 
        if (gelf_getehdr(elf, &ehdr) == NULL) {
-               if (v)
-                       fprintf(stderr, "%s: cannot get elf header.\n", __func__);
+               pr_err("%s: cannot get elf header.\n", __func__);
                goto out_elf_end;
        }
 
@@ -587,9 +814,7 @@ static int dso__load_sym(struct dso *self, int fd, const char *name,
        elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) {
                struct symbol *f;
                const char *elf_name;
-               char *demangled;
-               u64 obj_start;
-               struct section *section = NULL;
+               char *demangled = NULL;
                int is_label = elf_sym__is_label(&sym);
                const char *section_name;
 
@@ -605,52 +830,85 @@ static int dso__load_sym(struct dso *self, int fd, const char *name,
                if (is_label && !elf_sec__is_text(&shdr, secstrs))
                        continue;
 
+               elf_name = elf_sym__name(&sym, symstrs);
                section_name = elf_sec__name(&shdr, secstrs);
-               obj_start = sym.st_value;
 
-               if (self->adjust_symbols) {
-                       if (v >= 2)
-                               printf("adjusting symbol: st_value: %Lx sh_addr: %Lx sh_offset: %Lx\n",
-                                       (u64)sym.st_value, (u64)shdr.sh_addr, (u64)shdr.sh_offset);
+               if (kernel || kmodule) {
+                       char dso_name[PATH_MAX];
 
-                       sym.st_value -= shdr.sh_addr - shdr.sh_offset;
-               }
+                       if (strcmp(section_name,
+                                  curr_dso->short_name + dso_name_len) == 0)
+                               goto new_symbol;
 
-               if (mod) {
-                       section = mod->sections->find_section(mod->sections, section_name);
-                       if (section)
-                               sym.st_value += section->vma;
-                       else {
-                               fprintf(stderr, "dso__load_sym() module %s lookup of %s failed\n",
-                                       mod->name, section_name);
-                               goto out_elf_end;
+                       if (strcmp(section_name, ".text") == 0) {
+                               curr_map = map;
+                               curr_dso = self;
+                               goto new_symbol;
                        }
+
+                       snprintf(dso_name, sizeof(dso_name),
+                                "%s%s", self->short_name, section_name);
+
+                       curr_map = thread__find_map_by_name(thread, dso_name);
+                       if (curr_map == NULL) {
+                               u64 start = sym.st_value;
+
+                               if (kmodule)
+                                       start += map->start + shdr.sh_offset;
+
+                               curr_dso = dso__new(dso_name);
+                               if (curr_dso == NULL)
+                                       goto out_elf_end;
+                               curr_map = map__new2(start, curr_dso,
+                                                    MAP__FUNCTION);
+                               if (curr_map == NULL) {
+                                       dso__delete(curr_dso);
+                                       goto out_elf_end;
+                               }
+                               curr_map->map_ip = identity__map_ip;
+                               curr_map->unmap_ip = identity__map_ip;
+                               curr_dso->origin = DSO__ORIG_KERNEL;
+                               __thread__insert_map(kthread, curr_map);
+                               dsos__add(&dsos__kernel, curr_dso);
+                       } else
+                               curr_dso = curr_map->dso;
+
+                       goto new_symbol;
+               }
+
+               if (curr_dso->adjust_symbols) {
+                       pr_debug2("adjusting symbol: st_value: %Lx sh_addr: "
+                                 "%Lx sh_offset: %Lx\n", (u64)sym.st_value,
+                                 (u64)shdr.sh_addr, (u64)shdr.sh_offset);
+                       sym.st_value -= shdr.sh_addr - shdr.sh_offset;
                }
                /*
                 * We need to figure out if the object was created from C++ sources
                 * DWARF DW_compile_unit has this, but we don't always have access
                 * to it...
                 */
-               elf_name = elf_sym__name(&sym, symstrs);
                demangled = bfd_demangle(NULL, elf_name, DMGL_PARAMS | DMGL_ANSI);
                if (demangled != NULL)
                        elf_name = demangled;
-
-               f = symbol__new(sym.st_value, sym.st_size, elf_name,
-                               self->sym_priv_size, obj_start, v);
+new_symbol:
+               f = symbol__new(sym.st_value, sym.st_size, elf_name);
                free(demangled);
                if (!f)
                        goto out_elf_end;
 
-               if (filter && filter(self, f))
-                       symbol__delete(f, self->sym_priv_size);
+               if (filter && filter(curr_map, f))
+                       symbol__delete(f);
                else {
-                       f->module = mod;
-                       dso__insert_symbol(self, f);
+                       symbols__insert(&curr_dso->symbols[curr_map->type], f);
                        nr++;
                }
        }
 
+       /*
+        * For misannotated, zeroed, ASM function sizes.
+        */
+       if (nr > 0)
+               symbols__fixup_end(&self->symbols[map->type]);
        err = nr;
 out_elf_end:
        elf_end(elf);
@@ -658,63 +916,153 @@ out_close:
        return err;
 }
 
-#define BUILD_ID_SIZE 128
+static bool dso__build_id_equal(const struct dso *self, u8 *build_id)
+{
+       return memcmp(self->build_id, build_id, sizeof(self->build_id)) == 0;
+}
 
-static char *dso__read_build_id(struct dso *self, int v)
+static bool __dsos__read_build_ids(struct list_head *head)
 {
-       int i;
+       bool have_build_id = false;
+       struct dso *pos;
+
+       list_for_each_entry(pos, head, node)
+               if (filename__read_build_id(pos->long_name, pos->build_id,
+                                           sizeof(pos->build_id)) > 0) {
+                       have_build_id     = true;
+                       pos->has_build_id = true;
+               }
+
+       return have_build_id;
+}
+
+bool dsos__read_build_ids(void)
+{
+       return __dsos__read_build_ids(&dsos__kernel) ||
+              __dsos__read_build_ids(&dsos__user);
+}
+
+/*
+ * Align offset to 4 bytes as needed for note name and descriptor data.
+ */
+#define NOTE_ALIGN(n) (((n) + 3) & -4U)
+
+int filename__read_build_id(const char *filename, void *bf, size_t size)
+{
+       int fd, err = -1;
        GElf_Ehdr ehdr;
        GElf_Shdr shdr;
-       Elf_Data *build_id_data;
+       Elf_Data *data;
        Elf_Scn *sec;
-       char *build_id = NULL, *bid;
-       unsigned char *raw;
+       Elf_Kind ek;
+       void *ptr;
        Elf *elf;
-       int fd = open(self->name, O_RDONLY);
 
+       if (size < BUILD_ID_SIZE)
+               goto out;
+
+       fd = open(filename, O_RDONLY);
        if (fd < 0)
                goto out;
 
        elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
        if (elf == NULL) {
-               if (v)
-                       fprintf(stderr, "%s: cannot read %s ELF file.\n",
-                               __func__, self->name);
+               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_elf_end;
+
        if (gelf_getehdr(elf, &ehdr) == NULL) {
-               if (v)
-                       fprintf(stderr, "%s: cannot get elf header.\n", __func__);
+               pr_err("%s: cannot get elf header.\n", __func__);
                goto out_elf_end;
        }
 
-       sec = elf_section_by_name(elf, &ehdr, &shdr, ".note.gnu.build-id", NULL);
-       if (sec == NULL)
-               goto out_elf_end;
+       sec = elf_section_by_name(elf, &ehdr, &shdr,
+                                 ".note.gnu.build-id", NULL);
+       if (sec == NULL) {
+               sec = elf_section_by_name(elf, &ehdr, &shdr,
+                                         ".notes", NULL);
+               if (sec == NULL)
+                       goto out_elf_end;
+       }
 
-       build_id_data = elf_getdata(sec, NULL);
-       if (build_id_data == NULL)
-               goto out_elf_end;
-       build_id = malloc(BUILD_ID_SIZE);
-       if (build_id == NULL)
+       data = elf_getdata(sec, NULL);
+       if (data == NULL)
                goto out_elf_end;
-       raw = build_id_data->d_buf + 16;
-       bid = build_id;
 
-       for (i = 0; i < 20; ++i) {
-               sprintf(bid, "%02x", *raw);
-               ++raw;
-               bid += 2;
+       ptr = data->d_buf;
+       while (ptr < (data->d_buf + data->d_size)) {
+               GElf_Nhdr *nhdr = ptr;
+               int namesz = NOTE_ALIGN(nhdr->n_namesz),
+                   descsz = NOTE_ALIGN(nhdr->n_descsz);
+               const char *name;
+
+               ptr += sizeof(*nhdr);
+               name = ptr;
+               ptr += namesz;
+               if (nhdr->n_type == NT_GNU_BUILD_ID &&
+                   nhdr->n_namesz == sizeof("GNU")) {
+                       if (memcmp(name, "GNU", sizeof("GNU")) == 0) {
+                               memcpy(bf, ptr, BUILD_ID_SIZE);
+                               err = BUILD_ID_SIZE;
+                               break;
+                       }
+               }
+               ptr += descsz;
        }
-       if (v >= 2)
-               printf("%s(%s): %s\n", __func__, self->name, build_id);
 out_elf_end:
        elf_end(elf);
 out_close:
        close(fd);
 out:
-       return build_id;
+       return err;
+}
+
+int sysfs__read_build_id(const char *filename, void *build_id, size_t size)
+{
+       int fd, err = -1;
+
+       if (size < BUILD_ID_SIZE)
+               goto out;
+
+       fd = open(filename, O_RDONLY);
+       if (fd < 0)
+               goto out;
+
+       while (1) {
+               char bf[BUFSIZ];
+               GElf_Nhdr nhdr;
+               int namesz, descsz;
+
+               if (read(fd, &nhdr, sizeof(nhdr)) != sizeof(nhdr))
+                       break;
+
+               namesz = NOTE_ALIGN(nhdr.n_namesz);
+               descsz = NOTE_ALIGN(nhdr.n_descsz);
+               if (nhdr.n_type == NT_GNU_BUILD_ID &&
+                   nhdr.n_namesz == sizeof("GNU")) {
+                       if (read(fd, bf, namesz) != namesz)
+                               break;
+                       if (memcmp(bf, "GNU", sizeof("GNU")) == 0) {
+                               if (read(fd, build_id,
+                                   BUILD_ID_SIZE) == BUILD_ID_SIZE) {
+                                       err = 0;
+                                       break;
+                               }
+                       } else if (read(fd, bf, descsz) != descsz)
+                               break;
+               } else {
+                       int n = namesz + descsz;
+                       if (read(fd, bf, n) != n)
+                               break;
+               }
+       }
+       close(fd);
+out:
+       return err;
 }
 
 char dso__symtab_origin(const struct dso *self)
@@ -726,6 +1074,7 @@ char dso__symtab_origin(const struct dso *self)
                [DSO__ORIG_UBUNTU] =   'u',
                [DSO__ORIG_BUILDID] =  'b',
                [DSO__ORIG_DSO] =      'd',
+               [DSO__ORIG_KMODULE] =  'K',
        };
 
        if (self == NULL || self->origin == DSO__ORIG_NOT_FOUND)
@@ -733,20 +1082,27 @@ char dso__symtab_origin(const struct dso *self)
        return origin[self->origin];
 }
 
-int dso__load(struct dso *self, symbol_filter_t filter, int v)
+int dso__load(struct dso *self, struct map *map, symbol_filter_t filter)
 {
        int size = PATH_MAX;
-       char *name = malloc(size), *build_id = NULL;
+       char *name;
+       u8 build_id[BUILD_ID_SIZE];
        int ret = -1;
        int fd;
 
+       dso__set_loaded(self, map->type);
+
+       if (self->kernel)
+               return dso__load_kernel_sym(self, map, kthread, filter);
+
+       name = malloc(size);
        if (!name)
                return -1;
 
        self->adjust_symbols = 0;
 
        if (strncmp(self->name, "/tmp/perf-", 10) == 0) {
-               ret = dso__load_perf_map(self, filter, v);
+               ret = dso__load_perf_map(self, map, filter);
                self->origin = ret > 0 ? DSO__ORIG_JAVA_JIT :
                                         DSO__ORIG_NOT_FOUND;
                return ret;
@@ -759,34 +1115,50 @@ more:
                self->origin++;
                switch (self->origin) {
                case DSO__ORIG_FEDORA:
-                       snprintf(name, size, "/usr/lib/debug%s.debug", self->name);
+                       snprintf(name, size, "/usr/lib/debug%s.debug",
+                                self->long_name);
                        break;
                case DSO__ORIG_UBUNTU:
-                       snprintf(name, size, "/usr/lib/debug%s", self->name);
+                       snprintf(name, size, "/usr/lib/debug%s",
+                                self->long_name);
                        break;
                case DSO__ORIG_BUILDID:
-                       build_id = dso__read_build_id(self, v);
-                       if (build_id != NULL) {
+                       if (filename__read_build_id(self->long_name, build_id,
+                                                   sizeof(build_id))) {
+                               char build_id_hex[BUILD_ID_SIZE * 2 + 1];
+
+                               build_id__sprintf(build_id, sizeof(build_id),
+                                                 build_id_hex);
                                snprintf(name, size,
                                         "/usr/lib/debug/.build-id/%.2s/%s.debug",
-                                       build_id, build_id + 2);
-                               free(build_id);
+                                       build_id_hex, build_id_hex + 2);
+                               if (self->has_build_id)
+                                       goto compare_build_id;
                                break;
                        }
                        self->origin++;
                        /* Fall thru */
                case DSO__ORIG_DSO:
-                       snprintf(name, size, "%s", self->name);
+                       snprintf(name, size, "%s", self->long_name);
                        break;
 
                default:
                        goto out;
                }
 
+               if (self->has_build_id) {
+                       if (filename__read_build_id(name, build_id,
+                                                   sizeof(build_id)) < 0)
+                               goto more;
+compare_build_id:
+                       if (!dso__build_id_equal(self, build_id))
+                               goto more;
+               }
+
                fd = open(name, O_RDONLY);
        } while (fd < 0);
 
-       ret = dso__load_sym(self, fd, name, filter, v, NULL);
+       ret = dso__load_sym(self, map, NULL, name, fd, filter, 0, 0);
        close(fd);
 
        /*
@@ -796,7 +1168,7 @@ more:
                goto more;
 
        if (ret > 0) {
-               int nr_plt = dso__synthesize_plt_symbols(self, v);
+               int nr_plt = dso__synthesize_plt_symbols(self, map, filter);
                if (nr_plt > 0)
                        ret += nr_plt;
        }
@@ -807,151 +1179,279 @@ out:
        return ret;
 }
 
-static int dso__load_module(struct dso *self, struct mod_dso *mods, const char *name,
-                            symbol_filter_t filter, int v)
+static struct map *thread__find_map_by_name(struct thread *self, char *name)
 {
-       struct module *mod = mod_dso__find_module(mods, name);
-       int err = 0, fd;
+       struct rb_node *nd;
 
-       if (mod == NULL || !mod->active)
-               return err;
+       for (nd = rb_first(&self->maps[MAP__FUNCTION]); nd; nd = rb_next(nd)) {
+               struct map *map = rb_entry(nd, struct map, rb_node);
 
-       fd = open(mod->path, O_RDONLY);
+               if (map->dso && strcmp(map->dso->name, name) == 0)
+                       return map;
+       }
 
-       if (fd < 0)
-               return err;
+       return NULL;
+}
 
-       err = dso__load_sym(self, fd, name, filter, v, mod);
-       close(fd);
+static int dsos__set_modules_path_dir(char *dirname)
+{
+       struct dirent *dent;
+       DIR *dir = opendir(dirname);
 
-       return err;
+       if (!dir) {
+               pr_debug("%s: cannot open %s dir\n", __func__, dirname);
+               return -1;
+       }
+
+       while ((dent = readdir(dir)) != NULL) {
+               char path[PATH_MAX];
+
+               if (dent->d_type == DT_DIR) {
+                       if (!strcmp(dent->d_name, ".") ||
+                           !strcmp(dent->d_name, ".."))
+                               continue;
+
+                       snprintf(path, sizeof(path), "%s/%s",
+                                dirname, dent->d_name);
+                       if (dsos__set_modules_path_dir(path) < 0)
+                               goto failure;
+               } else {
+                       char *dot = strrchr(dent->d_name, '.'),
+                            dso_name[PATH_MAX];
+                       struct map *map;
+                       char *long_name;
+
+                       if (dot == NULL || strcmp(dot, ".ko"))
+                               continue;
+                       snprintf(dso_name, sizeof(dso_name), "[%.*s]",
+                                (int)(dot - dent->d_name), dent->d_name);
+
+                       strxfrchar(dso_name, '-', '_');
+                       map = thread__find_map_by_name(kthread, dso_name);
+                       if (map == NULL)
+                               continue;
+
+                       snprintf(path, sizeof(path), "%s/%s",
+                                dirname, dent->d_name);
+
+                       long_name = strdup(path);
+                       if (long_name == NULL)
+                               goto failure;
+                       dso__set_long_name(map->dso, long_name);
+               }
+       }
+
+       return 0;
+failure:
+       closedir(dir);
+       return -1;
 }
 
-int dso__load_modules(struct dso *self, symbol_filter_t filter, int v)
+static int dsos__set_modules_path(void)
 {
-       struct mod_dso *mods = mod_dso__new_dso("modules");
-       struct module *pos;
-       struct rb_node *next;
-       int err, count = 0;
+       struct utsname uts;
+       char modules_path[PATH_MAX];
 
-       err = mod_dso__load_modules(mods);
-
-       if (err <= 0)
-               return err;
+       if (uname(&uts) < 0)
+               return -1;
 
-       /*
-        * Iterate over modules, and load active symbols.
-        */
-       next = rb_first(&mods->mods);
-       while (next) {
-               pos = rb_entry(next, struct module, rb_node);
-               err = dso__load_module(self, mods, pos->name, filter, v);
+       snprintf(modules_path, sizeof(modules_path), "/lib/modules/%s/kernel",
+                uts.release);
 
-               if (err < 0)
-                       break;
+       return dsos__set_modules_path_dir(modules_path);
+}
 
-               next = rb_next(&pos->rb_node);
-               count += err;
-       }
+/*
+ * Constructor variant for modules (where we know from /proc/modules where
+ * they are loaded) and for vmlinux, where only after we load all the
+ * symbols we'll know where it starts and ends.
+ */
+static struct map *map__new2(u64 start, struct dso *dso, enum map_type type)
+{
+       struct map *self = malloc(sizeof(*self));
 
-       if (err < 0) {
-               mod_dso__delete_modules(mods);
-               mod_dso__delete_self(mods);
-               return err;
+       if (self != NULL) {
+               /*
+                * ->end will be filled after we load all the symbols
+                */
+               map__init(self, type, start, 0, 0, dso);
        }
 
-       return count;
+       return self;
 }
 
-static inline void dso__fill_symbol_holes(struct dso *self)
+static int thread__create_module_maps(struct thread *self)
 {
-       struct symbol *prev = NULL;
-       struct rb_node *nd;
+       char *line = NULL;
+       size_t n;
+       FILE *file = fopen("/proc/modules", "r");
+       struct map *map;
 
-       for (nd = rb_last(&self->syms); nd; nd = rb_prev(nd)) {
-               struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
+       if (file == NULL)
+               return -1;
 
-               if (prev) {
-                       u64 hole = 0;
-                       int alias = pos->start == prev->start;
+       while (!feof(file)) {
+               char name[PATH_MAX];
+               u64 start;
+               struct dso *dso;
+               char *sep;
+               int line_len;
 
-                       if (!alias)
-                               hole = prev->start - pos->end - 1;
+               line_len = getline(&line, &n, file);
+               if (line_len < 0)
+                       break;
 
-                       if (hole || alias) {
-                               if (alias)
-                                       pos->end = prev->end;
-                               else if (hole)
-                                       pos->end = prev->start - 1;
-                       }
+               if (!line)
+                       goto out_failure;
+
+               line[--line_len] = '\0'; /* \n */
+
+               sep = strrchr(line, 'x');
+               if (sep == NULL)
+                       continue;
+
+               hex2u64(sep + 1, &start);
+
+               sep = strchr(line, ' ');
+               if (sep == NULL)
+                       continue;
+
+               *sep = '\0';
+
+               snprintf(name, sizeof(name), "[%s]", line);
+               dso = dso__new(name);
+
+               if (dso == NULL)
+                       goto out_delete_line;
+
+               map = map__new2(start, dso, MAP__FUNCTION);
+               if (map == NULL) {
+                       dso__delete(dso);
+                       goto out_delete_line;
                }
-               prev = pos;
+
+               snprintf(name, sizeof(name),
+                        "/sys/module/%s/notes/.note.gnu.build-id", line);
+               if (sysfs__read_build_id(name, dso->build_id,
+                                        sizeof(dso->build_id)) == 0)
+                       dso->has_build_id = true;
+
+               dso->origin = DSO__ORIG_KMODULE;
+               __thread__insert_map(self, map);
+               dsos__add(&dsos__kernel, dso);
        }
+
+       free(line);
+       fclose(file);
+
+       return dsos__set_modules_path();
+
+out_delete_line:
+       free(line);
+out_failure:
+       return -1;
 }
 
-static int dso__load_vmlinux(struct dso *self, const char *vmlinux,
-                            symbol_filter_t filter, int v)
+static int dso__load_vmlinux(struct dso *self, struct map *map, struct thread *thread,
+                            const char *vmlinux, symbol_filter_t filter)
 {
-       int err, fd = open(vmlinux, O_RDONLY);
+       int err = -1, fd;
 
-       if (fd < 0)
-               return -1;
+       if (self->has_build_id) {
+               u8 build_id[BUILD_ID_SIZE];
 
-       err = dso__load_sym(self, fd, vmlinux, filter, v, NULL);
+               if (filename__read_build_id(vmlinux, build_id,
+                                           sizeof(build_id)) < 0) {
+                       pr_debug("No build_id in %s, ignoring it\n", vmlinux);
+                       return -1;
+               }
+               if (!dso__build_id_equal(self, build_id)) {
+                       char expected_build_id[BUILD_ID_SIZE * 2 + 1],
+                            vmlinux_build_id[BUILD_ID_SIZE * 2 + 1];
+
+                       build_id__sprintf(self->build_id,
+                                         sizeof(self->build_id),
+                                         expected_build_id);
+                       build_id__sprintf(build_id, sizeof(build_id),
+                                         vmlinux_build_id);
+                       pr_debug("build_id in %s is %s while expected is %s, "
+                                "ignoring it\n", vmlinux, vmlinux_build_id,
+                                expected_build_id);
+                       return -1;
+               }
+       }
 
-       if (err > 0)
-               dso__fill_symbol_holes(self);
+       fd = open(vmlinux, O_RDONLY);
+       if (fd < 0)
+               return -1;
 
+       dso__set_loaded(self, map->type);
+       err = dso__load_sym(self, map, thread, self->long_name, fd, filter, 1, 0);
        close(fd);
 
        return err;
 }
 
-int dso__load_kernel(struct dso *self, const char *vmlinux,
-                    symbol_filter_t filter, int v, int use_modules)
+static int dso__load_kernel_sym(struct dso *self, struct map *map,
+                               struct thread *thread, symbol_filter_t filter)
 {
-       int err = -1;
-
-       if (vmlinux) {
-               err = dso__load_vmlinux(self, vmlinux, filter, v);
-               if (err > 0 && use_modules) {
-                       int syms = dso__load_modules(self, filter, v);
-
-                       if (syms < 0) {
-                               fprintf(stderr, "dso__load_modules failed!\n");
-                               return syms;
+       int err;
+       bool is_kallsyms;
+
+       if (vmlinux_path != NULL) {
+               int i;
+               pr_debug("Looking at the vmlinux_path (%d entries long)\n",
+                        vmlinux_path__nr_entries);
+               for (i = 0; i < vmlinux_path__nr_entries; ++i) {
+                       err = dso__load_vmlinux(self, map, thread,
+                                               vmlinux_path[i], filter);
+                       if (err > 0) {
+                               pr_debug("Using %s for symbols\n",
+                                        vmlinux_path[i]);
+                               dso__set_long_name(self,
+                                                  strdup(vmlinux_path[i]));
+                               goto out_fixup;
                        }
-                       err += syms;
                }
        }
 
-       if (err <= 0)
-               err = dso__load_kallsyms(self, filter, v);
+       is_kallsyms = self->long_name[0] == '[';
+       if (is_kallsyms)
+               goto do_kallsyms;
 
-       if (err > 0)
-               self->origin = DSO__ORIG_KERNEL;
+       err = dso__load_vmlinux(self, map, thread, self->long_name, filter);
+       if (err <= 0) {
+               pr_info("The file %s cannot be used, "
+                       "trying to use /proc/kallsyms...", self->long_name);
+do_kallsyms:
+               err = dso__load_kallsyms(self, map, thread, filter);
+               if (err > 0 && !is_kallsyms)
+                        dso__set_long_name(self, strdup("[kernel.kallsyms]"));
+       }
+
+       if (err > 0) {
+out_fixup:
+               map__fixup_start(map);
+               map__fixup_end(map);
+       }
 
        return err;
 }
 
-LIST_HEAD(dsos);
-struct dso     *kernel_dso;
-struct dso     *vdso;
-struct dso     *hypervisor_dso;
-
-const char     *vmlinux_name = "vmlinux";
-int            modules;
+LIST_HEAD(dsos__user);
+LIST_HEAD(dsos__kernel);
+struct dso *vdso;
 
-static void dsos__add(struct dso *dso)
+static void dsos__add(struct list_head *head, struct dso *dso)
 {
-       list_add_tail(&dso->node, &dsos);
+       list_add_tail(&dso->node, head);
 }
 
-static struct dso *dsos__find(const char *name)
+static struct dso *dsos__find(struct list_head *head, const char *name)
 {
        struct dso *pos;
 
-       list_for_each_entry(pos, &dsos, node)
+       list_for_each_entry(pos, head, node)
                if (strcmp(pos->name, name) == 0)
                        return pos;
        return NULL;
@@ -959,79 +1459,170 @@ static struct dso *dsos__find(const char *name)
 
 struct dso *dsos__findnew(const char *name)
 {
-       struct dso *dso = dsos__find(name);
-       int nr;
-
-       if (dso)
-               return dso;
-
-       dso = dso__new(name, 0);
-       if (!dso)
-               goto out_delete_dso;
+       struct dso *dso = dsos__find(&dsos__user, name);
 
-       nr = dso__load(dso, NULL, verbose);
-       if (nr < 0) {
-               eprintf("Failed to open: %s\n", name);
-               goto out_delete_dso;
+       if (!dso) {
+               dso = dso__new(name);
+               if (dso != NULL) {
+                       dsos__add(&dsos__user, dso);
+                       dso__set_basename(dso);
+               }
        }
-       if (!nr)
-               eprintf("No symbols found in: %s, maybe install a debug package?\n", name);
-
-       dsos__add(dso);
 
        return dso;
+}
 
-out_delete_dso:
-       dso__delete(dso);
-       return NULL;
+static void __dsos__fprintf(struct list_head *head, FILE *fp)
+{
+       struct dso *pos;
+
+       list_for_each_entry(pos, head, node) {
+               int i;
+               for (i = 0; i < MAP__NR_TYPES; ++i)
+                       dso__fprintf(pos, i, fp);
+       }
 }
 
 void dsos__fprintf(FILE *fp)
 {
+       __dsos__fprintf(&dsos__kernel, fp);
+       __dsos__fprintf(&dsos__user, fp);
+}
+
+static size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp)
+{
        struct dso *pos;
+       size_t ret = 0;
 
-       list_for_each_entry(pos, &dsos, node)
-               dso__fprintf(pos, fp);
+       list_for_each_entry(pos, head, node) {
+               ret += dso__fprintf_buildid(pos, fp);
+               ret += fprintf(fp, " %s\n", pos->long_name);
+       }
+       return ret;
 }
 
-static struct symbol *vdso__find_symbol(struct dso *dso, u64 ip)
+size_t dsos__fprintf_buildid(FILE *fp)
 {
-       return dso__find_symbol(dso, ip);
+       return (__dsos__fprintf_buildid(&dsos__kernel, fp) +
+               __dsos__fprintf_buildid(&dsos__user, fp));
 }
 
-int load_kernel(void)
+static int thread__create_kernel_map(struct thread *self, const char *vmlinux)
 {
-       int err;
+       struct map *kmap;
+       struct dso *kernel = dso__new(vmlinux ?: "[kernel.kallsyms]");
 
-       kernel_dso = dso__new("[kernel]", 0);
-       if (!kernel_dso)
+       if (kernel == NULL)
                return -1;
 
-       err = dso__load_kernel(kernel_dso, vmlinux_name, NULL, verbose, modules);
-       if (err <= 0) {
-               dso__delete(kernel_dso);
-               kernel_dso = NULL;
-       } else
-               dsos__add(kernel_dso);
+       kmap = map__new2(0, kernel, MAP__FUNCTION);
+       if (kmap == NULL)
+               goto out_delete_kernel_dso;
 
-       vdso = dso__new("[vdso]", 0);
-       if (!vdso)
-               return -1;
+       kmap->map_ip       = kmap->unmap_ip = identity__map_ip;
+       kernel->short_name = "[kernel]";
+       kernel->kernel     = 1;
 
-       vdso->find_symbol = vdso__find_symbol;
+       vdso = dso__new("[vdso]");
+       if (vdso == NULL)
+               goto out_delete_kernel_map;
+       dso__set_loaded(vdso, MAP__FUNCTION);
 
-       dsos__add(vdso);
+       if (sysfs__read_build_id("/sys/kernel/notes", kernel->build_id,
+                                sizeof(kernel->build_id)) == 0)
+               kernel->has_build_id = true;
 
-       hypervisor_dso = dso__new("[hypervisor]", 0);
-       if (!hypervisor_dso)
-               return -1;
-       dsos__add(hypervisor_dso);
+       __thread__insert_map(self, kmap);
+       dsos__add(&dsos__kernel, kernel);
+       dsos__add(&dsos__user, vdso);
 
-       return err;
+       return 0;
+
+out_delete_kernel_map:
+       map__delete(kmap);
+out_delete_kernel_dso:
+       dso__delete(kernel);
+       return -1;
+}
+
+static void vmlinux_path__exit(void)
+{
+       while (--vmlinux_path__nr_entries >= 0) {
+               free(vmlinux_path[vmlinux_path__nr_entries]);
+               vmlinux_path[vmlinux_path__nr_entries] = NULL;
+       }
+
+       free(vmlinux_path);
+       vmlinux_path = NULL;
 }
 
+static int vmlinux_path__init(void)
+{
+       struct utsname uts;
+       char bf[PATH_MAX];
+
+       if (uname(&uts) < 0)
+               return -1;
+
+       vmlinux_path = malloc(sizeof(char *) * 5);
+       if (vmlinux_path == NULL)
+               return -1;
+
+       vmlinux_path[vmlinux_path__nr_entries] = strdup("vmlinux");
+       if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
+               goto out_fail;
+       ++vmlinux_path__nr_entries;
+       vmlinux_path[vmlinux_path__nr_entries] = strdup("/boot/vmlinux");
+       if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
+               goto out_fail;
+       ++vmlinux_path__nr_entries;
+       snprintf(bf, sizeof(bf), "/boot/vmlinux-%s", uts.release);
+       vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
+       if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
+               goto out_fail;
+       ++vmlinux_path__nr_entries;
+       snprintf(bf, sizeof(bf), "/lib/modules/%s/build/vmlinux", uts.release);
+       vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
+       if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
+               goto out_fail;
+       ++vmlinux_path__nr_entries;
+       snprintf(bf, sizeof(bf), "/usr/lib/debug/lib/modules/%s/vmlinux",
+                uts.release);
+       vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
+       if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
+               goto out_fail;
+       ++vmlinux_path__nr_entries;
+
+       return 0;
+
+out_fail:
+       vmlinux_path__exit();
+       return -1;
+}
 
-void symbol__init(void)
+int symbol__init(struct symbol_conf *conf)
 {
+       const struct symbol_conf *pconf = conf ?: &symbol_conf__defaults;
+
        elf_version(EV_CURRENT);
+       symbol__priv_size = pconf->priv_size;
+       thread__init(kthread, 0);
+
+       if (pconf->try_vmlinux_path && vmlinux_path__init() < 0)
+               return -1;
+
+       if (thread__create_kernel_map(kthread, pconf->vmlinux_name) < 0) {
+               vmlinux_path__exit();
+               return -1;
+       }
+
+       kthread->use_modules = pconf->use_modules;
+       if (pconf->use_modules && thread__create_module_maps(kthread) < 0)
+               pr_debug("Failed to load list of modules in use, "
+                        "continuing...\n");
+       /*
+        * Now that we have all the maps created, just set the ->end of them:
+        */
+       thread__fixup_maps_end(kthread);
+       return 0;
 }
index 829da9e..17003ef 100644 (file)
@@ -1,11 +1,11 @@
-#ifndef _PERF_SYMBOL_
-#define _PERF_SYMBOL_ 1
+#ifndef __PERF_SYMBOL
+#define __PERF_SYMBOL 1
 
 #include <linux/types.h>
+#include <stdbool.h>
 #include "types.h"
 #include <linux/list.h>
 #include <linux/rbtree.h>
-#include "module.h"
 #include "event.h"
 
 #ifdef HAVE_CPLUS_DEMANGLE
@@ -46,57 +46,75 @@ struct symbol {
        struct rb_node  rb_node;
        u64             start;
        u64             end;
-       u64             obj_start;
-       u64             hist_sum;
-       u64             *hist;
-       struct module   *module;
-       void            *priv;
        char            name[0];
 };
 
+struct symbol_conf {
+       unsigned short  priv_size;
+       bool            try_vmlinux_path,
+                       use_modules;
+       const char      *vmlinux_name;
+};
+
+extern unsigned int symbol__priv_size;
+
+static inline void *symbol__priv(struct symbol *self)
+{
+       return ((void *)self) - symbol__priv_size;
+}
+
+struct addr_location {
+       struct thread *thread;
+       struct map    *map;
+       struct symbol *sym;
+       u64           addr;
+       char          level;
+};
+
 struct dso {
        struct list_head node;
-       struct rb_root   syms;
-       struct symbol    *(*find_symbol)(struct dso *, u64 ip);
-       unsigned int     sym_priv_size;
-       unsigned char    adjust_symbols;
-       unsigned char    slen_calculated;
+       struct rb_root   symbols[MAP__NR_TYPES];
+       struct symbol    *(*find_symbol)(struct dso *self,
+                                        enum map_type type, u64 addr);
+       u8               adjust_symbols:1;
+       u8               slen_calculated:1;
+       u8               has_build_id:1;
+       u8               kernel:1;
        unsigned char    origin;
+       u8               loaded;
+       u8               build_id[BUILD_ID_SIZE];
+       u16              long_name_len;
+       const char       *short_name;
+       char             *long_name;
        char             name[0];
 };
 
-extern const char *sym_hist_filter;
-
-typedef int (*symbol_filter_t)(struct dso *self, struct symbol *sym);
-
-struct dso *dso__new(const char *name, unsigned int sym_priv_size);
+struct dso *dso__new(const char *name);
 void dso__delete(struct dso *self);
 
-static inline void *dso__sym_priv(struct dso *self, struct symbol *sym)
-{
-       return ((void *)sym) - self->sym_priv_size;
-}
-
-struct symbol *dso__find_symbol(struct dso *self, u64 ip);
+bool dso__loaded(const struct dso *self, enum map_type type);
 
-int dso__load_kernel(struct dso *self, const char *vmlinux,
-                    symbol_filter_t filter, int verbose, int modules);
-int dso__load_modules(struct dso *self, symbol_filter_t filter, int verbose);
-int dso__load(struct dso *self, symbol_filter_t filter, int verbose);
 struct dso *dsos__findnew(const char *name);
+int dso__load(struct dso *self, struct map *map, symbol_filter_t filter);
 void dsos__fprintf(FILE *fp);
+size_t dsos__fprintf_buildid(FILE *fp);
 
-size_t dso__fprintf(struct dso *self, FILE *fp);
+size_t dso__fprintf_buildid(struct dso *self, FILE *fp);
+size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp);
 char dso__symtab_origin(const struct dso *self);
+void dso__set_build_id(struct dso *self, void *build_id);
+
+int filename__read_build_id(const char *filename, void *bf, size_t size);
+int sysfs__read_build_id(const char *filename, void *bf, size_t size);
+bool dsos__read_build_ids(void);
+int build_id__sprintf(u8 *self, int len, char *bf);
 
-int load_kernel(void);
+size_t kernel_maps__fprintf(FILE *fp);
 
-void symbol__init(void);
+int symbol__init(struct symbol_conf *conf);
 
-extern struct list_head dsos;
-extern struct dso *kernel_dso;
+struct thread;
+struct thread *kthread;
+extern struct list_head dsos__user, dsos__kernel;
 extern struct dso *vdso;
-extern struct dso *hypervisor_dso;
-extern const char *vmlinux_name;
-extern int   modules;
-#endif /* _PERF_SYMBOL_ */
+#endif /* __PERF_SYMBOL */
index 45efb5d..603f561 100644 (file)
@@ -6,16 +6,29 @@
 #include "util.h"
 #include "debug.h"
 
+static struct rb_root threads;
+static struct thread *last_match;
+
+void thread__init(struct thread *self, pid_t pid)
+{
+       int i;
+       self->pid = pid;
+       self->comm = NULL;
+       for (i = 0; i < MAP__NR_TYPES; ++i) {
+               self->maps[i] = RB_ROOT;
+               INIT_LIST_HEAD(&self->removed_maps[i]);
+       }
+}
+
 static struct thread *thread__new(pid_t pid)
 {
-       struct thread *self = calloc(1, sizeof(*self));
+       struct thread *self = zalloc(sizeof(*self));
 
        if (self != NULL) {
-               self->pid = pid;
+               thread__init(self, pid);
                self->comm = malloc(32);
                if (self->comm)
                        snprintf(self->comm, 32, ":%d", self->pid);
-               INIT_LIST_HEAD(&self->maps);
        }
 
        return self;
@@ -29,21 +42,84 @@ int thread__set_comm(struct thread *self, const char *comm)
        return self->comm ? 0 : -ENOMEM;
 }
 
-static size_t thread__fprintf(struct thread *self, FILE *fp)
+int thread__comm_len(struct thread *self)
+{
+       if (!self->comm_len) {
+               if (!self->comm)
+                       return 0;
+               self->comm_len = strlen(self->comm);
+       }
+
+       return self->comm_len;
+}
+
+static const char *map_type__name[MAP__NR_TYPES] = {
+       [MAP__FUNCTION] = "Functions",
+};
+
+static size_t __thread__fprintf_maps(struct thread *self,
+                                    enum map_type type, FILE *fp)
+{
+       size_t printed = fprintf(fp, "%s:\n", map_type__name[type]);
+       struct rb_node *nd;
+
+       for (nd = rb_first(&self->maps[type]); nd; nd = rb_next(nd)) {
+               struct map *pos = rb_entry(nd, struct map, rb_node);
+               printed += fprintf(fp, "Map:");
+               printed += map__fprintf(pos, fp);
+               if (verbose > 1) {
+                       printed += dso__fprintf(pos->dso, type, fp);
+                       printed += fprintf(fp, "--\n");
+               }
+       }
+
+       return printed;
+}
+
+size_t thread__fprintf_maps(struct thread *self, FILE *fp)
+{
+       size_t printed = 0, i;
+       for (i = 0; i < MAP__NR_TYPES; ++i)
+               printed += __thread__fprintf_maps(self, i, fp);
+       return printed;
+}
+
+static size_t __thread__fprintf_removed_maps(struct thread *self,
+                                            enum map_type type, FILE *fp)
 {
        struct map *pos;
-       size_t ret = fprintf(fp, "Thread %d %s\n", self->pid, self->comm);
+       size_t printed = 0;
+
+       list_for_each_entry(pos, &self->removed_maps[type], node) {
+               printed += fprintf(fp, "Map:");
+               printed += map__fprintf(pos, fp);
+               if (verbose > 1) {
+                       printed += dso__fprintf(pos->dso, type, fp);
+                       printed += fprintf(fp, "--\n");
+               }
+       }
+       return printed;
+}
 
-       list_for_each_entry(pos, &self->maps, node)
-               ret += map__fprintf(pos, fp);
+static size_t thread__fprintf_removed_maps(struct thread *self, FILE *fp)
+{
+       size_t printed = 0, i;
+       for (i = 0; i < MAP__NR_TYPES; ++i)
+               printed += __thread__fprintf_removed_maps(self, i, fp);
+       return printed;
+}
 
-       return ret;
+static size_t thread__fprintf(struct thread *self, FILE *fp)
+{
+       size_t printed = fprintf(fp, "Thread %d %s\n", self->pid, self->comm);
+       printed += thread__fprintf_removed_maps(self, fp);
+       printed += fprintf(fp, "Removed maps:\n");
+       return printed + thread__fprintf_removed_maps(self, fp);
 }
 
-struct thread *
-threads__findnew(pid_t pid, struct rb_root *threads, struct thread **last_match)
+struct thread *threads__findnew(pid_t pid)
 {
-       struct rb_node **p = &threads->rb_node;
+       struct rb_node **p = &threads.rb_node;
        struct rb_node *parent = NULL;
        struct thread *th;
 
@@ -52,15 +128,15 @@ threads__findnew(pid_t pid, struct rb_root *threads, struct thread **last_match)
         * so most of the time we dont have to look up
         * the full rbtree:
         */
-       if (*last_match && (*last_match)->pid == pid)
-               return *last_match;
+       if (last_match && last_match->pid == pid)
+               return last_match;
 
        while (*p != NULL) {
                parent = *p;
                th = rb_entry(parent, struct thread, rb_node);
 
                if (th->pid == pid) {
-                       *last_match = th;
+                       last_match = th;
                        return th;
                }
 
@@ -73,17 +149,16 @@ threads__findnew(pid_t pid, struct rb_root *threads, struct thread **last_match)
        th = thread__new(pid);
        if (th != NULL) {
                rb_link_node(&th->rb_node, parent, p);
-               rb_insert_color(&th->rb_node, threads);
-               *last_match = th;
+               rb_insert_color(&th->rb_node, &threads);
+               last_match = th;
        }
 
        return th;
 }
 
-struct thread *
-register_idle_thread(struct rb_root *threads, struct thread **last_match)
+struct thread *register_idle_thread(void)
 {
-       struct thread *thread = threads__findnew(0, threads, last_match);
+       struct thread *thread = threads__findnew(0);
 
        if (!thread || thread__set_comm(thread, "swapper")) {
                fprintf(stderr, "problem inserting idle task.\n");
@@ -93,79 +168,116 @@ register_idle_thread(struct rb_root *threads, struct thread **last_match)
        return thread;
 }
 
-void thread__insert_map(struct thread *self, struct map *map)
+static void thread__remove_overlappings(struct thread *self, struct map *map)
 {
-       struct map *pos, *tmp;
+       struct rb_root *root = &self->maps[map->type];
+       struct rb_node *next = rb_first(root);
 
-       list_for_each_entry_safe(pos, tmp, &self->maps, node) {
-               if (map__overlap(pos, map)) {
-                       if (verbose >= 2) {
-                               printf("overlapping maps:\n");
-                               map__fprintf(map, stdout);
-                               map__fprintf(pos, stdout);
-                       }
+       while (next) {
+               struct map *pos = rb_entry(next, struct map, rb_node);
+               next = rb_next(&pos->rb_node);
 
-                       if (map->start <= pos->start && map->end > pos->start)
-                               pos->start = map->end;
+               if (!map__overlap(pos, map))
+                       continue;
 
-                       if (map->end >= pos->end && map->start < pos->end)
-                               pos->end = map->start;
+               if (verbose >= 2) {
+                       fputs("overlapping maps:\n", stderr);
+                       map__fprintf(map, stderr);
+                       map__fprintf(pos, stderr);
+               }
 
-                       if (verbose >= 2) {
-                               printf("after collision:\n");
-                               map__fprintf(pos, stdout);
-                       }
+               rb_erase(&pos->rb_node, root);
+               /*
+                * We may have references to this map, for instance in some
+                * hist_entry instances, so just move them to a separate
+                * list.
+                */
+               list_add_tail(&pos->node, &self->removed_maps[map->type]);
+       }
+}
 
-                       if (pos->start >= pos->end) {
-                               list_del_init(&pos->node);
-                               free(pos);
-                       }
-               }
+void maps__insert(struct rb_root *maps, struct map *map)
+{
+       struct rb_node **p = &maps->rb_node;
+       struct rb_node *parent = NULL;
+       const u64 ip = map->start;
+       struct map *m;
+
+       while (*p != NULL) {
+               parent = *p;
+               m = rb_entry(parent, struct map, rb_node);
+               if (ip < m->start)
+                       p = &(*p)->rb_left;
+               else
+                       p = &(*p)->rb_right;
        }
 
-       list_add_tail(&map->node, &self->maps);
+       rb_link_node(&map->rb_node, parent, p);
+       rb_insert_color(&map->rb_node, maps);
 }
 
-int thread__fork(struct thread *self, struct thread *parent)
+struct map *maps__find(struct rb_root *maps, u64 ip)
 {
-       struct map *map;
+       struct rb_node **p = &maps->rb_node;
+       struct rb_node *parent = NULL;
+       struct map *m;
 
-       if (self->comm)
-               free(self->comm);
-       self->comm = strdup(parent->comm);
-       if (!self->comm)
-               return -ENOMEM;
+       while (*p != NULL) {
+               parent = *p;
+               m = rb_entry(parent, struct map, rb_node);
+               if (ip < m->start)
+                       p = &(*p)->rb_left;
+               else if (ip > m->end)
+                       p = &(*p)->rb_right;
+               else
+                       return m;
+       }
+
+       return NULL;
+}
+
+void thread__insert_map(struct thread *self, struct map *map)
+{
+       thread__remove_overlappings(self, map);
+       maps__insert(&self->maps[map->type], map);
+}
 
-       list_for_each_entry(map, &parent->maps, node) {
+static int thread__clone_maps(struct thread *self, struct thread *parent,
+                             enum map_type type)
+{
+       struct rb_node *nd;
+       for (nd = rb_first(&parent->maps[type]); nd; nd = rb_next(nd)) {
+               struct map *map = rb_entry(nd, struct map, rb_node);
                struct map *new = map__clone(map);
-               if (!new)
+               if (new == NULL)
                        return -ENOMEM;
                thread__insert_map(self, new);
        }
-
        return 0;
 }
 
-struct map *thread__find_map(struct thread *self, u64 ip)
+int thread__fork(struct thread *self, struct thread *parent)
 {
-       struct map *pos;
+       int i;
 
-       if (self == NULL)
-               return NULL;
-
-       list_for_each_entry(pos, &self->maps, node)
-               if (ip >= pos->start && ip <= pos->end)
-                       return pos;
+       if (self->comm)
+               free(self->comm);
+       self->comm = strdup(parent->comm);
+       if (!self->comm)
+               return -ENOMEM;
 
-       return NULL;
+       for (i = 0; i < MAP__NR_TYPES; ++i)
+               if (thread__clone_maps(self, parent, i) < 0)
+                       return -ENOMEM;
+       return 0;
 }
 
-size_t threads__fprintf(FILE *fp, struct rb_root *threads)
+size_t threads__fprintf(FILE *fp)
 {
        size_t ret = 0;
        struct rb_node *nd;
 
-       for (nd = rb_first(threads); nd; nd = rb_next(nd)) {
+       for (nd = rb_first(&threads); nd; nd = rb_next(nd)) {
                struct thread *pos = rb_entry(nd, struct thread, rb_node);
 
                ret += thread__fprintf(pos, fp);
@@ -173,3 +285,15 @@ size_t threads__fprintf(FILE *fp, struct rb_root *threads)
 
        return ret;
 }
+
+struct symbol *thread__find_symbol(struct thread *self,
+                                  enum map_type type, u64 addr,
+                                  symbol_filter_t filter)
+{
+       struct map *map = thread__find_map(self, type, addr);
+
+       if (map != NULL)
+               return map__find_symbol(map, map->map_ip(map, addr), filter);
+
+       return NULL;
+}
index 32aea3c..686d6e9 100644 (file)
@@ -1,22 +1,56 @@
+#ifndef __PERF_THREAD_H
+#define __PERF_THREAD_H
+
 #include <linux/rbtree.h>
-#include <linux/list.h>
 #include <unistd.h>
 #include "symbol.h"
 
 struct thread {
        struct rb_node          rb_node;
-       struct list_head        maps;
+       struct rb_root          maps[MAP__NR_TYPES];
+       struct list_head        removed_maps[MAP__NR_TYPES];
        pid_t                   pid;
+       bool                    use_modules;
        char                    shortname[3];
        char                    *comm;
+       int                     comm_len;
 };
 
+void thread__init(struct thread *self, pid_t pid);
 int thread__set_comm(struct thread *self, const char *comm);
-struct thread *
-threads__findnew(pid_t pid, struct rb_root *threads, struct thread **last_match);
-struct thread *
-register_idle_thread(struct rb_root *threads, struct thread **last_match);
+int thread__comm_len(struct thread *self);
+struct thread *threads__findnew(pid_t pid);
+struct thread *register_idle_thread(void);
 void thread__insert_map(struct thread *self, struct map *map);
 int thread__fork(struct thread *self, struct thread *parent);
-struct map *thread__find_map(struct thread *self, u64 ip);
-size_t threads__fprintf(FILE *fp, struct rb_root *threads);
+size_t thread__fprintf_maps(struct thread *self, FILE *fp);
+size_t threads__fprintf(FILE *fp);
+
+void maps__insert(struct rb_root *maps, struct map *map);
+struct map *maps__find(struct rb_root *maps, u64 addr);
+
+static inline struct map *thread__find_map(struct thread *self,
+                                          enum map_type type, u64 addr)
+{
+       return self ? maps__find(&self->maps[type], addr) : NULL;
+}
+
+static inline void __thread__insert_map(struct thread *self, struct map *map)
+{
+        maps__insert(&self->maps[map->type], map);
+}
+
+void thread__find_addr_location(struct thread *self, u8 cpumode,
+                               enum map_type type, u64 addr,
+                               struct addr_location *al,
+                               symbol_filter_t filter);
+struct symbol *thread__find_symbol(struct thread *self,
+                                  enum map_type type, u64 addr,
+                                  symbol_filter_t filter);
+
+static inline struct symbol *
+thread__find_function(struct thread *self, u64 addr, symbol_filter_t filter)
+{
+       return thread__find_symbol(self, MAP__FUNCTION, addr, filter);
+}
+#endif /* __PERF_THREAD_H */
index af4b057..cace355 100644 (file)
 #include <ctype.h>
 #include <errno.h>
 #include <stdbool.h>
+#include <linux/kernel.h>
 
 #include "../perf.h"
 #include "trace-event.h"
 
-
 #define VERSION "0.5"
 
 #define _STR(x) #x
@@ -483,27 +483,33 @@ static struct tracepoint_path *
 get_tracepoints_path(struct perf_event_attr *pattrs, int nb_events)
 {
        struct tracepoint_path path, *ppath = &path;
-       int i;
+       int i, nr_tracepoints = 0;
 
        for (i = 0; i < nb_events; i++) {
                if (pattrs[i].type != PERF_TYPE_TRACEPOINT)
                        continue;
+               ++nr_tracepoints;
                ppath->next = tracepoint_id_to_path(pattrs[i].config);
                if (!ppath->next)
                        die("%s\n", "No memory to alloc tracepoints list");
                ppath = ppath->next;
        }
 
-       return path.next;
+       return nr_tracepoints > 0 ? path.next : NULL;
 }
-void read_tracing_data(struct perf_event_attr *pattrs, int nb_events)
+
+int read_tracing_data(int fd, struct perf_event_attr *pattrs, int nb_events)
 {
        char buf[BUFSIZ];
-       struct tracepoint_path *tps;
+       struct tracepoint_path *tps = get_tracepoints_path(pattrs, nb_events);
+
+       /*
+        * What? No tracepoints? No sense writing anything here, bail out.
+        */
+       if (tps == NULL)
+               return -1;
 
-       output_fd = open(output_file, O_WRONLY | O_CREAT | O_TRUNC | O_LARGEFILE, 0644);
-       if (output_fd < 0)
-               die("creating file '%s'", output_file);
+       output_fd = fd;
 
        buf[0] = 23;
        buf[1] = 8;
@@ -530,11 +536,11 @@ void read_tracing_data(struct perf_event_attr *pattrs, int nb_events)
        page_size = getpagesize();
        write_or_die(&page_size, 4);
 
-       tps = get_tracepoints_path(pattrs, nb_events);
-
        read_header_files();
        read_ftrace_files(tps);
        read_event_files(tps);
        read_proc_kallsyms();
        read_ftrace_printk();
+
+       return 0;
 }
index 55c9659..0302405 100644 (file)
@@ -40,12 +40,19 @@ int header_page_size_size;
 int header_page_data_offset;
 int header_page_data_size;
 
+int latency_format;
+
 static char *input_buf;
 static unsigned long long input_buf_ptr;
 static unsigned long long input_buf_siz;
 
 static int cpus;
 static int long_size;
+static int is_flag_field;
+static int is_symbolic_field;
+
+static struct format_field *
+find_any_field(struct event *event, const char *name);
 
 static void init_input_buf(char *buf, unsigned long long size)
 {
@@ -284,18 +291,19 @@ void parse_ftrace_printk(char *file, unsigned int size __unused)
        char *line;
        char *next = NULL;
        char *addr_str;
-       int ret;
        int i;
 
        line = strtok_r(file, "\n", &next);
        while (line) {
+               addr_str = strsep(&line, ":");
+               if (!line) {
+                       warning("error parsing print strings");
+                       break;
+               }
                item = malloc_or_die(sizeof(*item));
-               ret = sscanf(line, "%as : %as",
-                            (float *)(void *)&addr_str, /* workaround gcc warning */
-                            (float *)(void *)&item->printk);
                item->addr = strtoull(addr_str, NULL, 16);
-               free(addr_str);
-
+               /* fmt still has a space, skip it */
+               item->printk = strdup(line+1);
                item->next = list;
                list = item;
                line = strtok_r(NULL, "\n", &next);
@@ -522,7 +530,10 @@ static enum event_type __read_token(char **tok)
                        last_ch = ch;
                        ch = __read_char();
                        buf[i++] = ch;
-               } while (ch != quote_ch && last_ch != '\\');
+                       /* the '\' '\' will cancel itself */
+                       if (ch == '\\' && last_ch == '\\')
+                               last_ch = 0;
+               } while (ch != quote_ch || last_ch == '\\');
                /* remove the last quote */
                i--;
                goto out;
@@ -610,7 +621,7 @@ static enum event_type read_token_item(char **tok)
 static int test_type(enum event_type type, enum event_type expect)
 {
        if (type != expect) {
-               die("Error: expected type %d but read %d",
+               warning("Error: expected type %d but read %d",
                    expect, type);
                return -1;
        }
@@ -621,13 +632,13 @@ static int test_type_token(enum event_type type, char *token,
                    enum event_type expect, const char *expect_tok)
 {
        if (type != expect) {
-               die("Error: expected type %d but read %d",
+               warning("Error: expected type %d but read %d",
                    expect, type);
                return -1;
        }
 
        if (strcmp(token, expect_tok) != 0) {
-               die("Error: expected '%s' but read '%s'",
+               warning("Error: expected '%s' but read '%s'",
                    expect_tok, token);
                return -1;
        }
@@ -665,7 +676,7 @@ static int __read_expected(enum event_type expect, const char *str, int newline_
 
        free_token(token);
 
-       return 0;
+       return ret;
 }
 
 static int read_expected(enum event_type expect, const char *str)
@@ -682,10 +693,10 @@ static char *event_read_name(void)
 {
        char *token;
 
-       if (read_expected(EVENT_ITEM, (char *)"name") < 0)
+       if (read_expected(EVENT_ITEM, "name") < 0)
                return NULL;
 
-       if (read_expected(EVENT_OP, (char *)":") < 0)
+       if (read_expected(EVENT_OP, ":") < 0)
                return NULL;
 
        if (read_expect_type(EVENT_ITEM, &token) < 0)
@@ -703,10 +714,10 @@ static int event_read_id(void)
        char *token;
        int id;
 
-       if (read_expected_item(EVENT_ITEM, (char *)"ID") < 0)
+       if (read_expected_item(EVENT_ITEM, "ID") < 0)
                return -1;
 
-       if (read_expected(EVENT_OP, (char *)":") < 0)
+       if (read_expected(EVENT_OP, ":") < 0)
                return -1;
 
        if (read_expect_type(EVENT_ITEM, &token) < 0)
@@ -721,6 +732,24 @@ static int event_read_id(void)
        return -1;
 }
 
+static int field_is_string(struct format_field *field)
+{
+       if ((field->flags & FIELD_IS_ARRAY) &&
+           (!strstr(field->type, "char") || !strstr(field->type, "u8") ||
+            !strstr(field->type, "s8")))
+               return 1;
+
+       return 0;
+}
+
+static int field_is_dynamic(struct format_field *field)
+{
+       if (!strcmp(field->type, "__data_loc"))
+               return 1;
+
+       return 0;
+}
+
 static int event_read_fields(struct event *event, struct format_field **fields)
 {
        struct format_field *field = NULL;
@@ -738,7 +767,7 @@ static int event_read_fields(struct event *event, struct format_field **fields)
 
                count++;
 
-               if (test_type_token(type, token, EVENT_ITEM, (char *)"field"))
+               if (test_type_token(type, token, EVENT_ITEM, "field"))
                        goto fail;
                free_token(token);
 
@@ -753,7 +782,7 @@ static int event_read_fields(struct event *event, struct format_field **fields)
                        type = read_token(&token);
                }
 
-               if (test_type_token(type, token, EVENT_OP, (char *)":") < 0)
+               if (test_type_token(type, token, EVENT_OP, ":") < 0)
                        return -1;
 
                if (read_expect_type(EVENT_ITEM, &token) < 0)
@@ -865,14 +894,20 @@ static int event_read_fields(struct event *event, struct format_field **fields)
                        free(brackets);
                }
 
-               if (test_type_token(type, token,  EVENT_OP, (char *)";"))
+               if (field_is_string(field)) {
+                       field->flags |= FIELD_IS_STRING;
+                       if (field_is_dynamic(field))
+                               field->flags |= FIELD_IS_DYNAMIC;
+               }
+
+               if (test_type_token(type, token,  EVENT_OP, ";"))
                        goto fail;
                free_token(token);
 
-               if (read_expected(EVENT_ITEM, (char *)"offset") < 0)
+               if (read_expected(EVENT_ITEM, "offset") < 0)
                        goto fail_expect;
 
-               if (read_expected(EVENT_OP, (char *)":") < 0)
+               if (read_expected(EVENT_OP, ":") < 0)
                        goto fail_expect;
 
                if (read_expect_type(EVENT_ITEM, &token))
@@ -880,13 +915,13 @@ static int event_read_fields(struct event *event, struct format_field **fields)
                field->offset = strtoul(token, NULL, 0);
                free_token(token);
 
-               if (read_expected(EVENT_OP, (char *)";") < 0)
+               if (read_expected(EVENT_OP, ";") < 0)
                        goto fail_expect;
 
-               if (read_expected(EVENT_ITEM, (char *)"size") < 0)
+               if (read_expected(EVENT_ITEM, "size") < 0)
                        goto fail_expect;
 
-               if (read_expected(EVENT_OP, (char *)":") < 0)
+               if (read_expected(EVENT_OP, ":") < 0)
                        goto fail_expect;
 
                if (read_expect_type(EVENT_ITEM, &token))
@@ -894,11 +929,34 @@ static int event_read_fields(struct event *event, struct format_field **fields)
                field->size = strtoul(token, NULL, 0);
                free_token(token);
 
-               if (read_expected(EVENT_OP, (char *)";") < 0)
+               if (read_expected(EVENT_OP, ";") < 0)
                        goto fail_expect;
 
-               if (read_expect_type(EVENT_NEWLINE, &token) < 0)
-                       goto fail;
+               type = read_token(&token);
+               if (type != EVENT_NEWLINE) {
+                       /* newer versions of the kernel have a "signed" type */
+                       if (test_type_token(type, token, EVENT_ITEM, "signed"))
+                               goto fail;
+
+                       free_token(token);
+
+                       if (read_expected(EVENT_OP, ":") < 0)
+                               goto fail_expect;
+
+                       if (read_expect_type(EVENT_ITEM, &token))
+                               goto fail;
+
+                       if (strtoul(token, NULL, 0))
+                               field->flags |= FIELD_IS_SIGNED;
+
+                       free_token(token);
+                       if (read_expected(EVENT_OP, ";") < 0)
+                               goto fail_expect;
+
+                       if (read_expect_type(EVENT_NEWLINE, &token))
+                               goto fail;
+               }
+
                free_token(token);
 
                *fields = field;
@@ -921,10 +979,10 @@ static int event_read_format(struct event *event)
        char *token;
        int ret;
 
-       if (read_expected_item(EVENT_ITEM, (char *)"format") < 0)
+       if (read_expected_item(EVENT_ITEM, "format") < 0)
                return -1;
 
-       if (read_expected(EVENT_OP, (char *)":") < 0)
+       if (read_expected(EVENT_OP, ":") < 0)
                return -1;
 
        if (read_expect_type(EVENT_NEWLINE, &token))
@@ -984,7 +1042,7 @@ process_cond(struct event *event, struct print_arg *top, char **tok)
 
        *tok = NULL;
        type = process_arg(event, left, &token);
-       if (test_type_token(type, token, EVENT_OP, (char *)":"))
+       if (test_type_token(type, token, EVENT_OP, ":"))
                goto out_free;
 
        arg->op.op = token;
@@ -1004,6 +1062,35 @@ out_free:
        return EVENT_ERROR;
 }
 
+static enum event_type
+process_array(struct event *event, struct print_arg *top, char **tok)
+{
+       struct print_arg *arg;
+       enum event_type type;
+       char *token = NULL;
+
+       arg = malloc_or_die(sizeof(*arg));
+       memset(arg, 0, sizeof(*arg));
+
+       *tok = NULL;
+       type = process_arg(event, arg, &token);
+       if (test_type_token(type, token, EVENT_OP, "]"))
+               goto out_free;
+
+       top->op.right = arg;
+
+       free_token(token);
+       type = read_token_item(&token);
+       *tok = token;
+
+       return type;
+
+out_free:
+       free_token(*tok);
+       free_arg(arg);
+       return EVENT_ERROR;
+}
+
 static int get_op_prio(char *op)
 {
        if (!op[1]) {
@@ -1128,6 +1215,8 @@ process_op(struct event *event, struct print_arg *arg, char **tok)
                   strcmp(token, "*") == 0 ||
                   strcmp(token, "^") == 0 ||
                   strcmp(token, "/") == 0 ||
+                  strcmp(token, "<") == 0 ||
+                  strcmp(token, ">") == 0 ||
                   strcmp(token, "==") == 0 ||
                   strcmp(token, "!=") == 0) {
 
@@ -1144,17 +1233,46 @@ process_op(struct event *event, struct print_arg *arg, char **tok)
 
                right = malloc_or_die(sizeof(*right));
 
-               type = process_arg(event, right, tok);
+               type = read_token_item(&token);
+               *tok = token;
+
+               /* could just be a type pointer */
+               if ((strcmp(arg->op.op, "*") == 0) &&
+                   type == EVENT_DELIM && (strcmp(token, ")") == 0)) {
+                       if (left->type != PRINT_ATOM)
+                               die("bad pointer type");
+                       left->atom.atom = realloc(left->atom.atom,
+                                           sizeof(left->atom.atom) + 3);
+                       strcat(left->atom.atom, " *");
+                       *arg = *left;
+                       free(arg);
+
+                       return type;
+               }
+
+               type = process_arg_token(event, right, tok, type);
 
                arg->op.right = right;
 
+       } else if (strcmp(token, "[") == 0) {
+
+               left = malloc_or_die(sizeof(*left));
+               *left = *arg;
+
+               arg->type = PRINT_OP;
+               arg->op.op = token;
+               arg->op.left = left;
+
+               arg->op.prio = 0;
+               type = process_array(event, arg, tok);
+
        } else {
-               die("unknown op '%s'", token);
+               warning("unknown op '%s'", token);
+               event->flags |= EVENT_FL_FAILED;
                /* the arg is now the left side */
                return EVENT_NONE;
        }
 
-
        if (type == EVENT_OP) {
                int prio;
 
@@ -1178,7 +1296,7 @@ process_entry(struct event *event __unused, struct print_arg *arg,
        char *field;
        char *token;
 
-       if (read_expected(EVENT_OP, (char *)"->") < 0)
+       if (read_expected(EVENT_OP, "->") < 0)
                return EVENT_ERROR;
 
        if (read_expect_type(EVENT_ITEM, &token) < 0)
@@ -1188,6 +1306,16 @@ process_entry(struct event *event __unused, struct print_arg *arg,
        arg->type = PRINT_FIELD;
        arg->field.name = field;
 
+       if (is_flag_field) {
+               arg->field.field = find_any_field(event, arg->field.name);
+               arg->field.field->flags |= FIELD_IS_FLAG;
+               is_flag_field = 0;
+       } else if (is_symbolic_field) {
+               arg->field.field = find_any_field(event, arg->field.name);
+               arg->field.field->flags |= FIELD_IS_SYMBOLIC;
+               is_symbolic_field = 0;
+       }
+
        type = read_token(&token);
        *tok = token;
 
@@ -1338,14 +1466,14 @@ process_fields(struct event *event, struct print_flag_sym **list, char **tok)
        do {
                free_token(token);
                type = read_token_item(&token);
-               if (test_type_token(type, token, EVENT_OP, (char *)"{"))
+               if (test_type_token(type, token, EVENT_OP, "{"))
                        break;
 
                arg = malloc_or_die(sizeof(*arg));
 
                free_token(token);
                type = process_arg(event, arg, &token);
-               if (test_type_token(type, token, EVENT_DELIM, (char *)","))
+               if (test_type_token(type, token, EVENT_DELIM, ","))
                        goto out_free;
 
                field = malloc_or_die(sizeof(*field));
@@ -1356,7 +1484,7 @@ process_fields(struct event *event, struct print_flag_sym **list, char **tok)
 
                free_token(token);
                type = process_arg(event, arg, &token);
-               if (test_type_token(type, token, EVENT_OP, (char *)"}"))
+               if (test_type_token(type, token, EVENT_OP, "}"))
                        goto out_free;
 
                value = arg_eval(arg);
@@ -1391,13 +1519,13 @@ process_flags(struct event *event, struct print_arg *arg, char **tok)
        memset(arg, 0, sizeof(*arg));
        arg->type = PRINT_FLAGS;
 
-       if (read_expected_item(EVENT_DELIM, (char *)"(") < 0)
+       if (read_expected_item(EVENT_DELIM, "(") < 0)
                return EVENT_ERROR;
 
        field = malloc_or_die(sizeof(*field));
 
        type = process_arg(event, field, &token);
-       if (test_type_token(type, token, EVENT_DELIM, (char *)","))
+       if (test_type_token(type, token, EVENT_DELIM, ","))
                goto out_free;
 
        arg->flags.field = field;
@@ -1408,11 +1536,11 @@ process_flags(struct event *event, struct print_arg *arg, char **tok)
                type = read_token_item(&token);
        }
 
-       if (test_type_token(type, token, EVENT_DELIM, (char *)","))
+       if (test_type_token(type, token, EVENT_DELIM, ","))
                goto out_free;
 
        type = process_fields(event, &arg->flags.flags, &token);
-       if (test_type_token(type, token, EVENT_DELIM, (char *)")"))
+       if (test_type_token(type, token, EVENT_DELIM, ")"))
                goto out_free;
 
        free_token(token);
@@ -1434,19 +1562,19 @@ process_symbols(struct event *event, struct print_arg *arg, char **tok)
        memset(arg, 0, sizeof(*arg));
        arg->type = PRINT_SYMBOL;
 
-       if (read_expected_item(EVENT_DELIM, (char *)"(") < 0)
+       if (read_expected_item(EVENT_DELIM, "(") < 0)
                return EVENT_ERROR;
 
        field = malloc_or_die(sizeof(*field));
 
        type = process_arg(event, field, &token);
-       if (test_type_token(type, token, EVENT_DELIM, (char *)","))
+       if (test_type_token(type, token, EVENT_DELIM, ","))
                goto out_free;
 
        arg->symbol.field = field;
 
        type = process_fields(event, &arg->symbol.symbols, &token);
-       if (test_type_token(type, token, EVENT_DELIM, (char *)")"))
+       if (test_type_token(type, token, EVENT_DELIM, ")"))
                goto out_free;
 
        free_token(token);
@@ -1463,7 +1591,6 @@ process_paren(struct event *event, struct print_arg *arg, char **tok)
 {
        struct print_arg *item_arg;
        enum event_type type;
-       int ptr_cast = 0;
        char *token;
 
        type = process_arg(event, arg, &token);
@@ -1471,28 +1598,13 @@ process_paren(struct event *event, struct print_arg *arg, char **tok)
        if (type == EVENT_ERROR)
                return EVENT_ERROR;
 
-       if (type == EVENT_OP) {
-               /* handle the ptr casts */
-               if (!strcmp(token, "*")) {
-                       /*
-                        * FIXME: should we zapp whitespaces before ')' ?
-                        * (may require a peek_token_item())
-                        */
-                       if (__peek_char() == ')') {
-                               ptr_cast = 1;
-                               free_token(token);
-                               type = read_token_item(&token);
-                       }
-               }
-               if (!ptr_cast) {
-                       type = process_op(event, arg, &token);
+       if (type == EVENT_OP)
+               type = process_op(event, arg, &token);
 
-                       if (type == EVENT_ERROR)
-                               return EVENT_ERROR;
-               }
-       }
+       if (type == EVENT_ERROR)
+               return EVENT_ERROR;
 
-       if (test_type_token(type, token, EVENT_DELIM, (char *)")")) {
+       if (test_type_token(type, token, EVENT_DELIM, ")")) {
                free_token(token);
                return EVENT_ERROR;
        }
@@ -1516,13 +1628,6 @@ process_paren(struct event *event, struct print_arg *arg, char **tok)
                item_arg = malloc_or_die(sizeof(*item_arg));
 
                arg->type = PRINT_TYPE;
-               if (ptr_cast) {
-                       char *old = arg->atom.atom;
-
-                       arg->atom.atom = malloc_or_die(strlen(old + 3));
-                       sprintf(arg->atom.atom, "%s *", old);
-                       free(old);
-               }
                arg->typecast.type = arg->atom.atom;
                arg->typecast.item = item_arg;
                type = process_arg_token(event, item_arg, &token, type);
@@ -1540,7 +1645,7 @@ process_str(struct event *event __unused, struct print_arg *arg, char **tok)
        enum event_type type;
        char *token;
 
-       if (read_expected(EVENT_DELIM, (char *)"(") < 0)
+       if (read_expected(EVENT_DELIM, "(") < 0)
                return EVENT_ERROR;
 
        if (read_expect_type(EVENT_ITEM, &token) < 0)
@@ -1550,7 +1655,7 @@ process_str(struct event *event __unused, struct print_arg *arg, char **tok)
        arg->string.string = token;
        arg->string.offset = -1;
 
-       if (read_expected(EVENT_DELIM, (char *)")") < 0)
+       if (read_expected(EVENT_DELIM, ")") < 0)
                return EVENT_ERROR;
 
        type = read_token(&token);
@@ -1578,9 +1683,11 @@ process_arg_token(struct event *event, struct print_arg *arg,
                        type = process_entry(event, arg, &token);
                } else if (strcmp(token, "__print_flags") == 0) {
                        free_token(token);
+                       is_flag_field = 1;
                        type = process_flags(event, arg, &token);
                } else if (strcmp(token, "__print_symbolic") == 0) {
                        free_token(token);
+                       is_symbolic_field = 1;
                        type = process_symbols(event, arg, &token);
                } else if (strcmp(token, "__get_str") == 0) {
                        free_token(token);
@@ -1637,12 +1744,18 @@ process_arg_token(struct event *event, struct print_arg *arg,
 
 static int event_read_print_args(struct event *event, struct print_arg **list)
 {
-       enum event_type type;
+       enum event_type type = EVENT_ERROR;
        struct print_arg *arg;
        char *token;
        int args = 0;
 
        do {
+               if (type == EVENT_NEWLINE) {
+                       free_token(token);
+                       type = read_token_item(&token);
+                       continue;
+               }
+
                arg = malloc_or_die(sizeof(*arg));
                memset(arg, 0, sizeof(*arg));
 
@@ -1683,18 +1796,19 @@ static int event_read_print(struct event *event)
        char *token;
        int ret;
 
-       if (read_expected_item(EVENT_ITEM, (char *)"print") < 0)
+       if (read_expected_item(EVENT_ITEM, "print") < 0)
                return -1;
 
-       if (read_expected(EVENT_ITEM, (char *)"fmt") < 0)
+       if (read_expected(EVENT_ITEM, "fmt") < 0)
                return -1;
 
-       if (read_expected(EVENT_OP, (char *)":") < 0)
+       if (read_expected(EVENT_OP, ":") < 0)
                return -1;
 
        if (read_expect_type(EVENT_DQUOTE, &token) < 0)
                goto fail;
 
+ concat:
        event->print_fmt.format = token;
        event->print_fmt.args = NULL;
 
@@ -1704,7 +1818,22 @@ static int event_read_print(struct event *event)
        if (type == EVENT_NONE)
                return 0;
 
-       if (test_type_token(type, token, EVENT_DELIM, (char *)","))
+       /* Handle concatination of print lines */
+       if (type == EVENT_DQUOTE) {
+               char *cat;
+
+               cat = malloc_or_die(strlen(event->print_fmt.format) +
+                                   strlen(token) + 1);
+               strcpy(cat, event->print_fmt.format);
+               strcat(cat, token);
+               free_token(token);
+               free_token(event->print_fmt.format);
+               event->print_fmt.format = NULL;
+               token = cat;
+               goto concat;
+       }
+
+       if (test_type_token(type, token, EVENT_DELIM, ","))
                goto fail;
 
        free_token(token);
@@ -1713,7 +1842,7 @@ static int event_read_print(struct event *event)
        if (ret < 0)
                return -1;
 
-       return 0;
+       return ret;
 
  fail:
        free_token(token);
@@ -1759,7 +1888,7 @@ find_any_field(struct event *event, const char *name)
        return find_field(event, name);
 }
 
-static unsigned long long read_size(void *ptr, int size)
+unsigned long long read_size(void *ptr, int size)
 {
        switch (size) {
        case 1:
@@ -1822,37 +1951,67 @@ static int get_common_info(const char *type, int *offset, int *size)
        return 0;
 }
 
-int trace_parse_common_type(void *data)
+static int __parse_common(void *data, int *size, int *offset,
+                         const char *name)
 {
-       static int type_offset;
-       static int type_size;
        int ret;
 
-       if (!type_size) {
-               ret = get_common_info("common_type",
-                                     &type_offset,
-                                     &type_size);
+       if (!*size) {
+               ret = get_common_info(name, offset, size);
                if (ret < 0)
                        return ret;
        }
-       return read_size(data + type_offset, type_size);
+       return read_size(data + *offset, *size);
+}
+
+int trace_parse_common_type(void *data)
+{
+       static int type_offset;
+       static int type_size;
+
+       return __parse_common(data, &type_size, &type_offset,
+                             "common_type");
 }
 
-static int parse_common_pid(void *data)
+int trace_parse_common_pid(void *data)
 {
        static int pid_offset;
        static int pid_size;
+
+       return __parse_common(data, &pid_size, &pid_offset,
+                             "common_pid");
+}
+
+int parse_common_pc(void *data)
+{
+       static int pc_offset;
+       static int pc_size;
+
+       return __parse_common(data, &pc_size, &pc_offset,
+                             "common_preempt_count");
+}
+
+int parse_common_flags(void *data)
+{
+       static int flags_offset;
+       static int flags_size;
+
+       return __parse_common(data, &flags_size, &flags_offset,
+                             "common_flags");
+}
+
+int parse_common_lock_depth(void *data)
+{
+       static int ld_offset;
+       static int ld_size;
        int ret;
 
-       if (!pid_size) {
-               ret = get_common_info("common_pid",
-                                     &pid_offset,
-                                     &pid_size);
-               if (ret < 0)
-                       return ret;
-       }
+       ret = __parse_common(data, &ld_size, &ld_offset,
+                            "common_lock_depth");
+       if (ret < 0)
+               return -1;
 
-       return read_size(data + pid_offset, pid_size);
+       return ret;
 }
 
 struct event *trace_find_event(int id)
@@ -1866,11 +2025,20 @@ struct event *trace_find_event(int id)
        return event;
 }
 
+struct event *trace_find_next_event(struct event *event)
+{
+       if (!event)
+               return event_list;
+
+       return event->next;
+}
+
 static unsigned long long eval_num_arg(void *data, int size,
                                   struct event *event, struct print_arg *arg)
 {
        unsigned long long val = 0;
        unsigned long long left, right;
+       struct print_arg *larg;
 
        switch (arg->type) {
        case PRINT_NULL:
@@ -1897,6 +2065,26 @@ static unsigned long long eval_num_arg(void *data, int size,
                return 0;
                break;
        case PRINT_OP:
+               if (strcmp(arg->op.op, "[") == 0) {
+                       /*
+                        * Arrays are special, since we don't want
+                        * to read the arg as is.
+                        */
+                       if (arg->op.left->type != PRINT_FIELD)
+                               goto default_op; /* oops, all bets off */
+                       larg = arg->op.left;
+                       if (!larg->field.field) {
+                               larg->field.field =
+                                       find_any_field(event, larg->field.name);
+                               if (!larg->field.field)
+                                       die("field %s not found", larg->field.name);
+                       }
+                       right = eval_num_arg(data, size, event, arg->op.right);
+                       val = read_size(data + larg->field.field->offset +
+                                       right * long_size, long_size);
+                       break;
+               }
+ default_op:
                left = eval_num_arg(data, size, event, arg->op.left);
                right = eval_num_arg(data, size, event, arg->op.right);
                switch (arg->op.op[0]) {
@@ -1947,6 +2135,12 @@ static unsigned long long eval_num_arg(void *data, int size,
                                die("unknown op '%s'", arg->op.op);
                        val = left == right;
                        break;
+               case '-':
+                       val = left - right;
+                       break;
+               case '+':
+                       val = left + right;
+                       break;
                default:
                        die("unknown op '%s'", arg->op.op);
                }
@@ -1978,7 +2172,7 @@ static const struct flag flags[] = {
        { "HRTIMER_RESTART", 1 },
 };
 
-static unsigned long long eval_flag(const char *flag)
+unsigned long long eval_flag(const char *flag)
 {
        int i;
 
@@ -2145,8 +2339,9 @@ static struct print_arg *make_bprint_args(char *fmt, void *data, int size, struc
                        case 'u':
                        case 'x':
                        case 'i':
-                               bptr = (void *)(((unsigned long)bptr + (long_size - 1)) &
-                                               ~(long_size - 1));
+                               /* the pointers are always 4 bytes aligned */
+                               bptr = (void *)(((unsigned long)bptr + 3) &
+                                               ~3);
                                switch (ls) {
                                case 0:
                                case 1:
@@ -2270,7 +2465,27 @@ static void pretty_print(void *data, int size, struct event *event)
 
        for (; *ptr; ptr++) {
                ls = 0;
-               if (*ptr == '%') {
+               if (*ptr == '\\') {
+                       ptr++;
+                       switch (*ptr) {
+                       case 'n':
+                               printf("\n");
+                               break;
+                       case 't':
+                               printf("\t");
+                               break;
+                       case 'r':
+                               printf("\r");
+                               break;
+                       case '\\':
+                               printf("\\");
+                               break;
+                       default:
+                               printf("%c", *ptr);
+                               break;
+                       }
+
+               } else if (*ptr == '%') {
                        saveptr = ptr;
                        show_func = 0;
  cont_process:
@@ -2377,6 +2592,41 @@ static inline int log10_cpu(int nb)
        return 1;
 }
 
+static void print_lat_fmt(void *data, int size __unused)
+{
+       unsigned int lat_flags;
+       unsigned int pc;
+       int lock_depth;
+       int hardirq;
+       int softirq;
+
+       lat_flags = parse_common_flags(data);
+       pc = parse_common_pc(data);
+       lock_depth = parse_common_lock_depth(data);
+
+       hardirq = lat_flags & TRACE_FLAG_HARDIRQ;
+       softirq = lat_flags & TRACE_FLAG_SOFTIRQ;
+
+       printf("%c%c%c",
+              (lat_flags & TRACE_FLAG_IRQS_OFF) ? 'd' :
+              (lat_flags & TRACE_FLAG_IRQS_NOSUPPORT) ?
+              'X' : '.',
+              (lat_flags & TRACE_FLAG_NEED_RESCHED) ?
+              'N' : '.',
+              (hardirq && softirq) ? 'H' :
+              hardirq ? 'h' : softirq ? 's' : '.');
+
+       if (pc)
+               printf("%x", pc);
+       else
+               printf(".");
+
+       if (lock_depth < 0)
+               printf(".");
+       else
+               printf("%d", lock_depth);
+}
+
 /* taken from Linux, written by Frederic Weisbecker */
 static void print_graph_cpu(int cpu)
 {
@@ -2452,7 +2702,7 @@ get_return_for_leaf(int cpu, int cur_pid, unsigned long long cur_func,
        if (!(event->flags & EVENT_FL_ISFUNCRET))
                return NULL;
 
-       pid = parse_common_pid(next->data);
+       pid = trace_parse_common_pid(next->data);
        field = find_field(event, "func");
        if (!field)
                die("function return does not have field func");
@@ -2620,6 +2870,11 @@ pretty_print_func_ent(void *data, int size, struct event *event,
 
        printf(" | ");
 
+       if (latency_format) {
+               print_lat_fmt(data, size);
+               printf(" | ");
+       }
+
        field = find_field(event, "func");
        if (!field)
                die("function entry does not have func field");
@@ -2663,6 +2918,11 @@ pretty_print_func_ret(void *data, int size __unused, struct event *event,
 
        printf(" | ");
 
+       if (latency_format) {
+               print_lat_fmt(data, size);
+               printf(" | ");
+       }
+
        field = find_field(event, "rettime");
        if (!field)
                die("can't find rettime in return graph");
@@ -2724,19 +2984,30 @@ void print_event(int cpu, void *data, int size, unsigned long long nsecs,
 
        event = trace_find_event(type);
        if (!event) {
-               printf("ug! no event found for type %d\n", type);
+               warning("ug! no event found for type %d", type);
                return;
        }
 
-       pid = parse_common_pid(data);
+       pid = trace_parse_common_pid(data);
 
        if (event->flags & (EVENT_FL_ISFUNCENT | EVENT_FL_ISFUNCRET))
                return pretty_print_func_graph(data, size, event, cpu,
                                               pid, comm, secs, usecs);
 
-       printf("%16s-%-5d [%03d] %5lu.%09Lu: %s: ",
-              comm, pid,  cpu,
-              secs, nsecs, event->name);
+       if (latency_format) {
+               printf("%8.8s-%-5d %3d",
+                      comm, pid, cpu);
+               print_lat_fmt(data, size);
+       } else
+               printf("%16s-%-5d [%03d]", comm, pid,  cpu);
+
+       printf(" %5lu.%06lu: %s: ", secs, usecs, event->name);
+
+       if (event->flags & EVENT_FL_FAILED) {
+               printf("EVENT '%s' FAILED TO PARSE\n",
+                      event->name);
+               return;
+       }
 
        pretty_print(data, size, event);
        printf("\n");
@@ -2807,46 +3078,71 @@ static void print_args(struct print_arg *args)
        }
 }
 
-static void parse_header_field(char *type,
+static void parse_header_field(const char *field,
                               int *offset, int *size)
 {
        char *token;
+       int type;
 
-       if (read_expected(EVENT_ITEM, (char *)"field") < 0)
+       if (read_expected(EVENT_ITEM, "field") < 0)
                return;
-       if (read_expected(EVENT_OP, (char *)":") < 0)
+       if (read_expected(EVENT_OP, ":") < 0)
                return;
+
        /* type */
        if (read_expect_type(EVENT_ITEM, &token) < 0)
-               return;
+               goto fail;
        free_token(token);
 
-       if (read_expected(EVENT_ITEM, type) < 0)
+       if (read_expected(EVENT_ITEM, field) < 0)
                return;
-       if (read_expected(EVENT_OP, (char *)";") < 0)
+       if (read_expected(EVENT_OP, ";") < 0)
                return;
-       if (read_expected(EVENT_ITEM, (char *)"offset") < 0)
+       if (read_expected(EVENT_ITEM, "offset") < 0)
                return;
-       if (read_expected(EVENT_OP, (char *)":") < 0)
+       if (read_expected(EVENT_OP, ":") < 0)
                return;
        if (read_expect_type(EVENT_ITEM, &token) < 0)
-               return;
+               goto fail;
        *offset = atoi(token);
        free_token(token);
-       if (read_expected(EVENT_OP, (char *)";") < 0)
+       if (read_expected(EVENT_OP, ";") < 0)
                return;
-       if (read_expected(EVENT_ITEM, (char *)"size") < 0)
+       if (read_expected(EVENT_ITEM, "size") < 0)
                return;
-       if (read_expected(EVENT_OP, (char *)":") < 0)
+       if (read_expected(EVENT_OP, ":") < 0)
                return;
        if (read_expect_type(EVENT_ITEM, &token) < 0)
-               return;
+               goto fail;
        *size = atoi(token);
        free_token(token);
-       if (read_expected(EVENT_OP, (char *)";") < 0)
-               return;
-       if (read_expect_type(EVENT_NEWLINE, &token) < 0)
+       if (read_expected(EVENT_OP, ";") < 0)
                return;
+       type = read_token(&token);
+       if (type != EVENT_NEWLINE) {
+               /* newer versions of the kernel have a "signed" type */
+               if (type != EVENT_ITEM)
+                       goto fail;
+
+               if (strcmp(token, "signed") != 0)
+                       goto fail;
+
+               free_token(token);
+
+               if (read_expected(EVENT_OP, ":") < 0)
+                       return;
+
+               if (read_expect_type(EVENT_ITEM, &token))
+                       goto fail;
+
+               free_token(token);
+               if (read_expected(EVENT_OP, ";") < 0)
+                       return;
+
+               if (read_expect_type(EVENT_NEWLINE, &token))
+                       goto fail;
+       }
+ fail:
        free_token(token);
 }
 
@@ -2854,11 +3150,11 @@ int parse_header_page(char *buf, unsigned long size)
 {
        init_input_buf(buf, size);
 
-       parse_header_field((char *)"timestamp", &header_page_ts_offset,
+       parse_header_field("timestamp", &header_page_ts_offset,
                           &header_page_ts_size);
-       parse_header_field((char *)"commit", &header_page_size_offset,
+       parse_header_field("commit", &header_page_size_offset,
                           &header_page_size_size);
-       parse_header_field((char *)"data", &header_page_data_offset,
+       parse_header_field("data", &header_page_data_offset,
                           &header_page_data_size);
 
        return 0;
@@ -2909,6 +3205,9 @@ int parse_ftrace_file(char *buf, unsigned long size)
        if (ret < 0)
                die("failed to read ftrace event print fmt");
 
+       /* New ftrace handles args */
+       if (ret > 0)
+               return 0;
        /*
         * The arguments for ftrace files are parsed by the fields.
         * Set up the fields as their arguments.
@@ -2926,7 +3225,7 @@ int parse_ftrace_file(char *buf, unsigned long size)
        return 0;
 }
 
-int parse_event_file(char *buf, unsigned long size, char *system__unused __unused)
+int parse_event_file(char *buf, unsigned long size, char *sys)
 {
        struct event *event;
        int ret;
@@ -2946,12 +3245,18 @@ int parse_event_file(char *buf, unsigned long size, char *system__unused __unuse
                die("failed to read event id");
 
        ret = event_read_format(event);
-       if (ret < 0)
-               die("failed to read event format");
+       if (ret < 0) {
+               warning("failed to read event format for %s", event->name);
+               goto event_failed;
+       }
 
        ret = event_read_print(event);
-       if (ret < 0)
-               die("failed to read event print fmt");
+       if (ret < 0) {
+               warning("failed to read event print fmt for %s", event->name);
+               goto event_failed;
+       }
+
+       event->system = strdup(sys);
 
 #define PRINT_ARGS 0
        if (PRINT_ARGS && event->print_fmt.args)
@@ -2959,6 +3264,12 @@ int parse_event_file(char *buf, unsigned long size, char *system__unused __unuse
 
        add_event(event);
        return 0;
+
+ event_failed:
+       event->flags |= EVENT_FL_FAILED;
+       /* still add it even if it failed */
+       add_event(event);
+       return -1;
 }
 
 void parse_set_info(int nr_cpus, int long_sz)
diff --git a/tools/perf/util/trace-event-perl.c b/tools/perf/util/trace-event-perl.c
new file mode 100644 (file)
index 0000000..51e833f
--- /dev/null
@@ -0,0 +1,598 @@
+/*
+ * trace-event-perl.  Feed perf trace events to an embedded Perl interpreter.
+ *
+ * Copyright (C) 2009 Tom Zanussi <tzanussi@gmail.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+
+#include "../perf.h"
+#include "util.h"
+#include "trace-event.h"
+#include "trace-event-perl.h"
+
+void xs_init(pTHX);
+
+void boot_Perf__Trace__Context(pTHX_ CV *cv);
+void boot_DynaLoader(pTHX_ CV *cv);
+
+void xs_init(pTHX)
+{
+       const char *file = __FILE__;
+       dXSUB_SYS;
+
+       newXS("Perf::Trace::Context::bootstrap", boot_Perf__Trace__Context,
+             file);
+       newXS("DynaLoader::boot_DynaLoader", boot_DynaLoader, file);
+}
+
+INTERP my_perl;
+
+#define FTRACE_MAX_EVENT                               \
+       ((1 << (sizeof(unsigned short) * 8)) - 1)
+
+struct event *events[FTRACE_MAX_EVENT];
+
+static struct scripting_context *scripting_context;
+
+static char *cur_field_name;
+static int zero_flag_atom;
+
+static void define_symbolic_value(const char *ev_name,
+                                 const char *field_name,
+                                 const char *field_value,
+                                 const char *field_str)
+{
+       unsigned long long value;
+       dSP;
+
+       value = eval_flag(field_value);
+
+       ENTER;
+       SAVETMPS;
+       PUSHMARK(SP);
+
+       XPUSHs(sv_2mortal(newSVpv(ev_name, 0)));
+       XPUSHs(sv_2mortal(newSVpv(field_name, 0)));
+       XPUSHs(sv_2mortal(newSVuv(value)));
+       XPUSHs(sv_2mortal(newSVpv(field_str, 0)));
+
+       PUTBACK;
+       if (get_cv("main::define_symbolic_value", 0))
+               call_pv("main::define_symbolic_value", G_SCALAR);
+       SPAGAIN;
+       PUTBACK;
+       FREETMPS;
+       LEAVE;
+}
+
+static void define_symbolic_values(struct print_flag_sym *field,
+                                  const char *ev_name,
+                                  const char *field_name)
+{
+       define_symbolic_value(ev_name, field_name, field->value, field->str);
+       if (field->next)
+               define_symbolic_values(field->next, ev_name, field_name);
+}
+
+static void define_symbolic_field(const char *ev_name,
+                                 const char *field_name)
+{
+       dSP;
+
+       ENTER;
+       SAVETMPS;
+       PUSHMARK(SP);
+
+       XPUSHs(sv_2mortal(newSVpv(ev_name, 0)));
+       XPUSHs(sv_2mortal(newSVpv(field_name, 0)));
+
+       PUTBACK;
+       if (get_cv("main::define_symbolic_field", 0))
+               call_pv("main::define_symbolic_field", G_SCALAR);
+       SPAGAIN;
+       PUTBACK;
+       FREETMPS;
+       LEAVE;
+}
+
+static void define_flag_value(const char *ev_name,
+                             const char *field_name,
+                             const char *field_value,
+                             const char *field_str)
+{
+       unsigned long long value;
+       dSP;
+
+       value = eval_flag(field_value);
+
+       ENTER;
+       SAVETMPS;
+       PUSHMARK(SP);
+
+       XPUSHs(sv_2mortal(newSVpv(ev_name, 0)));
+       XPUSHs(sv_2mortal(newSVpv(field_name, 0)));
+       XPUSHs(sv_2mortal(newSVuv(value)));
+       XPUSHs(sv_2mortal(newSVpv(field_str, 0)));
+
+       PUTBACK;
+       if (get_cv("main::define_flag_value", 0))
+               call_pv("main::define_flag_value", G_SCALAR);
+       SPAGAIN;
+       PUTBACK;
+       FREETMPS;
+       LEAVE;
+}
+
+static void define_flag_values(struct print_flag_sym *field,
+                              const char *ev_name,
+                              const char *field_name)
+{
+       define_flag_value(ev_name, field_name, field->value, field->str);
+       if (field->next)
+               define_flag_values(field->next, ev_name, field_name);
+}
+
+static void define_flag_field(const char *ev_name,
+                             const char *field_name,
+                             const char *delim)
+{
+       dSP;
+
+       ENTER;
+       SAVETMPS;
+       PUSHMARK(SP);
+
+       XPUSHs(sv_2mortal(newSVpv(ev_name, 0)));
+       XPUSHs(sv_2mortal(newSVpv(field_name, 0)));
+       XPUSHs(sv_2mortal(newSVpv(delim, 0)));
+
+       PUTBACK;
+       if (get_cv("main::define_flag_field", 0))
+               call_pv("main::define_flag_field", G_SCALAR);
+       SPAGAIN;
+       PUTBACK;
+       FREETMPS;
+       LEAVE;
+}
+
+static void define_event_symbols(struct event *event,
+                                const char *ev_name,
+                                struct print_arg *args)
+{
+       switch (args->type) {
+       case PRINT_NULL:
+               break;
+       case PRINT_ATOM:
+               define_flag_value(ev_name, cur_field_name, "0",
+                                 args->atom.atom);
+               zero_flag_atom = 0;
+               break;
+       case PRINT_FIELD:
+               if (cur_field_name)
+                       free(cur_field_name);
+               cur_field_name = strdup(args->field.name);
+               break;
+       case PRINT_FLAGS:
+               define_event_symbols(event, ev_name, args->flags.field);
+               define_flag_field(ev_name, cur_field_name, args->flags.delim);
+               define_flag_values(args->flags.flags, ev_name, cur_field_name);
+               break;
+       case PRINT_SYMBOL:
+               define_event_symbols(event, ev_name, args->symbol.field);
+               define_symbolic_field(ev_name, cur_field_name);
+               define_symbolic_values(args->symbol.symbols, ev_name,
+                                      cur_field_name);
+               break;
+       case PRINT_STRING:
+               break;
+       case PRINT_TYPE:
+               define_event_symbols(event, ev_name, args->typecast.item);
+               break;
+       case PRINT_OP:
+               if (strcmp(args->op.op, ":") == 0)
+                       zero_flag_atom = 1;
+               define_event_symbols(event, ev_name, args->op.left);
+               define_event_symbols(event, ev_name, args->op.right);
+               break;
+       default:
+               /* we should warn... */
+               return;
+       }
+
+       if (args->next)
+               define_event_symbols(event, ev_name, args->next);
+}
+
+static inline struct event *find_cache_event(int type)
+{
+       static char ev_name[256];
+       struct event *event;
+
+       if (events[type])
+               return events[type];
+
+       events[type] = event = trace_find_event(type);
+       if (!event)
+               return NULL;
+
+       sprintf(ev_name, "%s::%s", event->system, event->name);
+
+       define_event_symbols(event, ev_name, event->print_fmt.args);
+
+       return event;
+}
+
+int common_pc(struct scripting_context *context)
+{
+       int pc;
+
+       pc = parse_common_pc(context->event_data);
+
+       return pc;
+}
+
+int common_flags(struct scripting_context *context)
+{
+       int flags;
+
+       flags = parse_common_flags(context->event_data);
+
+       return flags;
+}
+
+int common_lock_depth(struct scripting_context *context)
+{
+       int lock_depth;
+
+       lock_depth = parse_common_lock_depth(context->event_data);
+
+       return lock_depth;
+}
+
+static void perl_process_event(int cpu, void *data,
+                              int size __attribute((unused)),
+                              unsigned long long nsecs, char *comm)
+{
+       struct format_field *field;
+       static char handler[256];
+       unsigned long long val;
+       unsigned long s, ns;
+       struct event *event;
+       int type;
+       int pid;
+
+       dSP;
+
+       type = trace_parse_common_type(data);
+
+       event = find_cache_event(type);
+       if (!event)
+               die("ug! no event found for type %d", type);
+
+       pid = trace_parse_common_pid(data);
+
+       sprintf(handler, "%s::%s", event->system, event->name);
+
+       s = nsecs / NSECS_PER_SEC;
+       ns = nsecs - s * NSECS_PER_SEC;
+
+       scripting_context->event_data = data;
+
+       ENTER;
+       SAVETMPS;
+       PUSHMARK(SP);
+
+       XPUSHs(sv_2mortal(newSVpv(handler, 0)));
+       XPUSHs(sv_2mortal(newSViv(PTR2IV(scripting_context))));
+       XPUSHs(sv_2mortal(newSVuv(cpu)));
+       XPUSHs(sv_2mortal(newSVuv(s)));
+       XPUSHs(sv_2mortal(newSVuv(ns)));
+       XPUSHs(sv_2mortal(newSViv(pid)));
+       XPUSHs(sv_2mortal(newSVpv(comm, 0)));
+
+       /* common fields other than pid can be accessed via xsub fns */
+
+       for (field = event->format.fields; field; field = field->next) {
+               if (field->flags & FIELD_IS_STRING) {
+                       int offset;
+                       if (field->flags & FIELD_IS_DYNAMIC) {
+                               offset = *(int *)(data + field->offset);
+                               offset &= 0xffff;
+                       } else
+                               offset = field->offset;
+                       XPUSHs(sv_2mortal(newSVpv((char *)data + offset, 0)));
+               } else { /* FIELD_IS_NUMERIC */
+                       val = read_size(data + field->offset, field->size);
+                       if (field->flags & FIELD_IS_SIGNED) {
+                               XPUSHs(sv_2mortal(newSViv(val)));
+                       } else {
+                               XPUSHs(sv_2mortal(newSVuv(val)));
+                       }
+               }
+       }
+
+       PUTBACK;
+
+       if (get_cv(handler, 0))
+               call_pv(handler, G_SCALAR);
+       else if (get_cv("main::trace_unhandled", 0)) {
+               XPUSHs(sv_2mortal(newSVpv(handler, 0)));
+               XPUSHs(sv_2mortal(newSViv(PTR2IV(scripting_context))));
+               XPUSHs(sv_2mortal(newSVuv(cpu)));
+               XPUSHs(sv_2mortal(newSVuv(nsecs)));
+               XPUSHs(sv_2mortal(newSViv(pid)));
+               XPUSHs(sv_2mortal(newSVpv(comm, 0)));
+               call_pv("main::trace_unhandled", G_SCALAR);
+       }
+       SPAGAIN;
+       PUTBACK;
+       FREETMPS;
+       LEAVE;
+}
+
+static void run_start_sub(void)
+{
+       dSP; /* access to Perl stack */
+       PUSHMARK(SP);
+
+       if (get_cv("main::trace_begin", 0))
+               call_pv("main::trace_begin", G_DISCARD | G_NOARGS);
+}
+
+/*
+ * Start trace script
+ */
+static int perl_start_script(const char *script)
+{
+       const char *command_line[2] = { "", NULL };
+
+       command_line[1] = script;
+
+       my_perl = perl_alloc();
+       perl_construct(my_perl);
+
+       if (perl_parse(my_perl, xs_init, 2, (char **)command_line,
+                      (char **)NULL))
+               return -1;
+
+       perl_run(my_perl);
+       if (SvTRUE(ERRSV))
+               return -1;
+
+       run_start_sub();
+
+       fprintf(stderr, "perf trace started with Perl script %s\n\n", script);
+
+       return 0;
+}
+
+/*
+ * Stop trace script
+ */
+static int perl_stop_script(void)
+{
+       dSP; /* access to Perl stack */
+       PUSHMARK(SP);
+
+       if (get_cv("main::trace_end", 0))
+               call_pv("main::trace_end", G_DISCARD | G_NOARGS);
+
+       perl_destruct(my_perl);
+       perl_free(my_perl);
+
+       fprintf(stderr, "\nperf trace Perl script stopped\n");
+
+       return 0;
+}
+
+static int perl_generate_script(const char *outfile)
+{
+       struct event *event = NULL;
+       struct format_field *f;
+       char fname[PATH_MAX];
+       int not_first, count;
+       FILE *ofp;
+
+       sprintf(fname, "%s.pl", outfile);
+       ofp = fopen(fname, "w");
+       if (ofp == NULL) {
+               fprintf(stderr, "couldn't open %s\n", fname);
+               return -1;
+       }
+
+       fprintf(ofp, "# perf trace event handlers, "
+               "generated by perf trace -g perl\n");
+
+       fprintf(ofp, "# Licensed under the terms of the GNU GPL"
+               " License version 2\n\n");
+
+       fprintf(ofp, "# The common_* event handler fields are the most useful "
+               "fields common to\n");
+
+       fprintf(ofp, "# all events.  They don't necessarily correspond to "
+               "the 'common_*' fields\n");
+
+       fprintf(ofp, "# in the format files.  Those fields not available as "
+               "handler params can\n");
+
+       fprintf(ofp, "# be retrieved using Perl functions of the form "
+               "common_*($context).\n");
+
+       fprintf(ofp, "# See Context.pm for the list of available "
+               "functions.\n\n");
+
+       fprintf(ofp, "use lib \"$ENV{'PERF_EXEC_PATH'}/scripts/perl/"
+               "Perf-Trace-Util/lib\";\n");
+
+       fprintf(ofp, "use lib \"./Perf-Trace-Util/lib\";\n");
+       fprintf(ofp, "use Perf::Trace::Core;\n");
+       fprintf(ofp, "use Perf::Trace::Context;\n");
+       fprintf(ofp, "use Perf::Trace::Util;\n\n");
+
+       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))) {
+               fprintf(ofp, "sub %s::%s\n{\n", event->system, event->name);
+               fprintf(ofp, "\tmy (");
+
+               fprintf(ofp, "$event_name, ");
+               fprintf(ofp, "$context, ");
+               fprintf(ofp, "$common_cpu, ");
+               fprintf(ofp, "$common_secs, ");
+               fprintf(ofp, "$common_nsecs,\n");
+               fprintf(ofp, "\t    $common_pid, ");
+               fprintf(ofp, "$common_comm,\n\t    ");
+
+               not_first = 0;
+               count = 0;
+
+               for (f = event->format.fields; f; f = f->next) {
+                       if (not_first++)
+                               fprintf(ofp, ", ");
+                       if (++count % 5 == 0)
+                               fprintf(ofp, "\n\t    ");
+
+                       fprintf(ofp, "$%s", f->name);
+               }
+               fprintf(ofp, ") = @_;\n\n");
+
+               fprintf(ofp, "\tprint_header($event_name, $common_cpu, "
+                       "$common_secs, $common_nsecs,\n\t             "
+                       "$common_pid, $common_comm);\n\n");
+
+               fprintf(ofp, "\tprintf(\"");
+
+               not_first = 0;
+               count = 0;
+
+               for (f = event->format.fields; f; f = f->next) {
+                       if (not_first++)
+                               fprintf(ofp, ", ");
+                       if (count && count % 4 == 0) {
+                               fprintf(ofp, "\".\n\t       \"");
+                       }
+                       count++;
+
+                       fprintf(ofp, "%s=", f->name);
+                       if (f->flags & FIELD_IS_STRING ||
+                           f->flags & FIELD_IS_FLAG ||
+                           f->flags & FIELD_IS_SYMBOLIC)
+                               fprintf(ofp, "%%s");
+                       else if (f->flags & FIELD_IS_SIGNED)
+                               fprintf(ofp, "%%d");
+                       else
+                               fprintf(ofp, "%%u");
+               }
+
+               fprintf(ofp, "\\n\",\n\t       ");
+
+               not_first = 0;
+               count = 0;
+
+               for (f = event->format.fields; f; f = f->next) {
+                       if (not_first++)
+                               fprintf(ofp, ", ");
+
+                       if (++count % 5 == 0)
+                               fprintf(ofp, "\n\t       ");
+
+                       if (f->flags & FIELD_IS_FLAG) {
+                               if ((count - 1) % 5 != 0) {
+                                       fprintf(ofp, "\n\t       ");
+                                       count = 4;
+                               }
+                               fprintf(ofp, "flag_str(\"");
+                               fprintf(ofp, "%s::%s\", ", event->system,
+                                       event->name);
+                               fprintf(ofp, "\"%s\", $%s)", f->name,
+                                       f->name);
+                       } else if (f->flags & FIELD_IS_SYMBOLIC) {
+                               if ((count - 1) % 5 != 0) {
+                                       fprintf(ofp, "\n\t       ");
+                                       count = 4;
+                               }
+                               fprintf(ofp, "symbol_str(\"");
+                               fprintf(ofp, "%s::%s\", ", event->system,
+                                       event->name);
+                               fprintf(ofp, "\"%s\", $%s)", f->name,
+                                       f->name);
+                       } else
+                               fprintf(ofp, "$%s", f->name);
+               }
+
+               fprintf(ofp, ");\n");
+               fprintf(ofp, "}\n\n");
+       }
+
+       fprintf(ofp, "sub trace_unhandled\n{\n\tmy ($event_name, $context, "
+               "$common_cpu, $common_secs, $common_nsecs,\n\t    "
+               "$common_pid, $common_comm) = @_;\n\n");
+
+       fprintf(ofp, "\tprint_header($event_name, $common_cpu, "
+               "$common_secs, $common_nsecs,\n\t             $common_pid, "
+               "$common_comm);\n}\n\n");
+
+       fprintf(ofp, "sub print_header\n{\n"
+               "\tmy ($event_name, $cpu, $secs, $nsecs, $pid, $comm) = @_;\n\n"
+               "\tprintf(\"%%-20s %%5u %%05u.%%09u %%8u %%-20s \",\n\t       "
+               "$event_name, $cpu, $secs, $nsecs, $pid, $comm);\n}");
+
+       fclose(ofp);
+
+       fprintf(stderr, "generated Perl script: %s\n", fname);
+
+       return 0;
+}
+
+struct scripting_ops perl_scripting_ops = {
+       .name = "Perl",
+       .start_script = perl_start_script,
+       .stop_script = perl_stop_script,
+       .process_event = perl_process_event,
+       .generate_script = perl_generate_script,
+};
+
+#ifdef NO_LIBPERL
+void setup_perl_scripting(void)
+{
+       fprintf(stderr, "Perl scripting not supported."
+               "  Install libperl and rebuild perf to enable it.  e.g. "
+               "apt-get install libperl-dev (ubuntu), yum install "
+               "perl-ExtUtils-Embed (Fedora), etc.\n");
+}
+#else
+void setup_perl_scripting(void)
+{
+       int err;
+       err = script_spec_register("Perl", &perl_scripting_ops);
+       if (err)
+               die("error registering Perl script extension");
+
+       err = script_spec_register("pl", &perl_scripting_ops);
+       if (err)
+               die("error registering pl script extension");
+
+       scripting_context = malloc(sizeof(struct scripting_context));
+}
+#endif
diff --git a/tools/perf/util/trace-event-perl.h b/tools/perf/util/trace-event-perl.h
new file mode 100644 (file)
index 0000000..8fe0d86
--- /dev/null
@@ -0,0 +1,51 @@
+#ifndef __PERF_TRACE_EVENT_PERL_H
+#define __PERF_TRACE_EVENT_PERL_H
+#ifdef NO_LIBPERL
+typedef int INTERP;
+#define dSP
+#define ENTER
+#define SAVETMPS
+#define PUTBACK
+#define SPAGAIN
+#define FREETMPS
+#define LEAVE
+#define SP
+#define ERRSV
+#define G_SCALAR               (0)
+#define G_DISCARD              (0)
+#define G_NOARGS               (0)
+#define PUSHMARK(a)
+#define SvTRUE(a)              (0)
+#define XPUSHs(s)
+#define sv_2mortal(a)
+#define newSVpv(a,b)
+#define newSVuv(a)
+#define newSViv(a)
+#define get_cv(a,b)            (0)
+#define call_pv(a,b)           (0)
+#define perl_alloc()           (0)
+#define perl_construct(a)      (0)
+#define perl_parse(a,b,c,d,e)  (0)
+#define perl_run(a)            (0)
+#define perl_destruct(a)       (0)
+#define perl_free(a)           (0)
+#define pTHX                   void
+#define CV                     void
+#define dXSUB_SYS
+#define pTHX_
+static inline void newXS(const char *a, void *b, const char *c) {}
+#else
+#include <EXTERN.h>
+#include <perl.h>
+typedef PerlInterpreter * INTERP;
+#endif
+
+struct scripting_context {
+       void *event_data;
+};
+
+int common_pc(struct scripting_context *context);
+int common_flags(struct scripting_context *context);
+int common_lock_depth(struct scripting_context *context);
+
+#endif /* __PERF_TRACE_EVENT_PERL_H */
index 1b5c847..342dfdd 100644 (file)
@@ -458,9 +458,8 @@ struct record *trace_read_data(int cpu)
        return data;
 }
 
-void trace_report(void)
+void trace_report(int fd)
 {
-       const char *input_file = "trace.info";
        char buf[BUFSIZ];
        char test[] = { 23, 8, 68 };
        char *version;
@@ -468,17 +467,15 @@ void trace_report(void)
        int show_funcs = 0;
        int show_printk = 0;
 
-       input_fd = open(input_file, O_RDONLY);
-       if (input_fd < 0)
-               die("opening '%s'\n", input_file);
+       input_fd = fd;
 
        read_or_die(buf, 3);
        if (memcmp(buf, test, 3) != 0)
-               die("not an trace data file");
+               die("no trace data in the file");
 
        read_or_die(buf, 7);
        if (memcmp(buf, "tracing", 7) != 0)
-               die("not a trace file (missing tracing)");
+               die("not a trace file (missing 'tracing' tag)");
 
        version = read_string();
        if (show_version)
index 693f815..81698d5 100644 (file)
@@ -1,5 +1,5 @@
-#ifndef _TRACE_EVENTS_H
-#define _TRACE_EVENTS_H
+#ifndef __PERF_TRACE_EVENTS_H
+#define __PERF_TRACE_EVENTS_H
 
 #include "parse-events.h"
 
@@ -26,6 +26,11 @@ enum {
 enum format_flags {
        FIELD_IS_ARRAY          = 1,
        FIELD_IS_POINTER        = 2,
+       FIELD_IS_SIGNED         = 4,
+       FIELD_IS_STRING         = 8,
+       FIELD_IS_DYNAMIC        = 16,
+       FIELD_IS_FLAG           = 32,
+       FIELD_IS_SYMBOLIC       = 64,
 };
 
 struct format_field {
@@ -132,15 +137,18 @@ struct event {
        int                     flags;
        struct format           format;
        struct print_fmt        print_fmt;
+       char                    *system;
 };
 
 enum {
-       EVENT_FL_ISFTRACE       = 1,
-       EVENT_FL_ISPRINT        = 2,
-       EVENT_FL_ISBPRINT       = 4,
-       EVENT_FL_ISFUNC         = 8,
-       EVENT_FL_ISFUNCENT      = 16,
-       EVENT_FL_ISFUNCRET      = 32,
+       EVENT_FL_ISFTRACE       = 0x01,
+       EVENT_FL_ISPRINT        = 0x02,
+       EVENT_FL_ISBPRINT       = 0x04,
+       EVENT_FL_ISFUNC         = 0x08,
+       EVENT_FL_ISFUNCENT      = 0x10,
+       EVENT_FL_ISFUNCRET      = 0x20,
+
+       EVENT_FL_FAILED         = 0x80000000
 };
 
 struct record {
@@ -154,7 +162,7 @@ struct record *trace_read_data(int cpu);
 
 void parse_set_info(int nr_cpus, int long_sz);
 
-void trace_report(void);
+void trace_report(int fd);
 
 void *malloc_or_die(unsigned int size);
 
@@ -166,7 +174,7 @@ void print_funcs(void);
 void print_printk(void);
 
 int parse_ftrace_file(char *buf, unsigned long size);
-int parse_event_file(char *buf, unsigned long size, char *system);
+int parse_event_file(char *buf, unsigned long size, char *sys);
 void print_event(int cpu, void *data, int size, unsigned long long nsecs,
                  char *comm);
 
@@ -233,13 +241,45 @@ extern int header_page_size_size;
 extern int header_page_data_offset;
 extern int header_page_data_size;
 
+extern int latency_format;
+
 int parse_header_page(char *buf, unsigned long size);
 int trace_parse_common_type(void *data);
+int trace_parse_common_pid(void *data);
+int parse_common_pc(void *data);
+int parse_common_flags(void *data);
+int parse_common_lock_depth(void *data);
 struct event *trace_find_event(int id);
+struct event *trace_find_next_event(struct event *event);
+unsigned long long read_size(void *ptr, int size);
 unsigned long long
 raw_field_value(struct event *event, const char *name, void *data);
 void *raw_field_ptr(struct event *event, const char *name, void *data);
+unsigned long long eval_flag(const char *flag);
+
+int read_tracing_data(int fd, struct perf_event_attr *pattrs, int nb_events);
+
+/* taken from kernel/trace/trace.h */
+enum trace_flag_type {
+       TRACE_FLAG_IRQS_OFF             = 0x01,
+       TRACE_FLAG_IRQS_NOSUPPORT       = 0x02,
+       TRACE_FLAG_NEED_RESCHED         = 0x04,
+       TRACE_FLAG_HARDIRQ              = 0x08,
+       TRACE_FLAG_SOFTIRQ              = 0x10,
+};
+
+struct scripting_ops {
+       const char *name;
+       int (*start_script) (const char *);
+       int (*stop_script) (void);
+       void (*process_event) (int cpu, void *data, int size,
+                              unsigned long long nsecs, char *comm);
+       int (*generate_script) (const char *outfile);
+};
+
+int script_spec_register(const char *spec, struct scripting_ops *ops);
 
-void read_tracing_data(struct perf_event_attr *pattrs, int nb_events);
+extern struct scripting_ops perl_scripting_ops;
+void setup_perl_scripting(void);
 
-#endif /* _TRACE_EVENTS_H */
+#endif /* __PERF_TRACE_EVENTS_H */
index 5e75f90..7d6b833 100644 (file)
@@ -1,5 +1,5 @@
-#ifndef _PERF_TYPES_H
-#define _PERF_TYPES_H
+#ifndef __PERF_TYPES_H
+#define __PERF_TYPES_H
 
 /*
  * We define u64 as unsigned long long for every architecture
@@ -14,4 +14,4 @@ typedef signed short     s16;
 typedef unsigned char     u8;
 typedef signed char       s8;
 
-#endif /* _PERF_TYPES_H */
+#endif /* __PERF_TYPES_H */
index 9de2329..c673d88 100644 (file)
@@ -84,6 +84,9 @@
 #include <iconv.h>
 #endif
 
+extern const char *graph_line;
+extern const char *graph_dotted_line;
+
 /* On most systems <limits.h> would have given us this, but
  * not on some systems (e.g. GNU/Hurd).
  */
@@ -134,6 +137,15 @@ extern void die(const char *err, ...) NORETURN __attribute__((format (printf, 1,
 extern int error(const char *err, ...) __attribute__((format (printf, 1, 2)));
 extern void warning(const char *err, ...) __attribute__((format (printf, 1, 2)));
 
+#include "../../../include/linux/stringify.h"
+
+#define DIE_IF(cnd)    \
+       do { if (cnd)   \
+               die(" at (" __FILE__ ":" __stringify(__LINE__) "): "    \
+                   __stringify(cnd) "\n");                             \
+       } while (0)
+
+
 extern void set_die_routine(void (*routine)(const char *err, va_list params) NORETURN);
 
 extern int prefixcmp(const char *str, const char *prefix);
@@ -278,17 +290,15 @@ static inline char *gitstrchrnul(const char *s, int c)
  * Wrappers:
  */
 extern char *xstrdup(const char *str);
-extern void *xmalloc(size_t size);
+extern void *xmalloc(size_t size) __attribute__((weak));
 extern void *xmemdupz(const void *data, size_t len);
 extern char *xstrndup(const char *str, size_t len);
-extern void *xrealloc(void *ptr, size_t size);
-extern void *xcalloc(size_t nmemb, size_t size);
-extern void *xmmap(void *start, size_t length, int prot, int flags, int fd, off_t offset);
-extern ssize_t xread(int fd, void *buf, size_t len);
-extern ssize_t xwrite(int fd, const void *buf, size_t len);
-extern int xdup(int fd);
-extern FILE *xfdopen(int fd, const char *mode);
-extern int xmkstemp(char *template);
+extern void *xrealloc(void *ptr, size_t size) __attribute__((weak));
+
+static inline void *zalloc(size_t size)
+{
+       return calloc(1, size);
+}
 
 static inline size_t xsize_t(off_t len)
 {
@@ -306,6 +316,7 @@ static inline int has_extension(const char *filename, const char *ext)
 #undef isascii
 #undef isspace
 #undef isdigit
+#undef isxdigit
 #undef isalpha
 #undef isprint
 #undef isalnum
@@ -323,6 +334,8 @@ extern unsigned char sane_ctype[256];
 #define isascii(x) (((x) & ~0x7f) == 0)
 #define isspace(x) sane_istest(x,GIT_SPACE)
 #define isdigit(x) sane_istest(x,GIT_DIGIT)
+#define isxdigit(x)    \
+       (sane_istest(toupper(x), GIT_ALPHA | GIT_DIGIT) && toupper(x) < 'G')
 #define isalpha(x) sane_istest(x,GIT_ALPHA)
 #define isalnum(x) sane_istest(x,GIT_ALPHA | GIT_DIGIT)
 #define isprint(x) sane_istest(x,GIT_PRINT)
index cadf8cf..2fa967e 100644 (file)
@@ -1,5 +1,5 @@
-#ifndef _PERF_VALUES_H
-#define _PERF_VALUES_H
+#ifndef __PERF_VALUES_H
+#define __PERF_VALUES_H
 
 #include "types.h"
 
@@ -24,4 +24,4 @@ void perf_read_values_add_value(struct perf_read_values *values,
 void perf_read_values_display(FILE *fp, struct perf_read_values *values,
                              int raw);
 
-#endif /* _PERF_VALUES_H */
+#endif /* __PERF_VALUES_H */
index 4574ac2..bf44ca8 100644 (file)
@@ -79,43 +79,12 @@ void *xrealloc(void *ptr, size_t size)
        return ret;
 }
 
-void *xcalloc(size_t nmemb, size_t size)
-{
-       void *ret = calloc(nmemb, size);
-       if (!ret && (!nmemb || !size))
-               ret = calloc(1, 1);
-       if (!ret) {
-               release_pack_memory(nmemb * size, -1);
-               ret = calloc(nmemb, size);
-               if (!ret && (!nmemb || !size))
-                       ret = calloc(1, 1);
-               if (!ret)
-                       die("Out of memory, calloc failed");
-       }
-       return ret;
-}
-
-void *xmmap(void *start, size_t length,
-       int prot, int flags, int fd, off_t offset)
-{
-       void *ret = mmap(start, length, prot, flags, fd, offset);
-       if (ret == MAP_FAILED) {
-               if (!length)
-                       return NULL;
-               release_pack_memory(length, fd);
-               ret = mmap(start, length, prot, flags, fd, offset);
-               if (ret == MAP_FAILED)
-                       die("Out of memory? mmap failed: %s", strerror(errno));
-       }
-       return ret;
-}
-
 /*
  * xread() is the same a read(), but it automatically restarts read()
  * operations with a recoverable error (EAGAIN and EINTR). xread()
  * DOES NOT GUARANTEE that "len" bytes is read even if the data is available.
  */
-ssize_t xread(int fd, void *buf, size_t len)
+static ssize_t xread(int fd, void *buf, size_t len)
 {
        ssize_t nr;
        while (1) {
@@ -131,7 +100,7 @@ ssize_t xread(int fd, void *buf, size_t len)
  * operations with a recoverable error (EAGAIN and EINTR). xwrite() DOES NOT
  * GUARANTEE that "len" bytes is written even if the operation is successful.
  */
-ssize_t xwrite(int fd, const void *buf, size_t len)
+static ssize_t xwrite(int fd, const void *buf, size_t len)
 {
        ssize_t nr;
        while (1) {
@@ -179,29 +148,3 @@ ssize_t write_in_full(int fd, const void *buf, size_t count)
 
        return total;
 }
-
-int xdup(int fd)
-{
-       int ret = dup(fd);
-       if (ret < 0)
-               die("dup failed: %s", strerror(errno));
-       return ret;
-}
-
-FILE *xfdopen(int fd, const char *mode)
-{
-       FILE *stream = fdopen(fd, mode);
-       if (stream == NULL)
-               die("Out of memory? fdopen failed: %s", strerror(errno));
-       return stream;
-}
-
-int xmkstemp(char *template)
-{
-       int fd;
-
-       fd = mkstemp(template);
-       if (fd < 0)
-               die("Unable to create temporary file: %s", strerror(errno));
-       return fd;
-}
diff --git a/virt/kvm/assigned-dev.c b/virt/kvm/assigned-dev.c
new file mode 100644 (file)
index 0000000..fd9c097
--- /dev/null
@@ -0,0 +1,818 @@
+/*
+ * Kernel-based Virtual Machine - device assignment support
+ *
+ * Copyright (C) 2006-9 Red Hat, Inc
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#include <linux/kvm_host.h>
+#include <linux/kvm.h>
+#include <linux/uaccess.h>
+#include <linux/vmalloc.h>
+#include <linux/errno.h>
+#include <linux/spinlock.h>
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+#include "irq.h"
+
+static struct kvm_assigned_dev_kernel *kvm_find_assigned_dev(struct list_head *head,
+                                                     int assigned_dev_id)
+{
+       struct list_head *ptr;
+       struct kvm_assigned_dev_kernel *match;
+
+       list_for_each(ptr, head) {
+               match = list_entry(ptr, struct kvm_assigned_dev_kernel, list);
+               if (match->assigned_dev_id == assigned_dev_id)
+                       return match;
+       }
+       return NULL;
+}
+
+static int find_index_from_host_irq(struct kvm_assigned_dev_kernel
+                                   *assigned_dev, int irq)
+{
+       int i, index;
+       struct msix_entry *host_msix_entries;
+
+       host_msix_entries = assigned_dev->host_msix_entries;
+
+       index = -1;
+       for (i = 0; i < assigned_dev->entries_nr; i++)
+               if (irq == host_msix_entries[i].vector) {
+                       index = i;
+                       break;
+               }
+       if (index < 0) {
+               printk(KERN_WARNING "Fail to find correlated MSI-X entry!\n");
+               return 0;
+       }
+
+       return index;
+}
+
+static void kvm_assigned_dev_interrupt_work_handler(struct work_struct *work)
+{
+       struct kvm_assigned_dev_kernel *assigned_dev;
+       struct kvm *kvm;
+       int i;
+
+       assigned_dev = container_of(work, struct kvm_assigned_dev_kernel,
+                                   interrupt_work);
+       kvm = assigned_dev->kvm;
+
+       spin_lock_irq(&assigned_dev->assigned_dev_lock);
+       if (assigned_dev->irq_requested_type & KVM_DEV_IRQ_HOST_MSIX) {
+               struct kvm_guest_msix_entry *guest_entries =
+                       assigned_dev->guest_msix_entries;
+               for (i = 0; i < assigned_dev->entries_nr; i++) {
+                       if (!(guest_entries[i].flags &
+                                       KVM_ASSIGNED_MSIX_PENDING))
+                               continue;
+                       guest_entries[i].flags &= ~KVM_ASSIGNED_MSIX_PENDING;
+                       kvm_set_irq(assigned_dev->kvm,
+                                   assigned_dev->irq_source_id,
+                                   guest_entries[i].vector, 1);
+               }
+       } else
+               kvm_set_irq(assigned_dev->kvm, assigned_dev->irq_source_id,
+                           assigned_dev->guest_irq, 1);
+
+       spin_unlock_irq(&assigned_dev->assigned_dev_lock);
+}
+
+static irqreturn_t kvm_assigned_dev_intr(int irq, void *dev_id)
+{
+       unsigned long flags;
+       struct kvm_assigned_dev_kernel *assigned_dev =
+               (struct kvm_assigned_dev_kernel *) dev_id;
+
+       spin_lock_irqsave(&assigned_dev->assigned_dev_lock, flags);
+       if (assigned_dev->irq_requested_type & KVM_DEV_IRQ_HOST_MSIX) {
+               int index = find_index_from_host_irq(assigned_dev, irq);
+               if (index < 0)
+                       goto out;
+               assigned_dev->guest_msix_entries[index].flags |=
+                       KVM_ASSIGNED_MSIX_PENDING;
+       }
+
+       schedule_work(&assigned_dev->interrupt_work);
+
+       if (assigned_dev->irq_requested_type & KVM_DEV_IRQ_GUEST_INTX) {
+               disable_irq_nosync(irq);
+               assigned_dev->host_irq_disabled = true;
+       }
+
+out:
+       spin_unlock_irqrestore(&assigned_dev->assigned_dev_lock, flags);
+       return IRQ_HANDLED;
+}
+
+/* Ack the irq line for an assigned device */
+static void kvm_assigned_dev_ack_irq(struct kvm_irq_ack_notifier *kian)
+{
+       struct kvm_assigned_dev_kernel *dev;
+       unsigned long flags;
+
+       if (kian->gsi == -1)
+               return;
+
+       dev = container_of(kian, struct kvm_assigned_dev_kernel,
+                          ack_notifier);
+
+       kvm_set_irq(dev->kvm, dev->irq_source_id, dev->guest_irq, 0);
+
+       /* The guest irq may be shared so this ack may be
+        * from another device.
+        */
+       spin_lock_irqsave(&dev->assigned_dev_lock, flags);
+       if (dev->host_irq_disabled) {
+               enable_irq(dev->host_irq);
+               dev->host_irq_disabled = false;
+       }
+       spin_unlock_irqrestore(&dev->assigned_dev_lock, flags);
+}
+
+static void deassign_guest_irq(struct kvm *kvm,
+                              struct kvm_assigned_dev_kernel *assigned_dev)
+{
+       kvm_unregister_irq_ack_notifier(kvm, &assigned_dev->ack_notifier);
+       assigned_dev->ack_notifier.gsi = -1;
+
+       if (assigned_dev->irq_source_id != -1)
+               kvm_free_irq_source_id(kvm, assigned_dev->irq_source_id);
+       assigned_dev->irq_source_id = -1;
+       assigned_dev->irq_requested_type &= ~(KVM_DEV_IRQ_GUEST_MASK);
+}
+
+/* The function implicit hold kvm->lock mutex due to cancel_work_sync() */
+static void deassign_host_irq(struct kvm *kvm,
+                             struct kvm_assigned_dev_kernel *assigned_dev)
+{
+       /*
+        * In kvm_free_device_irq, cancel_work_sync return true if:
+        * 1. work is scheduled, and then cancelled.
+        * 2. work callback is executed.
+        *
+        * The first one ensured that the irq is disabled and no more events
+        * would happen. But for the second one, the irq may be enabled (e.g.
+        * for MSI). So we disable irq here to prevent further events.
+        *
+        * Notice this maybe result in nested disable if the interrupt type is
+        * INTx, but it's OK for we are going to free it.
+        *
+        * If this function is a part of VM destroy, please ensure that till
+        * now, the kvm state is still legal for probably we also have to wait
+        * interrupt_work done.
+        */
+       if (assigned_dev->irq_requested_type & KVM_DEV_IRQ_HOST_MSIX) {
+               int i;
+               for (i = 0; i < assigned_dev->entries_nr; i++)
+                       disable_irq_nosync(assigned_dev->
+                                          host_msix_entries[i].vector);
+
+               cancel_work_sync(&assigned_dev->interrupt_work);
+
+               for (i = 0; i < assigned_dev->entries_nr; i++)
+                       free_irq(assigned_dev->host_msix_entries[i].vector,
+                                (void *)assigned_dev);
+
+               assigned_dev->entries_nr = 0;
+               kfree(assigned_dev->host_msix_entries);
+               kfree(assigned_dev->guest_msix_entries);
+               pci_disable_msix(assigned_dev->dev);
+       } else {
+               /* Deal with MSI and INTx */
+               disable_irq_nosync(assigned_dev->host_irq);
+               cancel_work_sync(&assigned_dev->interrupt_work);
+
+               free_irq(assigned_dev->host_irq, (void *)assigned_dev);
+
+               if (assigned_dev->irq_requested_type & KVM_DEV_IRQ_HOST_MSI)
+                       pci_disable_msi(assigned_dev->dev);
+       }
+
+       assigned_dev->irq_requested_type &= ~(KVM_DEV_IRQ_HOST_MASK);
+}
+
+static int kvm_deassign_irq(struct kvm *kvm,
+                           struct kvm_assigned_dev_kernel *assigned_dev,
+                           unsigned long irq_requested_type)
+{
+       unsigned long guest_irq_type, host_irq_type;
+
+       if (!irqchip_in_kernel(kvm))
+               return -EINVAL;
+       /* no irq assignment to deassign */
+       if (!assigned_dev->irq_requested_type)
+               return -ENXIO;
+
+       host_irq_type = irq_requested_type & KVM_DEV_IRQ_HOST_MASK;
+       guest_irq_type = irq_requested_type & KVM_DEV_IRQ_GUEST_MASK;
+
+       if (host_irq_type)
+               deassign_host_irq(kvm, assigned_dev);
+       if (guest_irq_type)
+               deassign_guest_irq(kvm, assigned_dev);
+
+       return 0;
+}
+
+static void kvm_free_assigned_irq(struct kvm *kvm,
+                                 struct kvm_assigned_dev_kernel *assigned_dev)
+{
+       kvm_deassign_irq(kvm, assigned_dev, assigned_dev->irq_requested_type);
+}
+
+static void kvm_free_assigned_device(struct kvm *kvm,
+                                    struct kvm_assigned_dev_kernel
+                                    *assigned_dev)
+{
+       kvm_free_assigned_irq(kvm, assigned_dev);
+
+       pci_reset_function(assigned_dev->dev);
+
+       pci_release_regions(assigned_dev->dev);
+       pci_disable_device(assigned_dev->dev);
+       pci_dev_put(assigned_dev->dev);
+
+       list_del(&assigned_dev->list);
+       kfree(assigned_dev);
+}
+
+void kvm_free_all_assigned_devices(struct kvm *kvm)
+{
+       struct list_head *ptr, *ptr2;
+       struct kvm_assigned_dev_kernel *assigned_dev;
+
+       list_for_each_safe(ptr, ptr2, &kvm->arch.assigned_dev_head) {
+               assigned_dev = list_entry(ptr,
+                                         struct kvm_assigned_dev_kernel,
+                                         list);
+
+               kvm_free_assigned_device(kvm, assigned_dev);
+       }
+}
+
+static int assigned_device_enable_host_intx(struct kvm *kvm,
+                                           struct kvm_assigned_dev_kernel *dev)
+{
+       dev->host_irq = dev->dev->irq;
+       /* Even though this is PCI, we don't want to use shared
+        * interrupts. Sharing host devices with guest-assigned devices
+        * on the same interrupt line is not a happy situation: there
+        * are going to be long delays in accepting, acking, etc.
+        */
+       if (request_irq(dev->host_irq, kvm_assigned_dev_intr,
+                       0, "kvm_assigned_intx_device", (void *)dev))
+               return -EIO;
+       return 0;
+}
+
+#ifdef __KVM_HAVE_MSI
+static int assigned_device_enable_host_msi(struct kvm *kvm,
+                                          struct kvm_assigned_dev_kernel *dev)
+{
+       int r;
+
+       if (!dev->dev->msi_enabled) {
+               r = pci_enable_msi(dev->dev);
+               if (r)
+                       return r;
+       }
+
+       dev->host_irq = dev->dev->irq;
+       if (request_irq(dev->host_irq, kvm_assigned_dev_intr, 0,
+                       "kvm_assigned_msi_device", (void *)dev)) {
+               pci_disable_msi(dev->dev);
+               return -EIO;
+       }
+
+       return 0;
+}
+#endif
+
+#ifdef __KVM_HAVE_MSIX
+static int assigned_device_enable_host_msix(struct kvm *kvm,
+                                           struct kvm_assigned_dev_kernel *dev)
+{
+       int i, r = -EINVAL;
+
+       /* host_msix_entries and guest_msix_entries should have been
+        * initialized */
+       if (dev->entries_nr == 0)
+               return r;
+
+       r = pci_enable_msix(dev->dev, dev->host_msix_entries, dev->entries_nr);
+       if (r)
+               return r;
+
+       for (i = 0; i < dev->entries_nr; i++) {
+               r = request_irq(dev->host_msix_entries[i].vector,
+                               kvm_assigned_dev_intr, 0,
+                               "kvm_assigned_msix_device",
+                               (void *)dev);
+               /* FIXME: free requested_irq's on failure */
+               if (r)
+                       return r;
+       }
+
+       return 0;
+}
+
+#endif
+
+static int assigned_device_enable_guest_intx(struct kvm *kvm,
+                               struct kvm_assigned_dev_kernel *dev,
+                               struct kvm_assigned_irq *irq)
+{
+       dev->guest_irq = irq->guest_irq;
+       dev->ack_notifier.gsi = irq->guest_irq;
+       return 0;
+}
+
+#ifdef __KVM_HAVE_MSI
+static int assigned_device_enable_guest_msi(struct kvm *kvm,
+                       struct kvm_assigned_dev_kernel *dev,
+                       struct kvm_assigned_irq *irq)
+{
+       dev->guest_irq = irq->guest_irq;
+       dev->ack_notifier.gsi = -1;
+       dev->host_irq_disabled = false;
+       return 0;
+}
+#endif
+
+#ifdef __KVM_HAVE_MSIX
+static int assigned_device_enable_guest_msix(struct kvm *kvm,
+                       struct kvm_assigned_dev_kernel *dev,
+                       struct kvm_assigned_irq *irq)
+{
+       dev->guest_irq = irq->guest_irq;
+       dev->ack_notifier.gsi = -1;
+       dev->host_irq_disabled = false;
+       return 0;
+}
+#endif
+
+static int assign_host_irq(struct kvm *kvm,
+                          struct kvm_assigned_dev_kernel *dev,
+                          __u32 host_irq_type)
+{
+       int r = -EEXIST;
+
+       if (dev->irq_requested_type & KVM_DEV_IRQ_HOST_MASK)
+               return r;
+
+       switch (host_irq_type) {
+       case KVM_DEV_IRQ_HOST_INTX:
+               r = assigned_device_enable_host_intx(kvm, dev);
+               break;
+#ifdef __KVM_HAVE_MSI
+       case KVM_DEV_IRQ_HOST_MSI:
+               r = assigned_device_enable_host_msi(kvm, dev);
+               break;
+#endif
+#ifdef __KVM_HAVE_MSIX
+       case KVM_DEV_IRQ_HOST_MSIX:
+               r = assigned_device_enable_host_msix(kvm, dev);
+               break;
+#endif
+       default:
+               r = -EINVAL;
+       }
+
+       if (!r)
+               dev->irq_requested_type |= host_irq_type;
+
+       return r;
+}
+
+static int assign_guest_irq(struct kvm *kvm,
+                           struct kvm_assigned_dev_kernel *dev,
+                           struct kvm_assigned_irq *irq,
+                           unsigned long guest_irq_type)
+{
+       int id;
+       int r = -EEXIST;
+
+       if (dev->irq_requested_type & KVM_DEV_IRQ_GUEST_MASK)
+               return r;
+
+       id = kvm_request_irq_source_id(kvm);
+       if (id < 0)
+               return id;
+
+       dev->irq_source_id = id;
+
+       switch (guest_irq_type) {
+       case KVM_DEV_IRQ_GUEST_INTX:
+               r = assigned_device_enable_guest_intx(kvm, dev, irq);
+               break;
+#ifdef __KVM_HAVE_MSI
+       case KVM_DEV_IRQ_GUEST_MSI:
+               r = assigned_device_enable_guest_msi(kvm, dev, irq);
+               break;
+#endif
+#ifdef __KVM_HAVE_MSIX
+       case KVM_DEV_IRQ_GUEST_MSIX:
+               r = assigned_device_enable_guest_msix(kvm, dev, irq);
+               break;
+#endif
+       default:
+               r = -EINVAL;
+       }
+
+       if (!r) {
+               dev->irq_requested_type |= guest_irq_type;
+               kvm_register_irq_ack_notifier(kvm, &dev->ack_notifier);
+       } else
+               kvm_free_irq_source_id(kvm, dev->irq_source_id);
+
+       return r;
+}
+
+/* TODO Deal with KVM_DEV_IRQ_ASSIGNED_MASK_MSIX */
+static int kvm_vm_ioctl_assign_irq(struct kvm *kvm,
+                                  struct kvm_assigned_irq *assigned_irq)
+{
+       int r = -EINVAL;
+       struct kvm_assigned_dev_kernel *match;
+       unsigned long host_irq_type, guest_irq_type;
+
+       if (!capable(CAP_SYS_RAWIO))
+               return -EPERM;
+
+       if (!irqchip_in_kernel(kvm))
+               return r;
+
+       mutex_lock(&kvm->lock);
+       r = -ENODEV;
+       match = kvm_find_assigned_dev(&kvm->arch.assigned_dev_head,
+                                     assigned_irq->assigned_dev_id);
+       if (!match)
+               goto out;
+
+       host_irq_type = (assigned_irq->flags & KVM_DEV_IRQ_HOST_MASK);
+       guest_irq_type = (assigned_irq->flags & KVM_DEV_IRQ_GUEST_MASK);
+
+       r = -EINVAL;
+       /* can only assign one type at a time */
+       if (hweight_long(host_irq_type) > 1)
+               goto out;
+       if (hweight_long(guest_irq_type) > 1)
+               goto out;
+       if (host_irq_type == 0 && guest_irq_type == 0)
+               goto out;
+
+       r = 0;
+       if (host_irq_type)
+               r = assign_host_irq(kvm, match, host_irq_type);
+       if (r)
+               goto out;
+
+       if (guest_irq_type)
+               r = assign_guest_irq(kvm, match, assigned_irq, guest_irq_type);
+out:
+       mutex_unlock(&kvm->lock);
+       return r;
+}
+
+static int kvm_vm_ioctl_deassign_dev_irq(struct kvm *kvm,
+                                        struct kvm_assigned_irq
+                                        *assigned_irq)
+{
+       int r = -ENODEV;
+       struct kvm_assigned_dev_kernel *match;
+
+       mutex_lock(&kvm->lock);
+
+       match = kvm_find_assigned_dev(&kvm->arch.assigned_dev_head,
+                                     assigned_irq->assigned_dev_id);
+       if (!match)
+               goto out;
+
+       r = kvm_deassign_irq(kvm, match, assigned_irq->flags);
+out:
+       mutex_unlock(&kvm->lock);
+       return r;
+}
+
+static int kvm_vm_ioctl_assign_device(struct kvm *kvm,
+                                     struct kvm_assigned_pci_dev *assigned_dev)
+{
+       int r = 0;
+       struct kvm_assigned_dev_kernel *match;
+       struct pci_dev *dev;
+
+       down_read(&kvm->slots_lock);
+       mutex_lock(&kvm->lock);
+
+       match = kvm_find_assigned_dev(&kvm->arch.assigned_dev_head,
+                                     assigned_dev->assigned_dev_id);
+       if (match) {
+               /* device already assigned */
+               r = -EEXIST;
+               goto out;
+       }
+
+       match = kzalloc(sizeof(struct kvm_assigned_dev_kernel), GFP_KERNEL);
+       if (match == NULL) {
+               printk(KERN_INFO "%s: Couldn't allocate memory\n",
+                      __func__);
+               r = -ENOMEM;
+               goto out;
+       }
+       dev = pci_get_bus_and_slot(assigned_dev->busnr,
+                                  assigned_dev->devfn);
+       if (!dev) {
+               printk(KERN_INFO "%s: host device not found\n", __func__);
+               r = -EINVAL;
+               goto out_free;
+       }
+       if (pci_enable_device(dev)) {
+               printk(KERN_INFO "%s: Could not enable PCI device\n", __func__);
+               r = -EBUSY;
+               goto out_put;
+       }
+       r = pci_request_regions(dev, "kvm_assigned_device");
+       if (r) {
+               printk(KERN_INFO "%s: Could not get access to device regions\n",
+                      __func__);
+               goto out_disable;
+       }
+
+       pci_reset_function(dev);
+
+       match->assigned_dev_id = assigned_dev->assigned_dev_id;
+       match->host_busnr = assigned_dev->busnr;
+       match->host_devfn = assigned_dev->devfn;
+       match->flags = assigned_dev->flags;
+       match->dev = dev;
+       spin_lock_init(&match->assigned_dev_lock);
+       match->irq_source_id = -1;
+       match->kvm = kvm;
+       match->ack_notifier.irq_acked = kvm_assigned_dev_ack_irq;
+       INIT_WORK(&match->interrupt_work,
+                 kvm_assigned_dev_interrupt_work_handler);
+
+       list_add(&match->list, &kvm->arch.assigned_dev_head);
+
+       if (assigned_dev->flags & KVM_DEV_ASSIGN_ENABLE_IOMMU) {
+               if (!kvm->arch.iommu_domain) {
+                       r = kvm_iommu_map_guest(kvm);
+                       if (r)
+                               goto out_list_del;
+               }
+               r = kvm_assign_device(kvm, match);
+               if (r)
+                       goto out_list_del;
+       }
+
+out:
+       mutex_unlock(&kvm->lock);
+       up_read(&kvm->slots_lock);
+       return r;
+out_list_del:
+       list_del(&match->list);
+       pci_release_regions(dev);
+out_disable:
+       pci_disable_device(dev);
+out_put:
+       pci_dev_put(dev);
+out_free:
+       kfree(match);
+       mutex_unlock(&kvm->lock);
+       up_read(&kvm->slots_lock);
+       return r;
+}
+
+static int kvm_vm_ioctl_deassign_device(struct kvm *kvm,
+               struct kvm_assigned_pci_dev *assigned_dev)
+{
+       int r = 0;
+       struct kvm_assigned_dev_kernel *match;
+
+       mutex_lock(&kvm->lock);
+
+       match = kvm_find_assigned_dev(&kvm->arch.assigned_dev_head,
+                                     assigned_dev->assigned_dev_id);
+       if (!match) {
+               printk(KERN_INFO "%s: device hasn't been assigned before, "
+                 "so cannot be deassigned\n", __func__);
+               r = -EINVAL;
+               goto out;
+       }
+
+       if (match->flags & KVM_DEV_ASSIGN_ENABLE_IOMMU)
+               kvm_deassign_device(kvm, match);
+
+       kvm_free_assigned_device(kvm, match);
+
+out:
+       mutex_unlock(&kvm->lock);
+       return r;
+}
+
+
+#ifdef __KVM_HAVE_MSIX
+static int kvm_vm_ioctl_set_msix_nr(struct kvm *kvm,
+                                   struct kvm_assigned_msix_nr *entry_nr)
+{
+       int r = 0;
+       struct kvm_assigned_dev_kernel *adev;
+
+       mutex_lock(&kvm->lock);
+
+       adev = kvm_find_assigned_dev(&kvm->arch.assigned_dev_head,
+                                     entry_nr->assigned_dev_id);
+       if (!adev) {
+               r = -EINVAL;
+               goto msix_nr_out;
+       }
+
+       if (adev->entries_nr == 0) {
+               adev->entries_nr = entry_nr->entry_nr;
+               if (adev->entries_nr == 0 ||
+                   adev->entries_nr >= KVM_MAX_MSIX_PER_DEV) {
+                       r = -EINVAL;
+                       goto msix_nr_out;
+               }
+
+               adev->host_msix_entries = kzalloc(sizeof(struct msix_entry) *
+                                               entry_nr->entry_nr,
+                                               GFP_KERNEL);
+               if (!adev->host_msix_entries) {
+                       r = -ENOMEM;
+                       goto msix_nr_out;
+               }
+               adev->guest_msix_entries = kzalloc(
+                               sizeof(struct kvm_guest_msix_entry) *
+                               entry_nr->entry_nr, GFP_KERNEL);
+               if (!adev->guest_msix_entries) {
+                       kfree(adev->host_msix_entries);
+                       r = -ENOMEM;
+                       goto msix_nr_out;
+               }
+       } else /* Not allowed set MSI-X number twice */
+               r = -EINVAL;
+msix_nr_out:
+       mutex_unlock(&kvm->lock);
+       return r;
+}
+
+static int kvm_vm_ioctl_set_msix_entry(struct kvm *kvm,
+                                      struct kvm_assigned_msix_entry *entry)
+{
+       int r = 0, i;
+       struct kvm_assigned_dev_kernel *adev;
+
+       mutex_lock(&kvm->lock);
+
+       adev = kvm_find_assigned_dev(&kvm->arch.assigned_dev_head,
+                                     entry->assigned_dev_id);
+
+       if (!adev) {
+               r = -EINVAL;
+               goto msix_entry_out;
+       }
+
+       for (i = 0; i < adev->entries_nr; i++)
+               if (adev->guest_msix_entries[i].vector == 0 ||
+                   adev->guest_msix_entries[i].entry == entry->entry) {
+                       adev->guest_msix_entries[i].entry = entry->entry;
+                       adev->guest_msix_entries[i].vector = entry->gsi;
+                       adev->host_msix_entries[i].entry = entry->entry;
+                       break;
+               }
+       if (i == adev->entries_nr) {
+               r = -ENOSPC;
+               goto msix_entry_out;
+       }
+
+msix_entry_out:
+       mutex_unlock(&kvm->lock);
+
+       return r;
+}
+#endif
+
+long kvm_vm_ioctl_assigned_device(struct kvm *kvm, unsigned ioctl,
+                                 unsigned long arg)
+{
+       void __user *argp = (void __user *)arg;
+       int r = -ENOTTY;
+
+       switch (ioctl) {
+       case KVM_ASSIGN_PCI_DEVICE: {
+               struct kvm_assigned_pci_dev assigned_dev;
+
+               r = -EFAULT;
+               if (copy_from_user(&assigned_dev, argp, sizeof assigned_dev))
+                       goto out;
+               r = kvm_vm_ioctl_assign_device(kvm, &assigned_dev);
+               if (r)
+                       goto out;
+               break;
+       }
+       case KVM_ASSIGN_IRQ: {
+               r = -EOPNOTSUPP;
+               break;
+       }
+#ifdef KVM_CAP_ASSIGN_DEV_IRQ
+       case KVM_ASSIGN_DEV_IRQ: {
+               struct kvm_assigned_irq assigned_irq;
+
+               r = -EFAULT;
+               if (copy_from_user(&assigned_irq, argp, sizeof assigned_irq))
+                       goto out;
+               r = kvm_vm_ioctl_assign_irq(kvm, &assigned_irq);
+               if (r)
+                       goto out;
+               break;
+       }
+       case KVM_DEASSIGN_DEV_IRQ: {
+               struct kvm_assigned_irq assigned_irq;
+
+               r = -EFAULT;
+               if (copy_from_user(&assigned_irq, argp, sizeof assigned_irq))
+                       goto out;
+               r = kvm_vm_ioctl_deassign_dev_irq(kvm, &assigned_irq);
+               if (r)
+                       goto out;
+               break;
+       }
+#endif
+#ifdef KVM_CAP_DEVICE_DEASSIGNMENT
+       case KVM_DEASSIGN_PCI_DEVICE: {
+               struct kvm_assigned_pci_dev assigned_dev;
+
+               r = -EFAULT;
+               if (copy_from_user(&assigned_dev, argp, sizeof assigned_dev))
+                       goto out;
+               r = kvm_vm_ioctl_deassign_device(kvm, &assigned_dev);
+               if (r)
+                       goto out;
+               break;
+       }
+#endif
+#ifdef KVM_CAP_IRQ_ROUTING
+       case KVM_SET_GSI_ROUTING: {
+               struct kvm_irq_routing routing;
+               struct kvm_irq_routing __user *urouting;
+               struct kvm_irq_routing_entry *entries;
+
+               r = -EFAULT;
+               if (copy_from_user(&routing, argp, sizeof(routing)))
+                       goto out;
+               r = -EINVAL;
+               if (routing.nr >= KVM_MAX_IRQ_ROUTES)
+                       goto out;
+               if (routing.flags)
+                       goto out;
+               r = -ENOMEM;
+               entries = vmalloc(routing.nr * sizeof(*entries));
+               if (!entries)
+                       goto out;
+               r = -EFAULT;
+               urouting = argp;
+               if (copy_from_user(entries, urouting->entries,
+                                  routing.nr * sizeof(*entries)))
+                       goto out_free_irq_routing;
+               r = kvm_set_irq_routing(kvm, entries, routing.nr,
+                                       routing.flags);
+       out_free_irq_routing:
+               vfree(entries);
+               break;
+       }
+#endif /* KVM_CAP_IRQ_ROUTING */
+#ifdef __KVM_HAVE_MSIX
+       case KVM_ASSIGN_SET_MSIX_NR: {
+               struct kvm_assigned_msix_nr entry_nr;
+               r = -EFAULT;
+               if (copy_from_user(&entry_nr, argp, sizeof entry_nr))
+                       goto out;
+               r = kvm_vm_ioctl_set_msix_nr(kvm, &entry_nr);
+               if (r)
+                       goto out;
+               break;
+       }
+       case KVM_ASSIGN_SET_MSIX_ENTRY: {
+               struct kvm_assigned_msix_entry entry;
+               r = -EFAULT;
+               if (copy_from_user(&entry, argp, sizeof entry))
+                       goto out;
+               r = kvm_vm_ioctl_set_msix_entry(kvm, &entry);
+               if (r)
+                       goto out;
+               break;
+       }
+#endif
+       }
+out:
+       return r;
+}
+
index bb4ebd8..30f70fd 100644 (file)
@@ -61,10 +61,8 @@ irqfd_inject(struct work_struct *work)
        struct _irqfd *irqfd = container_of(work, struct _irqfd, inject);
        struct kvm *kvm = irqfd->kvm;
 
-       mutex_lock(&kvm->irq_lock);
        kvm_set_irq(kvm, KVM_USERSPACE_IRQ_SOURCE_ID, irqfd->gsi, 1);
        kvm_set_irq(kvm, KVM_USERSPACE_IRQ_SOURCE_ID, irqfd->gsi, 0);
-       mutex_unlock(&kvm->irq_lock);
 }
 
 /*
index 9fe140b..38a2d20 100644 (file)
@@ -182,6 +182,7 @@ int kvm_ioapic_set_irq(struct kvm_ioapic *ioapic, int irq, int level)
        union kvm_ioapic_redirect_entry entry;
        int ret = 1;
 
+       mutex_lock(&ioapic->lock);
        if (irq >= 0 && irq < IOAPIC_NUM_PINS) {
                entry = ioapic->redirtbl[irq];
                level ^= entry.fields.polarity;
@@ -198,34 +199,51 @@ int kvm_ioapic_set_irq(struct kvm_ioapic *ioapic, int irq, int level)
                }
                trace_kvm_ioapic_set_irq(entry.bits, irq, ret == 0);
        }
+       mutex_unlock(&ioapic->lock);
+
        return ret;
 }
 
-static void __kvm_ioapic_update_eoi(struct kvm_ioapic *ioapic, int pin,
-                                   int trigger_mode)
+static void __kvm_ioapic_update_eoi(struct kvm_ioapic *ioapic, int vector,
+                                    int trigger_mode)
 {
-       union kvm_ioapic_redirect_entry *ent;
+       int i;
+
+       for (i = 0; i < IOAPIC_NUM_PINS; i++) {
+               union kvm_ioapic_redirect_entry *ent = &ioapic->redirtbl[i];
 
-       ent = &ioapic->redirtbl[pin];
+               if (ent->fields.vector != vector)
+                       continue;
 
-       kvm_notify_acked_irq(ioapic->kvm, KVM_IRQCHIP_IOAPIC, pin);
+               /*
+                * We are dropping lock while calling ack notifiers because ack
+                * notifier callbacks for assigned devices call into IOAPIC
+                * recursively. Since remote_irr is cleared only after call
+                * to notifiers if the same vector will be delivered while lock
+                * is dropped it will be put into irr and will be delivered
+                * after ack notifier returns.
+                */
+               mutex_unlock(&ioapic->lock);
+               kvm_notify_acked_irq(ioapic->kvm, KVM_IRQCHIP_IOAPIC, i);
+               mutex_lock(&ioapic->lock);
+
+               if (trigger_mode != IOAPIC_LEVEL_TRIG)
+                       continue;
 
-       if (trigger_mode == IOAPIC_LEVEL_TRIG) {
                ASSERT(ent->fields.trig_mode == IOAPIC_LEVEL_TRIG);
                ent->fields.remote_irr = 0;
-               if (!ent->fields.mask && (ioapic->irr & (1 << pin)))
-                       ioapic_service(ioapic, pin);
+               if (!ent->fields.mask && (ioapic->irr & (1 << i)))
+                       ioapic_service(ioapic, i);
        }
 }
 
 void kvm_ioapic_update_eoi(struct kvm *kvm, int vector, int trigger_mode)
 {
        struct kvm_ioapic *ioapic = kvm->arch.vioapic;
-       int i;
 
-       for (i = 0; i < IOAPIC_NUM_PINS; i++)
-               if (ioapic->redirtbl[i].fields.vector == vector)
-                       __kvm_ioapic_update_eoi(ioapic, i, trigger_mode);
+       mutex_lock(&ioapic->lock);
+       __kvm_ioapic_update_eoi(ioapic, vector, trigger_mode);
+       mutex_unlock(&ioapic->lock);
 }
 
 static inline struct kvm_ioapic *to_ioapic(struct kvm_io_device *dev)
@@ -250,8 +268,8 @@ static int ioapic_mmio_read(struct kvm_io_device *this, gpa_t addr, int len,
        ioapic_debug("addr %lx\n", (unsigned long)addr);
        ASSERT(!(addr & 0xf));  /* check alignment */
 
-       mutex_lock(&ioapic->kvm->irq_lock);
        addr &= 0xff;
+       mutex_lock(&ioapic->lock);
        switch (addr) {
        case IOAPIC_REG_SELECT:
                result = ioapic->ioregsel;
@@ -265,6 +283,8 @@ static int ioapic_mmio_read(struct kvm_io_device *this, gpa_t addr, int len,
                result = 0;
                break;
        }
+       mutex_unlock(&ioapic->lock);
+
        switch (len) {
        case 8:
                *(u64 *) val = result;
@@ -277,7 +297,6 @@ static int ioapic_mmio_read(struct kvm_io_device *this, gpa_t addr, int len,
        default:
                printk(KERN_WARNING "ioapic: wrong length %d\n", len);
        }
-       mutex_unlock(&ioapic->kvm->irq_lock);
        return 0;
 }
 
@@ -293,15 +312,15 @@ static int ioapic_mmio_write(struct kvm_io_device *this, gpa_t addr, int len,
                     (void*)addr, len, val);
        ASSERT(!(addr & 0xf));  /* check alignment */
 
-       mutex_lock(&ioapic->kvm->irq_lock);
        if (len == 4 || len == 8)
                data = *(u32 *) val;
        else {
                printk(KERN_WARNING "ioapic: Unsupported size %d\n", len);
-               goto unlock;
+               return 0;
        }
 
        addr &= 0xff;
+       mutex_lock(&ioapic->lock);
        switch (addr) {
        case IOAPIC_REG_SELECT:
                ioapic->ioregsel = data;
@@ -312,15 +331,14 @@ static int ioapic_mmio_write(struct kvm_io_device *this, gpa_t addr, int len,
                break;
 #ifdef CONFIG_IA64
        case IOAPIC_REG_EOI:
-               kvm_ioapic_update_eoi(ioapic->kvm, data, IOAPIC_LEVEL_TRIG);
+               __kvm_ioapic_update_eoi(ioapic, data, IOAPIC_LEVEL_TRIG);
                break;
 #endif
 
        default:
                break;
        }
-unlock:
-       mutex_unlock(&ioapic->kvm->irq_lock);
+       mutex_unlock(&ioapic->lock);
        return 0;
 }
 
@@ -349,6 +367,7 @@ int kvm_ioapic_init(struct kvm *kvm)
        ioapic = kzalloc(sizeof(struct kvm_ioapic), GFP_KERNEL);
        if (!ioapic)
                return -ENOMEM;
+       mutex_init(&ioapic->lock);
        kvm->arch.vioapic = ioapic;
        kvm_ioapic_reset(ioapic);
        kvm_iodevice_init(&ioapic->dev, &ioapic_mmio_ops);
@@ -360,3 +379,26 @@ int kvm_ioapic_init(struct kvm *kvm)
        return ret;
 }
 
+int kvm_get_ioapic(struct kvm *kvm, struct kvm_ioapic_state *state)
+{
+       struct kvm_ioapic *ioapic = ioapic_irqchip(kvm);
+       if (!ioapic)
+               return -EINVAL;
+
+       mutex_lock(&ioapic->lock);
+       memcpy(state, ioapic, sizeof(struct kvm_ioapic_state));
+       mutex_unlock(&ioapic->lock);
+       return 0;
+}
+
+int kvm_set_ioapic(struct kvm *kvm, struct kvm_ioapic_state *state)
+{
+       struct kvm_ioapic *ioapic = ioapic_irqchip(kvm);
+       if (!ioapic)
+               return -EINVAL;
+
+       mutex_lock(&ioapic->lock);
+       memcpy(ioapic, state, sizeof(struct kvm_ioapic_state));
+       mutex_unlock(&ioapic->lock);
+       return 0;
+}
index 7080b71..419c43b 100644 (file)
@@ -41,9 +41,11 @@ struct kvm_ioapic {
        u32 irr;
        u32 pad;
        union kvm_ioapic_redirect_entry redirtbl[IOAPIC_NUM_PINS];
+       unsigned long irq_states[IOAPIC_NUM_PINS];
        struct kvm_io_device dev;
        struct kvm *kvm;
        void (*ack_notifier)(void *opaque, int irq);
+       struct mutex lock;
 };
 
 #ifdef DEBUG
@@ -73,4 +75,7 @@ int kvm_ioapic_set_irq(struct kvm_ioapic *ioapic, int irq, int level);
 void kvm_ioapic_reset(struct kvm_ioapic *ioapic);
 int kvm_irq_delivery_to_apic(struct kvm *kvm, struct kvm_lapic *src,
                struct kvm_lapic_irq *irq);
+int kvm_get_ioapic(struct kvm *kvm, struct kvm_ioapic_state *state);
+int kvm_set_ioapic(struct kvm *kvm, struct kvm_ioapic_state *state);
+
 #endif
index 001663f..9b07734 100644 (file)
 
 #include "ioapic.h"
 
+static inline int kvm_irq_line_state(unsigned long *irq_state,
+                                    int irq_source_id, int level)
+{
+       /* Logical OR for level trig interrupt */
+       if (level)
+               set_bit(irq_source_id, irq_state);
+       else
+               clear_bit(irq_source_id, irq_state);
+
+       return !!(*irq_state);
+}
+
 static int kvm_set_pic_irq(struct kvm_kernel_irq_routing_entry *e,
-                          struct kvm *kvm, int level)
+                          struct kvm *kvm, int irq_source_id, int level)
 {
 #ifdef CONFIG_X86
-       return kvm_pic_set_irq(pic_irqchip(kvm), e->irqchip.pin, level);
+       struct kvm_pic *pic = pic_irqchip(kvm);
+       level = kvm_irq_line_state(&pic->irq_states[e->irqchip.pin],
+                                  irq_source_id, level);
+       return kvm_pic_set_irq(pic, e->irqchip.pin, level);
 #else
        return -1;
 #endif
 }
 
 static int kvm_set_ioapic_irq(struct kvm_kernel_irq_routing_entry *e,
-                             struct kvm *kvm, int level)
+                             struct kvm *kvm, int irq_source_id, int level)
 {
-       return kvm_ioapic_set_irq(kvm->arch.vioapic, e->irqchip.pin, level);
+       struct kvm_ioapic *ioapic = kvm->arch.vioapic;
+       level = kvm_irq_line_state(&ioapic->irq_states[e->irqchip.pin],
+                                  irq_source_id, level);
+
+       return kvm_ioapic_set_irq(ioapic, e->irqchip.pin, level);
 }
 
 inline static bool kvm_is_dm_lowest_prio(struct kvm_lapic_irq *irq)
@@ -63,8 +82,6 @@ int kvm_irq_delivery_to_apic(struct kvm *kvm, struct kvm_lapic *src,
        int i, r = -1;
        struct kvm_vcpu *vcpu, *lowest = NULL;
 
-       WARN_ON(!mutex_is_locked(&kvm->irq_lock));
-
        if (irq->dest_mode == 0 && irq->dest_id == 0xff &&
                        kvm_is_dm_lowest_prio(irq))
                printk(KERN_INFO "kvm: apic: phys broadcast and lowest prio\n");
@@ -96,10 +113,13 @@ int kvm_irq_delivery_to_apic(struct kvm *kvm, struct kvm_lapic *src,
 }
 
 static int kvm_set_msi(struct kvm_kernel_irq_routing_entry *e,
-                      struct kvm *kvm, int level)
+                      struct kvm *kvm, int irq_source_id, int level)
 {
        struct kvm_lapic_irq irq;
 
+       if (!level)
+               return -1;
+
        trace_kvm_msi_set_irq(e->msi.address_lo, e->msi.data);
 
        irq.dest_id = (e->msi.address_lo &
@@ -116,78 +136,67 @@ static int kvm_set_msi(struct kvm_kernel_irq_routing_entry *e,
        return kvm_irq_delivery_to_apic(kvm, NULL, &irq);
 }
 
-/* This should be called with the kvm->irq_lock mutex held
+/*
  * Return value:
  *  < 0   Interrupt was ignored (masked or not delivered for other reasons)
  *  = 0   Interrupt was coalesced (previous irq is still pending)
  *  > 0   Number of CPUs interrupt was delivered to
  */
-int kvm_set_irq(struct kvm *kvm, int irq_source_id, int irq, int level)
+int kvm_set_irq(struct kvm *kvm, int irq_source_id, u32 irq, int level)
 {
-       struct kvm_kernel_irq_routing_entry *e;
-       unsigned long *irq_state, sig_level;
-       int ret = -1;
+       struct kvm_kernel_irq_routing_entry *e, irq_set[KVM_NR_IRQCHIPS];
+       int ret = -1, i = 0;
+       struct kvm_irq_routing_table *irq_rt;
+       struct hlist_node *n;
 
        trace_kvm_set_irq(irq, level, irq_source_id);
 
-       WARN_ON(!mutex_is_locked(&kvm->irq_lock));
-
-       if (irq < KVM_IOAPIC_NUM_PINS) {
-               irq_state = (unsigned long *)&kvm->arch.irq_states[irq];
-
-               /* Logical OR for level trig interrupt */
-               if (level)
-                       set_bit(irq_source_id, irq_state);
-               else
-                       clear_bit(irq_source_id, irq_state);
-               sig_level = !!(*irq_state);
-       } else if (!level)
-               return ret;
-       else /* Deal with MSI/MSI-X */
-               sig_level = 1;
-
        /* Not possible to detect if the guest uses the PIC or the
         * IOAPIC.  So set the bit in both. The guest will ignore
         * writes to the unused one.
         */
-       list_for_each_entry(e, &kvm->irq_routing, link)
-               if (e->gsi == irq) {
-                       int r = e->set(e, kvm, sig_level);
-                       if (r < 0)
-                               continue;
+       rcu_read_lock();
+       irq_rt = rcu_dereference(kvm->irq_routing);
+       if (irq < irq_rt->nr_rt_entries)
+               hlist_for_each_entry(e, n, &irq_rt->map[irq], link)
+                       irq_set[i++] = *e;
+       rcu_read_unlock();
+
+       while(i--) {
+               int r;
+               r = irq_set[i].set(&irq_set[i], kvm, irq_source_id, level);
+               if (r < 0)
+                       continue;
+
+               ret = r + ((ret < 0) ? 0 : ret);
+       }
 
-                       ret = r + ((ret < 0) ? 0 : ret);
-               }
        return ret;
 }
 
 void kvm_notify_acked_irq(struct kvm *kvm, unsigned irqchip, unsigned pin)
 {
-       struct kvm_kernel_irq_routing_entry *e;
        struct kvm_irq_ack_notifier *kian;
        struct hlist_node *n;
-       unsigned gsi = pin;
+       int gsi;
 
        trace_kvm_ack_irq(irqchip, pin);
 
-       list_for_each_entry(e, &kvm->irq_routing, link)
-               if (e->type == KVM_IRQ_ROUTING_IRQCHIP &&
-                   e->irqchip.irqchip == irqchip &&
-                   e->irqchip.pin == pin) {
-                       gsi = e->gsi;
-                       break;
-               }
-
-       hlist_for_each_entry(kian, n, &kvm->arch.irq_ack_notifier_list, link)
-               if (kian->gsi == gsi)
-                       kian->irq_acked(kian);
+       rcu_read_lock();
+       gsi = rcu_dereference(kvm->irq_routing)->chip[irqchip][pin];
+       if (gsi != -1)
+               hlist_for_each_entry_rcu(kian, n, &kvm->irq_ack_notifier_list,
+                                        link)
+                       if (kian->gsi == gsi)
+                               kian->irq_acked(kian);
+       rcu_read_unlock();
 }
 
 void kvm_register_irq_ack_notifier(struct kvm *kvm,
                                   struct kvm_irq_ack_notifier *kian)
 {
        mutex_lock(&kvm->irq_lock);
-       hlist_add_head(&kian->link, &kvm->arch.irq_ack_notifier_list);
+       hlist_add_head_rcu(&kian->link, &kvm->irq_ack_notifier_list);
        mutex_unlock(&kvm->irq_lock);
 }
 
@@ -195,8 +204,9 @@ void kvm_unregister_irq_ack_notifier(struct kvm *kvm,
                                    struct kvm_irq_ack_notifier *kian)
 {
        mutex_lock(&kvm->irq_lock);
-       hlist_del_init(&kian->link);
+       hlist_del_init_rcu(&kian->link);
        mutex_unlock(&kvm->irq_lock);
+       synchronize_rcu();
 }
 
 int kvm_request_irq_source_id(struct kvm *kvm)
@@ -205,16 +215,17 @@ int kvm_request_irq_source_id(struct kvm *kvm)
        int irq_source_id;
 
        mutex_lock(&kvm->irq_lock);
-       irq_source_id = find_first_zero_bit(bitmap,
-                               sizeof(kvm->arch.irq_sources_bitmap));
+       irq_source_id = find_first_zero_bit(bitmap, BITS_PER_LONG);
 
-       if (irq_source_id >= sizeof(kvm->arch.irq_sources_bitmap)) {
+       if (irq_source_id >= BITS_PER_LONG) {
                printk(KERN_WARNING "kvm: exhaust allocatable IRQ sources!\n");
-               return -EFAULT;
+               irq_source_id = -EFAULT;
+               goto unlock;
        }
 
        ASSERT(irq_source_id != KVM_USERSPACE_IRQ_SOURCE_ID);
        set_bit(irq_source_id, bitmap);
+unlock:
        mutex_unlock(&kvm->irq_lock);
 
        return irq_source_id;
@@ -228,13 +239,23 @@ void kvm_free_irq_source_id(struct kvm *kvm, int irq_source_id)
 
        mutex_lock(&kvm->irq_lock);
        if (irq_source_id < 0 ||
-           irq_source_id >= sizeof(kvm->arch.irq_sources_bitmap)) {
+           irq_source_id >= BITS_PER_LONG) {
                printk(KERN_ERR "kvm: IRQ source ID out of range!\n");
-               return;
+               goto unlock;
        }
-       for (i = 0; i < KVM_IOAPIC_NUM_PINS; i++)
-               clear_bit(irq_source_id, &kvm->arch.irq_states[i]);
        clear_bit(irq_source_id, &kvm->arch.irq_sources_bitmap);
+       if (!irqchip_in_kernel(kvm))
+               goto unlock;
+
+       for (i = 0; i < KVM_IOAPIC_NUM_PINS; i++) {
+               clear_bit(irq_source_id, &kvm->arch.vioapic->irq_states[i]);
+               if (i >= 16)
+                       continue;
+#ifdef CONFIG_X86
+               clear_bit(irq_source_id, &pic_irqchip(kvm)->irq_states[i]);
+#endif
+       }
+unlock:
        mutex_unlock(&kvm->irq_lock);
 }
 
@@ -243,7 +264,7 @@ void kvm_register_irq_mask_notifier(struct kvm *kvm, int irq,
 {
        mutex_lock(&kvm->irq_lock);
        kimn->irq = irq;
-       hlist_add_head(&kimn->link, &kvm->mask_notifier_list);
+       hlist_add_head_rcu(&kimn->link, &kvm->mask_notifier_list);
        mutex_unlock(&kvm->irq_lock);
 }
 
@@ -251,8 +272,9 @@ void kvm_unregister_irq_mask_notifier(struct kvm *kvm, int irq,
                                      struct kvm_irq_mask_notifier *kimn)
 {
        mutex_lock(&kvm->irq_lock);
-       hlist_del(&kimn->link);
+       hlist_del_rcu(&kimn->link);
        mutex_unlock(&kvm->irq_lock);
+       synchronize_rcu();
 }
 
 void kvm_fire_mask_notifiers(struct kvm *kvm, int irq, bool mask)
@@ -260,33 +282,37 @@ void kvm_fire_mask_notifiers(struct kvm *kvm, int irq, bool mask)
        struct kvm_irq_mask_notifier *kimn;
        struct hlist_node *n;
 
-       WARN_ON(!mutex_is_locked(&kvm->irq_lock));
-
-       hlist_for_each_entry(kimn, n, &kvm->mask_notifier_list, link)
+       rcu_read_lock();
+       hlist_for_each_entry_rcu(kimn, n, &kvm->mask_notifier_list, link)
                if (kimn->irq == irq)
                        kimn->func(kimn, mask);
-}
-
-static void __kvm_free_irq_routing(struct list_head *irq_routing)
-{
-       struct kvm_kernel_irq_routing_entry *e, *n;
-
-       list_for_each_entry_safe(e, n, irq_routing, link)
-               kfree(e);
+       rcu_read_unlock();
 }
 
 void kvm_free_irq_routing(struct kvm *kvm)
 {
-       mutex_lock(&kvm->irq_lock);
-       __kvm_free_irq_routing(&kvm->irq_routing);
-       mutex_unlock(&kvm->irq_lock);
+       /* Called only during vm destruction. Nobody can use the pointer
+          at this stage */
+       kfree(kvm->irq_routing);
 }
 
-static int setup_routing_entry(struct kvm_kernel_irq_routing_entry *e,
+static int setup_routing_entry(struct kvm_irq_routing_table *rt,
+                              struct kvm_kernel_irq_routing_entry *e,
                               const struct kvm_irq_routing_entry *ue)
 {
        int r = -EINVAL;
        int delta;
+       struct kvm_kernel_irq_routing_entry *ei;
+       struct hlist_node *n;
+
+       /*
+        * Do not allow GSI to be mapped to the same irqchip more than once.
+        * Allow only one to one mapping between GSI and MSI.
+        */
+       hlist_for_each_entry(ei, n, &rt->map[ue->gsi], link)
+               if (ei->type == KVM_IRQ_ROUTING_MSI ||
+                   ue->u.irqchip.irqchip == ei->irqchip.irqchip)
+                       return r;
 
        e->gsi = ue->gsi;
        e->type = ue->type;
@@ -309,6 +335,9 @@ static int setup_routing_entry(struct kvm_kernel_irq_routing_entry *e,
                }
                e->irqchip.irqchip = ue->u.irqchip.irqchip;
                e->irqchip.pin = ue->u.irqchip.pin + delta;
+               if (e->irqchip.pin >= KVM_IOAPIC_NUM_PINS)
+                       goto out;
+               rt->chip[ue->u.irqchip.irqchip][e->irqchip.pin] = ue->gsi;
                break;
        case KVM_IRQ_ROUTING_MSI:
                e->set = kvm_set_msi;
@@ -319,6 +348,8 @@ static int setup_routing_entry(struct kvm_kernel_irq_routing_entry *e,
        default:
                goto out;
        }
+
+       hlist_add_head(&e->link, &rt->map[e->gsi]);
        r = 0;
 out:
        return r;
@@ -330,43 +361,53 @@ int kvm_set_irq_routing(struct kvm *kvm,
                        unsigned nr,
                        unsigned flags)
 {
-       struct list_head irq_list = LIST_HEAD_INIT(irq_list);
-       struct list_head tmp = LIST_HEAD_INIT(tmp);
-       struct kvm_kernel_irq_routing_entry *e = NULL;
-       unsigned i;
+       struct kvm_irq_routing_table *new, *old;
+       u32 i, j, nr_rt_entries = 0;
        int r;
 
        for (i = 0; i < nr; ++i) {
+               if (ue[i].gsi >= KVM_MAX_IRQ_ROUTES)
+                       return -EINVAL;
+               nr_rt_entries = max(nr_rt_entries, ue[i].gsi);
+       }
+
+       nr_rt_entries += 1;
+
+       new = kzalloc(sizeof(*new) + (nr_rt_entries * sizeof(struct hlist_head))
+                     + (nr * sizeof(struct kvm_kernel_irq_routing_entry)),
+                     GFP_KERNEL);
+
+       if (!new)
+               return -ENOMEM;
+
+       new->rt_entries = (void *)&new->map[nr_rt_entries];
+
+       new->nr_rt_entries = nr_rt_entries;
+       for (i = 0; i < 3; i++)
+               for (j = 0; j < KVM_IOAPIC_NUM_PINS; j++)
+                       new->chip[i][j] = -1;
+
+       for (i = 0; i < nr; ++i) {
                r = -EINVAL;
-               if (ue->gsi >= KVM_MAX_IRQ_ROUTES)
-                       goto out;
                if (ue->flags)
                        goto out;
-               r = -ENOMEM;
-               e = kzalloc(sizeof(*e), GFP_KERNEL);
-               if (!e)
-                       goto out;
-               r = setup_routing_entry(e, ue);
+               r = setup_routing_entry(new, &new->rt_entries[i], ue);
                if (r)
                        goto out;
                ++ue;
-               list_add(&e->link, &irq_list);
-               e = NULL;
        }
 
        mutex_lock(&kvm->irq_lock);
-       list_splice(&kvm->irq_routing, &tmp);
-       INIT_LIST_HEAD(&kvm->irq_routing);
-       list_splice(&irq_list, &kvm->irq_routing);
-       INIT_LIST_HEAD(&irq_list);
-       list_splice(&tmp, &irq_list);
+       old = kvm->irq_routing;
+       rcu_assign_pointer(kvm->irq_routing, new);
        mutex_unlock(&kvm->irq_lock);
+       synchronize_rcu();
 
+       new = old;
        r = 0;
 
 out:
-       kfree(e);
-       __kvm_free_irq_routing(&irq_list);
+       kfree(new);
        return r;
 }
 
index 7495ce3..f92ba13 100644 (file)
@@ -43,6 +43,7 @@
 #include <linux/swap.h>
 #include <linux/bitops.h>
 #include <linux/spinlock.h>
+#include <linux/compat.h>
 
 #include <asm/processor.h>
 #include <asm/io.h>
 #include "coalesced_mmio.h"
 #endif
 
-#ifdef KVM_CAP_DEVICE_ASSIGNMENT
-#include <linux/pci.h>
-#include <linux/interrupt.h>
-#include "irq.h"
-#endif
-
 #define CREATE_TRACE_POINTS
 #include <trace/events/kvm.h>
 
@@ -75,6 +70,8 @@ DEFINE_SPINLOCK(kvm_lock);
 LIST_HEAD(vm_list);
 
 static cpumask_var_t cpus_hardware_enabled;
+static int kvm_usage_count = 0;
+static atomic_t hardware_enable_failed;
 
 struct kmem_cache *kvm_vcpu_cache;
 EXPORT_SYMBOL_GPL(kvm_vcpu_cache);
@@ -85,615 +82,13 @@ struct dentry *kvm_debugfs_dir;
 
 static long kvm_vcpu_ioctl(struct file *file, unsigned int ioctl,
                           unsigned long arg);
+static int hardware_enable_all(void);
+static void hardware_disable_all(void);
 
 static bool kvm_rebooting;
 
 static bool largepages_enabled = true;
 
-#ifdef KVM_CAP_DEVICE_ASSIGNMENT
-static struct kvm_assigned_dev_kernel *kvm_find_assigned_dev(struct list_head *head,
-                                                     int assigned_dev_id)
-{
-       struct list_head *ptr;
-       struct kvm_assigned_dev_kernel *match;
-
-       list_for_each(ptr, head) {
-               match = list_entry(ptr, struct kvm_assigned_dev_kernel, list);
-               if (match->assigned_dev_id == assigned_dev_id)
-                       return match;
-       }
-       return NULL;
-}
-
-static int find_index_from_host_irq(struct kvm_assigned_dev_kernel
-                                   *assigned_dev, int irq)
-{
-       int i, index;
-       struct msix_entry *host_msix_entries;
-
-       host_msix_entries = assigned_dev->host_msix_entries;
-
-       index = -1;
-       for (i = 0; i < assigned_dev->entries_nr; i++)
-               if (irq == host_msix_entries[i].vector) {
-                       index = i;
-                       break;
-               }
-       if (index < 0) {
-               printk(KERN_WARNING "Fail to find correlated MSI-X entry!\n");
-               return 0;
-       }
-
-       return index;
-}
-
-static void kvm_assigned_dev_interrupt_work_handler(struct work_struct *work)
-{
-       struct kvm_assigned_dev_kernel *assigned_dev;
-       struct kvm *kvm;
-       int i;
-
-       assigned_dev = container_of(work, struct kvm_assigned_dev_kernel,
-                                   interrupt_work);
-       kvm = assigned_dev->kvm;
-
-       mutex_lock(&kvm->irq_lock);
-       spin_lock_irq(&assigned_dev->assigned_dev_lock);
-       if (assigned_dev->irq_requested_type & KVM_DEV_IRQ_HOST_MSIX) {
-               struct kvm_guest_msix_entry *guest_entries =
-                       assigned_dev->guest_msix_entries;
-               for (i = 0; i < assigned_dev->entries_nr; i++) {
-                       if (!(guest_entries[i].flags &
-                                       KVM_ASSIGNED_MSIX_PENDING))
-                               continue;
-                       guest_entries[i].flags &= ~KVM_ASSIGNED_MSIX_PENDING;
-                       kvm_set_irq(assigned_dev->kvm,
-                                   assigned_dev->irq_source_id,
-                                   guest_entries[i].vector, 1);
-               }
-       } else
-               kvm_set_irq(assigned_dev->kvm, assigned_dev->irq_source_id,
-                           assigned_dev->guest_irq, 1);
-
-       spin_unlock_irq(&assigned_dev->assigned_dev_lock);
-       mutex_unlock(&assigned_dev->kvm->irq_lock);
-}
-
-static irqreturn_t kvm_assigned_dev_intr(int irq, void *dev_id)
-{
-       unsigned long flags;
-       struct kvm_assigned_dev_kernel *assigned_dev =
-               (struct kvm_assigned_dev_kernel *) dev_id;
-
-       spin_lock_irqsave(&assigned_dev->assigned_dev_lock, flags);
-       if (assigned_dev->irq_requested_type & KVM_DEV_IRQ_HOST_MSIX) {
-               int index = find_index_from_host_irq(assigned_dev, irq);
-               if (index < 0)
-                       goto out;
-               assigned_dev->guest_msix_entries[index].flags |=
-                       KVM_ASSIGNED_MSIX_PENDING;
-       }
-
-       schedule_work(&assigned_dev->interrupt_work);
-
-       if (assigned_dev->irq_requested_type & KVM_DEV_IRQ_GUEST_INTX) {
-               disable_irq_nosync(irq);
-               assigned_dev->host_irq_disabled = true;
-       }
-
-out:
-       spin_unlock_irqrestore(&assigned_dev->assigned_dev_lock, flags);
-       return IRQ_HANDLED;
-}
-
-/* Ack the irq line for an assigned device */
-static void kvm_assigned_dev_ack_irq(struct kvm_irq_ack_notifier *kian)
-{
-       struct kvm_assigned_dev_kernel *dev;
-       unsigned long flags;
-
-       if (kian->gsi == -1)
-               return;
-
-       dev = container_of(kian, struct kvm_assigned_dev_kernel,
-                          ack_notifier);
-
-       kvm_set_irq(dev->kvm, dev->irq_source_id, dev->guest_irq, 0);
-
-       /* The guest irq may be shared so this ack may be
-        * from another device.
-        */
-       spin_lock_irqsave(&dev->assigned_dev_lock, flags);
-       if (dev->host_irq_disabled) {
-               enable_irq(dev->host_irq);
-               dev->host_irq_disabled = false;
-       }
-       spin_unlock_irqrestore(&dev->assigned_dev_lock, flags);
-}
-
-static void deassign_guest_irq(struct kvm *kvm,
-                              struct kvm_assigned_dev_kernel *assigned_dev)
-{
-       kvm_unregister_irq_ack_notifier(kvm, &assigned_dev->ack_notifier);
-       assigned_dev->ack_notifier.gsi = -1;
-
-       if (assigned_dev->irq_source_id != -1)
-               kvm_free_irq_source_id(kvm, assigned_dev->irq_source_id);
-       assigned_dev->irq_source_id = -1;
-       assigned_dev->irq_requested_type &= ~(KVM_DEV_IRQ_GUEST_MASK);
-}
-
-/* The function implicit hold kvm->lock mutex due to cancel_work_sync() */
-static void deassign_host_irq(struct kvm *kvm,
-                             struct kvm_assigned_dev_kernel *assigned_dev)
-{
-       /*
-        * In kvm_free_device_irq, cancel_work_sync return true if:
-        * 1. work is scheduled, and then cancelled.
-        * 2. work callback is executed.
-        *
-        * The first one ensured that the irq is disabled and no more events
-        * would happen. But for the second one, the irq may be enabled (e.g.
-        * for MSI). So we disable irq here to prevent further events.
-        *
-        * Notice this maybe result in nested disable if the interrupt type is
-        * INTx, but it's OK for we are going to free it.
-        *
-        * If this function is a part of VM destroy, please ensure that till
-        * now, the kvm state is still legal for probably we also have to wait
-        * interrupt_work done.
-        */
-       if (assigned_dev->irq_requested_type & KVM_DEV_IRQ_HOST_MSIX) {
-               int i;
-               for (i = 0; i < assigned_dev->entries_nr; i++)
-                       disable_irq_nosync(assigned_dev->
-                                          host_msix_entries[i].vector);
-
-               cancel_work_sync(&assigned_dev->interrupt_work);
-
-               for (i = 0; i < assigned_dev->entries_nr; i++)
-                       free_irq(assigned_dev->host_msix_entries[i].vector,
-                                (void *)assigned_dev);
-
-               assigned_dev->entries_nr = 0;
-               kfree(assigned_dev->host_msix_entries);
-               kfree(assigned_dev->guest_msix_entries);
-               pci_disable_msix(assigned_dev->dev);
-       } else {
-               /* Deal with MSI and INTx */
-               disable_irq_nosync(assigned_dev->host_irq);
-               cancel_work_sync(&assigned_dev->interrupt_work);
-
-               free_irq(assigned_dev->host_irq, (void *)assigned_dev);
-
-               if (assigned_dev->irq_requested_type & KVM_DEV_IRQ_HOST_MSI)
-                       pci_disable_msi(assigned_dev->dev);
-       }
-
-       assigned_dev->irq_requested_type &= ~(KVM_DEV_IRQ_HOST_MASK);
-}
-
-static int kvm_deassign_irq(struct kvm *kvm,
-                           struct kvm_assigned_dev_kernel *assigned_dev,
-                           unsigned long irq_requested_type)
-{
-       unsigned long guest_irq_type, host_irq_type;
-
-       if (!irqchip_in_kernel(kvm))
-               return -EINVAL;
-       /* no irq assignment to deassign */
-       if (!assigned_dev->irq_requested_type)
-               return -ENXIO;
-
-       host_irq_type = irq_requested_type & KVM_DEV_IRQ_HOST_MASK;
-       guest_irq_type = irq_requested_type & KVM_DEV_IRQ_GUEST_MASK;
-
-       if (host_irq_type)
-               deassign_host_irq(kvm, assigned_dev);
-       if (guest_irq_type)
-               deassign_guest_irq(kvm, assigned_dev);
-
-       return 0;
-}
-
-static void kvm_free_assigned_irq(struct kvm *kvm,
-                                 struct kvm_assigned_dev_kernel *assigned_dev)
-{
-       kvm_deassign_irq(kvm, assigned_dev, assigned_dev->irq_requested_type);
-}
-
-static void kvm_free_assigned_device(struct kvm *kvm,
-                                    struct kvm_assigned_dev_kernel
-                                    *assigned_dev)
-{
-       kvm_free_assigned_irq(kvm, assigned_dev);
-
-       pci_reset_function(assigned_dev->dev);
-
-       pci_release_regions(assigned_dev->dev);
-       pci_disable_device(assigned_dev->dev);
-       pci_dev_put(assigned_dev->dev);
-
-       list_del(&assigned_dev->list);
-       kfree(assigned_dev);
-}
-
-void kvm_free_all_assigned_devices(struct kvm *kvm)
-{
-       struct list_head *ptr, *ptr2;
-       struct kvm_assigned_dev_kernel *assigned_dev;
-
-       list_for_each_safe(ptr, ptr2, &kvm->arch.assigned_dev_head) {
-               assigned_dev = list_entry(ptr,
-                                         struct kvm_assigned_dev_kernel,
-                                         list);
-
-               kvm_free_assigned_device(kvm, assigned_dev);
-       }
-}
-
-static int assigned_device_enable_host_intx(struct kvm *kvm,
-                                           struct kvm_assigned_dev_kernel *dev)
-{
-       dev->host_irq = dev->dev->irq;
-       /* Even though this is PCI, we don't want to use shared
-        * interrupts. Sharing host devices with guest-assigned devices
-        * on the same interrupt line is not a happy situation: there
-        * are going to be long delays in accepting, acking, etc.
-        */
-       if (request_irq(dev->host_irq, kvm_assigned_dev_intr,
-                       0, "kvm_assigned_intx_device", (void *)dev))
-               return -EIO;
-       return 0;
-}
-
-#ifdef __KVM_HAVE_MSI
-static int assigned_device_enable_host_msi(struct kvm *kvm,
-                                          struct kvm_assigned_dev_kernel *dev)
-{
-       int r;
-
-       if (!dev->dev->msi_enabled) {
-               r = pci_enable_msi(dev->dev);
-               if (r)
-                       return r;
-       }
-
-       dev->host_irq = dev->dev->irq;
-       if (request_irq(dev->host_irq, kvm_assigned_dev_intr, 0,
-                       "kvm_assigned_msi_device", (void *)dev)) {
-               pci_disable_msi(dev->dev);
-               return -EIO;
-       }
-
-       return 0;
-}
-#endif
-
-#ifdef __KVM_HAVE_MSIX
-static int assigned_device_enable_host_msix(struct kvm *kvm,
-                                           struct kvm_assigned_dev_kernel *dev)
-{
-       int i, r = -EINVAL;
-
-       /* host_msix_entries and guest_msix_entries should have been
-        * initialized */
-       if (dev->entries_nr == 0)
-               return r;
-
-       r = pci_enable_msix(dev->dev, dev->host_msix_entries, dev->entries_nr);
-       if (r)
-               return r;
-
-       for (i = 0; i < dev->entries_nr; i++) {
-               r = request_irq(dev->host_msix_entries[i].vector,
-                               kvm_assigned_dev_intr, 0,
-                               "kvm_assigned_msix_device",
-                               (void *)dev);
-               /* FIXME: free requested_irq's on failure */
-               if (r)
-                       return r;
-       }
-
-       return 0;
-}
-
-#endif
-
-static int assigned_device_enable_guest_intx(struct kvm *kvm,
-                               struct kvm_assigned_dev_kernel *dev,
-                               struct kvm_assigned_irq *irq)
-{
-       dev->guest_irq = irq->guest_irq;
-       dev->ack_notifier.gsi = irq->guest_irq;
-       return 0;
-}
-
-#ifdef __KVM_HAVE_MSI
-static int assigned_device_enable_guest_msi(struct kvm *kvm,
-                       struct kvm_assigned_dev_kernel *dev,
-                       struct kvm_assigned_irq *irq)
-{
-       dev->guest_irq = irq->guest_irq;
-       dev->ack_notifier.gsi = -1;
-       dev->host_irq_disabled = false;
-       return 0;
-}
-#endif
-#ifdef __KVM_HAVE_MSIX
-static int assigned_device_enable_guest_msix(struct kvm *kvm,
-                       struct kvm_assigned_dev_kernel *dev,
-                       struct kvm_assigned_irq *irq)
-{
-       dev->guest_irq = irq->guest_irq;
-       dev->ack_notifier.gsi = -1;
-       dev->host_irq_disabled = false;
-       return 0;
-}
-#endif
-
-static int assign_host_irq(struct kvm *kvm,
-                          struct kvm_assigned_dev_kernel *dev,
-                          __u32 host_irq_type)
-{
-       int r = -EEXIST;
-
-       if (dev->irq_requested_type & KVM_DEV_IRQ_HOST_MASK)
-               return r;
-
-       switch (host_irq_type) {
-       case KVM_DEV_IRQ_HOST_INTX:
-               r = assigned_device_enable_host_intx(kvm, dev);
-               break;
-#ifdef __KVM_HAVE_MSI
-       case KVM_DEV_IRQ_HOST_MSI:
-               r = assigned_device_enable_host_msi(kvm, dev);
-               break;
-#endif
-#ifdef __KVM_HAVE_MSIX
-       case KVM_DEV_IRQ_HOST_MSIX:
-               r = assigned_device_enable_host_msix(kvm, dev);
-               break;
-#endif
-       default:
-               r = -EINVAL;
-       }
-
-       if (!r)
-               dev->irq_requested_type |= host_irq_type;
-
-       return r;
-}
-
-static int assign_guest_irq(struct kvm *kvm,
-                           struct kvm_assigned_dev_kernel *dev,
-                           struct kvm_assigned_irq *irq,
-                           unsigned long guest_irq_type)
-{
-       int id;
-       int r = -EEXIST;
-
-       if (dev->irq_requested_type & KVM_DEV_IRQ_GUEST_MASK)
-               return r;
-
-       id = kvm_request_irq_source_id(kvm);
-       if (id < 0)
-               return id;
-
-       dev->irq_source_id = id;
-
-       switch (guest_irq_type) {
-       case KVM_DEV_IRQ_GUEST_INTX:
-               r = assigned_device_enable_guest_intx(kvm, dev, irq);
-               break;
-#ifdef __KVM_HAVE_MSI
-       case KVM_DEV_IRQ_GUEST_MSI:
-               r = assigned_device_enable_guest_msi(kvm, dev, irq);
-               break;
-#endif
-#ifdef __KVM_HAVE_MSIX
-       case KVM_DEV_IRQ_GUEST_MSIX:
-               r = assigned_device_enable_guest_msix(kvm, dev, irq);
-               break;
-#endif
-       default:
-               r = -EINVAL;
-       }
-
-       if (!r) {
-               dev->irq_requested_type |= guest_irq_type;
-               kvm_register_irq_ack_notifier(kvm, &dev->ack_notifier);
-       } else
-               kvm_free_irq_source_id(kvm, dev->irq_source_id);
-
-       return r;
-}
-
-/* TODO Deal with KVM_DEV_IRQ_ASSIGNED_MASK_MSIX */
-static int kvm_vm_ioctl_assign_irq(struct kvm *kvm,
-                                  struct kvm_assigned_irq *assigned_irq)
-{
-       int r = -EINVAL;
-       struct kvm_assigned_dev_kernel *match;
-       unsigned long host_irq_type, guest_irq_type;
-
-       if (!capable(CAP_SYS_RAWIO))
-               return -EPERM;
-
-       if (!irqchip_in_kernel(kvm))
-               return r;
-
-       mutex_lock(&kvm->lock);
-       r = -ENODEV;
-       match = kvm_find_assigned_dev(&kvm->arch.assigned_dev_head,
-                                     assigned_irq->assigned_dev_id);
-       if (!match)
-               goto out;
-
-       host_irq_type = (assigned_irq->flags & KVM_DEV_IRQ_HOST_MASK);
-       guest_irq_type = (assigned_irq->flags & KVM_DEV_IRQ_GUEST_MASK);
-
-       r = -EINVAL;
-       /* can only assign one type at a time */
-       if (hweight_long(host_irq_type) > 1)
-               goto out;
-       if (hweight_long(guest_irq_type) > 1)
-               goto out;
-       if (host_irq_type == 0 && guest_irq_type == 0)
-               goto out;
-
-       r = 0;
-       if (host_irq_type)
-               r = assign_host_irq(kvm, match, host_irq_type);
-       if (r)
-               goto out;
-
-       if (guest_irq_type)
-               r = assign_guest_irq(kvm, match, assigned_irq, guest_irq_type);
-out:
-       mutex_unlock(&kvm->lock);
-       return r;
-}
-
-static int kvm_vm_ioctl_deassign_dev_irq(struct kvm *kvm,
-                                        struct kvm_assigned_irq
-                                        *assigned_irq)
-{
-       int r = -ENODEV;
-       struct kvm_assigned_dev_kernel *match;
-
-       mutex_lock(&kvm->lock);
-
-       match = kvm_find_assigned_dev(&kvm->arch.assigned_dev_head,
-                                     assigned_irq->assigned_dev_id);
-       if (!match)
-               goto out;
-
-       r = kvm_deassign_irq(kvm, match, assigned_irq->flags);
-out:
-       mutex_unlock(&kvm->lock);
-       return r;
-}
-
-static int kvm_vm_ioctl_assign_device(struct kvm *kvm,
-                                     struct kvm_assigned_pci_dev *assigned_dev)
-{
-       int r = 0;
-       struct kvm_assigned_dev_kernel *match;
-       struct pci_dev *dev;
-
-       down_read(&kvm->slots_lock);
-       mutex_lock(&kvm->lock);
-
-       match = kvm_find_assigned_dev(&kvm->arch.assigned_dev_head,
-                                     assigned_dev->assigned_dev_id);
-       if (match) {
-               /* device already assigned */
-               r = -EEXIST;
-               goto out;
-       }
-
-       match = kzalloc(sizeof(struct kvm_assigned_dev_kernel), GFP_KERNEL);
-       if (match == NULL) {
-               printk(KERN_INFO "%s: Couldn't allocate memory\n",
-                      __func__);
-               r = -ENOMEM;
-               goto out;
-       }
-       dev = pci_get_bus_and_slot(assigned_dev->busnr,
-                                  assigned_dev->devfn);
-       if (!dev) {
-               printk(KERN_INFO "%s: host device not found\n", __func__);
-               r = -EINVAL;
-               goto out_free;
-       }
-       if (pci_enable_device(dev)) {
-               printk(KERN_INFO "%s: Could not enable PCI device\n", __func__);
-               r = -EBUSY;
-               goto out_put;
-       }
-       r = pci_request_regions(dev, "kvm_assigned_device");
-       if (r) {
-               printk(KERN_INFO "%s: Could not get access to device regions\n",
-                      __func__);
-               goto out_disable;
-       }
-
-       pci_reset_function(dev);
-
-       match->assigned_dev_id = assigned_dev->assigned_dev_id;
-       match->host_busnr = assigned_dev->busnr;
-       match->host_devfn = assigned_dev->devfn;
-       match->flags = assigned_dev->flags;
-       match->dev = dev;
-       spin_lock_init(&match->assigned_dev_lock);
-       match->irq_source_id = -1;
-       match->kvm = kvm;
-       match->ack_notifier.irq_acked = kvm_assigned_dev_ack_irq;
-       INIT_WORK(&match->interrupt_work,
-                 kvm_assigned_dev_interrupt_work_handler);
-
-       list_add(&match->list, &kvm->arch.assigned_dev_head);
-
-       if (assigned_dev->flags & KVM_DEV_ASSIGN_ENABLE_IOMMU) {
-               if (!kvm->arch.iommu_domain) {
-                       r = kvm_iommu_map_guest(kvm);
-                       if (r)
-                               goto out_list_del;
-               }
-               r = kvm_assign_device(kvm, match);
-               if (r)
-                       goto out_list_del;
-       }
-
-out:
-       mutex_unlock(&kvm->lock);
-       up_read(&kvm->slots_lock);
-       return r;
-out_list_del:
-       list_del(&match->list);
-       pci_release_regions(dev);
-out_disable:
-       pci_disable_device(dev);
-out_put:
-       pci_dev_put(dev);
-out_free:
-       kfree(match);
-       mutex_unlock(&kvm->lock);
-       up_read(&kvm->slots_lock);
-       return r;
-}
-#endif
-
-#ifdef KVM_CAP_DEVICE_DEASSIGNMENT
-static int kvm_vm_ioctl_deassign_device(struct kvm *kvm,
-               struct kvm_assigned_pci_dev *assigned_dev)
-{
-       int r = 0;
-       struct kvm_assigned_dev_kernel *match;
-
-       mutex_lock(&kvm->lock);
-
-       match = kvm_find_assigned_dev(&kvm->arch.assigned_dev_head,
-                                     assigned_dev->assigned_dev_id);
-       if (!match) {
-               printk(KERN_INFO "%s: device hasn't been assigned before, "
-                 "so cannot be deassigned\n", __func__);
-               r = -EINVAL;
-               goto out;
-       }
-
-       if (match->flags & KVM_DEV_ASSIGN_ENABLE_IOMMU)
-               kvm_deassign_device(kvm, match);
-
-       kvm_free_assigned_device(kvm, match);
-
-out:
-       mutex_unlock(&kvm->lock);
-       return r;
-}
-#endif
-
 inline int kvm_is_mmio_pfn(pfn_t pfn)
 {
        if (pfn_valid(pfn)) {
@@ -949,6 +344,7 @@ static const struct mmu_notifier_ops kvm_mmu_notifier_ops = {
 
 static struct kvm *kvm_create_vm(void)
 {
+       int r = 0;
        struct kvm *kvm = kvm_arch_create_vm();
 #ifdef KVM_COALESCED_MMIO_PAGE_OFFSET
        struct page *page;
@@ -956,16 +352,21 @@ static struct kvm *kvm_create_vm(void)
 
        if (IS_ERR(kvm))
                goto out;
+
+       r = hardware_enable_all();
+       if (r)
+               goto out_err_nodisable;
+
 #ifdef CONFIG_HAVE_KVM_IRQCHIP
-       INIT_LIST_HEAD(&kvm->irq_routing);
        INIT_HLIST_HEAD(&kvm->mask_notifier_list);
+       INIT_HLIST_HEAD(&kvm->irq_ack_notifier_list);
 #endif
 
 #ifdef KVM_COALESCED_MMIO_PAGE_OFFSET
        page = alloc_page(GFP_KERNEL | __GFP_ZERO);
        if (!page) {
-               kfree(kvm);
-               return ERR_PTR(-ENOMEM);
+               r = -ENOMEM;
+               goto out_err;
        }
        kvm->coalesced_mmio_ring =
                        (struct kvm_coalesced_mmio_ring *)page_address(page);
@@ -973,15 +374,13 @@ static struct kvm *kvm_create_vm(void)
 
 #if defined(CONFIG_MMU_NOTIFIER) && defined(KVM_ARCH_WANT_MMU_NOTIFIER)
        {
-               int err;
                kvm->mmu_notifier.ops = &kvm_mmu_notifier_ops;
-               err = mmu_notifier_register(&kvm->mmu_notifier, current->mm);
-               if (err) {
+               r = mmu_notifier_register(&kvm->mmu_notifier, current->mm);
+               if (r) {
 #ifdef KVM_COALESCED_MMIO_PAGE_OFFSET
                        put_page(page);
 #endif
-                       kfree(kvm);
-                       return ERR_PTR(err);
+                       goto out_err;
                }
        }
 #endif
@@ -1005,6 +404,12 @@ static struct kvm *kvm_create_vm(void)
 #endif
 out:
        return kvm;
+
+out_err:
+       hardware_disable_all();
+out_err_nodisable:
+       kfree(kvm);
+       return ERR_PTR(r);
 }
 
 /*
@@ -1063,6 +468,7 @@ static void kvm_destroy_vm(struct kvm *kvm)
        kvm_arch_flush_shadow(kvm);
 #endif
        kvm_arch_destroy_vm(kvm);
+       hardware_disable_all();
        mmdrop(mm);
 }
 
@@ -1689,9 +1095,7 @@ void kvm_vcpu_block(struct kvm_vcpu *vcpu)
                if (signal_pending(current))
                        break;
 
-               vcpu_put(vcpu);
                schedule();
-               vcpu_load(vcpu);
        }
 
        finish_wait(&vcpu->wq, &wait);
@@ -1705,6 +1109,21 @@ void kvm_resched(struct kvm_vcpu *vcpu)
 }
 EXPORT_SYMBOL_GPL(kvm_resched);
 
+void kvm_vcpu_on_spin(struct kvm_vcpu *vcpu)
+{
+       ktime_t expires;
+       DEFINE_WAIT(wait);
+
+       prepare_to_wait(&vcpu->wq, &wait, TASK_INTERRUPTIBLE);
+
+       /* Sleep for 100 us, and hope lock-holder got scheduled */
+       expires = ktime_add_ns(ktime_get(), 100000UL);
+       schedule_hrtimeout(&expires, HRTIMER_MODE_ABS);
+
+       finish_wait(&vcpu->wq, &wait);
+}
+EXPORT_SYMBOL_GPL(kvm_vcpu_on_spin);
+
 static int kvm_vcpu_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
 {
        struct kvm_vcpu *vcpu = vma->vm_file->private_data;
@@ -1828,88 +1247,6 @@ static int kvm_vcpu_ioctl_set_sigmask(struct kvm_vcpu *vcpu, sigset_t *sigset)
        return 0;
 }
 
-#ifdef __KVM_HAVE_MSIX
-static int kvm_vm_ioctl_set_msix_nr(struct kvm *kvm,
-                                   struct kvm_assigned_msix_nr *entry_nr)
-{
-       int r = 0;
-       struct kvm_assigned_dev_kernel *adev;
-
-       mutex_lock(&kvm->lock);
-
-       adev = kvm_find_assigned_dev(&kvm->arch.assigned_dev_head,
-                                     entry_nr->assigned_dev_id);
-       if (!adev) {
-               r = -EINVAL;
-               goto msix_nr_out;
-       }
-
-       if (adev->entries_nr == 0) {
-               adev->entries_nr = entry_nr->entry_nr;
-               if (adev->entries_nr == 0 ||
-                   adev->entries_nr >= KVM_MAX_MSIX_PER_DEV) {
-                       r = -EINVAL;
-                       goto msix_nr_out;
-               }
-
-               adev->host_msix_entries = kzalloc(sizeof(struct msix_entry) *
-                                               entry_nr->entry_nr,
-                                               GFP_KERNEL);
-               if (!adev->host_msix_entries) {
-                       r = -ENOMEM;
-                       goto msix_nr_out;
-               }
-               adev->guest_msix_entries = kzalloc(
-                               sizeof(struct kvm_guest_msix_entry) *
-                               entry_nr->entry_nr, GFP_KERNEL);
-               if (!adev->guest_msix_entries) {
-                       kfree(adev->host_msix_entries);
-                       r = -ENOMEM;
-                       goto msix_nr_out;
-               }
-       } else /* Not allowed set MSI-X number twice */
-               r = -EINVAL;
-msix_nr_out:
-       mutex_unlock(&kvm->lock);
-       return r;
-}
-
-static int kvm_vm_ioctl_set_msix_entry(struct kvm *kvm,
-                                      struct kvm_assigned_msix_entry *entry)
-{
-       int r = 0, i;
-       struct kvm_assigned_dev_kernel *adev;
-
-       mutex_lock(&kvm->lock);
-
-       adev = kvm_find_assigned_dev(&kvm->arch.assigned_dev_head,
-                                     entry->assigned_dev_id);
-
-       if (!adev) {
-               r = -EINVAL;
-               goto msix_entry_out;
-       }
-
-       for (i = 0; i < adev->entries_nr; i++)
-               if (adev->guest_msix_entries[i].vector == 0 ||
-                   adev->guest_msix_entries[i].entry == entry->entry) {
-                       adev->guest_msix_entries[i].entry = entry->entry;
-                       adev->guest_msix_entries[i].vector = entry->gsi;
-                       adev->host_msix_entries[i].entry = entry->entry;
-                       break;
-               }
-       if (i == adev->entries_nr) {
-               r = -ENOSPC;
-               goto msix_entry_out;
-       }
-
-msix_entry_out:
-       mutex_unlock(&kvm->lock);
-
-       return r;
-}
-#endif
-
 static long kvm_vcpu_ioctl(struct file *filp,
                           unsigned int ioctl, unsigned long arg)
 {
@@ -2168,112 +1505,6 @@ static long kvm_vm_ioctl(struct file *filp,
                break;
        }
 #endif
-#ifdef KVM_CAP_DEVICE_ASSIGNMENT
-       case KVM_ASSIGN_PCI_DEVICE: {
-               struct kvm_assigned_pci_dev assigned_dev;
-
-               r = -EFAULT;
-               if (copy_from_user(&assigned_dev, argp, sizeof assigned_dev))
-                       goto out;
-               r = kvm_vm_ioctl_assign_device(kvm, &assigned_dev);
-               if (r)
-                       goto out;
-               break;
-       }
-       case KVM_ASSIGN_IRQ: {
-               r = -EOPNOTSUPP;
-               break;
-       }
-#ifdef KVM_CAP_ASSIGN_DEV_IRQ
-       case KVM_ASSIGN_DEV_IRQ: {
-               struct kvm_assigned_irq assigned_irq;
-
-               r = -EFAULT;
-               if (copy_from_user(&assigned_irq, argp, sizeof assigned_irq))
-                       goto out;
-               r = kvm_vm_ioctl_assign_irq(kvm, &assigned_irq);
-               if (r)
-                       goto out;
-               break;
-       }
-       case KVM_DEASSIGN_DEV_IRQ: {
-               struct kvm_assigned_irq assigned_irq;
-
-               r = -EFAULT;
-               if (copy_from_user(&assigned_irq, argp, sizeof assigned_irq))
-                       goto out;
-               r = kvm_vm_ioctl_deassign_dev_irq(kvm, &assigned_irq);
-               if (r)
-                       goto out;
-               break;
-       }
-#endif
-#endif
-#ifdef KVM_CAP_DEVICE_DEASSIGNMENT
-       case KVM_DEASSIGN_PCI_DEVICE: {
-               struct kvm_assigned_pci_dev assigned_dev;
-
-               r = -EFAULT;
-               if (copy_from_user(&assigned_dev, argp, sizeof assigned_dev))
-                       goto out;
-               r = kvm_vm_ioctl_deassign_device(kvm, &assigned_dev);
-               if (r)
-                       goto out;
-               break;
-       }
-#endif
-#ifdef KVM_CAP_IRQ_ROUTING
-       case KVM_SET_GSI_ROUTING: {
-               struct kvm_irq_routing routing;
-               struct kvm_irq_routing __user *urouting;
-               struct kvm_irq_routing_entry *entries;
-
-               r = -EFAULT;
-               if (copy_from_user(&routing, argp, sizeof(routing)))
-                       goto out;
-               r = -EINVAL;
-               if (routing.nr >= KVM_MAX_IRQ_ROUTES)
-                       goto out;
-               if (routing.flags)
-                       goto out;
-               r = -ENOMEM;
-               entries = vmalloc(routing.nr * sizeof(*entries));
-               if (!entries)
-                       goto out;
-               r = -EFAULT;
-               urouting = argp;
-               if (copy_from_user(entries, urouting->entries,
-                                  routing.nr * sizeof(*entries)))
-                       goto out_free_irq_routing;
-               r = kvm_set_irq_routing(kvm, entries, routing.nr,
-                                       routing.flags);
-       out_free_irq_routing:
-               vfree(entries);
-               break;
-       }
-#endif /* KVM_CAP_IRQ_ROUTING */
-#ifdef __KVM_HAVE_MSIX
-       case KVM_ASSIGN_SET_MSIX_NR: {
-               struct kvm_assigned_msix_nr entry_nr;
-               r = -EFAULT;
-               if (copy_from_user(&entry_nr, argp, sizeof entry_nr))
-                       goto out;
-               r = kvm_vm_ioctl_set_msix_nr(kvm, &entry_nr);
-               if (r)
-                       goto out;
-               break;
-       }
-       case KVM_ASSIGN_SET_MSIX_ENTRY: {
-               struct kvm_assigned_msix_entry entry;
-               r = -EFAULT;
-               if (copy_from_user(&entry, argp, sizeof entry))
-                       goto out;
-               r = kvm_vm_ioctl_set_msix_entry(kvm, &entry);
-               if (r)
-                       goto out;
-               break;
-       }
-#endif
        case KVM_IRQFD: {
                struct kvm_irqfd data;
 
@@ -2305,11 +1536,59 @@ static long kvm_vm_ioctl(struct file *filp,
 #endif
        default:
                r = kvm_arch_vm_ioctl(filp, ioctl, arg);
+               if (r == -ENOTTY)
+                       r = kvm_vm_ioctl_assigned_device(kvm, ioctl, arg);
        }
 out:
        return r;
 }
 
+#ifdef CONFIG_COMPAT
+struct compat_kvm_dirty_log {
+       __u32 slot;
+       __u32 padding1;
+       union {
+               compat_uptr_t dirty_bitmap; /* one bit per page */
+               __u64 padding2;
+       };
+};
+
+static long kvm_vm_compat_ioctl(struct file *filp,
+                          unsigned int ioctl, unsigned long arg)
+{
+       struct kvm *kvm = filp->private_data;
+       int r;
+
+       if (kvm->mm != current->mm)
+               return -EIO;
+       switch (ioctl) {
+       case KVM_GET_DIRTY_LOG: {
+               struct compat_kvm_dirty_log compat_log;
+               struct kvm_dirty_log log;
+
+               r = -EFAULT;
+               if (copy_from_user(&compat_log, (void __user *)arg,
+                                  sizeof(compat_log)))
+                       goto out;
+               log.slot         = compat_log.slot;
+               log.padding1     = compat_log.padding1;
+               log.padding2     = compat_log.padding2;
+               log.dirty_bitmap = compat_ptr(compat_log.dirty_bitmap);
+
+               r = kvm_vm_ioctl_get_dirty_log(kvm, &log);
+               if (r)
+                       goto out;
+               break;
+       }
+       default:
+               r = kvm_vm_ioctl(filp, ioctl, arg);
+       }
+
+out:
+       return r;
+}
+#endif
+
 static int kvm_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
 {
        struct page *page[1];
@@ -2344,7 +1623,9 @@ static int kvm_vm_mmap(struct file *file, struct vm_area_struct *vma)
 static struct file_operations kvm_vm_fops = {
        .release        = kvm_vm_release,
        .unlocked_ioctl = kvm_vm_ioctl,
-       .compat_ioctl   = kvm_vm_ioctl,
+#ifdef CONFIG_COMPAT
+       .compat_ioctl   = kvm_vm_compat_ioctl,
+#endif
        .mmap           = kvm_vm_mmap,
 };
 
@@ -2372,6 +1653,7 @@ static long kvm_dev_ioctl_check_extension_generic(long arg)
 #ifdef CONFIG_KVM_APIC_ARCHITECTURE
        case KVM_CAP_SET_BOOT_CPU_ID:
 #endif
+       case KVM_CAP_INTERNAL_ERROR_DATA:
                return 1;
 #ifdef CONFIG_HAVE_KVM_IRQCHIP
        case KVM_CAP_IRQ_ROUTING:
@@ -2442,11 +1724,21 @@ static struct miscdevice kvm_dev = {
 static void hardware_enable(void *junk)
 {
        int cpu = raw_smp_processor_id();
+       int r;
 
        if (cpumask_test_cpu(cpu, cpus_hardware_enabled))
                return;
+
        cpumask_set_cpu(cpu, cpus_hardware_enabled);
-       kvm_arch_hardware_enable(NULL);
+
+       r = kvm_arch_hardware_enable(NULL);
+
+       if (r) {
+               cpumask_clear_cpu(cpu, cpus_hardware_enabled);
+               atomic_inc(&hardware_enable_failed);
+               printk(KERN_INFO "kvm: enabling virtualization on "
+                                "CPU%d failed\n", cpu);
+       }
 }
 
 static void hardware_disable(void *junk)
@@ -2459,11 +1751,52 @@ static void hardware_disable(void *junk)
        kvm_arch_hardware_disable(NULL);
 }
 
+static void hardware_disable_all_nolock(void)
+{
+       BUG_ON(!kvm_usage_count);
+
+       kvm_usage_count--;
+       if (!kvm_usage_count)
+               on_each_cpu(hardware_disable, NULL, 1);
+}
+
+static void hardware_disable_all(void)
+{
+       spin_lock(&kvm_lock);
+       hardware_disable_all_nolock();
+       spin_unlock(&kvm_lock);
+}
+
+static int hardware_enable_all(void)
+{
+       int r = 0;
+
+       spin_lock(&kvm_lock);
+
+       kvm_usage_count++;
+       if (kvm_usage_count == 1) {
+               atomic_set(&hardware_enable_failed, 0);
+               on_each_cpu(hardware_enable, NULL, 1);
+
+               if (atomic_read(&hardware_enable_failed)) {
+                       hardware_disable_all_nolock();
+                       r = -EBUSY;
+               }
+       }
+
+       spin_unlock(&kvm_lock);
+
+       return r;
+}
+
 static int kvm_cpu_hotplug(struct notifier_block *notifier, unsigned long val,
                           void *v)
 {
        int cpu = (long)v;
 
+       if (!kvm_usage_count)
+               return NOTIFY_OK;
+
        val &= ~CPU_TASKS_FROZEN;
        switch (val) {
        case CPU_DYING:
@@ -2666,13 +1999,15 @@ static void kvm_exit_debug(void)
 
 static int kvm_suspend(struct sys_device *dev, pm_message_t state)
 {
-       hardware_disable(NULL);
+       if (kvm_usage_count)
+               hardware_disable(NULL);
        return 0;
 }
 
 static int kvm_resume(struct sys_device *dev)
 {
-       hardware_enable(NULL);
+       if (kvm_usage_count)
+               hardware_enable(NULL);
        return 0;
 }
 
@@ -2747,7 +2082,6 @@ int kvm_init(void *opaque, unsigned int vcpu_size,
                        goto out_free_1;
        }
 
-       on_each_cpu(hardware_enable, NULL, 1);
        r = register_cpu_notifier(&kvm_cpu_notifier);
        if (r)
                goto out_free_2;
@@ -2797,7 +2131,6 @@ out_free_3:
        unregister_reboot_notifier(&kvm_reboot_notifier);
        unregister_cpu_notifier(&kvm_cpu_notifier);
 out_free_2:
-       on_each_cpu(hardware_disable, NULL, 1);
 out_free_1:
        kvm_arch_hardware_unsetup();
 out_free_0a: